Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- --- a/ntfsprogs/mkntfs.c
- +++ b/ntfsprogs/mkntfs.c
- @@ -71,6 +71,7 @@
- #ifdef ENABLE_UUID
- #include <uuid/uuid.h>
- #endif
- +#include <sys/ioctl.h>
- #ifdef HAVE_GETOPT_H
- @@ -146,7 +147,7 @@
- #define basename(name) name
- #endif
- -typedef enum { WRITE_STANDARD, WRITE_BITMAP, WRITE_LOGFILE } WRITE_TYPE;
- +typedef enum { WRITE_STANDARD, WRITE_BITMAP, WRITE_LOGFILE, WRITE_NONE } WRITE_TYPE;
- #ifdef NO_NTFS_DEVICE_DEFAULT_IO_OPS
- #error "No default device io operations! Cannot build mkntfs. \
- @@ -204,8 +205,48 @@ static long long g_mft_zone_end = 0
- static long long g_num_bad_blocks = 0; /* Number of bad clusters */
- static long long *g_bad_blocks = NULL; /* Array of bad clusters */
- +static int backing_fd = 0;
- +static int backing_file_size = 2048 * 1024;
- +static runlist *reserved_runlist = NULL;
- +static s64 reserved_size = 0;
- +
- static struct BITMAP_ALLOCATION *g_allocation = NULL; /* Head of cluster allocations */
- +#define FE_COUNT 8000
- +#define FE_FLAG_LAST (1 << 0)
- +#define FE_FLAG_UNKNOWN (1 << 1)
- +#define FE_FLAG_UNALLOC (1 << 2)
- +#define FE_FLAG_NOALIGN (1 << 8)
- +
- +#define EXTENT_UNKNOWN (FE_FLAG_UNKNOWN | FE_FLAG_UNALLOC | FE_FLAG_NOALIGN)
- +
- +struct fe_s {
- + u64 logical;
- + u64 physical;
- + u64 length;
- + u64 reserved64[2];
- + u32 flags;
- + u32 reserved32[3];
- +};
- +
- +struct fm_s {
- + u64 start;
- + u64 length;
- + u32 flags;
- + u32 mapped_extents;
- + u32 extent_count;
- + u32 reserved;
- +};
- +
- +struct fs_s {
- + struct fm_s fm;
- + struct fe_s fe[FE_COUNT];
- +};
- +
- +struct fs_s extent_map = {};
- +
- +#define FIEMAP _IOWR('f', 11, struct fm_s)
- +
- /**
- * struct mkntfs_options
- */
- @@ -228,6 +269,87 @@ static struct mkntfs_options {
- char *label; /* -L, volume label */
- } opts;
- +static BOOL bitmap_allocate(LCN lcn, s64 length);
- +static BOOL bitmap_deallocate(LCN lcn, s64 length);
- +static runlist * allocate_scattered_clusters(s64 clusters);
- +static void deallocate_scattered_clusters(const runlist *rl);
- +
- +static runlist *make_reserved_runlist(s64 *size)
- +{
- + struct BITMAP_ALLOCATION *p = g_allocation;
- + runlist *rl = NULL;
- + int n = 0;
- + while (p) {
- + n++;
- + p = p->next;
- + }
- + printf("reserved runlist entries: %d\n", n);
- + rl = calloc(sizeof(*rl), n + 1);
- + VCN vcn = 0LL;
- + n = 0;
- + p = g_allocation;
- + while (p) {
- + rl[n].lcn = p->lcn;
- + rl[n].length = p->length;
- + rl[n].vcn = vcn;
- + printf("vcn=%ld lcn=%ld len=%ld\n", vcn, p->lcn, p->length);
- + vcn += p->length;
- + p = p->next;
- + n++;
- + }
- + rl[n].lcn = -1LL;
- + rl[n].length = 0LL;
- + rl[n].vcn = vcn;
- + *size = vcn * g_vol->cluster_size;
- + return rl;
- +}
- +
- +static s64 peek_lcn(s64 size) {
- + s64 mask = g_vol->cluster_size - 1;
- + size = (size + mask) & ~mask;
- + static int initialized = 0;
- +
- + if (initialized == 0) {
- + initialized = 1;
- +
- + // Initialize unallocated space.
- + printf("Initializing available clusters.\n");
- +
- + // Mark everything allocated.
- + bitmap_allocate(0, g_vol->nr_clusters);
- +
- + // Punch holes where we have backing store.
- + for (int i = 0; i < extent_map.fm.mapped_extents; i++) {
- + s64 aligned_start = (extent_map.fe[i].physical + mask) & ~mask;
- + s64 aligned_end = (extent_map.fe[i].physical + extent_map.fe[i].length) & ~mask;
- + s64 length = aligned_end - aligned_start;
- +
- + bitmap_deallocate(
- + aligned_start / g_vol->cluster_size,
- + length / g_vol->cluster_size);
- +
- + if (extent_map.fe[i].flags & FE_FLAG_LAST) {
- + break;
- + }
- + }
- +
- + bitmap_deallocate(0, 8192 / g_vol->cluster_size);
- + reserved_runlist = make_reserved_runlist(&reserved_size);
- + bitmap_allocate(0, 8192 / g_vol->cluster_size);
- + }
- +
- + runlist *rl = allocate_scattered_clusters(size / g_vol->cluster_size);
- +
- + if (rl == NULL) {
- + printf("Failed to alloc disk space: %ld\n", size);
- + return 0;
- + }
- +
- + s64 start_lcn = rl[0].lcn;
- + deallocate_scattered_clusters(rl);
- +
- + return start_lcn;
- +}
- /**
- * mkntfs_license
- @@ -364,7 +486,7 @@ static BOOL bitmap_allocate(LCN lcn, s64
- /* make sure the requested lcns were not allocated */
- if ((q && ((q->lcn + q->length) > lcn))
- || (p && ((lcn + length) > p->lcn))) {
- - ntfs_log_error("Bitmap allocation error\n");
- + ntfs_log_error("Bitmap allocation error (%ld, %ld)\n", lcn, length);
- done = FALSE;
- }
- if (q && ((q->lcn + q->length) == lcn)) {
- @@ -588,12 +710,88 @@ static void mkntfs_init_options(struct m
- opts2->sectors_per_track = -1;
- }
- +static int update_backing_extent_map(int fd)
- +{
- + extent_map.fm.length = ~0ULL;
- + extent_map.fm.flags = 0;
- + extent_map.fm.extent_count = FE_COUNT;
- +
- + if (-1 == ioctl(fd, FIEMAP, &extent_map)) {
- + int err = errno;
- + perror("ioctl(FIEMAP)");
- + return err;
- + }
- +
- + if (1) fprintf(stderr, "ioctl(FIEMAP) returned %lu extents\n", (u64)extent_map.fm.mapped_extents);
- + if (!extent_map.fm.mapped_extents) {
- + return -EINVAL;
- + } else {
- + for (int i = 0; i < extent_map.fm.mapped_extents; i++) {
- +
- + if (1) fprintf(stderr, "log=%lu phy=%lu len=%lu flags=0x%x\n",
- + extent_map.fe[i].logical, extent_map.fe[i].physical,
- + extent_map.fe[i].length, extent_map.fe[i].flags);
- +#if 0
- + u64 phy_blk, ext_len;
- + if (fs.fe[i].flags & EXTENT_UNKNOWN) {
- + } else {
- + phy_blk = fs.fe[i].physical / blksize;
- + ext_len = fs.fe[i].length / blksize;
- + }
- + //handle_extent(ext, sectors_per_block, start_lba);
- +#endif
- +
- + if (extent_map.fe[i].flags & FE_FLAG_LAST) {
- + /*
- + * Hit an ext4 bug in 2.6.29.4, where some FIEMAP calls
- + * had the LAST flag set in the final returned extent,
- + * even though there were *plenty* more extents to be had
- + * from continued FIEMAP calls.
- + *
- + * So, we'll ignore it here, and instead rely on getting
- + * a zero count back from fs.fm.mapped_extents at the end.
- + */
- + if (0) fprintf(stderr, "%s: ignoring LAST bit\n", __func__);
- + //done = 1;
- + }
- +
- + }
- + //fs.fm.start = (fs.fe[i-1].logical + fs.fe[i-1].length);
- + }
- + return 0;
- +}
- +
- +static int backing_file_init(const char *name)
- +{
- + backing_fd = open(name, O_CREAT|O_TRUNC|O_RDWR, 0644);
- + if (backing_fd == -1) {
- + perror("open");
- + return 0;
- + }
- +
- + const char buf[1024] = {0x55};
- + for (int i = 0; i < backing_file_size / 1024; i++) {
- + if (write(backing_fd, buf, sizeof(buf)) == -1) {
- + perror("write");
- + return 0;
- + }
- + }
- + fsync(backing_fd);
- + fdatasync(backing_fd);
- +
- + if (update_backing_extent_map(backing_fd) != 0) {
- + return 0;
- + }
- +
- + return 1;
- +}
- +
- /**
- * mkntfs_parse_options
- */
- static int mkntfs_parse_options(int argc, char *argv[], struct mkntfs_options *opts2)
- {
- - static const char *sopt = "-c:CfFhH:IlL:np:qQs:S:TUvVz:";
- + static const char *sopt = "-c:CfFhH:IlL:np:qQs:S:TUvVz:B:";
- static const struct option lopt[] = {
- { "cluster-size", required_argument, NULL, 'c' },
- { "debug", no_argument, NULL, 'Z' },
- @@ -616,6 +814,7 @@ static int mkntfs_parse_options(int argc
- { "verbose", no_argument, NULL, 'v' },
- { "version", no_argument, NULL, 'V' },
- { "zero-time", no_argument, NULL, 'T' },
- + { "backing-file", required_argument, NULL, 'B' },
- { NULL, 0, NULL, 0 }
- };
- @@ -728,13 +927,22 @@ static int mkntfs_parse_options(int argc
- &opts2->mft_zone_multiplier))
- err++;
- break;
- + case 'B':
- + // Skip initializing all blocks with zeroes.
- + opts2->quick_format = TRUE;
- + if (!backing_file_init(optarg)) {
- + ntfs_log_error("Could not open backing file: %s\n", optarg);
- + err++;
- + }
- + break;
- default:
- if (ntfs_log_parse_option (argv[optind-1]))
- break;
- if (((optopt == 'c') || (optopt == 'H') ||
- (optopt == 'L') || (optopt == 'p') ||
- (optopt == 's') || (optopt == 'S') ||
- - (optopt == 'N') || (optopt == 'z')) &&
- + (optopt == 'N') || (optopt == 'z') ||
- + (optopt == 'B')) &&
- (!optarg)) {
- ntfs_log_error("Option '%s' requires an "
- "argument.\n", argv[optind-1]);
- @@ -904,6 +1112,7 @@ static s64 ntfs_rlwrite(struct ntfs_devi
- return val_len;
- total = 0LL;
- delta = 0LL;
- + if (!val) printf("ntfs_rlwrite: val is NULL\n");
- for (i = 0; rl[i].length; i++) {
- length = rl[i].length * g_vol->cluster_size;
- /* Don't write sparse runs. */
- @@ -939,6 +1148,9 @@ static s64 ntfs_rlwrite(struct ntfs_devi
- bytes_written = mkntfs_logfile_write(dev,
- total, length);
- break;
- + case WRITE_NONE :
- + bytes_written = length;
- + break;
- default :
- bytes_written = dev->d_ops->write(dev,
- val + total, length);
- @@ -966,6 +1178,7 @@ static s64 ntfs_rlwrite(struct ntfs_devi
- return total;
- }
- }
- + if (!val) printf("total=%ld delta=%ld\n", total, delta);
- if (delta) {
- int eo;
- char *b = ntfs_calloc(delta);
- @@ -1511,6 +1724,7 @@ static int insert_positioned_attr_in_mft
- for (i = 0, highest_vcn = 0LL; rl[i].length; i++)
- highest_vcn += rl[i].length;
- /* Does the value fit inside the allocated size? */
- + ntfs_log_error("val_len: %ld vcn_len: %ld\n", val_len, highest_vcn * g_vol->cluster_size);
- if (highest_vcn * g_vol->cluster_size < val_len) {
- ntfs_log_error("BUG: Allocated size is smaller than data size!\n");
- err = -EINVAL;
- @@ -1562,6 +1776,7 @@ static int insert_positioned_attr_in_mft
- a->data_size = cpu_to_sle64(val_len);
- if (name_len)
- memcpy((char*)a + hdr_size, uname, name_len << 1);
- + ntfs_log_error("write data\n");
- if (flags & ATTR_COMPRESSION_MASK) {
- if (flags & ATTR_COMPRESSION_MASK & ~ATTR_IS_COMPRESSED) {
- ntfs_log_error("Unknown compression format. Reverting "
- @@ -1583,10 +1798,18 @@ static int insert_positioned_attr_in_mft
- == const_cpu_to_le32(FILE_LogFile)))
- bw = ntfs_rlwrite(g_vol->dev, rl, val, val_len,
- &inited_size, WRITE_LOGFILE);
- - else
- - bw = ntfs_rlwrite(g_vol->dev, rl, val, val_len,
- - &inited_size, WRITE_STANDARD);
- + else {
- + if (rl == reserved_runlist) {
- + printf("WRITE_NONE\n");
- + bw = ntfs_rlwrite(g_vol->dev, rl, val, val_len,
- + &inited_size, WRITE_NONE);
- + } else {
- + bw = ntfs_rlwrite(g_vol->dev, rl, val, val_len,
- + &inited_size, WRITE_STANDARD);
- + }
- + }
- if (bw != val_len) {
- + ntfs_log_error("bw=%ld val_len=%ld\n", bw, val_len);
- ntfs_log_error("Error writing non-resident attribute "
- "value.\n");
- return -errno;
- @@ -1601,6 +1824,7 @@ static int insert_positioned_attr_in_mft
- /* remove attribute */
- if (err >= 0)
- err = -EIO;
- + ntfs_log_error("bw=%ld val_len=%ld\n", bw, val_len);
- ntfs_log_error("insert_positioned_attr_in_mft_record failed "
- "with error %i.\n", err < 0 ? err : (int)bw);
- }
- @@ -3449,6 +3673,64 @@ static void mkntfs_cleanup(void)
- }
- }
- +#define DEV_FD(dev) (*(int *)dev->d_private)
- +
- +static s64 backing_pwrite(struct ntfs_device *dev, const void *buf, s64 count, s64 offset)
- +{
- + if (offset == 0) {
- + // Write the bootsector directly
- + ssize_t written = pwrite(DEV_FD(dev), buf, 512, 0);
- + (void)written;
- + return count;
- + }
- + // Everything else gets translated into writes to the backing file.
- + for (int i = 0; i < extent_map.fm.mapped_extents; i++) {
- + s64 phy_start = extent_map.fe[i].physical;
- + s64 phy_end = phy_start + extent_map.fe[i].length;
- + s64 delta = offset - phy_start;
- + s64 log_offset = extent_map.fe[i].logical + delta;
- + if (offset >= phy_start && offset < phy_end) {
- + printf("%ld -(%ld)-> %ld\n", offset, delta, log_offset);
- + if (offset + count < phy_end) {
- + return pwrite(backing_fd, buf, count, log_offset);
- + } else {
- + return pwrite(backing_fd, buf, phy_end - offset, log_offset);
- + }
- + }
- + if (extent_map.fe[i].flags & FE_FLAG_LAST)
- + break;
- + }
- + printf("bad write: %ld %ld\n", offset, count);
- + errno = EIO;
- + return -1;
- +}
- +
- +static s64 restricted_pwrite(struct ntfs_device *dev, const void *buf,
- + s64 count, s64 offset)
- +{
- + if (NDevReadOnly(dev)) {
- + errno = EROFS;
- + return -1;
- + }
- +
- + NDevSetDirty(dev);
- + return backing_pwrite(dev, buf, count, offset);
- +}
- +
- +static s64 restricted_write(struct ntfs_device *dev, const void *buf,
- + s64 count)
- +{
- + if (NDevReadOnly(dev)) {
- + errno = EROFS;
- + return -1;
- + }
- + int fd = DEV_FD(dev);
- + off_t offset = lseek(fd, 0, SEEK_CUR);
- +
- + s64 nwritten = restricted_pwrite(dev, buf, count, offset);
- + lseek(fd, nwritten, SEEK_CUR);
- + return nwritten;
- +}
- /**
- * mkntfs_open_partition -
- @@ -3459,12 +3741,17 @@ static BOOL mkntfs_open_partition(ntfs_v
- int i;
- struct stat sbuf;
- unsigned long mnt_flags;
- + struct ntfs_device_operations io_ops;
- + memcpy(&io_ops, &ntfs_device_default_io_ops, sizeof(io_ops));
- +
- + io_ops.write = restricted_write;
- + io_ops.pwrite = restricted_pwrite;
- /*
- * Allocate and initialize an ntfs device structure and attach it to
- * the volume.
- */
- - vol->dev = ntfs_device_alloc(opts.dev_name, 0, &ntfs_device_default_io_ops, NULL);
- + vol->dev = ntfs_device_alloc(opts.dev_name, 0, &io_ops, NULL);
- if (!vol->dev) {
- ntfs_log_perror("Could not create device");
- goto done;
- @@ -3912,9 +4199,9 @@ static BOOL mkntfs_initialize_bitmaps(vo
- return FALSE;
- g_rl_mft_bmp[0].vcn = 0LL;
- - /* Mft bitmap is right after $Boot's data. */
- - i = (8192 + g_vol->cluster_size - 1) / g_vol->cluster_size;
- + i = peek_lcn(g_vol->cluster_size);
- g_rl_mft_bmp[0].lcn = i;
- + printf("MFT bitmap placed at LCN %ld\n", i);
- /*
- * Size is always one cluster, even though valid data size and
- * initialized data size are only 8 bytes.
- @@ -3937,14 +4224,8 @@ static BOOL mkntfs_initialize_rl_mft(voi
- /* If user didn't specify the mft lcn, determine it now. */
- if (!g_mft_lcn) {
- - /*
- - * We start at the higher value out of 16kiB and just after the
- - * mft bitmap.
- - */
- - g_mft_lcn = g_rl_mft_bmp[0].lcn + g_rl_mft_bmp[0].length;
- - if (g_mft_lcn * g_vol->cluster_size < 16 * 1024)
- - g_mft_lcn = (16 * 1024 + g_vol->cluster_size - 1) /
- - g_vol->cluster_size;
- + g_mft_lcn = peek_lcn(g_mft_size);
- + printf("MFT placed at LCN %lld\n", g_mft_lcn);
- }
- ntfs_log_debug("$MFT logical cluster number = 0x%llx\n", g_mft_lcn);
- /* Determine MFT zone size. */
- @@ -3986,9 +4267,8 @@ static BOOL mkntfs_initialize_rl_mft(voi
- g_rl_mft[1].length = 0LL;
- /* Allocate clusters for mft. */
- bitmap_allocate(g_mft_lcn,j);
- - /* Determine mftmirr_lcn (middle of volume). */
- - g_mftmirr_lcn = (opts.num_sectors * opts.sector_size >> 1)
- - / g_vol->cluster_size;
- + g_mftmirr_lcn = peek_lcn(g_mft_size);
- + printf("MFT mirror at LCN %lld\n", g_mftmirr_lcn);
- ntfs_log_debug("$MFTMirr logical cluster number = 0x%llx\n",
- g_mftmirr_lcn);
- /* Create runlist for mft mirror. */
- @@ -4015,6 +4295,7 @@ static BOOL mkntfs_initialize_rl_mft(voi
- g_logfile_lcn = g_mftmirr_lcn + j;
- ntfs_log_debug("$LogFile logical cluster number = 0x%llx\n",
- g_logfile_lcn);
- + printf("LogFile at LCN %lld\n", g_logfile_lcn);
- return (done);
- }
- @@ -4032,7 +4313,8 @@ static BOOL mkntfs_initialize_rl_logfile
- return FALSE;
- - volume_size = g_vol->nr_clusters << g_vol->cluster_size_bits;
- + //volume_size = g_vol->nr_clusters << g_vol->cluster_size_bits;
- + volume_size = backing_file_size;
- g_rl_logfile[0].vcn = 0LL;
- g_rl_logfile[0].lcn = g_logfile_lcn;
- @@ -4078,6 +4360,7 @@ static BOOL mkntfs_initialize_rl_logfile
- ~(g_vol->cluster_size - 1);
- ntfs_log_debug("$LogFile (journal) size = %ikiB\n",
- g_logfile_size / 1024);
- + printf("LogFile size %d\n", g_logfile_size);
- /*
- * FIXME: The 256kiB limit is arbitrary. Should find out what the real
- * minimum requirement for Windows is so it doesn't blue screen.
- @@ -4118,8 +4401,10 @@ static BOOL mkntfs_initialize_rl_boot(vo
- g_rl_boot[0].length = j;
- g_rl_boot[1].lcn = -1LL;
- g_rl_boot[1].length = 0LL;
- +
- /* Allocate clusters for $Boot. */
- - return (bitmap_allocate(0,j));
- + return 1; // Already allocated.
- + //return (bitmap_allocate(0,j));
- }
- /**
- @@ -4445,7 +4730,7 @@ static BOOL mkntfs_create_root_structure
- le32 file_attrs;
- m = (MFT_RECORD*)(g_buf + i * g_vol->mft_record_size);
- - if (i < 16 || i > 23) {
- + if (i < 17 || i > 23) {
- m->mft_record_number = cpu_to_le32(i);
- m->flags |= MFT_RECORD_IN_USE;
- ntfs_bit_set(g_mft_bitmap, 0LL + i, 1);
- @@ -4870,6 +5155,7 @@ static BOOL mkntfs_create_root_structure
- strerror(-err));
- return FALSE;
- }
- +
- /* NTFS reserved system files (mft records 0xc-0xf) */
- for (i = 0xc; i < 0x10; i++) {
- ntfs_log_verbose("Creating system file (mft record 0x%x)\n", i);
- @@ -4886,6 +5172,7 @@ static BOOL mkntfs_create_root_structure
- return FALSE;
- }
- }
- +
- /* create systemfiles for ntfs volumes (3.1) */
- /* starting with file 24 (ignoring file 16-23) */
- extend_flags = FILE_ATTR_HIDDEN | FILE_ATTR_SYSTEM |
- @@ -4956,6 +5243,29 @@ static BOOL mkntfs_create_root_structure
- strerror(-err));
- return FALSE;
- }
- +
- +#if 1
- + /* Add entry for reserved space */
- + ntfs_log_error("Creating Reserved %ld\n", reserved_size);
- + int entry = 16;
- + m = (MFT_RECORD*)(g_buf + entry * g_vol->mft_record_size);
- + err = add_attr_data_positioned(m, "$Rsv", 0, CASE_SENSITIVE,
- + const_cpu_to_le16(0), reserved_runlist,
- + (const u8*)NULL, reserved_size);
- + if (!err)
- + err = create_hardlink(g_index_block, root_ref, m,
- + MK_LE_MREF(entry, entry),
- + reserved_size, reserved_size,
- + FILE_ATTR_HIDDEN | FILE_ATTR_SYSTEM, 0, 0,
- + "Reserved", FILE_NAME_WIN32_AND_DOS);
- + if (err < 0) {
- + free(bs);
- + ntfs_log_error("Couldn't create $Reserved: %s\n", strerror(-err));
- + return FALSE;
- + }
- +#endif
- +
- +
- return TRUE;
- }
Advertisement
Add Comment
Please, Sign In to add comment