Changes by: antona
Update of /cvsroot/linux-ntfs/linux-ntfs/libntfs
In directory usw-pr-cvs1:/tmp/cvs-serv22587/libntfs
Modified Files:
attrib.c disk_io.c
Log Message:
Make ntfs_attr_pread work with resident attributes and start on ntfs_attr_pwrite (incomplete!).
Index: attrib.c
===================================================================
RCS file: /cvsroot/linux-ntfs/linux-ntfs/libntfs/attrib.c,v
retrieving revision 1.40
retrieving revision 1.41
diff -U2 -r1.40 -r1.41
--- attrib.c 2 Jun 2002 23:02:20 -0000 1.40
+++ attrib.c 5 Jun 2002 00:29:18 -0000 1.41
@@ -37,4 +37,5 @@
#include "layout.h"
#include "inode.h"
+#include "endians.h"
/* FIXME: Need to write the new flags to disk. */
@@ -1656,19 +1657,19 @@
* @pos: byte position in the attribute to begin reading from
* @count: number of bytes to read
- * @dst: output data buffer
+ * @b: output data buffer
*
* This function will read @count bytes starting at offset @pos from the ntfs
- * attribute @na into the buffer @dst.
- *
- * On success, return return the number of successfully read bytes. If this
- * number is lower than @count this means that we have either reached end of
- * file or we encountered an error during the read so that the read is partial.
- * 0 means end of file or nothing to read (@count is 0).
+ * attribute @na into the data buffer @b.
*
- * On error and nothing has been read yet, return -1 with errno set
- * appropriately to the return code of ntfs_pread(), or to EINVAL in case of
- * invalid arguments.
+ * On success, return the number of successfully read bytes. If this number is
+ * lower than @count this means that the read reached end of file or thet an
+ * error was encountered during the read so that the read is partial. 0 means
+ * end of file or nothing was read (also return 0 when @count is 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.
*/
-__s64 ntfs_attr_pread(ntfs_attr *na, const __s64 pos, __s64 count, void *dst)
+__s64 ntfs_attr_pread(ntfs_attr *na, const __s64 pos, __s64 count, void *b)
{
__s64 br, to_read, ofs, total;
@@ -1680,5 +1681,5 @@
"0x%Lx, count 0x%Lx.\n", na->ni->mft_no, na->type, pos,
count);
- if (!na || !na->ni || !na->ni->vol || !dst || pos < 0 || count < 0) {
+ if (!na || !na->ni || !na->ni->vol || !b || pos < 0 || count < 0) {
errno = EINVAL;
return -1;
@@ -1690,22 +1691,66 @@
return -1;
}
+ /*
+ * Encrypted attributes are not supported. We return access denied,
+ * which is what Windows NT4 does, too.
+ */
+ if (NAttrEncrypted(na)) {
+ errno = EACCES;
+ return -1;
+ }
+ /* If this is a compressed attribute it needs special treatment. */
+ if (NAttrCompressed(na)) {
+ // TODO: Implement reading compressed attributes! (AIA)
+ // return ntfs_attr_pread_compressed(ntfs_attr *na,
+ // const __s64 pos, __s64 count, void *b);
+ errno = ENOTSUP;
+ return -1;
+ }
if (!count)
return 0;
/* Truncate reads beyond end of attribute. */
if (pos + count > na->data_size) {
- if (pos > na->data_size)
+ if (pos >= na->data_size)
return 0;
count = na->data_size - pos;
}
+ /* If it is a resident attribute, get the value from the mft record. */
+ if (!NAttrNonResident(na)) {
+ ntfs_attr_search_ctx *ctx;
+ char *val;
+
+ ctx = ntfs_get_attr_search_ctx(na->ni, NULL);
+ if (!ctx)
+ return -1;
+ if (ntfs_lookup_attr(na->type, na->name, na->name_len, 0,
+ 0, NULL, 0, ctx)) {
+ int eo;
+res_err_out:
+ eo = errno;
+ ntfs_put_attr_search_ctx(ctx);
+ errno = eo;
+ return -1;
+ }
+ val = (char*)ctx->attr + le16_to_cpu(ctx->attr->value_offset);
+ if (val < (char*)ctx->attr || val +
+ le32_to_cpu(ctx->attr->value_length) >
+ (char*)ctx->mrec + vol->mft_record_size) {
+ errno = EIO;
+ goto res_err_out;
+ }
+ memcpy(b, val + pos, count);
+ ntfs_put_attr_search_ctx(ctx);
+ return count;
+ }
total = 0;
/* Zero out reads beyond initialized size. */
if (pos + count > na->initialized_size) {
- if (pos > na->initialized_size) {
- memset(dst, 0, count);
+ if (pos >= na->initialized_size) {
+ memset(b, 0, count);
return count;
}
total = pos + count - na->initialized_size;
count -= total;
- memset(dst + count, 0, total);
+ memset(b + count, 0, total);
}
/* Find the run list element containing the vcn. */
@@ -1744,9 +1789,9 @@
to_read = min(count, (rl->length <<
vol->cluster_size_bits) - ofs);
- memset(dst, 0, to_read);
+ memset(b, 0, to_read);
/* Update progress counters. */
total += to_read;
count -= to_read;
- dst += to_read;
+ b += to_read;
continue;
}
@@ -1759,10 +1804,10 @@
rl->vcn, rl->lcn, ofs);
br = ntfs_pread(f, (rl->lcn << vol->cluster_size_bits) + ofs,
- to_read, dst);
+ to_read, b);
/* If everything ok, update progress counters and continue. */
if (br > 0) {
total += br;
count -= br;
- dst += br;
+ b += br;
continue;
}
@@ -1781,4 +1826,272 @@
/**
+ * ntfs_attr_pwrite - positioned write to an ntfs attribute
+ * @na: ntfs attribute to write to
+ * @pos: position in the attribute to write to
+ * @count: number of bytes to write
+ * @b: data buffer to write to disk
+ *
+ * This function will write @count bytes from data buffer @b to ntfs attribute
+ * @na at position @pos.
+ *
+ * On success, return the number of successfully written bytes. If this number
+ * is lower than @count 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 @count is 0).
+ *
+ * On error and nothing has been written, return -1 with errno set
+ * appropriately to the return code of ntfs_pwrite(), or to EINVAL in case of
+ * invalid arguments.
+ *
+ * NOTE: Currently changes in length of the attribute @na are not implemented.
+ * Thus if such a change is requested we return -1 with errno set to ENOTSUP.
+ */
+__s64 ntfs_attr_pwrite(ntfs_attr *na, const __s64 pos, __s64 count, void *b)
+{
+ __s64 br, to_write, ofs, total, old_initialized_size;
+ ntfs_volume *vol;
+ ntfs_attr_search_ctx *ctx = NULL;
+ run_list_element *rl;
+ int f, eo;
+ struct {
+ unsigned int initialized_size : 1;
+ } need_to_undo = { 0 };
+
+ Dprintf(__FUNCTION__ "(): Entering for inode 0x%Lx, attr 0x%x, pos "
+ "0x%Lx, count 0x%Lx.\n", na->ni->mft_no, na->type, pos,
+ count);
+ if (!na || !na->ni || !na->ni->vol || !b || pos < 0 || count < 0) {
+ errno = EINVAL;
+ return -1;
+ }
+ vol = na->ni->vol;
+ f = vol->fd;
+ if (!f) {
+ errno = EBADF;
+ return -1;
+ }
+ /*
+ * Encrypted attributes are not supported. We return access denied,
+ * which is what Windows NT4 does, too.
+ */
+ if (NAttrEncrypted(na)) {
+ errno = EACCES;
+ return -1;
+ }
+ /* If this is a compressed attribute it needs special treatment. */
+ if (NAttrCompressed(na)) {
+ // TODO: Implement writing compressed attributes! (AIA)
+ // return ntfs_attr_pwrite_compressed(ntfs_attr *na,
+ // const __s64 pos, __s64 count, void *b);
+ errno = ENOTSUP;
+ return -1;
+ }
+ if (!count)
+ return 0;
+ /* If the write reaches beyond the end, extend the attribute. */
+ if (pos + count > na->data_size) {
+ // TODO: Need to extend the attribute. For now, just do a
+ // partial write or abort if completely out of bounds. (AIA)
+ if (pos >= na->data_size) {
+ errno = ENOTSUP;
+ return -1;
+ }
+ count = na->data_size - pos;
+ }
+ old_initialized_size = na->initialized_size;
+ /* If it is a resident attribute, write the data to the mft record. */
+ if (!NAttrNonResident(na)) {
+ char *val;
+
+ ctx = ntfs_get_attr_search_ctx(na->ni, NULL);
+ if (!ctx)
+ goto err_out;
+ if (ntfs_lookup_attr(na->type, na->name, na->name_len, 0,
+ 0, NULL, 0, ctx))
+ goto err_out;
+ val = (char*)ctx->attr + le16_to_cpu(ctx->attr->value_offset);
+ if (val < (char*)ctx->attr || val +
+ le32_to_cpu(ctx->attr->value_length) >
+ (char*)ctx->mrec + vol->mft_record_size) {
+ errno = EIO;
+ goto err_out;
+ }
+ memcpy(val + pos, b, count);
+ if (ntfs_write_mft_record(vol, ctx->ntfs_ino->mft_no,
+ ctx->mrec)) {
+ /*
+ * NOTE: We are in a bad state at this moment. We have
+ * dirtied the mft record but we failed to commit it to
+ * disk. Since we have read the mft record ok before,
+ * it is unlikely to fail writing it, so is ok to just
+ * return error here... (AIA)
+ */
+ goto err_out;
+ }
+ ntfs_put_attr_search_ctx(ctx);
+ return count;
+ }
+ total = 0;
+ /* Find the run list element containing the vcn. */
+ rl = ntfs_attr_find_vcn(na, pos >> vol->cluster_size_bits);
+ if (!rl) {
+ /*
+ * If the vcn is not present it is an out of bounds read which
+ * means a read beyond end of file, thus just return 0.
+ */
+ if (errno == ENOENT)
+ goto done;
+ goto err_out;
+ }
+ /* Handle writes beyond initialized_size. */
+ if (pos + count > na->initialized_size) {
+ /* Set initialized_size to @pos + @count. */
+ ctx = ntfs_get_attr_search_ctx(na->ni, NULL);
+ if (!ctx)
+ goto err_out;
+ if (ntfs_lookup_attr(na->type, na->name, na->name_len, 0,
+ 0, NULL, 0, ctx))
+ goto err_out;
+ /* If write starts beyond initialized_size, zero the gap. */
+ if (pos > na->initialized_size) {
+ // TODO: Need to write zeroes in the region from
+ // na->initialized_size to @pos, then update the
+ // initialized size to equal @pos. If any sparse runs
+ // are encountered while filling the gap, need to
+ // honour them, i.e. do not instantiate them. Then can
+ // continue as if pos <= na->initialized_size, i.e. can
+ // just fall through and continue. (AIA)
+ errno = ENOTSUP;
+ goto err_out;
+ }
+ ctx->attr->initialized_size = scpu_to_le64(pos + count);
+ if (ntfs_write_mft_record(vol, ctx->ntfs_ino->mft_no,
+ ctx->mrec)) {
+ /*
+ * Undo the change in the in-memory copy and send it
+ * back for writing.
+ */
+ ctx->attr->initialized_size =
+ scpu_to_le64(old_initialized_size);
+ ntfs_write_mft_record(vol, ctx->ntfs_ino->mft_no,
+ ctx->mrec);
+ goto err_out;
+ }
+ na->initialized_size = pos + count;
+ ntfs_put_attr_search_ctx(ctx);
+ ctx = NULL;
+ /*
+ * NOTE: At this point the initialized_size in the mft record
+ * has been updated BUT there is random data on disk thus if
+ * we decide to abort, we MUST change the initialized_size
+ * again.
+ */
+ need_to_undo.initialized_size = 1;
+ }
+
+// FIXME: Am here! (AIA)
+errno = ENOTSUP;
+goto err_out;
+ /*
+ * Gather the requested data into the linear destination buffer. Note,
+ * a partial final vcn is taken care of by the @count capping of read
+ * length.
+ */
+ ofs = pos - (rl->vcn << vol->cluster_size_bits);
+ for (; count; rl++, ofs = 0) {
+ /* If we have reached the end of the run list return. */
+ if (!rl->length)
+ goto done;
+ if (rl->lcn < (LCN)0) {
+ if (rl->lcn != (LCN)LCN_HOLE) {
+ /*
+ * If we have already read anything, return how
+ * much. Same if the read is beyond the end.
+ */
+ if (total || rl->lcn == (LCN)LCN_ENOENT)
+ goto done;
+ errno = EIO;
+ goto err_out;
+ }
+ /* It is a hole, just zero the matching @dst range. */
+ to_write = min(count, (rl->length <<
+ vol->cluster_size_bits) - ofs);
+ memset(b, 0, to_write);
+ /* Update progress counters. */
+ total += to_write;
+ count -= to_write;
+ b += to_write;
+ continue;
+ }
+ /* It is a real lcn, read it into @dst. */
+ to_write = min(count, (rl->length << vol->cluster_size_bits) -
+ ofs);
+retry:
+ Dprintf(__FUNCTION__ "(): Reading 0x%Lx bytes from vcn "
+ "0x%Lx, lcn 0x%Lx, ofs 0x%Lx.\n", to_write,
+ rl->vcn, rl->lcn, ofs);
+ br = ntfs_pread(f, (rl->lcn << vol->cluster_size_bits) + ofs,
+ to_write, b);
+ /* If everything ok, update progress counters and continue. */
+ if (br > 0) {
+ total += br;
+ count -= br;
+ b += br;
+ continue;
+ }
+ /* If the syscall was interrupted, try again. */
+ if (br == (__s64)-1 && errno == EINTR)
+ goto retry;
+ /* If EOF or error, return number of bytes read. */
+ if (!br || total)
+ goto done;
+ /* Nothing read, return error. */
+ goto err_out;
+ }
+done:
+ if (ctx)
+ ntfs_put_attr_search_ctx(ctx);
+ /* Finally, return the number of bytes read. */
+ return total;
+err_out:
+ eo = errno;
+ if (need_to_undo.initialized_size) {
+ int err;
+
+ err = 0;
+ if (!ctx) {
+ ctx = ntfs_get_attr_search_ctx(na->ni, NULL);
+ if (!ctx)
+ err = 1;
+ } else
+ ntfs_reinit_attr_search_ctx(ctx);
+ if (!err) {
+ err = ntfs_lookup_attr(na->type, na->name,
+ na->name_len, 0, 0, NULL, 0, ctx);
+ if (!err) {
+ na->initialized_size = old_initialized_size;
+ ctx->attr->initialized_size = scpu_to_le64(
+ old_initialized_size);
+ err = ntfs_write_mft_record(vol,
+ ctx->ntfs_ino->mft_no,
+ ctx->mrec);
+ }
+ }
+ if (err) {
+ Dputs("Eeek! Failed to recover from error. Leaving "
+ "metadata in inconsistent state! Run "
+ "chkdsk!");
+ // FIXME: At this stage could try to recover by filling
+ // old_initialized_size -> new_initialized_size with
+ // data or at least zeroes. (AIA)
+ }
+ }
+ if (ctx)
+ ntfs_put_attr_search_ctx(ctx);
+ errno = eo;
+ return -1;
+}
+
+/**
* ntfs_attr_mst_pread - multi sector transfer protected ntfs attribute read
* @na: multi sector transfer protected ntfs attribute to read from
@@ -1791,21 +2104,20 @@
* at offset @pos from the ntfs attribute @na into the buffer @dst.
*
- * On succes, the multi sector transfer fixups are applied and the number of
- * read blocks is returned. If this number is lower than @bk_cnt this means we
- * that we have either reached end of file or we encountered an error during
- * the read so that the read is partial. 0 means end of file or nothing to read
- * (@bk_cnt is 0).
+ * On success, the multi sector transfer fixups are applied and the number of
+ * read blocks is returned. If this number is lower than @bk_cnt this means
+ * 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).
*
- * On error and nothing has been read yet, return -1 with errno set
- * appropriately to the return code of ntfs_pread(), or to EINVAL in case of
- * invalid arguments.
+ * 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.
*
* NOTE: If an incomplete multi sector transfer is detected the magic is
- * changed to BAAD but no error is returned, i.e. it is possible that
- * any of the returned blocks have multi sector transfer errors. This
- * should be detected by the caller by checking each block with
- * is_baad_recordp(&block). The reasoning is that we want to fixup as
- * many blocks as possible and we want to return even bad ones to the
- * caller so, e.g. in case of ntfsck, the errors can be repaired.
+ * changed to BAAD but no error is returned, i.e. it is possible that any of
+ * the returned blocks have multi sector transfer errors. This should be
+ * detected by the caller by checking each block with is_baad_recordp(&block).
+ * The reasoning is that we want to fixup as many blocks as possible and we
+ * want to return even bad ones to the caller so, e.g. in case of ntfsck, the
+ * errors can be repaired.
*/
__s64 ntfs_attr_mst_pread(ntfs_attr *na, const __s64 pos, const __s64 bk_cnt,
@@ -1822,5 +2134,5 @@
}
br = ntfs_attr_pread(na, pos, bk_cnt * bk_size, dst);
- if (!br || br == (__s64)-1)
+ if (br <= 0)
return br;
br /= bk_size;
Index: disk_io.c
===================================================================
RCS file: /cvsroot/linux-ntfs/linux-ntfs/libntfs/disk_io.c,v
retrieving revision 1.25
retrieving revision 1.26
diff -U2 -r1.25 -r1.26
--- disk_io.c 4 Jun 2002 12:12:42 -0000 1.25
+++ disk_io.c 5 Jun 2002 00:29:19 -0000 1.26
@@ -41,5 +41,5 @@
*
* This function will read @count bytes from file descriptor @fd at position
- * @pos into the buffer @b.
+ * @pos into the data buffer @b.
*
* On success, return the number of successfully read bytes. If this number is
@@ -93,6 +93,6 @@
* @b: data buffer to write to disk
*
- * This function will write @count bytes of data @b to file descriptor @fd at
- * position @pos.
+ * This function will write @count bytes from data buffer @b to file descriptor
+ * @fd at position @pos.
*
* On success, return the number of successfully written bytes. If this number
@@ -154,5 +154,5 @@
* 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.
+ * into the data buffer @b.
*
* On success, return the number of successfully read blocks. If this number is
@@ -210,5 +210,5 @@
* Multi sector transfer (mst) positioned write. This function will write
* @count blocks of size @bksize bytes each from data buffer @b to file
- * descriptor @fd at position @pos into the file @fd.
+ * descriptor @fd at position @pos.
*
* On success, return the number of successfully written blocks. If this number
|