aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorPavel Shilovsky <pshilovsky@samba.org>2012-09-18 19:20:31 -0400
committerSteve French <smfrench@gmail.com>2012-09-24 22:46:29 -0400
commit35143eb5c2e3ae6c91b29144449d23f05f573796 (patch)
treec022f223815788cad6dbc9156f9d47edefc5f81d /fs
parent8ceb984379462f94bdebef3288d569c6e1f912ea (diff)
CIFS: Add SMB2 support for rename operation
Signed-off-by: Pavel Shilovsky <piastryyy@gmail.com> Signed-off-by: Steve French <smfrench@gmail.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/cifs/smb2inode.c25
-rw-r--r--fs/cifs/smb2ops.c1
-rw-r--r--fs/cifs/smb2pdu.c107
-rw-r--r--fs/cifs/smb2pdu.h28
-rw-r--r--fs/cifs/smb2proto.h6
5 files changed, 167 insertions, 0 deletions
diff --git a/fs/cifs/smb2inode.c b/fs/cifs/smb2inode.c
index ee3a1ef686dd..a6952bafe331 100644
--- a/fs/cifs/smb2inode.c
+++ b/fs/cifs/smb2inode.c
@@ -74,6 +74,10 @@ smb2_open_op_close(const unsigned int xid, struct cifs_tcon *tcon,
74 * SMB2_open() call. 74 * SMB2_open() call.
75 */ 75 */
76 break; 76 break;
77 case SMB2_OP_RENAME:
78 tmprc = SMB2_rename(xid, tcon, persistent_fid, volatile_fid,
79 (__le16 *)data);
80 break;
77 default: 81 default:
78 cERROR(1, "Invalid command"); 82 cERROR(1, "Invalid command");
79 break; 83 break;
@@ -170,3 +174,24 @@ smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
170 0, CREATE_DELETE_ON_CLOSE, NULL, 174 0, CREATE_DELETE_ON_CLOSE, NULL,
171 SMB2_OP_DELETE); 175 SMB2_OP_DELETE);
172} 176}
177
178int
179smb2_rename_path(const unsigned int xid, struct cifs_tcon *tcon,
180 const char *from_name, const char *to_name,
181 struct cifs_sb_info *cifs_sb)
182{
183 __le16 *smb2_to_name = NULL;
184 int rc;
185
186 smb2_to_name = cifs_convert_path_to_utf16(to_name, cifs_sb);
187 if (smb2_to_name == NULL) {
188 rc = -ENOMEM;
189 goto smb2_rename_path;
190 }
191
192 rc = smb2_open_op_close(xid, tcon, cifs_sb, from_name, DELETE,
193 FILE_OPEN, 0, 0, smb2_to_name, SMB2_OP_RENAME);
194smb2_rename_path:
195 kfree(smb2_to_name);
196 return rc;
197}
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index f9c3dbee9010..5aaccb0f3aae 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -451,6 +451,7 @@ struct smb_version_operations smb21_operations = {
451 .mkdir_setinfo = smb2_mkdir_setinfo, 451 .mkdir_setinfo = smb2_mkdir_setinfo,
452 .rmdir = smb2_rmdir, 452 .rmdir = smb2_rmdir,
453 .unlink = smb2_unlink, 453 .unlink = smb2_unlink,
454 .rename = smb2_rename_path,
454 .open = smb2_open_file, 455 .open = smb2_open_file,
455 .set_fid = smb2_set_fid, 456 .set_fid = smb2_set_fid,
456 .close = smb2_close_file, 457 .close = smb2_close_file,
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index 30c92c847fe8..1dc11ce7934e 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -1602,3 +1602,110 @@ SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms,
1602 } 1602 }
1603 return rc; 1603 return rc;
1604} 1604}
1605
1606static int
1607send_set_info(const unsigned int xid, struct cifs_tcon *tcon,
1608 u64 persistent_fid, u64 volatile_fid, int info_class,
1609 unsigned int num, void **data, unsigned int *size)
1610{
1611 struct smb2_set_info_req *req;
1612 struct smb2_set_info_rsp *rsp = NULL;
1613 struct kvec *iov;
1614 int rc = 0;
1615 int resp_buftype;
1616 unsigned int i;
1617 struct TCP_Server_Info *server;
1618 struct cifs_ses *ses = tcon->ses;
1619
1620 if (ses && (ses->server))
1621 server = ses->server;
1622 else
1623 return -EIO;
1624
1625 if (!num)
1626 return -EINVAL;
1627
1628 iov = kmalloc(sizeof(struct kvec) * num, GFP_KERNEL);
1629 if (!iov)
1630 return -ENOMEM;
1631
1632 rc = small_smb2_init(SMB2_SET_INFO, tcon, (void **) &req);
1633 if (rc) {
1634 kfree(iov);
1635 return rc;
1636 }
1637
1638 req->InfoType = SMB2_O_INFO_FILE;
1639 req->FileInfoClass = info_class;
1640 req->PersistentFileId = persistent_fid;
1641 req->VolatileFileId = volatile_fid;
1642
1643 /* 4 for RFC1001 length and 1 for Buffer */
1644 req->BufferOffset =
1645 cpu_to_le16(sizeof(struct smb2_set_info_req) - 1 - 4);
1646 req->BufferLength = cpu_to_le32(*size);
1647
1648 inc_rfc1001_len(req, *size - 1 /* Buffer */);
1649
1650 memcpy(req->Buffer, *data, *size);
1651
1652 iov[0].iov_base = (char *)req;
1653 /* 4 for RFC1001 length */
1654 iov[0].iov_len = get_rfc1002_length(req) + 4;
1655
1656 for (i = 1; i < num; i++) {
1657 inc_rfc1001_len(req, size[i]);
1658 le32_add_cpu(&req->BufferLength, size[i]);
1659 iov[i].iov_base = (char *)data[i];
1660 iov[i].iov_len = size[i];
1661 }
1662
1663 rc = SendReceive2(xid, ses, iov, num, &resp_buftype, 0);
1664 rsp = (struct smb2_set_info_rsp *)iov[0].iov_base;
1665
1666 if (rc != 0) {
1667 cifs_stats_fail_inc(tcon, SMB2_SET_INFO_HE);
1668 goto out;
1669 }
1670
1671 if (rsp == NULL) {
1672 rc = -EIO;
1673 goto out;
1674 }
1675
1676out:
1677 free_rsp_buf(resp_buftype, rsp);
1678 kfree(iov);
1679 return rc;
1680}
1681
1682int
1683SMB2_rename(const unsigned int xid, struct cifs_tcon *tcon,
1684 u64 persistent_fid, u64 volatile_fid, __le16 *target_file)
1685{
1686 struct smb2_file_rename_info info;
1687 void **data;
1688 unsigned int size[2];
1689 int rc;
1690 int len = (2 * UniStrnlen((wchar_t *)target_file, PATH_MAX));
1691
1692 data = kmalloc(sizeof(void *) * 2, GFP_KERNEL);
1693 if (!data)
1694 return -ENOMEM;
1695
1696 info.ReplaceIfExists = 1; /* 1 = replace existing target with new */
1697 /* 0 = fail if target already exists */
1698 info.RootDirectory = 0; /* MBZ for network ops (why does spec say?) */
1699 info.FileNameLength = cpu_to_le32(len);
1700
1701 data[0] = &info;
1702 size[0] = sizeof(struct smb2_file_rename_info);
1703
1704 data[1] = target_file;
1705 size[1] = len + 2 /* null */;
1706
1707 rc = send_set_info(xid, tcon, persistent_fid, volatile_fid,
1708 FILE_RENAME_INFORMATION, 2, data, size);
1709 kfree(data);
1710 return rc;
1711}
diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h
index 21ec9ed280f9..b03ca37d0d58 100644
--- a/fs/cifs/smb2pdu.h
+++ b/fs/cifs/smb2pdu.h
@@ -568,6 +568,25 @@ struct smb2_query_info_rsp {
568 __u8 Buffer[1]; 568 __u8 Buffer[1];
569} __packed; 569} __packed;
570 570
571struct smb2_set_info_req {
572 struct smb2_hdr hdr;
573 __le16 StructureSize; /* Must be 33 */
574 __u8 InfoType;
575 __u8 FileInfoClass;
576 __le32 BufferLength;
577 __le16 BufferOffset;
578 __u16 Reserved;
579 __le32 AdditionalInformation;
580 __u64 PersistentFileId; /* opaque endianness */
581 __u64 VolatileFileId; /* opaque endianness */
582 __u8 Buffer[1];
583} __packed;
584
585struct smb2_set_info_rsp {
586 struct smb2_hdr hdr;
587 __le16 StructureSize; /* Must be 2 */
588} __packed;
589
571/* 590/*
572 * PDU infolevel structure definitions 591 * PDU infolevel structure definitions
573 * BB consider moving to a different header 592 * BB consider moving to a different header
@@ -625,6 +644,15 @@ struct smb2_file_internal_info {
625 __le64 IndexNumber; 644 __le64 IndexNumber;
626} __packed; /* level 6 Query */ 645} __packed; /* level 6 Query */
627 646
647struct smb2_file_rename_info { /* encoding of request for level 10 */
648 __u8 ReplaceIfExists; /* 1 = replace existing target with new */
649 /* 0 = fail if target already exists */
650 __u8 Reserved[7];
651 __u64 RootDirectory; /* MBZ for network operations (why says spec?) */
652 __le32 FileNameLength;
653 char FileName[0]; /* New name to be assigned */
654} __packed; /* level 10 Set */
655
628/* 656/*
629 * This level 18, although with struct with same name is different from cifs 657 * This level 18, although with struct with same name is different from cifs
630 * level 0x107. Level 0x107 has an extra u64 between AccessFlags and 658 * level 0x107. Level 0x107 has an extra u64 between AccessFlags and
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index dbbdc39fa209..b43036e8ad2a 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -65,6 +65,9 @@ extern int smb2_rmdir(const unsigned int xid, struct cifs_tcon *tcon,
65 const char *name, struct cifs_sb_info *cifs_sb); 65 const char *name, struct cifs_sb_info *cifs_sb);
66extern int smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon, 66extern int smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon,
67 const char *name, struct cifs_sb_info *cifs_sb); 67 const char *name, struct cifs_sb_info *cifs_sb);
68extern int smb2_rename_path(const unsigned int xid, struct cifs_tcon *tcon,
69 const char *from_name, const char *to_name,
70 struct cifs_sb_info *cifs_sb);
68 71
69extern int smb2_open_file(const unsigned int xid, struct cifs_tcon *tcon, 72extern int smb2_open_file(const unsigned int xid, struct cifs_tcon *tcon,
70 const char *full_path, int disposition, 73 const char *full_path, int disposition,
@@ -106,5 +109,8 @@ extern int smb2_async_writev(struct cifs_writedata *wdata);
106extern int SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms, 109extern int SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms,
107 unsigned int *nbytes, struct kvec *iov, int n_vec); 110 unsigned int *nbytes, struct kvec *iov, int n_vec);
108extern int SMB2_echo(struct TCP_Server_Info *server); 111extern int SMB2_echo(struct TCP_Server_Info *server);
112extern int SMB2_rename(const unsigned int xid, struct cifs_tcon *tcon,
113 u64 persistent_fid, u64 volatile_fid,
114 __le16 *target_file);
109 115
110#endif /* _SMB2PROTO_H */ 116#endif /* _SMB2PROTO_H */