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