Extended the allowed cluster size to 2MB

From Windows 10 Creators edition, the cluster size limit has been
extended to 2MB. This has implied redefining the boot sector field
"sectors_per_cluster" so that values greater than 128 can be recorded.
This commit is contained in:
Jean-Pierre André 2018-06-01 16:29:01 +02:00
parent e758709a2c
commit f862fcee00
6 changed files with 92 additions and 32 deletions

View File

@ -39,6 +39,13 @@ enum {
DEFSECBASE = 10000
};
/*
* Parameters for formatting
*/
/* Up to Windows 10, the cluster size was limited to 64K */
#define NTFS_MAX_CLUSTER_SIZE 2097152 /* Windows 10 Creators allows 2MB */
/*
* Parameters for compression
*/

View File

@ -38,6 +38,7 @@
#include <errno.h>
#endif
#include "param.h"
#include "compat.h"
#include "bootsect.h"
#include "debug.h"
@ -61,6 +62,7 @@ BOOL ntfs_boot_sector_is_ntfs(NTFS_BOOT_SECTOR *b)
{
u32 i;
BOOL ret = FALSE;
u16 sectors_per_cluster;
ntfs_log_debug("Beginning bootsector check.\n");
@ -83,15 +85,27 @@ BOOL ntfs_boot_sector_is_ntfs(NTFS_BOOT_SECTOR *b)
case 1: case 2: case 4: case 8: case 16: case 32: case 64: case 128:
break;
default:
ntfs_log_error("Unexpected sectors per cluster value (%d).\n",
if ((b->bpb.sectors_per_cluster < 240)
|| (b->bpb.sectors_per_cluster > 249)) {
if (b->bpb.sectors_per_cluster > 128)
ntfs_log_error("Unexpected sectors"
" per cluster value (code 0x%x)\n",
b->bpb.sectors_per_cluster);
else
ntfs_log_error("Unexpected sectors"
" per cluster value (%d).\n",
b->bpb.sectors_per_cluster);
goto not_ntfs;
}
}
ntfs_log_debug("Checking cluster size.\n");
i = (u32)le16_to_cpu(b->bpb.bytes_per_sector) *
b->bpb.sectors_per_cluster;
if (i > 65536) {
if (b->bpb.sectors_per_cluster > 128)
sectors_per_cluster = 1 << (256 - b->bpb.sectors_per_cluster);
else
sectors_per_cluster = b->bpb.sectors_per_cluster;
i = (u32)le16_to_cpu(b->bpb.bytes_per_sector) * sectors_per_cluster;
if (i > NTFS_MAX_CLUSTER_SIZE) {
ntfs_log_error("Unexpected cluster size (%d).\n", i);
goto not_ntfs;
}
@ -171,7 +185,7 @@ static const char *last_sector_error =
int ntfs_boot_sector_parse(ntfs_volume *vol, const NTFS_BOOT_SECTOR *bs)
{
s64 sectors;
u8 sectors_per_cluster;
u16 sectors_per_cluster;
s8 c;
/* We return -1 with errno = EINVAL on error. */
@ -186,6 +200,9 @@ int ntfs_boot_sector_parse(ntfs_volume *vol, const NTFS_BOOT_SECTOR *bs)
* below or equal the number_of_clusters) really belong in the
* ntfs_boot_sector_is_ntfs but in this way we can just do this once.
*/
if (bs->bpb.sectors_per_cluster > 128)
sectors_per_cluster = 1 << (256 - bs->bpb.sectors_per_cluster);
else
sectors_per_cluster = bs->bpb.sectors_per_cluster;
ntfs_log_debug("SectorsPerCluster = 0x%x\n", sectors_per_cluster);
if (sectors_per_cluster & (sectors_per_cluster - 1)) {

View File

@ -132,7 +132,7 @@ actual writing to the device.
.TP
\fB\-c\fR, \fB\-\-cluster\-size\fR BYTES
Specify the size of clusters in bytes. Valid cluster size values are powers of
two, with at least 256, and at most 65536 bytes per cluster. If omitted,
two, with at least 256, and at most 2097152 bytes (2MB) per cluster. If omitted,
.B mkntfs
uses 4096 bytes as the default cluster size.
.sp

View File

@ -6,7 +6,7 @@
* Copyright (c) 2002-2006 Szabolcs Szakacsits
* Copyright (c) 2005 Erik Sornes
* Copyright (c) 2007 Yura Pakhuchiy
* Copyright (c) 2010-2014 Jean-Pierre Andre
* Copyright (c) 2010-2018 Jean-Pierre Andre
*
* This utility will create an NTFS 1.2 or 3.1 volume on a user
* specified (block) device.
@ -119,6 +119,7 @@
# endif
#endif
#include "param.h"
#include "security.h"
#include "types.h"
#include "attrib.h"
@ -287,7 +288,7 @@ static void mkntfs_version(void)
ntfs_log_info("Copyright (c) 2002-2006 Szabolcs Szakacsits\n");
ntfs_log_info("Copyright (c) 2005 Erik Sornes\n");
ntfs_log_info("Copyright (c) 2007 Yura Pakhuchiy\n");
ntfs_log_info("Copyright (c) 2010-2014 Jean-Pierre Andre\n");
ntfs_log_info("Copyright (c) 2010-2018 Jean-Pierre Andre\n");
ntfs_log_info("\n%s\n%s%s\n", ntfs_gpl, ntfs_bugs, ntfs_home);
}
@ -3719,11 +3720,11 @@ static BOOL mkntfs_override_vol_params(ntfs_volume *vol)
/*
* For huge volumes, grow the cluster size until the number of
* clusters fits into 32 bits or the cluster size exceeds the
* maximum limit of 64kiB.
* maximum limit of NTFS_MAX_CLUSTER_SIZE.
*/
while (volume_size >> (ffs(vol->cluster_size) - 1 + 32)) {
vol->cluster_size <<= 1;
if (vol->cluster_size > 65535) {
if (vol->cluster_size >= NTFS_MAX_CLUSTER_SIZE) {
ntfs_log_error("Device is too large to hold an "
"NTFS volume (maximum size is "
"256TiB).\n");
@ -3744,15 +3745,18 @@ static BOOL mkntfs_override_vol_params(ntfs_volume *vol)
"to, or larger than, the sector size.\n");
return FALSE;
}
if (vol->cluster_size > 128 * (u32)opts.sector_size) {
/* Before Windows 10 Creators, the limit was 128 */
if (vol->cluster_size > 4096 * (u32)opts.sector_size) {
ntfs_log_error("The cluster size is invalid. It cannot be "
"more that 128 times the size of the sector "
"more that 4096 times the size of the sector "
"size.\n");
return FALSE;
}
if (vol->cluster_size > 65536) {
if (vol->cluster_size > NTFS_MAX_CLUSTER_SIZE) {
ntfs_log_error("The cluster size is invalid. The maximum "
"cluster size is 65536 bytes (64kiB).\n");
"cluster size is %lu bytes (%lukiB).\n",
(unsigned long)NTFS_MAX_CLUSTER_SIZE,
(unsigned long)(NTFS_MAX_CLUSTER_SIZE >> 10));
return FALSE;
}
vol->cluster_size_bits = ffs(vol->cluster_size) - 1;
@ -4387,6 +4391,7 @@ static BOOL mkntfs_create_root_structures(void)
u8 *sd;
FILE_ATTR_FLAGS extend_flags;
VOLUME_FLAGS volume_flags = const_cpu_to_le16(0);
int sectors_per_cluster;
int nr_sysfiles;
int buf_sds_first_size;
char *buf_sds;
@ -4639,8 +4644,11 @@ static BOOL mkntfs_create_root_structures(void)
* already inserted, so no need to worry about these things.
*/
bs->bpb.bytes_per_sector = cpu_to_le16(opts.sector_size);
bs->bpb.sectors_per_cluster = (u8)(g_vol->cluster_size /
opts.sector_size);
sectors_per_cluster = g_vol->cluster_size / opts.sector_size;
if (sectors_per_cluster > 128)
bs->bpb.sectors_per_cluster = 257 - ffs(sectors_per_cluster);
else
bs->bpb.sectors_per_cluster = sectors_per_cluster;
bs->bpb.media_type = 0xf8; /* hard disk */
bs->bpb.sectors_per_track = cpu_to_le16(opts.sectors_per_track);
ntfs_log_debug("sectors per track = %ld (0x%lx)\n",

View File

@ -3,7 +3,7 @@
*
* Copyright (c) 2003-2006 Szabolcs Szakacsits
* Copyright (c) 2004-2006 Anton Altaparmakov
* Copyright (c) 2010-2017 Jean-Pierre Andre
* Copyright (c) 2010-2018 Jean-Pierre Andre
* Special image format support copyright (c) 2004 Per Olofsson
*
* Clone NTFS data and/or metadata to a sparse file, image, device or stdout.
@ -71,6 +71,7 @@
*/
#define NTFS_DO_NOT_CHECK_ENDIANS
#include "param.h"
#include "debug.h"
#include "types.h"
#include "support.h"
@ -270,7 +271,6 @@ static int compare_bitmaps(struct bitmap *a, BOOL copy);
#define LAST_METADATA_INODE 11
#define NTFS_MAX_CLUSTER_SIZE 65536
#define NTFS_SECTOR_SIZE 512
#define rounded_up_division(a, b) (((a) + (b - 1)) / (b))
@ -393,7 +393,7 @@ static void version(void)
"Efficiently clone, image, restore or rescue an NTFS Volume.\n\n"
"Copyright (c) 2003-2006 Szabolcs Szakacsits\n"
"Copyright (c) 2004-2006 Anton Altaparmakov\n"
"Copyright (c) 2010-2016 Jean-Pierre Andre\n\n");
"Copyright (c) 2010-2018 Jean-Pierre Andre\n\n");
fprintf(stderr, "%s\n%s%s", ntfs_gpl, ntfs_bugs, ntfs_home);
exit(0);
}
@ -756,7 +756,7 @@ static void read_rescue(void *fd, char *buff, u32 csize, u32 bytes_per_sector,
static void copy_cluster(int rescue, u64 rescue_lcn, u64 lcn)
{
char buff[NTFS_MAX_CLUSTER_SIZE]; /* overflow checked at mount time */
char *buff;
/* vol is NULL if opt.restore_image is set */
s32 csize = le32_to_cpu(image_hdr.cluster_size);
BOOL backup_bootsector;
@ -783,6 +783,10 @@ static void copy_cluster(int rescue, u64 rescue_lcn, u64 lcn)
}
}
buff = (char*)ntfs_malloc(csize);
if (!buff)
err_exit("Not enough memory");
// need reading when not about to write ?
if (read_all(fd, buff, csize) == -1) {
@ -858,6 +862,7 @@ static void copy_cluster(int rescue, u64 rescue_lcn, u64 lcn)
perr_printf("Write failed");
#endif
}
free(buff);
}
static s64 lseek_out(int fd, s64 pos, int mode)
@ -995,7 +1000,11 @@ static void write_empty_clusters(s32 csize, s64 count,
struct progress_bar *progress, u64 *p_counter)
{
s64 i;
char buff[NTFS_MAX_CLUSTER_SIZE];
char *buff;
buff = (char*)ntfs_malloc(csize);
if (!buff)
err_exit("Not enough memory");
memset(buff, 0, csize);
@ -1004,6 +1013,7 @@ static void write_empty_clusters(s32 csize, s64 count,
perr_exit("write_all");
progress_update(progress, ++(*p_counter));
}
free(buff);
}
static void restore_image(void)
@ -1492,7 +1502,7 @@ static void write_set(char *buff, u32 csize, s64 *current_lcn,
static void copy_wipe_mft(ntfs_walk_clusters_ctx *image, runlist *rl)
{
char buff[NTFS_MAX_CLUSTER_SIZE]; /* overflow checked at mount time */
char *buff;
void *fd;
s64 mft_no;
u32 mft_record_size;
@ -1522,6 +1532,10 @@ static void copy_wipe_mft(ntfs_walk_clusters_ctx *image, runlist *rl)
clusters_per_set = mft_record_size/csize;
records_per_set = 1;
}
buff = (char*)ntfs_malloc(mft_record_size);
if (!buff)
err_exit("Not enough memory");
mft_no = 0;
ri = rj = 0;
wi = wj = 0;
@ -1554,6 +1568,7 @@ static void copy_wipe_mft(ntfs_walk_clusters_ctx *image, runlist *rl)
}
}
image->current_lcn = current_lcn;
free(buff);
}
/*
@ -1566,7 +1581,7 @@ static void copy_wipe_mft(ntfs_walk_clusters_ctx *image, runlist *rl)
static void copy_wipe_i30(ntfs_walk_clusters_ctx *image, runlist *rl)
{
char buff[NTFS_MAX_CLUSTER_SIZE]; /* overflow checked at mount time */
char *buff;
void *fd;
u32 indx_record_size;
u32 csize;
@ -1595,6 +1610,10 @@ static void copy_wipe_i30(ntfs_walk_clusters_ctx *image, runlist *rl)
clusters_per_set = indx_record_size/csize;
records_per_set = 1;
}
buff = (char*)ntfs_malloc(indx_record_size);
if (!buff)
err_exit("Not enough memory");
ri = rj = 0;
wi = wj = 0;
if (rl[ri].length)
@ -1627,6 +1646,7 @@ static void copy_wipe_i30(ntfs_walk_clusters_ctx *image, runlist *rl)
}
}
image->current_lcn = current_lcn;
free(buff);
}
static void dump_clusters(ntfs_walk_clusters_ctx *image, runlist *rl)

View File

@ -59,6 +59,7 @@
#include <fcntl.h>
#endif
#include "param.h"
#include "debug.h"
#include "types.h"
#include "support.h"
@ -246,8 +247,6 @@ static s64 max_free_cluster_range = 0;
#define DIRTY_INODE (1)
#define DIRTY_ATTRIB (2)
#define NTFS_MAX_CLUSTER_SIZE (65536)
static s64 rounded_up_division(s64 numer, s64 denom)
{
return (numer + (denom - 1)) / denom;
@ -407,7 +406,7 @@ static void version(void)
printf("Copyright (c) 2002-2005 Anton Altaparmakov\n");
printf("Copyright (c) 2002-2003 Richard Russon\n");
printf("Copyright (c) 2007 Yura Pakhuchiy\n");
printf("Copyright (c) 2011-2016 Jean-Pierre Andre\n");
printf("Copyright (c) 2011-2018 Jean-Pierre Andre\n");
printf("\n%s\n%s%s", ntfs_gpl, ntfs_bugs, ntfs_home);
}
@ -1891,9 +1890,13 @@ static void lseek_to_cluster(ntfs_volume *vol, s64 lcn)
static void copy_clusters(ntfs_resize_t *resize, s64 dest, s64 src, s64 len)
{
s64 i;
char buff[NTFS_MAX_CLUSTER_SIZE]; /* overflow checked at mount time */
char *buff;
ntfs_volume *vol = resize->vol;
buff = (char*)ntfs_malloc(vol->cluster_size);
if (!buff)
perr_exit("ntfs_malloc");
for (i = 0; i < len; i++) {
lseek_to_cluster(vol, src + i);
@ -1917,6 +1920,7 @@ static void copy_clusters(ntfs_resize_t *resize, s64 dest, s64 src, s64 len)
resize->relocations++;
progress_update(&resize->progress, resize->relocations);
}
free(buff);
}
static void relocate_clusters(ntfs_resize_t *r, runlist *dest_rl, s64 src_lcn)
@ -2758,6 +2762,10 @@ static void update_bootsector(ntfs_resize_t *r)
if (vol->dev->d_ops->read(vol->dev, bs, bs_size) == -1)
perr_exit("read() error");
if (bs->bpb.sectors_per_cluster > 128)
bs->number_of_sectors = cpu_to_sle64(r->new_volume_size
<< (256 - bs->bpb.sectors_per_cluster));
else
bs->number_of_sectors = cpu_to_sle64(r->new_volume_size *
bs->bpb.sectors_per_cluster);