|
@@ -60,34 +60,32 @@ static inline int cifs_convert_flags(unsigned int flags)
|
|
|
FILE_READ_DATA);
|
|
|
}
|
|
|
|
|
|
-static inline fmode_t cifs_posix_convert_flags(unsigned int flags)
|
|
|
+static u32 cifs_posix_convert_flags(unsigned int flags)
|
|
|
{
|
|
|
- fmode_t posix_flags = 0;
|
|
|
+ u32 posix_flags = 0;
|
|
|
|
|
|
if ((flags & O_ACCMODE) == O_RDONLY)
|
|
|
- posix_flags = FMODE_READ;
|
|
|
+ posix_flags = SMB_O_RDONLY;
|
|
|
else if ((flags & O_ACCMODE) == O_WRONLY)
|
|
|
- posix_flags = FMODE_WRITE;
|
|
|
- else if ((flags & O_ACCMODE) == O_RDWR) {
|
|
|
- /* GENERIC_ALL is too much permission to request
|
|
|
- can cause unnecessary access denied on create */
|
|
|
- /* return GENERIC_ALL; */
|
|
|
- posix_flags = FMODE_READ | FMODE_WRITE;
|
|
|
- }
|
|
|
- /* can not map O_CREAT or O_EXCL or O_TRUNC flags when
|
|
|
- reopening a file. They had their effect on the original open */
|
|
|
- if (flags & O_APPEND)
|
|
|
- posix_flags |= (fmode_t)O_APPEND;
|
|
|
+ posix_flags = SMB_O_WRONLY;
|
|
|
+ else if ((flags & O_ACCMODE) == O_RDWR)
|
|
|
+ posix_flags = SMB_O_RDWR;
|
|
|
+
|
|
|
+ if (flags & O_CREAT)
|
|
|
+ posix_flags |= SMB_O_CREAT;
|
|
|
+ if (flags & O_EXCL)
|
|
|
+ posix_flags |= SMB_O_EXCL;
|
|
|
+ if (flags & O_TRUNC)
|
|
|
+ posix_flags |= SMB_O_TRUNC;
|
|
|
+ /* be safe and imply O_SYNC for O_DSYNC */
|
|
|
if (flags & O_DSYNC)
|
|
|
- posix_flags |= (fmode_t)O_DSYNC;
|
|
|
- if (flags & __O_SYNC)
|
|
|
- posix_flags |= (fmode_t)__O_SYNC;
|
|
|
+ posix_flags |= SMB_O_SYNC;
|
|
|
if (flags & O_DIRECTORY)
|
|
|
- posix_flags |= (fmode_t)O_DIRECTORY;
|
|
|
+ posix_flags |= SMB_O_DIRECTORY;
|
|
|
if (flags & O_NOFOLLOW)
|
|
|
- posix_flags |= (fmode_t)O_NOFOLLOW;
|
|
|
+ posix_flags |= SMB_O_NOFOLLOW;
|
|
|
if (flags & O_DIRECT)
|
|
|
- posix_flags |= (fmode_t)O_DIRECT;
|
|
|
+ posix_flags |= SMB_O_DIRECT;
|
|
|
|
|
|
return posix_flags;
|
|
|
}
|
|
@@ -159,6 +157,68 @@ client_can_cache:
|
|
|
return rc;
|
|
|
}
|
|
|
|
|
|
+int cifs_posix_open(char *full_path, struct inode **pinode,
|
|
|
+ struct super_block *sb, int mode, unsigned int f_flags,
|
|
|
+ __u32 *poplock, __u16 *pnetfid, int xid)
|
|
|
+{
|
|
|
+ int rc;
|
|
|
+ FILE_UNIX_BASIC_INFO *presp_data;
|
|
|
+ __u32 posix_flags = 0;
|
|
|
+ struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
|
|
|
+ struct cifs_fattr fattr;
|
|
|
+ struct tcon_link *tlink;
|
|
|
+ struct cifsTconInfo *tcon;
|
|
|
+
|
|
|
+ cFYI(1, "posix open %s", full_path);
|
|
|
+
|
|
|
+ presp_data = kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL);
|
|
|
+ if (presp_data == NULL)
|
|
|
+ return -ENOMEM;
|
|
|
+
|
|
|
+ tlink = cifs_sb_tlink(cifs_sb);
|
|
|
+ if (IS_ERR(tlink)) {
|
|
|
+ rc = PTR_ERR(tlink);
|
|
|
+ goto posix_open_ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ tcon = tlink_tcon(tlink);
|
|
|
+ mode &= ~current_umask();
|
|
|
+
|
|
|
+ posix_flags = cifs_posix_convert_flags(f_flags);
|
|
|
+ rc = CIFSPOSIXCreate(xid, tcon, posix_flags, mode, pnetfid, presp_data,
|
|
|
+ poplock, full_path, cifs_sb->local_nls,
|
|
|
+ cifs_sb->mnt_cifs_flags &
|
|
|
+ CIFS_MOUNT_MAP_SPECIAL_CHR);
|
|
|
+ cifs_put_tlink(tlink);
|
|
|
+
|
|
|
+ if (rc)
|
|
|
+ goto posix_open_ret;
|
|
|
+
|
|
|
+ if (presp_data->Type == cpu_to_le32(-1))
|
|
|
+ goto posix_open_ret; /* open ok, caller does qpathinfo */
|
|
|
+
|
|
|
+ if (!pinode)
|
|
|
+ goto posix_open_ret; /* caller does not need info */
|
|
|
+
|
|
|
+ cifs_unix_basic_to_fattr(&fattr, presp_data, cifs_sb);
|
|
|
+
|
|
|
+ /* get new inode and set it up */
|
|
|
+ if (*pinode == NULL) {
|
|
|
+ cifs_fill_uniqueid(sb, &fattr);
|
|
|
+ *pinode = cifs_iget(sb, &fattr);
|
|
|
+ if (!*pinode) {
|
|
|
+ rc = -ENOMEM;
|
|
|
+ goto posix_open_ret;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ cifs_fattr_to_inode(*pinode, &fattr);
|
|
|
+ }
|
|
|
+
|
|
|
+posix_open_ret:
|
|
|
+ kfree(presp_data);
|
|
|
+ return rc;
|
|
|
+}
|
|
|
+
|
|
|
int cifs_open(struct inode *inode, struct file *file)
|
|
|
{
|
|
|
int rc = -EACCES;
|
|
@@ -205,12 +265,10 @@ int cifs_open(struct inode *inode, struct file *file)
|
|
|
(tcon->ses->capabilities & CAP_UNIX) &&
|
|
|
(CIFS_UNIX_POSIX_PATH_OPS_CAP &
|
|
|
le64_to_cpu(tcon->fsUnixInfo.Capability))) {
|
|
|
- int oflags = (int) cifs_posix_convert_flags(file->f_flags);
|
|
|
- oflags |= SMB_O_CREAT;
|
|
|
/* can not refresh inode info since size could be stale */
|
|
|
rc = cifs_posix_open(full_path, &inode, inode->i_sb,
|
|
|
cifs_sb->mnt_file_mode /* ignored */,
|
|
|
- oflags, &oplock, &netfid, xid);
|
|
|
+ file->f_flags, &oplock, &netfid, xid);
|
|
|
if (rc == 0) {
|
|
|
cFYI(1, "posix open succeeded");
|
|
|
|
|
@@ -426,8 +484,13 @@ reopen_error_exit:
|
|
|
if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) &&
|
|
|
(CIFS_UNIX_POSIX_PATH_OPS_CAP &
|
|
|
le64_to_cpu(tcon->fsUnixInfo.Capability))) {
|
|
|
- int oflags = (int) cifs_posix_convert_flags(file->f_flags);
|
|
|
- /* can not refresh inode info since size could be stale */
|
|
|
+
|
|
|
+ /*
|
|
|
+ * O_CREAT, O_EXCL and O_TRUNC already had their effect on the
|
|
|
+ * original open. Must mask them off for a reopen.
|
|
|
+ */
|
|
|
+ unsigned int oflags = file->f_flags & ~(O_CREAT|O_EXCL|O_TRUNC);
|
|
|
+
|
|
|
rc = cifs_posix_open(full_path, NULL, inode->i_sb,
|
|
|
cifs_sb->mnt_file_mode /* ignored */,
|
|
|
oflags, &oplock, &netfid, xid);
|