diff options
Diffstat (limited to 'fs/cifs/dir.c')
-rw-r--r-- | fs/cifs/dir.c | 189 |
1 files changed, 54 insertions, 135 deletions
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index f54e1866f0f4..e3137aa48cdd 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c | |||
@@ -101,68 +101,15 @@ cifs_bp_rename_retry: | |||
101 | return full_path; | 101 | return full_path; |
102 | } | 102 | } |
103 | 103 | ||
104 | /* Note: caller must free return buffer */ | 104 | /* char * build_wildcard_path_from_dentry(struct dentry *direntry) |
105 | char * | ||
106 | build_wildcard_path_from_dentry(struct dentry *direntry) | ||
107 | { | 105 | { |
108 | struct dentry *temp; | ||
109 | int namelen = 0; | ||
110 | char *full_path; | ||
111 | |||
112 | if(direntry == NULL) | ||
113 | return NULL; /* not much we can do if dentry is freed and | ||
114 | we need to reopen the file after it was closed implicitly | ||
115 | when the server crashed */ | ||
116 | |||
117 | cifs_bwp_rename_retry: | ||
118 | for (temp = direntry; !IS_ROOT(temp);) { | ||
119 | namelen += (1 + temp->d_name.len); | ||
120 | temp = temp->d_parent; | ||
121 | if(temp == NULL) { | ||
122 | cERROR(1,("corrupt dentry")); | ||
123 | return NULL; | ||
124 | } | ||
125 | } | ||
126 | |||
127 | full_path = kmalloc(namelen+3, GFP_KERNEL); | ||
128 | if(full_path == NULL) | 106 | if(full_path == NULL) |
129 | return full_path; | 107 | return full_path; |
130 | 108 | ||
131 | full_path[namelen] = '\\'; | 109 | full_path[namelen] = '\\'; |
132 | full_path[namelen+1] = '*'; | 110 | full_path[namelen+1] = '*'; |
133 | full_path[namelen+2] = 0; /* trailing null */ | 111 | full_path[namelen+2] = 0; |
134 | 112 | BB remove above eight lines BB */ | |
135 | for (temp = direntry; !IS_ROOT(temp);) { | ||
136 | namelen -= 1 + temp->d_name.len; | ||
137 | if (namelen < 0) { | ||
138 | break; | ||
139 | } else { | ||
140 | full_path[namelen] = '\\'; | ||
141 | strncpy(full_path + namelen + 1, temp->d_name.name, | ||
142 | temp->d_name.len); | ||
143 | cFYI(0, (" name: %s ", full_path + namelen)); | ||
144 | } | ||
145 | temp = temp->d_parent; | ||
146 | if(temp == NULL) { | ||
147 | cERROR(1,("corrupt dentry")); | ||
148 | kfree(full_path); | ||
149 | return NULL; | ||
150 | } | ||
151 | } | ||
152 | if (namelen != 0) { | ||
153 | cERROR(1, | ||
154 | ("We did not end path lookup where we expected namelen is %d", | ||
155 | namelen)); | ||
156 | /* presumably this is only possible if we were racing with a rename | ||
157 | of one of the parent directories (we can not lock the dentries | ||
158 | above us to prevent this, but retrying should be harmless) */ | ||
159 | kfree(full_path); | ||
160 | namelen = 0; | ||
161 | goto cifs_bwp_rename_retry; | ||
162 | } | ||
163 | |||
164 | return full_path; | ||
165 | } | ||
166 | 113 | ||
167 | /* Inode operations in similar order to how they appear in the Linux file fs.h */ | 114 | /* Inode operations in similar order to how they appear in the Linux file fs.h */ |
168 | 115 | ||
@@ -235,7 +182,8 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, | |||
235 | 182 | ||
236 | rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, | 183 | rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, |
237 | desiredAccess, CREATE_NOT_DIR, | 184 | desiredAccess, CREATE_NOT_DIR, |
238 | &fileHandle, &oplock, buf, cifs_sb->local_nls); | 185 | &fileHandle, &oplock, buf, cifs_sb->local_nls, |
186 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
239 | if (rc) { | 187 | if (rc) { |
240 | cFYI(1, ("cifs_create returned 0x%x ", rc)); | 188 | cFYI(1, ("cifs_create returned 0x%x ", rc)); |
241 | } else { | 189 | } else { |
@@ -248,13 +196,17 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, | |||
248 | (__u64)current->euid, | 196 | (__u64)current->euid, |
249 | (__u64)current->egid, | 197 | (__u64)current->egid, |
250 | 0 /* dev */, | 198 | 0 /* dev */, |
251 | cifs_sb->local_nls); | 199 | cifs_sb->local_nls, |
200 | cifs_sb->mnt_cifs_flags & | ||
201 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
252 | } else { | 202 | } else { |
253 | CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, | 203 | CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, |
254 | (__u64)-1, | 204 | (__u64)-1, |
255 | (__u64)-1, | 205 | (__u64)-1, |
256 | 0 /* dev */, | 206 | 0 /* dev */, |
257 | cifs_sb->local_nls); | 207 | cifs_sb->local_nls, |
208 | cifs_sb->mnt_cifs_flags & | ||
209 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
258 | } | 210 | } |
259 | else { | 211 | else { |
260 | /* BB implement via Windows security descriptors */ | 212 | /* BB implement via Windows security descriptors */ |
@@ -284,51 +236,48 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, | |||
284 | /* mknod case - do not leave file open */ | 236 | /* mknod case - do not leave file open */ |
285 | CIFSSMBClose(xid, pTcon, fileHandle); | 237 | CIFSSMBClose(xid, pTcon, fileHandle); |
286 | } else if(newinode) { | 238 | } else if(newinode) { |
287 | pCifsFile = (struct cifsFileInfo *) | 239 | pCifsFile = |
288 | kmalloc(sizeof (struct cifsFileInfo), GFP_KERNEL); | 240 | kmalloc(sizeof (struct cifsFileInfo), GFP_KERNEL); |
289 | 241 | ||
290 | if (pCifsFile) { | 242 | if(pCifsFile == NULL) |
291 | memset((char *)pCifsFile, 0, | 243 | goto cifs_create_out; |
292 | sizeof (struct cifsFileInfo)); | 244 | memset((char *)pCifsFile, 0, |
293 | pCifsFile->netfid = fileHandle; | 245 | sizeof (struct cifsFileInfo)); |
294 | pCifsFile->pid = current->tgid; | 246 | pCifsFile->netfid = fileHandle; |
295 | pCifsFile->pInode = newinode; | 247 | pCifsFile->pid = current->tgid; |
296 | pCifsFile->invalidHandle = FALSE; | 248 | pCifsFile->pInode = newinode; |
297 | pCifsFile->closePend = FALSE; | 249 | pCifsFile->invalidHandle = FALSE; |
298 | init_MUTEX(&pCifsFile->fh_sem); | 250 | pCifsFile->closePend = FALSE; |
299 | /* put the following in at open now */ | 251 | init_MUTEX(&pCifsFile->fh_sem); |
300 | /* pCifsFile->pfile = file; */ | 252 | /* set the following in open now |
301 | write_lock(&GlobalSMBSeslock); | 253 | pCifsFile->pfile = file; */ |
302 | list_add(&pCifsFile->tlist,&pTcon->openFileList); | 254 | write_lock(&GlobalSMBSeslock); |
303 | pCifsInode = CIFS_I(newinode); | 255 | list_add(&pCifsFile->tlist,&pTcon->openFileList); |
304 | if(pCifsInode) { | 256 | pCifsInode = CIFS_I(newinode); |
257 | if(pCifsInode) { | ||
305 | /* if readable file instance put first in list*/ | 258 | /* if readable file instance put first in list*/ |
306 | if (write_only == TRUE) { | 259 | if (write_only == TRUE) { |
307 | list_add_tail(&pCifsFile->flist, | 260 | list_add_tail(&pCifsFile->flist, |
308 | &pCifsInode->openFileList); | 261 | &pCifsInode->openFileList); |
309 | } else { | 262 | } else { |
310 | list_add(&pCifsFile->flist, | 263 | list_add(&pCifsFile->flist, |
311 | &pCifsInode->openFileList); | 264 | &pCifsInode->openFileList); |
312 | } | ||
313 | if((oplock & 0xF) == OPLOCK_EXCLUSIVE) { | ||
314 | pCifsInode->clientCanCacheAll = TRUE; | ||
315 | pCifsInode->clientCanCacheRead = TRUE; | ||
316 | cFYI(1,("Exclusive Oplock granted on inode %p", | ||
317 | newinode)); | ||
318 | } else if((oplock & 0xF) == OPLOCK_READ) | ||
319 | pCifsInode->clientCanCacheRead = TRUE; | ||
320 | } | 265 | } |
321 | write_unlock(&GlobalSMBSeslock); | 266 | if((oplock & 0xF) == OPLOCK_EXCLUSIVE) { |
267 | pCifsInode->clientCanCacheAll = TRUE; | ||
268 | pCifsInode->clientCanCacheRead = TRUE; | ||
269 | cFYI(1,("Exclusive Oplock for inode %p", | ||
270 | newinode)); | ||
271 | } else if((oplock & 0xF) == OPLOCK_READ) | ||
272 | pCifsInode->clientCanCacheRead = TRUE; | ||
322 | } | 273 | } |
274 | write_unlock(&GlobalSMBSeslock); | ||
323 | } | 275 | } |
324 | } | 276 | } |
325 | 277 | cifs_create_out: | |
326 | if (buf) | 278 | kfree(buf); |
327 | kfree(buf); | 279 | kfree(full_path); |
328 | if (full_path) | ||
329 | kfree(full_path); | ||
330 | FreeXid(xid); | 280 | FreeXid(xid); |
331 | |||
332 | return rc; | 281 | return rc; |
333 | } | 282 | } |
334 | 283 | ||
@@ -359,11 +308,15 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, dev_t dev | |||
359 | if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { | 308 | if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { |
360 | rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path, | 309 | rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path, |
361 | mode,(__u64)current->euid,(__u64)current->egid, | 310 | mode,(__u64)current->euid,(__u64)current->egid, |
362 | device_number, cifs_sb->local_nls); | 311 | device_number, cifs_sb->local_nls, |
312 | cifs_sb->mnt_cifs_flags & | ||
313 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
363 | } else { | 314 | } else { |
364 | rc = CIFSSMBUnixSetPerms(xid, pTcon, | 315 | rc = CIFSSMBUnixSetPerms(xid, pTcon, |
365 | full_path, mode, (__u64)-1, (__u64)-1, | 316 | full_path, mode, (__u64)-1, (__u64)-1, |
366 | device_number, cifs_sb->local_nls); | 317 | device_number, cifs_sb->local_nls, |
318 | cifs_sb->mnt_cifs_flags & | ||
319 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
367 | } | 320 | } |
368 | 321 | ||
369 | if(!rc) { | 322 | if(!rc) { |
@@ -375,10 +328,8 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, dev_t dev | |||
375 | } | 328 | } |
376 | } | 329 | } |
377 | 330 | ||
378 | if (full_path) | 331 | kfree(full_path); |
379 | kfree(full_path); | ||
380 | FreeXid(xid); | 332 | FreeXid(xid); |
381 | |||
382 | return rc; | 333 | return rc; |
383 | } | 334 | } |
384 | 335 | ||
@@ -447,43 +398,11 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, struct name | |||
447 | if file exists or not but no access BB */ | 398 | if file exists or not but no access BB */ |
448 | } | 399 | } |
449 | 400 | ||
450 | if (full_path) | 401 | kfree(full_path); |
451 | kfree(full_path); | ||
452 | FreeXid(xid); | 402 | FreeXid(xid); |
453 | return ERR_PTR(rc); | 403 | return ERR_PTR(rc); |
454 | } | 404 | } |
455 | 405 | ||
456 | int | ||
457 | cifs_dir_open(struct inode *inode, struct file *file) | ||
458 | { /* NB: currently unused since searches are opened in readdir */ | ||
459 | int rc = 0; | ||
460 | int xid; | ||
461 | struct cifs_sb_info *cifs_sb; | ||
462 | struct cifsTconInfo *pTcon; | ||
463 | char *full_path = NULL; | ||
464 | |||
465 | xid = GetXid(); | ||
466 | |||
467 | cifs_sb = CIFS_SB(inode->i_sb); | ||
468 | pTcon = cifs_sb->tcon; | ||
469 | |||
470 | if(file->f_dentry) { | ||
471 | down(&file->f_dentry->d_sb->s_vfs_rename_sem); | ||
472 | full_path = build_wildcard_path_from_dentry(file->f_dentry); | ||
473 | up(&file->f_dentry->d_sb->s_vfs_rename_sem); | ||
474 | } else { | ||
475 | FreeXid(xid); | ||
476 | return -EIO; | ||
477 | } | ||
478 | |||
479 | cFYI(1, ("inode = 0x%p and full path is %s", inode, full_path)); | ||
480 | |||
481 | if (full_path) | ||
482 | kfree(full_path); | ||
483 | FreeXid(xid); | ||
484 | return rc; | ||
485 | } | ||
486 | |||
487 | static int | 406 | static int |
488 | cifs_d_revalidate(struct dentry *direntry, struct nameidata *nd) | 407 | cifs_d_revalidate(struct dentry *direntry, struct nameidata *nd) |
489 | { | 408 | { |