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.c135
1 files changed, 113 insertions, 22 deletions
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
index 3f3538d4a1fa..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));
@@ -145,24 +146,23 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
145 return -ENOMEM; 146 return -ENOMEM;
146 } 147 }
147 148
148 if(nd) { 149 if(nd && (nd->flags & LOOKUP_OPEN)) {
149 if ((nd->intent.open.flags & O_ACCMODE) == O_RDONLY) 150 int oflags = nd->intent.open.flags;
150 desiredAccess = GENERIC_READ; 151
151 else if ((nd->intent.open.flags & O_ACCMODE) == O_WRONLY) { 152 desiredAccess = 0;
152 desiredAccess = GENERIC_WRITE; 153 if (oflags & FMODE_READ)
153 write_only = TRUE; 154 desiredAccess |= GENERIC_READ;
154 } else if ((nd->intent.open.flags & O_ACCMODE) == O_RDWR) { 155 if (oflags & FMODE_WRITE) {
155 /* GENERIC_ALL is too much permission to request */ 156 desiredAccess |= GENERIC_WRITE;
156 /* can cause unnecessary access denied on create */ 157 if (!(oflags & FMODE_READ))
157 /* desiredAccess = GENERIC_ALL; */ 158 write_only = TRUE;
158 desiredAccess = GENERIC_READ | GENERIC_WRITE;
159 } 159 }
160 160
161 if((nd->intent.open.flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) 161 if((oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
162 disposition = FILE_CREATE; 162 disposition = FILE_CREATE;
163 else if((nd->intent.open.flags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC)) 163 else if((oflags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC))
164 disposition = FILE_OVERWRITE_IF; 164 disposition = FILE_OVERWRITE_IF;
165 else if((nd->intent.open.flags & O_CREAT) == O_CREAT) 165 else if((oflags & O_CREAT) == O_CREAT)
166 disposition = FILE_OPEN_IF; 166 disposition = FILE_OPEN_IF;
167 else { 167 else {
168 cFYI(1,("Create flag not set in create function")); 168 cFYI(1,("Create flag not set in create function"));
@@ -184,6 +184,13 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
184 desiredAccess, CREATE_NOT_DIR, 184 desiredAccess, CREATE_NOT_DIR,
185 &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); 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 }
187 if (rc) { 194 if (rc) {
188 cFYI(1, ("cifs_create returned 0x%x ", rc)); 195 cFYI(1, ("cifs_create returned 0x%x ", rc));
189 } else { 196 } else {
@@ -209,7 +216,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
209 CIFS_MOUNT_MAP_SPECIAL_CHR); 216 CIFS_MOUNT_MAP_SPECIAL_CHR);
210 } 217 }
211 else { 218 else {
212 /* BB implement via Windows security descriptors */ 219 /* BB implement mode setting via Windows security descriptors */
213 /* eg CIFSSMBWinSetPerms(xid,pTcon,full_path,mode,-1,-1,local_nls);*/ 220 /* eg CIFSSMBWinSetPerms(xid,pTcon,full_path,mode,-1,-1,local_nls);*/
214 /* could set r/o dos attribute if mode & 0222 == 0 */ 221 /* could set r/o dos attribute if mode & 0222 == 0 */
215 } 222 }
@@ -226,10 +233,14 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
226 } 233 }
227 234
228 if (rc != 0) { 235 if (rc != 0) {
229 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",
230 rc)); 238 rc));
231 } else { 239 } else {
232 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;
233 d_instantiate(direntry, newinode); 244 d_instantiate(direntry, newinode);
234 } 245 }
235 if((nd->flags & LOOKUP_OPEN) == FALSE) { 246 if((nd->flags & LOOKUP_OPEN) == FALSE) {
@@ -303,8 +314,7 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, dev_t dev
303 up(&direntry->d_sb->s_vfs_rename_sem); 314 up(&direntry->d_sb->s_vfs_rename_sem);
304 if(full_path == NULL) 315 if(full_path == NULL)
305 rc = -ENOMEM; 316 rc = -ENOMEM;
306 317 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) { 318 if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
309 rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path, 319 rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path,
310 mode,(__u64)current->euid,(__u64)current->egid, 320 mode,(__u64)current->euid,(__u64)current->egid,
@@ -322,10 +332,49 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, dev_t dev
322 if(!rc) { 332 if(!rc) {
323 rc = cifs_get_inode_info_unix(&newinode, full_path, 333 rc = cifs_get_inode_info_unix(&newinode, full_path,
324 inode->i_sb,xid); 334 inode->i_sb,xid);
325 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;
326 if(rc == 0) 339 if(rc == 0)
327 d_instantiate(direntry, newinode); 340 d_instantiate(direntry, newinode);
328 } 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 }
329 } 378 }
330 379
331 kfree(full_path); 380 kfree(full_path);
@@ -382,7 +431,10 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, struct name
382 parent_dir_inode->i_sb,xid); 431 parent_dir_inode->i_sb,xid);
383 432
384 if ((rc == 0) && (newInode != NULL)) { 433 if ((rc == 0) && (newInode != NULL)) {
385 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;
386 d_add(direntry, newInode); 438 d_add(direntry, newInode);
387 439
388 /* 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 */
@@ -441,3 +493,42 @@ struct dentry_operations cifs_dentry_ops = {
441/* d_delete: cifs_d_delete, *//* not needed except for debugging */ 493/* 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 */ 494 /* no need for d_hash, d_compare, d_release, d_iput ... yet. BB confirm this BB */
443}; 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};