diff options
Diffstat (limited to 'fs/cifs/inode.c')
-rw-r--r-- | fs/cifs/inode.c | 419 |
1 files changed, 279 insertions, 140 deletions
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 46e54d39461d..28a22092d450 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c | |||
@@ -737,7 +737,7 @@ psx_del_no_retry: | |||
737 | /* ATTRS set to normal clears r/o bit */ | 737 | /* ATTRS set to normal clears r/o bit */ |
738 | pinfo_buf->Attributes = cpu_to_le32(ATTR_NORMAL); | 738 | pinfo_buf->Attributes = cpu_to_le32(ATTR_NORMAL); |
739 | if (!(pTcon->ses->flags & CIFS_SES_NT4)) | 739 | if (!(pTcon->ses->flags & CIFS_SES_NT4)) |
740 | rc = CIFSSMBSetTimes(xid, pTcon, full_path, | 740 | rc = CIFSSMBSetPathInfo(xid, pTcon, full_path, |
741 | pinfo_buf, | 741 | pinfo_buf, |
742 | cifs_sb->local_nls, | 742 | cifs_sb->local_nls, |
743 | cifs_sb->mnt_cifs_flags & | 743 | cifs_sb->mnt_cifs_flags & |
@@ -767,9 +767,10 @@ psx_del_no_retry: | |||
767 | cifs_sb->mnt_cifs_flags & | 767 | cifs_sb->mnt_cifs_flags & |
768 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 768 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
769 | if (rc == 0) { | 769 | if (rc == 0) { |
770 | rc = CIFSSMBSetFileTimes(xid, pTcon, | 770 | rc = CIFSSMBSetFileInfo(xid, pTcon, |
771 | pinfo_buf, | 771 | pinfo_buf, |
772 | netfid); | 772 | netfid, |
773 | current->tgid); | ||
773 | CIFSSMBClose(xid, pTcon, netfid); | 774 | CIFSSMBClose(xid, pTcon, netfid); |
774 | } | 775 | } |
775 | } | 776 | } |
@@ -984,32 +985,41 @@ mkdir_get_info: | |||
984 | * failed to get it from the server or was set bogus */ | 985 | * failed to get it from the server or was set bogus */ |
985 | if ((direntry->d_inode) && (direntry->d_inode->i_nlink < 2)) | 986 | if ((direntry->d_inode) && (direntry->d_inode->i_nlink < 2)) |
986 | direntry->d_inode->i_nlink = 2; | 987 | direntry->d_inode->i_nlink = 2; |
988 | |||
987 | mode &= ~current->fs->umask; | 989 | mode &= ~current->fs->umask; |
990 | /* must turn on setgid bit if parent dir has it */ | ||
991 | if (inode->i_mode & S_ISGID) | ||
992 | mode |= S_ISGID; | ||
993 | |||
988 | if (pTcon->unix_ext) { | 994 | if (pTcon->unix_ext) { |
995 | struct cifs_unix_set_info_args args = { | ||
996 | .mode = mode, | ||
997 | .ctime = NO_CHANGE_64, | ||
998 | .atime = NO_CHANGE_64, | ||
999 | .mtime = NO_CHANGE_64, | ||
1000 | .device = 0, | ||
1001 | }; | ||
989 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { | 1002 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { |
990 | CIFSSMBUnixSetPerms(xid, pTcon, full_path, | 1003 | args.uid = (__u64)current->fsuid; |
991 | mode, | 1004 | if (inode->i_mode & S_ISGID) |
992 | (__u64)current->fsuid, | 1005 | args.gid = (__u64)inode->i_gid; |
993 | (__u64)current->fsgid, | 1006 | else |
994 | 0 /* dev_t */, | 1007 | args.gid = (__u64)current->fsgid; |
995 | cifs_sb->local_nls, | ||
996 | cifs_sb->mnt_cifs_flags & | ||
997 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
998 | } else { | 1008 | } else { |
999 | CIFSSMBUnixSetPerms(xid, pTcon, full_path, | 1009 | args.uid = NO_CHANGE_64; |
1000 | mode, (__u64)-1, | 1010 | args.gid = NO_CHANGE_64; |
1001 | (__u64)-1, 0 /* dev_t */, | ||
1002 | cifs_sb->local_nls, | ||
1003 | cifs_sb->mnt_cifs_flags & | ||
1004 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
1005 | } | 1011 | } |
1012 | CIFSSMBUnixSetInfo(xid, pTcon, full_path, &args, | ||
1013 | cifs_sb->local_nls, | ||
1014 | cifs_sb->mnt_cifs_flags & | ||
1015 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
1006 | } else { | 1016 | } else { |
1007 | if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) && | 1017 | if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) && |
1008 | (mode & S_IWUGO) == 0) { | 1018 | (mode & S_IWUGO) == 0) { |
1009 | FILE_BASIC_INFO pInfo; | 1019 | FILE_BASIC_INFO pInfo; |
1010 | memset(&pInfo, 0, sizeof(pInfo)); | 1020 | memset(&pInfo, 0, sizeof(pInfo)); |
1011 | pInfo.Attributes = cpu_to_le32(ATTR_READONLY); | 1021 | pInfo.Attributes = cpu_to_le32(ATTR_READONLY); |
1012 | CIFSSMBSetTimes(xid, pTcon, full_path, | 1022 | CIFSSMBSetPathInfo(xid, pTcon, full_path, |
1013 | &pInfo, cifs_sb->local_nls, | 1023 | &pInfo, cifs_sb->local_nls, |
1014 | cifs_sb->mnt_cifs_flags & | 1024 | cifs_sb->mnt_cifs_flags & |
1015 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 1025 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
@@ -1024,8 +1034,12 @@ mkdir_get_info: | |||
1024 | CIFS_MOUNT_SET_UID) { | 1034 | CIFS_MOUNT_SET_UID) { |
1025 | direntry->d_inode->i_uid = | 1035 | direntry->d_inode->i_uid = |
1026 | current->fsuid; | 1036 | current->fsuid; |
1027 | direntry->d_inode->i_gid = | 1037 | if (inode->i_mode & S_ISGID) |
1028 | current->fsgid; | 1038 | direntry->d_inode->i_gid = |
1039 | inode->i_gid; | ||
1040 | else | ||
1041 | direntry->d_inode->i_gid = | ||
1042 | current->fsgid; | ||
1029 | } | 1043 | } |
1030 | } | 1044 | } |
1031 | } | 1045 | } |
@@ -1310,10 +1324,11 @@ int cifs_revalidate(struct dentry *direntry) | |||
1310 | /* if (S_ISDIR(direntry->d_inode->i_mode)) | 1324 | /* if (S_ISDIR(direntry->d_inode->i_mode)) |
1311 | shrink_dcache_parent(direntry); */ | 1325 | shrink_dcache_parent(direntry); */ |
1312 | if (S_ISREG(direntry->d_inode->i_mode)) { | 1326 | if (S_ISREG(direntry->d_inode->i_mode)) { |
1313 | if (direntry->d_inode->i_mapping) | 1327 | if (direntry->d_inode->i_mapping) { |
1314 | wbrc = filemap_fdatawait(direntry->d_inode->i_mapping); | 1328 | wbrc = filemap_fdatawait(direntry->d_inode->i_mapping); |
1315 | if (wbrc) | 1329 | if (wbrc) |
1316 | CIFS_I(direntry->d_inode)->write_behind_rc = wbrc; | 1330 | CIFS_I(direntry->d_inode)->write_behind_rc = wbrc; |
1331 | } | ||
1317 | /* may eventually have to do this for open files too */ | 1332 | /* may eventually have to do this for open files too */ |
1318 | if (list_empty(&(cifsInode->openFileList))) { | 1333 | if (list_empty(&(cifsInode->openFileList))) { |
1319 | /* changed on server - flush read ahead pages */ | 1334 | /* changed on server - flush read ahead pages */ |
@@ -1489,30 +1504,228 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs, | |||
1489 | return rc; | 1504 | return rc; |
1490 | } | 1505 | } |
1491 | 1506 | ||
1492 | int cifs_setattr(struct dentry *direntry, struct iattr *attrs) | 1507 | static int |
1508 | cifs_set_file_info(struct inode *inode, struct iattr *attrs, int xid, | ||
1509 | char *full_path, __u32 dosattr) | ||
1510 | { | ||
1511 | int rc; | ||
1512 | int oplock = 0; | ||
1513 | __u16 netfid; | ||
1514 | __u32 netpid; | ||
1515 | bool set_time = false; | ||
1516 | struct cifsFileInfo *open_file; | ||
1517 | struct cifsInodeInfo *cifsInode = CIFS_I(inode); | ||
1518 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); | ||
1519 | struct cifsTconInfo *pTcon = cifs_sb->tcon; | ||
1520 | FILE_BASIC_INFO info_buf; | ||
1521 | |||
1522 | if (attrs->ia_valid & ATTR_ATIME) { | ||
1523 | set_time = true; | ||
1524 | info_buf.LastAccessTime = | ||
1525 | cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_atime)); | ||
1526 | } else | ||
1527 | info_buf.LastAccessTime = 0; | ||
1528 | |||
1529 | if (attrs->ia_valid & ATTR_MTIME) { | ||
1530 | set_time = true; | ||
1531 | info_buf.LastWriteTime = | ||
1532 | cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_mtime)); | ||
1533 | } else | ||
1534 | info_buf.LastWriteTime = 0; | ||
1535 | |||
1536 | /* | ||
1537 | * Samba throws this field away, but windows may actually use it. | ||
1538 | * Do not set ctime unless other time stamps are changed explicitly | ||
1539 | * (i.e. by utimes()) since we would then have a mix of client and | ||
1540 | * server times. | ||
1541 | */ | ||
1542 | if (set_time && (attrs->ia_valid & ATTR_CTIME)) { | ||
1543 | cFYI(1, ("CIFS - CTIME changed")); | ||
1544 | info_buf.ChangeTime = | ||
1545 | cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_ctime)); | ||
1546 | } else | ||
1547 | info_buf.ChangeTime = 0; | ||
1548 | |||
1549 | info_buf.CreationTime = 0; /* don't change */ | ||
1550 | info_buf.Attributes = cpu_to_le32(dosattr); | ||
1551 | |||
1552 | /* | ||
1553 | * If the file is already open for write, just use that fileid | ||
1554 | */ | ||
1555 | open_file = find_writable_file(cifsInode); | ||
1556 | if (open_file) { | ||
1557 | netfid = open_file->netfid; | ||
1558 | netpid = open_file->pid; | ||
1559 | goto set_via_filehandle; | ||
1560 | } | ||
1561 | |||
1562 | /* | ||
1563 | * NT4 apparently returns success on this call, but it doesn't | ||
1564 | * really work. | ||
1565 | */ | ||
1566 | if (!(pTcon->ses->flags & CIFS_SES_NT4)) { | ||
1567 | rc = CIFSSMBSetPathInfo(xid, pTcon, full_path, | ||
1568 | &info_buf, cifs_sb->local_nls, | ||
1569 | cifs_sb->mnt_cifs_flags & | ||
1570 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
1571 | if (rc != -EOPNOTSUPP && rc != -EINVAL) | ||
1572 | goto out; | ||
1573 | } | ||
1574 | |||
1575 | cFYI(1, ("calling SetFileInfo since SetPathInfo for " | ||
1576 | "times not supported by this server")); | ||
1577 | rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, | ||
1578 | SYNCHRONIZE | FILE_WRITE_ATTRIBUTES, | ||
1579 | CREATE_NOT_DIR, &netfid, &oplock, | ||
1580 | NULL, cifs_sb->local_nls, | ||
1581 | cifs_sb->mnt_cifs_flags & | ||
1582 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
1583 | |||
1584 | if (rc != 0) { | ||
1585 | if (rc == -EIO) | ||
1586 | rc = -EINVAL; | ||
1587 | goto out; | ||
1588 | } | ||
1589 | |||
1590 | netpid = current->tgid; | ||
1591 | |||
1592 | set_via_filehandle: | ||
1593 | rc = CIFSSMBSetFileInfo(xid, pTcon, &info_buf, netfid, netpid); | ||
1594 | if (open_file == NULL) | ||
1595 | CIFSSMBClose(xid, pTcon, netfid); | ||
1596 | else | ||
1597 | atomic_dec(&open_file->wrtPending); | ||
1598 | out: | ||
1599 | return rc; | ||
1600 | } | ||
1601 | |||
1602 | static int | ||
1603 | cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs) | ||
1493 | { | 1604 | { |
1605 | int rc; | ||
1494 | int xid; | 1606 | int xid; |
1495 | struct cifs_sb_info *cifs_sb; | ||
1496 | struct cifsTconInfo *pTcon; | ||
1497 | char *full_path = NULL; | 1607 | char *full_path = NULL; |
1498 | int rc = -EACCES; | ||
1499 | FILE_BASIC_INFO time_buf; | ||
1500 | bool set_time = false; | ||
1501 | bool set_dosattr = false; | ||
1502 | __u64 mode = 0xFFFFFFFFFFFFFFFFULL; | ||
1503 | __u64 uid = 0xFFFFFFFFFFFFFFFFULL; | ||
1504 | __u64 gid = 0xFFFFFFFFFFFFFFFFULL; | ||
1505 | struct cifsInodeInfo *cifsInode; | ||
1506 | struct inode *inode = direntry->d_inode; | 1608 | struct inode *inode = direntry->d_inode; |
1609 | struct cifsInodeInfo *cifsInode = CIFS_I(inode); | ||
1610 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); | ||
1611 | struct cifsTconInfo *pTcon = cifs_sb->tcon; | ||
1612 | struct cifs_unix_set_info_args *args = NULL; | ||
1613 | |||
1614 | cFYI(1, ("setattr_unix on file %s attrs->ia_valid=0x%x", | ||
1615 | direntry->d_name.name, attrs->ia_valid)); | ||
1616 | |||
1617 | xid = GetXid(); | ||
1618 | |||
1619 | if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) == 0) { | ||
1620 | /* check if we have permission to change attrs */ | ||
1621 | rc = inode_change_ok(inode, attrs); | ||
1622 | if (rc < 0) | ||
1623 | goto out; | ||
1624 | else | ||
1625 | rc = 0; | ||
1626 | } | ||
1627 | |||
1628 | full_path = build_path_from_dentry(direntry); | ||
1629 | if (full_path == NULL) { | ||
1630 | rc = -ENOMEM; | ||
1631 | goto out; | ||
1632 | } | ||
1633 | |||
1634 | if ((attrs->ia_valid & ATTR_MTIME) || (attrs->ia_valid & ATTR_SIZE)) { | ||
1635 | /* | ||
1636 | Flush data before changing file size or changing the last | ||
1637 | write time of the file on the server. If the | ||
1638 | flush returns error, store it to report later and continue. | ||
1639 | BB: This should be smarter. Why bother flushing pages that | ||
1640 | will be truncated anyway? Also, should we error out here if | ||
1641 | the flush returns error? | ||
1642 | */ | ||
1643 | rc = filemap_write_and_wait(inode->i_mapping); | ||
1644 | if (rc != 0) { | ||
1645 | cifsInode->write_behind_rc = rc; | ||
1646 | rc = 0; | ||
1647 | } | ||
1648 | } | ||
1649 | |||
1650 | if (attrs->ia_valid & ATTR_SIZE) { | ||
1651 | rc = cifs_set_file_size(inode, attrs, xid, full_path); | ||
1652 | if (rc != 0) | ||
1653 | goto out; | ||
1654 | } | ||
1655 | |||
1656 | /* skip mode change if it's just for clearing setuid/setgid */ | ||
1657 | if (attrs->ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID)) | ||
1658 | attrs->ia_valid &= ~ATTR_MODE; | ||
1659 | |||
1660 | args = kmalloc(sizeof(*args), GFP_KERNEL); | ||
1661 | if (args == NULL) { | ||
1662 | rc = -ENOMEM; | ||
1663 | goto out; | ||
1664 | } | ||
1665 | |||
1666 | /* set up the struct */ | ||
1667 | if (attrs->ia_valid & ATTR_MODE) | ||
1668 | args->mode = attrs->ia_mode; | ||
1669 | else | ||
1670 | args->mode = NO_CHANGE_64; | ||
1671 | |||
1672 | if (attrs->ia_valid & ATTR_UID) | ||
1673 | args->uid = attrs->ia_uid; | ||
1674 | else | ||
1675 | args->uid = NO_CHANGE_64; | ||
1676 | |||
1677 | if (attrs->ia_valid & ATTR_GID) | ||
1678 | args->gid = attrs->ia_gid; | ||
1679 | else | ||
1680 | args->gid = NO_CHANGE_64; | ||
1681 | |||
1682 | if (attrs->ia_valid & ATTR_ATIME) | ||
1683 | args->atime = cifs_UnixTimeToNT(attrs->ia_atime); | ||
1684 | else | ||
1685 | args->atime = NO_CHANGE_64; | ||
1686 | |||
1687 | if (attrs->ia_valid & ATTR_MTIME) | ||
1688 | args->mtime = cifs_UnixTimeToNT(attrs->ia_mtime); | ||
1689 | else | ||
1690 | args->mtime = NO_CHANGE_64; | ||
1691 | |||
1692 | if (attrs->ia_valid & ATTR_CTIME) | ||
1693 | args->ctime = cifs_UnixTimeToNT(attrs->ia_ctime); | ||
1694 | else | ||
1695 | args->ctime = NO_CHANGE_64; | ||
1696 | |||
1697 | args->device = 0; | ||
1698 | rc = CIFSSMBUnixSetInfo(xid, pTcon, full_path, args, | ||
1699 | cifs_sb->local_nls, | ||
1700 | cifs_sb->mnt_cifs_flags & | ||
1701 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
1702 | |||
1703 | if (!rc) | ||
1704 | rc = inode_setattr(inode, attrs); | ||
1705 | out: | ||
1706 | kfree(args); | ||
1707 | kfree(full_path); | ||
1708 | FreeXid(xid); | ||
1709 | return rc; | ||
1710 | } | ||
1711 | |||
1712 | static int | ||
1713 | cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs) | ||
1714 | { | ||
1715 | int xid; | ||
1716 | struct inode *inode = direntry->d_inode; | ||
1717 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); | ||
1718 | struct cifsInodeInfo *cifsInode = CIFS_I(inode); | ||
1719 | char *full_path = NULL; | ||
1720 | int rc = -EACCES; | ||
1721 | __u32 dosattr = 0; | ||
1722 | __u64 mode = NO_CHANGE_64; | ||
1507 | 1723 | ||
1508 | xid = GetXid(); | 1724 | xid = GetXid(); |
1509 | 1725 | ||
1510 | cFYI(1, ("setattr on file %s attrs->iavalid 0x%x", | 1726 | cFYI(1, ("setattr on file %s attrs->iavalid 0x%x", |
1511 | direntry->d_name.name, attrs->ia_valid)); | 1727 | direntry->d_name.name, attrs->ia_valid)); |
1512 | 1728 | ||
1513 | cifs_sb = CIFS_SB(inode->i_sb); | ||
1514 | pTcon = cifs_sb->tcon; | ||
1515 | |||
1516 | if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) == 0) { | 1729 | if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) == 0) { |
1517 | /* check if we have permission to change attrs */ | 1730 | /* check if we have permission to change attrs */ |
1518 | rc = inode_change_ok(inode, attrs); | 1731 | rc = inode_change_ok(inode, attrs); |
@@ -1528,7 +1741,6 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) | |||
1528 | FreeXid(xid); | 1741 | FreeXid(xid); |
1529 | return -ENOMEM; | 1742 | return -ENOMEM; |
1530 | } | 1743 | } |
1531 | cifsInode = CIFS_I(inode); | ||
1532 | 1744 | ||
1533 | if ((attrs->ia_valid & ATTR_MTIME) || (attrs->ia_valid & ATTR_SIZE)) { | 1745 | if ((attrs->ia_valid & ATTR_MTIME) || (attrs->ia_valid & ATTR_SIZE)) { |
1534 | /* | 1746 | /* |
@@ -1559,21 +1771,8 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) | |||
1559 | * CIFSACL support + proper Windows to Unix idmapping, we may be | 1771 | * CIFSACL support + proper Windows to Unix idmapping, we may be |
1560 | * able to support this in the future. | 1772 | * able to support this in the future. |
1561 | */ | 1773 | */ |
1562 | if (!pTcon->unix_ext && | 1774 | if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID)) |
1563 | !(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID)) { | ||
1564 | attrs->ia_valid &= ~(ATTR_UID | ATTR_GID); | 1775 | attrs->ia_valid &= ~(ATTR_UID | ATTR_GID); |
1565 | } else { | ||
1566 | if (attrs->ia_valid & ATTR_UID) { | ||
1567 | cFYI(1, ("UID changed to %d", attrs->ia_uid)); | ||
1568 | uid = attrs->ia_uid; | ||
1569 | } | ||
1570 | if (attrs->ia_valid & ATTR_GID) { | ||
1571 | cFYI(1, ("GID changed to %d", attrs->ia_gid)); | ||
1572 | gid = attrs->ia_gid; | ||
1573 | } | ||
1574 | } | ||
1575 | |||
1576 | time_buf.Attributes = 0; | ||
1577 | 1776 | ||
1578 | /* skip mode change if it's just for clearing setuid/setgid */ | 1777 | /* skip mode change if it's just for clearing setuid/setgid */ |
1579 | if (attrs->ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID)) | 1778 | if (attrs->ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID)) |
@@ -1584,13 +1783,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) | |||
1584 | mode = attrs->ia_mode; | 1783 | mode = attrs->ia_mode; |
1585 | } | 1784 | } |
1586 | 1785 | ||
1587 | if ((pTcon->unix_ext) | 1786 | if (attrs->ia_valid & ATTR_MODE) { |
1588 | && (attrs->ia_valid & (ATTR_MODE | ATTR_GID | ATTR_UID))) | ||
1589 | rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, uid, gid, | ||
1590 | 0 /* dev_t */, cifs_sb->local_nls, | ||
1591 | cifs_sb->mnt_cifs_flags & | ||
1592 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
1593 | else if (attrs->ia_valid & ATTR_MODE) { | ||
1594 | rc = 0; | 1787 | rc = 0; |
1595 | #ifdef CONFIG_CIFS_EXPERIMENTAL | 1788 | #ifdef CONFIG_CIFS_EXPERIMENTAL |
1596 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) | 1789 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) |
@@ -1599,24 +1792,19 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) | |||
1599 | #endif | 1792 | #endif |
1600 | if (((mode & S_IWUGO) == 0) && | 1793 | if (((mode & S_IWUGO) == 0) && |
1601 | (cifsInode->cifsAttrs & ATTR_READONLY) == 0) { | 1794 | (cifsInode->cifsAttrs & ATTR_READONLY) == 0) { |
1602 | set_dosattr = true; | 1795 | |
1603 | time_buf.Attributes = cpu_to_le32(cifsInode->cifsAttrs | | 1796 | dosattr = cifsInode->cifsAttrs | ATTR_READONLY; |
1604 | ATTR_READONLY); | 1797 | |
1605 | /* fix up mode if we're not using dynperm */ | 1798 | /* fix up mode if we're not using dynperm */ |
1606 | if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) == 0) | 1799 | if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) == 0) |
1607 | attrs->ia_mode = inode->i_mode & ~S_IWUGO; | 1800 | attrs->ia_mode = inode->i_mode & ~S_IWUGO; |
1608 | } else if ((mode & S_IWUGO) && | 1801 | } else if ((mode & S_IWUGO) && |
1609 | (cifsInode->cifsAttrs & ATTR_READONLY)) { | 1802 | (cifsInode->cifsAttrs & ATTR_READONLY)) { |
1610 | /* If file is readonly on server, we would | 1803 | |
1611 | not be able to write to it - so if any write | 1804 | dosattr = cifsInode->cifsAttrs & ~ATTR_READONLY; |
1612 | bit is enabled for user or group or other we | 1805 | /* Attributes of 0 are ignored */ |
1613 | need to at least try to remove r/o dos attr */ | 1806 | if (dosattr == 0) |
1614 | set_dosattr = true; | 1807 | dosattr |= ATTR_NORMAL; |
1615 | time_buf.Attributes = cpu_to_le32(cifsInode->cifsAttrs & | ||
1616 | (~ATTR_READONLY)); | ||
1617 | /* Windows ignores set to zero */ | ||
1618 | if (time_buf.Attributes == 0) | ||
1619 | time_buf.Attributes |= cpu_to_le32(ATTR_NORMAL); | ||
1620 | 1808 | ||
1621 | /* reset local inode permissions to normal */ | 1809 | /* reset local inode permissions to normal */ |
1622 | if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)) { | 1810 | if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)) { |
@@ -1634,82 +1822,18 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) | |||
1634 | } | 1822 | } |
1635 | } | 1823 | } |
1636 | 1824 | ||
1637 | if (attrs->ia_valid & ATTR_ATIME) { | 1825 | if (attrs->ia_valid & (ATTR_MTIME|ATTR_ATIME|ATTR_CTIME) || |
1638 | set_time = true; | 1826 | ((attrs->ia_valid & ATTR_MODE) && dosattr)) { |
1639 | time_buf.LastAccessTime = | 1827 | rc = cifs_set_file_info(inode, attrs, xid, full_path, dosattr); |
1640 | cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_atime)); | 1828 | /* BB: check for rc = -EOPNOTSUPP and switch to legacy mode */ |
1641 | } else | ||
1642 | time_buf.LastAccessTime = 0; | ||
1643 | |||
1644 | if (attrs->ia_valid & ATTR_MTIME) { | ||
1645 | set_time = true; | ||
1646 | time_buf.LastWriteTime = | ||
1647 | cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_mtime)); | ||
1648 | } else | ||
1649 | time_buf.LastWriteTime = 0; | ||
1650 | /* Do not set ctime explicitly unless other time | ||
1651 | stamps are changed explicitly (i.e. by utime() | ||
1652 | since we would then have a mix of client and | ||
1653 | server times */ | ||
1654 | 1829 | ||
1655 | if (set_time && (attrs->ia_valid & ATTR_CTIME)) { | ||
1656 | set_time = true; | ||
1657 | /* Although Samba throws this field away | ||
1658 | it may be useful to Windows - but we do | ||
1659 | not want to set ctime unless some other | ||
1660 | timestamp is changing */ | ||
1661 | cFYI(1, ("CIFS - CTIME changed")); | ||
1662 | time_buf.ChangeTime = | ||
1663 | cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_ctime)); | ||
1664 | } else | ||
1665 | time_buf.ChangeTime = 0; | ||
1666 | |||
1667 | if (set_time || set_dosattr) { | ||
1668 | time_buf.CreationTime = 0; /* do not change */ | ||
1669 | /* In the future we should experiment - try setting timestamps | ||
1670 | via Handle (SetFileInfo) instead of by path */ | ||
1671 | if (!(pTcon->ses->flags & CIFS_SES_NT4)) | ||
1672 | rc = CIFSSMBSetTimes(xid, pTcon, full_path, &time_buf, | ||
1673 | cifs_sb->local_nls, | ||
1674 | cifs_sb->mnt_cifs_flags & | ||
1675 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
1676 | else | ||
1677 | rc = -EOPNOTSUPP; | ||
1678 | |||
1679 | if (rc == -EOPNOTSUPP) { | ||
1680 | int oplock = 0; | ||
1681 | __u16 netfid; | ||
1682 | |||
1683 | cFYI(1, ("calling SetFileInfo since SetPathInfo for " | ||
1684 | "times not supported by this server")); | ||
1685 | /* BB we could scan to see if we already have it open | ||
1686 | and pass in pid of opener to function */ | ||
1687 | rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, | ||
1688 | SYNCHRONIZE | FILE_WRITE_ATTRIBUTES, | ||
1689 | CREATE_NOT_DIR, &netfid, &oplock, | ||
1690 | NULL, cifs_sb->local_nls, | ||
1691 | cifs_sb->mnt_cifs_flags & | ||
1692 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
1693 | if (rc == 0) { | ||
1694 | rc = CIFSSMBSetFileTimes(xid, pTcon, &time_buf, | ||
1695 | netfid); | ||
1696 | CIFSSMBClose(xid, pTcon, netfid); | ||
1697 | } else { | ||
1698 | /* BB For even older servers we could convert time_buf | ||
1699 | into old DOS style which uses two second | ||
1700 | granularity */ | ||
1701 | |||
1702 | /* rc = CIFSSMBSetTimesLegacy(xid, pTcon, full_path, | ||
1703 | &time_buf, cifs_sb->local_nls); */ | ||
1704 | } | ||
1705 | } | ||
1706 | /* Even if error on time set, no sense failing the call if | 1830 | /* Even if error on time set, no sense failing the call if |
1707 | the server would set the time to a reasonable value anyway, | 1831 | the server would set the time to a reasonable value anyway, |
1708 | and this check ensures that we are not being called from | 1832 | and this check ensures that we are not being called from |
1709 | sys_utimes in which case we ought to fail the call back to | 1833 | sys_utimes in which case we ought to fail the call back to |
1710 | the user when the server rejects the call */ | 1834 | the user when the server rejects the call */ |
1711 | if ((rc) && (attrs->ia_valid & | 1835 | if ((rc) && (attrs->ia_valid & |
1712 | (ATTR_MODE | ATTR_GID | ATTR_UID | ATTR_SIZE))) | 1836 | (ATTR_MODE | ATTR_GID | ATTR_UID | ATTR_SIZE))) |
1713 | rc = 0; | 1837 | rc = 0; |
1714 | } | 1838 | } |
1715 | 1839 | ||
@@ -1723,6 +1847,21 @@ cifs_setattr_exit: | |||
1723 | return rc; | 1847 | return rc; |
1724 | } | 1848 | } |
1725 | 1849 | ||
1850 | int | ||
1851 | cifs_setattr(struct dentry *direntry, struct iattr *attrs) | ||
1852 | { | ||
1853 | struct inode *inode = direntry->d_inode; | ||
1854 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); | ||
1855 | struct cifsTconInfo *pTcon = cifs_sb->tcon; | ||
1856 | |||
1857 | if (pTcon->unix_ext) | ||
1858 | return cifs_setattr_unix(direntry, attrs); | ||
1859 | |||
1860 | return cifs_setattr_nounix(direntry, attrs); | ||
1861 | |||
1862 | /* BB: add cifs_setattr_legacy for really old servers */ | ||
1863 | } | ||
1864 | |||
1726 | #if 0 | 1865 | #if 0 |
1727 | void cifs_delete_inode(struct inode *inode) | 1866 | void cifs_delete_inode(struct inode *inode) |
1728 | { | 1867 | { |