Commit 4468eb3fd102cad559e51594a01cbc65b994d264

Authored by Jeff Layton
Committed by Steve French
1 parent aaa9bbe039

on non-posix shares, clear write bits in mode when ATTR_READONLY is set

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.
It also cleans up how modes are set in cifs_get_inode_info for both the
"normal" and "dynperm" cases.

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

Showing 2 changed files with 75 additions and 72 deletions Side-by-side Diff

... ... @@ -418,6 +418,7 @@
418 418 char *buf = NULL;
419 419 bool adjustTZ = false;
420 420 bool is_dfs_referral = false;
  421 + umode_t default_mode;
421 422  
422 423 pTcon = cifs_sb->tcon;
423 424 cFYI(1, ("Getting info on %s", full_path));
424 425  
425 426  
... ... @@ -530,47 +531,42 @@
530 531 inode->i_mtime.tv_sec += pTcon->ses->server->timeAdj;
531 532 }
532 533  
533   - /* set default mode. will override for dirs below */
534   - if (atomic_read(&cifsInfo->inUse) == 0)
535   - /* new inode, can safely set these fields */
536   - inode->i_mode = cifs_sb->mnt_file_mode;
537   - else /* since we set the inode type below we need to mask off
538   - to avoid strange results if type changes and both
539   - get orred in */
540   - inode->i_mode &= ~S_IFMT;
541   -/* if (attr & ATTR_REPARSE) */
542   - /* We no longer handle these as symlinks because we could not
543   - follow them due to the absolute path with drive letter */
544   - if (attr & ATTR_DIRECTORY) {
545   - /* override default perms since we do not do byte range locking
546   - on dirs */
547   - inode->i_mode = cifs_sb->mnt_dir_mode;
548   - inode->i_mode |= S_IFDIR;
549   - } else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) &&
550   - (cifsInfo->cifsAttrs & ATTR_SYSTEM) &&
551   - /* No need to le64 convert size of zero */
552   - (pfindData->EndOfFile == 0)) {
553   - inode->i_mode = cifs_sb->mnt_file_mode;
554   - inode->i_mode |= S_IFIFO;
555   -/* BB Finish for SFU style symlinks and devices */
556   - } else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) &&
557   - (cifsInfo->cifsAttrs & ATTR_SYSTEM)) {
558   - if (decode_sfu_inode(inode, le64_to_cpu(pfindData->EndOfFile),
559   - full_path, cifs_sb, xid))
560   - cFYI(1, ("Unrecognized sfu inode type"));
  534 + /* get default inode mode */
  535 + if (attr & ATTR_DIRECTORY)
  536 + default_mode = cifs_sb->mnt_dir_mode;
  537 + else
  538 + default_mode = cifs_sb->mnt_file_mode;
561 539  
562   - cFYI(1, ("sfu mode 0%o", inode->i_mode));
  540 + /* set permission bits */
  541 + if (atomic_read(&cifsInfo->inUse) == 0 ||
  542 + (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) == 0)
  543 + inode->i_mode = default_mode;
  544 + else {
  545 + /* just reenable write bits if !ATTR_READONLY */
  546 + if ((inode->i_mode & S_IWUGO) == 0 &&
  547 + (attr & ATTR_READONLY) == 0)
  548 + inode->i_mode |= (S_IWUGO & default_mode);
  549 + inode->i_mode &= ~S_IFMT;
  550 + }
  551 + /* clear write bits if ATTR_READONLY is set */
  552 + if (attr & ATTR_READONLY)
  553 + inode->i_mode &= ~S_IWUGO;
  554 +
  555 + /* set inode type */
  556 + if ((attr & ATTR_SYSTEM) &&
  557 + (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)) {
  558 + /* no need to fix endianness on 0 */
  559 + if (pfindData->EndOfFile == 0)
  560 + inode->i_mode |= S_IFIFO;
  561 + else if (decode_sfu_inode(inode,
  562 + le64_to_cpu(pfindData->EndOfFile),
  563 + full_path, cifs_sb, xid))
  564 + cFYI(1, ("unknown SFU file type\n"));
563 565 } else {
564   - inode->i_mode |= S_IFREG;
565   - /* treat dos attribute of read-only as read-only mode eg 555 */
566   - if (cifsInfo->cifsAttrs & ATTR_READONLY)
567   - inode->i_mode &= ~(S_IWUGO);
568   - else if ((inode->i_mode & S_IWUGO) == 0)
569   - /* the ATTR_READONLY flag may have been */
570   - /* changed on server -- set any w bits */
571   - /* allowed by mnt_file_mode */
572   - inode->i_mode |= (S_IWUGO & cifs_sb->mnt_file_mode);
573   - /* BB add code to validate if device or weird share or device type? */
  566 + if (attr & ATTR_DIRECTORY)
  567 + inode->i_mode |= S_IFDIR;
  568 + else
  569 + inode->i_mode |= S_IFREG;
574 570 }
575 571  
576 572 spin_lock(&inode->i_lock);
... ... @@ -132,6 +132,7 @@
132 132 __u32 attr;
133 133 __u64 allocation_size;
134 134 __u64 end_of_file;
  135 + umode_t default_mode;
135 136  
136 137 /* save mtime and size */
137 138 local_mtime = tmp_inode->i_mtime;
138 139  
139 140  
140 141  
141 142  
142 143  
143 144  
144 145  
... ... @@ -187,48 +188,54 @@
187 188 if (atomic_read(&cifsInfo->inUse) == 0) {
188 189 tmp_inode->i_uid = cifs_sb->mnt_uid;
189 190 tmp_inode->i_gid = cifs_sb->mnt_gid;
190   - /* set default mode. will override for dirs below */
191   - tmp_inode->i_mode = cifs_sb->mnt_file_mode;
192   - } else {
193   - /* mask off the type bits since it gets set
194   - below and we do not want to get two type
195   - bits set */
  191 + }
  192 +
  193 + if (attr & ATTR_DIRECTORY)
  194 + default_mode = cifs_sb->mnt_dir_mode;
  195 + else
  196 + default_mode = cifs_sb->mnt_file_mode;
  197 +
  198 + /* set initial permissions */
  199 + if ((atomic_read(&cifsInfo->inUse) == 0) ||
  200 + (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) == 0)
  201 + tmp_inode->i_mode = default_mode;
  202 + else {
  203 + /* just reenable write bits if !ATTR_READONLY */
  204 + if ((tmp_inode->i_mode & S_IWUGO) == 0 &&
  205 + (attr & ATTR_READONLY) == 0)
  206 + tmp_inode->i_mode |= (S_IWUGO & default_mode);
  207 +
196 208 tmp_inode->i_mode &= ~S_IFMT;
197 209 }
198 210  
199   - if (attr & ATTR_DIRECTORY) {
200   - *pobject_type = DT_DIR;
201   - /* override default perms since we do not lock dirs */
202   - if (atomic_read(&cifsInfo->inUse) == 0)
203   - tmp_inode->i_mode = cifs_sb->mnt_dir_mode;
204   - tmp_inode->i_mode |= S_IFDIR;
205   - } else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) &&
206   - (attr & ATTR_SYSTEM)) {
  211 + /* clear write bits if ATTR_READONLY is set */
  212 + if (attr & ATTR_READONLY)
  213 + tmp_inode->i_mode &= ~S_IWUGO;
  214 +
  215 + /* set inode type */
  216 + if ((attr & ATTR_SYSTEM) &&
  217 + (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)) {
207 218 if (end_of_file == 0) {
208   - *pobject_type = DT_FIFO;
209 219 tmp_inode->i_mode |= S_IFIFO;
  220 + *pobject_type = DT_FIFO;
210 221 } else {
211   - /* rather than get the type here, we mark the
212   - inode as needing revalidate and get the real type
213   - (blk vs chr vs. symlink) later ie in lookup */
214   - *pobject_type = DT_REG;
  222 + /*
  223 + * trying to get the type can be slow, so just call
  224 + * this a regular file for now, and mark for reval
  225 + */
215 226 tmp_inode->i_mode |= S_IFREG;
  227 + *pobject_type = DT_REG;
216 228 cifsInfo->time = 0;
217 229 }
218   -/* we no longer mark these because we could not follow them */
219   -/* } else if (attr & ATTR_REPARSE) {
220   - *pobject_type = DT_LNK;
221   - tmp_inode->i_mode |= S_IFLNK; */
222 230 } else {
223   - *pobject_type = DT_REG;
224   - tmp_inode->i_mode |= S_IFREG;
225   - if (attr & ATTR_READONLY)
226   - tmp_inode->i_mode &= ~(S_IWUGO);
227   - else if ((tmp_inode->i_mode & S_IWUGO) == 0)
228   - /* the ATTR_READONLY flag may have been changed on */
229   - /* server -- set any w bits allowed by mnt_file_mode */
230   - tmp_inode->i_mode |= (S_IWUGO & cifs_sb->mnt_file_mode);
231   - } /* could add code here - to validate if device or weird share type? */
  231 + if (attr & ATTR_DIRECTORY) {
  232 + tmp_inode->i_mode |= S_IFDIR;
  233 + *pobject_type = DT_DIR;
  234 + } else {
  235 + tmp_inode->i_mode |= S_IFREG;
  236 + *pobject_type = DT_REG;
  237 + }
  238 + }
232 239  
233 240 /* can not fill in nlink here as in qpathinfo version and Unx search */
234 241 if (atomic_read(&cifsInfo->inUse) == 0)