at v2.6.13 919 lines 29 kB view raw
1/* 2 * fs/cifs/readdir.c 3 * 4 * Directory search handling 5 * 6 * Copyright (C) International Business Machines Corp., 2004, 2005 7 * Author(s): Steve French (sfrench@us.ibm.com) 8 * 9 * This library is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU Lesser General Public License as published 11 * by the Free Software Foundation; either version 2.1 of the License, or 12 * (at your option) any later version. 13 * 14 * This library is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 17 * the GNU Lesser General Public License for more details. 18 * 19 * You should have received a copy of the GNU Lesser General Public License 20 * along with this library; if not, write to the Free Software 21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 22 */ 23#include <linux/fs.h> 24#include <linux/stat.h> 25#include <linux/smp_lock.h> 26#include "cifspdu.h" 27#include "cifsglob.h" 28#include "cifsproto.h" 29#include "cifs_unicode.h" 30#include "cifs_debug.h" 31#include "cifs_fs_sb.h" 32#include "cifsfs.h" 33 34/* BB fixme - add debug wrappers around this function to disable it fixme BB */ 35/* static void dump_cifs_file_struct(struct file *file, char *label) 36{ 37 struct cifsFileInfo * cf; 38 39 if(file) { 40 cf = file->private_data; 41 if(cf == NULL) { 42 cFYI(1,("empty cifs private file data")); 43 return; 44 } 45 if(cf->invalidHandle) { 46 cFYI(1,("invalid handle")); 47 } 48 if(cf->srch_inf.endOfSearch) { 49 cFYI(1,("end of search")); 50 } 51 if(cf->srch_inf.emptyDir) { 52 cFYI(1,("empty dir")); 53 } 54 55 } 56} */ 57 58/* Returns one if new inode created (which therefore needs to be hashed) */ 59/* Might check in the future if inode number changed so we can rehash inode */ 60static int construct_dentry(struct qstr *qstring, struct file *file, 61 struct inode **ptmp_inode, struct dentry **pnew_dentry) 62{ 63 struct dentry *tmp_dentry; 64 struct cifs_sb_info *cifs_sb; 65 struct cifsTconInfo *pTcon; 66 int rc = 0; 67 68 cFYI(1, ("For %s", qstring->name)); 69 cifs_sb = CIFS_SB(file->f_dentry->d_sb); 70 pTcon = cifs_sb->tcon; 71 72 qstring->hash = full_name_hash(qstring->name, qstring->len); 73 tmp_dentry = d_lookup(file->f_dentry, qstring); 74 if (tmp_dentry) { 75 cFYI(0, ("existing dentry with inode 0x%p", tmp_dentry->d_inode)); 76 *ptmp_inode = tmp_dentry->d_inode; 77/* BB overwrite old name? i.e. tmp_dentry->d_name and tmp_dentry->d_name.len??*/ 78 if(*ptmp_inode == NULL) { 79 *ptmp_inode = new_inode(file->f_dentry->d_sb); 80 if(*ptmp_inode == NULL) 81 return rc; 82 rc = 1; 83 d_instantiate(tmp_dentry, *ptmp_inode); 84 } 85 } else { 86 tmp_dentry = d_alloc(file->f_dentry, qstring); 87 if(tmp_dentry == NULL) { 88 cERROR(1,("Failed allocating dentry")); 89 *ptmp_inode = NULL; 90 return rc; 91 } 92 93 *ptmp_inode = new_inode(file->f_dentry->d_sb); 94 tmp_dentry->d_op = &cifs_dentry_ops; 95 if(*ptmp_inode == NULL) 96 return rc; 97 rc = 1; 98 d_instantiate(tmp_dentry, *ptmp_inode); 99 d_rehash(tmp_dentry); 100 } 101 102 tmp_dentry->d_time = jiffies; 103 *pnew_dentry = tmp_dentry; 104 return rc; 105} 106 107static void fill_in_inode(struct inode *tmp_inode, 108 FILE_DIRECTORY_INFO *pfindData, int *pobject_type, int isNewInode) 109{ 110 loff_t local_size; 111 struct timespec local_mtime; 112 113 struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode); 114 struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb); 115 __u32 attr = le32_to_cpu(pfindData->ExtFileAttributes); 116 __u64 allocation_size = le64_to_cpu(pfindData->AllocationSize); 117 __u64 end_of_file = le64_to_cpu(pfindData->EndOfFile); 118 119 cifsInfo->cifsAttrs = attr; 120 cifsInfo->time = jiffies; 121 122 /* save mtime and size */ 123 local_mtime = tmp_inode->i_mtime; 124 local_size = tmp_inode->i_size; 125 126 /* Linux can not store file creation time unfortunately so ignore it */ 127 tmp_inode->i_atime = 128 cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime)); 129 tmp_inode->i_mtime = 130 cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime)); 131 tmp_inode->i_ctime = 132 cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime)); 133 /* treat dos attribute of read-only as read-only mode bit e.g. 555? */ 134 /* 2767 perms - indicate mandatory locking */ 135 /* BB fill in uid and gid here? with help from winbind? 136 or retrieve from NTFS stream extended attribute */ 137 if (atomic_read(&cifsInfo->inUse) == 0) { 138 tmp_inode->i_uid = cifs_sb->mnt_uid; 139 tmp_inode->i_gid = cifs_sb->mnt_gid; 140 /* set default mode. will override for dirs below */ 141 tmp_inode->i_mode = cifs_sb->mnt_file_mode; 142 } 143 144 if (attr & ATTR_DIRECTORY) { 145 *pobject_type = DT_DIR; 146 /* override default perms since we do not lock dirs */ 147 if(atomic_read(&cifsInfo->inUse) == 0) { 148 tmp_inode->i_mode = cifs_sb->mnt_dir_mode; 149 } 150 tmp_inode->i_mode |= S_IFDIR; 151/* we no longer mark these because we could not follow them */ 152/* } else if (attr & ATTR_REPARSE) { 153 *pobject_type = DT_LNK; 154 tmp_inode->i_mode |= S_IFLNK; */ 155 } else { 156 *pobject_type = DT_REG; 157 tmp_inode->i_mode |= S_IFREG; 158 if (attr & ATTR_READONLY) 159 tmp_inode->i_mode &= ~(S_IWUGO); 160 } /* could add code here - to validate if device or weird share type? */ 161 162 /* can not fill in nlink here as in qpathinfo version and Unx search */ 163 if (atomic_read(&cifsInfo->inUse) == 0) { 164 atomic_set(&cifsInfo->inUse, 1); 165 } 166 167 if (is_size_safe_to_change(cifsInfo)) { 168 /* can not safely change the file size here if the 169 client is writing to it due to potential races */ 170 i_size_write(tmp_inode, end_of_file); 171 172 /* 512 bytes (2**9) is the fake blocksize that must be used */ 173 /* for this calculation, even though the reported blocksize is larger */ 174 tmp_inode->i_blocks = (512 - 1 + allocation_size) >> 9; 175 } 176 177 if (allocation_size < end_of_file) 178 cFYI(1, ("May be sparse file, allocation less than file size")); 179 cFYI(1, 180 ("File Size %ld and blocks %ld and blocksize %ld", 181 (unsigned long)tmp_inode->i_size, tmp_inode->i_blocks, 182 tmp_inode->i_blksize)); 183 if (S_ISREG(tmp_inode->i_mode)) { 184 cFYI(1, ("File inode")); 185 tmp_inode->i_op = &cifs_file_inode_ops; 186 if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) 187 tmp_inode->i_fop = &cifs_file_direct_ops; 188 else 189 tmp_inode->i_fop = &cifs_file_ops; 190 tmp_inode->i_data.a_ops = &cifs_addr_ops; 191 192 if(isNewInode) 193 return; /* No sense invalidating pages for new inode since we 194 have not started caching readahead file data yet */ 195 196 if (timespec_equal(&tmp_inode->i_mtime, &local_mtime) && 197 (local_size == tmp_inode->i_size)) { 198 cFYI(1, ("inode exists but unchanged")); 199 } else { 200 /* file may have changed on server */ 201 cFYI(1, ("invalidate inode, readdir detected change")); 202 invalidate_remote_inode(tmp_inode); 203 } 204 } else if (S_ISDIR(tmp_inode->i_mode)) { 205 cFYI(1, ("Directory inode")); 206 tmp_inode->i_op = &cifs_dir_inode_ops; 207 tmp_inode->i_fop = &cifs_dir_ops; 208 } else if (S_ISLNK(tmp_inode->i_mode)) { 209 cFYI(1, ("Symbolic Link inode")); 210 tmp_inode->i_op = &cifs_symlink_inode_ops; 211 } else { 212 cFYI(1, ("Init special inode")); 213 init_special_inode(tmp_inode, tmp_inode->i_mode, 214 tmp_inode->i_rdev); 215 } 216} 217 218static void unix_fill_in_inode(struct inode *tmp_inode, 219 FILE_UNIX_INFO *pfindData, int *pobject_type, int isNewInode) 220{ 221 loff_t local_size; 222 struct timespec local_mtime; 223 224 struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode); 225 struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb); 226 227 __u32 type = le32_to_cpu(pfindData->Type); 228 __u64 num_of_bytes = le64_to_cpu(pfindData->NumOfBytes); 229 __u64 end_of_file = le64_to_cpu(pfindData->EndOfFile); 230 cifsInfo->time = jiffies; 231 atomic_inc(&cifsInfo->inUse); 232 233 /* save mtime and size */ 234 local_mtime = tmp_inode->i_mtime; 235 local_size = tmp_inode->i_size; 236 237 tmp_inode->i_atime = 238 cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime)); 239 tmp_inode->i_mtime = 240 cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastModificationTime)); 241 tmp_inode->i_ctime = 242 cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastStatusChange)); 243 244 tmp_inode->i_mode = le64_to_cpu(pfindData->Permissions); 245 if (type == UNIX_FILE) { 246 *pobject_type = DT_REG; 247 tmp_inode->i_mode |= S_IFREG; 248 } else if (type == UNIX_SYMLINK) { 249 *pobject_type = DT_LNK; 250 tmp_inode->i_mode |= S_IFLNK; 251 } else if (type == UNIX_DIR) { 252 *pobject_type = DT_DIR; 253 tmp_inode->i_mode |= S_IFDIR; 254 } else if (type == UNIX_CHARDEV) { 255 *pobject_type = DT_CHR; 256 tmp_inode->i_mode |= S_IFCHR; 257 tmp_inode->i_rdev = MKDEV(le64_to_cpu(pfindData->DevMajor), 258 le64_to_cpu(pfindData->DevMinor) & MINORMASK); 259 } else if (type == UNIX_BLOCKDEV) { 260 *pobject_type = DT_BLK; 261 tmp_inode->i_mode |= S_IFBLK; 262 tmp_inode->i_rdev = MKDEV(le64_to_cpu(pfindData->DevMajor), 263 le64_to_cpu(pfindData->DevMinor) & MINORMASK); 264 } else if (type == UNIX_FIFO) { 265 *pobject_type = DT_FIFO; 266 tmp_inode->i_mode |= S_IFIFO; 267 } else if (type == UNIX_SOCKET) { 268 *pobject_type = DT_SOCK; 269 tmp_inode->i_mode |= S_IFSOCK; 270 } 271 272 tmp_inode->i_uid = le64_to_cpu(pfindData->Uid); 273 tmp_inode->i_gid = le64_to_cpu(pfindData->Gid); 274 tmp_inode->i_nlink = le64_to_cpu(pfindData->Nlinks); 275 276 if (is_size_safe_to_change(cifsInfo)) { 277 /* can not safely change the file size here if the 278 client is writing to it due to potential races */ 279 i_size_write(tmp_inode,end_of_file); 280 281 /* 512 bytes (2**9) is the fake blocksize that must be used */ 282 /* for this calculation, not the real blocksize */ 283 tmp_inode->i_blocks = (512 - 1 + num_of_bytes) >> 9; 284 } 285 286 if (S_ISREG(tmp_inode->i_mode)) { 287 cFYI(1, ("File inode")); 288 tmp_inode->i_op = &cifs_file_inode_ops; 289 if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) 290 tmp_inode->i_fop = &cifs_file_direct_ops; 291 else 292 tmp_inode->i_fop = &cifs_file_ops; 293 tmp_inode->i_data.a_ops = &cifs_addr_ops; 294 295 if(isNewInode) 296 return; /* No sense invalidating pages for new inode since we 297 have not started caching readahead file data yet */ 298 299 if (timespec_equal(&tmp_inode->i_mtime, &local_mtime) && 300 (local_size == tmp_inode->i_size)) { 301 cFYI(1, ("inode exists but unchanged")); 302 } else { 303 /* file may have changed on server */ 304 cFYI(1, ("invalidate inode, readdir detected change")); 305 invalidate_remote_inode(tmp_inode); 306 } 307 } else if (S_ISDIR(tmp_inode->i_mode)) { 308 cFYI(1, ("Directory inode")); 309 tmp_inode->i_op = &cifs_dir_inode_ops; 310 tmp_inode->i_fop = &cifs_dir_ops; 311 } else if (S_ISLNK(tmp_inode->i_mode)) { 312 cFYI(1, ("Symbolic Link inode")); 313 tmp_inode->i_op = &cifs_symlink_inode_ops; 314/* tmp_inode->i_fop = *//* do not need to set to anything */ 315 } else { 316 cFYI(1, ("Special inode")); 317 init_special_inode(tmp_inode, tmp_inode->i_mode, 318 tmp_inode->i_rdev); 319 } 320} 321 322static int initiate_cifs_search(const int xid, struct file *file) 323{ 324 int rc = 0; 325 char * full_path; 326 struct cifsFileInfo * cifsFile; 327 struct cifs_sb_info *cifs_sb; 328 struct cifsTconInfo *pTcon; 329 330 if(file->private_data == NULL) { 331 file->private_data = 332 kmalloc(sizeof(struct cifsFileInfo),GFP_KERNEL); 333 } 334 335 if(file->private_data == NULL) { 336 return -ENOMEM; 337 } else { 338 memset(file->private_data,0,sizeof(struct cifsFileInfo)); 339 } 340 cifsFile = file->private_data; 341 cifsFile->invalidHandle = TRUE; 342 cifsFile->srch_inf.endOfSearch = FALSE; 343 344 if(file->f_dentry == NULL) 345 return -ENOENT; 346 347 cifs_sb = CIFS_SB(file->f_dentry->d_sb); 348 if(cifs_sb == NULL) 349 return -EINVAL; 350 351 pTcon = cifs_sb->tcon; 352 if(pTcon == NULL) 353 return -EINVAL; 354 355 down(&file->f_dentry->d_sb->s_vfs_rename_sem); 356 full_path = build_path_from_dentry(file->f_dentry); 357 up(&file->f_dentry->d_sb->s_vfs_rename_sem); 358 359 if(full_path == NULL) { 360 return -ENOMEM; 361 } 362 363 cFYI(1, ("Full path: %s start at: %lld", full_path, file->f_pos)); 364 365ffirst_retry: 366 /* test for Unix extensions */ 367 if (pTcon->ses->capabilities & CAP_UNIX) { 368 cifsFile->srch_inf.info_level = SMB_FIND_FILE_UNIX; 369 } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) { 370 cifsFile->srch_inf.info_level = SMB_FIND_FILE_ID_FULL_DIR_INFO; 371 } else /* not srvinos - BB fixme add check for backlevel? */ { 372 cifsFile->srch_inf.info_level = SMB_FIND_FILE_DIRECTORY_INFO; 373 } 374 375 rc = CIFSFindFirst(xid, pTcon,full_path,cifs_sb->local_nls, 376 &cifsFile->netfid, &cifsFile->srch_inf, 377 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); 378 if(rc == 0) 379 cifsFile->invalidHandle = FALSE; 380 if((rc == -EOPNOTSUPP) && 381 (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)) { 382 cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_SERVER_INUM; 383 goto ffirst_retry; 384 } 385 kfree(full_path); 386 return rc; 387} 388 389/* return length of unicode string in bytes */ 390static int cifs_unicode_bytelen(char *str) 391{ 392 int len; 393 __le16 * ustr = (__le16 *)str; 394 395 for(len=0;len <= PATH_MAX;len++) { 396 if(ustr[len] == 0) 397 return len << 1; 398 } 399 cFYI(1,("Unicode string longer than PATH_MAX found")); 400 return len << 1; 401} 402 403static char *nxt_dir_entry(char *old_entry, char *end_of_smb) 404{ 405 char * new_entry; 406 FILE_DIRECTORY_INFO * pDirInfo = (FILE_DIRECTORY_INFO *)old_entry; 407 408 new_entry = old_entry + le32_to_cpu(pDirInfo->NextEntryOffset); 409 cFYI(1,("new entry %p old entry %p",new_entry,old_entry)); 410 /* validate that new_entry is not past end of SMB */ 411 if(new_entry >= end_of_smb) { 412 cERROR(1, 413 ("search entry %p began after end of SMB %p old entry %p", 414 new_entry, end_of_smb, old_entry)); 415 return NULL; 416 } else if (new_entry + sizeof(FILE_DIRECTORY_INFO) > end_of_smb) { 417 cERROR(1,("search entry %p extends after end of SMB %p", 418 new_entry, end_of_smb)); 419 return NULL; 420 } else 421 return new_entry; 422 423} 424 425#define UNICODE_DOT cpu_to_le16(0x2e) 426 427/* return 0 if no match and 1 for . (current directory) and 2 for .. (parent) */ 428static int cifs_entry_is_dot(char *current_entry, struct cifsFileInfo *cfile) 429{ 430 int rc = 0; 431 char * filename = NULL; 432 int len = 0; 433 434 if(cfile->srch_inf.info_level == 0x202) { 435 FILE_UNIX_INFO * pFindData = (FILE_UNIX_INFO *)current_entry; 436 filename = &pFindData->FileName[0]; 437 if(cfile->srch_inf.unicode) { 438 len = cifs_unicode_bytelen(filename); 439 } else { 440 /* BB should we make this strnlen of PATH_MAX? */ 441 len = strnlen(filename, 5); 442 } 443 } else if(cfile->srch_inf.info_level == 0x101) { 444 FILE_DIRECTORY_INFO * pFindData = 445 (FILE_DIRECTORY_INFO *)current_entry; 446 filename = &pFindData->FileName[0]; 447 len = le32_to_cpu(pFindData->FileNameLength); 448 } else if(cfile->srch_inf.info_level == 0x102) { 449 FILE_FULL_DIRECTORY_INFO * pFindData = 450 (FILE_FULL_DIRECTORY_INFO *)current_entry; 451 filename = &pFindData->FileName[0]; 452 len = le32_to_cpu(pFindData->FileNameLength); 453 } else if(cfile->srch_inf.info_level == 0x105) { 454 SEARCH_ID_FULL_DIR_INFO * pFindData = 455 (SEARCH_ID_FULL_DIR_INFO *)current_entry; 456 filename = &pFindData->FileName[0]; 457 len = le32_to_cpu(pFindData->FileNameLength); 458 } else if(cfile->srch_inf.info_level == 0x104) { 459 FILE_BOTH_DIRECTORY_INFO * pFindData = 460 (FILE_BOTH_DIRECTORY_INFO *)current_entry; 461 filename = &pFindData->FileName[0]; 462 len = le32_to_cpu(pFindData->FileNameLength); 463 } else { 464 cFYI(1,("Unknown findfirst level %d",cfile->srch_inf.info_level)); 465 } 466 467 if(filename) { 468 if(cfile->srch_inf.unicode) { 469 __le16 *ufilename = (__le16 *)filename; 470 if(len == 2) { 471 /* check for . */ 472 if(ufilename[0] == UNICODE_DOT) 473 rc = 1; 474 } else if(len == 4) { 475 /* check for .. */ 476 if((ufilename[0] == UNICODE_DOT) 477 &&(ufilename[1] == UNICODE_DOT)) 478 rc = 2; 479 } 480 } else /* ASCII */ { 481 if(len == 1) { 482 if(filename[0] == '.') 483 rc = 1; 484 } else if(len == 2) { 485 if((filename[0] == '.') && (filename[1] == '.')) 486 rc = 2; 487 } 488 } 489 } 490 491 return rc; 492} 493 494/* find the corresponding entry in the search */ 495/* 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 497 assume that they are located in the findfirst return buffer.*/ 498/* We start counting in the buffer with entry 2 and increment for every 499 entry (do not increment for . or .. entry) */ 500static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon, 501 struct file *file, char **ppCurrentEntry, int *num_to_ret) 502{ 503 int rc = 0; 504 int pos_in_buf = 0; 505 loff_t first_entry_in_buffer; 506 loff_t index_to_find = file->f_pos; 507 struct cifsFileInfo * cifsFile = file->private_data; 508 /* check if index in the buffer */ 509 510 if((cifsFile == NULL) || (ppCurrentEntry == NULL) || (num_to_ret == NULL)) 511 return -ENOENT; 512 513 *ppCurrentEntry = NULL; 514 first_entry_in_buffer = 515 cifsFile->srch_inf.index_of_last_entry - 516 cifsFile->srch_inf.entries_in_buffer; 517/* dump_cifs_file_struct(file, "In fce ");*/ 518 if(index_to_find < first_entry_in_buffer) { 519 /* close and restart search */ 520 cFYI(1,("search backing up - close and restart search")); 521 cifsFile->invalidHandle = TRUE; 522 CIFSFindClose(xid, pTcon, cifsFile->netfid); 523 kfree(cifsFile->search_resume_name); 524 cifsFile->search_resume_name = NULL; 525 if(cifsFile->srch_inf.ntwrk_buf_start) { 526 cFYI(1,("freeing SMB ff cache buf on search rewind")); 527 cifs_buf_release(cifsFile->srch_inf.ntwrk_buf_start); 528 } 529 rc = initiate_cifs_search(xid,file); 530 if(rc) { 531 cFYI(1,("error %d reinitiating a search on rewind",rc)); 532 return rc; 533 } 534 } 535 536 while((index_to_find >= cifsFile->srch_inf.index_of_last_entry) && 537 (rc == 0) && (cifsFile->srch_inf.endOfSearch == FALSE)){ 538 cFYI(1,("calling findnext2")); 539 rc = CIFSFindNext(xid,pTcon,cifsFile->netfid, &cifsFile->srch_inf); 540 if(rc) 541 return -ENOENT; 542 } 543 if(index_to_find < cifsFile->srch_inf.index_of_last_entry) { 544 /* we found the buffer that contains the entry */ 545 /* scan and find it */ 546 int i; 547 char * current_entry; 548 char * end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + 549 smbCalcSize((struct smb_hdr *) 550 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 553 - cifsFile->srch_inf.entries_in_buffer; 554 pos_in_buf = index_to_find - first_entry_in_buffer; 555 cFYI(1,("found entry - pos_in_buf %d",pos_in_buf)); 556 current_entry = cifsFile->srch_inf.srch_entries_start; 557 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 */ 559 /* if( . or ..) 560 skip */ 561 rc = cifs_entry_is_dot(current_entry,cifsFile); 562 if(rc == 1) /* is . or .. so skip */ { 563 cFYI(1,("Entry is .")); /* BB removeme BB */ 564 /* continue; */ 565 } else if (rc == 2 ) { 566 cFYI(1,("Entry is ..")); /* BB removeme BB */ 567 /* continue; */ 568 } 569 current_entry = nxt_dir_entry(current_entry,end_of_smb); 570 } 571 if((current_entry == NULL) && (i < pos_in_buf)) { 572 /* BB fixme - check if we should flag this error */ 573 cERROR(1,("reached end of buf searching for pos in buf" 574 " %d index to find %lld rc %d", 575 pos_in_buf,index_to_find,rc)); 576 } 577 rc = 0; 578 *ppCurrentEntry = current_entry; 579 } else { 580 cFYI(1,("index not in buffer - could not findnext into it")); 581 return 0; 582 } 583 584 if(pos_in_buf >= cifsFile->srch_inf.entries_in_buffer) { 585 cFYI(1,("can not return entries when pos_in_buf beyond last entry")); 586 *num_to_ret = 0; 587 } else 588 *num_to_ret = cifsFile->srch_inf.entries_in_buffer - pos_in_buf; 589/* dump_cifs_file_struct(file, "end fce ");*/ 590 591 return rc; 592} 593 594/* inode num, inode type and filename returned */ 595static int cifs_get_name_from_search_buf(struct qstr *pqst, 596 char *current_entry, __u16 level, unsigned int unicode, 597 struct cifs_sb_info * cifs_sb, ino_t *pinum) 598{ 599 int rc = 0; 600 unsigned int len = 0; 601 char * filename; 602 struct nls_table * nlt = cifs_sb->local_nls; 603 604 *pinum = 0; 605 606 if(level == SMB_FIND_FILE_UNIX) { 607 FILE_UNIX_INFO * pFindData = (FILE_UNIX_INFO *)current_entry; 608 609 filename = &pFindData->FileName[0]; 610 if(unicode) { 611 len = cifs_unicode_bytelen(filename); 612 } else { 613 /* BB should we make this strnlen of PATH_MAX? */ 614 len = strnlen(filename, PATH_MAX); 615 } 616 617 /* BB fixme - hash low and high 32 bits if not 64 bit arch BB fixme */ 618 if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) 619 *pinum = pFindData->UniqueId; 620 } else if(level == SMB_FIND_FILE_DIRECTORY_INFO) { 621 FILE_DIRECTORY_INFO * pFindData = 622 (FILE_DIRECTORY_INFO *)current_entry; 623 filename = &pFindData->FileName[0]; 624 len = le32_to_cpu(pFindData->FileNameLength); 625 } else if(level == SMB_FIND_FILE_FULL_DIRECTORY_INFO) { 626 FILE_FULL_DIRECTORY_INFO * pFindData = 627 (FILE_FULL_DIRECTORY_INFO *)current_entry; 628 filename = &pFindData->FileName[0]; 629 len = le32_to_cpu(pFindData->FileNameLength); 630 } else if(level == SMB_FIND_FILE_ID_FULL_DIR_INFO) { 631 SEARCH_ID_FULL_DIR_INFO * pFindData = 632 (SEARCH_ID_FULL_DIR_INFO *)current_entry; 633 filename = &pFindData->FileName[0]; 634 len = le32_to_cpu(pFindData->FileNameLength); 635 *pinum = pFindData->UniqueId; 636 } else if(level == SMB_FIND_FILE_BOTH_DIRECTORY_INFO) { 637 FILE_BOTH_DIRECTORY_INFO * pFindData = 638 (FILE_BOTH_DIRECTORY_INFO *)current_entry; 639 filename = &pFindData->FileName[0]; 640 len = le32_to_cpu(pFindData->FileNameLength); 641 } else { 642 cFYI(1,("Unknown findfirst level %d",level)); 643 return -EINVAL; 644 } 645 if(unicode) { 646 /* BB fixme - test with long names */ 647 /* Note converted filename can be longer than in unicode */ 648 if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR) 649 pqst->len = cifs_convertUCSpath((char *)pqst->name, 650 (__le16 *)filename, len/2, nlt); 651 else 652 pqst->len = cifs_strfromUCS_le((char *)pqst->name, 653 (wchar_t *)filename,len/2,nlt); 654 } else { 655 pqst->name = filename; 656 pqst->len = len; 657 } 658 pqst->hash = full_name_hash(pqst->name,pqst->len); 659/* cFYI(1,("filldir on %s",pqst->name)); */ 660 return rc; 661} 662 663static int cifs_filldir(char *pfindEntry, struct file *file, 664 filldir_t filldir, void *direntry, char *scratch_buf) 665{ 666 int rc = 0; 667 struct qstr qstring; 668 struct cifsFileInfo * pCifsF; 669 unsigned obj_type; 670 ino_t inum; 671 struct cifs_sb_info * cifs_sb; 672 struct inode *tmp_inode; 673 struct dentry *tmp_dentry; 674 675 /* get filename and len into qstring */ 676 /* get dentry */ 677 /* decide whether to create and populate ionde */ 678 if((direntry == NULL) || (file == NULL)) 679 return -EINVAL; 680 681 pCifsF = file->private_data; 682 683 if((scratch_buf == NULL) || (pfindEntry == NULL) || (pCifsF == NULL)) 684 return -ENOENT; 685 686 if(file->f_dentry == NULL) 687 return -ENOENT; 688 689 cifs_sb = CIFS_SB(file->f_dentry->d_sb); 690 691 qstring.name = scratch_buf; 692 rc = cifs_get_name_from_search_buf(&qstring,pfindEntry, 693 pCifsF->srch_inf.info_level, 694 pCifsF->srch_inf.unicode,cifs_sb, 695 &inum /* returned */); 696 697 if(rc) 698 return rc; 699 700 rc = construct_dentry(&qstring,file,&tmp_inode, &tmp_dentry); 701 if((tmp_inode == NULL) || (tmp_dentry == NULL)) 702 return -ENOMEM; 703 704 if(rc) { 705 /* inode created, we need to hash it with right inode number */ 706 if(inum != 0) { 707 /* BB fixme - hash the 2 32 quantities bits together if necessary BB */ 708 tmp_inode->i_ino = inum; 709 } 710 insert_inode_hash(tmp_inode); 711 } 712 713 /* we pass in rc below, indicating whether it is a new inode, 714 so we can figure out whether to invalidate the inode cached 715 data if the file has changed */ 716 if(pCifsF->srch_inf.info_level == SMB_FIND_FILE_UNIX) { 717 unix_fill_in_inode(tmp_inode, 718 (FILE_UNIX_INFO *)pfindEntry,&obj_type, rc); 719 } else { 720 fill_in_inode(tmp_inode, 721 (FILE_DIRECTORY_INFO *)pfindEntry,&obj_type, rc); 722 } 723 724 rc = filldir(direntry,qstring.name,qstring.len,file->f_pos,tmp_inode->i_ino,obj_type); 725 if(rc) { 726 cFYI(1,("filldir rc = %d",rc)); 727 } 728 729 dput(tmp_dentry); 730 return rc; 731} 732 733static int cifs_save_resume_key(const char *current_entry, 734 struct cifsFileInfo *cifsFile) 735{ 736 int rc = 0; 737 unsigned int len = 0; 738 __u16 level; 739 char * filename; 740 741 if((cifsFile == NULL) || (current_entry == NULL)) 742 return -EINVAL; 743 744 level = cifsFile->srch_inf.info_level; 745 746 if(level == SMB_FIND_FILE_UNIX) { 747 FILE_UNIX_INFO * pFindData = (FILE_UNIX_INFO *)current_entry; 748 749 filename = &pFindData->FileName[0]; 750 if(cifsFile->srch_inf.unicode) { 751 len = cifs_unicode_bytelen(filename); 752 } else { 753 /* BB should we make this strnlen of PATH_MAX? */ 754 len = strnlen(filename, PATH_MAX); 755 } 756 cifsFile->srch_inf.resume_key = pFindData->ResumeKey; 757 } else if(level == SMB_FIND_FILE_DIRECTORY_INFO) { 758 FILE_DIRECTORY_INFO * pFindData = 759 (FILE_DIRECTORY_INFO *)current_entry; 760 filename = &pFindData->FileName[0]; 761 len = le32_to_cpu(pFindData->FileNameLength); 762 cifsFile->srch_inf.resume_key = pFindData->FileIndex; 763 } else if(level == SMB_FIND_FILE_FULL_DIRECTORY_INFO) { 764 FILE_FULL_DIRECTORY_INFO * pFindData = 765 (FILE_FULL_DIRECTORY_INFO *)current_entry; 766 filename = &pFindData->FileName[0]; 767 len = le32_to_cpu(pFindData->FileNameLength); 768 cifsFile->srch_inf.resume_key = pFindData->FileIndex; 769 } else if(level == SMB_FIND_FILE_ID_FULL_DIR_INFO) { 770 SEARCH_ID_FULL_DIR_INFO * pFindData = 771 (SEARCH_ID_FULL_DIR_INFO *)current_entry; 772 filename = &pFindData->FileName[0]; 773 len = le32_to_cpu(pFindData->FileNameLength); 774 cifsFile->srch_inf.resume_key = pFindData->FileIndex; 775 } else if(level == SMB_FIND_FILE_BOTH_DIRECTORY_INFO) { 776 FILE_BOTH_DIRECTORY_INFO * pFindData = 777 (FILE_BOTH_DIRECTORY_INFO *)current_entry; 778 filename = &pFindData->FileName[0]; 779 len = le32_to_cpu(pFindData->FileNameLength); 780 cifsFile->srch_inf.resume_key = pFindData->FileIndex; 781 } else { 782 cFYI(1,("Unknown findfirst level %d",level)); 783 return -EINVAL; 784 } 785 cifsFile->srch_inf.resume_name_len = len; 786 cifsFile->srch_inf.presume_name = filename; 787 return rc; 788} 789 790int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) 791{ 792 int rc = 0; 793 int xid,i; 794 struct cifs_sb_info *cifs_sb; 795 struct cifsTconInfo *pTcon; 796 struct cifsFileInfo *cifsFile = NULL; 797 char * current_entry; 798 int num_to_fill = 0; 799 char * tmp_buf = NULL; 800 char * end_of_smb; 801 802 xid = GetXid(); 803 804 if(file->f_dentry == NULL) { 805 FreeXid(xid); 806 return -EIO; 807 } 808/* dump_cifs_file_struct(file, "Begin rdir "); */ 809 810 cifs_sb = CIFS_SB(file->f_dentry->d_sb); 811 pTcon = cifs_sb->tcon; 812 if(pTcon == NULL) 813 return -EINVAL; 814 815/* cFYI(1,("readdir2 pos: %lld",file->f_pos)); */ 816 817 switch ((int) file->f_pos) { 818 case 0: 819 /*if (filldir(direntry, ".", 1, file->f_pos, 820 file->f_dentry->d_inode->i_ino, DT_DIR) < 0) { 821 cERROR(1, ("Filldir for current dir failed ")); 822 rc = -ENOMEM; 823 break; 824 } 825 file->f_pos++; */ 826 case 1: 827 /* if (filldir(direntry, "..", 2, file->f_pos, 828 file->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0) { 829 cERROR(1, ("Filldir for parent dir failed ")); 830 rc = -ENOMEM; 831 break; 832 } 833 file->f_pos++; */ 834 case 2: 835 /* 1) If search is active, 836 is in current search buffer? 837 if it before then restart search 838 if after then keep searching till find it */ 839 840 if(file->private_data == NULL) { 841 rc = initiate_cifs_search(xid,file); 842 cFYI(1,("initiate cifs search rc %d",rc)); 843 if(rc) { 844 FreeXid(xid); 845 return rc; 846 } 847 } 848 default: 849 if(file->private_data == NULL) { 850 rc = -EINVAL; 851 FreeXid(xid); 852 return rc; 853 } 854 cifsFile = file->private_data; 855 if (cifsFile->srch_inf.endOfSearch) { 856 if(cifsFile->srch_inf.emptyDir) { 857 cFYI(1, ("End of search, empty dir")); 858 rc = 0; 859 break; 860 } 861 } /* else { 862 cifsFile->invalidHandle = TRUE; 863 CIFSFindClose(xid, pTcon, cifsFile->netfid); 864 } 865 kfree(cifsFile->search_resume_name); 866 cifsFile->search_resume_name = NULL; */ 867 868 /* BB account for . and .. in f_pos as special case */ 869 /* dump_cifs_file_struct(file, "rdir after default ");*/ 870 871 rc = find_cifs_entry(xid,pTcon, file, 872 &current_entry,&num_to_fill); 873 if(rc) { 874 cFYI(1,("fce error %d",rc)); 875 goto rddir2_exit; 876 } else if (current_entry != NULL) { 877 cFYI(1,("entry %lld found",file->f_pos)); 878 } else { 879 cFYI(1,("could not find entry")); 880 goto rddir2_exit; 881 } 882 cFYI(1,("loop through %d times filling dir for net buf %p", 883 num_to_fill,cifsFile->srch_inf.ntwrk_buf_start)); 884 end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + 885 smbCalcSize((struct smb_hdr *) 886 cifsFile->srch_inf.ntwrk_buf_start); 887 /* To be safe - for UCS to UTF-8 with strings loaded 888 with the rare long characters alloc more to account for 889 such multibyte target UTF-8 characters. cifs_unicode.c, 890 which actually does the conversion, has the same limit */ 891 tmp_buf = kmalloc((2 * NAME_MAX) + 4, GFP_KERNEL); 892 for(i=0;(i<num_to_fill) && (rc == 0);i++) { 893 if(current_entry == NULL) { 894 /* evaluate whether this case is an error */ 895 cERROR(1,("past end of SMB num to fill %d i %d", 896 num_to_fill, i)); 897 break; 898 } 899 900 rc = cifs_filldir(current_entry, file, 901 filldir, direntry,tmp_buf); 902 file->f_pos++; 903 if(file->f_pos == cifsFile->srch_inf.index_of_last_entry) { 904 cFYI(1,("last entry in buf at pos %lld %s", 905 file->f_pos,tmp_buf)); /* BB removeme BB */ 906 cifs_save_resume_key(current_entry,cifsFile); 907 break; 908 } else 909 current_entry = nxt_dir_entry(current_entry,end_of_smb); 910 } 911 kfree(tmp_buf); 912 break; 913 } /* end switch */ 914 915rddir2_exit: 916 /* dump_cifs_file_struct(file, "end rdir "); */ 917 FreeXid(xid); 918 return rc; 919}