aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/cifs/cifsglob.h3
-rw-r--r--fs/cifs/cifsproto.h5
-rw-r--r--fs/cifs/cifssmb.c22
-rw-r--r--fs/cifs/inode.c92
-rw-r--r--fs/cifs/smb1ops.c1
5 files changed, 66 insertions, 57 deletions
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 6217df707909..a0105c547ffd 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -275,6 +275,9 @@ struct smb_version_operations {
275 /* open, rename and delete file */ 275 /* open, rename and delete file */
276 int (*rename_pending_delete)(const char *, struct dentry *, 276 int (*rename_pending_delete)(const char *, struct dentry *,
277 const unsigned int); 277 const unsigned int);
278 /* send rename request */
279 int (*rename)(const unsigned int, struct cifs_tcon *, const char *,
280 const char *, struct cifs_sb_info *);
278 /* open a file for non-posix mounts */ 281 /* open a file for non-posix mounts */
279 int (*open)(const unsigned int, struct cifs_tcon *, const char *, int, 282 int (*open)(const unsigned int, struct cifs_tcon *, const char *, int,
280 int, int, struct cifs_fid *, __u32 *, FILE_ALL_INFO *, 283 int, int, struct cifs_fid *, __u32 *, FILE_ALL_INFO *,
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 541738fcaebc..eecd233c6912 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -310,9 +310,8 @@ extern int CIFSPOSIXDelFile(const unsigned int xid, struct cifs_tcon *tcon,
310extern int CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon, 310extern int CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon,
311 const char *name, struct cifs_sb_info *cifs_sb); 311 const char *name, struct cifs_sb_info *cifs_sb);
312extern int CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon, 312extern int CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
313 const char *fromName, const char *toName, 313 const char *from_name, const char *to_name,
314 const struct nls_table *nls_codepage, 314 struct cifs_sb_info *cifs_sb);
315 int remap_special_chars);
316extern int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *tcon, 315extern int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *tcon,
317 int netfid, const char *target_name, 316 int netfid, const char *target_name,
318 const struct nls_table *nls_codepage, 317 const struct nls_table *nls_codepage,
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 733119dad493..b8cd335d6f11 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -2531,8 +2531,8 @@ CIFSSMBFlush(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
2531 2531
2532int 2532int
2533CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon, 2533CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
2534 const char *fromName, const char *toName, 2534 const char *from_name, const char *to_name,
2535 const struct nls_table *nls_codepage, int remap) 2535 struct cifs_sb_info *cifs_sb)
2536{ 2536{
2537 int rc = 0; 2537 int rc = 0;
2538 RENAME_REQ *pSMB = NULL; 2538 RENAME_REQ *pSMB = NULL;
@@ -2540,6 +2540,7 @@ CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
2540 int bytes_returned; 2540 int bytes_returned;
2541 int name_len, name_len2; 2541 int name_len, name_len2;
2542 __u16 count; 2542 __u16 count;
2543 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
2543 2544
2544 cFYI(1, "In CIFSSMBRename"); 2545 cFYI(1, "In CIFSSMBRename");
2545renameRetry: 2546renameRetry:
@@ -2554,9 +2555,9 @@ renameRetry:
2554 ATTR_DIRECTORY); 2555 ATTR_DIRECTORY);
2555 2556
2556 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { 2557 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2557 name_len = 2558 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2558 cifsConvertToUTF16((__le16 *) pSMB->OldFileName, fromName, 2559 from_name, PATH_MAX,
2559 PATH_MAX, nls_codepage, remap); 2560 cifs_sb->local_nls, remap);
2560 name_len++; /* trailing null */ 2561 name_len++; /* trailing null */
2561 name_len *= 2; 2562 name_len *= 2;
2562 pSMB->OldFileName[name_len] = 0x04; /* pad */ 2563 pSMB->OldFileName[name_len] = 0x04; /* pad */
@@ -2564,17 +2565,18 @@ renameRetry:
2564 pSMB->OldFileName[name_len + 1] = 0x00; 2565 pSMB->OldFileName[name_len + 1] = 0x00;
2565 name_len2 = 2566 name_len2 =
2566 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2], 2567 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
2567 toName, PATH_MAX, nls_codepage, remap); 2568 to_name, PATH_MAX, cifs_sb->local_nls,
2569 remap);
2568 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ; 2570 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2569 name_len2 *= 2; /* convert to bytes */ 2571 name_len2 *= 2; /* convert to bytes */
2570 } else { /* BB improve the check for buffer overruns BB */ 2572 } else { /* BB improve the check for buffer overruns BB */
2571 name_len = strnlen(fromName, PATH_MAX); 2573 name_len = strnlen(from_name, PATH_MAX);
2572 name_len++; /* trailing null */ 2574 name_len++; /* trailing null */
2573 strncpy(pSMB->OldFileName, fromName, name_len); 2575 strncpy(pSMB->OldFileName, from_name, name_len);
2574 name_len2 = strnlen(toName, PATH_MAX); 2576 name_len2 = strnlen(to_name, PATH_MAX);
2575 name_len2++; /* trailing null */ 2577 name_len2++; /* trailing null */
2576 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */ 2578 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2577 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2); 2579 strncpy(&pSMB->OldFileName[name_len + 1], to_name, name_len2);
2578 name_len2++; /* trailing null */ 2580 name_len2++; /* trailing null */
2579 name_len2++; /* signature byte */ 2581 name_len2++; /* signature byte */
2580 } 2582 }
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index c6f6b02cf3b5..2f3235f08c3f 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -1512,29 +1512,32 @@ rmdir_exit:
1512} 1512}
1513 1513
1514static int 1514static int
1515cifs_do_rename(unsigned int xid, struct dentry *from_dentry, 1515cifs_do_rename(const unsigned int xid, struct dentry *from_dentry,
1516 const char *fromPath, struct dentry *to_dentry, 1516 const char *from_path, struct dentry *to_dentry,
1517 const char *toPath) 1517 const char *to_path)
1518{ 1518{
1519 struct cifs_sb_info *cifs_sb = CIFS_SB(from_dentry->d_sb); 1519 struct cifs_sb_info *cifs_sb = CIFS_SB(from_dentry->d_sb);
1520 struct tcon_link *tlink; 1520 struct tcon_link *tlink;
1521 struct cifs_tcon *pTcon; 1521 struct cifs_tcon *tcon;
1522 struct TCP_Server_Info *server;
1522 __u16 srcfid; 1523 __u16 srcfid;
1523 int oplock, rc; 1524 int oplock, rc;
1524 1525
1525 tlink = cifs_sb_tlink(cifs_sb); 1526 tlink = cifs_sb_tlink(cifs_sb);
1526 if (IS_ERR(tlink)) 1527 if (IS_ERR(tlink))
1527 return PTR_ERR(tlink); 1528 return PTR_ERR(tlink);
1528 pTcon = tlink_tcon(tlink); 1529 tcon = tlink_tcon(tlink);
1530 server = tcon->ses->server;
1531
1532 if (!server->ops->rename)
1533 return -ENOSYS;
1529 1534
1530 /* try path-based rename first */ 1535 /* try path-based rename first */
1531 rc = CIFSSMBRename(xid, pTcon, fromPath, toPath, cifs_sb->local_nls, 1536 rc = server->ops->rename(xid, tcon, from_path, to_path, cifs_sb);
1532 cifs_sb->mnt_cifs_flags &
1533 CIFS_MOUNT_MAP_SPECIAL_CHR);
1534 1537
1535 /* 1538 /*
1536 * don't bother with rename by filehandle unless file is busy and 1539 * Don't bother with rename by filehandle unless file is busy and
1537 * source Note that cross directory moves do not work with 1540 * source. Note that cross directory moves do not work with
1538 * rename by filehandle to various Windows servers. 1541 * rename by filehandle to various Windows servers.
1539 */ 1542 */
1540 if (rc == 0 || rc != -ETXTBSY) 1543 if (rc == 0 || rc != -ETXTBSY)
@@ -1545,29 +1548,28 @@ cifs_do_rename(unsigned int xid, struct dentry *from_dentry,
1545 goto do_rename_exit; 1548 goto do_rename_exit;
1546 1549
1547 /* open the file to be renamed -- we need DELETE perms */ 1550 /* open the file to be renamed -- we need DELETE perms */
1548 rc = CIFSSMBOpen(xid, pTcon, fromPath, FILE_OPEN, DELETE, 1551 rc = CIFSSMBOpen(xid, tcon, from_path, FILE_OPEN, DELETE,
1549 CREATE_NOT_DIR, &srcfid, &oplock, NULL, 1552 CREATE_NOT_DIR, &srcfid, &oplock, NULL,
1550 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & 1553 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
1551 CIFS_MOUNT_MAP_SPECIAL_CHR); 1554 CIFS_MOUNT_MAP_SPECIAL_CHR);
1552
1553 if (rc == 0) { 1555 if (rc == 0) {
1554 rc = CIFSSMBRenameOpenFile(xid, pTcon, srcfid, 1556 rc = CIFSSMBRenameOpenFile(xid, tcon, srcfid,
1555 (const char *) to_dentry->d_name.name, 1557 (const char *) to_dentry->d_name.name,
1556 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & 1558 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
1557 CIFS_MOUNT_MAP_SPECIAL_CHR); 1559 CIFS_MOUNT_MAP_SPECIAL_CHR);
1558 1560 CIFSSMBClose(xid, tcon, srcfid);
1559 CIFSSMBClose(xid, pTcon, srcfid);
1560 } 1561 }
1561do_rename_exit: 1562do_rename_exit:
1562 cifs_put_tlink(tlink); 1563 cifs_put_tlink(tlink);
1563 return rc; 1564 return rc;
1564} 1565}
1565 1566
1566int cifs_rename(struct inode *source_dir, struct dentry *source_dentry, 1567int
1567 struct inode *target_dir, struct dentry *target_dentry) 1568cifs_rename(struct inode *source_dir, struct dentry *source_dentry,
1569 struct inode *target_dir, struct dentry *target_dentry)
1568{ 1570{
1569 char *fromName = NULL; 1571 char *from_name = NULL;
1570 char *toName = NULL; 1572 char *to_name = NULL;
1571 struct cifs_sb_info *cifs_sb; 1573 struct cifs_sb_info *cifs_sb;
1572 struct tcon_link *tlink; 1574 struct tcon_link *tlink;
1573 struct cifs_tcon *tcon; 1575 struct cifs_tcon *tcon;
@@ -1588,25 +1590,25 @@ int cifs_rename(struct inode *source_dir, struct dentry *source_dentry,
1588 * we already have the rename sem so we do not need to 1590 * we already have the rename sem so we do not need to
1589 * grab it again here to protect the path integrity 1591 * grab it again here to protect the path integrity
1590 */ 1592 */
1591 fromName = build_path_from_dentry(source_dentry); 1593 from_name = build_path_from_dentry(source_dentry);
1592 if (fromName == NULL) { 1594 if (from_name == NULL) {
1593 rc = -ENOMEM; 1595 rc = -ENOMEM;
1594 goto cifs_rename_exit; 1596 goto cifs_rename_exit;
1595 } 1597 }
1596 1598
1597 toName = build_path_from_dentry(target_dentry); 1599 to_name = build_path_from_dentry(target_dentry);
1598 if (toName == NULL) { 1600 if (to_name == NULL) {
1599 rc = -ENOMEM; 1601 rc = -ENOMEM;
1600 goto cifs_rename_exit; 1602 goto cifs_rename_exit;
1601 } 1603 }
1602 1604
1603 rc = cifs_do_rename(xid, source_dentry, fromName, 1605 rc = cifs_do_rename(xid, source_dentry, from_name, target_dentry,
1604 target_dentry, toName); 1606 to_name);
1605 1607
1606 if (rc == -EEXIST && tcon->unix_ext) { 1608 if (rc == -EEXIST && tcon->unix_ext) {
1607 /* 1609 /*
1608 * Are src and dst hardlinks of same inode? We can 1610 * Are src and dst hardlinks of same inode? We can only tell
1609 * only tell with unix extensions enabled 1611 * with unix extensions enabled.
1610 */ 1612 */
1611 info_buf_source = 1613 info_buf_source =
1612 kmalloc(2 * sizeof(FILE_UNIX_BASIC_INFO), 1614 kmalloc(2 * sizeof(FILE_UNIX_BASIC_INFO),
@@ -1617,19 +1619,19 @@ int cifs_rename(struct inode *source_dir, struct dentry *source_dentry,
1617 } 1619 }
1618 1620
1619 info_buf_target = info_buf_source + 1; 1621 info_buf_target = info_buf_source + 1;
1620 tmprc = CIFSSMBUnixQPathInfo(xid, tcon, fromName, 1622 tmprc = CIFSSMBUnixQPathInfo(xid, tcon, from_name,
1621 info_buf_source, 1623 info_buf_source,
1622 cifs_sb->local_nls, 1624 cifs_sb->local_nls,
1623 cifs_sb->mnt_cifs_flags & 1625 cifs_sb->mnt_cifs_flags &
1624 CIFS_MOUNT_MAP_SPECIAL_CHR); 1626 CIFS_MOUNT_MAP_SPECIAL_CHR);
1625 if (tmprc != 0) 1627 if (tmprc != 0)
1626 goto unlink_target; 1628 goto unlink_target;
1627 1629
1628 tmprc = CIFSSMBUnixQPathInfo(xid, tcon, toName, 1630 tmprc = CIFSSMBUnixQPathInfo(xid, tcon, to_name,
1629 info_buf_target, 1631 info_buf_target,
1630 cifs_sb->local_nls, 1632 cifs_sb->local_nls,
1631 cifs_sb->mnt_cifs_flags & 1633 cifs_sb->mnt_cifs_flags &
1632 CIFS_MOUNT_MAP_SPECIAL_CHR); 1634 CIFS_MOUNT_MAP_SPECIAL_CHR);
1633 1635
1634 if (tmprc == 0 && (info_buf_source->UniqueId == 1636 if (tmprc == 0 && (info_buf_source->UniqueId ==
1635 info_buf_target->UniqueId)) { 1637 info_buf_target->UniqueId)) {
@@ -1637,8 +1639,11 @@ int cifs_rename(struct inode *source_dir, struct dentry *source_dentry,
1637 rc = 0; 1639 rc = 0;
1638 goto cifs_rename_exit; 1640 goto cifs_rename_exit;
1639 } 1641 }
1640 } /* else ... BB we could add the same check for Windows by 1642 }
1641 checking the UniqueId via FILE_INTERNAL_INFO */ 1643 /*
1644 * else ... BB we could add the same check for Windows by
1645 * checking the UniqueId via FILE_INTERNAL_INFO
1646 */
1642 1647
1643unlink_target: 1648unlink_target:
1644 /* Try unlinking the target dentry if it's not negative */ 1649 /* Try unlinking the target dentry if it's not negative */
@@ -1646,15 +1651,14 @@ unlink_target:
1646 tmprc = cifs_unlink(target_dir, target_dentry); 1651 tmprc = cifs_unlink(target_dir, target_dentry);
1647 if (tmprc) 1652 if (tmprc)
1648 goto cifs_rename_exit; 1653 goto cifs_rename_exit;
1649 1654 rc = cifs_do_rename(xid, source_dentry, from_name,
1650 rc = cifs_do_rename(xid, source_dentry, fromName, 1655 target_dentry, to_name);
1651 target_dentry, toName);
1652 } 1656 }
1653 1657
1654cifs_rename_exit: 1658cifs_rename_exit:
1655 kfree(info_buf_source); 1659 kfree(info_buf_source);
1656 kfree(fromName); 1660 kfree(from_name);
1657 kfree(toName); 1661 kfree(to_name);
1658 free_xid(xid); 1662 free_xid(xid);
1659 cifs_put_tlink(tlink); 1663 cifs_put_tlink(tlink);
1660 return rc; 1664 return rc;
diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
index aa55c2fbf793..377392003655 100644
--- a/fs/cifs/smb1ops.c
+++ b/fs/cifs/smb1ops.c
@@ -800,6 +800,7 @@ struct smb_version_operations smb1_operations = {
800 .rmdir = CIFSSMBRmDir, 800 .rmdir = CIFSSMBRmDir,
801 .unlink = CIFSSMBDelFile, 801 .unlink = CIFSSMBDelFile,
802 .rename_pending_delete = cifs_rename_pending_delete, 802 .rename_pending_delete = cifs_rename_pending_delete,
803 .rename = CIFSSMBRename,
803 .open = cifs_open_file, 804 .open = cifs_open_file,
804 .set_fid = cifs_set_fid, 805 .set_fid = cifs_set_fid,
805 .close = cifs_close_file, 806 .close = cifs_close_file,