aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs/dir.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/cifs/dir.c')
-rw-r--r--fs/cifs/dir.c108
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
498static 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
513static 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
531struct 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};