[CIFS] when not using unix extensions, check for and set ATTR_READONLY on create and mkdir

When creating a directory on a CIFS share without POSIX extensions,
and the given mode has no write bits set, set the ATTR_READONLY bit.

When creating a file, set ATTR_READONLY if the create mode has no write
bits set and we're not using unix extensions.

There are some comments about this being problematic due to the VFS
splitting creates into 2 parts. I'm not sure what that's actually
talking about, but I'm assuming that it has something to do with how
mknod is implemented. In the simple case where we have no unix
extensions and we're just creating a regular file, there's no reason
we can't set ATTR_READONLY.

Signed-off-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Steve French <sfrench@us.ibm.com>

authored by Jeff Layton and committed by Steve French 67750fb9 02eadeff

+31 -17
+1
fs/cifs/cifspdu.h
··· 340 #define OPEN_NO_RECALL 0x00400000 341 #define OPEN_FREE_SPACE_QUERY 0x00800000 /* should be zero */ 342 #define CREATE_OPTIONS_MASK 0x007FFFFF 343 #define CREATE_OPTION_SPECIAL 0x20000000 /* system. NB not sent over wire */ 344 345 /* ImpersonationLevel flags */
··· 340 #define OPEN_NO_RECALL 0x00400000 341 #define OPEN_FREE_SPACE_QUERY 0x00800000 /* should be zero */ 342 #define CREATE_OPTIONS_MASK 0x007FFFFF 343 + #define CREATE_OPTION_READONLY 0x10000000 344 #define CREATE_OPTION_SPECIAL 0x20000000 /* system. NB not sent over wire */ 345 346 /* ImpersonationLevel flags */
+6 -10
fs/cifs/cifssmb.c
··· 1224 else /* BB FIXME BB */ 1225 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/); 1226 1227 - /* if ((omode & S_IWUGO) == 0) 1228 - pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/ 1229 - /* Above line causes problems due to vfs splitting create into two 1230 - pieces - need to set mode after file created not while it is 1231 - being created */ 1232 1233 /* BB FIXME BB */ 1234 /* pSMB->CreateOptions = cpu_to_le32(create_options & ··· 1328 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM); 1329 else 1330 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL); 1331 /* XP does not handle ATTR_POSIX_SEMANTICS */ 1332 /* but it helps speed up case sensitive checks for other 1333 servers such as Samba */ 1334 if (tcon->ses->capabilities & CAP_UNIX) 1335 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS); 1336 1337 - /* if ((omode & S_IWUGO) == 0) 1338 - pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/ 1339 - /* Above line causes problems due to vfs splitting create into two 1340 - pieces - need to set mode after file created not while it is 1341 - being created */ 1342 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL); 1343 pSMB->CreateDisposition = cpu_to_le32(openDisposition); 1344 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
··· 1224 else /* BB FIXME BB */ 1225 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/); 1226 1227 + if (create_options & CREATE_OPTION_READONLY) 1228 + pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY); 1229 1230 /* BB FIXME BB */ 1231 /* pSMB->CreateOptions = cpu_to_le32(create_options & ··· 1331 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM); 1332 else 1333 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL); 1334 + 1335 /* XP does not handle ATTR_POSIX_SEMANTICS */ 1336 /* but it helps speed up case sensitive checks for other 1337 servers such as Samba */ 1338 if (tcon->ses->capabilities & CAP_UNIX) 1339 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS); 1340 1341 + if (create_options & CREATE_OPTION_READONLY) 1342 + pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY); 1343 + 1344 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL); 1345 pSMB->CreateDisposition = cpu_to_le32(openDisposition); 1346 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
+13 -3
fs/cifs/dir.c
··· 119 { 120 int rc = -ENOENT; 121 int xid; 122 int oplock = 0; 123 int desiredAccess = GENERIC_READ | GENERIC_WRITE; 124 __u16 fileHandle; ··· 177 FreeXid(xid); 178 return -ENOMEM; 179 } 180 if (cifs_sb->tcon->ses->capabilities & CAP_NT_SMBS) 181 rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, 182 - desiredAccess, CREATE_NOT_DIR, 183 &fileHandle, &oplock, buf, cifs_sb->local_nls, 184 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); 185 else ··· 198 if (rc == -EIO) { 199 /* old server, retry the open legacy style */ 200 rc = SMBLegacyOpen(xid, pTcon, full_path, disposition, 201 - desiredAccess, CREATE_NOT_DIR, 202 &fileHandle, &oplock, buf, cifs_sb->local_nls, 203 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); 204 } ··· 208 /* If Open reported that we actually created a file 209 then we now have to set the mode if possible */ 210 if ((pTcon->unix_ext) && (oplock & CIFS_CREATE_ACTION)) { 211 - mode &= ~current->fs->umask; 212 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { 213 CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, 214 (__u64)current->fsuid,
··· 119 { 120 int rc = -ENOENT; 121 int xid; 122 + int create_options = CREATE_NOT_DIR; 123 int oplock = 0; 124 int desiredAccess = GENERIC_READ | GENERIC_WRITE; 125 __u16 fileHandle; ··· 176 FreeXid(xid); 177 return -ENOMEM; 178 } 179 + 180 + mode &= ~current->fs->umask; 181 + 182 + /* 183 + * if we're not using unix extensions, see if we need to set 184 + * ATTR_READONLY on the create call 185 + */ 186 + if (!pTcon->unix_ext && (mode & S_IWUGO) == 0) 187 + create_options |= CREATE_OPTION_READONLY; 188 + 189 if (cifs_sb->tcon->ses->capabilities & CAP_NT_SMBS) 190 rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, 191 + desiredAccess, create_options, 192 &fileHandle, &oplock, buf, cifs_sb->local_nls, 193 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); 194 else ··· 187 if (rc == -EIO) { 188 /* old server, retry the open legacy style */ 189 rc = SMBLegacyOpen(xid, pTcon, full_path, disposition, 190 + desiredAccess, create_options, 191 &fileHandle, &oplock, buf, cifs_sb->local_nls, 192 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); 193 } ··· 197 /* If Open reported that we actually created a file 198 then we now have to set the mode if possible */ 199 if ((pTcon->unix_ext) && (oplock & CIFS_CREATE_ACTION)) { 200 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { 201 CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, 202 (__u64)current->fsuid,
+11 -4
fs/cifs/inode.c
··· 974 * failed to get it from the server or was set bogus */ 975 if ((direntry->d_inode) && (direntry->d_inode->i_nlink < 2)) 976 direntry->d_inode->i_nlink = 2; 977 if (pTcon->unix_ext) { 978 - mode &= ~current->fs->umask; 979 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { 980 CIFSSMBUnixSetPerms(xid, pTcon, full_path, 981 mode, ··· 994 CIFS_MOUNT_MAP_SPECIAL_CHR); 995 } 996 } else { 997 - /* BB to be implemented via Windows secrty descriptors 998 - eg CIFSSMBWinSetPerms(xid, pTcon, full_path, mode, 999 - -1, -1, local_nls); */ 1000 if (direntry->d_inode) { 1001 direntry->d_inode->i_mode = mode; 1002 direntry->d_inode->i_mode |= S_IFDIR;
··· 974 * failed to get it from the server or was set bogus */ 975 if ((direntry->d_inode) && (direntry->d_inode->i_nlink < 2)) 976 direntry->d_inode->i_nlink = 2; 977 + mode &= ~current->fs->umask; 978 if (pTcon->unix_ext) { 979 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { 980 CIFSSMBUnixSetPerms(xid, pTcon, full_path, 981 mode, ··· 994 CIFS_MOUNT_MAP_SPECIAL_CHR); 995 } 996 } else { 997 + if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) && 998 + (mode & S_IWUGO) == 0) { 999 + FILE_BASIC_INFO pInfo; 1000 + memset(&pInfo, 0, sizeof(pInfo)); 1001 + pInfo.Attributes = cpu_to_le32(ATTR_READONLY); 1002 + CIFSSMBSetTimes(xid, pTcon, full_path, 1003 + &pInfo, cifs_sb->local_nls, 1004 + cifs_sb->mnt_cifs_flags & 1005 + CIFS_MOUNT_MAP_SPECIAL_CHR); 1006 + } 1007 if (direntry->d_inode) { 1008 direntry->d_inode->i_mode = mode; 1009 direntry->d_inode->i_mode |= S_IFDIR;