Add new API mft.[hc]::ntfs_mft_record_{layout,format}() and make

mkntfs use it.

(Logical change 1.335)
This commit is contained in:
cantab.net!aia21 2004-03-15 12:50:18 +00:00
parent b5af3df4b8
commit 2bd298bc2d
3 changed files with 141 additions and 58 deletions

View File

@ -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); 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 ntfs_inode *ntfs_mft_record_alloc(ntfs_volume *vol, s64 start);
extern int ntfs_mft_record_free(ntfs_volume *vol, ntfs_inode *ni); extern int ntfs_mft_record_free(ntfs_volume *vol, ntfs_inode *ni);

View File

@ -123,7 +123,7 @@ int ntfs_mft_records_write(const ntfs_volume *vol, const MFT_REF mref,
int cnt = 0, res = 0; int cnt = 0, res = 0;
Dprintf("%s(): Entering for inode 0x%llx.\n", __FUNCTION__, MREF(mref)); 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; errno = EINVAL;
return -1; return -1;
} }
@ -134,6 +134,10 @@ int ntfs_mft_records_write(const ntfs_volume *vol, const MFT_REF mref,
return -1; return -1;
} }
if (m < vol->mftmirr_size) { if (m < vol->mftmirr_size) {
if (!vol->mftmirr_na) {
errno = EINVAL;
return -1;
}
cnt = vol->mftmirr_size - m; cnt = vol->mftmirr_size - m;
if (cnt > count) if (cnt > count)
cnt = count; cnt = count;
@ -248,9 +252,126 @@ read_failed:
return -1; 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 * 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) * @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 * 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 * 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 * @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. * Free the mft record of the open inode @ni on the mounted ntfs volume @vol.

View File

@ -123,6 +123,7 @@
#include "mst.h" #include "mst.h"
#include "dir.h" #include "dir.h"
#include "runlist.h" #include "runlist.h"
#include "mft.h"
#include "utils.h" #include "utils.h"
#ifdef NO_NTFS_DEVICE_DEFAULT_IO_OPS #ifdef NO_NTFS_DEVICE_DEFAULT_IO_OPS
@ -954,59 +955,6 @@ static void dump_mft_record(MFT_RECORD *m)
printf("-- End of attributes. --\n"); 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 * make_room_for_attribute - make room for an attribute inside an mft record
* @m: mft record * @m: mft record
@ -3092,8 +3040,17 @@ int main(int argc, char **argv)
Qprintf(" - Done.\n"); Qprintf(" - Done.\n");
} }
Qprintf("Creating NTFS volume structures.\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 * 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 * sequence numbers of each system file to equal the mft record number