diff options
author | Pavel Shilovsky <pshilovsky@samba.org> | 2012-09-18 19:20:31 -0400 |
---|---|---|
committer | Steve French <smfrench@gmail.com> | 2012-09-24 22:46:29 -0400 |
commit | 35143eb5c2e3ae6c91b29144449d23f05f573796 (patch) | |
tree | c022f223815788cad6dbc9156f9d47edefc5f81d /fs | |
parent | 8ceb984379462f94bdebef3288d569c6e1f912ea (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.c | 25 | ||||
-rw-r--r-- | fs/cifs/smb2ops.c | 1 | ||||
-rw-r--r-- | fs/cifs/smb2pdu.c | 107 | ||||
-rw-r--r-- | fs/cifs/smb2pdu.h | 28 | ||||
-rw-r--r-- | fs/cifs/smb2proto.h | 6 |
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 | |||
178 | int | ||
179 | smb2_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); | ||
194 | smb2_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 | |||
1606 | static int | ||
1607 | send_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 | |||
1676 | out: | ||
1677 | free_rsp_buf(resp_buftype, rsp); | ||
1678 | kfree(iov); | ||
1679 | return rc; | ||
1680 | } | ||
1681 | |||
1682 | int | ||
1683 | SMB2_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 | ||
571 | struct 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 | |||
585 | struct 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 | ||
647 | struct 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); |
66 | extern int smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon, | 66 | extern 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); |
68 | extern 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 | ||
69 | extern int smb2_open_file(const unsigned int xid, struct cifs_tcon *tcon, | 72 | extern 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); | |||
106 | extern int SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms, | 109 | extern 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); |
108 | extern int SMB2_echo(struct TCP_Server_Info *server); | 111 | extern int SMB2_echo(struct TCP_Server_Info *server); |
112 | extern 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 */ |