diff options
-rw-r--r-- | fs/cifs/inode.c | 157 |
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 | ||
1507 | static int | ||
1508 | cifs_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); | ||
1610 | out: | ||
1611 | kfree(args); | ||
1612 | kfree(full_path); | ||
1613 | FreeXid(xid); | ||
1614 | return rc; | ||
1615 | } | ||
1616 | |||
1507 | int cifs_setattr(struct dentry *direntry, struct iattr *attrs) | 1617 | int 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) |