return 0;
}
+static char *alloc_parent_path(struct dentry *dentry, size_t namelen)
+{
+ struct cifs_sb_info *cifs_sb = CIFS_SB(dentry);
+ void *page = alloc_dentry_path();
+ const char *path;
+ size_t size;
+ char *npath;
-/* Inode operations in similar order to how they appear in Linux file fs.h */
+ path = build_path_from_dentry(dentry->d_parent, page);
+ if (IS_ERR(path)) {
+ npath = ERR_CAST(path);
+ goto out;
+ }
+
+ size = strlen(path) + namelen + 2;
+ npath = kmalloc(size, GFP_KERNEL);
+ if (!npath)
+ npath = ERR_PTR(-ENOMEM);
+ else
+ scnprintf(npath, size, "%s%c", path, CIFS_DIR_SEP(cifs_sb));
+out:
+ free_dentry_path(page);
+ return npath;
+}
-static int cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned int xid,
- struct tcon_link *tlink, unsigned int oflags, umode_t mode, __u32 *oplock,
- struct cifs_fid *fid, struct cifs_open_info_data *buf)
+/* Inode operations in similar order to how they appear in Linux file fs.h */
+static int __cifs_do_create(struct inode *dir, struct dentry *direntry,
+ const char *full_path, unsigned int xid,
+ struct tcon_link *tlink, unsigned int oflags,
+ umode_t mode, __u32 *oplock, struct cifs_fid *fid,
+ struct cifs_open_info_data *buf,
+ struct inode **inode)
{
int rc = -ENOENT;
int create_options = CREATE_NOT_DIR;
int desired_access;
- struct cifs_sb_info *cifs_sb = CIFS_SB(inode);
+ struct cifs_sb_info *cifs_sb = CIFS_SB(dir);
struct cifs_tcon *tcon = tlink_tcon(tlink);
- const char *full_path;
- void *page = alloc_dentry_path();
struct inode *newinode = NULL;
unsigned int sbflags = cifs_sb_flags(cifs_sb);
int disposition;
if (tcon->ses->server->oplocks)
*oplock = REQ_OPLOCK;
- full_path = build_path_from_dentry(direntry, page);
- if (IS_ERR(full_path)) {
- rc = PTR_ERR(full_path);
- goto out;
- }
-
/* If we're caching, we need to be able to fill in around partial writes. */
- if (cifs_fscache_enabled(inode) && (oflags & O_ACCMODE) == O_WRONLY)
+ if (cifs_fscache_enabled(dir) && (oflags & O_ACCMODE) == O_WRONLY)
rdwr_for_fscache = 1;
#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
if (tcon->unix_ext && cap_unix(tcon->ses) && !tcon->broken_posix_open &&
(CIFS_UNIX_POSIX_PATH_OPS_CAP &
le64_to_cpu(tcon->fsUnixInfo.Capability))) {
- rc = cifs_posix_open(full_path, &newinode, inode->i_sb, mode,
+ rc = cifs_posix_open(full_path, &newinode, dir->i_sb, mode,
oflags, oplock, &fid->netfid, xid);
switch (rc) {
case 0:
if (S_ISDIR(newinode->i_mode)) {
CIFSSMBClose(xid, tcon, fid->netfid);
iput(newinode);
- rc = -EISDIR;
- goto out;
+ return -EISDIR;
}
if (!S_ISREG(newinode->i_mode)) {
break;
default:
- goto out;
+ return rc;
}
/*
* fallthrough to retry, using older open call, this is case
desired_access |= GENERIC_WRITE;
if (rdwr_for_fscache == 1)
desired_access |= GENERIC_READ;
+ if (oflags & O_TMPFILE)
+ desired_access |= DELETE;
disposition = FILE_OVERWRITE_IF;
- if ((oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
+ if (oflags & O_CREAT) {
+ if (oflags & O_EXCL)
+ disposition = FILE_CREATE;
+ else if (oflags & O_TRUNC)
+ disposition = FILE_OVERWRITE_IF;
+ else
+ disposition = FILE_OPEN_IF;
+ } else if (oflags & O_TMPFILE) {
disposition = FILE_CREATE;
- else if ((oflags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC))
- disposition = FILE_OVERWRITE_IF;
- else if ((oflags & O_CREAT) == O_CREAT)
- disposition = FILE_OPEN_IF;
- else
+ } else {
cifs_dbg(FYI, "Create flag not set in create function\n");
+ }
/*
* BB add processing to set equivalent of mode - e.g. via CreateX with
* ACLs
*/
- if (!server->ops->open) {
- rc = -ENOSYS;
- goto out;
- }
+ if (!server->ops->open)
+ return -EOPNOTSUPP;
create_options |= cifs_open_create_options(oflags, create_options);
/*
rdwr_for_fscache = 2;
goto retry_open;
}
- goto out;
+ return rc;
}
if (rdwr_for_fscache == 2)
- cifs_invalidate_cache(inode, FSCACHE_INVAL_DIO_WRITE);
+ cifs_invalidate_cache(dir, FSCACHE_INVAL_DIO_WRITE);
#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
/*
if (sbflags & CIFS_MOUNT_SET_UID) {
args.uid = current_fsuid();
- if (inode->i_mode & S_ISGID)
- args.gid = inode->i_gid;
+ if (dir->i_mode & S_ISGID)
+ args.gid = dir->i_gid;
else
args.gid = current_fsgid();
} else {
cifs_create_get_file_info:
/* server might mask mode so we have to query for it */
if (tcon->unix_ext)
- rc = cifs_get_inode_info_unix(&newinode, full_path, inode->i_sb,
+ rc = cifs_get_inode_info_unix(&newinode, full_path, dir->i_sb,
xid);
else {
#else
{
#endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */
/* TODO: Add support for calling POSIX query info here, but passing in fid */
- rc = cifs_get_inode_info(&newinode, full_path, buf, inode->i_sb, xid, fid);
+ rc = cifs_get_inode_info(&newinode, full_path, buf, dir->i_sb, xid, fid);
if (newinode) {
if (server->ops->set_lease_key)
server->ops->set_lease_key(newinode, fid);
newinode->i_mode = mode;
if (sbflags & CIFS_MOUNT_SET_UID) {
newinode->i_uid = current_fsuid();
- if (inode->i_mode & S_ISGID)
- newinode->i_gid = inode->i_gid;
+ if (dir->i_mode & S_ISGID)
+ newinode->i_gid = dir->i_gid;
else
newinode->i_gid = current_fsgid();
}
goto out_err;
}
- if (newinode)
- if (S_ISDIR(newinode->i_mode)) {
- rc = -EISDIR;
- goto out_err;
- }
+ if (newinode && S_ISDIR(newinode->i_mode)) {
+ rc = -EISDIR;
+ goto out_err;
+ }
d_drop(direntry);
- d_add(direntry, newinode);
-
-out:
- free_dentry_path(page);
+ *inode = newinode;
return rc;
out_err:
server->ops->close(xid, tcon, fid);
if (newinode)
iput(newinode);
- goto out;
+ return rc;
}
+static int cifs_do_create(struct inode *dir, struct dentry *direntry,
+ unsigned int xid, struct tcon_link *tlink,
+ unsigned int oflags, umode_t mode,
+ __u32 *oplock, struct cifs_fid *fid,
+ struct cifs_open_info_data *buf)
+{
+ void *page = alloc_dentry_path();
+ const char *full_path;
+ struct inode *inode;
+ int rc;
+
+ full_path = build_path_from_dentry(direntry, page);
+ if (IS_ERR(full_path)) {
+ rc = PTR_ERR(full_path);
+ } else {
+ rc = __cifs_do_create(dir, direntry, full_path, xid,
+ tlink, oflags, mode, oplock,
+ fid, buf, &inode);
+ if (!rc)
+ d_add(direntry, inode);
+ }
+ free_dentry_path(page);
+ return rc;
+}
+
+
+/*
+ * Look up, create and open a CIFS file.
+ *
+ * The initial dentry state is in-lookup or hashed-negative. On success, dentry
+ * will become hashed-positive by calling d_drop() & d_add(), respectively.
+ */
int
cifs_atomic_open(struct inode *inode, struct dentry *direntry,
struct file *file, unsigned int oflags, umode_t mode)
return rc;
}
+/*
+ * Create a CIFS file.
+ *
+ * The initial dentry state is hashed-negative. On success, dentry will become
+ * hashed-positive by calling d_drop() & d_add(), respectively.
+ */
int cifs_create(struct mnt_idmap *idmap, struct inode *inode,
struct dentry *direntry, umode_t mode, bool excl)
{
return 0;
}
+static int set_hidden_attr(const unsigned int xid,
+ struct TCP_Server_Info *server,
+ struct file *file)
+{
+ struct dentry *dentry = file->f_path.dentry;
+ struct cifsInodeInfo *cinode = CIFS_I(d_inode(dentry));
+ FILE_BASIC_INFO fi = {
+ .Attributes = cpu_to_le32(cinode->cifsAttrs |
+ ATTR_HIDDEN),
+ };
+ void *page = alloc_dentry_path();
+ const char *full_path;
+ int rc;
+
+ full_path = build_path_from_dentry(dentry, page);
+ if (IS_ERR(full_path))
+ rc = PTR_ERR(full_path);
+ else
+ rc = server->ops->set_file_info(d_inode(dentry),
+ full_path, &fi, xid);
+ free_dentry_path(page);
+ return rc;
+}
+
+/*
+ * Create a hidden temporary CIFS file with delete-on-close bit set.
+ *
+ * The initial dentry state is unhashed-negative. On success, dentry will
+ * become unhashed-positive by calling d_drop() & d_instantiate(), respectively.
+ */
+int cifs_tmpfile(struct mnt_idmap *idmap, struct inode *dir,
+ struct file *file, umode_t mode)
+{
+ struct dentry *dentry = file->f_path.dentry;
+ struct cifs_sb_info *cifs_sb = CIFS_SB(dir);
+ size_t size = CIFS_TMPNAME_LEN + 1;
+ int retries = 0, max_retries = 16;
+ struct TCP_Server_Info *server;
+ struct cifs_pending_open open;
+ struct cifsFileInfo *cfile;
+ struct cifs_fid fid = {};
+ struct tcon_link *tlink;
+ struct cifs_tcon *tcon;
+ unsigned int sbflags;
+ struct inode *inode;
+ char *path, *name;
+ unsigned int xid;
+ __u32 oplock;
+ int rc;
+
+ if (unlikely(cifs_forced_shutdown(cifs_sb)))
+ return smb_EIO(smb_eio_trace_forced_shutdown);
+
+ tlink = cifs_sb_tlink(cifs_sb);
+ if (IS_ERR(tlink))
+ return PTR_ERR(tlink);
+ tcon = tlink_tcon(tlink);
+ server = tcon->ses->server;
+
+ xid = get_xid();
+
+ if (server->vals->protocol_id < SMB20_PROT_ID) {
+ cifs_dbg(VFS | ONCE, "O_TMPFILE is supported only in SMB2+\n");
+ rc = -EOPNOTSUPP;
+ goto out;
+ }
+
+ if (server->ops->new_lease_key)
+ server->ops->new_lease_key(&fid);
+ cifs_add_pending_open(&fid, tlink, &open);
+
+ path = alloc_parent_path(dentry, size - 1);
+ if (IS_ERR(path)) {
+ cifs_del_pending_open(&open);
+ rc = PTR_ERR(path);
+ goto out;
+ }
+
+ name = path + strlen(path);
+ do {
+ scnprintf(name, size,
+ CIFS_TMPNAME_PREFIX "%0*x",
+ CIFS_TMPNAME_COUNTER_LEN,
+ atomic_inc_return(&cifs_tmpcounter));
+ rc = __cifs_do_create(dir, dentry, path, xid, tlink,
+ file->f_flags, mode, &oplock,
+ &fid, NULL, &inode);
+ if (!rc) {
+ set_nlink(inode, 0);
+ mark_inode_dirty(inode);
+ d_mark_tmpfile_name(file, &QSTR_LEN(name, size - 1));
+ d_instantiate(dentry, inode);
+ break;
+ }
+ } while (unlikely(rc == -EEXIST) && ++retries < max_retries);
+
+ kfree(path);
+ if (rc) {
+ cifs_del_pending_open(&open);
+ goto out;
+ }
+
+ rc = finish_open(file, dentry, generic_file_open);
+ if (rc)
+ goto err_open;
+
+ sbflags = cifs_sb_flags(cifs_sb);
+ if ((file->f_flags & O_DIRECT) && (sbflags & CIFS_MOUNT_STRICT_IO)) {
+ if (sbflags & CIFS_MOUNT_NO_BRL)
+ file->f_op = &cifs_file_direct_nobrl_ops;
+ else
+ file->f_op = &cifs_file_direct_ops;
+ }
+
+ cfile = cifs_new_fileinfo(&fid, file, tlink, oplock, NULL);
+ if (!cfile) {
+ rc = -ENOMEM;
+ goto err_open;
+ }
+
+ rc = set_hidden_attr(xid, server, file);
+ if (rc)
+ goto out;
+
+ fscache_use_cookie(cifs_inode_cookie(file_inode(file)),
+ file->f_mode & FMODE_WRITE);
+out:
+ cifs_put_tlink(tlink);
+ free_xid(xid);
+ return rc;
+err_open:
+ cifs_del_pending_open(&open);
+ if (server->ops->close)
+ server->ops->close(xid, tcon, &fid);
+ goto out;
+}
+
+char *cifs_silly_fullpath(struct dentry *dentry)
+{
+ unsigned char name[CIFS_SILLYNAME_LEN + 1];
+ int retries = 0, max_retries = 16;
+ size_t namesize = sizeof(name);
+ struct dentry *sdentry = NULL;
+ char *path;
+
+ do {
+ dput(sdentry);
+ scnprintf(name, namesize,
+ CIFS_SILLYNAME_PREFIX "%0*x",
+ CIFS_SILLYNAME_COUNTER_LEN,
+ atomic_inc_return(&cifs_sillycounter));
+ sdentry = lookup_noperm(&QSTR(name), dentry->d_parent);
+ if (IS_ERR(sdentry))
+ return ERR_CAST(sdentry);
+ if (d_is_negative(sdentry)) {
+ dput(sdentry);
+ path = alloc_parent_path(dentry, CIFS_SILLYNAME_LEN);
+ if (!IS_ERR(path))
+ strcat(path, name);
+ return path;
+ }
+ } while (++retries < max_retries);
+ dput(sdentry);
+ return ERR_PTR(-EBUSY);
+}
+
const struct dentry_operations cifs_ci_dentry_ops = {
.d_revalidate = cifs_d_revalidate,
.d_hash = cifs_ci_hash,
return 0;
}
+/*
+ * If @cfile is NULL, then need to account for trailing CLOSE request in the
+ * compound chain.
+ */
+static void set_next_compound(struct cifs_tcon *tcon,
+ struct cifsFileInfo *cfile,
+ int i, int num_cmds,
+ struct smb_rqst *rqst, int *num_rqst)
+{
+ int k = !cfile ? 1 : 0;
+
+ if (i + 1 < num_cmds + k)
+ smb2_set_next_command(tcon, &rqst[*num_rqst]);
+ if (i + k > 0)
+ smb2_set_related(&rqst[*num_rqst]);
+ (*num_rqst)++;
+}
+
+#define COMP_PID(cfile) ((cfile) ? (cfile)->fid.persistent_fid : COMPOUND_FID)
+#define COMP_VID(cfile) ((cfile) ? (cfile)->fid.volatile_fid : COMPOUND_FID)
+
/*
* note: If cfile is passed, the reference to it is dropped here.
* So make sure that you do not reuse cfile after return from this func.
rqst[num_rqst].rq_iov = &vars->qi_iov;
rqst[num_rqst].rq_nvec = 1;
- if (cfile) {
- rc = SMB2_query_info_init(tcon, server,
- &rqst[num_rqst],
- cfile->fid.persistent_fid,
- cfile->fid.volatile_fid,
- FILE_ALL_INFORMATION,
- SMB2_O_INFO_FILE, 0,
- sizeof(struct smb2_file_all_info) +
- PATH_MAX * 2, 0, NULL);
- } else {
- rc = SMB2_query_info_init(tcon, server,
- &rqst[num_rqst],
- COMPOUND_FID,
- COMPOUND_FID,
- FILE_ALL_INFORMATION,
- SMB2_O_INFO_FILE, 0,
- sizeof(struct smb2_file_all_info) +
- PATH_MAX * 2, 0, NULL);
- }
- if (!rc && (!cfile || num_rqst > 1)) {
- smb2_set_next_command(tcon, &rqst[num_rqst]);
- smb2_set_related(&rqst[num_rqst]);
- } else if (rc) {
+ rc = SMB2_query_info_init(tcon, server,
+ &rqst[num_rqst],
+ COMP_PID(cfile), COMP_VID(cfile),
+ FILE_ALL_INFORMATION,
+ SMB2_O_INFO_FILE, 0,
+ sizeof(struct smb2_file_all_info) +
+ PATH_MAX * 2, 0, NULL);
+ if (rc)
goto finished;
- }
- num_rqst++;
+ set_next_compound(tcon, cfile, i, num_cmds, rqst, &num_rqst);
trace_smb3_query_info_compound_enter(xid, tcon->tid,
ses->Suid, full_path);
break;
rqst[num_rqst].rq_iov = &vars->qi_iov;
rqst[num_rqst].rq_nvec = 1;
- if (cfile) {
- /* TBD: fix following to allow for longer SIDs */
- rc = SMB2_query_info_init(tcon, server,
- &rqst[num_rqst],
- cfile->fid.persistent_fid,
- cfile->fid.volatile_fid,
- SMB_FIND_FILE_POSIX_INFO,
- SMB2_O_INFO_FILE, 0,
- sizeof(struct smb311_posix_qinfo) +
- (PATH_MAX * 2) +
- (sizeof(struct smb_sid) * 2), 0, NULL);
- } else {
- rc = SMB2_query_info_init(tcon, server,
- &rqst[num_rqst],
- COMPOUND_FID,
- COMPOUND_FID,
- SMB_FIND_FILE_POSIX_INFO,
- SMB2_O_INFO_FILE, 0,
- sizeof(struct smb311_posix_qinfo) +
- (PATH_MAX * 2) +
- (sizeof(struct smb_sid) * 2), 0, NULL);
- }
- if (!rc && (!cfile || num_rqst > 1)) {
- smb2_set_next_command(tcon, &rqst[num_rqst]);
- smb2_set_related(&rqst[num_rqst]);
- } else if (rc) {
+ /* TBD: fix following to allow for longer SIDs */
+ rc = SMB2_query_info_init(tcon, server,
+ &rqst[num_rqst],
+ COMP_PID(cfile), COMP_VID(cfile),
+ SMB_FIND_FILE_POSIX_INFO,
+ SMB2_O_INFO_FILE, 0,
+ sizeof(struct smb311_posix_qinfo) +
+ (PATH_MAX * 2) +
+ (sizeof(struct smb_sid) * 2), 0, NULL);
+ if (rc)
goto finished;
- }
- num_rqst++;
+ set_next_compound(tcon, cfile, i, num_cmds, rqst, &num_rqst);
trace_smb3_posix_query_info_compound_enter(xid, tcon->tid,
ses->Suid, full_path);
break;
size[0] = 1; /* sizeof __u8 See MS-FSCC section 2.4.11 */
data[0] = &delete_pending[0];
- if (cfile) {
- rc = SMB2_set_info_init(tcon, server,
- &rqst[num_rqst],
- cfile->fid.persistent_fid,
- cfile->fid.volatile_fid,
- current->tgid,
- FILE_DISPOSITION_INFORMATION,
- SMB2_O_INFO_FILE, 0,
- data, size);
- } else {
- rc = SMB2_set_info_init(tcon, server,
- &rqst[num_rqst],
- COMPOUND_FID,
- COMPOUND_FID,
- current->tgid,
- FILE_DISPOSITION_INFORMATION,
- SMB2_O_INFO_FILE, 0,
- data, size);
- }
- if (!rc && (!cfile || num_rqst > 1)) {
- smb2_set_next_command(tcon, &rqst[num_rqst]);
- smb2_set_related(&rqst[num_rqst]);
- } else if (rc) {
+ rc = SMB2_set_info_init(tcon, server,
+ &rqst[num_rqst],
+ COMP_PID(cfile), COMP_VID(cfile),
+ current->tgid, FILE_DISPOSITION_INFORMATION,
+ SMB2_O_INFO_FILE, 0,
+ data, size);
+ if (rc)
goto finished;
- }
- num_rqst++;
+ set_next_compound(tcon, cfile, i, num_cmds, rqst, &num_rqst);
trace_smb3_unlink_enter(xid, tcon->tid, ses->Suid, full_path);
break;
case SMB2_OP_SET_EOF:
size[0] = in_iov[i].iov_len;
data[0] = in_iov[i].iov_base;
- if (cfile) {
- rc = SMB2_set_info_init(tcon, server,
- &rqst[num_rqst],
- cfile->fid.persistent_fid,
- cfile->fid.volatile_fid,
- current->tgid,
- FILE_END_OF_FILE_INFORMATION,
- SMB2_O_INFO_FILE, 0,
- data, size);
- } else {
- rc = SMB2_set_info_init(tcon, server,
- &rqst[num_rqst],
- COMPOUND_FID,
- COMPOUND_FID,
- current->tgid,
- FILE_END_OF_FILE_INFORMATION,
- SMB2_O_INFO_FILE, 0,
- data, size);
- }
- if (!rc && (!cfile || num_rqst > 1)) {
- smb2_set_next_command(tcon, &rqst[num_rqst]);
- smb2_set_related(&rqst[num_rqst]);
- } else if (rc) {
+ rc = SMB2_set_info_init(tcon, server,
+ &rqst[num_rqst],
+ COMP_PID(cfile), COMP_VID(cfile),
+ current->tgid, FILE_END_OF_FILE_INFORMATION,
+ SMB2_O_INFO_FILE, 0,
+ data, size);
+ if (rc)
goto finished;
- }
- num_rqst++;
+ set_next_compound(tcon, cfile, i, num_cmds, rqst, &num_rqst);
trace_smb3_set_eof_enter(xid, tcon->tid, ses->Suid, full_path);
break;
case SMB2_OP_SET_INFO:
size[0] = in_iov[i].iov_len;
data[0] = in_iov[i].iov_base;
- if (cfile) {
- rc = SMB2_set_info_init(tcon, server,
- &rqst[num_rqst],
- cfile->fid.persistent_fid,
- cfile->fid.volatile_fid, current->tgid,
- FILE_BASIC_INFORMATION,
- SMB2_O_INFO_FILE, 0, data, size);
- } else {
- rc = SMB2_set_info_init(tcon, server,
- &rqst[num_rqst],
- COMPOUND_FID,
- COMPOUND_FID, current->tgid,
- FILE_BASIC_INFORMATION,
- SMB2_O_INFO_FILE, 0, data, size);
- }
- if (!rc && (!cfile || num_rqst > 1)) {
- smb2_set_next_command(tcon, &rqst[num_rqst]);
- smb2_set_related(&rqst[num_rqst]);
- } else if (rc) {
+ rc = SMB2_set_info_init(tcon, server,
+ &rqst[num_rqst],
+ COMP_PID(cfile), COMP_VID(cfile),
+ current->tgid, FILE_BASIC_INFORMATION,
+ SMB2_O_INFO_FILE, 0, data, size);
+ if (rc)
goto finished;
- }
- num_rqst++;
+ set_next_compound(tcon, cfile, i, num_cmds, rqst, &num_rqst);
trace_smb3_set_info_compound_enter(xid, tcon->tid,
ses->Suid, full_path);
break;
size[1] = len + 2 /* null */;
data[1] = in_iov[i].iov_base;
- if (cfile) {
- rc = SMB2_set_info_init(tcon, server,
- &rqst[num_rqst],
- cfile->fid.persistent_fid,
- cfile->fid.volatile_fid,
- current->tgid, FILE_RENAME_INFORMATION,
- SMB2_O_INFO_FILE, 0, data, size);
- } else {
- rc = SMB2_set_info_init(tcon, server,
- &rqst[num_rqst],
- COMPOUND_FID, COMPOUND_FID,
- current->tgid, FILE_RENAME_INFORMATION,
- SMB2_O_INFO_FILE, 0, data, size);
- }
- if (!rc && (!cfile || num_rqst > 1)) {
- smb2_set_next_command(tcon, &rqst[num_rqst]);
- smb2_set_related(&rqst[num_rqst]);
- } else if (rc) {
+ rc = SMB2_set_info_init(tcon, server,
+ &rqst[num_rqst],
+ COMP_PID(cfile), COMP_VID(cfile),
+ current->tgid, FILE_RENAME_INFORMATION,
+ SMB2_O_INFO_FILE, 0, data, size);
+
+ if (rc)
goto finished;
- }
- num_rqst++;
+ set_next_compound(tcon, cfile, i, num_cmds, rqst, &num_rqst);
trace_smb3_rename_enter(xid, tcon->tid, ses->Suid, full_path);
break;
case SMB2_OP_HARDLINK:
- rqst[num_rqst].rq_iov = &vars->si_iov[0];
+ rqst[num_rqst].rq_iov = vars->hl_iov;
rqst[num_rqst].rq_nvec = 2;
len = in_iov[i].iov_len;
data[1] = in_iov[i].iov_base;
rc = SMB2_set_info_init(tcon, server,
- &rqst[num_rqst], COMPOUND_FID,
- COMPOUND_FID, current->tgid,
- FILE_LINK_INFORMATION,
+ &rqst[num_rqst],
+ COMP_PID(cfile), COMP_VID(cfile),
+ current->tgid, FILE_LINK_INFORMATION,
SMB2_O_INFO_FILE, 0, data, size);
if (rc)
goto finished;
- smb2_set_next_command(tcon, &rqst[num_rqst]);
- smb2_set_related(&rqst[num_rqst++]);
+ set_next_compound(tcon, cfile, i, num_cmds, rqst, &num_rqst);
trace_smb3_hardlink_enter(xid, tcon->tid, ses->Suid, full_path);
break;
case SMB2_OP_SET_REPARSE:
rqst[num_rqst].rq_iov = vars->io_iov;
rqst[num_rqst].rq_nvec = ARRAY_SIZE(vars->io_iov);
- if (cfile) {
- rc = SMB2_ioctl_init(tcon, server, &rqst[num_rqst],
- cfile->fid.persistent_fid,
- cfile->fid.volatile_fid,
- FSCTL_SET_REPARSE_POINT,
- in_iov[i].iov_base,
- in_iov[i].iov_len, 0);
- } else {
- rc = SMB2_ioctl_init(tcon, server, &rqst[num_rqst],
- COMPOUND_FID, COMPOUND_FID,
- FSCTL_SET_REPARSE_POINT,
- in_iov[i].iov_base,
- in_iov[i].iov_len, 0);
- }
- if (!rc && (!cfile || num_rqst > 1)) {
- smb2_set_next_command(tcon, &rqst[num_rqst]);
- smb2_set_related(&rqst[num_rqst]);
- } else if (rc) {
+ rc = SMB2_ioctl_init(tcon, server, &rqst[num_rqst],
+ COMP_PID(cfile), COMP_VID(cfile),
+ FSCTL_SET_REPARSE_POINT,
+ in_iov[i].iov_base,
+ in_iov[i].iov_len, 0);
+ if (rc)
goto finished;
- }
- num_rqst++;
+ set_next_compound(tcon, cfile, i, num_cmds, rqst, &num_rqst);
trace_smb3_set_reparse_compound_enter(xid, tcon->tid,
ses->Suid, full_path);
break;
rqst[num_rqst].rq_iov = vars->io_iov;
rqst[num_rqst].rq_nvec = ARRAY_SIZE(vars->io_iov);
- if (cfile) {
- rc = SMB2_ioctl_init(tcon, server, &rqst[num_rqst],
- cfile->fid.persistent_fid,
- cfile->fid.volatile_fid,
- FSCTL_GET_REPARSE_POINT,
- NULL, 0, CIFSMaxBufSize);
- } else {
- rc = SMB2_ioctl_init(tcon, server, &rqst[num_rqst],
- COMPOUND_FID, COMPOUND_FID,
- FSCTL_GET_REPARSE_POINT,
- NULL, 0, CIFSMaxBufSize);
- }
- if (!rc && (!cfile || num_rqst > 1)) {
- smb2_set_next_command(tcon, &rqst[num_rqst]);
- smb2_set_related(&rqst[num_rqst]);
- } else if (rc) {
+ rc = SMB2_ioctl_init(tcon, server, &rqst[num_rqst],
+ COMP_PID(cfile), COMP_VID(cfile),
+ FSCTL_GET_REPARSE_POINT,
+ NULL, 0, CIFSMaxBufSize);
+ if (rc)
goto finished;
- }
- num_rqst++;
+ set_next_compound(tcon, cfile, i, num_cmds, rqst, &num_rqst);
trace_smb3_get_reparse_compound_enter(xid, tcon->tid,
ses->Suid, full_path);
break;
rqst[num_rqst].rq_iov = &vars->ea_iov;
rqst[num_rqst].rq_nvec = 1;
- if (cfile) {
- rc = SMB2_query_info_init(tcon, server,
- &rqst[num_rqst],
- cfile->fid.persistent_fid,
- cfile->fid.volatile_fid,
- FILE_FULL_EA_INFORMATION,
- SMB2_O_INFO_FILE, 0,
- SMB2_WSL_MAX_QUERY_EA_RESP_SIZE,
- sizeof(wsl_query_eas),
- (void *)wsl_query_eas);
- } else {
- rc = SMB2_query_info_init(tcon, server,
- &rqst[num_rqst],
- COMPOUND_FID,
- COMPOUND_FID,
- FILE_FULL_EA_INFORMATION,
- SMB2_O_INFO_FILE, 0,
- SMB2_WSL_MAX_QUERY_EA_RESP_SIZE,
- sizeof(wsl_query_eas),
- (void *)wsl_query_eas);
- }
- if (!rc && (!cfile || num_rqst > 1)) {
- smb2_set_next_command(tcon, &rqst[num_rqst]);
- smb2_set_related(&rqst[num_rqst]);
- } else if (rc) {
+ rc = SMB2_query_info_init(tcon, server,
+ &rqst[num_rqst],
+ COMP_PID(cfile), COMP_VID(cfile),
+ FILE_FULL_EA_INFORMATION,
+ SMB2_O_INFO_FILE, 0,
+ SMB2_WSL_MAX_QUERY_EA_RESP_SIZE,
+ sizeof(wsl_query_eas),
+ (void *)wsl_query_eas);
+ if (rc)
goto finished;
- }
- num_rqst++;
+ set_next_compound(tcon, cfile, i, num_cmds, rqst, &num_rqst);
trace_smb3_query_wsl_ea_compound_enter(xid, tcon->tid,
ses->Suid, full_path);
break;
cifs_i = CIFS_I(inode);
dosattrs = cifs_i->cifsAttrs | ATTR_READONLY;
data.Attributes = cpu_to_le32(dosattrs);
- cifs_get_writable_path(tcon, name, FIND_ANY, &cfile);
+ cifs_get_writable_path(tcon, name, inode, FIND_ANY, &cfile);
oparms = CIFS_OPARMS(cifs_sb, tcon, name, FILE_WRITE_ATTRIBUTES,
FILE_CREATE, CREATE_NOT_FILE, ACL_NO_MODE);
tmprc = smb2_compound_op(xid, tcon, cifs_sb, name,
const char *from_name, const char *to_name,
struct cifs_sb_info *cifs_sb)
{
+ struct inode *inode = source_dentry ? d_inode(source_dentry) : NULL;
struct cifsFileInfo *cfile;
__u32 co = file_create_options(source_dentry);
drop_cached_dir_by_name(xid, tcon, from_name, cifs_sb);
- cifs_get_writable_path(tcon, from_name, FIND_WITH_DELETE, &cfile);
+ cifs_get_writable_path(tcon, from_name, inode,
+ FIND_WITH_DELETE, &cfile);
int rc = smb2_set_path_attr(xid, tcon, from_name, to_name, cifs_sb,
co, DELETE, SMB2_OP_RENAME, cfile, source_dentry);
if (rc == -EINVAL) {
cifs_dbg(FYI, "invalid lease key, resending request without lease");
- cifs_get_writable_path(tcon, from_name, FIND_WITH_DELETE, &cfile);
+ cifs_get_writable_path(tcon, from_name, inode,
+ FIND_WITH_DELETE, &cfile);
rc = smb2_set_path_attr(xid, tcon, from_name, to_name, cifs_sb,
co, DELETE, SMB2_OP_RENAME, cfile, NULL);
}
const char *from_name, const char *to_name,
struct cifs_sb_info *cifs_sb)
{
+ struct inode *inode = source_dentry ? d_inode(source_dentry) : NULL;
__u32 co = file_create_options(source_dentry);
+ struct cifsFileInfo *cfile;
+
+ if (inode) {
+ struct cifsInodeInfo *cinode = CIFS_I(inode);
+ FILE_BASIC_INFO fi;
+ __le32 attrs;
+ int rc;
+ if (!test_bit(CIFS_INO_TMPFILE, &CIFS_I(inode)->flags))
+ goto out;
+
+ attrs = cpu_to_le32(cinode->cifsAttrs & ~ATTR_HIDDEN);
+ fi = (FILE_BASIC_INFO){ .Attributes = attrs, };
+ rc = smb2_set_file_info(inode, from_name, &fi, xid);
+ if (rc)
+ return rc;
+ }
+
+out:
+ cifs_get_writable_path(tcon, from_name, inode,
+ FIND_WITH_DELETE, &cfile);
return smb2_set_path_attr(xid, tcon, from_name, to_name,
cifs_sb, co, FILE_READ_ATTRIBUTES,
- SMB2_OP_HARDLINK, NULL, NULL);
+ SMB2_OP_HARDLINK, cfile, NULL);
}
int
struct cifs_sb_info *cifs_sb, bool set_alloc,
struct dentry *dentry)
{
+ struct inode *inode = dentry ? d_inode(dentry) : NULL;
+ __le64 eof = cpu_to_le64(size);
struct cifs_open_parms oparms;
struct cifsFileInfo *cfile;
struct kvec in_iov;
- __le64 eof = cpu_to_le64(size);
int rc;
in_iov.iov_base = &eof;
in_iov.iov_len = sizeof(eof);
- cifs_get_writable_path(tcon, full_path, FIND_ANY, &cfile);
+ cifs_get_writable_path(tcon, full_path, inode, FIND_ANY, &cfile);
oparms = CIFS_OPARMS(cifs_sb, tcon, full_path, FILE_WRITE_DATA,
FILE_OPEN, 0, ACL_NO_MODE);
cfile, NULL, NULL, dentry);
if (rc == -EINVAL) {
cifs_dbg(FYI, "invalid lease key, resending request without lease");
- cifs_get_writable_path(tcon, full_path, FIND_ANY, &cfile);
+ cifs_get_writable_path(tcon, full_path,
+ inode, FIND_ANY, &cfile);
rc = smb2_compound_op(xid, tcon, cifs_sb,
full_path, &oparms, &in_iov,
&(int){SMB2_OP_SET_EOF}, 1,
(buf->LastWriteTime == 0) && (buf->ChangeTime == 0)) {
if (buf->Attributes == 0)
goto out; /* would be a no op, no sense sending this */
- cifs_get_writable_path(tcon, full_path, FIND_ANY, &cfile);
+ cifs_get_writable_path(tcon, full_path,
+ inode, FIND_ANY, &cfile);
}
oparms = CIFS_OPARMS(cifs_sb, tcon, full_path, FILE_WRITE_ATTRIBUTES,
if (tcon->posix_extensions) {
cmds[1] = SMB2_OP_POSIX_QUERY_INFO;
- cifs_get_writable_path(tcon, full_path, FIND_ANY, &cfile);
+ cifs_get_writable_path(tcon, full_path, NULL, FIND_ANY, &cfile);
rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, &oparms,
in_iov, cmds, 2, cfile, out_iov, out_buftype, NULL);
if (!rc) {
}
} else {
cmds[1] = SMB2_OP_QUERY_INFO;
- cifs_get_writable_path(tcon, full_path, FIND_ANY, &cfile);
+ cifs_get_writable_path(tcon, full_path, NULL, FIND_ANY, &cfile);
rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, &oparms,
in_iov, cmds, 2, cfile, out_iov, out_buftype, NULL);
if (!rc) {
struct dentry *dentry,
const unsigned int xid)
{
- struct cifs_sb_info *cifs_sb = CIFS_SB(d_inode(dentry)->i_sb);
struct cifsInodeInfo *cinode = CIFS_I(d_inode(dentry));
+ struct cifs_sb_info *cifs_sb = CIFS_SB(dentry);
__le16 *utf16_path __free(kfree) = NULL;
__u32 co = file_create_options(dentry);
int cmds[] = {
char *to_name __free(kfree) = NULL;
__u32 attrs = cinode->cifsAttrs;
struct cifs_open_parms oparms;
- static atomic_t sillycounter;
struct cifsFileInfo *cfile;
struct tcon_link *tlink;
struct cifs_tcon *tcon;
struct kvec iov[2];
- const char *ppath;
- void *page;
- size_t len;
int rc;
tlink = cifs_sb_tlink(cifs_sb);
return PTR_ERR(tlink);
tcon = tlink_tcon(tlink);
- page = alloc_dentry_path();
-
- ppath = build_path_from_dentry(dentry->d_parent, page);
- if (IS_ERR(ppath)) {
- rc = PTR_ERR(ppath);
- goto out;
- }
-
- len = strlen(ppath) + strlen("/.__smb1234") + 1;
- to_name = kmalloc(len, GFP_KERNEL);
- if (!to_name) {
- rc = -ENOMEM;
+ to_name = cifs_silly_fullpath(dentry);
+ if (IS_ERR(to_name)) {
+ rc = PTR_ERR(to_name);
+ to_name = NULL;
goto out;
}
- scnprintf(to_name, len, "%s%c.__smb%04X", ppath, CIFS_DIR_SEP(cifs_sb),
- atomic_inc_return(&sillycounter) & 0xffff);
-
- utf16_path = utf16_smb2_path(cifs_sb, to_name, len);
+ utf16_path = utf16_smb2_path(cifs_sb, to_name, strlen(to_name));
if (!utf16_path) {
rc = -ENOMEM;
goto out;
iov[1].iov_base = utf16_path;
iov[1].iov_len = sizeof(*utf16_path) * UniStrlen((wchar_t *)utf16_path);
- cifs_get_writable_path(tcon, full_path, FIND_WITH_DELETE, &cfile);
+ cifs_get_writable_path(tcon, full_path, d_inode(dentry),
+ FIND_WITH_DELETE, &cfile);
rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, &oparms, iov,
cmds, num_cmds, cfile, NULL, NULL, dentry);
if (rc == -EINVAL) {
cifs_dbg(FYI, "invalid lease key, resending request without lease\n");
- cifs_get_writable_path(tcon, full_path, FIND_WITH_DELETE, &cfile);
+ cifs_get_writable_path(tcon, full_path, d_inode(dentry),
+ FIND_WITH_DELETE, &cfile);
rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, &oparms, iov,
cmds, num_cmds, cfile, NULL, NULL, NULL);
}
}
out:
cifs_put_tlink(tlink);
- free_dentry_path(page);
return rc;
}