On Tue, Sep 03, 2013 at 09:52:55PM +0200, Jean-Pierre André wrote:

[snip]

> >Thanks for the reply.
> >
> >I made a simple change, I set the initialized size to be equal to data
> >size:
> >
> >attr->initialized_size = cpu_to_le64(na->data_size);
> >
> >instead of:
> >
> >attr->initialized_size = cpu_to_le64(na->initialized_size);
> >
> >That seems to have solved the issue I was having. Now, I am using the
> >fuse drive to do the writes and all works as expected.
> >
> >What do you think of that change?
> 
> This is wrong, you make the file to be visible up to its
> apparent size, even in parts not yet written to. However
> this shows that what I suggested (quoted above) would
> do the job.
> 
> Initialized size serves as a fence to indicate the part of
> a file which has not been written to, and should not be
> disclosed. This allocated space may contain data left
> over by another user. Data size is the apparent size of
> the file and the space between initialized size and data
> size must appear as zeroed when read.
> 

Hi,

Sorry for the long overdue reply.

I have attached two patches here that I have been using based on your
code. This applies to ntfs-3g-2013.1.13AR.1:

 1. truncate_solid.patch
 2. ntfs_fallocate.patch
    + This adds an fallocate operation to the fuse layer. Of course,
      this will need fuse-2.9.2 or higher and a kernel that adds the
      fallocate op to the fuse driver.

Thus, this allows me to call fallocate sys call and have the desired
effect.

Thanks,
Amit
Implement fallocate.
--- a/src/ntfs-3g.c
+++ b/src/ntfs-3g.c
@@ -3305,6 +3305,140 @@
 	ntfs_close();
 }
 
+static int ntfs_fallocate(const char *path, int mode, off_t offset, off_t len, struct
+		fuse_file_info *fi)
+{
+	int res = -1;
+	ntfs_inode *ni = NULL;
+	ntfs_attr *na = NULL;
+	s64 data_size;
+	s64 initialized_size;
+	ntfs_attr_search_ctx *sctx;
+	ATTR_RECORD *attr;
+
+	ntfs_log_info("ntfs_fallocate: path=%s, mode=%d, offset=%lld, len=%lld\n",
+			path, mode, (long long int) offset, (long long int) len);
+
+	ni = ntfs_pathname_to_inode(ctx->vol, NULL, path);
+	if (!ni)
+	{
+		ntfs_log_error("Failed to open file \"%s\": %s\n",
+				path, strerror(errno));
+		goto out;
+	}
+
+	/* Open the specified attribute. */
+	na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0);
+	if (!na) {
+		ntfs_log_error("Failed to open attribute for inode: %s\n",
+				strerror(errno));
+		goto out;
+	}
+
+	/* Locate the attribute record, needed for updating sizes */
+	sctx = ntfs_attr_get_search_ctx(ni, NULL);
+	if (!sctx)
+	{
+		ntfs_log_error("Failed to allocate a search context\n");
+		goto out;
+	}
+	else
+	{
+		if (ntfs_attr_lookup(AT_DATA, AT_UNNAMED, 0, CASE_SENSITIVE, 0, NULL, 0, sctx))
+		{
+			ntfs_log_error("Failed to locate the attribute\n");
+			goto out;
+		}
+	}
+
+	initialized_size = na->initialized_size;
+	data_size = na->data_size;
+	int err = 0;
+
+	if (initialized_size < (offset + len))
+	{
+
+		/* Truncate to initialized size when within request */
+		if (initialized_size >= offset)
+		{
+			err = ntfs_attr_truncate(na, initialized_size);
+		}
+		else
+		{
+			/* Sparse allocation to begin of request */
+			err = ntfs_attr_truncate(na, offset);
+		}
+
+		/* Allocate the attribute as requested */
+		if (!err)
+			err = ntfs_attr_truncate_solid(na, offset + len);
+		if (err)
+		{
+			ntfs_log_error("Failed to truncate attribute 0x%lx: %s\n",
+				(unsigned long)le32_to_cpu(AT_DATA), strerror(errno));
+			goto out;
+		}
+	}
+	else
+	{
+		/* There is initialized data past the requested allocation This
+		 * may mean a requested allocation within a hole, but we
+		 * currently cannot do anything without losing data.
+         */
+		ntfs_log_error("** Unsupported case : existing "
+				"data beyond the requested allocation\n");
+		err = TRUE;
+	}
+
+	/* Set the sizes, even after an error, to keep consistency */
+	na->initialized_size = initialized_size;
+
+	/* Restore the original apparent size if there is an error */
+	if (err)
+		na->data_size = data_size;
+	else
+	{
+		/* otherwise man fallocate and man posix_fallocate() do not
+		 * mention the final apparent size.  the opengroup spec for
+		 * posix_fallocate() requires size to be set to offs+len
+		 * TODO check the behavior of another file system
+		 */
+		na->data_size = offset + len;
+	}
+
+	/* Feed the sizes into the attribute */
+	attr = sctx->attr;
+	attr->data_size = cpu_to_le64(na->data_size);
+	attr->initialized_size = cpu_to_le64(na->data_size);
+	attr->allocated_size = cpu_to_le64(na->allocated_size);
+	ntfs_attr_put_search_ctx(sctx);
+
+	/* Copy sizes to inode, if this is the unnamed data attribute
+	 * In our case, data attribute is always unnamed data attr.
+	 */
+	ni->data_size = na->data_size;
+	ni->allocated_size = na->allocated_size;
+
+	/* Mark file name dirty, to update the sizes in directories */
+	NInoFileNameSetDirty(ni);
+	NInoSetDirty(ni);
+
+	/* Close the attribute. */
+	ntfs_attr_close(na);
+	na = NULL;
+
+	/* Done */
+	res = err;
+
+out:
+	if (na)
+		ntfs_attr_close(na);
+	if (ni)
+		ntfs_inode_close(ni);
+
+	return res;
+}
+
 static struct fuse_operations ntfs_3g_ops = {
 #if defined(HAVE_UTIMENSAT) && (defined(FUSE_INTERNAL) || (FUSE_VERSION > 28))
 		/*
@@ -3362,8 +3496,9 @@
 #endif /* defined(__APPLE__) || defined(__DARWIN__) */
 #if defined(FUSE_CAP_DONT_MASK) || defined(FUSE_CAP_BIG_WRITES) \
 		|| (defined(__APPLE__) || defined(__DARWIN__))
-	.init		= ntfs_init
+	.init		= ntfs_init,
 #endif
+	.fallocate  = ntfs_fallocate
 };
 
 static int ntfs_fuse_init(void)
Add patch to support truncate solid.
--- a/include/ntfs-3g/attrib.h
+++ b/include/ntfs-3g/attrib.h
@@ -61,7 +61,8 @@
 typedef enum {			/* ways of processing holes when expanding */
 	HOLES_NO,
 	HOLES_OK,
-	HOLES_DELAY
+	HOLES_DELAY,
+	HOLES_NONRES
 } hole_type;
 
 /**
--- a/libntfs-3g/attrib.c
+++ b/libntfs-3g/attrib.c
@@ -4928,7 +4928,7 @@
  *	ENOSPC - There is no enough space in base mft to resize $ATTRIBUTE_LIST.
  */
 static int ntfs_resident_attr_resize_i(ntfs_attr *na, const s64 newsize,
-			BOOL force_non_resident)
+			hole_type holes)
 {
 	ntfs_attr_search_ctx *ctx;
 	ntfs_volume *vol;
@@ -4966,7 +4966,7 @@
 	 * attribute non-resident if the attribute type supports it. If it is
 	 * smaller we can go ahead and attempt the resize.
 	 */
-	if ((newsize < vol->mft_record_size) && !force_non_resident) {
+	if ((newsize < vol->mft_record_size) && (holes != HOLES_NONRES)) {
 		/* Perform the resize of the attribute record. */
 		if (!(ret = ntfs_resident_attr_value_resize(ctx->mrec, ctx->attr,
 				newsize))) {
@@ -5011,7 +5011,7 @@
 		 * could cause the attribute to be made resident again,
 		 * so size changes are not allowed.
 		 */
-		if (force_non_resident) {
+		if (holes == HOLES_NONRES) {
 			ret = 0;
 			if (newsize != na->data_size) {
 				ntfs_log_error("Cannot change size when"
@@ -5022,7 +5022,7 @@
 			return (ret);
 		}
 		/* Resize non-resident attribute */
-		return ntfs_attr_truncate_i(na, newsize, HOLES_OK);
+		return ntfs_attr_truncate_i(na, newsize, holes);
 	} else if (errno != ENOSPC && errno != EPERM) {
 		err = errno;
 		ntfs_log_perror("Failed to make attribute non-resident");
@@ -5078,7 +5078,7 @@
 		ntfs_inode_mark_dirty(tna->ni);
 		ntfs_attr_close(tna);
 		ntfs_attr_put_search_ctx(ctx);
-		return ntfs_resident_attr_resize_i(na, newsize, force_non_resident);
+		return ntfs_resident_attr_resize_i(na, newsize, holes);
 	}
 	/* Check whether error occurred. */
 	if (errno != ENOENT) {
@@ -5098,7 +5098,7 @@
 			ntfs_log_perror("Could not free space in MFT record");
 			return -1;
 		}
-		return ntfs_resident_attr_resize_i(na, newsize, force_non_resident);
+		return ntfs_resident_attr_resize_i(na, newsize, holes);
 	}
 
 	/*
@@ -5137,7 +5137,7 @@
 		ntfs_attr_put_search_ctx(ctx);
 		if (ntfs_inode_add_attrlist(ni))
 			return -1;
-		return ntfs_resident_attr_resize_i(na, newsize, force_non_resident);
+		return ntfs_resident_attr_resize_i(na, newsize, holes);
 	}
 	/* Allocate new mft record. */
 	ni = ntfs_mft_record_alloc(vol, ni);
@@ -5158,7 +5158,7 @@
 
 	ntfs_attr_put_search_ctx(ctx);
 	/* Try to perform resize once again. */
-	return ntfs_resident_attr_resize_i(na, newsize, force_non_resident);
+	return ntfs_resident_attr_resize_i(na, newsize, holes);
 
 resize_done:
 	/*
@@ -5179,7 +5179,7 @@
 	int ret; 
 	
 	ntfs_log_enter("Entering\n");
-	ret = ntfs_resident_attr_resize_i(na, newsize, FALSE);
+	ret = ntfs_resident_attr_resize_i(na, newsize, HOLES_OK);
 	ntfs_log_leave("\n");
 	return ret;
 }
@@ -5203,7 +5203,7 @@
 {
 	int res;
 
-	res = ntfs_resident_attr_resize_i(na, na->data_size, TRUE);
+	res = ntfs_resident_attr_resize_i(na, na->data_size, HOLES_NONRES);
 	if (!res && !NAttrNonResident(na)) {
 		res = -1;
 		errno = EIO;
@@ -6441,7 +6441,7 @@
 		else
 			ret = ntfs_non_resident_attr_shrink(na, fullsize);
 	} else
-		ret = ntfs_resident_attr_resize(na, newsize);
+		ret = ret = ntfs_resident_attr_resize_i(na, newsize, holes);
 out:	
 	ntfs_log_leave("Return status %d\n", ret);
 	return ret;
------------------------------------------------------------------------------
October Webinars: Code for Performance
Free Intel webinars can help you accelerate application performance.
Explore tips for MPI, OpenMP, advanced profiling, and more. Get the most from 
the latest Intel processors and coprocessors. See abstracts and register >
http://pubads.g.doubleclick.net/gampad/clk?id=60133471&iu=/4140/ostg.clktrk
_______________________________________________
ntfs-3g-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/ntfs-3g-devel

Reply via email to