Changes by: antona
Update of /cvsroot/linux-ntfs/linux-ntfs/libntfs
In directory usw-pr-cvs1:/tmp/cvs-serv31088/libntfs
Modified Files:
attrib.c disk_io.c mft.c
Log Message:
Mft mirror now updated from ntfs_write_mft_record, yey! Fixup ntfstools accordingly.
Index: attrib.c
===================================================================
RCS file: /cvsroot/linux-ntfs/linux-ntfs/libntfs/attrib.c,v
retrieving revision 1.42
retrieving revision 1.43
diff -U2 -r1.42 -r1.43
--- attrib.c 5 Jun 2002 09:19:44 -0000 1.42
+++ attrib.c 5 Jun 2002 20:32:53 -0000 1.43
@@ -2128,8 +2128,8 @@
* @bk_cnt: number of mst protected blocks to read
* @bk_size: size of each mst protected block in bytes
- * @dst: output data buffer
+ * @b: output data buffer
*
* This function will read @bk_cnt blocks of size @bk_size bytes each starting
- * at offset @pos from the ntfs attribute @na into the buffer @dst.
+ * at offset @pos from the ntfs attribute @na into the data buffer @b.
*
* On success, the multi sector transfer fixups are applied and the number of
@@ -2137,8 +2137,9 @@
* that the read has either reached end of attribute or that an error was
* encountered during the read so that the read is partial. 0 means end of
- * attribute or nothing to read (@bk_cnt or @bk_size are 0).
+ * attribute or nothing to read (also return 0 when @bk_cnt or @bk_size are 0).
*
* On error and nothing has been read, return -1 with errno set appropriately
- * to the return code of ntfs_pread() or to EINVAL in case of invalid arguments.
+ * to the return code of ntfs_attr_pread() or to EINVAL in case of invalid
+ * arguments.
*
* NOTE: If an incomplete multi sector transfer is detected the magic is
@@ -2151,5 +2152,5 @@
*/
__s64 ntfs_attr_mst_pread(ntfs_attr *na, const __s64 pos, const __s64 bk_cnt,
- const __u32 bk_size, void *dst)
+ const __u32 bk_size, void *b)
{
__s64 br;
@@ -2162,12 +2163,80 @@
return -1;
}
- br = ntfs_attr_pread(na, pos, bk_cnt * bk_size, dst);
+ br = ntfs_attr_pread(na, pos, bk_cnt * bk_size, b);
if (br <= 0)
return br;
br /= bk_size;
- for (end = dst + br * bk_size; dst < end; dst += bk_size)
- ntfs_post_read_mst_fixup((NTFS_RECORD*)dst, bk_size);
+ for (end = b + br * bk_size; b < end; b += bk_size)
+ ntfs_post_read_mst_fixup((NTFS_RECORD*)b, bk_size);
/* Finally, return the number of blocks read. */
return br;
+}
+
+/**
+ * ntfs_attr_mst_pwrite - multi sector transfer protected ntfs attribute write
+ * @na: multi sector transfer protected ntfs attribute to write to
+ * @pos: position in the attribute to write to
+ * @bk_cnt: number of mst protected blocks to write
+ * @bk_size: size of each mst protected block in bytes
+ * @b: data buffer to write to disk
+ *
+ * This function will write @bk_cnt blocks of size @bk_size bytes each from
+ * data buffer @b to multi sector transfer (mst) protected ntfs attribute @na
+ * at position @pos.
+ *
+ * On success, return the number of successfully written blocks. If this number
+ * is lower than @bk_cnt this means that an error was encountered during the
+ * write so that the write is partial. 0 means nothing was written (also
+ * return 0 when @bk_cnt or @bk_size are 0).
+ *
+ * On error and nothing has been written, return -1 with errno set
+ * appropriately to the return code of ntfs_attr_pwrite(), or to EINVAL in case
+ * of invalid arguments.
+ *
+ * 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 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 ntfs_attr_mst_pwrite(ntfs_attr *na, const __s64 pos, __s64 bk_cnt,
+ const __u32 bk_size, void *b)
+{
+ __s64 written, i;
+
+ Dprintf(__FUNCTION__ "(): Entering for inode 0x%Lx, attr type 0x%x, "
+ "pos 0x%Lx.\n", na->ni->mft_no, na->type, pos);
+ if (bk_cnt < 0 || bk_size % NTFS_SECTOR_SIZE) {
+ errno = EINVAL;
+ return -1;
+ }
+ if (!bk_cnt)
+ return 0;
+ /* Prepare data for writing. */
+ for (i = 0; i < bk_cnt; ++i) {
+ int err;
+
+ err = ntfs_pre_write_mst_fixup((NTFS_RECORD*)(b + i * bk_size),
+ bk_size);
+ if (err < 0) {
+ /* Abort write at this position. */
+ if (!i)
+ return err;
+ bk_cnt = i;
+ break;
+ }
+ }
+ /* Write the prepared data. */
+ written = ntfs_attr_pwrite(na, pos, bk_cnt * bk_size, b);
+ /* Quickly deprotect the data again. */
+ for (i = 0; i < bk_cnt; ++i)
+ ntfs_post_write_mst_fixup((NTFS_RECORD*)(b + i * bk_size));
+ if (written <= 0)
+ return written;
+ /* Finally, return the number of complete blocks written. */
+ return written / bk_size;
}
Index: disk_io.c
===================================================================
RCS file: /cvsroot/linux-ntfs/linux-ntfs/libntfs/disk_io.c,v
retrieving revision 1.26
retrieving revision 1.27
diff -U2 -r1.26 -r1.27
--- disk_io.c 5 Jun 2002 00:29:19 -0000 1.26
+++ disk_io.c 5 Jun 2002 20:32:53 -0000 1.27
@@ -235,5 +235,5 @@
__s64 written, i;
- if (bksize & (bksize - 1) || bksize % NTFS_SECTOR_SIZE) {
+ if (count < 0 || bksize % NTFS_SECTOR_SIZE) {
errno = EINVAL;
return -1;
@@ -260,5 +260,5 @@
for (i = 0; i < count; ++i)
ntfs_post_write_mst_fixup((NTFS_RECORD*)(b + i * bksize));
- if (written < 0)
+ if (written <= 0)
return written;
/* Finally, return the number of complete blocks written. */
Index: mft.c
===================================================================
RCS file: /cvsroot/linux-ntfs/linux-ntfs/libntfs/mft.c,v
retrieving revision 1.26
retrieving revision 1.27
diff -U2 -r1.26 -r1.27
--- mft.c 1 Jun 2002 00:41:45 -0000 1.26
+++ mft.c 5 Jun 2002 20:32:53 -0000 1.27
@@ -24,4 +24,5 @@
#include <stdlib.h>
#include <errno.h>
+#include <string.h>
#include "mft.h"
@@ -85,62 +86,77 @@
* @b: data buffer containing the mft records to write
*
- * Write mft records starting with @mref from buffer @b to volume @vol. Return
- * 0 on success or -1 on error, with errno set to the error code.
+ * Write @count mft records starting at @mref from data buffer @b to volume
+ * @vol. Return 0 on success or -1 on error, with errno set to the error code.
*
* Before the mft records are written, they are mst protected. After the write,
* they are deprotected again, thus resulting in an increase in the update
- * sequence number inside the buffer @b.
+ * sequence number inside the data buffer @b.
*
- * FIXME: Take ->initialized_size & ->data_size into consideration... (AIA)
- * TODO/FIXME: Should this extend $MFT? Probably... (AIA)
+ * If any mft records are written which are also represented in the mft mirror
+ * $MFTMirr, we make a copy of the relevant parts of the data buffer @b into a
+ * temporary buffer before we do the actual write. Then if at least one mft
+ * record was successfully written, we write the appropriate mft records from
+ * the copied buffer to the mft mirror, too.
*/
int ntfs_write_mft_records(const ntfs_volume *vol, const MFT_REF mref,
const __s64 count, MFT_RECORD *b)
{
- __s64 bw, ofs;
- LCN lcn;
+ __s64 bw;
VCN m;
+ void *bmirr = NULL;
+ int cnt = 0, res = 0;
- if (!vol || !b || count < 0) {
+ Dprintf(__FUNCTION__ "(): Entering for inode 0x%Lx.\n", MREF(mref));
+ if (!vol || !vol->mft_na || !b || count < 0) {
errno = EINVAL;
return -1;
}
- if (!vol->fd) {
- errno = EBADF;
- return -1;
- }
m = MREF(mref);
- if (vol->nr_mft_records < m + count) {
- errno = ESPIPE;
+ if (m < vol->mftmirr_size) {
+ cnt = vol->mftmirr_size - m;
+ bmirr = malloc(cnt * vol->mft_record_size);
+ if (!bmirr)
+ return -1;
+ memcpy(bmirr, b, cnt * vol->mft_record_size);
+ }
+ if (m + count > vol->nr_mft_records) {
+ // TODO: Need to extend $MFT. This is not just normal attribute
+ // extension as many rules need to be observed. (AIA)
+ if (bmirr);
+ free(bmirr);
+ errno = ENOTSUP;
return -1;
}
- /* Starting cluster of the first mft record to write. */
- lcn = ntfs_rl_vcn_to_lcn(vol->mft_na->rl, m <<
- vol->mft_record_size_bits >> vol->cluster_size_bits);
- /*
- * We always keep the COMPLETE run list for $MFT/$DATA in
- * vol->mft_rl.
- */
- if (lcn < 0) {
- Dprintf(__FUNCTION__ "(): BUG! ntfs_vcn_to_lcn() on $MFT/$DATA "
- "returned %Li.\n", lcn);
- errno = EIO;
- return -1;
- }
- /* Offset within the cluster of the first mft record to write. */
- ofs = (m << vol->mft_record_size_bits) & (vol->cluster_size - 1);
- bw = ntfs_mst_pwrite(vol->fd, (lcn << vol->cluster_size_bits) + ofs,
+ bw = ntfs_attr_mst_pwrite(vol->mft_na, m << vol->mft_record_size_bits,
count, vol->mft_record_size, b);
if (bw != count) {
if (bw != -1)
errno = EIO;
- if (!bw)
- Dputs("Error: ran out of input data writing $Mft "
+ if (bw >= 0)
+ Dputs("Error: partial write while writing $Mft "
"record(s)!\n");
else
Dperror("Error writing $Mft record(s)");
- return -1;
+ res = errno;
}
- return 0;
+ if (bmirr && bw > 0) {
+ if (bw < cnt)
+ cnt = bw;
+ bw = ntfs_attr_mst_pwrite(vol->mftmirr_na,
+ m << vol->mft_record_size_bits, cnt,
+ vol->mft_record_size, bmirr);
+ if (bw != cnt) {
+ if (bw != -1)
+ errno = EIO;
+ Dputs("Error: failed to sync $MFTMirr! Run chkdsk.");
+ res = errno;
+ }
+ }
+ if (bmirr)
+ free(bmirr);
+ if (!res)
+ return res;
+ errno = res;
+ return -1;
}
@@ -184,7 +200,10 @@
return -1;
}
- m = (MFT_RECORD*)malloc(vol->mft_record_size);
- if (!m)
- return -1;
+ m = *mrec;
+ if (!m) {
+ m = (MFT_RECORD*)malloc(vol->mft_record_size);
+ if (!m)
+ return -1;
+ }
if (ntfs_read_mft_record(vol, mref, m)) {
err = errno;
@@ -208,5 +227,6 @@
err = EIO;
read_failed:
- free(m);
+ if (m != *mrec)
+ free(m);
errno = err;
return -1;
|