mirror of
https://git.code.sf.net/p/ntfs-3g/ntfs-3g.git
synced 2024-11-23 18:14:24 +08:00
Add new API mft.[hc]::ntfs_mft_record_{layout,format}() and make
mkntfs use it. (Logical change 1.335)
This commit is contained in:
parent
b5af3df4b8
commit
2bd298bc2d
@ -101,6 +101,11 @@ static __inline__ u32 ntfs_mft_record_get_data_size(const MFT_RECORD *m)
|
||||
return le32_to_cpu(m->bytes_in_use);
|
||||
}
|
||||
|
||||
extern int ntfs_mft_record_layout(const ntfs_volume *vol, const MFT_REF mref,
|
||||
MFT_RECORD *mrec);
|
||||
|
||||
extern int ntfs_mft_record_format(const ntfs_volume *vol, const MFT_REF mref);
|
||||
|
||||
extern ntfs_inode *ntfs_mft_record_alloc(ntfs_volume *vol, s64 start);
|
||||
|
||||
extern int ntfs_mft_record_free(ntfs_volume *vol, ntfs_inode *ni);
|
||||
|
127
libntfs/mft.c
127
libntfs/mft.c
@ -123,7 +123,7 @@ int ntfs_mft_records_write(const ntfs_volume *vol, const MFT_REF mref,
|
||||
int cnt = 0, res = 0;
|
||||
|
||||
Dprintf("%s(): Entering for inode 0x%llx.\n", __FUNCTION__, MREF(mref));
|
||||
if (!vol || !vol->mft_na || !b || count < 0) {
|
||||
if (!vol || !vol->mft_na || vol->mftmirr_size <= 0 || !b || count < 0) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
@ -134,6 +134,10 @@ int ntfs_mft_records_write(const ntfs_volume *vol, const MFT_REF mref,
|
||||
return -1;
|
||||
}
|
||||
if (m < vol->mftmirr_size) {
|
||||
if (!vol->mftmirr_na) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
cnt = vol->mftmirr_size - m;
|
||||
if (cnt > count)
|
||||
cnt = count;
|
||||
@ -248,9 +252,126 @@ read_failed:
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_mft_record_layout - layout an mft record into a memory buffer
|
||||
* @vol: volume to which the mft record will belong
|
||||
* @mref: mft reference specifying the mft record number
|
||||
* @m: destination buffer of size >= @vol->mft_record_size bytes
|
||||
*
|
||||
* Layout an empty, unused mft record with the mft reference @mref into the
|
||||
* buffer @m. The volume @vol is needed because the mft record structure was
|
||||
* modified in NTFS 3.1 so we need to know which volume version this mft record
|
||||
* will be used on.
|
||||
*
|
||||
* On success return 0 and on error return -1 with errno set to the error code.
|
||||
*/
|
||||
int ntfs_mft_record_layout(const ntfs_volume *vol, const MFT_REF mref,
|
||||
MFT_RECORD *m)
|
||||
{
|
||||
ATTR_RECORD *a;
|
||||
|
||||
if (!vol || !m) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
/* Aligned to 2-byte boundary. */
|
||||
if (vol->major_ver < 3 || (vol->major_ver == 3 && !vol->minor_ver))
|
||||
m->usa_ofs = cpu_to_le16((sizeof(MFT_RECORD_OLD) + 1) & ~1);
|
||||
else {
|
||||
/* Abort if mref is > 32 bits. */
|
||||
if (MREF(mref) & 0x0000ffff00000000ull) {
|
||||
fprintf(stderr, "Mft reference exceeds 32 bits!");
|
||||
errno = ERANGE;
|
||||
return -1;
|
||||
}
|
||||
m->usa_ofs = cpu_to_le16((sizeof(MFT_RECORD) + 1) & ~1);
|
||||
/*
|
||||
* Set the NTFS 3.1+ specific fields while we know that the
|
||||
* volume version is 3.1+.
|
||||
*/
|
||||
m->reserved = cpu_to_le16(0);
|
||||
m->mft_record_number = cpu_to_le32(MREF(mref));
|
||||
}
|
||||
m->magic = magic_FILE;
|
||||
if (vol->mft_record_size >= NTFS_SECTOR_SIZE)
|
||||
m->usa_count = cpu_to_le16(vol->mft_record_size /
|
||||
NTFS_SECTOR_SIZE + 1);
|
||||
else {
|
||||
m->usa_count = cpu_to_le16(1);
|
||||
fprintf(stderr, "Sector size is bigger than MFT record size. "
|
||||
"Setting usa_count to 1. If Windows\nchkdsk "
|
||||
"reports this as corruption, please email "
|
||||
"linux-ntfs-dev@lists.sf.net\nstating that "
|
||||
"you saw this message and that the file "
|
||||
"system created was corrupt.\nThank you.");
|
||||
}
|
||||
/* Set the update sequence number to 1. */
|
||||
*(u16*)((u8*)m + le16_to_cpu(m->usa_ofs)) = cpu_to_le16(1);
|
||||
m->lsn = cpu_to_le64(0ull);
|
||||
m->sequence_number = cpu_to_le16(1);
|
||||
m->link_count = cpu_to_le16(0);
|
||||
/* Aligned to 8-byte boundary. */
|
||||
m->attrs_offset = cpu_to_le16((le16_to_cpu(m->usa_ofs) +
|
||||
(le16_to_cpu(m->usa_count) << 1) + 7) & ~7);
|
||||
m->flags = cpu_to_le16(0);
|
||||
/*
|
||||
* Using attrs_offset plus eight bytes (for the termination attribute),
|
||||
* aligned to 8-byte boundary.
|
||||
*/
|
||||
m->bytes_in_use = cpu_to_le32((le16_to_cpu(m->attrs_offset) + 8 + 7) &
|
||||
~7);
|
||||
m->bytes_allocated = cpu_to_le32(vol->mft_record_size);
|
||||
m->base_mft_record = cpu_to_le64((MFT_REF)0);
|
||||
m->next_attr_instance = cpu_to_le16(0);
|
||||
a = (ATTR_RECORD*)((u8*)m + le16_to_cpu(m->attrs_offset));
|
||||
a->type = AT_END;
|
||||
a->length = cpu_to_le32(0);
|
||||
/* Finally, clear the unused part of the mft record. */
|
||||
memset((u8*)a + 8, 0, vol->mft_record_size - ((u8*)a + 8 - (u8*)m));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_mft_record_format - format an mft record on an ntfs volume
|
||||
* @vol: volume on which to format the mft record
|
||||
* @mref: mft reference specifying mft record to format
|
||||
*
|
||||
* Format the mft record with the mft reference @mref in $MFT/$DATA, i.e. lay
|
||||
* out an empty, unused mft record in memory and write it to the volume @vol.
|
||||
*
|
||||
* On success return 0 and on error return -1 with errno set to the error code.
|
||||
*/
|
||||
int ntfs_mft_record_format(const ntfs_volume *vol, const MFT_REF mref)
|
||||
{
|
||||
MFT_RECORD *m;
|
||||
int err;
|
||||
|
||||
if (!vol || !vol->mft_na) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
m = malloc(vol->mft_record_size);
|
||||
if (!m)
|
||||
return -1;
|
||||
if (ntfs_mft_record_layout(vol, mref, m)) {
|
||||
err = errno;
|
||||
free(m);
|
||||
errno = err;
|
||||
return -1;
|
||||
}
|
||||
if (ntfs_mft_record_write(vol, mref, m)) {
|
||||
err = errno;
|
||||
free(m);
|
||||
errno = err;
|
||||
return -1;
|
||||
}
|
||||
free(m);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_mft_record_alloc - allocate an mft record on an ntfs volume
|
||||
* @vol: mounted ntfs volume on which to allocate the mft record
|
||||
* @vol: volume on which to allocate the mft record
|
||||
* @start: starting mft record at which to allocate (or -1 if none)
|
||||
*
|
||||
* Allocate an mft record in $MFT/$DATA starting to search for a free record
|
||||
@ -274,7 +395,7 @@ ntfs_inode *ntfs_mft_record_alloc(ntfs_volume *vol, s64 start)
|
||||
|
||||
/**
|
||||
* ntfs_mft_record_free - free an mft record on an ntfs volume
|
||||
* @vol: mounted ntfs volume on which to free the mft record
|
||||
* @vol: volume on which to free the mft record
|
||||
* @ni: open ntfs inode of the mft record to free
|
||||
*
|
||||
* Free the mft record of the open inode @ni on the mounted ntfs volume @vol.
|
||||
|
@ -123,6 +123,7 @@
|
||||
#include "mst.h"
|
||||
#include "dir.h"
|
||||
#include "runlist.h"
|
||||
#include "mft.h"
|
||||
#include "utils.h"
|
||||
|
||||
#ifdef NO_NTFS_DEVICE_DEFAULT_IO_OPS
|
||||
@ -954,59 +955,6 @@ static void dump_mft_record(MFT_RECORD *m)
|
||||
printf("-- End of attributes. --\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* format_mft_record
|
||||
*/
|
||||
static void format_mft_record(MFT_RECORD *m)
|
||||
{
|
||||
ATTR_RECORD *a;
|
||||
|
||||
memset(m, 0, vol->mft_record_size);
|
||||
m->magic = magic_FILE;
|
||||
/*
|
||||
* Aligned to 2-byte boundary. Note, we use the MFT_RECORD_OLD here
|
||||
* explicitly as the MFT_RECORD structure has extra fields at the end
|
||||
* which are only present in NTFS 3.1+.
|
||||
*/
|
||||
m->usa_ofs = cpu_to_le16((sizeof(MFT_RECORD_OLD) + 1) & ~1);
|
||||
if (vol->mft_record_size >= NTFS_SECTOR_SIZE)
|
||||
m->usa_count = cpu_to_le16(vol->mft_record_size /
|
||||
NTFS_SECTOR_SIZE + 1);
|
||||
else {
|
||||
m->usa_count = cpu_to_le16(1);
|
||||
Qprintf("Sector size is bigger than MFT record size. Setting "
|
||||
"usa_count to 1. If Windows\nchkdsk reports this as "
|
||||
"corruption, please email linux-ntfs-dev@lists.sf.net\n"
|
||||
"stating that you saw this message and that the file "
|
||||
"system created was corrupt.\nThank you.");
|
||||
}
|
||||
/* Set the update sequence number to 1. */
|
||||
*(u16*)((u8*)m + le16_to_cpu(m->usa_ofs)) = cpu_to_le16(1);
|
||||
m->lsn = cpu_to_le64(0LL);
|
||||
m->sequence_number = cpu_to_le16(1);
|
||||
m->link_count = cpu_to_le16(0);
|
||||
/* Aligned to 8-byte boundary. */
|
||||
m->attrs_offset = cpu_to_le16((le16_to_cpu(m->usa_ofs) +
|
||||
(le16_to_cpu(m->usa_count) << 1) + 7) & ~7);
|
||||
m->flags = cpu_to_le16(0);
|
||||
/*
|
||||
* Using attrs_offset plus eight bytes (for the termination attribute),
|
||||
* aligned to 8-byte boundary.
|
||||
*/
|
||||
m->bytes_in_use = cpu_to_le32((le16_to_cpu(m->attrs_offset) + 8 + 7) &
|
||||
~7);
|
||||
m->bytes_allocated = cpu_to_le32(vol->mft_record_size);
|
||||
m->base_mft_record = cpu_to_le64((MFT_REF)0);
|
||||
m->next_attr_instance = cpu_to_le16(0);
|
||||
a = (ATTR_RECORD*)((char*)m + le16_to_cpu(m->attrs_offset));
|
||||
a->type = AT_END;
|
||||
a->length = cpu_to_le32(0);
|
||||
#if 0
|
||||
if (!opts.quiet && opts.verbose > 1)
|
||||
dump_mft_record(m);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* make_room_for_attribute - make room for an attribute inside an mft record
|
||||
* @m: mft record
|
||||
@ -3092,8 +3040,17 @@ int main(int argc, char **argv)
|
||||
Qprintf(" - Done.\n");
|
||||
}
|
||||
Qprintf("Creating NTFS volume structures.\n");
|
||||
/* Setup an empty mft record. */
|
||||
format_mft_record((MFT_RECORD*)buf);
|
||||
/*
|
||||
* Setup an empty mft record. Note, we can just give 0 as the mft
|
||||
* reference as we are creating an NTFS 1.2 volume for which the mft
|
||||
* reference is ignored by ntfs_mft_record_layout().
|
||||
*/
|
||||
if (ntfs_mft_record_layout(vol, 0, (MFT_RECORD *)buf))
|
||||
err_exit("Error: Failed to layout mft record.\n");
|
||||
#if 0
|
||||
if (!opts.quiet && opts.verbose > 1)
|
||||
dump_mft_record((MFT_RECORD*)buf);
|
||||
#endif
|
||||
/*
|
||||
* Copy the mft record onto all 16 records in the buffer and setup the
|
||||
* sequence numbers of each system file to equal the mft record number
|
||||
|
Loading…
Reference in New Issue
Block a user