[linux-cifs-client] [PATCH 2/5] [CIFS] on non-posix shares, clear write bits in mode when ATTR_READONLY is set

Jeff Layton jlayton at redhat.com
Mon May 12 14:49:42 GMT 2008


When mounting a share with posix extensions disabled, cifs_get_inode_info
turns off all the write bits in the mode for regular files if ATTR_READONLY
is set. Directories and other inode types, however, can also have
ATTR_READONLY set, but the mode gives no indication of this.

This patch makes this apply to other inode types besides regular files.
If "dynperm" is enabled then ATTR_READONLY will have no effect on the
mode. In that case, we have no way to know whether this mode was
explicitly set by the user, so it's safest not to touch it.

Signed-off-by: Jeff Layton <jlayton at redhat.com>
---

 fs/cifs/inode.c   |   75 ++++++++++++++++++++++-------------------------------
 fs/cifs/readdir.c |   62 ++++++++++++++++++++++----------------------
 2 files changed, 62 insertions(+), 75 deletions(-)
-------------- next part --------------
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index fcbdbb6..f160128 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -512,52 +512,39 @@ try_again_CIFSSMBQPathInfo:
 			inode->i_mtime.tv_sec += pTcon->ses->server->timeAdj;
 		}
 
-		/* set default mode. will override for dirs below */
-		if (atomic_read(&cifsInfo->inUse) == 0)
-			/* new inode, can safely set these fields */
-			inode->i_mode = cifs_sb->mnt_file_mode;
-		else /* since we set the inode type below we need to mask off
-		     to avoid strange results if type changes and both
-		     get orred in */
+		/* set permission bits */
+		if (atomic_read(&cifsInfo->inUse) == 0 ||
+		    (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) == 0) {
+			/* set default permissions (sans inode type) */
+			if (attr & ATTR_DIRECTORY)
+				inode->i_mode = cifs_sb->mnt_dir_mode;
+			else
+				inode->i_mode = cifs_sb->mnt_file_mode;
+
+			/* clear write bits if ATTR_READONLY is set */
+			if (attr & ATTR_READONLY)
+				inode->i_mode &= ~S_IWUGO;
+		} else {
+			/* existing inode and we're faking modes, we can't
+			   reliably change the mode to match ATTR_READONLY */
 			inode->i_mode &= ~S_IFMT;
-/*		if (attr & ATTR_REPARSE)  */
-		/* We no longer handle these as symlinks because we could not
-		   follow them due to the absolute path with drive letter */
-		if (attr & ATTR_DIRECTORY) {
-		/* override default perms since we do not do byte range locking
-		   on dirs */
-			inode->i_mode = cifs_sb->mnt_dir_mode;
-			inode->i_mode |= S_IFDIR;
-		} else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) &&
-			   (cifsInfo->cifsAttrs & ATTR_SYSTEM) &&
-			   /* No need to le64 convert size of zero */
-			   (pfindData->EndOfFile == 0)) {
-			inode->i_mode = cifs_sb->mnt_file_mode;
-			inode->i_mode |= S_IFIFO;
-/* BB Finish for SFU style symlinks and devices */
-		} else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) &&
-			   (cifsInfo->cifsAttrs & ATTR_SYSTEM)) {
-			if (decode_sfu_inode(inode,
-					 le64_to_cpu(pfindData->EndOfFile),
-					 search_path,
-					 cifs_sb, xid))
-				cFYI(1, ("Unrecognized sfu inode type"));
-
-			cFYI(1, ("sfu mode 0%o", inode->i_mode));
+		}
+
+		/* set inode type */
+		if ((attr & ATTR_SYSTEM) &&
+		    (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)) {
+			/* no need to fix endianness on 0 */
+			if (pfindData->EndOfFile == 0)
+				inode->i_mode |= S_IFIFO;
+			else if (decode_sfu_inode(inode,
+					le64_to_cpu(pfindData->EndOfFile),
+					search_path, cifs_sb, xid))
+				cFYI(1, ("unknown SFU file type\n"));
 		} else {
-			inode->i_mode |= S_IFREG;
-			/* treat the dos attribute of read-only as read-only
-			   mode e.g. 555 */
-			if (cifsInfo->cifsAttrs & ATTR_READONLY)
-				inode->i_mode &= ~(S_IWUGO);
-			else if ((inode->i_mode & S_IWUGO) == 0)
-				/* the ATTR_READONLY flag may have been	*/
-				/* changed on server -- set any w bits	*/
-				/* allowed by mnt_file_mode		*/
-				inode->i_mode |= (S_IWUGO &
-						  cifs_sb->mnt_file_mode);
-		/* BB add code here -
-		   validate if device or weird share or device type? */
+			if (attr & ATTR_DIRECTORY)
+				inode->i_mode |= S_IFDIR;
+			else
+				inode->i_mode |= S_IFREG;
 		}
 
 		spin_lock(&inode->i_lock);
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c
index 34ec321..e52ba62 100644
--- a/fs/cifs/readdir.c
+++ b/fs/cifs/readdir.c
@@ -187,48 +187,48 @@ static void fill_in_inode(struct inode *tmp_inode, int new_buf_type,
 	if (atomic_read(&cifsInfo->inUse) == 0) {
 		tmp_inode->i_uid = cifs_sb->mnt_uid;
 		tmp_inode->i_gid = cifs_sb->mnt_gid;
-		/* set default mode. will override for dirs below */
-		tmp_inode->i_mode = cifs_sb->mnt_file_mode;
+	}
+
+	/* set initial permissions */
+	if ((atomic_read(&cifsInfo->inUse) == 0) ||
+	    (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) == 0) {
+		if (attr & ATTR_DIRECTORY)
+			tmp_inode->i_mode = cifs_sb->mnt_dir_mode;
+		else
+			tmp_inode->i_mode = cifs_sb->mnt_file_mode;
+
+		/* clear write bits if ATTR_READONLY is set */
+		if (attr & ATTR_READONLY)
+			tmp_inode->i_mode &= ~S_IWUGO;
 	} else {
-		/* mask off the type bits since it gets set
-		below and we do not want to get two type
-		bits set */
+		/* existing inode and we're faking permissions */
 		tmp_inode->i_mode &= ~S_IFMT;
 	}
 
-	if (attr & ATTR_DIRECTORY) {
-		*pobject_type = DT_DIR;
-		/* override default perms since we do not lock dirs */
-		if (atomic_read(&cifsInfo->inUse) == 0)
-			tmp_inode->i_mode = cifs_sb->mnt_dir_mode;
-		tmp_inode->i_mode |= S_IFDIR;
-	} else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) &&
-		   (attr & ATTR_SYSTEM)) {
+	/* set inode type */
+	if ((attr & ATTR_SYSTEM) &&
+	    (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)) {
 		if (end_of_file == 0)  {
-			*pobject_type = DT_FIFO;
 			tmp_inode->i_mode |= S_IFIFO;
+			*pobject_type = DT_FIFO;
 		} else {
-			/* rather than get the type here, we mark the
-			inode as needing revalidate and get the real type
-			(blk vs chr vs. symlink) later ie in lookup */
-			*pobject_type = DT_REG;
+			/*
+			 * trying to get the type can be slow, so just call
+			 * this a regular file for now, and mark for reval
+			 */
 			tmp_inode->i_mode |= S_IFREG;
+			*pobject_type = DT_REG;
 			cifsInfo->time = 0;
 		}
-/* we no longer mark these because we could not follow them */
-/*        } else if (attr & ATTR_REPARSE) {
-		*pobject_type = DT_LNK;
-		tmp_inode->i_mode |= S_IFLNK; */
 	} else {
-		*pobject_type = DT_REG;
-		tmp_inode->i_mode |= S_IFREG;
-		if (attr & ATTR_READONLY)
-			tmp_inode->i_mode &= ~(S_IWUGO);
-		else if ((tmp_inode->i_mode & S_IWUGO) == 0)
-			/* the ATTR_READONLY flag may have been changed on   */
-			/* server -- set any w bits allowed by mnt_file_mode */
-			tmp_inode->i_mode |= (S_IWUGO & cifs_sb->mnt_file_mode);
-	} /* could add code here - to validate if device or weird share type? */
+		if (attr & ATTR_DIRECTORY) {
+			tmp_inode->i_mode |= S_IFDIR;
+			*pobject_type = DT_DIR;
+		} else {
+			tmp_inode->i_mode |= S_IFREG;
+			*pobject_type = DT_REG;
+		}
+	}
 
 	/* can not fill in nlink here as in qpathinfo version and Unx search */
 	if (atomic_read(&cifsInfo->inUse) == 0)


More information about the linux-cifs-client mailing list