diff options
Diffstat (limited to 'fs/cifs/readdir.c')
-rw-r--r-- | fs/cifs/readdir.c | 84 |
1 files changed, 65 insertions, 19 deletions
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index 22557716f9af..a86bd1c07602 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c | |||
@@ -91,7 +91,10 @@ static int construct_dentry(struct qstr *qstring, struct file *file, | |||
91 | } | 91 | } |
92 | 92 | ||
93 | *ptmp_inode = new_inode(file->f_dentry->d_sb); | 93 | *ptmp_inode = new_inode(file->f_dentry->d_sb); |
94 | tmp_dentry->d_op = &cifs_dentry_ops; | 94 | if (pTcon->nocase) |
95 | tmp_dentry->d_op = &cifs_ci_dentry_ops; | ||
96 | else | ||
97 | tmp_dentry->d_op = &cifs_dentry_ops; | ||
95 | if(*ptmp_inode == NULL) | 98 | if(*ptmp_inode == NULL) |
96 | return rc; | 99 | return rc; |
97 | rc = 1; | 100 | rc = 1; |
@@ -148,6 +151,13 @@ static void fill_in_inode(struct inode *tmp_inode, | |||
148 | tmp_inode->i_mode = cifs_sb->mnt_dir_mode; | 151 | tmp_inode->i_mode = cifs_sb->mnt_dir_mode; |
149 | } | 152 | } |
150 | tmp_inode->i_mode |= S_IFDIR; | 153 | tmp_inode->i_mode |= S_IFDIR; |
154 | } else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) && | ||
155 | (attr & ATTR_SYSTEM) && (end_of_file == 0)) { | ||
156 | *pobject_type = DT_FIFO; | ||
157 | tmp_inode->i_mode |= S_IFIFO; | ||
158 | /* BB Finish for SFU style symlinks and devies */ | ||
159 | /* } else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) && | ||
160 | (attr & ATTR_SYSTEM) && ) { */ | ||
151 | /* we no longer mark these because we could not follow them */ | 161 | /* we no longer mark these because we could not follow them */ |
152 | /* } else if (attr & ATTR_REPARSE) { | 162 | /* } else if (attr & ATTR_REPARSE) { |
153 | *pobject_type = DT_LNK; | 163 | *pobject_type = DT_LNK; |
@@ -187,11 +197,17 @@ static void fill_in_inode(struct inode *tmp_inode, | |||
187 | tmp_inode->i_fop = &cifs_file_direct_ops; | 197 | tmp_inode->i_fop = &cifs_file_direct_ops; |
188 | else | 198 | else |
189 | tmp_inode->i_fop = &cifs_file_ops; | 199 | tmp_inode->i_fop = &cifs_file_ops; |
200 | if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) | ||
201 | tmp_inode->i_fop->lock = NULL; | ||
190 | tmp_inode->i_data.a_ops = &cifs_addr_ops; | 202 | tmp_inode->i_data.a_ops = &cifs_addr_ops; |
191 | 203 | if((cifs_sb->tcon) && (cifs_sb->tcon->ses) && | |
204 | (cifs_sb->tcon->ses->server->maxBuf < | ||
205 | 4096 + MAX_CIFS_HDR_SIZE)) | ||
206 | tmp_inode->i_data.a_ops->readpages = NULL; | ||
192 | if(isNewInode) | 207 | if(isNewInode) |
193 | return; /* No sense invalidating pages for new inode since we | 208 | return; /* No sense invalidating pages for new inode |
194 | have not started caching readahead file data yet */ | 209 | since have not started caching readahead file |
210 | data yet */ | ||
195 | 211 | ||
196 | if (timespec_equal(&tmp_inode->i_mtime, &local_mtime) && | 212 | if (timespec_equal(&tmp_inode->i_mtime, &local_mtime) && |
197 | (local_size == tmp_inode->i_size)) { | 213 | (local_size == tmp_inode->i_size)) { |
@@ -290,7 +306,13 @@ static void unix_fill_in_inode(struct inode *tmp_inode, | |||
290 | tmp_inode->i_fop = &cifs_file_direct_ops; | 306 | tmp_inode->i_fop = &cifs_file_direct_ops; |
291 | else | 307 | else |
292 | tmp_inode->i_fop = &cifs_file_ops; | 308 | tmp_inode->i_fop = &cifs_file_ops; |
309 | if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) | ||
310 | tmp_inode->i_fop->lock = NULL; | ||
293 | tmp_inode->i_data.a_ops = &cifs_addr_ops; | 311 | tmp_inode->i_data.a_ops = &cifs_addr_ops; |
312 | if((cifs_sb->tcon) && (cifs_sb->tcon->ses) && | ||
313 | (cifs_sb->tcon->ses->server->maxBuf < | ||
314 | 4096 + MAX_CIFS_HDR_SIZE)) | ||
315 | tmp_inode->i_data.a_ops->readpages = NULL; | ||
294 | 316 | ||
295 | if(isNewInode) | 317 | if(isNewInode) |
296 | return; /* No sense invalidating pages for new inode since we | 318 | return; /* No sense invalidating pages for new inode since we |
@@ -374,7 +396,8 @@ ffirst_retry: | |||
374 | 396 | ||
375 | rc = CIFSFindFirst(xid, pTcon,full_path,cifs_sb->local_nls, | 397 | rc = CIFSFindFirst(xid, pTcon,full_path,cifs_sb->local_nls, |
376 | &cifsFile->netfid, &cifsFile->srch_inf, | 398 | &cifsFile->netfid, &cifsFile->srch_inf, |
377 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); | 399 | cifs_sb->mnt_cifs_flags & |
400 | CIFS_MOUNT_MAP_SPECIAL_CHR, CIFS_DIR_SEP(cifs_sb)); | ||
378 | if(rc == 0) | 401 | if(rc == 0) |
379 | cifsFile->invalidHandle = FALSE; | 402 | cifsFile->invalidHandle = FALSE; |
380 | if((rc == -EOPNOTSUPP) && | 403 | if((rc == -EOPNOTSUPP) && |
@@ -491,6 +514,30 @@ static int cifs_entry_is_dot(char *current_entry, struct cifsFileInfo *cfile) | |||
491 | return rc; | 514 | return rc; |
492 | } | 515 | } |
493 | 516 | ||
517 | /* Check if directory that we are searching has changed so we can decide | ||
518 | whether we can use the cached search results from the previous search */ | ||
519 | static int is_dir_changed(struct file * file) | ||
520 | { | ||
521 | struct inode * inode; | ||
522 | struct cifsInodeInfo *cifsInfo; | ||
523 | |||
524 | if(file->f_dentry == NULL) | ||
525 | return 0; | ||
526 | |||
527 | inode = file->f_dentry->d_inode; | ||
528 | |||
529 | if(inode == NULL) | ||
530 | return 0; | ||
531 | |||
532 | cifsInfo = CIFS_I(inode); | ||
533 | |||
534 | if(cifsInfo->time == 0) | ||
535 | return 1; /* directory was changed, perhaps due to unlink */ | ||
536 | else | ||
537 | return 0; | ||
538 | |||
539 | } | ||
540 | |||
494 | /* find the corresponding entry in the search */ | 541 | /* find the corresponding entry in the search */ |
495 | /* Note that the SMB server returns search entries for . and .. which | 542 | /* Note that the SMB server returns search entries for . and .. which |
496 | complicates logic here if we choose to parse for them and we do not | 543 | complicates logic here if we choose to parse for them and we do not |
@@ -507,7 +554,8 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon, | |||
507 | struct cifsFileInfo * cifsFile = file->private_data; | 554 | struct cifsFileInfo * cifsFile = file->private_data; |
508 | /* check if index in the buffer */ | 555 | /* check if index in the buffer */ |
509 | 556 | ||
510 | if((cifsFile == NULL) || (ppCurrentEntry == NULL) || (num_to_ret == NULL)) | 557 | if((cifsFile == NULL) || (ppCurrentEntry == NULL) || |
558 | (num_to_ret == NULL)) | ||
511 | return -ENOENT; | 559 | return -ENOENT; |
512 | 560 | ||
513 | *ppCurrentEntry = NULL; | 561 | *ppCurrentEntry = NULL; |
@@ -515,7 +563,9 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon, | |||
515 | cifsFile->srch_inf.index_of_last_entry - | 563 | cifsFile->srch_inf.index_of_last_entry - |
516 | cifsFile->srch_inf.entries_in_buffer; | 564 | cifsFile->srch_inf.entries_in_buffer; |
517 | /* dump_cifs_file_struct(file, "In fce ");*/ | 565 | /* dump_cifs_file_struct(file, "In fce ");*/ |
518 | if(index_to_find < first_entry_in_buffer) { | 566 | if(((index_to_find < cifsFile->srch_inf.index_of_last_entry) && |
567 | is_dir_changed(file)) || | ||
568 | (index_to_find < first_entry_in_buffer)) { | ||
519 | /* close and restart search */ | 569 | /* close and restart search */ |
520 | cFYI(1,("search backing up - close and restart search")); | 570 | cFYI(1,("search backing up - close and restart search")); |
521 | cifsFile->invalidHandle = TRUE; | 571 | cifsFile->invalidHandle = TRUE; |
@@ -536,7 +586,8 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon, | |||
536 | while((index_to_find >= cifsFile->srch_inf.index_of_last_entry) && | 586 | while((index_to_find >= cifsFile->srch_inf.index_of_last_entry) && |
537 | (rc == 0) && (cifsFile->srch_inf.endOfSearch == FALSE)){ | 587 | (rc == 0) && (cifsFile->srch_inf.endOfSearch == FALSE)){ |
538 | cFYI(1,("calling findnext2")); | 588 | cFYI(1,("calling findnext2")); |
539 | rc = CIFSFindNext(xid,pTcon,cifsFile->netfid, &cifsFile->srch_inf); | 589 | rc = CIFSFindNext(xid,pTcon,cifsFile->netfid, |
590 | &cifsFile->srch_inf); | ||
540 | if(rc) | 591 | if(rc) |
541 | return -ENOENT; | 592 | return -ENOENT; |
542 | } | 593 | } |
@@ -548,14 +599,13 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon, | |||
548 | char * end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + | 599 | char * end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + |
549 | smbCalcSize((struct smb_hdr *) | 600 | smbCalcSize((struct smb_hdr *) |
550 | cifsFile->srch_inf.ntwrk_buf_start); | 601 | cifsFile->srch_inf.ntwrk_buf_start); |
551 | /* dump_cifs_file_struct(file,"found entry in fce "); */ | ||
552 | first_entry_in_buffer = cifsFile->srch_inf.index_of_last_entry | 602 | first_entry_in_buffer = cifsFile->srch_inf.index_of_last_entry |
553 | - cifsFile->srch_inf.entries_in_buffer; | 603 | - cifsFile->srch_inf.entries_in_buffer; |
554 | pos_in_buf = index_to_find - first_entry_in_buffer; | 604 | pos_in_buf = index_to_find - first_entry_in_buffer; |
555 | cFYI(1,("found entry - pos_in_buf %d",pos_in_buf)); | 605 | cFYI(1,("found entry - pos_in_buf %d",pos_in_buf)); |
556 | current_entry = cifsFile->srch_inf.srch_entries_start; | 606 | current_entry = cifsFile->srch_inf.srch_entries_start; |
557 | for(i=0;(i<(pos_in_buf)) && (current_entry != NULL);i++) { | 607 | for(i=0;(i<(pos_in_buf)) && (current_entry != NULL);i++) { |
558 | /* go entry to next entry figuring out which we need to start with */ | 608 | /* go entry by entry figuring out which is first */ |
559 | /* if( . or ..) | 609 | /* if( . or ..) |
560 | skip */ | 610 | skip */ |
561 | rc = cifs_entry_is_dot(current_entry,cifsFile); | 611 | rc = cifs_entry_is_dot(current_entry,cifsFile); |
@@ -582,11 +632,10 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon, | |||
582 | } | 632 | } |
583 | 633 | ||
584 | if(pos_in_buf >= cifsFile->srch_inf.entries_in_buffer) { | 634 | if(pos_in_buf >= cifsFile->srch_inf.entries_in_buffer) { |
585 | cFYI(1,("can not return entries when pos_in_buf beyond last entry")); | 635 | cFYI(1,("can not return entries pos_in_buf beyond last entry")); |
586 | *num_to_ret = 0; | 636 | *num_to_ret = 0; |
587 | } else | 637 | } else |
588 | *num_to_ret = cifsFile->srch_inf.entries_in_buffer - pos_in_buf; | 638 | *num_to_ret = cifsFile->srch_inf.entries_in_buffer - pos_in_buf; |
589 | /* dump_cifs_file_struct(file, "end fce ");*/ | ||
590 | 639 | ||
591 | return rc; | 640 | return rc; |
592 | } | 641 | } |
@@ -721,7 +770,8 @@ static int cifs_filldir(char *pfindEntry, struct file *file, | |||
721 | (FILE_DIRECTORY_INFO *)pfindEntry,&obj_type, rc); | 770 | (FILE_DIRECTORY_INFO *)pfindEntry,&obj_type, rc); |
722 | } | 771 | } |
723 | 772 | ||
724 | rc = filldir(direntry,qstring.name,qstring.len,file->f_pos,tmp_inode->i_ino,obj_type); | 773 | rc = filldir(direntry,qstring.name,qstring.len,file->f_pos, |
774 | tmp_inode->i_ino,obj_type); | ||
725 | if(rc) { | 775 | if(rc) { |
726 | cFYI(1,("filldir rc = %d",rc)); | 776 | cFYI(1,("filldir rc = %d",rc)); |
727 | } | 777 | } |
@@ -805,15 +855,12 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) | |||
805 | FreeXid(xid); | 855 | FreeXid(xid); |
806 | return -EIO; | 856 | return -EIO; |
807 | } | 857 | } |
808 | /* dump_cifs_file_struct(file, "Begin rdir "); */ | ||
809 | 858 | ||
810 | cifs_sb = CIFS_SB(file->f_dentry->d_sb); | 859 | cifs_sb = CIFS_SB(file->f_dentry->d_sb); |
811 | pTcon = cifs_sb->tcon; | 860 | pTcon = cifs_sb->tcon; |
812 | if(pTcon == NULL) | 861 | if(pTcon == NULL) |
813 | return -EINVAL; | 862 | return -EINVAL; |
814 | 863 | ||
815 | /* cFYI(1,("readdir2 pos: %lld",file->f_pos)); */ | ||
816 | |||
817 | switch ((int) file->f_pos) { | 864 | switch ((int) file->f_pos) { |
818 | case 0: | 865 | case 0: |
819 | /*if (filldir(direntry, ".", 1, file->f_pos, | 866 | /*if (filldir(direntry, ".", 1, file->f_pos, |
@@ -866,7 +913,6 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) | |||
866 | cifsFile->search_resume_name = NULL; */ | 913 | cifsFile->search_resume_name = NULL; */ |
867 | 914 | ||
868 | /* BB account for . and .. in f_pos as special case */ | 915 | /* BB account for . and .. in f_pos as special case */ |
869 | /* dump_cifs_file_struct(file, "rdir after default ");*/ | ||
870 | 916 | ||
871 | rc = find_cifs_entry(xid,pTcon, file, | 917 | rc = find_cifs_entry(xid,pTcon, file, |
872 | ¤t_entry,&num_to_fill); | 918 | ¤t_entry,&num_to_fill); |
@@ -906,14 +952,14 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) | |||
906 | cifs_save_resume_key(current_entry,cifsFile); | 952 | cifs_save_resume_key(current_entry,cifsFile); |
907 | break; | 953 | break; |
908 | } else | 954 | } else |
909 | current_entry = nxt_dir_entry(current_entry,end_of_smb); | 955 | current_entry = nxt_dir_entry(current_entry, |
956 | end_of_smb); | ||
910 | } | 957 | } |
911 | kfree(tmp_buf); | 958 | kfree(tmp_buf); |
912 | break; | 959 | break; |
913 | } /* end switch */ | 960 | } /* end switch */ |
914 | 961 | ||
915 | rddir2_exit: | 962 | rddir2_exit: |
916 | /* dump_cifs_file_struct(file, "end rdir "); */ | ||
917 | FreeXid(xid); | 963 | FreeXid(xid); |
918 | return rc; | 964 | return rc; |
919 | } | 965 | } |