diff options
Diffstat (limited to 'fs/cifs/file.c')
-rw-r--r-- | fs/cifs/file.c | 113 |
1 files changed, 88 insertions, 25 deletions
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index c10f0851cd21..b1ca6a43ac1a 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
@@ -60,34 +60,32 @@ static inline int cifs_convert_flags(unsigned int flags) | |||
60 | FILE_READ_DATA); | 60 | FILE_READ_DATA); |
61 | } | 61 | } |
62 | 62 | ||
63 | static inline fmode_t cifs_posix_convert_flags(unsigned int flags) | 63 | static u32 cifs_posix_convert_flags(unsigned int flags) |
64 | { | 64 | { |
65 | fmode_t posix_flags = 0; | 65 | u32 posix_flags = 0; |
66 | 66 | ||
67 | if ((flags & O_ACCMODE) == O_RDONLY) | 67 | if ((flags & O_ACCMODE) == O_RDONLY) |
68 | posix_flags = FMODE_READ; | 68 | posix_flags = SMB_O_RDONLY; |
69 | else if ((flags & O_ACCMODE) == O_WRONLY) | 69 | else if ((flags & O_ACCMODE) == O_WRONLY) |
70 | posix_flags = FMODE_WRITE; | 70 | posix_flags = SMB_O_WRONLY; |
71 | else if ((flags & O_ACCMODE) == O_RDWR) { | 71 | else if ((flags & O_ACCMODE) == O_RDWR) |
72 | /* GENERIC_ALL is too much permission to request | 72 | posix_flags = SMB_O_RDWR; |
73 | can cause unnecessary access denied on create */ | 73 | |
74 | /* return GENERIC_ALL; */ | 74 | if (flags & O_CREAT) |
75 | posix_flags = FMODE_READ | FMODE_WRITE; | 75 | posix_flags |= SMB_O_CREAT; |
76 | } | 76 | if (flags & O_EXCL) |
77 | /* can not map O_CREAT or O_EXCL or O_TRUNC flags when | 77 | posix_flags |= SMB_O_EXCL; |
78 | reopening a file. They had their effect on the original open */ | 78 | if (flags & O_TRUNC) |
79 | if (flags & O_APPEND) | 79 | posix_flags |= SMB_O_TRUNC; |
80 | posix_flags |= (fmode_t)O_APPEND; | 80 | /* be safe and imply O_SYNC for O_DSYNC */ |
81 | if (flags & O_DSYNC) | 81 | if (flags & O_DSYNC) |
82 | posix_flags |= (fmode_t)O_DSYNC; | 82 | posix_flags |= SMB_O_SYNC; |
83 | if (flags & __O_SYNC) | ||
84 | posix_flags |= (fmode_t)__O_SYNC; | ||
85 | if (flags & O_DIRECTORY) | 83 | if (flags & O_DIRECTORY) |
86 | posix_flags |= (fmode_t)O_DIRECTORY; | 84 | posix_flags |= SMB_O_DIRECTORY; |
87 | if (flags & O_NOFOLLOW) | 85 | if (flags & O_NOFOLLOW) |
88 | posix_flags |= (fmode_t)O_NOFOLLOW; | 86 | posix_flags |= SMB_O_NOFOLLOW; |
89 | if (flags & O_DIRECT) | 87 | if (flags & O_DIRECT) |
90 | posix_flags |= (fmode_t)O_DIRECT; | 88 | posix_flags |= SMB_O_DIRECT; |
91 | 89 | ||
92 | return posix_flags; | 90 | return posix_flags; |
93 | } | 91 | } |
@@ -159,6 +157,68 @@ client_can_cache: | |||
159 | return rc; | 157 | return rc; |
160 | } | 158 | } |
161 | 159 | ||
160 | int cifs_posix_open(char *full_path, struct inode **pinode, | ||
161 | struct super_block *sb, int mode, unsigned int f_flags, | ||
162 | __u32 *poplock, __u16 *pnetfid, int xid) | ||
163 | { | ||
164 | int rc; | ||
165 | FILE_UNIX_BASIC_INFO *presp_data; | ||
166 | __u32 posix_flags = 0; | ||
167 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb); | ||
168 | struct cifs_fattr fattr; | ||
169 | struct tcon_link *tlink; | ||
170 | struct cifsTconInfo *tcon; | ||
171 | |||
172 | cFYI(1, "posix open %s", full_path); | ||
173 | |||
174 | presp_data = kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL); | ||
175 | if (presp_data == NULL) | ||
176 | return -ENOMEM; | ||
177 | |||
178 | tlink = cifs_sb_tlink(cifs_sb); | ||
179 | if (IS_ERR(tlink)) { | ||
180 | rc = PTR_ERR(tlink); | ||
181 | goto posix_open_ret; | ||
182 | } | ||
183 | |||
184 | tcon = tlink_tcon(tlink); | ||
185 | mode &= ~current_umask(); | ||
186 | |||
187 | posix_flags = cifs_posix_convert_flags(f_flags); | ||
188 | rc = CIFSPOSIXCreate(xid, tcon, posix_flags, mode, pnetfid, presp_data, | ||
189 | poplock, full_path, cifs_sb->local_nls, | ||
190 | cifs_sb->mnt_cifs_flags & | ||
191 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
192 | cifs_put_tlink(tlink); | ||
193 | |||
194 | if (rc) | ||
195 | goto posix_open_ret; | ||
196 | |||
197 | if (presp_data->Type == cpu_to_le32(-1)) | ||
198 | goto posix_open_ret; /* open ok, caller does qpathinfo */ | ||
199 | |||
200 | if (!pinode) | ||
201 | goto posix_open_ret; /* caller does not need info */ | ||
202 | |||
203 | cifs_unix_basic_to_fattr(&fattr, presp_data, cifs_sb); | ||
204 | |||
205 | /* get new inode and set it up */ | ||
206 | if (*pinode == NULL) { | ||
207 | cifs_fill_uniqueid(sb, &fattr); | ||
208 | *pinode = cifs_iget(sb, &fattr); | ||
209 | if (!*pinode) { | ||
210 | rc = -ENOMEM; | ||
211 | goto posix_open_ret; | ||
212 | } | ||
213 | } else { | ||
214 | cifs_fattr_to_inode(*pinode, &fattr); | ||
215 | } | ||
216 | |||
217 | posix_open_ret: | ||
218 | kfree(presp_data); | ||
219 | return rc; | ||
220 | } | ||
221 | |||
162 | int cifs_open(struct inode *inode, struct file *file) | 222 | int cifs_open(struct inode *inode, struct file *file) |
163 | { | 223 | { |
164 | int rc = -EACCES; | 224 | int rc = -EACCES; |
@@ -205,12 +265,10 @@ int cifs_open(struct inode *inode, struct file *file) | |||
205 | (tcon->ses->capabilities & CAP_UNIX) && | 265 | (tcon->ses->capabilities & CAP_UNIX) && |
206 | (CIFS_UNIX_POSIX_PATH_OPS_CAP & | 266 | (CIFS_UNIX_POSIX_PATH_OPS_CAP & |
207 | le64_to_cpu(tcon->fsUnixInfo.Capability))) { | 267 | le64_to_cpu(tcon->fsUnixInfo.Capability))) { |
208 | int oflags = (int) cifs_posix_convert_flags(file->f_flags); | ||
209 | oflags |= SMB_O_CREAT; | ||
210 | /* can not refresh inode info since size could be stale */ | 268 | /* can not refresh inode info since size could be stale */ |
211 | rc = cifs_posix_open(full_path, &inode, inode->i_sb, | 269 | rc = cifs_posix_open(full_path, &inode, inode->i_sb, |
212 | cifs_sb->mnt_file_mode /* ignored */, | 270 | cifs_sb->mnt_file_mode /* ignored */, |
213 | oflags, &oplock, &netfid, xid); | 271 | file->f_flags, &oplock, &netfid, xid); |
214 | if (rc == 0) { | 272 | if (rc == 0) { |
215 | cFYI(1, "posix open succeeded"); | 273 | cFYI(1, "posix open succeeded"); |
216 | 274 | ||
@@ -426,8 +484,13 @@ reopen_error_exit: | |||
426 | if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) && | 484 | if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) && |
427 | (CIFS_UNIX_POSIX_PATH_OPS_CAP & | 485 | (CIFS_UNIX_POSIX_PATH_OPS_CAP & |
428 | le64_to_cpu(tcon->fsUnixInfo.Capability))) { | 486 | le64_to_cpu(tcon->fsUnixInfo.Capability))) { |
429 | int oflags = (int) cifs_posix_convert_flags(file->f_flags); | 487 | |
430 | /* can not refresh inode info since size could be stale */ | 488 | /* |
489 | * O_CREAT, O_EXCL and O_TRUNC already had their effect on the | ||
490 | * original open. Must mask them off for a reopen. | ||
491 | */ | ||
492 | unsigned int oflags = file->f_flags & ~(O_CREAT|O_EXCL|O_TRUNC); | ||
493 | |||
431 | rc = cifs_posix_open(full_path, NULL, inode->i_sb, | 494 | rc = cifs_posix_open(full_path, NULL, inode->i_sb, |
432 | cifs_sb->mnt_file_mode /* ignored */, | 495 | cifs_sb->mnt_file_mode /* ignored */, |
433 | oflags, &oplock, &netfid, xid); | 496 | oflags, &oplock, &netfid, xid); |