From d874c302001878037cf400eaf80ee3631771f555 Mon Sep 17 00:00:00 2001 From: Konstantin Germanov Date: Tue, 28 Jun 2022 06:44:09 -0400 Subject: [PATCH 1/8] Extend API to pass dev_offset Add option device offset. --- include/ntfs-3g/device.h | 5 +++++ include/ntfs-3g/volume.h | 1 + libntfs-3g/device.c | 25 +++++++++++++++++++++++++ libntfs-3g/volume.c | 35 ++++++++++++++++++++++++++++++++++- 4 files changed, 65 insertions(+), 1 deletion(-) diff --git a/include/ntfs-3g/device.h b/include/ntfs-3g/device.h index 709cb4fa..86627d5a 100644 --- a/include/ntfs-3g/device.h +++ b/include/ntfs-3g/device.h @@ -90,6 +90,8 @@ struct ntfs_device { heads or -1. */ int d_sectors_per_track; /* Disk geometry: number of sectors per track or -1. */ + s64 dev_offset; /* Offset from the start of the device + where the ntfs filesystem begins.*/ }; struct stat; @@ -117,6 +119,9 @@ struct ntfs_device_operations { extern struct ntfs_device *ntfs_device_alloc(const char *name, const long state, struct ntfs_device_operations *dops, void *priv_data); +extern struct ntfs_device *ntfs_device_alloc_ext(const char *name, const long state, + struct ntfs_device_operations *dops, void *priv_data, s64 dev_offset); + extern int ntfs_device_free(struct ntfs_device *dev); extern int ntfs_device_sync(struct ntfs_device *dev); diff --git a/include/ntfs-3g/volume.h b/include/ntfs-3g/volume.h index 42800a28..b29dc861 100644 --- a/include/ntfs-3g/volume.h +++ b/include/ntfs-3g/volume.h @@ -299,6 +299,7 @@ extern ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, ntfs_mount_flags flags); extern ntfs_volume *ntfs_mount(const char *name, ntfs_mount_flags flags); +extern ntfs_volume *ntfs_mount_ext(const char *name, ntfs_mount_flags flags, const s64 dev_offset); extern int ntfs_umount(ntfs_volume *vol, const BOOL force); extern int ntfs_version_is_supported(ntfs_volume *vol); diff --git a/libntfs-3g/device.c b/libntfs-3g/device.c index a5c32f42..41d56568 100644 --- a/libntfs-3g/device.c +++ b/libntfs-3g/device.c @@ -114,6 +114,30 @@ struct ntfs_device *ntfs_device_alloc(const char *name, const long state, struct ntfs_device_operations *dops, void *priv_data) { + return ntfs_device_alloc_ext(name, state, dops, priv_data, 0); +} + +/** + * ntfs_device_alloc_ext - allocate an ntfs device structure and pre-initialize it + * @name: name of the device (must be present) + * @state: initial device state (usually zero) + * @dops: ntfs device operations to use with the device (must be present) + * @priv_data: pointer to private data (optional) + * @dev_offset: offset from beginning of device where the ntfs filesystem begins + * + * Allocate an ntfs device structure and pre-initialize it with the user- + * specified device operations @dops, device state @state, device name @name, + * and optional private data @priv_data. + * + * Note, @name is copied and can hence be freed after this functions returns. + * + * On success return a pointer to the allocated ntfs device structure and on + * error return NULL with errno set to the error code returned by ntfs_malloc(). + */ +struct ntfs_device *ntfs_device_alloc_ext(const char *name, const long state, + struct ntfs_device_operations *dops, void *priv_data, const s64 dev_offset) +{ + struct ntfs_device *dev; if (!name) { @@ -134,6 +158,7 @@ struct ntfs_device *ntfs_device_alloc(const char *name, const long state, dev->d_private = priv_data; dev->d_heads = -1; dev->d_sectors_per_track = -1; + dev->dev_offset = dev_offset; } return dev; } diff --git a/libntfs-3g/volume.c b/libntfs-3g/volume.c index a6d467b3..6523716a 100644 --- a/libntfs-3g/volume.c +++ b/libntfs-3g/volume.c @@ -1413,13 +1413,46 @@ int ntfs_set_ignore_case(ntfs_volume *vol) */ ntfs_volume *ntfs_mount(const char *name __attribute__((unused)), ntfs_mount_flags flags __attribute__((unused))) +{ + return ntfs_mount_ext(name, flags, 0); +} + +/** + * ntfs_mount_ext - open ntfs volume with dev_offset + * @name: name of device/file to open + * @flags: optional mount flags + * @dev_offset: offset from beginning of device where the ntfs filesystem begins + * + * This function mounts an ntfs volume. @name should contain the name of the + * device/file to mount as the ntfs volume. + * + * @flags is an optional second parameter. The same flags are used as for + * the mount system call (man 2 mount). Currently only the following flags + * is implemented: + * NTFS_MNT_RDONLY - mount volume read-only + * + * The function opens the device or file @name and verifies that it contains a + * valid bootsector. Then, it allocates an ntfs_volume structure and initializes + * some of the values inside the structure from the information stored in the + * bootsector. It proceeds to load the necessary system files and completes + * setting up the structure. + * + * Return the allocated volume structure on success and NULL on error with + * errno set to the error code. + * + * Note, that a copy is made of @name, and hence it can be discarded as + * soon as the function returns. + */ + +ntfs_volume *ntfs_mount_ext(const char *name __attribute__((unused)), + ntfs_mount_flags flags __attribute__((unused)), const s64 dev_offset) { #ifndef NO_NTFS_DEVICE_DEFAULT_IO_OPS struct ntfs_device *dev; ntfs_volume *vol; /* Allocate an ntfs_device structure. */ - dev = ntfs_device_alloc(name, 0, &ntfs_device_default_io_ops, NULL); + dev = ntfs_device_alloc_ext(name, 0, &ntfs_device_default_io_ops, NULL, dev_offset); if (!dev) return NULL; /* Call ntfs_device_mount() to do the actual mount. */ From 1980c1a3ddfb5f7e92a5ba7321fe43e83d9d6d0a Mon Sep 17 00:00:00 2001 From: Konstantin Germanov Date: Tue, 28 Jun 2022 06:46:08 -0400 Subject: [PATCH 2/8] Adjust size of volume with dev_offset The volume's size should be smaller on dev_offset --- libntfs-3g/device.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/libntfs-3g/device.c b/libntfs-3g/device.c index 41d56568..e69e6100 100644 --- a/libntfs-3g/device.c +++ b/libntfs-3g/device.c @@ -566,7 +566,7 @@ s64 ntfs_device_size_get(struct ntfs_device *dev, int block_size) ntfs_log_debug("BLKGETSIZE64 nr bytes = %llu (0x%llx)\n", (unsigned long long)size, (unsigned long long)size); - return (s64)size / block_size; + return (s64)(size - dev->dev_offset) / block_size; } } #endif @@ -576,7 +576,7 @@ s64 ntfs_device_size_get(struct ntfs_device *dev, int block_size) if (dev->d_ops->ioctl(dev, BLKGETSIZE, &size) >= 0) { ntfs_log_debug("BLKGETSIZE nr 512 byte blocks = %lu (0x%lx)\n", size, size); - return (s64)size * 512 / block_size; + return (s64)(size * 512 - dev->dev_offset) / block_size; } } #endif @@ -587,7 +587,7 @@ s64 ntfs_device_size_get(struct ntfs_device *dev, int block_size) ntfs_log_debug("FDGETPRM nr 512 byte blocks = %lu (0x%lx)\n", (unsigned long)this_floppy.size, (unsigned long)this_floppy.size); - return (s64)this_floppy.size * 512 / block_size; + return (s64)(this_floppy.size * 512 - dev->dev_offset) / block_size; } } #endif @@ -600,7 +600,7 @@ s64 ntfs_device_size_get(struct ntfs_device *dev, int block_size) ntfs_log_debug("DIOCGMEDIASIZE nr bytes = %llu (0x%llx)\n", (unsigned long long)size, (unsigned long long)size); - return (s64)size / block_size; + return (s64)(size - dev->dev_offset) / block_size; } } #endif @@ -617,7 +617,7 @@ s64 ntfs_device_size_get(struct ntfs_device *dev, int block_size) ntfs_log_debug("DKIOCGETBLOCKCOUNT nr blocks = %llu (0x%llx)\n", (unsigned long long) blocks, (unsigned long long) blocks); - return blocks * sector_size / block_size; + return (blocks * sector_size - dev->dev_offset) / block_size; } } #endif From 8b1146506144d5d91bd5c6f6fd1b05f3b862f0cf Mon Sep 17 00:00:00 2001 From: Konstantin Germanov Date: Tue, 28 Jun 2022 06:54:14 -0400 Subject: [PATCH 3/8] Use dev_offset on Unix IO Add dev_offset on operations --- libntfs-3g/unix_io.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/libntfs-3g/unix_io.c b/libntfs-3g/unix_io.c index 5495a6a4..c8daa7ef 100644 --- a/libntfs-3g/unix_io.c +++ b/libntfs-3g/unix_io.c @@ -244,7 +244,7 @@ static int ntfs_device_unix_io_close(struct ntfs_device *dev) static s64 ntfs_device_unix_io_seek(struct ntfs_device *dev, s64 offset, int whence) { - return lseek(DEV_FD(dev), offset, whence); + return lseek(DEV_FD(dev), offset + dev->dev_offset, whence); } /** @@ -298,7 +298,7 @@ static s64 ntfs_device_unix_io_write(struct ntfs_device *dev, const void *buf, static s64 ntfs_device_unix_io_pread(struct ntfs_device *dev, void *buf, s64 count, s64 offset) { - return pread(DEV_FD(dev), buf, count, offset); + return pread(DEV_FD(dev), buf, count, offset + dev->dev_offset); } /** @@ -320,7 +320,7 @@ static s64 ntfs_device_unix_io_pwrite(struct ntfs_device *dev, const void *buf, return -1; } NDevSetDirty(dev); - return pwrite(DEV_FD(dev), buf, count, offset); + return pwrite(DEV_FD(dev), buf, count, offset + dev->dev_offset); } /** @@ -356,7 +356,15 @@ static int ntfs_device_unix_io_sync(struct ntfs_device *dev) */ static int ntfs_device_unix_io_stat(struct ntfs_device *dev, struct stat *buf) { - return fstat(DEV_FD(dev), buf); + int res = fstat(DEV_FD(dev), buf); + + if (res == 0) { + buf->st_size -= dev->dev_offset; + buf->st_blocks = ((buf->st_blksize == 0) ? + 0 : buf->st_size / buf->st_blksize); + } + + return res; } /** From 5ecfcc5e88492ed96400bb3c7daa10c0a4ae2ebb Mon Sep 17 00:00:00 2001 From: Konstantin Germanov Date: Tue, 28 Jun 2022 07:03:43 -0400 Subject: [PATCH 4/8] Use dev_offset on Win32 IO Add dev_offset on operations --- libntfs-3g/win32_io.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/libntfs-3g/win32_io.c b/libntfs-3g/win32_io.c index 9c72dee3..8d4937d3 100644 --- a/libntfs-3g/win32_io.c +++ b/libntfs-3g/win32_io.c @@ -1285,13 +1285,13 @@ static s64 ntfs_device_win32_seek(struct ntfs_device *dev, s64 offset, s64 abs_ofs; win32_fd *fd = (win32_fd *)dev->d_private; - ntfs_log_trace("seek offset = 0x%llx, whence = %d.\n", offset, whence); + ntfs_log_trace("seek offset = 0x%llx, whence = %d.\n", offset + dev->dev_offset, whence); switch (whence) { case SEEK_SET: - abs_ofs = offset; + abs_ofs = offset + dev->dev_offset; break; case SEEK_CUR: - abs_ofs = fd->pos + offset; + abs_ofs = fd->pos + offset + dev->dev_offset; break; case SEEK_END: /* End of partition != end of disk. */ @@ -1301,7 +1301,7 @@ static s64 ntfs_device_win32_seek(struct ntfs_device *dev, s64 offset, errno = EOPNOTSUPP; return -1; } - abs_ofs = fd->part_length + offset; + abs_ofs = fd->part_length + offset + dev->dev_offset; break; default: ntfs_log_trace("Wrong mode %d.\n", whence); @@ -1788,7 +1788,7 @@ static int ntfs_device_win32_stat(struct ntfs_device *dev, struct stat *buf) } memset(buf, 0, sizeof(struct stat)); buf->st_mode = st_mode; - buf->st_size = fd->part_length; + buf->st_size = fd->part_length - dev->dev_offset; if (buf->st_size != -1) buf->st_blocks = buf->st_size >> 9; else @@ -1911,10 +1911,10 @@ static s64 ntfs_device_win32_pread(struct ntfs_device *dev, void *b, /* read the fast way if sector aligned */ fd = (win32_fd*)dev->d_private; - if (!((count | offset) & (fd->geo_sector_size - 1))) { - got = ntfs_device_win32_pio(fd, offset, count, b, (void*)NULL); + if (!((count | (offset + dev->dev_offset)) & (fd->geo_sector_size - 1))) { + got = ntfs_device_win32_pio(fd, offset + dev->dev_offset, count, b, (void*)NULL); } else { - if (ntfs_device_win32_seek(dev, offset, 0) == -1) + if (ntfs_device_win32_seek(dev, offset + dev->dev_offset, 0) == -1) got = 0; else got = ntfs_device_win32_read(dev, b, count); @@ -1931,10 +1931,10 @@ static s64 ntfs_device_win32_pwrite(struct ntfs_device *dev, const void *b, /* write the fast way if sector aligned */ fd = (win32_fd*)dev->d_private; - if (!((count | offset) & (fd->geo_sector_size - 1))) { - put = ntfs_device_win32_pio(fd, offset, count, (void*)NULL, b); + if (!((count | (offset + dev->dev_offset)) & (fd->geo_sector_size - 1))) { + put = ntfs_device_win32_pio(fd, offset + dev->dev_offset, count, (void*)NULL, b); } else { - if (ntfs_device_win32_seek(dev, offset, 0) == -1) + if (ntfs_device_win32_seek(dev, offset + dev->dev_offset, 0) == -1) put = 0; else put = ntfs_device_win32_write(dev, b, count); From 23d3ddd6eef97860d656db6174acc6f7dc4a0ace Mon Sep 17 00:00:00 2001 From: Konstantin Germanov Date: Tue, 28 Jun 2022 07:10:37 -0400 Subject: [PATCH 5/8] Add option dev_offset to parse_mount_options --- src/ntfs-3g_common.c | 4 ++++ src/ntfs-3g_common.h | 2 ++ 2 files changed, 6 insertions(+) diff --git a/src/ntfs-3g_common.c b/src/ntfs-3g_common.c index 29021dfc..a5bbe3dc 100644 --- a/src/ntfs-3g_common.c +++ b/src/ntfs-3g_common.c @@ -132,6 +132,7 @@ const struct DEFOPTION optionlist[] = { { "-h", OPT_HELP, FLGOPT_BOGUS }, { "--version", OPT_VERSION, FLGOPT_BOGUS }, { "-V", OPT_VERSION, FLGOPT_BOGUS }, + { "dev_offset", OPT_DEV_OFFSET, FLGOPT_DECIMAL }, { (const char*)NULL, 0, 0 } /* end marker */ } ; @@ -519,6 +520,9 @@ char *parse_mount_options(ntfs_fuse_context_t *ctx, goto err_exit; } break; + case OPT_DEV_OFFSET : + ctx->dev_offset = strtoull(val, 0, 0); + break; case OPT_FSNAME : /* Filesystem name. */ /* * We need this to be able to check whether filesystem diff --git a/src/ntfs-3g_common.h b/src/ntfs-3g_common.h index 8ead5107..1161328f 100644 --- a/src/ntfs-3g_common.h +++ b/src/ntfs-3g_common.h @@ -96,6 +96,7 @@ enum { OPT_SPECIAL_FILES, OPT_HELP, OPT_VERSION, + OPT_DEV_OFFSET, } ; /* Option flags */ @@ -178,6 +179,7 @@ typedef struct { struct SECURITY_CONTEXT security; struct open_file *open_files; /* only defined in lowntfs-3g */ u64 latest_ghost; + s64 dev_offset; } ntfs_fuse_context_t; extern const char *EXEC_NAME; From 5447c6436ee783d8e68803973a39b186f127decd Mon Sep 17 00:00:00 2001 From: Konstantin Germanov Date: Wed, 29 Jun 2022 05:41:22 -0400 Subject: [PATCH 6/8] Add option dev_offset to lowntfs-3g --- src/lowntfs-3g.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/lowntfs-3g.c b/src/lowntfs-3g.c index 9330500c..5b16465f 100644 --- a/src/lowntfs-3g.c +++ b/src/lowntfs-3g.c @@ -267,7 +267,7 @@ static const char *usage_msg = "\n" "Usage: %s [-o option[,...]] \n" "\n" -"Options: ro (read-only mount), windows_names, uid=, gid=,\n" +"Options: ro (read-only mount), dev_offset=, windows_names, uid=, gid=,\n" " umask=, fmask=, dmask=, streams_interface=.\n" " Please see the details in the manual (type: man ntfs-3g).\n" "\n" @@ -4307,11 +4307,11 @@ static int ntfs_fuse_init(void) return 0; } -static int ntfs_open(const char *device) +static int ntfs_open(const char *device, const s64 dev_offset) { unsigned long flags = 0; ntfs_volume *vol; - + if (!ctx->blkdev) flags |= NTFS_MNT_EXCLUSIVE; if (ctx->ro) @@ -4324,7 +4324,7 @@ static int ntfs_open(const char *device) if (ctx->hiberfile) flags |= NTFS_MNT_IGNORE_HIBERFILE; - ctx->vol = vol = ntfs_mount(device, flags); + ctx->vol = vol = ntfs_mount_ext(device, flags, dev_offset); if (!vol) { ntfs_log_perror("Failed to mount '%s'", device); goto err_out; @@ -4724,7 +4724,7 @@ int main(int argc, char *argv[]) goto err2; } #endif - err = ntfs_open(opts.device); + err = ntfs_open(opts.device, ctx->dev_offset); if (err) goto err_out; From 18485dd984ebba7ae2061eaf94b5660889ab6f36 Mon Sep 17 00:00:00 2001 From: Konstantin Germanov Date: Wed, 29 Jun 2022 05:44:44 -0400 Subject: [PATCH 7/8] Add option dev_offset to ntfs-3g --- src/ntfs-3g.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ntfs-3g.c b/src/ntfs-3g.c index d8227e71..eea9f523 100644 --- a/src/ntfs-3g.c +++ b/src/ntfs-3g.c @@ -202,7 +202,7 @@ static const char *usage_msg = "\n" "Usage: %s [-o option[,...]] \n" "\n" -"Options: ro (read-only mount), windows_names, uid=, gid=,\n" +"Options: ro (read-only mount), windows_names, dev_offset=, uid=, gid=,\n" " umask=, fmask=, dmask=, streams_interface=.\n" " Please see the details in the manual (type: man ntfs-3g).\n" "\n" @@ -4020,7 +4020,7 @@ static int ntfs_fuse_init(void) return 0; } -static int ntfs_open(const char *device) +static int ntfs_open(const char *device, const s64 dev_offset) { unsigned long flags = 0; @@ -4036,7 +4036,7 @@ static int ntfs_open(const char *device) if (ctx->hiberfile) flags |= NTFS_MNT_IGNORE_HIBERFILE; - ctx->vol = ntfs_mount(device, flags); + ctx->vol = ntfs_mount_ext(device, flags, dev_offset); if (!ctx->vol) { ntfs_log_perror("Failed to mount '%s'", device); goto err_out; @@ -4452,7 +4452,7 @@ int main(int argc, char *argv[]) goto err2; } #endif - err = ntfs_open(opts.device); + err = ntfs_open(opts.device, ctx->dev_offset); if (err) goto err_out; From c75dc0697c4244a27d2b69826ccd57a64fb5382f Mon Sep 17 00:00:00 2001 From: Konstantin Germanov Date: Wed, 29 Jun 2022 05:49:41 -0400 Subject: [PATCH 8/8] Add option dev_offset to ntfs-3g.probe --- src/ntfs-3g.probe.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/ntfs-3g.probe.c b/src/ntfs-3g.probe.c index cb73aee4..05acec35 100644 --- a/src/ntfs-3g.probe.c +++ b/src/ntfs-3g.probe.c @@ -45,6 +45,7 @@ typedef enum { static struct options { probe_t probetype; char *device; + s64 dev_offset; } opts; static const char *EXEC_NAME = "ntfs-3g.probe"; @@ -55,13 +56,13 @@ static const char *usage_msg = "\n" "Copyright (C) 2007 Szabolcs Szakacsits\n" "\n" -"Usage: %s <--readonly|--readwrite> \n" +"Usage: %s <--readonly|--readwrite> <--dev_offset n> \n" "\n" "Example: ntfs-3g.probe --readwrite /dev/sda1\n" "\n" "%s"; -static int ntfs_open(const char *device) +static int ntfs_open(const char *device, const s64 dev_offset) { ntfs_volume *vol; unsigned long flags = 0; @@ -70,7 +71,7 @@ static int ntfs_open(const char *device) if (opts.probetype == PROBE_READONLY) flags |= NTFS_MNT_RDONLY; - vol = ntfs_mount(device, flags); + vol = ntfs_mount_ext(device, flags, dev_offset); if (!vol) ret = ntfs_volume_error(errno); @@ -89,11 +90,12 @@ static int parse_options(int argc, char *argv[]) { int c; - static const char *sopt = "-hrw"; + static const char *sopt = "-hrwo:"; static const struct option lopt[] = { { "readonly", no_argument, NULL, 'r' }, { "readwrite", no_argument, NULL, 'w' }, { "help", no_argument, NULL, 'h' }, + { "dev_offset", required_argument, NULL, 'o' }, { NULL, 0, NULL, 0 } }; @@ -125,6 +127,9 @@ static int parse_options(int argc, char *argv[]) case 'w': opts.probetype = PROBE_READWRITE; break; + case 'o': + opts.dev_offset = optarg ? strtoull(optarg, 0, 0) : 0; + break; default: ntfs_log_error("%s: Unknown option '%s'.\n", EXEC_NAME, argv[optind - 1]); @@ -156,7 +161,7 @@ int main(int argc, char *argv[]) exit(NTFS_VOLUME_SYNTAX_ERROR); } - err = ntfs_open(opts.device); + err = ntfs_open(opts.device, opts.dev_offset); free(opts.device); if (err)