@@ -1045,6 +1045,7 @@ const struct inode_operations cifs_dir_inode_ops = {
.setattr = cifs_setattr,
.symlink = cifs_symlink,
.mknod = cifs_mknod,
+ .tmpfile = smb3_tmpfile,
.listxattr = cifs_listxattr,
};
@@ -71,6 +71,7 @@ extern struct dentry *cifs_lookup(struct inode *, struct dentry *,
extern int cifs_unlink(struct inode *dir, struct dentry *dentry);
extern int cifs_hardlink(struct dentry *, struct inode *, struct dentry *);
extern int cifs_mknod(struct inode *, struct dentry *, umode_t, dev_t);
+extern int smb3_tmpfile(struct inode *, struct dentry *, umode_t);
extern int cifs_mkdir(struct inode *, struct dentry *, umode_t);
extern int cifs_rmdir(struct inode *, struct dentry *);
extern int cifs_rename2(struct inode *, struct dentry *, struct inode *,
@@ -374,6 +374,7 @@
#define CREATE_OPTIONS_MASK 0x007FFFFF
#define CREATE_OPTION_READONLY 0x10000000
#define CREATE_OPTION_SPECIAL 0x20000000 /* system. NB not sent over wire */
+#define CREATE_OPTION_TMP 0x40000000 /* set hidden/temporary as attrs */
/* ImpersonationLevel flags */
#define SECURITY_ANONYMOUS 0
@@ -220,12 +220,15 @@ check_name(struct dentry *direntry, struct cifs_tcon *tcon)
}
+/* minimum supported name length in old systems would be 8.3 names, 12 bytes */
+#define SHORT_NAME_LEN 12 /* 8 + 1 (for dot) + 3 */
+
/* Inode operations in similar order to how they appear in Linux file fs.h */
static int
cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned int xid,
struct tcon_link *tlink, unsigned oflags, umode_t mode,
- __u32 *oplock, struct cifs_fid *fid)
+ __u32 *oplock, struct cifs_fid *fid, bool tmp)
{
int rc = -ENOENT;
int create_options = CREATE_NOT_DIR;
@@ -243,10 +246,21 @@ cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned int xid,
if (tcon->ses->server->oplocks)
*oplock = REQ_OPLOCK;
- full_path = build_path_from_dentry(direntry);
+ if (tmp)
+ full_path = kmalloc(SHORT_NAME_LEN + 1 /* for trailing null */,
+ GFP_KERNEL);
+ else
+ full_path = build_path_from_dentry(direntry);
if (!full_path)
return -ENOMEM;
+ /* fill in 8.3 (maximum size on some old file systems) random name */
+ if (tmp) {
+ scnprintf(full_path, SHORT_NAME_LEN, "%lu", jiffies);
+ full_path[SHORT_NAME_LEN] = 0; /* trailing null */
+ full_path[8] = '.'; /* 8.3 names have . as eighth character */
+ }
+
if (tcon->unix_ext && cap_unix(tcon->ses) && !tcon->broken_posix_open &&
(CIFS_UNIX_POSIX_PATH_OPS_CAP &
le64_to_cpu(tcon->fsUnixInfo.Capability))) {
@@ -321,6 +335,8 @@ cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned int xid,
desired_access |= GENERIC_READ; /* is this too little? */
if (OPEN_FMODE(oflags) & FMODE_WRITE)
desired_access |= GENERIC_WRITE;
+ if (tmp)
+ desired_access |= DELETE;
disposition = FILE_OVERWRITE_IF;
if ((oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
@@ -448,6 +464,7 @@ cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned int xid,
d_add(direntry, newinode);
out:
+ cifs_dbg(VFS, "exiting cifs_do_create with rc %d\n",rc); /* BB REMOVEME */
kfree(buf);
kfree(full_path);
return rc;
@@ -527,7 +544,7 @@ cifs_atomic_open(struct inode *inode, struct dentry *direntry,
cifs_add_pending_open(&fid, tlink, &open);
rc = cifs_do_create(inode, direntry, xid, tlink, oflags, mode,
- &oplock, &fid);
+ &oplock, &fid, false);
if (rc) {
cifs_del_pending_open(&open);
@@ -603,7 +620,47 @@ int cifs_create(struct inode *inode, struct dentry *direntry, umode_t mode,
server->ops->new_lease_key(&fid);
rc = cifs_do_create(inode, direntry, xid, tlink, oflags, mode,
- &oplock, &fid);
+ &oplock, &fid, false);
+ if (!rc && server->ops->close)
+ server->ops->close(xid, tcon, &fid);
+
+
+ cifs_put_tlink(tlink);
+out_free_xid:
+ free_xid(xid);
+ return rc;
+}
+
+/*
+ * O_TMPFILE can be simulated over SMB3 using ATTR_TEMPORARY
+ */
+int smb3_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode)
+{
+ int rc = -EOPNOTSUPP;
+ unsigned int xid = get_xid();
+ unsigned oflags = O_EXCL | O_CREAT | O_RDWR;
+ struct tcon_link *tlink;
+ struct cifs_tcon *tcon;
+ struct TCP_Server_Info *server;
+ struct cifs_fid fid;
+ __u32 oplock;
+
+ cifs_dbg(FYI, "create tmpfile - dentry = 0x%p with mode 0x%x\n",
+ dentry, mode);
+
+ tlink = cifs_sb_tlink(CIFS_SB(dir->i_sb));
+ rc = PTR_ERR(tlink);
+ if (IS_ERR(tlink))
+ goto out_free_xid;
+
+ tcon = tlink_tcon(tlink);
+ server = tcon->ses->server;
+
+ if (server->ops->new_lease_key)
+ server->ops->new_lease_key(&fid);
+
+ rc = cifs_do_create(dir, dentry, xid, tlink, oflags, mode,
+ &oplock, &fid, true);
if (!rc && server->ops->close)
server->ops->close(xid, tcon, &fid);
@@ -2455,6 +2455,8 @@ SMB2_open_init(struct cifs_tcon *tcon, struct smb_rqst *rqst, __u8 *oplock,
file_attributes |= ATTR_READONLY;
if (oparms->create_options & CREATE_OPTION_SPECIAL)
file_attributes |= ATTR_SYSTEM;
+ if (oparms->create_options & CREATE_OPTION_TMP)
+ file_attributes |= ATTR_TEMPORARY | ATTR_HIDDEN;
req->ImpersonationLevel = IL_IMPERSONATION;
req->DesiredAccess = cpu_to_le32(oparms->desired_access);