aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs
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
commit568798cc6211553e2494a6876fa19d064c822e79 (patch)
treefa73b97cac75ae54a08a5e0dfc26c2120243a412 /fs/cifs
parentd6e906f1b571d15ff5778a049802f6ef6f70159a (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.h1
-rw-r--r--fs/cifs/smb2inode.c34
-rw-r--r--fs/cifs/smb2ops.c1
-rw-r--r--fs/cifs/smb2pdu.c31
-rw-r--r--fs/cifs/smb2pdu.h9
-rw-r--r--fs/cifs/smb2proto.h6
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
178int 182static int
179smb2_rename_path(const unsigned int xid, struct cifs_tcon *tcon, 183smb2_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);
194smb2_rename_path: 198smb2_rename_path:
195 kfree(smb2_to_name); 199 kfree(smb2_to_name);
196 return rc; 200 return rc;
197} 201}
202
203int
204smb2_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
212int
213smb2_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
1713int
1714SMB2_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
656struct 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,
68extern int smb2_rename_path(const unsigned int xid, struct cifs_tcon *tcon, 68extern 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);
71extern 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
72extern int smb2_open_file(const unsigned int xid, struct cifs_tcon *tcon, 75extern 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);
112extern int SMB2_rename(const unsigned int xid, struct cifs_tcon *tcon, 115extern 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);
118extern 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 */