aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs/readdir.c
diff options
context:
space:
mode:
authorSteve French <sfrench@us.ibm.com>2006-06-06 20:18:43 -0400
committerSteve French <sfrench@us.ibm.com>2006-06-06 20:18:43 -0400
commit5bafd76593f060540acbea3b61e3087e009aa269 (patch)
treeb5baf62243810b7aa36619a8cf64ab24d82952fb /fs/cifs/readdir.c
parenta8ee03441f66e0674e641c0cbe1a9534cdee968f (diff)
[CIFS] Add support for readdir to legacy servers
Fixes oops to OS/2 on ls and removes redundant NTCreateX calls to servers which do not support NT SMBs. Key operations to OS/2 work. Signed-off-by: Steve French <sfrench@us.ibm.com>
Diffstat (limited to 'fs/cifs/readdir.c')
-rw-r--r--fs/cifs/readdir.c150
1 files changed, 109 insertions, 41 deletions
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c
index e3e762d774df..03bbcb377913 100644
--- a/fs/cifs/readdir.c
+++ b/fs/cifs/readdir.c
@@ -109,32 +109,52 @@ static int construct_dentry(struct qstr *qstring, struct file *file,
109 return rc; 109 return rc;
110} 110}
111 111
112static void fill_in_inode(struct inode *tmp_inode, 112static void fill_in_inode(struct inode *tmp_inode, int new_buf_type,
113 FILE_DIRECTORY_INFO *pfindData, int *pobject_type, int isNewInode) 113 char * buf, int *pobject_type, int isNewInode)
114{ 114{
115 loff_t local_size; 115 loff_t local_size;
116 struct timespec local_mtime; 116 struct timespec local_mtime;
117 117
118 struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode); 118 struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode);
119 struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb); 119 struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb);
120 __u32 attr = le32_to_cpu(pfindData->ExtFileAttributes); 120 __u32 attr;
121 __u64 allocation_size = le64_to_cpu(pfindData->AllocationSize); 121 __u64 allocation_size;
122 __u64 end_of_file = le64_to_cpu(pfindData->EndOfFile); 122 __u64 end_of_file;
123
124 cifsInfo->cifsAttrs = attr;
125 cifsInfo->time = jiffies;
126 123
127 /* save mtime and size */ 124 /* save mtime and size */
128 local_mtime = tmp_inode->i_mtime; 125 local_mtime = tmp_inode->i_mtime;
129 local_size = tmp_inode->i_size; 126 local_size = tmp_inode->i_size;
130 127
128 if(new_buf_type) {
129 FILE_DIRECTORY_INFO *pfindData = (FILE_DIRECTORY_INFO *)buf;
130
131 attr = le32_to_cpu(pfindData->ExtFileAttributes);
132 allocation_size = le64_to_cpu(pfindData->AllocationSize);
133 end_of_file = le64_to_cpu(pfindData->EndOfFile);
134 tmp_inode->i_atime =
135 cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime));
136 tmp_inode->i_mtime =
137 cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime));
138 tmp_inode->i_ctime =
139 cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime));
140 } else { /* legacy, OS2 and DOS style */
141 FIND_FILE_STANDARD_INFO * pfindData =
142 (FIND_FILE_STANDARD_INFO *)buf;
143
144 attr = le16_to_cpu(pfindData->Attributes);
145 allocation_size = le32_to_cpu(pfindData->AllocationSize);
146 end_of_file = le32_to_cpu(pfindData->DataSize);
147 tmp_inode->i_atime = CURRENT_TIME;
148 /* tmp_inode->i_mtime = BB FIXME - add dos time handling
149 tmp_inode->i_ctime = 0; BB FIXME */
150
151 }
152
131 /* Linux can not store file creation time unfortunately so ignore it */ 153 /* Linux can not store file creation time unfortunately so ignore it */
132 tmp_inode->i_atime = 154
133 cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime)); 155 cifsInfo->cifsAttrs = attr;
134 tmp_inode->i_mtime = 156 cifsInfo->time = jiffies;
135 cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime)); 157
136 tmp_inode->i_ctime =
137 cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime));
138 /* treat dos attribute of read-only as read-only mode bit e.g. 555? */ 158 /* treat dos attribute of read-only as read-only mode bit e.g. 555? */
139 /* 2767 perms - indicate mandatory locking */ 159 /* 2767 perms - indicate mandatory locking */
140 /* BB fill in uid and gid here? with help from winbind? 160 /* BB fill in uid and gid here? with help from winbind?
@@ -420,7 +440,10 @@ static int initiate_cifs_search(const int xid, struct file *file)
420ffirst_retry: 440ffirst_retry:
421 /* test for Unix extensions */ 441 /* test for Unix extensions */
422 if (pTcon->ses->capabilities & CAP_UNIX) { 442 if (pTcon->ses->capabilities & CAP_UNIX) {
423 cifsFile->srch_inf.info_level = SMB_FIND_FILE_UNIX; 443 cifsFile->srch_inf.info_level = SMB_FIND_FILE_UNIX;
444 } else if ((pTcon->ses->capabilities &
445 (CAP_NT_SMBS | CAP_NT_FIND)) == 0) {
446 cifsFile->srch_inf.info_level = SMB_FIND_FILE_INFO_STANDARD;
424 } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) { 447 } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
425 cifsFile->srch_inf.info_level = SMB_FIND_FILE_ID_FULL_DIR_INFO; 448 cifsFile->srch_inf.info_level = SMB_FIND_FILE_ID_FULL_DIR_INFO;
426 } else /* not srvinos - BB fixme add check for backlevel? */ { 449 } else /* not srvinos - BB fixme add check for backlevel? */ {
@@ -456,12 +479,19 @@ static int cifs_unicode_bytelen(char *str)
456 return len << 1; 479 return len << 1;
457} 480}
458 481
459static char *nxt_dir_entry(char *old_entry, char *end_of_smb) 482static char *nxt_dir_entry(char *old_entry, char *end_of_smb, int level)
460{ 483{
461 char * new_entry; 484 char * new_entry;
462 FILE_DIRECTORY_INFO * pDirInfo = (FILE_DIRECTORY_INFO *)old_entry; 485 FILE_DIRECTORY_INFO * pDirInfo = (FILE_DIRECTORY_INFO *)old_entry;
463 486
464 new_entry = old_entry + le32_to_cpu(pDirInfo->NextEntryOffset); 487 if(level == SMB_FIND_FILE_INFO_STANDARD) {
488 FIND_FILE_STANDARD_INFO * pfData;
489 pfData = (FIND_FILE_STANDARD_INFO *)pDirInfo;
490
491 new_entry = old_entry + sizeof(FIND_FILE_STANDARD_INFO) +
492 pfData->FileNameLength;
493 } else
494 new_entry = old_entry + le32_to_cpu(pDirInfo->NextEntryOffset);
465 cFYI(1,("new entry %p old entry %p",new_entry,old_entry)); 495 cFYI(1,("new entry %p old entry %p",new_entry,old_entry));
466 /* validate that new_entry is not past end of SMB */ 496 /* validate that new_entry is not past end of SMB */
467 if(new_entry >= end_of_smb) { 497 if(new_entry >= end_of_smb) {
@@ -469,7 +499,10 @@ static char *nxt_dir_entry(char *old_entry, char *end_of_smb)
469 ("search entry %p began after end of SMB %p old entry %p", 499 ("search entry %p began after end of SMB %p old entry %p",
470 new_entry, end_of_smb, old_entry)); 500 new_entry, end_of_smb, old_entry));
471 return NULL; 501 return NULL;
472 } else if (new_entry + sizeof(FILE_DIRECTORY_INFO) > end_of_smb) { 502 } else if(((level == SMB_FIND_FILE_INFO_STANDARD) &&
503 (new_entry + sizeof(FIND_FILE_STANDARD_INFO) > end_of_smb)) ||
504 ((level != SMB_FIND_FILE_INFO_STANDARD) &&
505 (new_entry + sizeof(FILE_DIRECTORY_INFO) > end_of_smb))) {
473 cERROR(1,("search entry %p extends after end of SMB %p", 506 cERROR(1,("search entry %p extends after end of SMB %p",
474 new_entry, end_of_smb)); 507 new_entry, end_of_smb));
475 return NULL; 508 return NULL;
@@ -487,7 +520,7 @@ static int cifs_entry_is_dot(char *current_entry, struct cifsFileInfo *cfile)
487 char * filename = NULL; 520 char * filename = NULL;
488 int len = 0; 521 int len = 0;
489 522
490 if(cfile->srch_inf.info_level == 0x202) { 523 if(cfile->srch_inf.info_level == SMB_FIND_FILE_UNIX) {
491 FILE_UNIX_INFO * pFindData = (FILE_UNIX_INFO *)current_entry; 524 FILE_UNIX_INFO * pFindData = (FILE_UNIX_INFO *)current_entry;
492 filename = &pFindData->FileName[0]; 525 filename = &pFindData->FileName[0];
493 if(cfile->srch_inf.unicode) { 526 if(cfile->srch_inf.unicode) {
@@ -496,26 +529,34 @@ static int cifs_entry_is_dot(char *current_entry, struct cifsFileInfo *cfile)
496 /* BB should we make this strnlen of PATH_MAX? */ 529 /* BB should we make this strnlen of PATH_MAX? */
497 len = strnlen(filename, 5); 530 len = strnlen(filename, 5);
498 } 531 }
499 } else if(cfile->srch_inf.info_level == 0x101) { 532 } else if(cfile->srch_inf.info_level == SMB_FIND_FILE_DIRECTORY_INFO) {
500 FILE_DIRECTORY_INFO * pFindData = 533 FILE_DIRECTORY_INFO * pFindData =
501 (FILE_DIRECTORY_INFO *)current_entry; 534 (FILE_DIRECTORY_INFO *)current_entry;
502 filename = &pFindData->FileName[0]; 535 filename = &pFindData->FileName[0];
503 len = le32_to_cpu(pFindData->FileNameLength); 536 len = le32_to_cpu(pFindData->FileNameLength);
504 } else if(cfile->srch_inf.info_level == 0x102) { 537 } else if(cfile->srch_inf.info_level ==
538 SMB_FIND_FILE_FULL_DIRECTORY_INFO) {
505 FILE_FULL_DIRECTORY_INFO * pFindData = 539 FILE_FULL_DIRECTORY_INFO * pFindData =
506 (FILE_FULL_DIRECTORY_INFO *)current_entry; 540 (FILE_FULL_DIRECTORY_INFO *)current_entry;
507 filename = &pFindData->FileName[0]; 541 filename = &pFindData->FileName[0];
508 len = le32_to_cpu(pFindData->FileNameLength); 542 len = le32_to_cpu(pFindData->FileNameLength);
509 } else if(cfile->srch_inf.info_level == 0x105) { 543 } else if(cfile->srch_inf.info_level ==
544 SMB_FIND_FILE_ID_FULL_DIR_INFO) {
510 SEARCH_ID_FULL_DIR_INFO * pFindData = 545 SEARCH_ID_FULL_DIR_INFO * pFindData =
511 (SEARCH_ID_FULL_DIR_INFO *)current_entry; 546 (SEARCH_ID_FULL_DIR_INFO *)current_entry;
512 filename = &pFindData->FileName[0]; 547 filename = &pFindData->FileName[0];
513 len = le32_to_cpu(pFindData->FileNameLength); 548 len = le32_to_cpu(pFindData->FileNameLength);
514 } else if(cfile->srch_inf.info_level == 0x104) { 549 } else if(cfile->srch_inf.info_level ==
550 SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
515 FILE_BOTH_DIRECTORY_INFO * pFindData = 551 FILE_BOTH_DIRECTORY_INFO * pFindData =
516 (FILE_BOTH_DIRECTORY_INFO *)current_entry; 552 (FILE_BOTH_DIRECTORY_INFO *)current_entry;
517 filename = &pFindData->FileName[0]; 553 filename = &pFindData->FileName[0];
518 len = le32_to_cpu(pFindData->FileNameLength); 554 len = le32_to_cpu(pFindData->FileNameLength);
555 } else if(cfile->srch_inf.info_level == SMB_FIND_FILE_INFO_STANDARD) {
556 FIND_FILE_STANDARD_INFO * pFindData =
557 (FIND_FILE_STANDARD_INFO *)current_entry;
558 filename = &pFindData->FileName[0];
559 len = le32_to_cpu(pFindData->FileNameLength);
519 } else { 560 } else {
520 cFYI(1,("Unknown findfirst level %d",cfile->srch_inf.info_level)); 561 cFYI(1,("Unknown findfirst level %d",cfile->srch_inf.info_level));
521 } 562 }
@@ -651,10 +692,12 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon,
651 first_entry_in_buffer = cifsFile->srch_inf.index_of_last_entry 692 first_entry_in_buffer = cifsFile->srch_inf.index_of_last_entry
652 - cifsFile->srch_inf.entries_in_buffer; 693 - cifsFile->srch_inf.entries_in_buffer;
653 pos_in_buf = index_to_find - first_entry_in_buffer; 694 pos_in_buf = index_to_find - first_entry_in_buffer;
654 cFYI(1,("found entry - pos_in_buf %d",pos_in_buf)); 695 cFYI(1,("found entry - pos_in_buf %d",pos_in_buf));
696
655 for(i=0;(i<(pos_in_buf)) && (current_entry != NULL);i++) { 697 for(i=0;(i<(pos_in_buf)) && (current_entry != NULL);i++) {
656 /* go entry by entry figuring out which is first */ 698 /* go entry by entry figuring out which is first */
657 current_entry = nxt_dir_entry(current_entry,end_of_smb); 699 current_entry = nxt_dir_entry(current_entry,end_of_smb,
700 cifsFile->srch_inf.info_level);
658 } 701 }
659 if((current_entry == NULL) && (i < pos_in_buf)) { 702 if((current_entry == NULL) && (i < pos_in_buf)) {
660 /* BB fixme - check if we should flag this error */ 703 /* BB fixme - check if we should flag this error */
@@ -681,7 +724,7 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon,
681/* inode num, inode type and filename returned */ 724/* inode num, inode type and filename returned */
682static int cifs_get_name_from_search_buf(struct qstr *pqst, 725static int cifs_get_name_from_search_buf(struct qstr *pqst,
683 char *current_entry, __u16 level, unsigned int unicode, 726 char *current_entry, __u16 level, unsigned int unicode,
684 struct cifs_sb_info * cifs_sb, ino_t *pinum) 727 struct cifs_sb_info * cifs_sb, int max_len, ino_t *pinum)
685{ 728{
686 int rc = 0; 729 int rc = 0;
687 unsigned int len = 0; 730 unsigned int len = 0;
@@ -725,10 +768,22 @@ static int cifs_get_name_from_search_buf(struct qstr *pqst,
725 (FILE_BOTH_DIRECTORY_INFO *)current_entry; 768 (FILE_BOTH_DIRECTORY_INFO *)current_entry;
726 filename = &pFindData->FileName[0]; 769 filename = &pFindData->FileName[0];
727 len = le32_to_cpu(pFindData->FileNameLength); 770 len = le32_to_cpu(pFindData->FileNameLength);
771 } else if(level == SMB_FIND_FILE_INFO_STANDARD) {
772 FIND_FILE_STANDARD_INFO * pFindData =
773 (FIND_FILE_STANDARD_INFO *)current_entry;
774 filename = &pFindData->FileName[0];
775 /* one byte length, no name conversion */
776 len = (unsigned int)pFindData->FileNameLength;
728 } else { 777 } else {
729 cFYI(1,("Unknown findfirst level %d",level)); 778 cFYI(1,("Unknown findfirst level %d",level));
730 return -EINVAL; 779 return -EINVAL;
731 } 780 }
781
782 if(len > max_len) {
783 cERROR(1,("bad search response length %d past smb end", len));
784 return -EINVAL;
785 }
786
732 if(unicode) { 787 if(unicode) {
733 /* BB fixme - test with long names */ 788 /* BB fixme - test with long names */
734 /* Note converted filename can be longer than in unicode */ 789 /* Note converted filename can be longer than in unicode */
@@ -748,7 +803,7 @@ static int cifs_get_name_from_search_buf(struct qstr *pqst,
748} 803}
749 804
750static int cifs_filldir(char *pfindEntry, struct file *file, 805static int cifs_filldir(char *pfindEntry, struct file *file,
751 filldir_t filldir, void *direntry, char *scratch_buf) 806 filldir_t filldir, void *direntry, char *scratch_buf, int max_len)
752{ 807{
753 int rc = 0; 808 int rc = 0;
754 struct qstr qstring; 809 struct qstr qstring;
@@ -784,6 +839,7 @@ static int cifs_filldir(char *pfindEntry, struct file *file,
784 rc = cifs_get_name_from_search_buf(&qstring,pfindEntry, 839 rc = cifs_get_name_from_search_buf(&qstring,pfindEntry,
785 pCifsF->srch_inf.info_level, 840 pCifsF->srch_inf.info_level,
786 pCifsF->srch_inf.unicode,cifs_sb, 841 pCifsF->srch_inf.unicode,cifs_sb,
842 max_len,
787 &inum /* returned */); 843 &inum /* returned */);
788 844
789 if(rc) 845 if(rc)
@@ -805,13 +861,16 @@ static int cifs_filldir(char *pfindEntry, struct file *file,
805 /* we pass in rc below, indicating whether it is a new inode, 861 /* we pass in rc below, indicating whether it is a new inode,
806 so we can figure out whether to invalidate the inode cached 862 so we can figure out whether to invalidate the inode cached
807 data if the file has changed */ 863 data if the file has changed */
808 if(pCifsF->srch_inf.info_level == SMB_FIND_FILE_UNIX) { 864 if(pCifsF->srch_inf.info_level == SMB_FIND_FILE_UNIX)
809 unix_fill_in_inode(tmp_inode, 865 unix_fill_in_inode(tmp_inode,
810 (FILE_UNIX_INFO *)pfindEntry,&obj_type, rc); 866 (FILE_UNIX_INFO *)pfindEntry,
811 } else { 867 &obj_type, rc);
812 fill_in_inode(tmp_inode, 868 else if(pCifsF->srch_inf.info_level == SMB_FIND_FILE_INFO_STANDARD)
813 (FILE_DIRECTORY_INFO *)pfindEntry,&obj_type, rc); 869 fill_in_inode(tmp_inode, 0 /* old level 1 buffer type */,
814 } 870 pfindEntry, &obj_type, rc);
871 else
872 fill_in_inode(tmp_inode, 1 /* NT */, pfindEntry, &obj_type, rc);
873
815 874
816 rc = filldir(direntry,qstring.name,qstring.len,file->f_pos, 875 rc = filldir(direntry,qstring.name,qstring.len,file->f_pos,
817 tmp_inode->i_ino,obj_type); 876 tmp_inode->i_ino,obj_type);
@@ -871,6 +930,12 @@ static int cifs_save_resume_key(const char *current_entry,
871 filename = &pFindData->FileName[0]; 930 filename = &pFindData->FileName[0];
872 len = le32_to_cpu(pFindData->FileNameLength); 931 len = le32_to_cpu(pFindData->FileNameLength);
873 cifsFile->srch_inf.resume_key = pFindData->FileIndex; 932 cifsFile->srch_inf.resume_key = pFindData->FileIndex;
933 } else if(level == SMB_FIND_FILE_INFO_STANDARD) {
934 FIND_FILE_STANDARD_INFO * pFindData =
935 (FIND_FILE_STANDARD_INFO *)current_entry;
936 filename = &pFindData->FileName[0];
937 /* one byte length, no name conversion */
938 len = (unsigned int)pFindData->FileNameLength;
874 } else { 939 } else {
875 cFYI(1,("Unknown findfirst level %d",level)); 940 cFYI(1,("Unknown findfirst level %d",level));
876 return -EINVAL; 941 return -EINVAL;
@@ -891,6 +956,7 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
891 int num_to_fill = 0; 956 int num_to_fill = 0;
892 char * tmp_buf = NULL; 957 char * tmp_buf = NULL;
893 char * end_of_smb; 958 char * end_of_smb;
959 int max_len;
894 960
895 xid = GetXid(); 961 xid = GetXid();
896 962
@@ -966,10 +1032,11 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
966 goto rddir2_exit; 1032 goto rddir2_exit;
967 } 1033 }
968 cFYI(1,("loop through %d times filling dir for net buf %p", 1034 cFYI(1,("loop through %d times filling dir for net buf %p",
969 num_to_fill,cifsFile->srch_inf.ntwrk_buf_start)); 1035 num_to_fill,cifsFile->srch_inf.ntwrk_buf_start));
970 end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + 1036 max_len = smbCalcSize((struct smb_hdr *)
971 smbCalcSize((struct smb_hdr *) 1037 cifsFile->srch_inf.ntwrk_buf_start);
972 cifsFile->srch_inf.ntwrk_buf_start); 1038 end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + max_len;
1039
973 /* To be safe - for UCS to UTF-8 with strings loaded 1040 /* To be safe - for UCS to UTF-8 with strings loaded
974 with the rare long characters alloc more to account for 1041 with the rare long characters alloc more to account for
975 such multibyte target UTF-8 characters. cifs_unicode.c, 1042 such multibyte target UTF-8 characters. cifs_unicode.c,
@@ -984,8 +1051,8 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
984 } 1051 }
985 /* if buggy server returns . and .. late do 1052 /* if buggy server returns . and .. late do
986 we want to check for that here? */ 1053 we want to check for that here? */
987 rc = cifs_filldir(current_entry, file, 1054 rc = cifs_filldir(current_entry, file,
988 filldir, direntry,tmp_buf); 1055 filldir, direntry, tmp_buf, max_len);
989 file->f_pos++; 1056 file->f_pos++;
990 if(file->f_pos == 1057 if(file->f_pos ==
991 cifsFile->srch_inf.index_of_last_entry) { 1058 cifsFile->srch_inf.index_of_last_entry) {
@@ -994,8 +1061,9 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
994 cifs_save_resume_key(current_entry,cifsFile); 1061 cifs_save_resume_key(current_entry,cifsFile);
995 break; 1062 break;
996 } else 1063 } else
997 current_entry = nxt_dir_entry(current_entry, 1064 current_entry =
998 end_of_smb); 1065 nxt_dir_entry(current_entry, end_of_smb,
1066 cifsFile->srch_inf.info_level);
999 } 1067 }
1000 kfree(tmp_buf); 1068 kfree(tmp_buf);
1001 break; 1069 break;