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; }
static int smb2_open_op_close(const unsigned int xid, struct cifs_tcon *tcon, struct cifs_sb_info *cifs_sb, const char *full_path, __u32 desired_access, __u32 create_disposition, __u32 file_attributes, __u32 create_options, void *data, int command) { int rc, tmprc = 0; u64 persistent_fid, volatile_fid; __le16 *utf16_path; utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb); if (!utf16_path) return -ENOMEM; rc = SMB2_open(xid, tcon, utf16_path, &persistent_fid, &volatile_fid, desired_access, create_disposition, file_attributes, create_options); if (rc) { kfree(utf16_path); return rc; } switch (command) { case SMB2_OP_DELETE: break; case SMB2_OP_QUERY_INFO: tmprc = SMB2_query_info(xid, tcon, persistent_fid, volatile_fid, (struct smb2_file_all_info *)data); break; case SMB2_OP_MKDIR: /* * Directories are created through parameters in the * SMB2_open() call. */ break; default: cERROR(1, "Invalid command"); break; } rc = SMB2_close(xid, tcon, persistent_fid, volatile_fid); if (tmprc) rc = tmprc; kfree(utf16_path); return rc; }
static int smb2_set_path_attr(const unsigned int xid, struct cifs_tcon *tcon, const char *from_name, const char *to_name, struct cifs_sb_info *cifs_sb, __u32 access, int command) { __le16 *smb2_to_name = NULL; int rc; smb2_to_name = cifs_convert_path_to_utf16(to_name, cifs_sb); if (smb2_to_name == NULL) { rc = -ENOMEM; goto smb2_rename_path; } rc = smb2_open_op_close(xid, tcon, cifs_sb, from_name, access, FILE_OPEN, 0, smb2_to_name, command); smb2_rename_path: kfree(smb2_to_name); return rc; }
static long cifs_ioctl_query_info(unsigned int xid, struct file *filep, unsigned long p) { struct inode *inode = file_inode(filep); struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb); struct dentry *dentry = filep->f_path.dentry; unsigned char *path; __le16 *utf16_path = NULL, root_path; int rc = 0; path = build_path_from_dentry(dentry); if (path == NULL) return -ENOMEM; cifs_dbg(FYI, "%s %s\n", __func__, path); if (!path[0]) { root_path = 0; utf16_path = &root_path; } else { utf16_path = cifs_convert_path_to_utf16(path + 1, cifs_sb); if (!utf16_path) { rc = -ENOMEM; goto ici_exit; } } if (tcon->ses->server->ops->ioctl_query_info) rc = tcon->ses->server->ops->ioctl_query_info( xid, tcon, utf16_path, filep->private_data ? 0 : 1, p); else rc = -EOPNOTSUPP; ici_exit: if (utf16_path != &root_path) kfree(utf16_path); kfree(path); return rc; }
static int smb2_open_op_close(const unsigned int xid, struct cifs_tcon *tcon, struct cifs_sb_info *cifs_sb, const char *full_path, __u32 desired_access, __u32 create_disposition, __u32 create_options, void *data, int command) { int rc, tmprc = 0; __le16 *utf16_path; __u8 oplock = SMB2_OPLOCK_LEVEL_NONE; struct cifs_open_parms oparms; struct cifs_fid fid; utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb); if (!utf16_path) return -ENOMEM; oparms.tcon = tcon; oparms.desired_access = desired_access; oparms.share_access = FILE_SHARE_ALL; oparms.disposition = create_disposition; oparms.create_options = create_options; oparms.fid = &fid; oparms.reconnect = false; rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL); if (rc) { kfree(utf16_path); return rc; } switch (command) { case SMB2_OP_DELETE: break; case SMB2_OP_QUERY_INFO: tmprc = SMB2_query_info(xid, tcon, fid.persistent_fid, fid.volatile_fid, (struct smb2_file_all_info *)data); break; case SMB2_OP_MKDIR: /* * Directories are created through parameters in the * SMB2_open() call. */ break; case SMB2_OP_RENAME: tmprc = SMB2_rename(xid, tcon, fid.persistent_fid, fid.volatile_fid, (__le16 *)data); break; case SMB2_OP_HARDLINK: tmprc = SMB2_set_hardlink(xid, tcon, fid.persistent_fid, fid.volatile_fid, (__le16 *)data); break; case SMB2_OP_SET_EOF: tmprc = SMB2_set_eof(xid, tcon, fid.persistent_fid, fid.volatile_fid, current->tgid, (__le64 *)data, false); break; case SMB2_OP_SET_INFO: tmprc = SMB2_set_info(xid, tcon, fid.persistent_fid, fid.volatile_fid, (FILE_BASIC_INFO *)data); break; default: cifs_dbg(VFS, "Invalid command\n"); break; } rc = SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid); if (tmprc) rc = tmprc; kfree(utf16_path); return rc; }
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; }