diff options
Diffstat (limited to 'fs/cifs/dir.c')
-rw-r--r-- | fs/cifs/dir.c | 108 |
1 files changed, 100 insertions, 8 deletions
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index d335269bd91c..8dfe717a332a 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c | |||
@@ -48,6 +48,7 @@ build_path_from_dentry(struct dentry *direntry) | |||
48 | struct dentry *temp; | 48 | struct dentry *temp; |
49 | int namelen = 0; | 49 | int namelen = 0; |
50 | char *full_path; | 50 | char *full_path; |
51 | char dirsep = CIFS_DIR_SEP(CIFS_SB(direntry->d_sb)); | ||
51 | 52 | ||
52 | if(direntry == NULL) | 53 | if(direntry == NULL) |
53 | return NULL; /* not much we can do if dentry is freed and | 54 | return NULL; /* not much we can do if dentry is freed and |
@@ -74,7 +75,7 @@ cifs_bp_rename_retry: | |||
74 | if (namelen < 0) { | 75 | if (namelen < 0) { |
75 | break; | 76 | break; |
76 | } else { | 77 | } else { |
77 | full_path[namelen] = '\\'; | 78 | full_path[namelen] = dirsep; |
78 | strncpy(full_path + namelen + 1, temp->d_name.name, | 79 | strncpy(full_path + namelen + 1, temp->d_name.name, |
79 | temp->d_name.len); | 80 | temp->d_name.len); |
80 | cFYI(0, (" name: %s ", full_path + namelen)); | 81 | cFYI(0, (" name: %s ", full_path + namelen)); |
@@ -183,6 +184,13 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, | |||
183 | desiredAccess, CREATE_NOT_DIR, | 184 | desiredAccess, CREATE_NOT_DIR, |
184 | &fileHandle, &oplock, buf, cifs_sb->local_nls, | 185 | &fileHandle, &oplock, buf, cifs_sb->local_nls, |
185 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); | 186 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); |
187 | if(rc == -EIO) { | ||
188 | /* old server, retry the open legacy style */ | ||
189 | rc = SMBLegacyOpen(xid, pTcon, full_path, disposition, | ||
190 | desiredAccess, CREATE_NOT_DIR, | ||
191 | &fileHandle, &oplock, buf, cifs_sb->local_nls, | ||
192 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
193 | } | ||
186 | if (rc) { | 194 | if (rc) { |
187 | cFYI(1, ("cifs_create returned 0x%x ", rc)); | 195 | cFYI(1, ("cifs_create returned 0x%x ", rc)); |
188 | } else { | 196 | } else { |
@@ -208,7 +216,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, | |||
208 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 216 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
209 | } | 217 | } |
210 | else { | 218 | else { |
211 | /* BB implement via Windows security descriptors */ | 219 | /* BB implement mode setting via Windows security descriptors */ |
212 | /* eg CIFSSMBWinSetPerms(xid,pTcon,full_path,mode,-1,-1,local_nls);*/ | 220 | /* eg CIFSSMBWinSetPerms(xid,pTcon,full_path,mode,-1,-1,local_nls);*/ |
213 | /* could set r/o dos attribute if mode & 0222 == 0 */ | 221 | /* could set r/o dos attribute if mode & 0222 == 0 */ |
214 | } | 222 | } |
@@ -225,10 +233,14 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, | |||
225 | } | 233 | } |
226 | 234 | ||
227 | if (rc != 0) { | 235 | if (rc != 0) { |
228 | cFYI(1,("Create worked but get_inode_info failed with rc = %d", | 236 | cFYI(1, |
237 | ("Create worked but get_inode_info failed rc = %d", | ||
229 | rc)); | 238 | rc)); |
230 | } else { | 239 | } else { |
231 | direntry->d_op = &cifs_dentry_ops; | 240 | if (pTcon->nocase) |
241 | direntry->d_op = &cifs_ci_dentry_ops; | ||
242 | else | ||
243 | direntry->d_op = &cifs_dentry_ops; | ||
232 | d_instantiate(direntry, newinode); | 244 | d_instantiate(direntry, newinode); |
233 | } | 245 | } |
234 | if((nd->flags & LOOKUP_OPEN) == FALSE) { | 246 | if((nd->flags & LOOKUP_OPEN) == FALSE) { |
@@ -302,8 +314,7 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, dev_t dev | |||
302 | up(&direntry->d_sb->s_vfs_rename_sem); | 314 | up(&direntry->d_sb->s_vfs_rename_sem); |
303 | if(full_path == NULL) | 315 | if(full_path == NULL) |
304 | rc = -ENOMEM; | 316 | rc = -ENOMEM; |
305 | 317 | else if (pTcon->ses->capabilities & CAP_UNIX) { | |
306 | if (full_path && (pTcon->ses->capabilities & CAP_UNIX)) { | ||
307 | if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { | 318 | if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { |
308 | rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path, | 319 | rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path, |
309 | mode,(__u64)current->euid,(__u64)current->egid, | 320 | mode,(__u64)current->euid,(__u64)current->egid, |
@@ -321,10 +332,49 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, dev_t dev | |||
321 | if(!rc) { | 332 | if(!rc) { |
322 | rc = cifs_get_inode_info_unix(&newinode, full_path, | 333 | rc = cifs_get_inode_info_unix(&newinode, full_path, |
323 | inode->i_sb,xid); | 334 | inode->i_sb,xid); |
324 | direntry->d_op = &cifs_dentry_ops; | 335 | if (pTcon->nocase) |
336 | direntry->d_op = &cifs_ci_dentry_ops; | ||
337 | else | ||
338 | direntry->d_op = &cifs_dentry_ops; | ||
325 | if(rc == 0) | 339 | if(rc == 0) |
326 | d_instantiate(direntry, newinode); | 340 | d_instantiate(direntry, newinode); |
327 | } | 341 | } |
342 | } else { | ||
343 | if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) { | ||
344 | int oplock = 0; | ||
345 | u16 fileHandle; | ||
346 | FILE_ALL_INFO * buf; | ||
347 | |||
348 | cFYI(1,("sfu compat create special file")); | ||
349 | |||
350 | buf = kmalloc(sizeof(FILE_ALL_INFO),GFP_KERNEL); | ||
351 | if(buf == NULL) { | ||
352 | kfree(full_path); | ||
353 | FreeXid(xid); | ||
354 | return -ENOMEM; | ||
355 | } | ||
356 | |||
357 | rc = CIFSSMBOpen(xid, pTcon, full_path, | ||
358 | FILE_CREATE, /* fail if exists */ | ||
359 | GENERIC_WRITE /* BB would | ||
360 | WRITE_OWNER | WRITE_DAC be better? */, | ||
361 | /* Create a file and set the | ||
362 | file attribute to SYSTEM */ | ||
363 | CREATE_NOT_DIR | CREATE_OPTION_SPECIAL, | ||
364 | &fileHandle, &oplock, buf, | ||
365 | cifs_sb->local_nls, | ||
366 | cifs_sb->mnt_cifs_flags & | ||
367 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
368 | |||
369 | if(!rc) { | ||
370 | /* BB Do not bother to decode buf since no | ||
371 | local inode yet to put timestamps in */ | ||
372 | CIFSSMBClose(xid, pTcon, fileHandle); | ||
373 | d_drop(direntry); | ||
374 | } | ||
375 | kfree(buf); | ||
376 | /* add code here to set EAs */ | ||
377 | } | ||
328 | } | 378 | } |
329 | 379 | ||
330 | kfree(full_path); | 380 | kfree(full_path); |
@@ -381,7 +431,10 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, struct name | |||
381 | parent_dir_inode->i_sb,xid); | 431 | parent_dir_inode->i_sb,xid); |
382 | 432 | ||
383 | if ((rc == 0) && (newInode != NULL)) { | 433 | if ((rc == 0) && (newInode != NULL)) { |
384 | direntry->d_op = &cifs_dentry_ops; | 434 | if (pTcon->nocase) |
435 | direntry->d_op = &cifs_ci_dentry_ops; | ||
436 | else | ||
437 | direntry->d_op = &cifs_dentry_ops; | ||
385 | d_add(direntry, newInode); | 438 | d_add(direntry, newInode); |
386 | 439 | ||
387 | /* since paths are not looked up by component - the parent directories are presumed to be good here */ | 440 | /* since paths are not looked up by component - the parent directories are presumed to be good here */ |
@@ -440,3 +493,42 @@ struct dentry_operations cifs_dentry_ops = { | |||
440 | /* d_delete: cifs_d_delete, *//* not needed except for debugging */ | 493 | /* d_delete: cifs_d_delete, *//* not needed except for debugging */ |
441 | /* no need for d_hash, d_compare, d_release, d_iput ... yet. BB confirm this BB */ | 494 | /* no need for d_hash, d_compare, d_release, d_iput ... yet. BB confirm this BB */ |
442 | }; | 495 | }; |
496 | |||
497 | static int cifs_ci_hash(struct dentry *dentry, struct qstr *q) | ||
498 | { | ||
499 | struct nls_table *codepage = CIFS_SB(dentry->d_inode->i_sb)->local_nls; | ||
500 | unsigned long hash; | ||
501 | int i; | ||
502 | |||
503 | hash = init_name_hash(); | ||
504 | for (i = 0; i < q->len; i++) | ||
505 | hash = partial_name_hash(nls_tolower(codepage, q->name[i]), | ||
506 | hash); | ||
507 | q->hash = end_name_hash(hash); | ||
508 | |||
509 | return 0; | ||
510 | } | ||
511 | |||
512 | static int cifs_ci_compare(struct dentry *dentry, struct qstr *a, | ||
513 | struct qstr *b) | ||
514 | { | ||
515 | struct nls_table *codepage = CIFS_SB(dentry->d_inode->i_sb)->local_nls; | ||
516 | |||
517 | if ((a->len == b->len) && | ||
518 | (nls_strnicmp(codepage, a->name, b->name, a->len) == 0)) { | ||
519 | /* | ||
520 | * To preserve case, don't let an existing negative dentry's | ||
521 | * case take precedence. If a is not a negative dentry, this | ||
522 | * should have no side effects | ||
523 | */ | ||
524 | memcpy((unsigned char *)a->name, b->name, a->len); | ||
525 | return 0; | ||
526 | } | ||
527 | return 1; | ||
528 | } | ||
529 | |||
530 | struct dentry_operations cifs_ci_dentry_ops = { | ||
531 | .d_revalidate = cifs_d_revalidate, | ||
532 | .d_hash = cifs_ci_hash, | ||
533 | .d_compare = cifs_ci_compare, | ||
534 | }; | ||