summaryrefslogtreecommitdiffstats
path: root/fs/cifs/link.c
diff options
context:
space:
mode:
authorSteve French <smfrench@gmail.com>2014-09-15 11:49:28 +0200
committerSteve French <smfrench@gmail.com>2014-10-16 22:20:20 +0200
commit5ab97578cbb3bf9a28dec4534cb86fbc35e600bb (patch)
tree1eaf7d9abbf28446519f3a4196fa4835da9286ec /fs/cifs/link.c
parentAllow mknod and mkfifo on SMB2/SMB3 mounts (diff)
downloadlinux-5ab97578cbb3bf9a28dec4534cb86fbc35e600bb.tar.xz
linux-5ab97578cbb3bf9a28dec4534cb86fbc35e600bb.zip
Add mfsymlinks support for SMB2.1/SMB3. Part 1 create symlink
Adds support on SMB2.1 and SMB3 mounts for emulation of symlinks via the "Minshall/French" symlink format already used for cifs mounts when mfsymlinks mount option is used (and also used by Apple). http://wiki.samba.org/index.php/UNIX_Extensions#Minshall.2BFrench_symlinks This first patch adds support to create them. The next patch will add support for recognizing them and reading them. Although CIFS/SMB3 have other types of symlinks, in the many use cases they aren't practical (e.g. either require cifs only mounts with unix extensions to Samba, or require the user to be Administrator to Windows for SMB3). This also helps enable running additional xfstests over SMB3 (since some xfstests directly or indirectly require symlink support). Signed-off-by: Steve French <smfrench@gmail.com> CC: Stefan Metzmacher <metze@samba.org>
Diffstat (limited to 'fs/cifs/link.c')
-rw-r--r--fs/cifs/link.c63
1 files changed, 63 insertions, 0 deletions
diff --git a/fs/cifs/link.c b/fs/cifs/link.c
index 5657416d3483..1216f4f1c6c9 100644
--- a/fs/cifs/link.c
+++ b/fs/cifs/link.c
@@ -28,6 +28,7 @@
#include "cifsproto.h"
#include "cifs_debug.h"
#include "cifs_fs_sb.h"
+#include "smb2proto.h"
/*
* M-F Symlink Functions - Begin
@@ -400,6 +401,68 @@ cifs_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
return rc;
}
+int
+smb3_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
+ struct cifs_sb_info *cifs_sb, const unsigned char *path,
+ char *pbuf, unsigned int *pbytes_written)
+{
+ int rc;
+ struct cifs_fid fid;
+ struct cifs_open_parms oparms;
+ struct cifs_io_parms io_parms;
+ int create_options = CREATE_NOT_DIR;
+ __le16 *utf16_path;
+ __u8 oplock = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
+ struct kvec iov[2];
+
+ if (backup_cred(cifs_sb))
+ create_options |= CREATE_OPEN_BACKUP_INTENT;
+
+ cifs_dbg(FYI, "%s: path: %s\n", __func__, path);
+
+ utf16_path = cifs_convert_path_to_utf16(path, cifs_sb);
+ if (!utf16_path)
+ return -ENOMEM;
+
+ oparms.tcon = tcon;
+ oparms.cifs_sb = cifs_sb;
+ oparms.desired_access = GENERIC_WRITE;
+ oparms.create_options = create_options;
+ oparms.disposition = FILE_CREATE;
+ oparms.fid = &fid;
+ oparms.reconnect = false;
+
+ rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL);
+ if (rc) {
+ kfree(utf16_path);
+ return rc;
+ }
+
+ io_parms.netfid = fid.netfid;
+ io_parms.pid = current->tgid;
+ io_parms.tcon = tcon;
+ io_parms.offset = 0;
+ io_parms.length = CIFS_MF_SYMLINK_FILE_SIZE;
+ io_parms.persistent_fid = fid.persistent_fid;
+ io_parms.volatile_fid = fid.volatile_fid;
+
+ /* iov[0] is reserved for smb header */
+ iov[1].iov_base = pbuf;
+ iov[1].iov_len = CIFS_MF_SYMLINK_FILE_SIZE;
+
+ rc = SMB2_write(xid, &io_parms, pbytes_written, iov, 1);
+
+ /* Make sure we wrote all of the symlink data */
+ if ((rc == 0) && (*pbytes_written != CIFS_MF_SYMLINK_FILE_SIZE))
+ rc = -EIO;
+
+ SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
+
+ kfree(utf16_path);
+ return rc;
+}
+
+
/*
* M-F Symlink Functions - End
*/