posix_acl: fix reference leaks in posix_acl_create
[firefly-linux-kernel-4.4.55.git] / fs / cifs / link.c
index 5657416d3483fd9dea39601e61e5c64e08ec3894..2ec6037f61c758e11f7e1238e0e3c17c9a65af12 100644 (file)
 #include "cifsproto.h"
 #include "cifs_debug.h"
 #include "cifs_fs_sb.h"
+#include "cifs_unicode.h"
+#ifdef CONFIG_CIFS_SMB2
+#include "smb2proto.h"
+#endif
 
 /*
  * M-F Symlink Functions - Begin
@@ -400,6 +404,134 @@ cifs_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
        return rc;
 }
 
+/*
+ * SMB 2.1/SMB3 Protocol specific functions
+ */
+#ifdef CONFIG_CIFS_SMB2
+int
+smb3_query_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
+                     struct cifs_sb_info *cifs_sb, const unsigned char *path,
+                     char *pbuf, unsigned int *pbytes_read)
+{
+       int rc;
+       struct cifs_fid fid;
+       struct cifs_open_parms oparms;
+       struct cifs_io_parms io_parms;
+       int buf_type = CIFS_NO_BUFFER;
+       __le16 *utf16_path;
+       __u8 oplock = SMB2_OPLOCK_LEVEL_II;
+       struct smb2_file_all_info *pfile_info = NULL;
+
+       oparms.tcon = tcon;
+       oparms.cifs_sb = cifs_sb;
+       oparms.desired_access = GENERIC_READ;
+       oparms.create_options = CREATE_NOT_DIR;
+       if (backup_cred(cifs_sb))
+               oparms.create_options |= CREATE_OPEN_BACKUP_INTENT;
+       oparms.disposition = FILE_OPEN;
+       oparms.fid = &fid;
+       oparms.reconnect = false;
+
+       utf16_path = cifs_convert_path_to_utf16(path, cifs_sb);
+       if (utf16_path == NULL)
+               return -ENOMEM;
+
+       pfile_info = kzalloc(sizeof(struct smb2_file_all_info) + PATH_MAX * 2,
+                            GFP_KERNEL);
+
+       if (pfile_info == NULL) {
+               kfree(utf16_path);
+               return  -ENOMEM;
+       }
+
+       rc = SMB2_open(xid, &oparms, utf16_path, &oplock, pfile_info, NULL);
+       if (rc)
+               goto qmf_out_open_fail;
+
+       if (pfile_info->EndOfFile != cpu_to_le64(CIFS_MF_SYMLINK_FILE_SIZE)) {
+               /* it's not a symlink */
+               rc = -ENOENT; /* Is there a better rc to return? */
+               goto qmf_out;
+       }
+
+       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;
+       rc = SMB2_read(xid, &io_parms, pbytes_read, &pbuf, &buf_type);
+qmf_out:
+       SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
+qmf_out_open_fail:
+       kfree(utf16_path);
+       kfree(pfile_info);
+       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;
+}
+#endif /* CONFIG_CIFS_SMB2 */
+
 /*
  * M-F Symlink Functions - End
  */
@@ -435,8 +567,7 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode,
        if (tcon->unix_ext)
                rc = CIFSUnixCreateHardLink(xid, tcon, from_name, to_name,
                                            cifs_sb->local_nls,
-                                           cifs_sb->mnt_cifs_flags &
-                                               CIFS_MOUNT_MAP_SPECIAL_CHR);
+                                           cifs_remap(cifs_sb));
        else {
                server = tcon->ses->server;
                if (!server->ops->create_hardlink) {
@@ -461,11 +592,7 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode,
                        spin_lock(&old_file->d_inode->i_lock);
                        inc_nlink(old_file->d_inode);
                        spin_unlock(&old_file->d_inode->i_lock);
-                       /*
-                        * BB should we make this contingent on superblock flag
-                        * NOATIME?
-                        */
-                       /* old_file->d_inode->i_ctime = CURRENT_TIME; */
+
                        /*
                         * parent dir timestamps will update from srv within a
                         * second, would it really be worth it to set the parent
@@ -475,7 +602,9 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode,
                }
                /*
                 * if not oplocked will force revalidate to get info on source
-                * file from srv
+                * file from srv.  Note Samba server prior to 4.2 has bug -
+                * not updating src file ctime on hardlinks but Windows servers
+                * handle it properly
                 */
                cifsInode->time = 0;