aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/cifs/inode.c157
1 files changed, 119 insertions, 38 deletions
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index 6d911896d74c..f68d1abe13e6 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -1504,30 +1504,138 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs,
1504 return rc; 1504 return rc;
1505} 1505}
1506 1506
1507static int
1508cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
1509{
1510 int rc;
1511 int xid;
1512 char *full_path = NULL;
1513 struct inode *inode = direntry->d_inode;
1514 struct cifsInodeInfo *cifsInode = CIFS_I(inode);
1515 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
1516 struct cifsTconInfo *pTcon = cifs_sb->tcon;
1517 struct cifs_unix_set_info_args *args = NULL;
1518
1519 cFYI(1, ("setattr_unix on file %s attrs->ia_valid=0x%x",
1520 direntry->d_name.name, attrs->ia_valid));
1521
1522 xid = GetXid();
1523
1524 if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) == 0) {
1525 /* check if we have permission to change attrs */
1526 rc = inode_change_ok(inode, attrs);
1527 if (rc < 0)
1528 goto out;
1529 else
1530 rc = 0;
1531 }
1532
1533 full_path = build_path_from_dentry(direntry);
1534 if (full_path == NULL) {
1535 rc = -ENOMEM;
1536 goto out;
1537 }
1538
1539 if ((attrs->ia_valid & ATTR_MTIME) || (attrs->ia_valid & ATTR_SIZE)) {
1540 /*
1541 Flush data before changing file size or changing the last
1542 write time of the file on the server. If the
1543 flush returns error, store it to report later and continue.
1544 BB: This should be smarter. Why bother flushing pages that
1545 will be truncated anyway? Also, should we error out here if
1546 the flush returns error?
1547 */
1548 rc = filemap_write_and_wait(inode->i_mapping);
1549 if (rc != 0) {
1550 cifsInode->write_behind_rc = rc;
1551 rc = 0;
1552 }
1553 }
1554
1555 if (attrs->ia_valid & ATTR_SIZE) {
1556 rc = cifs_set_file_size(inode, attrs, xid, full_path);
1557 if (rc != 0)
1558 goto out;
1559 }
1560
1561 /* skip mode change if it's just for clearing setuid/setgid */
1562 if (attrs->ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID))
1563 attrs->ia_valid &= ~ATTR_MODE;
1564
1565 args = kmalloc(sizeof(*args), GFP_KERNEL);
1566 if (args == NULL) {
1567 rc = -ENOMEM;
1568 goto out;
1569 }
1570
1571 /* set up the struct */
1572 if (attrs->ia_valid & ATTR_MODE)
1573 args->mode = attrs->ia_mode;
1574 else
1575 args->mode = NO_CHANGE_64;
1576
1577 if (attrs->ia_valid & ATTR_UID)
1578 args->uid = attrs->ia_uid;
1579 else
1580 args->uid = NO_CHANGE_64;
1581
1582 if (attrs->ia_valid & ATTR_GID)
1583 args->gid = attrs->ia_gid;
1584 else
1585 args->gid = NO_CHANGE_64;
1586
1587 if (attrs->ia_valid & ATTR_ATIME)
1588 args->atime = cifs_UnixTimeToNT(attrs->ia_atime);
1589 else
1590 args->atime = NO_CHANGE_64;
1591
1592 if (attrs->ia_valid & ATTR_MTIME)
1593 args->mtime = cifs_UnixTimeToNT(attrs->ia_mtime);
1594 else
1595 args->mtime = NO_CHANGE_64;
1596
1597 if (attrs->ia_valid & ATTR_CTIME)
1598 args->ctime = cifs_UnixTimeToNT(attrs->ia_ctime);
1599 else
1600 args->ctime = NO_CHANGE_64;
1601
1602 args->device = 0;
1603 rc = CIFSSMBUnixSetInfo(xid, pTcon, full_path, args,
1604 cifs_sb->local_nls,
1605 cifs_sb->mnt_cifs_flags &
1606 CIFS_MOUNT_MAP_SPECIAL_CHR);
1607
1608 if (!rc)
1609 rc = inode_setattr(inode, attrs);
1610out:
1611 kfree(args);
1612 kfree(full_path);
1613 FreeXid(xid);
1614 return rc;
1615}
1616
1507int cifs_setattr(struct dentry *direntry, struct iattr *attrs) 1617int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
1508{ 1618{
1509 int xid; 1619 int xid;
1510 struct cifs_sb_info *cifs_sb; 1620 struct inode *inode = direntry->d_inode;
1511 struct cifsTconInfo *pTcon; 1621 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
1622 struct cifsTconInfo *pTcon = cifs_sb->tcon;
1623 struct cifsInodeInfo *cifsInode = CIFS_I(inode);
1512 char *full_path = NULL; 1624 char *full_path = NULL;
1513 int rc = -EACCES; 1625 int rc = -EACCES;
1514 FILE_BASIC_INFO time_buf; 1626 FILE_BASIC_INFO time_buf;
1515 bool set_time = false; 1627 bool set_time = false;
1516 bool set_dosattr = false; 1628 bool set_dosattr = false;
1517 __u64 mode = NO_CHANGE_64; 1629 __u64 mode = NO_CHANGE_64;
1518 __u64 uid = NO_CHANGE_64; 1630
1519 __u64 gid = NO_CHANGE_64; 1631 if (pTcon->unix_ext)
1520 struct cifsInodeInfo *cifsInode; 1632 return cifs_setattr_unix(direntry, attrs);
1521 struct inode *inode = direntry->d_inode;
1522 1633
1523 xid = GetXid(); 1634 xid = GetXid();
1524 1635
1525 cFYI(1, ("setattr on file %s attrs->iavalid 0x%x", 1636 cFYI(1, ("setattr on file %s attrs->iavalid 0x%x",
1526 direntry->d_name.name, attrs->ia_valid)); 1637 direntry->d_name.name, attrs->ia_valid));
1527 1638
1528 cifs_sb = CIFS_SB(inode->i_sb);
1529 pTcon = cifs_sb->tcon;
1530
1531 if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) == 0) { 1639 if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) == 0) {
1532 /* check if we have permission to change attrs */ 1640 /* check if we have permission to change attrs */
1533 rc = inode_change_ok(inode, attrs); 1641 rc = inode_change_ok(inode, attrs);
@@ -1543,7 +1651,6 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
1543 FreeXid(xid); 1651 FreeXid(xid);
1544 return -ENOMEM; 1652 return -ENOMEM;
1545 } 1653 }
1546 cifsInode = CIFS_I(inode);
1547 1654
1548 if ((attrs->ia_valid & ATTR_MTIME) || (attrs->ia_valid & ATTR_SIZE)) { 1655 if ((attrs->ia_valid & ATTR_MTIME) || (attrs->ia_valid & ATTR_SIZE)) {
1549 /* 1656 /*
@@ -1574,19 +1681,8 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
1574 * CIFSACL support + proper Windows to Unix idmapping, we may be 1681 * CIFSACL support + proper Windows to Unix idmapping, we may be
1575 * able to support this in the future. 1682 * able to support this in the future.
1576 */ 1683 */
1577 if (!pTcon->unix_ext && 1684 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID))
1578 !(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID)) {
1579 attrs->ia_valid &= ~(ATTR_UID | ATTR_GID); 1685 attrs->ia_valid &= ~(ATTR_UID | ATTR_GID);
1580 } else {
1581 if (attrs->ia_valid & ATTR_UID) {
1582 cFYI(1, ("UID changed to %d", attrs->ia_uid));
1583 uid = attrs->ia_uid;
1584 }
1585 if (attrs->ia_valid & ATTR_GID) {
1586 cFYI(1, ("GID changed to %d", attrs->ia_gid));
1587 gid = attrs->ia_gid;
1588 }
1589 }
1590 1686
1591 time_buf.Attributes = 0; 1687 time_buf.Attributes = 0;
1592 1688
@@ -1599,22 +1695,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
1599 mode = attrs->ia_mode; 1695 mode = attrs->ia_mode;
1600 } 1696 }
1601 1697
1602 if ((pTcon->unix_ext) 1698 if (attrs->ia_valid & ATTR_MODE) {
1603 && (attrs->ia_valid & (ATTR_MODE | ATTR_GID | ATTR_UID))) {
1604 struct cifs_unix_set_info_args args = {
1605 .mode = mode,
1606 .uid = uid,
1607 .gid = gid,
1608 .ctime = NO_CHANGE_64,
1609 .atime = NO_CHANGE_64,
1610 .mtime = NO_CHANGE_64,
1611 .device = 0,
1612 };
1613 rc = CIFSSMBUnixSetInfo(xid, pTcon, full_path, &args,
1614 cifs_sb->local_nls,
1615 cifs_sb->mnt_cifs_flags &
1616 CIFS_MOUNT_MAP_SPECIAL_CHR);
1617 } else if (attrs->ia_valid & ATTR_MODE) {
1618 rc = 0; 1699 rc = 0;
1619#ifdef CONFIG_CIFS_EXPERIMENTAL 1700#ifdef CONFIG_CIFS_EXPERIMENTAL
1620 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) 1701 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL)