Changes by: antona
Update of /cvsroot/linux-ntfs/linux-ntfs/libntfs
In directory usw-pr-cvs1:/tmp/cvs-serv29096
Modified Files:
attrib.c disk_io.c mft.c volume.c
Log Message:
Big rewrite of disk_io.c. Now should have stable API for low level disk access. Move all mft record related stuff from disk_io.c to mft.c.
Index: attrib.c
===================================================================
RCS file: /cvsroot/linux-ntfs/linux-ntfs/libntfs/attrib.c,v
retrieving revision 1.18
retrieving revision 1.19
diff -U2 -r1.18 -r1.19
--- attrib.c 14 Apr 2002 15:26:23 -0000 1.18
+++ attrib.c 15 Apr 2002 00:42:07 -0000 1.19
@@ -341,8 +341,8 @@
*/
r = ntfs_pread(vol->fd, intbuf,
- vol->cluster_size,
- rl[i].length,
- rl[i].lcn <<
- vol->cluster_size_bits);
+ vol->cluster_size *
+ rl[i].length,
+ rl[i].lcn <<
+ vol->cluster_size_bits);
if (r != rl[i].length) {
#define ESTR "Error reading attribute value"
@@ -377,8 +377,7 @@
*/
r = ntfs_pread(vol->fd, b + total,
- vol->cluster_size,
- rl[i].length,
- rl[i].lcn <<
- vol->cluster_size_bits);
+ vol->cluster_size *
+ rl[i].length, rl[i].lcn <<
+ vol->cluster_size_bits);
if (r != rl[i].length) {
#define ESTR "Error reading attribute value"
Index: disk_io.c
===================================================================
RCS file: /cvsroot/linux-ntfs/linux-ntfs/libntfs/disk_io.c,v
retrieving revision 1.16
retrieving revision 1.17
diff -U2 -r1.16 -r1.17
--- disk_io.c 14 Apr 2002 15:26:23 -0000 1.16
+++ disk_io.c 15 Apr 2002 00:42:07 -0000 1.17
@@ -30,12 +30,75 @@
#include "types.h"
#include "disk_io.h"
-#include "bitmap.h"
+#include "debug.h"
-__s64 ntfs_pwrite(int fd, const void *b, __s64 count, const __s64 pos)
+/**
+ * ntfs_pread - positioned read from disk
+ * @fd: file descriptor to read from
+ * @pos: position in file descriptor to read from
+ * @count: number of bytes to read
+ * @b: output data buffer
+ *
+ * This function will read @count bytes from file descriptor @fd at position
+ * @pos into the buffer @b.
+ *
+ * On success, return the number of successfully read bytes. If this number is
+ * lower than @count this means that we have reached end of file. 0 means end
+ * of file or nothing to read (@count is 0). On error, return -1 with errno set
+ * appropriately to the return code of either lseek or read, or to EINVAL in
+ * case the data pointer @b was NULL.
+ */
+__s64 ntfs_pread(const int fd, const __s64 pos, __s64 count, void *b)
+{
+ __s64 br, total;
+ char retry;
+
+ if (!b || count < 0 || pos < 0) {
+ errno = EINVAL;
+ return -1;
+ }
+ if (!count)
+ return 0;
+ /* Locate to position. */
+ if (lseek(fd, pos, SEEK_SET) == (off_t)-1) {
+ Dprintf("ntfs_pread: lseek to 0x%Lx returned error: %s\n", pos,
+ strerror(errno));
+ return -1;
+ }
+ /* Read the data. */
+ total = retry = 0;
+ do {
+ br = read(fd, ((char *)b) + total, count);
+ if (br == -1)
+ return br;
+ else if (!br)
+ ++retry;
+ /* We just recycle count as a local variable here. */
+ count -= br;
+ total += br;
+ } while (count && (retry < 3));
+ /* Finally, return the number of bytes read. */
+ return count;
+}
+
+/**
+ * ntfs_pwrite - positioned write to disk
+ * @fd: file descriptor to write to
+ * @pos: position in file descriptor to write to
+ * @count: number of bytes to write
+ * @b: data buffer to write to disk
+ *
+ * This function will write @count bytes of data @b to file descriptor @fd at
+ * position @pos.
+ *
+ * On success return bytes written (0 means nothing written).
+ * On error return -1 with errno set appropriately to the return code of
+ * either lseek, malloc, write or fdatasync. Or errno is EINVAL if @b is null.
+ */
+__s64 ntfs_pwrite(int fd, const __s64 pos, __s64 count, const void *b)
{
__s64 written, total;
char retry;
- if (!b) {
+ if (!b || count < 0 || pos < 0) {
errno = EINVAL;
return -1;
@@ -44,6 +107,9 @@
return 0;
/* Locate to position. */
- if (lseek(fd, pos, SEEK_SET) == (off_t)-1)
+ if (lseek(fd, pos, SEEK_SET) == (off_t)-1) {
+ Dprintf("ntfs_pwrite: lseek to 0x%Lx returned error: %s\n",
+ pos, strerror(errno));
return -1;
+ }
/* Write the data. */
total = retry = 0;
@@ -65,411 +131,217 @@
}
-/*
+/**
+ * ntfs_mst_pread - multi sector transfer (mst) positioned read
+ * @fd: file descriptor to read from
+ * @pos: position in file descriptor to read from
+ * @count: number of blocks to read
+ * @bksize: size of each block that needs mst deprotecting
+ * @b: output data buffer
+ *
+ * Multi sector transfer (mst) positioned read. This function will read @count
+ * @blocks of size @bksize bytes each from file descriptor @fd at position @pos
+ * into the buffer @b.
+ *
+ * On success, return the number of successfully read blocks. If this number is
+ * lower than @count this means that we have reached end of file. 0 means end
+ * of file or nothing to read (@count or @bksize is 0). On error, return -1
+ * with errno set appropriately to the return code of either lseek or read, or
+ * to EINVAL in case the data pointer @b was NULL or the block size (@bksize)
+ * was not a multiple of NTFS_SECTOR_SIZE or @bksize was not a power of two.
+ *
+ * NOTE: If an incomplete multi sector transfer has been detected the magic
+ * will have been changed to magic_BAAD but no error will be returned.
+ * I.e. it is possible that we return count blocks as being read but that
+ * any number (between zero and count!) of these blocks is actually
+ * subject to a multi sector transfer error. This should be detected by
+ * the caller by checking for the magic being "BAAD".
+ */
+__s64 ntfs_mst_pread(const int fd, const __s64 pos, __s64 count,
+ const __u32 bksize, void *b)
+{
+ __s64 br, i;
+
+ if (!b || count < 0 || pos < 0 || bksize & bksize - 1 ||
+ bksize % NTFS_SECTOR_SIZE) {
+ errno = EINVAL;
+ return -1;
+ }
+ /* Do the read. */
+ br = ntfs_pread(fd, pos, count * bksize, b);
+ if (br == -1)
+ return br;
+ /*
+ * Apply fixups to successfully read data, disregarding any errors
+ * returned from the MST fixup function. This is because we want to
+ * fixup everything possible and we rely on the fact that the "BAAD"
+ * magic will be detected later on.
+ */
+ count = br / bksize;
+ for (i = 0; i < count; ++i)
+ post_read_mst_fixup((NTFS_RECORD*)(b + i * bksize), bksize);
+ /* Finally, return the number of complete blocks read. */
+ return count;
+}
+
+/**
+ * ntfs_mst_pwrite - multi sector transfer (mst) positioned write
+ * @fd: file descriptor to write to
+ * @pos: position in file descriptor to write to
+ * @count: number of blocks to write
+ * @bksize: size of each block that needs mst protecting
+ * @b: data buffer to write to disk
+ *
+ * Multi sector transfer (mst) positioned write. This function will write
+ * @count bytes of data @b to file descriptor @fd at position @pos.
+ *
+ * On success return bytes written (0 means nothing written).
+ * On error return -1 with errno set appropriately to the return code of
+ * either lseek, malloc, write or fdatasync. Or errno is EINVAL if @b is null.
+ *
* NOTE: We mst protect the data, write it, then mst deprotect it using a quick
* deprotect algorithm (no checking). This saves us from making a copy before
- * the write and at the same causes the usn to be incremented in the buffer.
- * This conceptually fits in better with the idea that cached data is always
- * deprotected and protection is performed when the data is actually going to
- * hit the disk and the cache is immediately deprotected again simulating an
- * mst read on the written data. This way cache coherency is achieved.
+ * the write and at the same time causes the usn to be incremented in the
+ * buffer. This conceptually fits in better with the idea that cached data is
+ * always deprotected and protection is performed when the data is actually
+ * going to hit the disk and the cache is immediately deprotected again
+ * simulating an mst read on the written data. This way cache coherency is
+ * achieved.
*/
-__s64 mst_pwrite(int fd, const void *b, __s64 count, const __s64 pos)
+__s64 ntfs_mst_pwrite(int fd, const __s64 pos, const __s64 count,
+ const __u32 bksize, const void *b)
{
- __s64 written, total, error;
+ __s64 written, towrite, total;
char retry;
- if (!b) {
+ if (!b || count < 0 || pos < 0 || bksize & bksize - 1 ||
+ bksize % NTFS_SECTOR_SIZE) {
errno = EINVAL;
- error = -1;
- goto error_end;
- }
- if (!count) {
- error = 0;
- goto error_end;
+ return -1;
}
- /* Locate to position. */
+ if (!count)
+ return 0;
+ /* Seek to position. */
if (lseek(fd, pos, SEEK_SET) == (off_t)-1) {
- error = -1;
- goto error_end;
+ Dprintf("ntfs_mst_pwrite: lseek to 0x%Lx returned error: %s\n",
+ pos, strerror(errno));
+ return -1;
}
/* Prepare data for writing. */
- pre_write_mst_fixup((NTFS_RECORD*)b, count);
+ for (i = 0; i < count; ++i)
+ pre_write_mst_fixup((NTFS_RECORD*)(b + i * bksize), bksize);
/* Write the prepared data. */
+ towrite = count * bksize;
total = retry = 0;
do {
- written = write(fd, ((char *)b) + total, count);
+ written = write(fd, ((char *)b) + total, towrite);
if (written == -1) {
- error = -1;
+ total = -1;
goto finished;
- }
- else if (!written)
+ } else if (!written)
++retry;
/* We just recycle count as a local variable here. */
- count -= written;
+ towrite -= written;
total += written;
- } while (count && (retry < 3));
- /* Sync write to disk. */
- if (fdatasync(fd) == -1) {
- error = -1;
- goto finished;
- }
- /* Finally return the number of bytes written. */
- error = total;
+ } while (towrite && (retry < 3));
finished:
/* Quickly deprotect the data again. */
- post_write_mst_fixup((NTFS_RECORD*)b);
-error_end:
- return error;
+ for (i = 0; i < count; ++i)
+ post_write_mst_fixup((NTFS_RECORD*)(b + i * bksize));
+ /* Sync write to disk. */
+ if (fdatasync(fd) == -1)
+ total = -1;
+ /* Convert bytes written to blocks written. */
+ if (total != -1)
+ total /= bksize;
+ /*
+ * Finally return the number of complete blocks written or -1 for
+ * error. We ignore errors where a partial block was written at the end
+ * because these will be caught later on anyway.
+ */
+ return total;
}
-__s64 ntfs_pread(const int fd, void *b, const __u32 bksize, __s64 count,
- const __s64 pos)
+/**
+ * ntfs_read_clusters - read ntfs clusters
+ * @vol: volume to read from
+ * @lcn: starting logical cluster number
+ * @count: number of clusters to read
+ * @b: output data buffer
+ *
+ * Read @count ntfs clusters starting at logical cluster number @lcn from
+ * volume @vol into buffer @b. Return number of clusters read or -1 on error,
+ * with errno set to the error code.
+ */
+__s64 ntfs_read_clusters(const ntfs_volume *vol, const __s64 lcn, __s64 count,
+ void *b)
{
- __s64 br, btr, total;
- char bksize_bits;
+ __s64 br;
- /* Nothing to read so, return 0. */
- if (!count || !bksize)
- return 0;
- /* Calculate bksize_bits. */
- for (bksize_bits = 0, br = bksize; br > 1; br >>= 1)
- ++bksize_bits;
- /* Check buffer. Only multiples of NTFS_SECTOR_SIZE and powers of
- two are alowed for bksize. */
- if (!b || (bksize_bits < NTFS_SECTOR_SIZE_BITS) ||
- (bksize != 1 << bksize_bits)) {
-#ifdef DEBUG
- if (!b)
- puts("ntfs_pread: b is NULL");
- if (bksize_bits < NTFS_SECTOR_SIZE_BITS)
- puts("ntfs_pread: bksize_bits < NTFS_SECTOR_SIZE_BITS");
- if (bksize != 1 << bksize_bits)
- puts("ntfs_pread: bksize != 1 << bksize_bits");
- puts("Returning EINVAL");
-#endif
+ if (!vol || !b || count < 0 || lcn < 0) {
errno = EINVAL;
return -1;
}
- /* Locate to position. */
- if (lseek(fd, pos, SEEK_SET) == (off_t)-1) {
-#ifdef DEBUG
- int eo = errno;
- printf("ntfs_pread: lseek to 0x%Lx returned -1\n", pos);
- errno = eo;
-#endif
+ if (!vol->fd) {
+ errno = EBADF;
return -1;
}
- /* Read the data. */
- total = 0;
- btr = count << bksize_bits;
- /* Loop until we have read all data even if it happens only a byte at
- a time. */
- do {
- br = read(fd, ((char *)b) + total, btr);
- if (br == -1)
- return br;
- if (!br) {
- /* Calculate the number of complete blocks read
- (and recycle count as a local variable). */
- count -= btr >> bksize_bits;
- break;
- }
- btr -= br;
- total += br;
- } while (btr);
- /* Finally, return the number of blocks read. */
- return count;
-}
-
-__s64 mst_pread(const int fd, void *b, const __u32 bksize, __s64 count,
- const __s64 pos)
-{
- __s64 br, i;
- char bksize_bits;
-
- /* Do the read. */
- count = ntfs_pread(fd, b, bksize, count, pos);
- /* Calculate bksize_bits. */
- for (bksize_bits = 0, br = bksize; br > 1; br >>= 1)
- ++bksize_bits;
- /* Apply fixups to successfully read data. Note, that we disregard
- any errors returned from the MST fixup function. This is because we
- want to fixup everything possible and we rely on the fact that the
- "BAAD" magic will be detected later on anyway (before the data is
- made use of). */
- for (i = 0; i < count; ++i)
- post_read_mst_fixup((NTFS_RECORD*)(b +
- (i << bksize_bits)), bksize);
- /* Finally, return the number of blocks read. */
- return count;
-}
-
-int get_clusters(const ntfs_volume *vol, __u8 *buf, const __s64 lcn,
- const int count)
-{
- __s64 br;
-
- if (!vol || !buf || count < 0 || lcn < 0)
- return -EINVAL;
- if (!vol->fd)
- return -EBADF;
- if (vol->number_of_clusters < lcn + count)
- return -ESPIPE;
- br = ntfs_pread(vol->fd, buf, vol->cluster_size, count,
- lcn << vol->cluster_size_bits);
- if (br != count) {
- int eo = errno;
-#define ESTR "Error reading cluster(s)"
- if (br == -1) {
- perror(ESTR);
- return -eo;
- } else if (!br)
- fprintf(stderr, "Error: partition is smaller than "
- "it should be!?! Weird!\n");
- else
- fprintf(stderr, ESTR ": unknown error\n");
-#undef ESTR
- return -EIO;
- }
- return br;
-}
-
-int put_clusters(ntfs_volume *vol, const __u8 *buf, const __s64 lcn, int count)
-{
- __s64 bw;
-
- if (!vol || !buf || count < 0 || lcn < 0)
- return -EINVAL;
- if (!vol->fd)
- return -EBADF;
- if (vol->number_of_clusters < lcn + count)
- return -ESPIPE;
- bw = ntfs_pwrite(vol->fd, buf, count << vol->cluster_size_bits,
- lcn << vol->cluster_size_bits);
- if (bw != count << vol->cluster_size_bits) {
- int eo = errno;
-#define ESTR "Error writting cluster(s)"
- if (bw == -1) {
- perror(ESTR);
- return -eo;
- } else if (!bw)
- fprintf(stderr, ESTR ": Ran out of input data!\n");
- else
- fprintf(stderr, ESTR ": unknown error\n");
-#undef ESTR
- return -EIO;
+ if (vol->number_of_clusters < lcn + count) {
+ errno = ESPIPE;
+ return -1;
}
- return bw >> vol->cluster_size_bits;
-}
-
-/**
- * get_mft_records - read records from the mft from disk
- * @vol: volume to read from
- * @mrec: output data buffer
- * @mref: starting mft record number
- * @count: number of mft records to read
- *
- * Read @count mft records starting at @mref from volume @vol into buffer
- * @mrec. Return @count on success or -ERRNO on error, where ERRNO is the error
- * code. This function will do the error reporting so caller really only needs
- * to check for sucess / failure.
- *
- * NOTE: @mrec has to be at least of size @count * vol->mft_record_size.
- */
-int get_mft_records(const ntfs_volume *vol, const MFT_RECORD *mrec,
- const MFT_REF *mref, const int count)
-{
- __s64 br, ofs;
- LCN lcn;
- VCN m;
-
- if (!vol || !mrec)
- return -EINVAL;
- if (!vol->fd)
- return -EBADF;
- m = MREF(*mref);
- if (vol->number_of_mft_records < m + count)
- return -ESPIPE;
- if (!ntfs_get_bit(vol->mft_bitmap, m))
- return -ENOENT;
- lcn = vcn_to_lcn(vol->mft_runlist, m << vol->mft_record_size_bits >>
- vol->cluster_size_bits);
- if (lcn == -1) {
- perror("Error sparse $Mft records are not supported");
- return -ENOTSUP;
- }
- ofs = m << vol->mft_record_size_bits & vol->cluster_size - 1;
- br = mst_pread(vol->fd, (__u8*)mrec, vol->mft_record_size, count,
- (lcn << vol->cluster_size_bits) + ofs);
+ count <<= vol->cluster_size_bits;
+ br = ntfs_pread(vol->fd, lcn << vol->cluster_size_bits, count, b);
if (br != count) {
- int eo = errno;
-#define ESTR "Error reading $Mft record"
- if (br == -1) {
- perror(ESTR);
- return -eo;
- } else if (!br)
- fprintf(stderr, "Error: partition is smaller than "
- "it should be!?! Weird!\n");
+ if (br != -1)
+ errno = EIO;
+ if (!br)
+ Dputs("Error: partition is smaller than it should be!");
else
- fprintf(stderr, ESTR ": unknown error\n");
-#undef ESTR
- return -EIO;
+ Dperror("Error reading cluster(s)");
+ return -1;
}
- return br;
-}
-
-/**
- * get_mft_record - read a record from the mft
- * @vol: volume to read from
- * @mrec: output data buffer
- * @mref: starting mft record number
- * @count: number of mft records to read
- *
- * Read mft record specified by @mref from volume @vol into buffer @mrec.
- * Return 1 on success or -ERRNO on error, where ERRNO is the error
- * code. This function will do the error reporting so caller really only needs
- * to check for sucess / failure.
- *
- * NOTE: @mrec has to be at least of size vol->mft_record_size.
- */
-__inline__ int get_mft_record(const ntfs_volume *vol, const MFT_RECORD *mrec,
- const MFT_REF *mref)
-{
- return get_mft_records(vol, mrec, mref, 1);
+ return br >> vol->cluster_size_bits;
}
/**
- * __read_file_record - read a FILE record from the mft from disk
- * @vol: volume to read from
- * @mref: mft reference specifying mft record to read
- * @mrec: address of pointer in which to return the mft record
- * @attr: address of pointer in which to return the first attribute
- *
- * Read a FILE record from the mft of @vol from the storage medium. @mref
- * specifies the mft record to read, including the sequence number. When the
- * function returns, @mrec and @attr will contain pointers to the read mft
- * record and to the first attribute within the mft record, respectively.
- * @attr is optional (can be NULL).
+ * ntfs_write_clusters - write ntfs clusters
+ * @vol: volume to write to
+ * @lcn: starting logical cluster number
+ * @count: number of clusters to write
+ * @b: data buffer to write to disk
*
- * The read mft record is checked for having the magic FILE, for being in use,
- * and for having a matching sequence number (if MSEQNO(*@mref) != 0).
- * If either of these fails, return -EIO.
- *
- * Return 0 on success, or -ERRNO on error, where ERRNO is the error code.
- *
- * Note: Caller has to free *@mrec when finished.
+ * Write @count ntfs clusters starting at logical cluster number @lcn from
+ * buffer @b to volume @vol. Return the nu,ber of clusters written or -1 on
+ * error, with errno set to the error code.
*/
-int __read_file_record(const ntfs_volume *vol, const MFT_REF *mref,
- MFT_RECORD **mrec, ATTR_RECORD **attr)
+__s64 ntfs_write_clusters(ntfs_volume *vol, const __s64 lcn, __s64 count,
+ const void *b)
{
- MFT_RECORD *m;
- ATTR_RECORD *a;
- int er = 0;
-
- if (!vol || !mrec) {
-#ifdef DEBUG
- fprintf(stderr, "read_file_record() received NULL pointer!\n");
-#endif
- return -EINVAL;
- }
- if (!(m = malloc(vol->mft_record_size)))
- return -ENOMEM;
- if ((er = get_mft_record(vol, m, mref)) != 1)
- goto failed;
- if (!is_file_record(m->magic))
- goto file_corrupt;
- if (MSEQNO(*mref) && MSEQNO(*mref) != le16_to_cpu(m->sequence_number))
- goto file_corrupt;
- if (!(m->flags & MFT_RECORD_IN_USE))
- goto file_corrupt;
- a = (ATTR_RECORD*)((char*)m + le16_to_cpu(m->attrs_offset));
- if (p2n(a) < p2n(m) || (char*)a > (char*)m + vol->mft_record_size)
- goto file_corrupt;
- *mrec = m;
- if (attr)
- *attr = a;
- return 0;
-file_corrupt:
-#ifdef DEBUG
- fprintf(stderr, "read_file_record(): file is corrupt.\n");
-#endif
- er = -EIO;
-failed:
- free(m);
- return er < 0 ? er : -EINVAL;
-}
-
-/**
- * read_file_record - read a FILE record from the mft from @vol
- * @vol: volume to read from
- * @mref: mft reference specifying mft record to read
- * @mrec: address of pointer in which to return the mft record
- * @attr: address of pointer in which to return the first attribute
- *
- * Return the FILE record @mref from the mft of @vol. @mref, the mft record to
- * return, includes the sequence number, which can be 0 if no sequence number
- * checking is to be performed. If the mft record is already loaded in the
- * volume's mft cache this is returned straight away. Otherwise a new mft entry
- * is allocated and inserted into the cache and the mft record is within the
- * entry is returned. When the function returns, @mrec and @attr will contain
- * pointers to the mft record and to the first attribute within the mft record,
- * respectively. @attr is optional (can be NULL).
- *
- * The mft record is checked for having the magic FILE, for being in use,
- * and for having a matching sequence number (if MSEQNO(*@mref) != 0).
- * If either of these fails, return -EIO.
- *
- * Return 0 on success, or -ERRNO on error, where ERRNO is the error code.
- *
- * Note: Caller has to free *@mrec when finished.
- */
-int read_file_record(const ntfs_volume *vol, const MFT_REF *mref,
- MFT_RECORD **mrec, ATTR_RECORD **attr)
-{
- return -ENOTSUP;
-}
+ __s64 bw;
-int put_mft_record(ntfs_volume *vol, const __u8 *buf, const MFT_REF *mref)
-{
- __s64 bw, m;
- __s64 lcn, ofs;
-
- if (!vol || !buf)
- return -EINVAL;
- if (!vol->fd)
- return -EBADF;
- m = MREF(*mref);
- if (vol->number_of_mft_records <= m)
- return -ESPIPE;
- if (!ntfs_get_bit(vol->mft_bitmap, m))
- return -ENOENT;
- lcn = vcn_to_lcn(vol->mft_runlist, m << vol->mft_record_size_bits >>
- vol->cluster_size_bits);
- if (lcn == -1) {
- perror("Error sparse $Mft records are not supported");
- return -ENOTSUP;
- }
- ofs = m << vol->mft_record_size_bits & vol->cluster_size - 1;
- if (lcn == -1) {
- int eo = errno;
- perror("Error determining on disk location of $Mft record");
- return -eo;
- }
- bw = mst_pwrite(vol->fd, buf, vol->mft_record_size,
- (lcn << vol->cluster_size_bits) + ofs);
- if (bw != vol->mft_record_size) {
- int eo = errno;
-#define ESTR "Error writing $Mft record"
- if (bw == -1) {
- perror(ESTR);
- return -eo;
- } else if (!bw)
- fprintf(stderr, ESTR ": Ran out of input data!\n");
+ if (!vol || !b || count < 0 || lcn < 0) {
+ errno = EINVAL;
+ return -1;
+ }
+ if (!vol->fd) {
+ errno = EBADF;
+ return -1;
+ }
+ if (vol->number_of_clusters < lcn + count) {
+ errno = ESPIPE;
+ return -1;
+ }
+ count <<= vol->cluster_size_bits;
+ bw = ntfs_pwrite(vol->fd, lcn << vol->cluster_size_bits, count, b);
+ if (bw != count) {
+ if (bw != -1)
+ errno = EIO;
+ if (!bw)
+ Dputs("Ran out of input data while writing clusters!");
else
- fprintf(stderr, ESTR ": unknown error\n");
-#undef ESTR
- return -EIO;
+ Dperror("Error writing cluster(s)");
+ return -1;
}
- return 1;
+ return bw >> vol->cluster_size_bits;
}
Index: mft.c
===================================================================
RCS file: /cvsroot/linux-ntfs/linux-ntfs/libntfs/mft.c,v
retrieving revision 1.13
retrieving revision 1.14
diff -U2 -r1.13 -r1.14
--- mft.c 14 Apr 2002 14:08:30 -0000 1.13
+++ mft.c 15 Apr 2002 00:42:07 -0000 1.14
@@ -23,3 +23,227 @@
#include "mft.h"
+#include "disk_io.h"
+#include "bitmap.h"
+
+/**
+ * get_mft_records - read records from the mft from disk
+ * @vol: volume to read from
+ * @mrec: output data buffer
+ * @mref: starting mft record number
+ * @count: number of mft records to read
+ *
+ * Read @count mft records starting at @mref from volume @vol into buffer
+ * @mrec. Return @count on success or -ERRNO on error, where ERRNO is the error
+ * code. This function will do the error reporting so caller really only needs
+ * to check for sucess / failure.
+ *
+ * NOTE: @mrec has to be at least of size @count * vol->mft_record_size.
+ */
+int get_mft_records(const ntfs_volume *vol, const MFT_RECORD *mrec,
+ const MFT_REF *mref, const int count)
+{
+ __s64 br, ofs;
+ LCN lcn;
+ VCN m;
+
+ if (!vol || !mrec)
+ return -EINVAL;
+ if (!vol->fd)
+ return -EBADF;
+ m = MREF(*mref);
+ if (vol->number_of_mft_records < m + count)
+ return -ESPIPE;
+ if (!ntfs_get_bit(vol->mft_bitmap, m))
+ return -ENOENT;
+ lcn = vcn_to_lcn(vol->mft_runlist, m << vol->mft_record_size_bits >>
+ vol->cluster_size_bits);
+ if (lcn == -1) {
+ perror("Error sparse $Mft records are not supported");
+ return -ENOTSUP;
+ }
+ ofs = m << vol->mft_record_size_bits & vol->cluster_size - 1;
+ br = mst_pread(vol->fd, (__u8*)mrec, vol->mft_record_size, count,
+ (lcn << vol->cluster_size_bits) + ofs);
+ if (br != count) {
+ int eo = errno;
+#define ESTR "Error reading $Mft record"
+ if (br == -1) {
+ perror(ESTR);
+ return -eo;
+ } else if (!br)
+ fprintf(stderr, "Error: partition is smaller than "
+ "it should be!?! Weird!\n");
+ else
+ fprintf(stderr, ESTR ": unknown error\n");
+#undef ESTR
+ return -EIO;
+ }
+ return br;
+}
+
+/**
+ * get_mft_record - read a record from the mft
+ * @vol: volume to read from
+ * @mrec: output data buffer
+ * @mref: starting mft record number
+ * @count: number of mft records to read
+ *
+ * Read mft record specified by @mref from volume @vol into buffer @mrec.
+ * Return 1 on success or -ERRNO on error, where ERRNO is the error
+ * code. This function will do the error reporting so caller really only needs
+ * to check for sucess / failure.
+ *
+ * NOTE: @mrec has to be at least of size vol->mft_record_size.
+ */
+__inline__ int get_mft_record(const ntfs_volume *vol, const MFT_RECORD *mrec,
+ const MFT_REF *mref)
+{
+ return get_mft_records(vol, mrec, mref, 1);
+}
+
+/**
+ * __read_file_record - read a FILE record from the mft from disk
+ * @vol: volume to read from
+ * @mref: mft reference specifying mft record to read
+ * @mrec: address of pointer in which to return the mft record
+ * @attr: address of pointer in which to return the first attribute
+ *
+ * Read a FILE record from the mft of @vol from the storage medium. @mref
+ * specifies the mft record to read, including the sequence number. When the
+ * function returns, @mrec and @attr will contain pointers to the read mft
+ * record and to the first attribute within the mft record, respectively.
+ * @attr is optional (can be NULL).
+ *
+ * The read mft record is checked for having the magic FILE, for being in use,
+ * and for having a matching sequence number (if MSEQNO(*@mref) != 0).
+ * If either of these fails, return -EIO.
+ *
+ * Return 0 on success, or -ERRNO on error, where ERRNO is the error code.
+ *
+ * Note: Caller has to free *@mrec when finished.
+ */
+int __read_file_record(const ntfs_volume *vol, const MFT_REF *mref,
+ MFT_RECORD **mrec, ATTR_RECORD **attr)
+{
+ MFT_RECORD *m;
+ ATTR_RECORD *a;
+ int er = 0;
+
+ if (!vol || !mrec) {
+#ifdef DEBUG
+ fprintf(stderr, "read_file_record() received NULL pointer!\n");
+#endif
+ return -EINVAL;
+ }
+ if (!(m = malloc(vol->mft_record_size)))
+ return -ENOMEM;
+ if ((er = get_mft_record(vol, m, mref)) != 1)
+ goto failed;
+ if (!is_file_record(m->magic))
+ goto file_corrupt;
+ if (MSEQNO(*mref) && MSEQNO(*mref) != le16_to_cpu(m->sequence_number))
+ goto file_corrupt;
+ if (!(m->flags & MFT_RECORD_IN_USE))
+ goto file_corrupt;
+ a = (ATTR_RECORD*)((char*)m + le16_to_cpu(m->attrs_offset));
+ if (p2n(a) < p2n(m) || (char*)a > (char*)m + vol->mft_record_size)
+ goto file_corrupt;
+ *mrec = m;
+ if (attr)
+ *attr = a;
+ return 0;
+file_corrupt:
+#ifdef DEBUG
+ fprintf(stderr, "read_file_record(): file is corrupt.\n");
+#endif
+ er = -EIO;
+failed:
+ free(m);
+ return er < 0 ? er : -EINVAL;
+}
+
+/**
+ * read_file_record - read a FILE record from the mft from @vol
+ * @vol: volume to read from
+ * @mref: mft reference specifying mft record to read
+ * @mrec: address of pointer in which to return the mft record
+ * @attr: address of pointer in which to return the first attribute
+ *
+ * Return the FILE record @mref from the mft of @vol. @mref, the mft record to
+ * return, includes the sequence number, which can be 0 if no sequence number
+ * checking is to be performed. If the mft record is already loaded in the
+ * volume's mft cache this is returned straight away. Otherwise a new mft entry
+ * is allocated and inserted into the cache and the mft record is within the
+ * entry is returned. When the function returns, @mrec and @attr will contain
+ * pointers to the mft record and to the first attribute within the mft record,
+ * respectively. @attr is optional (can be NULL).
+ *
+ * The mft record is checked for having the magic FILE, for being in use,
+ * and for having a matching sequence number (if MSEQNO(*@mref) != 0).
+ * If either of these fails, return -EIO.
+ *
+ * Return 0 on success, or -ERRNO on error, where ERRNO is the error code.
+ *
+ * Note: Caller has to free *@mrec when finished.
+ */
+int read_file_record(const ntfs_volume *vol, const MFT_REF *mref,
+ MFT_RECORD **mrec, ATTR_RECORD **attr)
+{
+ return -ENOTSUP;
+}
+
+/**
+ * put_mft_record - write a record to the mft
+ * @vol: volume to write to
+ * @buf: data buffer containing the mft record to write
+ * @mref: mft record number to write to
+ *
+ * Write mft record @mref from buffer @buf to volume @vol. Return 1 on
+ * success or -ERRNO on error, where ERRNO is the error code. This function
+ * will do the error reporting so caller really only needs to check for sucess
+ * / failure.
+ */
+int put_mft_record(ntfs_volume *vol, const __u8 *buf, const MFT_REF *mref)
+{
+ __s64 bw, m;
+ __s64 lcn, ofs;
+
+ if (!vol || !buf)
+ return -EINVAL;
+ if (!vol->fd)
+ return -EBADF;
+ m = MREF(*mref);
+ if (vol->number_of_mft_records <= m)
+ return -ESPIPE;
+ if (!ntfs_get_bit(vol->mft_bitmap, m))
+ return -ENOENT;
+ lcn = vcn_to_lcn(vol->mft_runlist, m << vol->mft_record_size_bits >>
+ vol->cluster_size_bits);
+ if (lcn == -1) {
+ perror("Error sparse $Mft records are not supported");
+ return -ENOTSUP;
+ }
+ ofs = m << vol->mft_record_size_bits & vol->cluster_size - 1;
+ if (lcn == -1) {
+ int eo = errno;
+ perror("Error determining on disk location of $Mft record");
+ return -eo;
+ }
+ bw = mst_pwrite(vol->fd, buf, vol->mft_record_size,
+ (lcn << vol->cluster_size_bits) + ofs);
+ if (bw != vol->mft_record_size) {
+ int eo = errno;
+#define ESTR "Error writing $Mft record"
+ if (bw == -1) {
+ perror(ESTR);
+ return -eo;
+ } else if (!bw)
+ fprintf(stderr, ESTR ": Ran out of input data!\n");
+ else
+ fprintf(stderr, ESTR ": unknown error\n");
+#undef ESTR
+ return -EIO;
+ }
+ return 1;
+}
Index: volume.c
===================================================================
RCS file: /cvsroot/linux-ntfs/linux-ntfs/libntfs/volume.c,v
retrieving revision 1.21
retrieving revision 1.22
diff -U2 -r1.21 -r1.22
--- volume.c 14 Apr 2002 14:08:30 -0000 1.21
+++ volume.c 15 Apr 2002 00:42:08 -0000 1.22
@@ -137,5 +137,5 @@
}
/* Now read the bootsector. */
- br = ntfs_pread(vol->fd, bs, sizeof(NTFS_BOOT_SECTOR), 1, 0);
+ br = ntfs_pread(vol->fd, bs, sizeof(NTFS_BOOT_SECTOR), 0);
if (br != 1) {
Dputs(FAILED);
|