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 | 568798cc6211553e2494a6876fa19d064c822e79 (patch) | |
tree | fa73b97cac75ae54a08a5e0dfc26c2120243a412 /fs/cifs | |
parent | d6e906f1b571d15ff5778a049802f6ef6f70159a (diff) |
CIFS: Add SMB2 support for hardlink operation
Signed-off-by: Pavel Shilovsky <pshilovsky@samba.org>
Signed-off-by: Steve French <smfrench@gmail.com>
Diffstat (limited to 'fs/cifs')
-rw-r--r-- | fs/cifs/smb2glob.h | 1 | ||||
-rw-r--r-- | fs/cifs/smb2inode.c | 34 | ||||
-rw-r--r-- | fs/cifs/smb2ops.c | 1 | ||||
-rw-r--r-- | fs/cifs/smb2pdu.c | 31 | ||||
-rw-r--r-- | fs/cifs/smb2pdu.h | 9 | ||||
-rw-r--r-- | fs/cifs/smb2proto.h | 6 |
6 files changed, 76 insertions, 6 deletions
diff --git a/fs/cifs/smb2glob.h b/fs/cifs/smb2glob.h index 8635574ea8b6..21555d8744fd 100644 --- a/fs/cifs/smb2glob.h +++ b/fs/cifs/smb2glob.h | |||
@@ -40,6 +40,7 @@ | |||
40 | #define SMB2_OP_MKDIR 5 | 40 | #define SMB2_OP_MKDIR 5 |
41 | #define SMB2_OP_RENAME 6 | 41 | #define SMB2_OP_RENAME 6 |
42 | #define SMB2_OP_DELETE 7 | 42 | #define SMB2_OP_DELETE 7 |
43 | #define SMB2_OP_HARDLINK 8 | ||
43 | 44 | ||
44 | /* Used when constructing chained read requests. */ | 45 | /* Used when constructing chained read requests. */ |
45 | #define CHAINED_REQUEST 1 | 46 | #define CHAINED_REQUEST 1 |
diff --git a/fs/cifs/smb2inode.c b/fs/cifs/smb2inode.c index a6952bafe331..1921c9c87ccd 100644 --- a/fs/cifs/smb2inode.c +++ b/fs/cifs/smb2inode.c | |||
@@ -78,6 +78,10 @@ smb2_open_op_close(const unsigned int xid, struct cifs_tcon *tcon, | |||
78 | tmprc = SMB2_rename(xid, tcon, persistent_fid, volatile_fid, | 78 | tmprc = SMB2_rename(xid, tcon, persistent_fid, volatile_fid, |
79 | (__le16 *)data); | 79 | (__le16 *)data); |
80 | break; | 80 | break; |
81 | case SMB2_OP_HARDLINK: | ||
82 | tmprc = SMB2_set_hardlink(xid, tcon, persistent_fid, | ||
83 | volatile_fid, (__le16 *)data); | ||
84 | break; | ||
81 | default: | 85 | default: |
82 | cERROR(1, "Invalid command"); | 86 | cERROR(1, "Invalid command"); |
83 | break; | 87 | break; |
@@ -175,10 +179,10 @@ smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon, const char *name, | |||
175 | SMB2_OP_DELETE); | 179 | SMB2_OP_DELETE); |
176 | } | 180 | } |
177 | 181 | ||
178 | int | 182 | static int |
179 | smb2_rename_path(const unsigned int xid, struct cifs_tcon *tcon, | 183 | smb2_set_path_attr(const unsigned int xid, struct cifs_tcon *tcon, |
180 | const char *from_name, const char *to_name, | 184 | const char *from_name, const char *to_name, |
181 | struct cifs_sb_info *cifs_sb) | 185 | struct cifs_sb_info *cifs_sb, __u32 access, int command) |
182 | { | 186 | { |
183 | __le16 *smb2_to_name = NULL; | 187 | __le16 *smb2_to_name = NULL; |
184 | int rc; | 188 | int rc; |
@@ -189,9 +193,27 @@ smb2_rename_path(const unsigned int xid, struct cifs_tcon *tcon, | |||
189 | goto smb2_rename_path; | 193 | goto smb2_rename_path; |
190 | } | 194 | } |
191 | 195 | ||
192 | rc = smb2_open_op_close(xid, tcon, cifs_sb, from_name, DELETE, | 196 | rc = smb2_open_op_close(xid, tcon, cifs_sb, from_name, access, |
193 | FILE_OPEN, 0, 0, smb2_to_name, SMB2_OP_RENAME); | 197 | FILE_OPEN, 0, 0, smb2_to_name, command); |
194 | smb2_rename_path: | 198 | smb2_rename_path: |
195 | kfree(smb2_to_name); | 199 | kfree(smb2_to_name); |
196 | return rc; | 200 | return rc; |
197 | } | 201 | } |
202 | |||
203 | int | ||
204 | smb2_rename_path(const unsigned int xid, struct cifs_tcon *tcon, | ||
205 | const char *from_name, const char *to_name, | ||
206 | struct cifs_sb_info *cifs_sb) | ||
207 | { | ||
208 | return smb2_set_path_attr(xid, tcon, from_name, to_name, cifs_sb, | ||
209 | DELETE, SMB2_OP_RENAME); | ||
210 | } | ||
211 | |||
212 | int | ||
213 | smb2_create_hardlink(const unsigned int xid, struct cifs_tcon *tcon, | ||
214 | const char *from_name, const char *to_name, | ||
215 | struct cifs_sb_info *cifs_sb) | ||
216 | { | ||
217 | return smb2_set_path_attr(xid, tcon, from_name, to_name, cifs_sb, | ||
218 | FILE_READ_ATTRIBUTES, SMB2_OP_HARDLINK); | ||
219 | } | ||
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index 5aaccb0f3aae..75693e983e76 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c | |||
@@ -452,6 +452,7 @@ struct smb_version_operations smb21_operations = { | |||
452 | .rmdir = smb2_rmdir, | 452 | .rmdir = smb2_rmdir, |
453 | .unlink = smb2_unlink, | 453 | .unlink = smb2_unlink, |
454 | .rename = smb2_rename_path, | 454 | .rename = smb2_rename_path, |
455 | .create_hardlink = smb2_create_hardlink, | ||
455 | .open = smb2_open_file, | 456 | .open = smb2_open_file, |
456 | .set_fid = smb2_set_fid, | 457 | .set_fid = smb2_set_fid, |
457 | .close = smb2_close_file, | 458 | .close = smb2_close_file, |
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index 1dc11ce7934e..a684c4ab42d6 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c | |||
@@ -1709,3 +1709,34 @@ SMB2_rename(const unsigned int xid, struct cifs_tcon *tcon, | |||
1709 | kfree(data); | 1709 | kfree(data); |
1710 | return rc; | 1710 | return rc; |
1711 | } | 1711 | } |
1712 | |||
1713 | int | ||
1714 | SMB2_set_hardlink(const unsigned int xid, struct cifs_tcon *tcon, | ||
1715 | u64 persistent_fid, u64 volatile_fid, __le16 *target_file) | ||
1716 | { | ||
1717 | struct smb2_file_link_info info; | ||
1718 | void **data; | ||
1719 | unsigned int size[2]; | ||
1720 | int rc; | ||
1721 | int len = (2 * UniStrnlen((wchar_t *)target_file, PATH_MAX)); | ||
1722 | |||
1723 | data = kmalloc(sizeof(void *) * 2, GFP_KERNEL); | ||
1724 | if (!data) | ||
1725 | return -ENOMEM; | ||
1726 | |||
1727 | info.ReplaceIfExists = 0; /* 1 = replace existing link with new */ | ||
1728 | /* 0 = fail if link already exists */ | ||
1729 | info.RootDirectory = 0; /* MBZ for network ops (why does spec say?) */ | ||
1730 | info.FileNameLength = cpu_to_le32(len); | ||
1731 | |||
1732 | data[0] = &info; | ||
1733 | size[0] = sizeof(struct smb2_file_link_info); | ||
1734 | |||
1735 | data[1] = target_file; | ||
1736 | size[1] = len + 2 /* null */; | ||
1737 | |||
1738 | rc = send_set_info(xid, tcon, persistent_fid, volatile_fid, | ||
1739 | FILE_LINK_INFORMATION, 2, data, size); | ||
1740 | kfree(data); | ||
1741 | return rc; | ||
1742 | } | ||
diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h index b03ca37d0d58..0f3c4828cd00 100644 --- a/fs/cifs/smb2pdu.h +++ b/fs/cifs/smb2pdu.h | |||
@@ -653,6 +653,15 @@ struct smb2_file_rename_info { /* encoding of request for level 10 */ | |||
653 | char FileName[0]; /* New name to be assigned */ | 653 | char FileName[0]; /* New name to be assigned */ |
654 | } __packed; /* level 10 Set */ | 654 | } __packed; /* level 10 Set */ |
655 | 655 | ||
656 | struct smb2_file_link_info { /* encoding of request for level 11 */ | ||
657 | __u8 ReplaceIfExists; /* 1 = replace existing link with new */ | ||
658 | /* 0 = fail if link already exists */ | ||
659 | __u8 Reserved[7]; | ||
660 | __u64 RootDirectory; /* MBZ for network operations (why says spec?) */ | ||
661 | __le32 FileNameLength; | ||
662 | char FileName[0]; /* Name to be assigned to new link */ | ||
663 | } __packed; /* level 11 Set */ | ||
664 | |||
656 | /* | 665 | /* |
657 | * This level 18, although with struct with same name is different from cifs | 666 | * This level 18, although with struct with same name is different from cifs |
658 | * level 0x107. Level 0x107 has an extra u64 between AccessFlags and | 667 | * level 0x107. Level 0x107 has an extra u64 between AccessFlags and |
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h index b43036e8ad2a..99f6945c8643 100644 --- a/fs/cifs/smb2proto.h +++ b/fs/cifs/smb2proto.h | |||
@@ -68,6 +68,9 @@ extern int smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon, | |||
68 | extern int smb2_rename_path(const unsigned int xid, struct cifs_tcon *tcon, | 68 | extern int smb2_rename_path(const unsigned int xid, struct cifs_tcon *tcon, |
69 | const char *from_name, const char *to_name, | 69 | const char *from_name, const char *to_name, |
70 | struct cifs_sb_info *cifs_sb); | 70 | struct cifs_sb_info *cifs_sb); |
71 | extern int smb2_create_hardlink(const unsigned int xid, struct cifs_tcon *tcon, | ||
72 | const char *from_name, const char *to_name, | ||
73 | struct cifs_sb_info *cifs_sb); | ||
71 | 74 | ||
72 | extern int smb2_open_file(const unsigned int xid, struct cifs_tcon *tcon, | 75 | extern int smb2_open_file(const unsigned int xid, struct cifs_tcon *tcon, |
73 | const char *full_path, int disposition, | 76 | const char *full_path, int disposition, |
@@ -112,5 +115,8 @@ extern int SMB2_echo(struct TCP_Server_Info *server); | |||
112 | extern int SMB2_rename(const unsigned int xid, struct cifs_tcon *tcon, | 115 | extern int SMB2_rename(const unsigned int xid, struct cifs_tcon *tcon, |
113 | u64 persistent_fid, u64 volatile_fid, | 116 | u64 persistent_fid, u64 volatile_fid, |
114 | __le16 *target_file); | 117 | __le16 *target_file); |
118 | extern int SMB2_set_hardlink(const unsigned int xid, struct cifs_tcon *tcon, | ||
119 | u64 persistent_fid, u64 volatile_fid, | ||
120 | __le16 *target_file); | ||
115 | 121 | ||
116 | #endif /* _SMB2PROTO_H */ | 122 | #endif /* _SMB2PROTO_H */ |