From f73d77d56845f85ea4a2a309d2efffb72d78afa7 Mon Sep 17 00:00:00 2001 From: aia21 Date: Sat, 9 Dec 2006 14:01:12 +0000 Subject: [PATCH] - Implement ntfs_pread() and ntfs_pwrite() in terms of device operations pread() and pwrite() respectively and fall back to using seek() + read()/write() if no pread()/pwrite() device operation is supplied or the OS does not support the pread()/pwrite() system call. Adapt unix_io pread()/pwrite() device operations to use pread()/ pwrite() system call and adapt win32_io device operations to not supply pread()/pwrite(). (Csaba Henk, Anton) --- CREDITS | 1 + ChangeLog | 7 ++++ libntfs/device.c | 79 +++++++++++++++++++++++++++++++++++++++++----- libntfs/dir.c | 14 ++------ libntfs/unix_io.c | 4 +-- libntfs/win32_io.c | 14 -------- 6 files changed, 84 insertions(+), 35 deletions(-) diff --git a/CREDITS b/CREDITS index 3c6c6df1..09698845 100644 --- a/CREDITS +++ b/CREDITS @@ -17,6 +17,7 @@ Matthew J. Fanto Yuval Fledel Marcin GibuĊ‚a Christophe Grenier +Csaba Henk Ian Jackson Carmelo Kintana Jan Kratochvil diff --git a/ChangeLog b/ChangeLog index 53d84111..9f3d41ce 100644 --- a/ChangeLog +++ b/ChangeLog @@ -99,6 +99,13 @@ xx/xx/2006 - x.xx.x - . - ntfsmount: fix rename if destination already exists. (Yura) - ntfsfix: do not set VOLUME_MOUNTED_ON_NT4 flag as it causes Vista to not boot any more. + - Implement ntfs_pread() and ntfs_pwrite() in terms of device + operations pread() and pwrite() respectively and fall back to using + seek() + read()/write() if no pread()/pwrite() device operation is + supplied or the OS does not support the pread()/pwrite() system call. + Adapt unix_io pread()/pwrite() device operations to use pread()/ + pwrite() system call and adapt win32_io device operations to not + supply pread()/pwrite(). (Csaba Henk, Anton) 21/06/2006 - 1.13.1 - Various fixes. diff --git a/libntfs/device.c b/libntfs/device.c index c732f8cc..1500479c 100644 --- a/libntfs/device.c +++ b/libntfs/device.c @@ -152,6 +152,22 @@ int ntfs_device_free(struct ntfs_device *dev) return 0; } +/** + * fake_pread - read operation disguised as pread + * @dev: device to read from + * @b: output data buffer + * @count: number of bytes to read + * @pos: position in device to read from + * + * Auxiliary function, used when we emulate pread by seek() + a sequence of + * read()s. + */ +static s64 fake_pread(struct ntfs_device *dev, void *b, s64 count, + s64 pos __attribute__((unused))) +{ + return dev->d_ops->read(dev, b, count); +} + /** * ntfs_pread - positioned read from disk * @dev: device to read from @@ -175,6 +191,7 @@ s64 ntfs_pread(struct ntfs_device *dev, const s64 pos, s64 count, void *b) { s64 br, total; struct ntfs_device_operations *dops; + s64 (*_pread)(struct ntfs_device *, void *, s64, s64); ntfs_log_trace("Entering for pos 0x%llx, count 0x%llx.\n", pos, count); if (!b || count < 0 || pos < 0) { @@ -184,21 +201,34 @@ s64 ntfs_pread(struct ntfs_device *dev, const s64 pos, s64 count, void *b) if (!count) return 0; dops = dev->d_ops; - /* Locate to position. */ - if (dops->seek(dev, pos, SEEK_SET) == (off_t)-1) { - ntfs_log_perror("ntfs_pread: device seek to 0x%llx returned error", - pos); + _pread = dops->pread; + if (!_pread) + _pread = fake_pread; +seek: + /* Locate to position if pread is to be emulated by seek() + read(). */ + if (_pread == fake_pread && + dops->seek(dev, pos, SEEK_SET) == (off_t)-1) { + ntfs_log_perror("ntfs_pread: device seek to 0x%llx returned " + "error", pos); return -1; } /* Read the data. */ for (total = 0; count; count -= br, total += br) { - br = dops->read(dev, (char*)b + total, count); + br = _pread(dev, (char*)b + total, count, pos + total); /* If everything ok, continue. */ if (br > 0) continue; /* If EOF or error return number of bytes read. */ if (!br || total) return total; + /* + * If pread is not supported by the OS, fall back to emulating + * it by seek() + read(). + */ + if (errno == ENOSYS && _pread != fake_pread) { + _pread = fake_pread; + goto seek; + } /* Nothing read and error, return error status. */ return br; } @@ -206,6 +236,22 @@ s64 ntfs_pread(struct ntfs_device *dev, const s64 pos, s64 count, void *b) return total; } +/** + * fake_pwrite - write operation disguised as pwrite + * @dev: device to write to + * @b: input data buffer + * @count: number of bytes to write + * @pos: position in device to write to + * + * Auxiliary function, used when we emulate pwrite by seek() + a sequence of + * write()s. + */ +static s64 fake_pwrite(struct ntfs_device *dev, const void *b, s64 count, + s64 pos __attribute__((unused))) +{ + return dev->d_ops->write(dev, b, count); +} + /** * ntfs_pwrite - positioned write to disk * @dev: device to write to @@ -230,6 +276,7 @@ s64 ntfs_pwrite(struct ntfs_device *dev, const s64 pos, s64 count, { s64 written, total; struct ntfs_device_operations *dops; + s64 (*_pwrite)(struct ntfs_device *, const void *, s64, s64); ntfs_log_trace("Entering for pos 0x%llx, count 0x%llx.\n", pos, count); if (!b || count < 0 || pos < 0) { @@ -243,8 +290,15 @@ s64 ntfs_pwrite(struct ntfs_device *dev, const s64 pos, s64 count, return -1; } dops = dev->d_ops; - /* Locate to position. */ - if (dops->seek(dev, pos, SEEK_SET) == (off_t)-1) { + _pwrite = dops->pwrite; + if (!_pwrite) + _pwrite = fake_pwrite; +seek: + /* + * Locate to position if pwrite is to be emulated by seek() + write(). + */ + if (_pwrite == fake_pwrite && + dops->seek(dev, pos, SEEK_SET) == (off_t)-1) { ntfs_log_perror("ntfs_pwrite: seek to 0x%llx returned error", pos); return -1; @@ -252,7 +306,8 @@ s64 ntfs_pwrite(struct ntfs_device *dev, const s64 pos, s64 count, NDevSetDirty(dev); /* Write the data. */ for (total = 0; count; count -= written, total += written) { - written = dops->write(dev, (const char*)b + total, count); + written = _pwrite(dev, (const char*)b + total, count, + pos + total); /* If everything ok, continue. */ if (written > 0) continue; @@ -261,6 +316,14 @@ s64 ntfs_pwrite(struct ntfs_device *dev, const s64 pos, s64 count, */ if (!written || total) break; + /* + * If pwrite is not supported by the OS, fall back to emulating + * it by seek() + write(). + */ + if (errno == ENOSYS && _pwrite != fake_pwrite) { + _pwrite = fake_pwrite; + goto seek; + } /* Nothing written and error, return error status. */ return written; } diff --git a/libntfs/dir.c b/libntfs/dir.c index b25e7ea5..3b157011 100644 --- a/libntfs/dir.c +++ b/libntfs/dir.c @@ -486,25 +486,23 @@ close_err_out: u64 ntfs_pathname_to_inode_num(ntfs_volume *vol, ntfs_inode *parent, const char *pathname) { - u64 inum, result = (u64)-1; + u64 inum, result; int len, err = 0; char *p, *q; ntfs_inode *ni = NULL; ntfschar *unicode = NULL; char *ascii = NULL; + inum = result = (u64)-1; if (!vol || !pathname) { err = EINVAL; goto close; } - ntfs_log_trace("Path: '%s'\n", pathname); - if (parent) { ni = parent; } else inum = FILE_root; - unicode = calloc(1, MAX_PATH); ascii = strdup(pathname); if (!unicode || !ascii) { @@ -512,7 +510,6 @@ u64 ntfs_pathname_to_inode_num(ntfs_volume *vol, ntfs_inode *parent, err = ENOMEM; goto close; } - p = ascii; /* Remove leading /'s. */ while (p && *p == PATH_SEP) @@ -527,14 +524,12 @@ u64 ntfs_pathname_to_inode_num(ntfs_volume *vol, ntfs_inode *parent, goto close; } } - /* Find the end of the first token. */ q = strchr(p, PATH_SEP); if (q != NULL) { *q = 0; q++; } - len = ntfs_mbstoucs(p, &unicode, MAX_PATH); if (len < 0) { ntfs_log_debug("Couldn't convert name to Unicode: " @@ -542,20 +537,17 @@ u64 ntfs_pathname_to_inode_num(ntfs_volume *vol, ntfs_inode *parent, err = EILSEQ; goto close; } - inum = ntfs_inode_lookup_by_name(ni, unicode, len); - if (inum == (u64) -1) { + if (inum == (u64)-1) { ntfs_log_debug("Couldn't find name '%s' in pathname " "'%s'.\n", p, pathname); err = ENOENT; goto close; } inum = MREF(inum); - if (ni != parent) ntfs_inode_close(ni); ni = NULL; - p = q; while (p && *p == PATH_SEP) p++; diff --git a/libntfs/unix_io.c b/libntfs/unix_io.c index 048791e0..cd1b4573 100644 --- a/libntfs/unix_io.c +++ b/libntfs/unix_io.c @@ -229,7 +229,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 ntfs_pread(dev, offset, count, buf); + return pread(DEV_FD(dev), buf, count, offset); } /** @@ -251,7 +251,7 @@ static s64 ntfs_device_unix_io_pwrite(struct ntfs_device *dev, const void *buf, return -1; } NDevSetDirty(dev); - return ntfs_pwrite(dev, offset, count, buf); + return pwrite(DEV_FD(dev), buf, count, offset); } /** diff --git a/libntfs/win32_io.c b/libntfs/win32_io.c index 752df435..4360a20c 100644 --- a/libntfs/win32_io.c +++ b/libntfs/win32_io.c @@ -1449,26 +1449,12 @@ static int ntfs_device_win32_ioctl(struct ntfs_device *dev, int request, } } -static s64 ntfs_device_win32_pread(struct ntfs_device *dev, void *b, - s64 count, s64 offset) -{ - return ntfs_pread(dev, offset, count, b); -} - -static s64 ntfs_device_win32_pwrite(struct ntfs_device *dev, const void *b, - s64 count, s64 offset) -{ - return ntfs_pwrite(dev, offset, count, b); -} - struct ntfs_device_operations ntfs_device_win32_io_ops = { .open = ntfs_device_win32_open, .close = ntfs_device_win32_close, .seek = ntfs_device_win32_seek, .read = ntfs_device_win32_read, .write = ntfs_device_win32_write, - .pread = ntfs_device_win32_pread, - .pwrite = ntfs_device_win32_pwrite, .sync = ntfs_device_win32_sync, .stat = ntfs_device_win32_stat, .ioctl = ntfs_device_win32_ioctl