aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/cifs/inode.c196
1 files changed, 109 insertions, 87 deletions
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index f68d1abe13e6..5c722ea21133 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -1505,6 +1505,101 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs,
1505} 1505}
1506 1506
1507static int 1507static int
1508cifs_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
1592set_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);
1598out:
1599 return rc;
1600}
1601
1602static int
1508cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs) 1603cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
1509{ 1604{
1510 int rc; 1605 int rc;
@@ -1623,9 +1718,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
1623 struct cifsInodeInfo *cifsInode = CIFS_I(inode); 1718 struct cifsInodeInfo *cifsInode = CIFS_I(inode);
1624 char *full_path = NULL; 1719 char *full_path = NULL;
1625 int rc = -EACCES; 1720 int rc = -EACCES;
1626 FILE_BASIC_INFO time_buf; 1721 __u32 dosattr = 0;
1627 bool set_time = false;
1628 bool set_dosattr = false;
1629 __u64 mode = NO_CHANGE_64; 1722 __u64 mode = NO_CHANGE_64;
1630 1723
1631 if (pTcon->unix_ext) 1724 if (pTcon->unix_ext)
@@ -1684,8 +1777,6 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
1684 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID)) 1777 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID))
1685 attrs->ia_valid &= ~(ATTR_UID | ATTR_GID); 1778 attrs->ia_valid &= ~(ATTR_UID | ATTR_GID);
1686 1779
1687 time_buf.Attributes = 0;
1688
1689 /* skip mode change if it's just for clearing setuid/setgid */ 1780 /* skip mode change if it's just for clearing setuid/setgid */
1690 if (attrs->ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID)) 1781 if (attrs->ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID))
1691 attrs->ia_valid &= ~ATTR_MODE; 1782 attrs->ia_valid &= ~ATTR_MODE;
@@ -1704,24 +1795,19 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
1704#endif 1795#endif
1705 if (((mode & S_IWUGO) == 0) && 1796 if (((mode & S_IWUGO) == 0) &&
1706 (cifsInode->cifsAttrs & ATTR_READONLY) == 0) { 1797 (cifsInode->cifsAttrs & ATTR_READONLY) == 0) {
1707 set_dosattr = true; 1798
1708 time_buf.Attributes = cpu_to_le32(cifsInode->cifsAttrs | 1799 dosattr = cifsInode->cifsAttrs | ATTR_READONLY;
1709 ATTR_READONLY); 1800
1710 /* fix up mode if we're not using dynperm */ 1801 /* fix up mode if we're not using dynperm */
1711 if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) == 0) 1802 if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) == 0)
1712 attrs->ia_mode = inode->i_mode & ~S_IWUGO; 1803 attrs->ia_mode = inode->i_mode & ~S_IWUGO;
1713 } else if ((mode & S_IWUGO) && 1804 } else if ((mode & S_IWUGO) &&
1714 (cifsInode->cifsAttrs & ATTR_READONLY)) { 1805 (cifsInode->cifsAttrs & ATTR_READONLY)) {
1715 /* If file is readonly on server, we would 1806
1716 not be able to write to it - so if any write 1807 dosattr = cifsInode->cifsAttrs & ~ATTR_READONLY;
1717 bit is enabled for user or group or other we 1808 /* Attributes of 0 are ignored */
1718 need to at least try to remove r/o dos attr */ 1809 if (dosattr == 0)
1719 set_dosattr = true; 1810 dosattr |= ATTR_NORMAL;
1720 time_buf.Attributes = cpu_to_le32(cifsInode->cifsAttrs &
1721 (~ATTR_READONLY));
1722 /* Windows ignores set to zero */
1723 if (time_buf.Attributes == 0)
1724 time_buf.Attributes |= cpu_to_le32(ATTR_NORMAL);
1725 1811
1726 /* reset local inode permissions to normal */ 1812 /* reset local inode permissions to normal */
1727 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)) { 1813 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)) {
@@ -1739,82 +1825,18 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
1739 } 1825 }
1740 } 1826 }
1741 1827
1742 if (attrs->ia_valid & ATTR_ATIME) { 1828 if (attrs->ia_valid & (ATTR_MTIME|ATTR_ATIME|ATTR_CTIME) ||
1743 set_time = true; 1829 ((attrs->ia_valid & ATTR_MODE) && dosattr)) {
1744 time_buf.LastAccessTime = 1830 rc = cifs_set_file_info(inode, attrs, xid, full_path, dosattr);
1745 cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_atime)); 1831 /* BB: check for rc = -EOPNOTSUPP and switch to legacy mode */
1746 } else
1747 time_buf.LastAccessTime = 0;
1748
1749 if (attrs->ia_valid & ATTR_MTIME) {
1750 set_time = true;
1751 time_buf.LastWriteTime =
1752 cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_mtime));
1753 } else
1754 time_buf.LastWriteTime = 0;
1755 /* Do not set ctime explicitly unless other time
1756 stamps are changed explicitly (i.e. by utime()
1757 since we would then have a mix of client and
1758 server times */
1759
1760 if (set_time && (attrs->ia_valid & ATTR_CTIME)) {
1761 set_time = true;
1762 /* Although Samba throws this field away
1763 it may be useful to Windows - but we do
1764 not want to set ctime unless some other
1765 timestamp is changing */
1766 cFYI(1, ("CIFS - CTIME changed"));
1767 time_buf.ChangeTime =
1768 cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_ctime));
1769 } else
1770 time_buf.ChangeTime = 0;
1771
1772 if (set_time || set_dosattr) {
1773 time_buf.CreationTime = 0; /* do not change */
1774 /* In the future we should experiment - try setting timestamps
1775 via Handle (SetFileInfo) instead of by path */
1776 if (!(pTcon->ses->flags & CIFS_SES_NT4))
1777 rc = CIFSSMBSetPathInfo(xid, pTcon, full_path,
1778 &time_buf, cifs_sb->local_nls,
1779 cifs_sb->mnt_cifs_flags &
1780 CIFS_MOUNT_MAP_SPECIAL_CHR);
1781 else
1782 rc = -EOPNOTSUPP;
1783
1784 if (rc == -EOPNOTSUPP) {
1785 int oplock = 0;
1786 __u16 netfid;
1787 1832
1788 cFYI(1, ("calling SetFileInfo since SetPathInfo for "
1789 "times not supported by this server"));
1790 /* BB we could scan to see if we already have it open
1791 and pass in pid of opener to function */
1792 rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN,
1793 SYNCHRONIZE | FILE_WRITE_ATTRIBUTES,
1794 CREATE_NOT_DIR, &netfid, &oplock,
1795 NULL, cifs_sb->local_nls,
1796 cifs_sb->mnt_cifs_flags &
1797 CIFS_MOUNT_MAP_SPECIAL_CHR);
1798 if (rc == 0) {
1799 rc = CIFSSMBSetFileInfo(xid, pTcon, &time_buf,
1800 netfid, current->tgid);
1801 CIFSSMBClose(xid, pTcon, netfid);
1802 } else {
1803 /* BB For even older servers we could convert time_buf
1804 into old DOS style which uses two second
1805 granularity */
1806
1807 /* rc = CIFSSMBSetTimesLegacy(xid, pTcon, full_path,
1808 &time_buf, cifs_sb->local_nls); */
1809 }
1810 }
1811 /* Even if error on time set, no sense failing the call if 1833 /* Even if error on time set, no sense failing the call if
1812 the server would set the time to a reasonable value anyway, 1834 the server would set the time to a reasonable value anyway,
1813 and this check ensures that we are not being called from 1835 and this check ensures that we are not being called from
1814 sys_utimes in which case we ought to fail the call back to 1836 sys_utimes in which case we ought to fail the call back to
1815 the user when the server rejects the call */ 1837 the user when the server rejects the call */
1816 if ((rc) && (attrs->ia_valid & 1838 if ((rc) && (attrs->ia_valid &
1817 (ATTR_MODE | ATTR_GID | ATTR_UID | ATTR_SIZE))) 1839 (ATTR_MODE | ATTR_GID | ATTR_UID | ATTR_SIZE)))
1818 rc = 0; 1840 rc = 0;
1819 } 1841 }
1820 1842