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 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
497static 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
512static 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
530struct 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};