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);
|
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);
|
||||||
|
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;
|
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.
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user