diff options
Diffstat (limited to 'fs/smb/client/link.c')
| -rw-r--r-- | fs/smb/client/link.c | 125 |
1 files changed, 62 insertions, 63 deletions
diff --git a/fs/smb/client/link.c b/fs/smb/client/link.c index c66be4904e1f..fdfdc9a3abdd 100644 --- a/fs/smb/client/link.c +++ b/fs/smb/client/link.c @@ -5,6 +5,7 @@ * Author(s): Steve French (sfrench@us.ibm.com) * */ +#include <crypto/md5.h> #include <linux/fs.h> #include <linux/stat.h> #include <linux/slab.h> @@ -18,6 +19,8 @@ #include "cifs_unicode.h" #include "smb2proto.h" #include "cifs_ioctl.h" +#include "fs_context.h" +#include "reparse.h" /* * M-F Symlink Functions - Begin @@ -35,35 +38,6 @@ #define CIFS_MF_SYMLINK_MD5_ARGS(md5_hash) md5_hash static int -symlink_hash(unsigned int link_len, const char *link_str, u8 *md5_hash) -{ - int rc; - struct shash_desc *md5 = NULL; - - rc = cifs_alloc_hash("md5", &md5); - if (rc) - goto symlink_hash_err; - - rc = crypto_shash_init(md5); - if (rc) { - cifs_dbg(VFS, "%s: Could not init md5 shash\n", __func__); - goto symlink_hash_err; - } - rc = crypto_shash_update(md5, link_str, link_len); - if (rc) { - cifs_dbg(VFS, "%s: Could not update with link_str\n", __func__); - goto symlink_hash_err; - } - rc = crypto_shash_final(md5, md5_hash); - if (rc) - cifs_dbg(VFS, "%s: Could not generate md5 hash\n", __func__); - -symlink_hash_err: - cifs_free_hash(&md5); - return rc; -} - -static int parse_mf_symlink(const u8 *buf, unsigned int buf_len, unsigned int *_link_len, char **_link_str) { @@ -87,11 +61,7 @@ parse_mf_symlink(const u8 *buf, unsigned int buf_len, unsigned int *_link_len, if (link_len > CIFS_MF_SYMLINK_LINK_MAXLEN) return -EINVAL; - rc = symlink_hash(link_len, link_str, md5_hash); - if (rc) { - cifs_dbg(FYI, "%s: MD5 hash failure: %d\n", __func__, rc); - return rc; - } + md5(link_str, link_len, md5_hash); scnprintf(md5_str2, sizeof(md5_str2), CIFS_MF_SYMLINK_MD5_FORMAT, @@ -113,7 +83,6 @@ parse_mf_symlink(const u8 *buf, unsigned int buf_len, unsigned int *_link_len, static int format_mf_symlink(u8 *buf, unsigned int buf_len, const char *link_str) { - int rc; unsigned int link_len; unsigned int ofs; u8 md5_hash[16]; @@ -126,11 +95,7 @@ format_mf_symlink(u8 *buf, unsigned int buf_len, const char *link_str) if (link_len > CIFS_MF_SYMLINK_LINK_MAXLEN) return -ENAMETOOLONG; - rc = symlink_hash(link_len, link_str, md5_hash); - if (rc) { - cifs_dbg(FYI, "%s: MD5 hash failure: %d\n", __func__, rc); - return rc; - } + md5(link_str, link_len, md5_hash); scnprintf(buf, buf_len, CIFS_MF_SYMLINK_LEN_FORMAT CIFS_MF_SYMLINK_MD5_FORMAT, @@ -195,7 +160,8 @@ create_mf_symlink(const unsigned int xid, struct cifs_tcon *tcon, goto out; if (bytes_written != CIFS_MF_SYMLINK_FILE_SIZE) - rc = -EIO; + rc = smb_EIO2(smb_eio_trace_symlink_file_size, + bytes_written, CIFS_MF_SYMLINK_FILE_SIZE); out: kfree(buf); return rc; @@ -269,7 +235,7 @@ cifs_query_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, struct cifs_open_parms oparms; struct cifs_io_parms io_parms = {0}; int buf_type = CIFS_NO_BUFFER; - FILE_ALL_INFO file_info; + struct cifs_open_info_data query_data; oparms = (struct cifs_open_parms) { .tcon = tcon, @@ -281,11 +247,11 @@ cifs_query_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, .fid = &fid, }; - rc = CIFS_open(xid, &oparms, &oplock, &file_info); + rc = tcon->ses->server->ops->open(xid, &oparms, &oplock, &query_data); if (rc) return rc; - if (file_info.EndOfFile != cpu_to_le64(CIFS_MF_SYMLINK_FILE_SIZE)) { + if (query_data.fi.EndOfFile != cpu_to_le64(CIFS_MF_SYMLINK_FILE_SIZE)) { rc = -ENOENT; /* it's not a symlink */ goto out; @@ -324,7 +290,7 @@ cifs_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, .fid = &fid, }; - rc = CIFS_open(xid, &oparms, &oplock, NULL); + rc = tcon->ses->server->ops->open(xid, &oparms, &oplock, NULL); if (rc) return rc; @@ -459,7 +425,8 @@ smb3_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, /* Make sure we wrote all of the symlink data */ if ((rc == 0) && (*pbytes_written != CIFS_MF_SYMLINK_FILE_SIZE)) - rc = -EIO; + rc = smb_EIO2(smb_eio_trace_short_symlink_write, + *pbytes_written, CIFS_MF_SYMLINK_FILE_SIZE); SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid); @@ -486,7 +453,7 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode, struct cifsInodeInfo *cifsInode; if (unlikely(cifs_forced_shutdown(cifs_sb))) - return -EIO; + return smb_EIO(smb_eio_trace_forced_shutdown); tlink = cifs_sb_tlink(cifs_sb); if (IS_ERR(tlink)) @@ -522,8 +489,8 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode, rc = -ENOSYS; goto cifs_hl_exit; } - rc = server->ops->create_hardlink(xid, tcon, from_name, to_name, - cifs_sb); + rc = server->ops->create_hardlink(xid, tcon, old_file, + from_name, to_name, cifs_sb); if ((rc == -EIO) || (rc == -EINVAL)) rc = -EOPNOTSUPP; } @@ -588,7 +555,7 @@ cifs_symlink(struct mnt_idmap *idmap, struct inode *inode, struct inode *newinode = NULL; if (unlikely(cifs_forced_shutdown(cifs_sb))) - return -EIO; + return smb_EIO(smb_eio_trace_forced_shutdown); page = alloc_dentry_path(); if (!page) @@ -599,6 +566,7 @@ cifs_symlink(struct mnt_idmap *idmap, struct inode *inode, tlink = cifs_sb_tlink(cifs_sb); if (IS_ERR(tlink)) { rc = PTR_ERR(tlink); + /* BB could be clearer if skipped put_tlink on error here, but harmless */ goto symlink_exit; } pTcon = tlink_tcon(tlink); @@ -613,27 +581,58 @@ cifs_symlink(struct mnt_idmap *idmap, struct inode *inode, cifs_dbg(FYI, "symname is %s\n", symname); /* BB what if DFS and this volume is on different share? BB */ - if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) - rc = create_mf_symlink(xid, pTcon, cifs_sb, full_path, symname); + rc = -EOPNOTSUPP; + switch (cifs_symlink_type(cifs_sb)) { + case CIFS_SYMLINK_TYPE_UNIX: #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY - else if (pTcon->unix_ext) - rc = CIFSUnixCreateSymLink(xid, pTcon, full_path, symname, - cifs_sb->local_nls, - cifs_remap(cifs_sb)); + if (pTcon->unix_ext) { + rc = CIFSUnixCreateSymLink(xid, pTcon, full_path, + symname, + cifs_sb->local_nls, + cifs_remap(cifs_sb)); + } #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ - /* else - rc = CIFSCreateReparseSymLink(xid, pTcon, fromName, toName, - cifs_sb_target->local_nls); */ + break; + + case CIFS_SYMLINK_TYPE_MFSYMLINKS: + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) { + rc = create_mf_symlink(xid, pTcon, cifs_sb, + full_path, symname); + } + break; + + case CIFS_SYMLINK_TYPE_SFU: + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) { + rc = __cifs_sfu_make_node(xid, inode, direntry, pTcon, + full_path, S_IFLNK, + 0, symname); + } + break; + + case CIFS_SYMLINK_TYPE_NATIVE: + case CIFS_SYMLINK_TYPE_NFS: + case CIFS_SYMLINK_TYPE_WSL: + if (CIFS_REPARSE_SUPPORT(pTcon)) { + rc = create_reparse_symlink(xid, inode, direntry, pTcon, + full_path, symname); + goto symlink_exit; + } + break; + default: + break; + } if (rc == 0) { - if (pTcon->posix_extensions) - rc = smb311_posix_get_inode_info(&newinode, full_path, inode->i_sb, xid); - else if (pTcon->unix_ext) + if (pTcon->posix_extensions) { + rc = smb311_posix_get_inode_info(&newinode, full_path, + NULL, inode->i_sb, xid); + } else if (pTcon->unix_ext) { rc = cifs_get_inode_info_unix(&newinode, full_path, inode->i_sb, xid); - else + } else { rc = cifs_get_inode_info(&newinode, full_path, NULL, inode->i_sb, xid, NULL); + } if (rc != 0) { cifs_dbg(FYI, "Create symlink ok, getinodeinfo fail rc = %d\n", |
