at v3.5 845 lines 24 kB view raw
1/* 2 * fs/cifs/readdir.c 3 * 4 * Directory search handling 5 * 6 * Copyright (C) International Business Machines Corp., 2004, 2008 7 * Copyright (C) Red Hat, Inc., 2011 8 * Author(s): Steve French (sfrench@us.ibm.com) 9 * 10 * This library is free software; you can redistribute it and/or modify 11 * it under the terms of the GNU Lesser General Public License as published 12 * by the Free Software Foundation; either version 2.1 of the License, or 13 * (at your option) any later version. 14 * 15 * This library is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 18 * the GNU Lesser General Public License for more details. 19 * 20 * You should have received a copy of the GNU Lesser General Public License 21 * along with this library; if not, write to the Free Software 22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 23 */ 24#include <linux/fs.h> 25#include <linux/pagemap.h> 26#include <linux/slab.h> 27#include <linux/stat.h> 28#include "cifspdu.h" 29#include "cifsglob.h" 30#include "cifsproto.h" 31#include "cifs_unicode.h" 32#include "cifs_debug.h" 33#include "cifs_fs_sb.h" 34#include "cifsfs.h" 35 36/* 37 * To be safe - for UCS to UTF-8 with strings loaded with the rare long 38 * characters alloc more to account for such multibyte target UTF-8 39 * characters. 40 */ 41#define UNICODE_NAME_MAX ((4 * NAME_MAX) + 2) 42 43#ifdef CONFIG_CIFS_DEBUG2 44static void dump_cifs_file_struct(struct file *file, char *label) 45{ 46 struct cifsFileInfo *cf; 47 48 if (file) { 49 cf = file->private_data; 50 if (cf == NULL) { 51 cFYI(1, "empty cifs private file data"); 52 return; 53 } 54 if (cf->invalidHandle) 55 cFYI(1, "invalid handle"); 56 if (cf->srch_inf.endOfSearch) 57 cFYI(1, "end of search"); 58 if (cf->srch_inf.emptyDir) 59 cFYI(1, "empty dir"); 60 } 61} 62#else 63static inline void dump_cifs_file_struct(struct file *file, char *label) 64{ 65} 66#endif /* DEBUG2 */ 67 68/* 69 * Find the dentry that matches "name". If there isn't one, create one. If it's 70 * a negative dentry or the uniqueid changed, then drop it and recreate it. 71 */ 72static struct dentry * 73cifs_readdir_lookup(struct dentry *parent, struct qstr *name, 74 struct cifs_fattr *fattr) 75{ 76 struct dentry *dentry, *alias; 77 struct inode *inode; 78 struct super_block *sb = parent->d_inode->i_sb; 79 80 cFYI(1, "For %s", name->name); 81 82 if (parent->d_op && parent->d_op->d_hash) 83 parent->d_op->d_hash(parent, parent->d_inode, name); 84 else 85 name->hash = full_name_hash(name->name, name->len); 86 87 dentry = d_lookup(parent, name); 88 if (dentry) { 89 inode = dentry->d_inode; 90 /* update inode in place if i_ino didn't change */ 91 if (inode && CIFS_I(inode)->uniqueid == fattr->cf_uniqueid) { 92 cifs_fattr_to_inode(inode, fattr); 93 return dentry; 94 } 95 d_drop(dentry); 96 dput(dentry); 97 } 98 99 dentry = d_alloc(parent, name); 100 if (dentry == NULL) 101 return NULL; 102 103 inode = cifs_iget(sb, fattr); 104 if (!inode) { 105 dput(dentry); 106 return NULL; 107 } 108 109 alias = d_materialise_unique(dentry, inode); 110 if (alias != NULL) { 111 dput(dentry); 112 if (IS_ERR(alias)) 113 return NULL; 114 dentry = alias; 115 } 116 117 return dentry; 118} 119 120static void 121cifs_fill_common_info(struct cifs_fattr *fattr, struct cifs_sb_info *cifs_sb) 122{ 123 fattr->cf_uid = cifs_sb->mnt_uid; 124 fattr->cf_gid = cifs_sb->mnt_gid; 125 126 if (fattr->cf_cifsattrs & ATTR_DIRECTORY) { 127 fattr->cf_mode = S_IFDIR | cifs_sb->mnt_dir_mode; 128 fattr->cf_dtype = DT_DIR; 129 } else { 130 fattr->cf_mode = S_IFREG | cifs_sb->mnt_file_mode; 131 fattr->cf_dtype = DT_REG; 132 } 133 134 if (fattr->cf_cifsattrs & ATTR_READONLY) 135 fattr->cf_mode &= ~S_IWUGO; 136 137 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL && 138 fattr->cf_cifsattrs & ATTR_SYSTEM) { 139 if (fattr->cf_eof == 0) { 140 fattr->cf_mode &= ~S_IFMT; 141 fattr->cf_mode |= S_IFIFO; 142 fattr->cf_dtype = DT_FIFO; 143 } else { 144 /* 145 * trying to get the type and mode via SFU can be slow, 146 * so just call those regular files for now, and mark 147 * for reval 148 */ 149 fattr->cf_flags |= CIFS_FATTR_NEED_REVAL; 150 } 151 } 152} 153 154static void 155cifs_dir_info_to_fattr(struct cifs_fattr *fattr, FILE_DIRECTORY_INFO *info, 156 struct cifs_sb_info *cifs_sb) 157{ 158 memset(fattr, 0, sizeof(*fattr)); 159 fattr->cf_cifsattrs = le32_to_cpu(info->ExtFileAttributes); 160 fattr->cf_eof = le64_to_cpu(info->EndOfFile); 161 fattr->cf_bytes = le64_to_cpu(info->AllocationSize); 162 fattr->cf_createtime = le64_to_cpu(info->CreationTime); 163 fattr->cf_atime = cifs_NTtimeToUnix(info->LastAccessTime); 164 fattr->cf_ctime = cifs_NTtimeToUnix(info->ChangeTime); 165 fattr->cf_mtime = cifs_NTtimeToUnix(info->LastWriteTime); 166 167 cifs_fill_common_info(fattr, cifs_sb); 168} 169 170static void 171cifs_std_info_to_fattr(struct cifs_fattr *fattr, FIND_FILE_STANDARD_INFO *info, 172 struct cifs_sb_info *cifs_sb) 173{ 174 int offset = cifs_sb_master_tcon(cifs_sb)->ses->server->timeAdj; 175 176 memset(fattr, 0, sizeof(*fattr)); 177 fattr->cf_atime = cnvrtDosUnixTm(info->LastAccessDate, 178 info->LastAccessTime, offset); 179 fattr->cf_ctime = cnvrtDosUnixTm(info->LastWriteDate, 180 info->LastWriteTime, offset); 181 fattr->cf_mtime = cnvrtDosUnixTm(info->LastWriteDate, 182 info->LastWriteTime, offset); 183 184 fattr->cf_cifsattrs = le16_to_cpu(info->Attributes); 185 fattr->cf_bytes = le32_to_cpu(info->AllocationSize); 186 fattr->cf_eof = le32_to_cpu(info->DataSize); 187 188 cifs_fill_common_info(fattr, cifs_sb); 189} 190 191/* BB eventually need to add the following helper function to 192 resolve NT_STATUS_STOPPED_ON_SYMLINK return code when 193 we try to do FindFirst on (NTFS) directory symlinks */ 194/* 195int get_symlink_reparse_path(char *full_path, struct cifs_sb_info *cifs_sb, 196 int xid) 197{ 198 __u16 fid; 199 int len; 200 int oplock = 0; 201 int rc; 202 struct cifs_tcon *ptcon = cifs_sb_tcon(cifs_sb); 203 char *tmpbuffer; 204 205 rc = CIFSSMBOpen(xid, ptcon, full_path, FILE_OPEN, GENERIC_READ, 206 OPEN_REPARSE_POINT, &fid, &oplock, NULL, 207 cifs_sb->local_nls, 208 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); 209 if (!rc) { 210 tmpbuffer = kmalloc(maxpath); 211 rc = CIFSSMBQueryReparseLinkInfo(xid, ptcon, full_path, 212 tmpbuffer, 213 maxpath -1, 214 fid, 215 cifs_sb->local_nls); 216 if (CIFSSMBClose(xid, ptcon, fid)) { 217 cFYI(1, "Error closing temporary reparsepoint open"); 218 } 219 } 220} 221 */ 222 223static int initiate_cifs_search(const int xid, struct file *file) 224{ 225 __u16 search_flags; 226 int rc = 0; 227 char *full_path = NULL; 228 struct cifsFileInfo *cifsFile; 229 struct cifs_sb_info *cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); 230 struct tcon_link *tlink = NULL; 231 struct cifs_tcon *pTcon; 232 233 if (file->private_data == NULL) { 234 tlink = cifs_sb_tlink(cifs_sb); 235 if (IS_ERR(tlink)) 236 return PTR_ERR(tlink); 237 238 cifsFile = kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL); 239 if (cifsFile == NULL) { 240 rc = -ENOMEM; 241 goto error_exit; 242 } 243 file->private_data = cifsFile; 244 cifsFile->tlink = cifs_get_tlink(tlink); 245 pTcon = tlink_tcon(tlink); 246 } else { 247 cifsFile = file->private_data; 248 pTcon = tlink_tcon(cifsFile->tlink); 249 } 250 251 cifsFile->invalidHandle = true; 252 cifsFile->srch_inf.endOfSearch = false; 253 254 full_path = build_path_from_dentry(file->f_path.dentry); 255 if (full_path == NULL) { 256 rc = -ENOMEM; 257 goto error_exit; 258 } 259 260 cFYI(1, "Full path: %s start at: %lld", full_path, file->f_pos); 261 262ffirst_retry: 263 /* test for Unix extensions */ 264 /* but now check for them on the share/mount not on the SMB session */ 265/* if (pTcon->ses->capabilities & CAP_UNIX) { */ 266 if (pTcon->unix_ext) 267 cifsFile->srch_inf.info_level = SMB_FIND_FILE_UNIX; 268 else if ((pTcon->ses->capabilities & 269 (CAP_NT_SMBS | CAP_NT_FIND)) == 0) { 270 cifsFile->srch_inf.info_level = SMB_FIND_FILE_INFO_STANDARD; 271 } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) { 272 cifsFile->srch_inf.info_level = SMB_FIND_FILE_ID_FULL_DIR_INFO; 273 } else /* not srvinos - BB fixme add check for backlevel? */ { 274 cifsFile->srch_inf.info_level = SMB_FIND_FILE_DIRECTORY_INFO; 275 } 276 277 search_flags = CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME; 278 if (backup_cred(cifs_sb)) 279 search_flags |= CIFS_SEARCH_BACKUP_SEARCH; 280 281 rc = CIFSFindFirst(xid, pTcon, full_path, cifs_sb->local_nls, 282 &cifsFile->netfid, search_flags, &cifsFile->srch_inf, 283 cifs_sb->mnt_cifs_flags & 284 CIFS_MOUNT_MAP_SPECIAL_CHR, CIFS_DIR_SEP(cifs_sb)); 285 if (rc == 0) 286 cifsFile->invalidHandle = false; 287 /* BB add following call to handle readdir on new NTFS symlink errors 288 else if STATUS_STOPPED_ON_SYMLINK 289 call get_symlink_reparse_path and retry with new path */ 290 else if ((rc == -EOPNOTSUPP) && 291 (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)) { 292 cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_SERVER_INUM; 293 goto ffirst_retry; 294 } 295error_exit: 296 kfree(full_path); 297 cifs_put_tlink(tlink); 298 return rc; 299} 300 301/* return length of unicode string in bytes */ 302static int cifs_unicode_bytelen(const char *str) 303{ 304 int len; 305 const __le16 *ustr = (const __le16 *)str; 306 307 for (len = 0; len <= PATH_MAX; len++) { 308 if (ustr[len] == 0) 309 return len << 1; 310 } 311 cFYI(1, "Unicode string longer than PATH_MAX found"); 312 return len << 1; 313} 314 315static char *nxt_dir_entry(char *old_entry, char *end_of_smb, int level) 316{ 317 char *new_entry; 318 FILE_DIRECTORY_INFO *pDirInfo = (FILE_DIRECTORY_INFO *)old_entry; 319 320 if (level == SMB_FIND_FILE_INFO_STANDARD) { 321 FIND_FILE_STANDARD_INFO *pfData; 322 pfData = (FIND_FILE_STANDARD_INFO *)pDirInfo; 323 324 new_entry = old_entry + sizeof(FIND_FILE_STANDARD_INFO) + 325 pfData->FileNameLength; 326 } else 327 new_entry = old_entry + le32_to_cpu(pDirInfo->NextEntryOffset); 328 cFYI(1, "new entry %p old entry %p", new_entry, old_entry); 329 /* validate that new_entry is not past end of SMB */ 330 if (new_entry >= end_of_smb) { 331 cERROR(1, "search entry %p began after end of SMB %p old entry %p", 332 new_entry, end_of_smb, old_entry); 333 return NULL; 334 } else if (((level == SMB_FIND_FILE_INFO_STANDARD) && 335 (new_entry + sizeof(FIND_FILE_STANDARD_INFO) > end_of_smb)) 336 || ((level != SMB_FIND_FILE_INFO_STANDARD) && 337 (new_entry + sizeof(FILE_DIRECTORY_INFO) > end_of_smb))) { 338 cERROR(1, "search entry %p extends after end of SMB %p", 339 new_entry, end_of_smb); 340 return NULL; 341 } else 342 return new_entry; 343 344} 345 346struct cifs_dirent { 347 const char *name; 348 size_t namelen; 349 u32 resume_key; 350 u64 ino; 351}; 352 353static void cifs_fill_dirent_unix(struct cifs_dirent *de, 354 const FILE_UNIX_INFO *info, bool is_unicode) 355{ 356 de->name = &info->FileName[0]; 357 if (is_unicode) 358 de->namelen = cifs_unicode_bytelen(de->name); 359 else 360 de->namelen = strnlen(de->name, PATH_MAX); 361 de->resume_key = info->ResumeKey; 362 de->ino = le64_to_cpu(info->basic.UniqueId); 363} 364 365static void cifs_fill_dirent_dir(struct cifs_dirent *de, 366 const FILE_DIRECTORY_INFO *info) 367{ 368 de->name = &info->FileName[0]; 369 de->namelen = le32_to_cpu(info->FileNameLength); 370 de->resume_key = info->FileIndex; 371} 372 373static void cifs_fill_dirent_full(struct cifs_dirent *de, 374 const FILE_FULL_DIRECTORY_INFO *info) 375{ 376 de->name = &info->FileName[0]; 377 de->namelen = le32_to_cpu(info->FileNameLength); 378 de->resume_key = info->FileIndex; 379} 380 381static void cifs_fill_dirent_search(struct cifs_dirent *de, 382 const SEARCH_ID_FULL_DIR_INFO *info) 383{ 384 de->name = &info->FileName[0]; 385 de->namelen = le32_to_cpu(info->FileNameLength); 386 de->resume_key = info->FileIndex; 387 de->ino = le64_to_cpu(info->UniqueId); 388} 389 390static void cifs_fill_dirent_both(struct cifs_dirent *de, 391 const FILE_BOTH_DIRECTORY_INFO *info) 392{ 393 de->name = &info->FileName[0]; 394 de->namelen = le32_to_cpu(info->FileNameLength); 395 de->resume_key = info->FileIndex; 396} 397 398static void cifs_fill_dirent_std(struct cifs_dirent *de, 399 const FIND_FILE_STANDARD_INFO *info) 400{ 401 de->name = &info->FileName[0]; 402 /* one byte length, no endianess conversion */ 403 de->namelen = info->FileNameLength; 404 de->resume_key = info->ResumeKey; 405} 406 407static int cifs_fill_dirent(struct cifs_dirent *de, const void *info, 408 u16 level, bool is_unicode) 409{ 410 memset(de, 0, sizeof(*de)); 411 412 switch (level) { 413 case SMB_FIND_FILE_UNIX: 414 cifs_fill_dirent_unix(de, info, is_unicode); 415 break; 416 case SMB_FIND_FILE_DIRECTORY_INFO: 417 cifs_fill_dirent_dir(de, info); 418 break; 419 case SMB_FIND_FILE_FULL_DIRECTORY_INFO: 420 cifs_fill_dirent_full(de, info); 421 break; 422 case SMB_FIND_FILE_ID_FULL_DIR_INFO: 423 cifs_fill_dirent_search(de, info); 424 break; 425 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO: 426 cifs_fill_dirent_both(de, info); 427 break; 428 case SMB_FIND_FILE_INFO_STANDARD: 429 cifs_fill_dirent_std(de, info); 430 break; 431 default: 432 cFYI(1, "Unknown findfirst level %d", level); 433 return -EINVAL; 434 } 435 436 return 0; 437} 438 439#define UNICODE_DOT cpu_to_le16(0x2e) 440 441/* return 0 if no match and 1 for . (current directory) and 2 for .. (parent) */ 442static int cifs_entry_is_dot(struct cifs_dirent *de, bool is_unicode) 443{ 444 int rc = 0; 445 446 if (!de->name) 447 return 0; 448 449 if (is_unicode) { 450 __le16 *ufilename = (__le16 *)de->name; 451 if (de->namelen == 2) { 452 /* check for . */ 453 if (ufilename[0] == UNICODE_DOT) 454 rc = 1; 455 } else if (de->namelen == 4) { 456 /* check for .. */ 457 if (ufilename[0] == UNICODE_DOT && 458 ufilename[1] == UNICODE_DOT) 459 rc = 2; 460 } 461 } else /* ASCII */ { 462 if (de->namelen == 1) { 463 if (de->name[0] == '.') 464 rc = 1; 465 } else if (de->namelen == 2) { 466 if (de->name[0] == '.' && de->name[1] == '.') 467 rc = 2; 468 } 469 } 470 471 return rc; 472} 473 474/* Check if directory that we are searching has changed so we can decide 475 whether we can use the cached search results from the previous search */ 476static int is_dir_changed(struct file *file) 477{ 478 struct inode *inode = file->f_path.dentry->d_inode; 479 struct cifsInodeInfo *cifsInfo = CIFS_I(inode); 480 481 if (cifsInfo->time == 0) 482 return 1; /* directory was changed, perhaps due to unlink */ 483 else 484 return 0; 485 486} 487 488static int cifs_save_resume_key(const char *current_entry, 489 struct cifsFileInfo *file_info) 490{ 491 struct cifs_dirent de; 492 int rc; 493 494 rc = cifs_fill_dirent(&de, current_entry, file_info->srch_inf.info_level, 495 file_info->srch_inf.unicode); 496 if (!rc) { 497 file_info->srch_inf.presume_name = de.name; 498 file_info->srch_inf.resume_name_len = de.namelen; 499 file_info->srch_inf.resume_key = de.resume_key; 500 } 501 return rc; 502} 503 504/* find the corresponding entry in the search */ 505/* Note that the SMB server returns search entries for . and .. which 506 complicates logic here if we choose to parse for them and we do not 507 assume that they are located in the findfirst return buffer.*/ 508/* We start counting in the buffer with entry 2 and increment for every 509 entry (do not increment for . or .. entry) */ 510static int find_cifs_entry(const int xid, struct cifs_tcon *pTcon, 511 struct file *file, char **ppCurrentEntry, int *num_to_ret) 512{ 513 __u16 search_flags; 514 int rc = 0; 515 int pos_in_buf = 0; 516 loff_t first_entry_in_buffer; 517 loff_t index_to_find = file->f_pos; 518 struct cifsFileInfo *cifsFile = file->private_data; 519 struct cifs_sb_info *cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); 520 /* check if index in the buffer */ 521 522 if ((cifsFile == NULL) || (ppCurrentEntry == NULL) || 523 (num_to_ret == NULL)) 524 return -ENOENT; 525 526 *ppCurrentEntry = NULL; 527 first_entry_in_buffer = 528 cifsFile->srch_inf.index_of_last_entry - 529 cifsFile->srch_inf.entries_in_buffer; 530 531 /* if first entry in buf is zero then is first buffer 532 in search response data which means it is likely . and .. 533 will be in this buffer, although some servers do not return 534 . and .. for the root of a drive and for those we need 535 to start two entries earlier */ 536 537 dump_cifs_file_struct(file, "In fce "); 538 if (((index_to_find < cifsFile->srch_inf.index_of_last_entry) && 539 is_dir_changed(file)) || 540 (index_to_find < first_entry_in_buffer)) { 541 /* close and restart search */ 542 cFYI(1, "search backing up - close and restart search"); 543 spin_lock(&cifs_file_list_lock); 544 if (!cifsFile->srch_inf.endOfSearch && 545 !cifsFile->invalidHandle) { 546 cifsFile->invalidHandle = true; 547 spin_unlock(&cifs_file_list_lock); 548 CIFSFindClose(xid, pTcon, cifsFile->netfid); 549 } else 550 spin_unlock(&cifs_file_list_lock); 551 if (cifsFile->srch_inf.ntwrk_buf_start) { 552 cFYI(1, "freeing SMB ff cache buf on search rewind"); 553 if (cifsFile->srch_inf.smallBuf) 554 cifs_small_buf_release(cifsFile->srch_inf. 555 ntwrk_buf_start); 556 else 557 cifs_buf_release(cifsFile->srch_inf. 558 ntwrk_buf_start); 559 cifsFile->srch_inf.ntwrk_buf_start = NULL; 560 } 561 rc = initiate_cifs_search(xid, file); 562 if (rc) { 563 cFYI(1, "error %d reinitiating a search on rewind", 564 rc); 565 return rc; 566 } 567 /* FindFirst/Next set last_entry to NULL on malformed reply */ 568 if (cifsFile->srch_inf.last_entry) 569 cifs_save_resume_key(cifsFile->srch_inf.last_entry, 570 cifsFile); 571 } 572 573 search_flags = CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME; 574 if (backup_cred(cifs_sb)) 575 search_flags |= CIFS_SEARCH_BACKUP_SEARCH; 576 577 while ((index_to_find >= cifsFile->srch_inf.index_of_last_entry) && 578 (rc == 0) && !cifsFile->srch_inf.endOfSearch) { 579 cFYI(1, "calling findnext2"); 580 rc = CIFSFindNext(xid, pTcon, cifsFile->netfid, search_flags, 581 &cifsFile->srch_inf); 582 /* FindFirst/Next set last_entry to NULL on malformed reply */ 583 if (cifsFile->srch_inf.last_entry) 584 cifs_save_resume_key(cifsFile->srch_inf.last_entry, 585 cifsFile); 586 if (rc) 587 return -ENOENT; 588 } 589 if (index_to_find < cifsFile->srch_inf.index_of_last_entry) { 590 /* we found the buffer that contains the entry */ 591 /* scan and find it */ 592 int i; 593 char *current_entry; 594 char *end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + 595 smbCalcSize((struct smb_hdr *) 596 cifsFile->srch_inf.ntwrk_buf_start); 597 598 current_entry = cifsFile->srch_inf.srch_entries_start; 599 first_entry_in_buffer = cifsFile->srch_inf.index_of_last_entry 600 - cifsFile->srch_inf.entries_in_buffer; 601 pos_in_buf = index_to_find - first_entry_in_buffer; 602 cFYI(1, "found entry - pos_in_buf %d", pos_in_buf); 603 604 for (i = 0; (i < (pos_in_buf)) && (current_entry != NULL); i++) { 605 /* go entry by entry figuring out which is first */ 606 current_entry = nxt_dir_entry(current_entry, end_of_smb, 607 cifsFile->srch_inf.info_level); 608 } 609 if ((current_entry == NULL) && (i < pos_in_buf)) { 610 /* BB fixme - check if we should flag this error */ 611 cERROR(1, "reached end of buf searching for pos in buf" 612 " %d index to find %lld rc %d", 613 pos_in_buf, index_to_find, rc); 614 } 615 rc = 0; 616 *ppCurrentEntry = current_entry; 617 } else { 618 cFYI(1, "index not in buffer - could not findnext into it"); 619 return 0; 620 } 621 622 if (pos_in_buf >= cifsFile->srch_inf.entries_in_buffer) { 623 cFYI(1, "can not return entries pos_in_buf beyond last"); 624 *num_to_ret = 0; 625 } else 626 *num_to_ret = cifsFile->srch_inf.entries_in_buffer - pos_in_buf; 627 628 return rc; 629} 630 631static int cifs_filldir(char *find_entry, struct file *file, filldir_t filldir, 632 void *dirent, char *scratch_buf, unsigned int max_len) 633{ 634 struct cifsFileInfo *file_info = file->private_data; 635 struct super_block *sb = file->f_path.dentry->d_sb; 636 struct cifs_sb_info *cifs_sb = CIFS_SB(sb); 637 struct cifs_dirent de = { NULL, }; 638 struct cifs_fattr fattr; 639 struct dentry *dentry; 640 struct qstr name; 641 int rc = 0; 642 ino_t ino; 643 644 rc = cifs_fill_dirent(&de, find_entry, file_info->srch_inf.info_level, 645 file_info->srch_inf.unicode); 646 if (rc) 647 return rc; 648 649 if (de.namelen > max_len) { 650 cERROR(1, "bad search response length %zd past smb end", 651 de.namelen); 652 return -EINVAL; 653 } 654 655 /* skip . and .. since we added them first */ 656 if (cifs_entry_is_dot(&de, file_info->srch_inf.unicode)) 657 return 0; 658 659 if (file_info->srch_inf.unicode) { 660 struct nls_table *nlt = cifs_sb->local_nls; 661 662 name.name = scratch_buf; 663 name.len = 664 cifs_from_utf16((char *)name.name, (__le16 *)de.name, 665 UNICODE_NAME_MAX, 666 min_t(size_t, de.namelen, 667 (size_t)max_len), nlt, 668 cifs_sb->mnt_cifs_flags & 669 CIFS_MOUNT_MAP_SPECIAL_CHR); 670 name.len -= nls_nullsize(nlt); 671 } else { 672 name.name = de.name; 673 name.len = de.namelen; 674 } 675 676 switch (file_info->srch_inf.info_level) { 677 case SMB_FIND_FILE_UNIX: 678 cifs_unix_basic_to_fattr(&fattr, 679 &((FILE_UNIX_INFO *)find_entry)->basic, 680 cifs_sb); 681 break; 682 case SMB_FIND_FILE_INFO_STANDARD: 683 cifs_std_info_to_fattr(&fattr, 684 (FIND_FILE_STANDARD_INFO *)find_entry, 685 cifs_sb); 686 break; 687 default: 688 cifs_dir_info_to_fattr(&fattr, 689 (FILE_DIRECTORY_INFO *)find_entry, 690 cifs_sb); 691 break; 692 } 693 694 if (de.ino && (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)) { 695 fattr.cf_uniqueid = de.ino; 696 } else { 697 fattr.cf_uniqueid = iunique(sb, ROOT_I); 698 cifs_autodisable_serverino(cifs_sb); 699 } 700 701 if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) && 702 CIFSCouldBeMFSymlink(&fattr)) 703 /* 704 * trying to get the type and mode can be slow, 705 * so just call those regular files for now, and mark 706 * for reval 707 */ 708 fattr.cf_flags |= CIFS_FATTR_NEED_REVAL; 709 710 ino = cifs_uniqueid_to_ino_t(fattr.cf_uniqueid); 711 dentry = cifs_readdir_lookup(file->f_dentry, &name, &fattr); 712 713 rc = filldir(dirent, name.name, name.len, file->f_pos, ino, 714 fattr.cf_dtype); 715 716 dput(dentry); 717 return rc; 718} 719 720 721int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) 722{ 723 int rc = 0; 724 int xid, i; 725 struct cifs_tcon *pTcon; 726 struct cifsFileInfo *cifsFile = NULL; 727 char *current_entry; 728 int num_to_fill = 0; 729 char *tmp_buf = NULL; 730 char *end_of_smb; 731 unsigned int max_len; 732 733 xid = GetXid(); 734 735 /* 736 * Ensure FindFirst doesn't fail before doing filldir() for '.' and 737 * '..'. Otherwise we won't be able to notify VFS in case of failure. 738 */ 739 if (file->private_data == NULL) { 740 rc = initiate_cifs_search(xid, file); 741 cFYI(1, "initiate cifs search rc %d", rc); 742 if (rc) 743 goto rddir2_exit; 744 } 745 746 switch ((int) file->f_pos) { 747 case 0: 748 if (filldir(direntry, ".", 1, file->f_pos, 749 file->f_path.dentry->d_inode->i_ino, DT_DIR) < 0) { 750 cERROR(1, "Filldir for current dir failed"); 751 rc = -ENOMEM; 752 break; 753 } 754 file->f_pos++; 755 case 1: 756 if (filldir(direntry, "..", 2, file->f_pos, 757 parent_ino(file->f_path.dentry), DT_DIR) < 0) { 758 cERROR(1, "Filldir for parent dir failed"); 759 rc = -ENOMEM; 760 break; 761 } 762 file->f_pos++; 763 default: 764 /* 1) If search is active, 765 is in current search buffer? 766 if it before then restart search 767 if after then keep searching till find it */ 768 769 if (file->private_data == NULL) { 770 rc = -EINVAL; 771 FreeXid(xid); 772 return rc; 773 } 774 cifsFile = file->private_data; 775 if (cifsFile->srch_inf.endOfSearch) { 776 if (cifsFile->srch_inf.emptyDir) { 777 cFYI(1, "End of search, empty dir"); 778 rc = 0; 779 break; 780 } 781 } /* else { 782 cifsFile->invalidHandle = true; 783 CIFSFindClose(xid, pTcon, cifsFile->netfid); 784 } */ 785 786 pTcon = tlink_tcon(cifsFile->tlink); 787 rc = find_cifs_entry(xid, pTcon, file, 788 &current_entry, &num_to_fill); 789 if (rc) { 790 cFYI(1, "fce error %d", rc); 791 goto rddir2_exit; 792 } else if (current_entry != NULL) { 793 cFYI(1, "entry %lld found", file->f_pos); 794 } else { 795 cFYI(1, "could not find entry"); 796 goto rddir2_exit; 797 } 798 cFYI(1, "loop through %d times filling dir for net buf %p", 799 num_to_fill, cifsFile->srch_inf.ntwrk_buf_start); 800 max_len = smbCalcSize((struct smb_hdr *) 801 cifsFile->srch_inf.ntwrk_buf_start); 802 end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + max_len; 803 804 tmp_buf = kmalloc(UNICODE_NAME_MAX, GFP_KERNEL); 805 if (tmp_buf == NULL) { 806 rc = -ENOMEM; 807 break; 808 } 809 810 for (i = 0; (i < num_to_fill) && (rc == 0); i++) { 811 if (current_entry == NULL) { 812 /* evaluate whether this case is an error */ 813 cERROR(1, "past SMB end, num to fill %d i %d", 814 num_to_fill, i); 815 break; 816 } 817 /* if buggy server returns . and .. late do 818 we want to check for that here? */ 819 rc = cifs_filldir(current_entry, file, 820 filldir, direntry, tmp_buf, max_len); 821 if (rc == -EOVERFLOW) { 822 rc = 0; 823 break; 824 } 825 826 file->f_pos++; 827 if (file->f_pos == 828 cifsFile->srch_inf.index_of_last_entry) { 829 cFYI(1, "last entry in buf at pos %lld %s", 830 file->f_pos, tmp_buf); 831 cifs_save_resume_key(current_entry, cifsFile); 832 break; 833 } else 834 current_entry = 835 nxt_dir_entry(current_entry, end_of_smb, 836 cifsFile->srch_inf.info_level); 837 } 838 kfree(tmp_buf); 839 break; 840 } /* end switch */ 841 842rddir2_exit: 843 FreeXid(xid); 844 return rc; 845}