aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs/inode.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/cifs/inode.c')
-rw-r--r--fs/cifs/inode.c148
1 files changed, 87 insertions, 61 deletions
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index 129dbfe4dca7..722be543ceec 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -418,6 +418,7 @@ int cifs_get_inode_info(struct inode **pinode,
418 char *buf = NULL; 418 char *buf = NULL;
419 bool adjustTZ = false; 419 bool adjustTZ = false;
420 bool is_dfs_referral = false; 420 bool is_dfs_referral = false;
421 umode_t default_mode;
421 422
422 pTcon = cifs_sb->tcon; 423 pTcon = cifs_sb->tcon;
423 cFYI(1, ("Getting info on %s", full_path)); 424 cFYI(1, ("Getting info on %s", full_path));
@@ -530,47 +531,42 @@ int cifs_get_inode_info(struct inode **pinode,
530 inode->i_mtime.tv_sec += pTcon->ses->server->timeAdj; 531 inode->i_mtime.tv_sec += pTcon->ses->server->timeAdj;
531 } 532 }
532 533
533 /* set default mode. will override for dirs below */ 534 /* get default inode mode */
534 if (atomic_read(&cifsInfo->inUse) == 0) 535 if (attr & ATTR_DIRECTORY)
535 /* new inode, can safely set these fields */ 536 default_mode = cifs_sb->mnt_dir_mode;
536 inode->i_mode = cifs_sb->mnt_file_mode; 537 else
537 else /* since we set the inode type below we need to mask off 538 default_mode = cifs_sb->mnt_file_mode;
538 to avoid strange results if type changes and both 539
539 get orred in */ 540 /* set permission bits */
540 inode->i_mode &= ~S_IFMT; 541 if (atomic_read(&cifsInfo->inUse) == 0 ||
541/* if (attr & ATTR_REPARSE) */ 542 (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) == 0)
542 /* We no longer handle these as symlinks because we could not 543 inode->i_mode = default_mode;
543 follow them due to the absolute path with drive letter */ 544 else {
544 if (attr & ATTR_DIRECTORY) { 545 /* just reenable write bits if !ATTR_READONLY */
545 /* override default perms since we do not do byte range locking 546 if ((inode->i_mode & S_IWUGO) == 0 &&
546 on dirs */ 547 (attr & ATTR_READONLY) == 0)
547 inode->i_mode = cifs_sb->mnt_dir_mode; 548 inode->i_mode |= (S_IWUGO & default_mode);
548 inode->i_mode |= S_IFDIR; 549 inode->i_mode &= ~S_IFMT;
549 } else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) && 550 }
550 (cifsInfo->cifsAttrs & ATTR_SYSTEM) && 551 /* clear write bits if ATTR_READONLY is set */
551 /* No need to le64 convert size of zero */ 552 if (attr & ATTR_READONLY)
552 (pfindData->EndOfFile == 0)) { 553 inode->i_mode &= ~S_IWUGO;
553 inode->i_mode = cifs_sb->mnt_file_mode; 554
554 inode->i_mode |= S_IFIFO; 555 /* set inode type */
555/* BB Finish for SFU style symlinks and devices */ 556 if ((attr & ATTR_SYSTEM) &&
556 } else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) && 557 (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)) {
557 (cifsInfo->cifsAttrs & ATTR_SYSTEM)) { 558 /* no need to fix endianness on 0 */
558 if (decode_sfu_inode(inode, le64_to_cpu(pfindData->EndOfFile), 559 if (pfindData->EndOfFile == 0)
559 full_path, cifs_sb, xid)) 560 inode->i_mode |= S_IFIFO;
560 cFYI(1, ("Unrecognized sfu inode type")); 561 else if (decode_sfu_inode(inode,
561 562 le64_to_cpu(pfindData->EndOfFile),
562 cFYI(1, ("sfu mode 0%o", inode->i_mode)); 563 full_path, cifs_sb, xid))
564 cFYI(1, ("unknown SFU file type\n"));
563 } else { 565 } else {
564 inode->i_mode |= S_IFREG; 566 if (attr & ATTR_DIRECTORY)
565 /* treat dos attribute of read-only as read-only mode eg 555 */ 567 inode->i_mode |= S_IFDIR;
566 if (cifsInfo->cifsAttrs & ATTR_READONLY) 568 else
567 inode->i_mode &= ~(S_IWUGO); 569 inode->i_mode |= S_IFREG;
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? */
574 } 570 }
575 571
576 spin_lock(&inode->i_lock); 572 spin_lock(&inode->i_lock);
@@ -1019,8 +1015,11 @@ mkdir_get_info:
1019 CIFS_MOUNT_MAP_SPECIAL_CHR); 1015 CIFS_MOUNT_MAP_SPECIAL_CHR);
1020 } 1016 }
1021 if (direntry->d_inode) { 1017 if (direntry->d_inode) {
1022 direntry->d_inode->i_mode = mode; 1018 if (cifs_sb->mnt_cifs_flags &
1023 direntry->d_inode->i_mode |= S_IFDIR; 1019 CIFS_MOUNT_DYNPERM)
1020 direntry->d_inode->i_mode =
1021 (mode | S_IFDIR);
1022
1024 if (cifs_sb->mnt_cifs_flags & 1023 if (cifs_sb->mnt_cifs_flags &
1025 CIFS_MOUNT_SET_UID) { 1024 CIFS_MOUNT_SET_UID) {
1026 direntry->d_inode->i_uid = 1025 direntry->d_inode->i_uid =
@@ -1547,13 +1546,26 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
1547 } else 1546 } else
1548 goto cifs_setattr_exit; 1547 goto cifs_setattr_exit;
1549 } 1548 }
1550 if (attrs->ia_valid & ATTR_UID) { 1549
1551 cFYI(1, ("UID changed to %d", attrs->ia_uid)); 1550 /*
1552 uid = attrs->ia_uid; 1551 * Without unix extensions we can't send ownership changes to the
1553 } 1552 * server, so silently ignore them. This is consistent with how
1554 if (attrs->ia_valid & ATTR_GID) { 1553 * local DOS/Windows filesystems behave (VFAT, NTFS, etc). With
1555 cFYI(1, ("GID changed to %d", attrs->ia_gid)); 1554 * CIFSACL support + proper Windows to Unix idmapping, we may be
1556 gid = attrs->ia_gid; 1555 * able to support this in the future.
1556 */
1557 if (!pTcon->unix_ext &&
1558 !(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID)) {
1559 attrs->ia_valid &= ~(ATTR_UID | ATTR_GID);
1560 } else {
1561 if (attrs->ia_valid & ATTR_UID) {
1562 cFYI(1, ("UID changed to %d", attrs->ia_uid));
1563 uid = attrs->ia_uid;
1564 }
1565 if (attrs->ia_valid & ATTR_GID) {
1566 cFYI(1, ("GID changed to %d", attrs->ia_gid));
1567 gid = attrs->ia_gid;
1568 }
1557 } 1569 }
1558 1570
1559 time_buf.Attributes = 0; 1571 time_buf.Attributes = 0;
@@ -1563,7 +1575,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
1563 attrs->ia_valid &= ~ATTR_MODE; 1575 attrs->ia_valid &= ~ATTR_MODE;
1564 1576
1565 if (attrs->ia_valid & ATTR_MODE) { 1577 if (attrs->ia_valid & ATTR_MODE) {
1566 cFYI(1, ("Mode changed to 0x%x", attrs->ia_mode)); 1578 cFYI(1, ("Mode changed to 0%o", attrs->ia_mode));
1567 mode = attrs->ia_mode; 1579 mode = attrs->ia_mode;
1568 } 1580 }
1569 1581
@@ -1578,18 +1590,18 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
1578#ifdef CONFIG_CIFS_EXPERIMENTAL 1590#ifdef CONFIG_CIFS_EXPERIMENTAL
1579 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) 1591 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL)
1580 rc = mode_to_acl(inode, full_path, mode); 1592 rc = mode_to_acl(inode, full_path, mode);
1581 else if ((mode & S_IWUGO) == 0) { 1593 else
1582#else
1583 if ((mode & S_IWUGO) == 0) {
1584#endif 1594#endif
1585 /* not writeable */ 1595 if (((mode & S_IWUGO) == 0) &&
1586 if ((cifsInode->cifsAttrs & ATTR_READONLY) == 0) { 1596 (cifsInode->cifsAttrs & ATTR_READONLY) == 0) {
1587 set_dosattr = true; 1597 set_dosattr = true;
1588 time_buf.Attributes = 1598 time_buf.Attributes = cpu_to_le32(cifsInode->cifsAttrs |
1589 cpu_to_le32(cifsInode->cifsAttrs | 1599 ATTR_READONLY);
1590 ATTR_READONLY); 1600 /* fix up mode if we're not using dynperm */
1591 } 1601 if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) == 0)
1592 } else if (cifsInode->cifsAttrs & ATTR_READONLY) { 1602 attrs->ia_mode = inode->i_mode & ~S_IWUGO;
1603 } else if ((mode & S_IWUGO) &&
1604 (cifsInode->cifsAttrs & ATTR_READONLY)) {
1593 /* If file is readonly on server, we would 1605 /* If file is readonly on server, we would
1594 not be able to write to it - so if any write 1606 not be able to write to it - so if any write
1595 bit is enabled for user or group or other we 1607 bit is enabled for user or group or other we
@@ -1600,6 +1612,20 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
1600 /* Windows ignores set to zero */ 1612 /* Windows ignores set to zero */
1601 if (time_buf.Attributes == 0) 1613 if (time_buf.Attributes == 0)
1602 time_buf.Attributes |= cpu_to_le32(ATTR_NORMAL); 1614 time_buf.Attributes |= cpu_to_le32(ATTR_NORMAL);
1615
1616 /* reset local inode permissions to normal */
1617 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)) {
1618 attrs->ia_mode &= ~(S_IALLUGO);
1619 if (S_ISDIR(inode->i_mode))
1620 attrs->ia_mode |=
1621 cifs_sb->mnt_dir_mode;
1622 else
1623 attrs->ia_mode |=
1624 cifs_sb->mnt_file_mode;
1625 }
1626 } else if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)) {
1627 /* ignore mode change - ATTR_READONLY hasn't changed */
1628 attrs->ia_valid &= ~ATTR_MODE;
1603 } 1629 }
1604 } 1630 }
1605 1631