diff --git a/ChangeLog b/ChangeLog index ac100332..a81e35f1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -100,6 +100,20 @@ - Fix stupid bug in libntfs/bitmap.c::ntfs_bitmap_set_bits_in_run() which caused bits to not be cleared or set if the first bit in the run was not a multiple of eight. (Anton) + - Change volume mounting (actually device opening) to happen with + O_EXCL bit set so at least on Linux no one can change the device + block size under our feet. (Anton) + - Change volume mounting and mkntfs to set the device block size to the + sector size using BLKBSZSET ioctl (Linux only). This should be + optimal for performance and should fixes the bug of not being able to + create the backup boot sector if the number of sectors on the device + is odd, the sector size is 512 bytes, and the kernel is 2.4. (Anton) + - Enforce cluster size, mft record size, and index record size to be at + least equal to the sector size and verify they are still valid and in + particular display a warning message if the volume will not be + mountable by the kernel driver (it requires mft record size and index + record size to be below or equal to the system page size which we + determine using sysconf()). (Anton) 10/10/2005 - 1.12.1 - Minor fix to location of mount.ntfs-fuse and mkfs.ntfs. diff --git a/NEWS b/NEWS index c5fa1a32..0f51ea3a 100644 --- a/NEWS +++ b/NEWS @@ -18,30 +18,4 @@ changing the file size and can read/write/add/remove named data streams via "file:stream" interface and list them via "ntfs.streams.list" extended attribute (this only if xattr support is enabled). (Yura Pakhuchiy) -Attribute resize code for normal and sparse files is completed. Thus, ntfscp -should always successfully overwrite any normal or sparse file even if file -size is changed. (Yura Pakhuchiy) - Moved back from BitKeeper to CVS on SF.net. - -ntfsprogs should now work completely on Windows 2000 and XP (Cygwin). -mkntfs does not create bootable volumes when on Windows. Volumes are locked -when using a R/W utility in order to prevent data corruption. (Yuval Fledel, -Anton Altaparmakov) - -ntfsinfo has been extended and now provides much more detailed information as -well as being able to resolve a path/filename instead of requiring the inode -number. (Yuval Fledel, Anton Altaparmakov) - -mkntfs now creates bootable ntfs volumes so you can install Windows on an -ntfs volume created with mkntfs and Windows will manage to boot afterwards. - -ntfsresize now supports relocation which generally means you are now able to -resize to any size you like (as long as there is enough free space). Note, -this modifies the command line options a little as well as the returned output -so applications using ntfsresize might need modifications before they will -work with the updated ntfsresize. (Szakacsits Szabolcs) - -ntfsprogs ("make libs" only) now compiles on FreeBSD, NetBSD, Windows (Cygwin), -and DOS (DJGPP). Thanks to Christophe Grenier for DOS and FreeBSD testing -and fixes and to Lode Leroy for Windows testing and fixes. diff --git a/configure.ac b/configure.ac index 4e0b44b8..269655aa 100644 --- a/configure.ac +++ b/configure.ac @@ -358,7 +358,7 @@ AC_FUNC_UTIME_NULL AC_FUNC_VPRINTF AC_CHECK_FUNCS([atexit dup2 fdatasync getopt_long hasmntopt mbsinit memmove \ memset realpath regcomp setlocale setxattr strcasecmp strchr strdup \ - strerror strnlen strtol strtoul utime]) + strerror strnlen strtol strtoul sysconf utime]) # Makefiles to be created by configure. AC_CONFIG_FILES([ diff --git a/include/ntfs/device.h b/include/ntfs/device.h index ecadb070..304445ff 100644 --- a/include/ntfs/device.h +++ b/include/ntfs/device.h @@ -1,7 +1,7 @@ /* * device.h - Exports for low level device io. Part of the Linux-NTFS project. * - * Copyright (c) 2000-2004 Anton Altaparmakov + * Copyright (c) 2000-2006 Anton Altaparmakov * * This program/include file is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as published @@ -118,5 +118,6 @@ extern s64 ntfs_device_partition_start_sector_get(struct ntfs_device *dev); extern int ntfs_device_heads_get(struct ntfs_device *dev); extern int ntfs_device_sectors_per_track_get(struct ntfs_device *dev); extern int ntfs_device_sector_size_get(struct ntfs_device *dev); +extern int ntfs_device_block_size_set(struct ntfs_device *dev, int block_size); #endif /* defined _NTFS_DEVICE_H */ diff --git a/include/ntfs/device_io.h b/include/ntfs/device_io.h index 76e84c79..6665b680 100644 --- a/include/ntfs/device_io.h +++ b/include/ntfs/device_io.h @@ -1,7 +1,7 @@ /* * device_io.h - Exports for default device io. Part of the Linux-NTFS project. * - * Copyright (c) 2000-2004 Anton Altaparmakov + * Copyright (c) 2000-2006 Anton Altaparmakov * * This program/include file is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as published @@ -36,7 +36,7 @@ #else /* __CYGWIN32__ */ #ifndef HDIO_GETGEO -# define HDIO_GETGEO 0x10000301 +# define HDIO_GETGEO 0x301 /** * struct hd_geometry - */ @@ -48,13 +48,16 @@ struct hd_geometry { }; #endif #ifndef BLKGETSIZE -# define BLKGETSIZE 0x10001260 +# define BLKGETSIZE 0x1260 #endif #ifndef BLKSSZGET -# define BLKSSZGET 0x10001268 +# define BLKSSZGET 0x1268 #endif #ifndef BLKGETSIZE64 -# define BLKGETSIZE64 0x10001272 +# define BLKGETSIZE64 0x80041272 +#endif +#ifndef BLKBSZSET +# define BLKBSZSET 0x40041271 #endif /* On Cygwin; use Win32 low level device operations. */ diff --git a/libntfs/bootsect.c b/libntfs/bootsect.c index 3b625ef2..93d95ff4 100644 --- a/libntfs/bootsect.c +++ b/libntfs/bootsect.c @@ -1,7 +1,7 @@ /** * bootsect.c - Boot sector handling code. Part of the Linux-NTFS project. * - * Copyright (c) 2000-2005 Anton Altaparmakov + * Copyright (c) 2000-2006 Anton Altaparmakov * Copyright (c) 2005 Yura Pakhuchiy * * This program/include file is free software; you can redistribute it and/or @@ -270,4 +270,3 @@ int ntfs_boot_sector_parse(ntfs_volume *vol, const NTFS_BOOT_SECTOR *bs) vol->mftmirr_size = vol->cluster_size / vol->mft_record_size; return 0; } - diff --git a/libntfs/device.c b/libntfs/device.c index 7f2689bf..968c2076 100644 --- a/libntfs/device.c +++ b/libntfs/device.c @@ -1,7 +1,7 @@ /** * device.c - Low level device io functions. Part of the Linux-NTFS project. * - * Copyright (c) 2004 Anton Altaparmakov + * Copyright (c) 2004-2006 Anton Altaparmakov * * This program/include file is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as published @@ -50,6 +50,9 @@ #ifdef HAVE_SYS_IOCTL_H #include #endif +#ifdef HAVE_SYS_MOUNT_H +#include +#endif #ifdef HAVE_LINUX_FD_H #include #endif @@ -75,6 +78,9 @@ #if defined(linux) && defined(_IO) && !defined(BLKSSZGET) # define BLKSSZGET _IO(0x12,104) /* Get device sector size in bytes. */ #endif +#if defined(linux) && defined(_IO) && !defined(BLKBSZSET) +# define BLKBSZSET _IOW(0x12,113,size_t) /* Set device block size in bytes. */ +#endif /** * ntfs_device_alloc - allocate an ntfs device structure and pre-initialize it @@ -641,6 +647,7 @@ int ntfs_device_sectors_per_track_get(struct ntfs_device *dev) #endif return -1; } + /** * ntfs_device_sector_size_get - get sector size of a device * @dev: open device @@ -650,8 +657,8 @@ int ntfs_device_sectors_per_track_get(struct ntfs_device *dev) * * The following error codes are defined: * EINVAL Input parameter error - * EOPNOTSUPP System does not support HDIO_GETGEO ioctl - * ENOTTY @dev is a file or a device not supporting HDIO_GETGEO + * EOPNOTSUPP System does not support BLKSSZGET ioctl + * ENOTTY @dev is a file or a device not supporting BLKSSZGET */ int ntfs_device_sector_size_get(struct ntfs_device *dev) { @@ -674,3 +681,37 @@ int ntfs_device_sector_size_get(struct ntfs_device *dev) return -1; } +/** + * ntfs_device_block_size_set - set block size of a device + * @dev: open device + * @block_size: block size to set @dev to + * + * On success, return 0. + * On error return -1 with errno set to the error code. + * + * The following error codes are defined: + * EINVAL Input parameter error + * EOPNOTSUPP System does not support HDIO_GETGEO ioctl + * ENOTTY @dev is a file or a device not supporting HDIO_GETGEO + */ +int ntfs_device_block_size_set(struct ntfs_device *dev, int block_size) +{ + if (!dev) { + errno = EINVAL; + return -1; + } +#ifdef BLKBSZSET + { + size_t s_block_size = block_size; + if (!dev->d_ops->ioctl(dev, BLKBSZSET, &s_block_size)) { + ntfs_log_debug("Used BLKBSZSET to set block size to " + "%d bytes\n", block_size); + return 0; + } + } +#else + errno = EOPNOTSUPP; +#endif + return -1; +} + diff --git a/libntfs/gnome-vfs-method.c b/libntfs/gnome-vfs-method.c index 49def0a7..28e5d8b7 100644 --- a/libntfs/gnome-vfs-method.c +++ b/libntfs/gnome-vfs-method.c @@ -3,7 +3,7 @@ * libntfs. Part of the Linux-NTFS project. * * Copyright (c) 2003 Jan Kratochvil - * Copyright (c) 2003-2005 Anton Altaparmakov + * Copyright (c) 2003-2006 Anton Altaparmakov * * This program/include file is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as published @@ -659,7 +659,7 @@ static GnomeVFSResult libntfs_gnomevfs_seek(GnomeVFSMethod *method, static GnomeVFSResult libntfs_gnomevfs_tell(GnomeVFSMethod *method, GnomeVFSMethodHandle *method_handle, - GnomeVFSFileOffset *offset_return) + GnomeVFSFileSize *offset_return) { GnomeVFSResult errvfsresult; struct libntfs_file *libntfs_file; @@ -676,7 +676,7 @@ static GnomeVFSResult libntfs_gnomevfs_tell(GnomeVFSMethod *method, return errvfsresult; *offset_return = libntfs_file->pos; - g_assert(*offset_return == libntfs_file->pos); + g_assert((s64)*offset_return == libntfs_file->pos); return errvfsresult; } diff --git a/libntfs/unix_io.c b/libntfs/unix_io.c index 0b702ba1..6ff72e2b 100644 --- a/libntfs/unix_io.c +++ b/libntfs/unix_io.c @@ -1,7 +1,7 @@ /** * unix_io.c - Unix style disk io functions. Part of the Linux-NTFS project. * - * Copyright (c) 2000-2003 Anton Altaparmakov + * Copyright (c) 2000-2006 Anton Altaparmakov * * This program/include file is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as published @@ -60,12 +60,13 @@ #include "device.h" #include "logging.h" -#if defined(linux) && defined(_IO) && !defined(BLKGETSIZE) -# define BLKGETSIZE _IO(0x12,96) /* Get device size in 512byte blocks. */ -#endif - #define DEV_FD(dev) (*(int *)dev->d_private) +/* Define to nothing if not present on this system. */ +#ifndef O_EXCL +# define O_EXCL 0 +#endif + /** * ntfs_device_unix_io_open - Open a device and lock it exclusively * @dev: @@ -86,8 +87,12 @@ static int ntfs_device_unix_io_open(struct ntfs_device *dev, int flags) } if (!(dev->d_private = malloc(sizeof(int)))) return -1; - /* Open the device/file obtaining the file descriptor. */ - if ((*(int *)dev->d_private = open(dev->d_name, flags)) == -1) { + /* + * Open the device/file obtaining the file descriptor for exclusive + * access. + */ + *(int*)dev->d_private = open(dev->d_name, flags | O_EXCL); + if (*(int*)dev->d_private == -1) { err = errno; goto err_out; } diff --git a/libntfs/volume.c b/libntfs/volume.c index d3f4d169..9e08c24c 100644 --- a/libntfs/volume.c +++ b/libntfs/volume.c @@ -1,7 +1,7 @@ /** * volume.c - NTFS volume handling code. Part of the Linux-NTFS project. * - * Copyright (c) 2000-2005 Anton Altaparmakov + * Copyright (c) 2000-2006 Anton Altaparmakov * Copyright (c) 2002-2005 Szabolcs Szakacsits * Copyright (c) 2004-2005 Richard Russon * @@ -467,7 +467,12 @@ ntfs_volume *ntfs_volume_startup(struct ntfs_device *dev, unsigned long flags) } free(bs); bs = NULL; - + /* Now set the device block size to the sector size. */ + if (ntfs_device_block_size_set(vol->dev, vol->sector_size)) + ntfs_log_debug("Failed to set the device block size to the " + "sector size. This may affect performance " + "but should be harmless otherwise. Error: " + "%s\n", strerror(errno)); /* * We now initialize the cluster allocator. * diff --git a/libntfs/win32_io.c b/libntfs/win32_io.c index a24abb3e..c7a3e8e8 100644 --- a/libntfs/win32_io.c +++ b/libntfs/win32_io.c @@ -4,7 +4,7 @@ * Part of the Linux-NTFS project. * * Copyright (c) 2003-2004 Lode Leroy - * Copyright (c) 2003-2005 Anton Altaparmakov + * Copyright (c) 2003-2006 Anton Altaparmakov * Copyright (c) 2004-2005 Yuval Fledel * * This program/include file is free software; you can redistribute it and/or @@ -1433,6 +1433,12 @@ static int ntfs_device_win32_ioctl(struct ntfs_device *dev, int request, case BLKSSZGET: ntfs_log_debug("BLKSSZGET detected.\n"); return ntfs_win32_blksszget(dev, (int *)argp); +#endif +#ifdef BLKBSZSET + case BLKBSZSET: + ntfs_log_debug("BLKBSZSET detected.\n"); + /* Nothing to do on Windows. */ + return 0; #endif default: ntfs_log_debug("unimplemented ioctl %d.\n", request); diff --git a/ntfsprogs/mkntfs.8.in b/ntfsprogs/mkntfs.8.in index 85662599..4da7b1de 100644 --- a/ntfsprogs/mkntfs.8.in +++ b/ntfsprogs/mkntfs.8.in @@ -271,26 +271,6 @@ and exit. \fB\-h\fR, \fB\-\-help\fR Show a list of options with a brief description of each one. .SH BUGS -.B mkntfs -writes the backup boot sector to the last sector of the block -.I device -being formatted. However, current versions of the Linux kernel (all versions -up to and including todays 2.4.18) either only report an even number of sectors -when the sector size is below 1024 bytes, which is the case for most hard -drives today (512 bytes sector size) or they return the correct number but -accessing the last sector fails. Either way, this means that when a partition -has an odd number of 512\-byte sectors, the last sector is either not reported -to us at all or it is not writable by us and hence the created NTFS volume -will either have the backup boot sector placed one sector ahead of where it -should be or it cannot be written at all. For this reason, -.B mkntfs -marks the NTFS volume dirty, so that when you reboot into Windows, check disk -runs automatically and creates a copy of the backup boot sector in the correct -location. This also has the benefit of catching any bugs in -.B mkntfs -as check disk would find any corrupt structures and repair them, as well as -report them. -.sp If you find a bug please send an email describing the problem to the development team: .br diff --git a/ntfsprogs/mkntfs.c b/ntfsprogs/mkntfs.c index b6c1c6d4..ce8d08ae 100644 --- a/ntfsprogs/mkntfs.c +++ b/ntfsprogs/mkntfs.c @@ -171,7 +171,7 @@ runlist *g_rl_boot = NULL; runlist *g_rl_bad = NULL; INDEX_ALLOCATION *g_index_block = NULL; ntfs_volume *g_vol = NULL; -int g_mft_size = 0; /* The bigger of 16kB & one cluster */ +int g_mft_size = 0; long long g_mft_lcn = 0; /* lcn of $MFT, $DATA attribute */ long long g_mftmirr_lcn = 0; /* lcn of $MFTMirr, $DATA */ long long g_logfile_lcn = 0; /* lcn of $LogFile, $DATA */ @@ -3457,8 +3457,10 @@ static BOOL mkntfs_open_partition(ntfs_volume *vol) } ntfs_log_warning("mkntfs forced anyway.\n"); #ifdef HAVE_LINUX_MAJOR_H - } else if ((IDE_DISK_MAJOR(MAJOR(sbuf.st_rdev)) && MINOR(sbuf.st_rdev) % 64 == 0) || - (SCSI_DISK_MAJOR(MAJOR(sbuf.st_rdev)) && MINOR(sbuf.st_rdev) % 16 == 0)) { + } else if ((IDE_DISK_MAJOR(MAJOR(sbuf.st_rdev)) && + MINOR(sbuf.st_rdev) % 64 == 0) || + (SCSI_DISK_MAJOR(MAJOR(sbuf.st_rdev)) && + MINOR(sbuf.st_rdev) % 16 == 0)) { ntfs_log_error("%s is entire device, not just one partition.\n", vol->dev->d_name); if (!opts.force) { ntfs_log_error("Refusing to make a filesystem here!\n"); @@ -3484,12 +3486,13 @@ done: } /** - * mkntfs_override_phys_params - + * mkntfs_override_vol_params - */ -static BOOL mkntfs_override_phys_params(ntfs_volume *vol) +static BOOL mkntfs_override_vol_params(ntfs_volume *vol) { - int i; s64 volume_size; + long page_size; + int i; BOOL winboot = TRUE; /* If user didn't specify the sector size, determine it now. */ @@ -3503,7 +3506,6 @@ static BOOL mkntfs_override_phys_params(ntfs_volume *vol) opts.sector_size = 512; } } - /* Validate sector size. */ if ((opts.sector_size - 1) & opts.sector_size) { ntfs_log_error("The sector size is invalid. It must be a " @@ -3516,10 +3518,17 @@ static BOOL mkntfs_override_phys_params(ntfs_volume *vol) return FALSE; } ntfs_log_debug("sector size = %ld bytes\n", opts.sector_size); - + /* Now set the device block size to the sector size. */ + if (ntfs_device_block_size_set(vol->dev, opts.sector_size)) + ntfs_log_debug("Failed to set the device block size to the " + "sector size. This may cause problems when " + "creating the backup boot sector and also may " + "affect performance but should be harmless " + "otherwise. Error: %s\n", strerror(errno)); /* If user didn't specify the number of sectors, determine it now. */ if (opts.num_sectors < 0) { - opts.num_sectors = ntfs_device_size_get(vol->dev, opts.sector_size); + opts.num_sectors = ntfs_device_size_get(vol->dev, + opts.sector_size); if (opts.num_sectors <= 0) { ntfs_log_error("Couldn't determine the size of %s. " "Please specify the number of sectors " @@ -3528,8 +3537,7 @@ static BOOL mkntfs_override_phys_params(ntfs_volume *vol) } } ntfs_log_debug("number of sectors = %lld (0x%llx)\n", opts.num_sectors, - opts.num_sectors); - + opts.num_sectors); /* * Reserve the last sector for the backup boot sector unless the * sector size is less than 512 bytes in which case reserve 512 bytes @@ -3539,10 +3547,10 @@ static BOOL mkntfs_override_phys_params(ntfs_volume *vol) if (opts.sector_size < 512) i = 512 / opts.sector_size; opts.num_sectors -= i; - /* If user didn't specify the partition start sector, determine it. */ if (opts.part_start_sect < 0) { - opts.part_start_sect = ntfs_device_partition_start_sector_get(vol->dev); + opts.part_start_sect = ntfs_device_partition_start_sector_get( + vol->dev); if (opts.part_start_sect < 0) { ntfs_log_warning("The partition start sector was not " "specified for %s and it could not be obtained " @@ -3563,10 +3571,10 @@ static BOOL mkntfs_override_phys_params(ntfs_volume *vol) "4294967295 (2^32-1).\n"); return FALSE; } - /* If user didn't specify the sectors per track, determine it now. */ if (opts.sectors_per_track < 0) { - opts.sectors_per_track = ntfs_device_sectors_per_track_get(vol->dev); + opts.sectors_per_track = ntfs_device_sectors_per_track_get( + vol->dev); if (opts.sectors_per_track < 0) { ntfs_log_warning("The number of sectors per track was " "not specified for %s and it could not be " @@ -3587,7 +3595,6 @@ static BOOL mkntfs_override_phys_params(ntfs_volume *vol) "is 65535.\n"); return FALSE; } - /* If user didn't specify the number of heads, determine it now. */ if (opts.heads < 0) { opts.heads = ntfs_device_heads_get(vol->dev); @@ -3610,17 +3617,14 @@ static BOOL mkntfs_override_phys_params(ntfs_volume *vol) ntfs_log_error("Invalid number of heads. Maximum is 65535.\n"); return FALSE; } - volume_size = opts.num_sectors * opts.sector_size; - /* Validate volume size. */ if (volume_size < (1 << 20)) { /* 1MiB */ - ntfs_log_error("Device is too small (%llikiB). Minimum NTFS " - "volume size is 1MiB.\n", volume_size / 1024); + ntfs_log_error("Device is too small (%llikiB). Minimum NTFS " + "volume size is 1MiB.\n", volume_size / 1024); return FALSE; } ntfs_log_debug("volume size = %llikiB\n", volume_size / 1024); - /* If user didn't specify the cluster size, determine it now. */ if (!vol->cluster_size) { if (volume_size <= 512LL << 20) /* <= 512MB */ @@ -3643,28 +3647,29 @@ static BOOL mkntfs_override_phys_params(ntfs_volume *vol) vol->cluster_size <<= 1; if (vol->cluster_size > 65535) { ntfs_log_error("Device is too large to hold an " - "NTFS volume (maximum size is 256TiB).\n"); + "NTFS volume (maximum size is " + "256TiB).\n"); return FALSE; } } ntfs_log_quiet("Cluster size has been automatically set to %d " - "bytes.\n", vol->cluster_size); + "bytes.\n", vol->cluster_size); } - /* Validate cluster size. */ if (vol->cluster_size & (vol->cluster_size - 1)) { ntfs_log_error("The cluster size is invalid. It must be a " - "power of two, e.g. 1024, 4096.\n"); + "power of two, e.g. 1024, 4096.\n"); return FALSE; } if (vol->cluster_size < (u32)opts.sector_size) { ntfs_log_error("The cluster size is invalid. It must be equal " - "to, or larger than, the sector size.\n"); + "to, or larger than, the sector size.\n"); return FALSE; } if (vol->cluster_size > 128 * (u32)opts.sector_size) { ntfs_log_error("The cluster size is invalid. It cannot be " - "more that 128 times the size of the sector size.\n"); + "more that 128 times the size of the sector " + "size.\n"); return FALSE; } if (vol->cluster_size > 65536) { @@ -3672,60 +3677,109 @@ static BOOL mkntfs_override_phys_params(ntfs_volume *vol) "cluster size is 65536 bytes (64kiB).\n"); return FALSE; } - vol->cluster_size_bits = ffs(vol->cluster_size) - 1; - ntfs_log_debug("cluster size = %u bytes\n", (unsigned int)vol->cluster_size); + ntfs_log_debug("cluster size = %u bytes\n", + (unsigned int)vol->cluster_size); if (vol->cluster_size > 4096) { if (opts.enable_compression) { if (!opts.force) { ntfs_log_error("Windows cannot use compression " - "when the cluster size is larger than " - "4096 bytes.\n"); + "when the cluster size is " + "larger than 4096 bytes.\n"); return FALSE; } opts.enable_compression = 0; } ntfs_log_warning("Windows cannot use compression when the " - "cluster size is larger than 4096 bytes. Compression " - "has been disabled for this volume.\n"); + "cluster size is larger than 4096 bytes. " + "Compression has been disabled for this " + "volume.\n"); } - vol->nr_clusters = volume_size / vol->cluster_size; - /* * Check the cluster_size and num_sectors for consistency with * sector_size and num_sectors. And check both of these for consistency * with volume_size. */ - if ((vol->nr_clusters != ((opts.num_sectors * opts.sector_size) / vol->cluster_size) || - (volume_size / opts.sector_size) != opts.num_sectors || - (volume_size / vol->cluster_size) != vol->nr_clusters)) { + if ((vol->nr_clusters != ((opts.num_sectors * opts.sector_size) / + vol->cluster_size) || + (volume_size / opts.sector_size) != opts.num_sectors || + (volume_size / vol->cluster_size) != + vol->nr_clusters)) { /* XXX is this code reachable? */ - ntfs_log_error("Illegal combination of volume/cluster/sector size and/or cluster/sector number.\n"); + ntfs_log_error("Illegal combination of volume/cluster/sector " + "size and/or cluster/sector number.\n"); return FALSE; } - ntfs_log_debug("number of clusters = %llu (0x%llx)\n", vol->nr_clusters, vol->nr_clusters); - + ntfs_log_debug("number of clusters = %llu (0x%llx)\n", + vol->nr_clusters, vol->nr_clusters); /* Number of clusters must fit within 32 bits (Win2k limitation). */ if (vol->nr_clusters >> 32) { if (vol->cluster_size >= 65536) { ntfs_log_error("Device is too large to hold an NTFS " - "volume (maximum size is 256TiB).\n"); + "volume (maximum size is 256TiB).\n"); return FALSE; } ntfs_log_error("Number of clusters exceeds 32 bits. Please " - "try again with a larger\ncluster size or leave the " - "cluster size unspecified and the smallest possible " - "cluster size for the size of the device will be used.\n"); + "try again with a larger\ncluster size or " + "leave the cluster size unspecified and the " + "smallest possible cluster size for the size " + "of the device will be used.\n"); return FALSE; } - + page_size = sysconf(_SC_PAGESIZE); + if (page_size < 0) + page_size = sysconf(_SC_PAGE_SIZE); + if (page_size >= 0) + ntfs_log_debug("System page size is %li bytes.\n", page_size); + else { + ntfs_log_warning("Failed to determine system page size. " + "Assuming safe default of 4096 bytes.\n"); + page_size = 4096; + } + /* + * Set the mft record size. By default this is 1024 but it has to be + * at least as big as a sector and not bigger than a page on the system + * or the NTFS kernel driver will not be able to mount the volume. + * TODO: The mft record size should be user specifiable just like the + * "inode size" can be specified on other Linux/Unix file systems. + */ + vol->mft_record_size = 1024; + if (vol->mft_record_size < vol->sector_size) + vol->mft_record_size = vol->sector_size; + if (vol->mft_record_size > (unsigned long)page_size) + ntfs_log_warning("Mft record size (%u bytes) exceeds system " + "page size (%li bytes). You will not be able " + "to mount this volume using the NTFS kernel " + "driver.\n", (unsigned)vol->mft_record_size, + page_size); + vol->mft_record_size_bits = ffs(vol->mft_record_size) - 1; + ntfs_log_debug("mft record size = %u bytes\n", + (unsigned)vol->mft_record_size); + /* + * Set the index record size. By default this is 4096 but it has to be + * at least as big as a sector and not bigger than a page on the system + * or the NTFS kernel driver will not be able to mount the volume. + * FIXME: Should we make the index record size to be user specifiable? + */ + vol->indx_record_size = 4096; + if (vol->indx_record_size < vol->sector_size) + vol->indx_record_size = vol->sector_size; + if (vol->indx_record_size > (unsigned long)page_size) + ntfs_log_warning("Index record size (%u bytes) exceeds system " + "page size (%li bytes). You will not be able " + "to mount this volume using the NTFS kernel " + "driver.\n", vol->indx_record_size, page_size); + vol->indx_record_size_bits = ffs(vol->indx_record_size) - 1; + ntfs_log_debug("index record size = %u bytes\n", + (unsigned)vol->indx_record_size); if (!winboot) { ntfs_log_warning("To boot from a device, Windows needs the " - "'partition start sector', the 'sectors per track' and " - "the 'number of heads' to be set.\n"); + "'partition start sector', the 'sectors per " + "track' and the 'number of heads' to be " + "set.\n"); ntfs_log_warning("Windows will not be able to boot from this " - "device.\n"); + "device.\n"); } return TRUE; } @@ -3759,6 +3813,11 @@ static BOOL mkntfs_initialize_bitmaps(void) * Determine mft_size: (16 (1.2) or 27 (3.0+) mft records) or * one cluster, whichever is bigger. */ + if (g_vol->major_ver >= 3) + g_mft_size = 27; + else + g_mft_size = 16; + g_mft_size *= g_vol->mft_record_size; g_mft_size = ((16 + 11 * (g_vol->major_ver >= 3)) * g_vol->mft_record_size); if (g_mft_size < (s32)g_vol->cluster_size) @@ -4254,16 +4313,17 @@ static int create_backup_boot_sector(u8 *buff) s = strerror(e); else s = "unknown error"; - if (bw != -1LL || (bw == -1LL && e != ENOSPC)) { + /* At least some 2.4 kernels return EIO instead of ENOSPC. */ + if (bw != -1LL || (bw == -1LL && e != ENOSPC && e != EIO)) { ntfs_log_critical("Couldn't write backup boot sector: %s\n", s); return -1; } bb_err: ntfs_log_error("Couldn't write backup boot sector. This is due to a " - "limitation in the\nLinux kernel. This is not " - "a major problem as Windows check disk will " - "create the\nbackup boot sector when it " - "is run on your next boot into Windows.\n"); + "limitation in the\nLinux kernel. This is not a major " + "problem as Windows check disk will create the\n" + "backup boot sector when it is run on your next boot " + "into Windows.\n"); return -1; } @@ -4653,20 +4713,17 @@ static BOOL mkntfs_create_root_structures(void) ntfs_log_error("Couldn't create $Boot: %s\n", strerror(-err)); return FALSE; } - if (create_backup_boot_sector((u8*)bs)) { /* - * Pre-2.6 kernels couldn't access the last sector - * if it was odd hence we schedule chkdsk to create it. + * Pre-2.6 kernels couldn't access the last sector if it was + * odd and we failed to set the device block size to the sector + * size, hence we schedule chkdsk to create it. */ volume_flags |= VOLUME_IS_DIRTY; } - free(bs); - if (!create_file_volume(m, root_ref, volume_flags)) return FALSE; - ntfs_log_verbose("Creating $BadClus (mft record 8)\n"); m = (MFT_RECORD*)(g_buf + 8 * g_vol->mft_record_size); /* FIXME: This should be IGNORE_CASE */ @@ -4937,18 +4994,15 @@ static int mkntfs_redirect(struct mkntfs_options *opts2) ntfs_log_error("Internal error: invalid parameters to mkntfs_options.\n"); goto done; } - /* Initialize the random number generator with the current time. */ srandom(mkntfs_time()); - /* Allocate and initialize ntfs_volume structure g_vol. */ g_vol = ntfs_volume_alloc(); if (!g_vol) { ntfs_log_perror("Could not create volume"); goto done; } - - /* transfer some options to the volume */ + /* Transfer some options to the volume. */ if (opts.label) { g_vol->vol_name = strdup(opts.label); if (!g_vol->vol_name) { @@ -4956,7 +5010,6 @@ static int mkntfs_redirect(struct mkntfs_options *opts2) goto done; } } - if (opts.ver_major) { g_vol->major_ver = opts.ver_major; g_vol->minor_ver = opts.ver_minor; @@ -4967,10 +5020,6 @@ static int mkntfs_redirect(struct mkntfs_options *opts2) } if (opts.cluster_size >= 0) g_vol->cluster_size = opts.cluster_size; - - g_vol->mft_record_size = 1024; - g_vol->mft_record_size_bits = 10; - /* Length is in unicode characters. */ g_vol->upcase_len = 65536; g_vol->upcase = malloc(g_vol->upcase_len * sizeof(ntfschar)); @@ -4979,84 +5028,73 @@ static int mkntfs_redirect(struct mkntfs_options *opts2) goto done; } init_upcase_table(g_vol->upcase, g_vol->upcase_len * sizeof(ntfschar)); - - g_vol->indx_record_size = 4096; - g_vol->indx_record_size_bits = 12; - if (g_vol->major_ver < 3) { g_vol->attrdef = ntfs_calloc(1, 36000); if (g_vol->attrdef) { - memcpy(g_vol->attrdef, attrdef_ntfs12_array, sizeof(attrdef_ntfs12_array)); + memcpy(g_vol->attrdef, attrdef_ntfs12_array, + sizeof(attrdef_ntfs12_array)); g_vol->attrdef_len = 36000; } } else { g_vol->attrdef = malloc(sizeof(attrdef_ntfs3x_array)); if (g_vol->attrdef) { - memcpy(g_vol->attrdef, attrdef_ntfs3x_array, sizeof(attrdef_ntfs3x_array)); + memcpy(g_vol->attrdef, attrdef_ntfs3x_array, + sizeof(attrdef_ntfs3x_array)); g_vol->attrdef_len = sizeof(attrdef_ntfs3x_array); } } - if (!g_vol->attrdef) { ntfs_log_perror("Could not create attrdef structure"); goto done; } - /* Open the partition. */ if (!mkntfs_open_partition(g_vol)) goto done; - - /* Decide on the sectors/tracks/heads/size, etc. */ - if (!mkntfs_override_phys_params(g_vol)) + /* + * Decide on the sector size, cluster size, mft record and index record + * sizes as well as the number of sectors/tracks/heads/size, etc. + */ + if (!mkntfs_override_vol_params(g_vol)) goto done; - /* Initialize $Bitmap and $MFT/$BITMAP related stuff. */ if (!mkntfs_initialize_bitmaps()) goto done; - /* Initialize MFT & set g_logfile_lcn. */ if (!mkntfs_initialize_rl_mft()) goto done; - /* Initialize $LogFile. */ if (!mkntfs_initialize_rl_logfile()) goto done; - /* Initialize $Boot. */ if (!mkntfs_initialize_rl_boot()) goto done; - /* Allocate a buffer large enough to hold the mft. */ g_buf = ntfs_calloc(1, g_mft_size); if (!g_buf) goto done; - /* Create runlist for $BadClus, $DATA named stream $Bad. */ if (!mkntfs_initialize_rl_bad()) goto done; - /* If not quick format, fill the device with 0s. */ if (!opts.quick_format) { if (!mkntfs_fill_device_with_zeroes()) goto done; } - /* Create NTFS volume structures. */ if (!mkntfs_create_root_structures()) goto done; - /* * - Do not step onto bad blocks!!! - * - If any bad blocks were specified or found, modify $BadClus, allocating the - * bad clusters in $Bitmap. + * - If any bad blocks were specified or found, modify $BadClus, + * allocating the bad clusters in $Bitmap. * - C&w bootsector backup bootsector (backup in last sector of the * partition). * - If NTFS 3.0+, c&w $Secure file and $Extend directory with the - * corresponding special files in it, i.e. $ObjId, $Quota, $Reparse, and - * $UsnJrnl. And others? Or not all necessary? + * corresponding special files in it, i.e. $ObjId, $Quota, $Reparse, + * and $UsnJrnl. And others? Or not all necessary? * - RE: Populate $root with the system files (and $Extend directory if - * applicable). Possibly should move this as far to the top as possible and - * update during each subsequent c&w of each system file. + * applicable). Possibly should move this as far to the top as + * possible and update during each subsequent c&w of each system file. */ ntfs_log_verbose("Syncing root directory index record.\n"); if (!mkntfs_sync_index_record(g_index_block, (MFT_RECORD*)(g_buf + 5 * diff --git a/ntfsprogs/ntfsmount.c b/ntfsprogs/ntfsmount.c index 3ca482b0..fbadfa4f 100644 --- a/ntfsprogs/ntfsmount.c +++ b/ntfsprogs/ntfsmount.c @@ -220,7 +220,7 @@ static long ntfs_fuse_get_nr_free_clusters(ntfs_volume *vol) * Return 0 on success or -errno on error. */ static int ntfs_fuse_statfs(const char *path __attribute__((unused)), -#if FUSE_VERSION >= 25 +#if defined(FUSE_VERSION) && (FUSE_VERSION >= 25) struct statvfs *sfs) #else struct statfs *sfs) @@ -234,7 +234,7 @@ static int ntfs_fuse_statfs(const char *path __attribute__((unused)), return -ENODEV; /* Optimal transfer block size. */ sfs->f_bsize = vol->cluster_size; -#if FUSE_VERSION >= 25 +#if defined(FUSE_VERSION) && (FUSE_VERSION >= 25) sfs->f_frsize = vol->cluster_size; #endif /* @@ -257,7 +257,7 @@ static int ntfs_fuse_statfs(const char *path __attribute__((unused)), size = 0; sfs->f_ffree = size; /* Maximum length of filenames. */ -#if FUSE_VERSION >= 25 +#if defined(FUSE_VERSION) && (FUSE_VERSION >= 25) sfs->f_namemax = NTFS_MAX_NAME_LEN; #else sfs->f_namelen = NTFS_MAX_NAME_LEN; @@ -1763,7 +1763,7 @@ static int parse_options(int argc, char *argv[]) int main(int argc, char *argv[]) { char *parsed_options; -#if FUSE_VERSION >= 25 +#if defined(FUSE_VERSION) && (FUSE_VERSION >= 25) struct fuse_args margs = FUSE_ARGS_INIT(0, NULL); #endif struct fuse *fh; @@ -1795,7 +1795,7 @@ int main(int argc, char *argv[]) } free(opts.device); /* Create filesystem. */ -#if FUSE_VERSION >= 25 +#if defined(FUSE_VERSION) && (FUSE_VERSION >= 25) if ((fuse_opt_add_arg(&margs, "") == -1 || fuse_opt_add_arg(&margs, "-o") == -1 || fuse_opt_add_arg(&margs, parsed_options) == -1)) @@ -1812,7 +1812,7 @@ int main(int argc, char *argv[]) return 5; } free(parsed_options); -#if FUSE_VERSION >= 25 +#if defined(FUSE_VERSION) && (FUSE_VERSION >= 25) fh = (struct fuse *)1; /* Cast anything except NULL to handle errors. */ margs = (struct fuse_args)FUSE_ARGS_INIT(0, NULL); if (fuse_opt_add_arg(&margs, "") == -1 ||