Module Name:    src
Committed By:   manu
Date:           Thu Jun 14 05:58:22 UTC 2012

Modified Files:
        src/lib/libperfuse: ops.c

Log Message:
Fix memory leak when we discard a voided setattr operation


To generate a diff of this commit:
cvs rdiff -u -r1.56 -r1.57 src/lib/libperfuse/ops.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/lib/libperfuse/ops.c
diff -u src/lib/libperfuse/ops.c:1.56 src/lib/libperfuse/ops.c:1.57
--- src/lib/libperfuse/ops.c:1.56	Wed Jun 13 01:45:56 2012
+++ src/lib/libperfuse/ops.c	Thu Jun 14 05:58:22 2012
@@ -1,4 +1,4 @@
-/*  $NetBSD: ops.c,v 1.56 2012/06/13 01:45:56 manu Exp $ */
+/*  $NetBSD: ops.c,v 1.57 2012/06/14 05:58:22 manu Exp $ */
 
 /*-
  *  Copyright (c) 2010-2011 Emmanuel Dreyfus. All rights reserved.
@@ -1696,6 +1696,7 @@ perfuse_node_setattr_ttl(struct puffs_us
 	struct fuse_attr_out *fao;
 	struct vattr *old_va;
 	int error;
+	int valid;
 #ifdef PERFUSE_DEBUG
 	struct vattr *old_vap;
 	int resize_debug = 0;
@@ -1719,39 +1720,94 @@ perfuse_node_setattr_ttl(struct puffs_us
 	}
 
 	old_va = puffs_pn_getvap((struct puffs_node *)opc);
+	valid = 0;
 
 	/*
 	 * Check for permission to change size
 	 */
-	if ((vap->va_size != (u_quad_t)PUFFS_VNOVAL) &&
-	    (error = mode_access(opc, pcr, PUFFS_VWRITE)) != 0)
-		return error;
+	if ((vap->va_size != (u_quad_t)PUFFS_VNOVAL)) {
+		if ((error = mode_access(opc, pcr, PUFFS_VWRITE)) != 0)
+			return error;
+		valid |= FUSE_FATTR_SIZE;
+	}
 
 	/*
-	 * Check for permission to change dates
+	 * Check for permission to change owner and group
 	 */
-	if (((vap->va_atime.tv_sec != (time_t)PUFFS_VNOVAL) ||
-	     (vap->va_mtime.tv_sec != (time_t)PUFFS_VNOVAL)) &&
-	    (puffs_access_times(old_va->va_uid, old_va->va_gid,
-				old_va->va_mode, 0, pcr) != 0))
-		return EACCES;
+	if ((vap->va_uid != (uid_t)PUFFS_VNOVAL) ||
+	    (vap->va_gid != (gid_t)PUFFS_VNOVAL)) {
+		if (puffs_access_chown(old_va->va_uid, old_va->va_gid,
+				       vap->va_uid, vap->va_gid, pcr) != 0)
+			return EACCES;
+
+		if (vap->va_uid != (uid_t)PUFFS_VNOVAL)
+			valid |= FUSE_FATTR_UID;
+
+		if (vap->va_gid != (uid_t)PUFFS_VNOVAL)
+			valid |= FUSE_FATTR_GID;
+	}
 
 	/*
-	 * Check for permission to change owner and group
+	 * Check for permission to change permissions
 	 */
-	if (((vap->va_uid != (uid_t)PUFFS_VNOVAL) ||
-	     (vap->va_gid != (gid_t)PUFFS_VNOVAL)) &&
-	    (puffs_access_chown(old_va->va_uid, old_va->va_gid,
-				vap->va_uid, vap->va_gid, pcr)) != 0)
-		return EACCES;
+	if (vap->va_mode != (mode_t)PUFFS_VNOVAL) {
+		if (puffs_access_chmod(old_va->va_uid, old_va->va_gid,
+				old_va->va_type, vap->va_mode, pcr) != 0)
+			return EACCES;
+		valid |= FUSE_FATTR_MODE;
+	}
 
 	/*
-	 * Check for permission to change permissions
+	 * Check for permission to change dates
 	 */
-	if ((vap->va_mode != (mode_t)PUFFS_VNOVAL) &&
-	    (puffs_access_chmod(old_va->va_uid, old_va->va_gid,
-				old_va->va_type, vap->va_mode, pcr)) != 0)
-		return EACCES;
+	if ((vap->va_atime.tv_sec != (time_t)PUFFS_VNOVAL) ||
+	    (vap->va_mtime.tv_sec != (time_t)PUFFS_VNOVAL)) {
+		if (vap->va_atime.tv_sec != (time_t)PUFFS_VNOVAL)
+			valid |= FUSE_FATTR_ATIME;
+
+		if (vap->va_mtime.tv_sec != (time_t)PUFFS_VNOVAL)
+			valid |= FUSE_FATTR_MTIME;
+
+		/*
+		 * ftruncate() sends only va_size, and metadata cache
+		 * flush adds va_atime and va_mtime. Some FUSE
+		 * filesystems will attempt to detect ftruncate by 
+		 * checking for FATTR_SIZE being set without
+		 * FATTR_UID|FATTR_GID|FATTR_ATIME|FATTR_MTIME|FATTR_MODE
+		 * 
+		 * Try to adapt and remove FATTR_ATIME|FATTR_MTIME
+		 * if we suspect a ftruncate().
+		 */ 
+		if ((valid & FUSE_FATTR_SIZE) &&
+		    !(valid & (FUSE_FATTR_UID|FUSE_FATTR_GID|FUSE_FATTR_MODE)))
+			valid &= ~(FUSE_FATTR_ATIME|FUSE_FATTR_MTIME);
+
+		/*
+		 * There is the same mess with fchmod()
+		 */
+		if ((valid & FUSE_FATTR_MODE) &&
+		    !(valid & (FUSE_FATTR_UID|FUSE_FATTR_GID)))
+			valid &= ~(FUSE_FATTR_ATIME|FUSE_FATTR_MTIME);
+
+		/*
+		 * And if a change on atime/mtime remains, check permissions.
+		 */
+		if ((valid & (FUSE_FATTR_ATIME|FUSE_FATTR_MTIME)) &&
+		    (puffs_access_times(old_va->va_uid, old_va->va_gid,
+				        old_va->va_mode, 0, pcr) != 0))
+			return EACCES;
+	}
+
+	/*
+	 * If nothing remain, discard the operation. This happend when
+	 * only ctime is changed.
+	 */
+	if (!(valid & (FUSE_FATTR_SIZE|FUSE_FATTR_ATIME|FUSE_FATTR_MTIME|
+		       FUSE_FATTR_MODE|FUSE_FATTR_UID|FUSE_FATTR_GID))) {
+		error = 0;
+		goto out;
+	}
+
 	
 	pm = ps->ps_new_msg(pu, opc, FUSE_SETATTR, sizeof(*fsi), pcr);
 	fsi = GET_INPAYLOAD(ps, pm, fuse_setattr_in);
@@ -1766,7 +1822,7 @@ perfuse_node_setattr_ttl(struct puffs_us
 		fsi->valid |= FUSE_FATTR_FH;
 	}
 
-	if (vap->va_size != (u_quad_t)PUFFS_VNOVAL) {
+	if (valid & FUSE_FATTR_SIZE) {
 		fsi->size = vap->va_size;
 		fsi->valid |= FUSE_FATTR_SIZE;
 
@@ -1787,10 +1843,8 @@ perfuse_node_setattr_ttl(struct puffs_us
 	 * dates being reset to Epoch on glusterfs. If one
 	 * is missing, use the old value.
  	 */
-	if ((vap->va_mtime.tv_sec != (time_t)PUFFS_VNOVAL) || 
-	    (vap->va_atime.tv_sec != (time_t)PUFFS_VNOVAL)) {
-		
-		if (vap->va_atime.tv_sec != (time_t)PUFFS_VNOVAL) {
+	if (valid & (FUSE_FATTR_ATIME|FUSE_FATTR_MTIME)) {
+		if (valid & FUSE_FATTR_ATIME) {
 			fsi->atime = vap->va_atime.tv_sec;
 			fsi->atimensec = (uint32_t)vap->va_atime.tv_nsec;
 		} else {
@@ -1798,7 +1852,7 @@ perfuse_node_setattr_ttl(struct puffs_us
 			fsi->atimensec = (uint32_t)old_va->va_atime.tv_nsec;
 		}
 
-		if (vap->va_mtime.tv_sec != (time_t)PUFFS_VNOVAL) {
+		if (valid & FUSE_FATTR_MTIME) {
 			fsi->mtime = vap->va_mtime.tv_sec;
 			fsi->mtimensec = (uint32_t)vap->va_mtime.tv_nsec;
 		} else {
@@ -1809,17 +1863,17 @@ perfuse_node_setattr_ttl(struct puffs_us
 		fsi->valid |= (FUSE_FATTR_MTIME|FUSE_FATTR_ATIME);
 	}
 
-	if (vap->va_mode != (mode_t)PUFFS_VNOVAL) {
+	if (valid & FUSE_FATTR_MODE) {
 		fsi->mode = vap->va_mode; 
 		fsi->valid |= FUSE_FATTR_MODE;
 	}
 	
-	if (vap->va_uid != (uid_t)PUFFS_VNOVAL) {
+	if (valid & FUSE_FATTR_UID) {
 		fsi->uid = vap->va_uid;
 		fsi->valid |= FUSE_FATTR_UID;
 	}
 
-	if (vap->va_gid != (gid_t)PUFFS_VNOVAL) {
+	if (valid & FUSE_FATTR_GID) {
 		fsi->gid = vap->va_gid;
 		fsi->valid |= FUSE_FATTR_GID;
 	}
@@ -1829,49 +1883,6 @@ perfuse_node_setattr_ttl(struct puffs_us
 		fsi->valid |= FUSE_FATTR_LOCKOWNER;
 	}
 
-	/*
-	 * ftruncate() sends only va_size, and metadata cache
-	 * flush adds va_atime and va_mtime. Some FUSE
-	 * filesystems will attempt to detect ftruncate by 
-	 * checking for FATTR_SIZE being set without
-	 * FATTR_UID|FATTR_GID|FATTR_ATIME|FATTR_MTIME|FATTR_MODE
-	 * 
-	 * Try to adapt and remove FATTR_ATIME|FATTR_MTIME
-	 * if we suspect a ftruncate().
-	 */ 
-	if ((vap->va_size != (u_quad_t)PUFFS_VNOVAL) &&
-	    ((vap->va_mode == (mode_t)PUFFS_VNOVAL) &&
-	     (vap->va_uid == (uid_t)PUFFS_VNOVAL) &&
-	     (vap->va_gid == (gid_t)PUFFS_VNOVAL))) {
-		fsi->atime = 0;
-		fsi->atimensec = 0;
-		fsi->mtime = 0;
-		fsi->mtimensec = 0;
-		fsi->valid &= ~(FUSE_FATTR_ATIME|FUSE_FATTR_MTIME);
-	}
-
-	/*
-	 * There is the same mess with fchmod()
-	 */
-	if ((vap->va_mode != (mode_t)PUFFS_VNOVAL) &&
-	    (vap->va_uid == (uid_t)PUFFS_VNOVAL) &&
-	    (vap->va_gid == (gid_t)PUFFS_VNOVAL)) {
-		fsi->atime = 0;
-		fsi->atimensec = 0;
-		fsi->mtime = 0;
-		fsi->mtimensec = 0;
-		fsi->valid &= ~(FUSE_FATTR_ATIME|FUSE_FATTR_MTIME);
-	}
-		    
-	/*
-	 * If nothing remain, discard the operation.
-	 */
-	if (!(fsi->valid & (FUSE_FATTR_SIZE|FUSE_FATTR_ATIME|FUSE_FATTR_MTIME|
-			    FUSE_FATTR_MODE|FUSE_FATTR_UID|FUSE_FATTR_GID))) {
-		ps->ps_destroy_msg(pm);
-		error = 0;
-		goto out;
-	}
 
 #ifdef PERFUSE_DEBUG
 	old_vap = puffs_pn_getvap((struct puffs_node *)opc);

Reply via email to