1/* 2 * fs/cifs/readdir.c 3 * 4 * Directory search handling 5 * 6 * Copyright (C) International Business Machines Corp., 2004, 2007 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/pagemap.h> 25#include <linux/stat.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#ifdef CONFIG_CIFS_DEBUG2 35static 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#endif /* DEBUG2 */ 58 59/* Returns one if new inode created (which therefore needs to be hashed) */ 60/* Might check in the future if inode number changed so we can rehash inode */ 61static int construct_dentry(struct qstr *qstring, struct file *file, 62 struct inode **ptmp_inode, struct dentry **pnew_dentry) 63{ 64 struct dentry *tmp_dentry; 65 struct cifs_sb_info *cifs_sb; 66 struct cifsTconInfo *pTcon; 67 int rc = 0; 68 69 cFYI(1, ("For %s", qstring->name)); 70 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); 71 pTcon = cifs_sb->tcon; 72 73 qstring->hash = full_name_hash(qstring->name, qstring->len); 74 tmp_dentry = d_lookup(file->f_path.dentry, qstring); 75 if (tmp_dentry) { 76 cFYI(0, ("existing dentry with inode 0x%p", tmp_dentry->d_inode)); 77 *ptmp_inode = tmp_dentry->d_inode; 78/* BB overwrite old name? i.e. tmp_dentry->d_name and tmp_dentry->d_name.len??*/ 79 if (*ptmp_inode == NULL) { 80 *ptmp_inode = new_inode(file->f_path.dentry->d_sb); 81 if (*ptmp_inode == NULL) 82 return rc; 83 rc = 1; 84 } 85 if (file->f_path.dentry->d_sb->s_flags & MS_NOATIME) 86 (*ptmp_inode)->i_flags |= S_NOATIME | S_NOCMTIME; 87 } else { 88 tmp_dentry = d_alloc(file->f_path.dentry, qstring); 89 if (tmp_dentry == NULL) { 90 cERROR(1,("Failed allocating dentry")); 91 *ptmp_inode = NULL; 92 return rc; 93 } 94 95 *ptmp_inode = new_inode(file->f_path.dentry->d_sb); 96 if (pTcon->nocase) 97 tmp_dentry->d_op = &cifs_ci_dentry_ops; 98 else 99 tmp_dentry->d_op = &cifs_dentry_ops; 100 if (*ptmp_inode == NULL) 101 return rc; 102 if (file->f_path.dentry->d_sb->s_flags & MS_NOATIME) 103 (*ptmp_inode)->i_flags |= S_NOATIME | S_NOCMTIME; 104 rc = 2; 105 } 106 107 tmp_dentry->d_time = jiffies; 108 *pnew_dentry = tmp_dentry; 109 return rc; 110} 111 112static void AdjustForTZ(struct cifsTconInfo * tcon, struct inode * inode) 113{ 114 if ((tcon) && (tcon->ses) && (tcon->ses->server)) { 115 inode->i_ctime.tv_sec += tcon->ses->server->timeAdj; 116 inode->i_mtime.tv_sec += tcon->ses->server->timeAdj; 117 inode->i_atime.tv_sec += tcon->ses->server->timeAdj; 118 } 119 return; 120} 121 122 123static void fill_in_inode(struct inode *tmp_inode, int new_buf_type, 124 char * buf, int *pobject_type, int isNewInode) 125{ 126 loff_t local_size; 127 struct timespec local_mtime; 128 129 struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode); 130 struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb); 131 __u32 attr; 132 __u64 allocation_size; 133 __u64 end_of_file; 134 135 /* save mtime and size */ 136 local_mtime = tmp_inode->i_mtime; 137 local_size = tmp_inode->i_size; 138 139 if (new_buf_type) { 140 FILE_DIRECTORY_INFO *pfindData = (FILE_DIRECTORY_INFO *)buf; 141 142 attr = le32_to_cpu(pfindData->ExtFileAttributes); 143 allocation_size = le64_to_cpu(pfindData->AllocationSize); 144 end_of_file = le64_to_cpu(pfindData->EndOfFile); 145 tmp_inode->i_atime = 146 cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime)); 147 tmp_inode->i_mtime = 148 cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime)); 149 tmp_inode->i_ctime = 150 cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime)); 151 } else { /* legacy, OS2 and DOS style */ 152/* struct timespec ts;*/ 153 FIND_FILE_STANDARD_INFO * pfindData = 154 (FIND_FILE_STANDARD_INFO *)buf; 155 156 tmp_inode->i_mtime = cnvrtDosUnixTm( 157 le16_to_cpu(pfindData->LastWriteDate), 158 le16_to_cpu(pfindData->LastWriteTime)); 159 tmp_inode->i_atime = cnvrtDosUnixTm( 160 le16_to_cpu(pfindData->LastAccessDate), 161 le16_to_cpu(pfindData->LastAccessTime)); 162 tmp_inode->i_ctime = cnvrtDosUnixTm( 163 le16_to_cpu(pfindData->LastWriteDate), 164 le16_to_cpu(pfindData->LastWriteTime)); 165 AdjustForTZ(cifs_sb->tcon, tmp_inode); 166 attr = le16_to_cpu(pfindData->Attributes); 167 allocation_size = le32_to_cpu(pfindData->AllocationSize); 168 end_of_file = le32_to_cpu(pfindData->DataSize); 169 } 170 171 /* Linux can not store file creation time unfortunately so ignore it */ 172 173 cifsInfo->cifsAttrs = attr; 174 cifsInfo->time = jiffies; 175 176 /* treat dos attribute of read-only as read-only mode bit e.g. 555? */ 177 /* 2767 perms - indicate mandatory locking */ 178 /* BB fill in uid and gid here? with help from winbind? 179 or retrieve from NTFS stream extended attribute */ 180 if (atomic_read(&cifsInfo->inUse) == 0) { 181 tmp_inode->i_uid = cifs_sb->mnt_uid; 182 tmp_inode->i_gid = cifs_sb->mnt_gid; 183 /* set default mode. will override for dirs below */ 184 tmp_inode->i_mode = cifs_sb->mnt_file_mode; 185 } else { 186 /* mask off the type bits since it gets set 187 below and we do not want to get two type 188 bits set */ 189 tmp_inode->i_mode &= ~S_IFMT; 190 } 191 192 if (attr & ATTR_DIRECTORY) { 193 *pobject_type = DT_DIR; 194 /* override default perms since we do not lock dirs */ 195 if (atomic_read(&cifsInfo->inUse) == 0) { 196 tmp_inode->i_mode = cifs_sb->mnt_dir_mode; 197 } 198 tmp_inode->i_mode |= S_IFDIR; 199 } else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) && 200 (attr & ATTR_SYSTEM)) { 201 if (end_of_file == 0) { 202 *pobject_type = DT_FIFO; 203 tmp_inode->i_mode |= S_IFIFO; 204 } else { 205 /* rather than get the type here, we mark the 206 inode as needing revalidate and get the real type 207 (blk vs chr vs. symlink) later ie in lookup */ 208 *pobject_type = DT_REG; 209 tmp_inode->i_mode |= S_IFREG; 210 cifsInfo->time = 0; 211 } 212/* we no longer mark these because we could not follow them */ 213/* } else if (attr & ATTR_REPARSE) { 214 *pobject_type = DT_LNK; 215 tmp_inode->i_mode |= S_IFLNK; */ 216 } else { 217 *pobject_type = DT_REG; 218 tmp_inode->i_mode |= S_IFREG; 219 if (attr & ATTR_READONLY) 220 tmp_inode->i_mode &= ~(S_IWUGO); 221 else if ((tmp_inode->i_mode & S_IWUGO) == 0) 222 /* the ATTR_READONLY flag may have been changed on */ 223 /* server -- set any w bits allowed by mnt_file_mode */ 224 tmp_inode->i_mode |= (S_IWUGO & cifs_sb->mnt_file_mode); 225 } /* could add code here - to validate if device or weird share type? */ 226 227 /* can not fill in nlink here as in qpathinfo version and Unx search */ 228 if (atomic_read(&cifsInfo->inUse) == 0) { 229 atomic_set(&cifsInfo->inUse, 1); 230 } 231 232 spin_lock(&tmp_inode->i_lock); 233 if (is_size_safe_to_change(cifsInfo, end_of_file)) { 234 /* can not safely change the file size here if the 235 client is writing to it due to potential races */ 236 i_size_write(tmp_inode, end_of_file); 237 238 /* 512 bytes (2**9) is the fake blocksize that must be used */ 239 /* for this calculation, even though the reported blocksize is larger */ 240 tmp_inode->i_blocks = (512 - 1 + allocation_size) >> 9; 241 } 242 spin_unlock(&tmp_inode->i_lock); 243 244 if (allocation_size < end_of_file) 245 cFYI(1, ("May be sparse file, allocation less than file size")); 246 cFYI(1, ("File Size %ld and blocks %llu", 247 (unsigned long)tmp_inode->i_size, 248 (unsigned long long)tmp_inode->i_blocks)); 249 if (S_ISREG(tmp_inode->i_mode)) { 250 cFYI(1, ("File inode")); 251 tmp_inode->i_op = &cifs_file_inode_ops; 252 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) { 253 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) 254 tmp_inode->i_fop = &cifs_file_direct_nobrl_ops; 255 else 256 tmp_inode->i_fop = &cifs_file_direct_ops; 257 258 } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) 259 tmp_inode->i_fop = &cifs_file_nobrl_ops; 260 else 261 tmp_inode->i_fop = &cifs_file_ops; 262 263 if ((cifs_sb->tcon) && (cifs_sb->tcon->ses) && 264 (cifs_sb->tcon->ses->server->maxBuf < 265 PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE)) 266 tmp_inode->i_data.a_ops = &cifs_addr_ops_smallbuf; 267 else 268 tmp_inode->i_data.a_ops = &cifs_addr_ops; 269 270 if (isNewInode) 271 return; /* No sense invalidating pages for new inode 272 since have not started caching readahead file 273 data yet */ 274 275 if (timespec_equal(&tmp_inode->i_mtime, &local_mtime) && 276 (local_size == tmp_inode->i_size)) { 277 cFYI(1, ("inode exists but unchanged")); 278 } else { 279 /* file may have changed on server */ 280 cFYI(1, ("invalidate inode, readdir detected change")); 281 invalidate_remote_inode(tmp_inode); 282 } 283 } else if (S_ISDIR(tmp_inode->i_mode)) { 284 cFYI(1, ("Directory inode")); 285 tmp_inode->i_op = &cifs_dir_inode_ops; 286 tmp_inode->i_fop = &cifs_dir_ops; 287 } else if (S_ISLNK(tmp_inode->i_mode)) { 288 cFYI(1, ("Symbolic Link inode")); 289 tmp_inode->i_op = &cifs_symlink_inode_ops; 290 } else { 291 cFYI(1, ("Init special inode")); 292 init_special_inode(tmp_inode, tmp_inode->i_mode, 293 tmp_inode->i_rdev); 294 } 295} 296 297static void unix_fill_in_inode(struct inode *tmp_inode, 298 FILE_UNIX_INFO *pfindData, int *pobject_type, int isNewInode) 299{ 300 loff_t local_size; 301 struct timespec local_mtime; 302 303 struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode); 304 struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb); 305 306 __u32 type = le32_to_cpu(pfindData->Type); 307 __u64 num_of_bytes = le64_to_cpu(pfindData->NumOfBytes); 308 __u64 end_of_file = le64_to_cpu(pfindData->EndOfFile); 309 cifsInfo->time = jiffies; 310 atomic_inc(&cifsInfo->inUse); 311 312 /* save mtime and size */ 313 local_mtime = tmp_inode->i_mtime; 314 local_size = tmp_inode->i_size; 315 316 tmp_inode->i_atime = 317 cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime)); 318 tmp_inode->i_mtime = 319 cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastModificationTime)); 320 tmp_inode->i_ctime = 321 cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastStatusChange)); 322 323 tmp_inode->i_mode = le64_to_cpu(pfindData->Permissions); 324 /* since we set the inode type below we need to mask off type 325 to avoid strange results if bits above were corrupt */ 326 tmp_inode->i_mode &= ~S_IFMT; 327 if (type == UNIX_FILE) { 328 *pobject_type = DT_REG; 329 tmp_inode->i_mode |= S_IFREG; 330 } else if (type == UNIX_SYMLINK) { 331 *pobject_type = DT_LNK; 332 tmp_inode->i_mode |= S_IFLNK; 333 } else if (type == UNIX_DIR) { 334 *pobject_type = DT_DIR; 335 tmp_inode->i_mode |= S_IFDIR; 336 } else if (type == UNIX_CHARDEV) { 337 *pobject_type = DT_CHR; 338 tmp_inode->i_mode |= S_IFCHR; 339 tmp_inode->i_rdev = MKDEV(le64_to_cpu(pfindData->DevMajor), 340 le64_to_cpu(pfindData->DevMinor) & MINORMASK); 341 } else if (type == UNIX_BLOCKDEV) { 342 *pobject_type = DT_BLK; 343 tmp_inode->i_mode |= S_IFBLK; 344 tmp_inode->i_rdev = MKDEV(le64_to_cpu(pfindData->DevMajor), 345 le64_to_cpu(pfindData->DevMinor) & MINORMASK); 346 } else if (type == UNIX_FIFO) { 347 *pobject_type = DT_FIFO; 348 tmp_inode->i_mode |= S_IFIFO; 349 } else if (type == UNIX_SOCKET) { 350 *pobject_type = DT_SOCK; 351 tmp_inode->i_mode |= S_IFSOCK; 352 } else { 353 /* safest to just call it a file */ 354 *pobject_type = DT_REG; 355 tmp_inode->i_mode |= S_IFREG; 356 cFYI(1,("unknown inode type %d",type)); 357 } 358 359 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID) 360 tmp_inode->i_uid = cifs_sb->mnt_uid; 361 else 362 tmp_inode->i_uid = le64_to_cpu(pfindData->Uid); 363 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID) 364 tmp_inode->i_gid = cifs_sb->mnt_gid; 365 else 366 tmp_inode->i_gid = le64_to_cpu(pfindData->Gid); 367 tmp_inode->i_nlink = le64_to_cpu(pfindData->Nlinks); 368 369 spin_lock(&tmp_inode->i_lock); 370 if (is_size_safe_to_change(cifsInfo, end_of_file)) { 371 /* can not safely change the file size here if the 372 client is writing to it due to potential races */ 373 i_size_write(tmp_inode, end_of_file); 374 375 /* 512 bytes (2**9) is the fake blocksize that must be used */ 376 /* for this calculation, not the real blocksize */ 377 tmp_inode->i_blocks = (512 - 1 + num_of_bytes) >> 9; 378 } 379 spin_unlock(&tmp_inode->i_lock); 380 381 if (S_ISREG(tmp_inode->i_mode)) { 382 cFYI(1, ("File inode")); 383 tmp_inode->i_op = &cifs_file_inode_ops; 384 385 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) { 386 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) 387 tmp_inode->i_fop = &cifs_file_direct_nobrl_ops; 388 else 389 tmp_inode->i_fop = &cifs_file_direct_ops; 390 } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) 391 tmp_inode->i_fop = &cifs_file_nobrl_ops; 392 else 393 tmp_inode->i_fop = &cifs_file_ops; 394 395 if ((cifs_sb->tcon) && (cifs_sb->tcon->ses) && 396 (cifs_sb->tcon->ses->server->maxBuf < 397 PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE)) 398 tmp_inode->i_data.a_ops = &cifs_addr_ops_smallbuf; 399 else 400 tmp_inode->i_data.a_ops = &cifs_addr_ops; 401 402 if (isNewInode) 403 return; /* No sense invalidating pages for new inode since we 404 have not started caching readahead file data yet */ 405 406 if (timespec_equal(&tmp_inode->i_mtime, &local_mtime) && 407 (local_size == tmp_inode->i_size)) { 408 cFYI(1, ("inode exists but unchanged")); 409 } else { 410 /* file may have changed on server */ 411 cFYI(1, ("invalidate inode, readdir detected change")); 412 invalidate_remote_inode(tmp_inode); 413 } 414 } else if (S_ISDIR(tmp_inode->i_mode)) { 415 cFYI(1, ("Directory inode")); 416 tmp_inode->i_op = &cifs_dir_inode_ops; 417 tmp_inode->i_fop = &cifs_dir_ops; 418 } else if (S_ISLNK(tmp_inode->i_mode)) { 419 cFYI(1, ("Symbolic Link inode")); 420 tmp_inode->i_op = &cifs_symlink_inode_ops; 421/* tmp_inode->i_fop = *//* do not need to set to anything */ 422 } else { 423 cFYI(1, ("Special inode")); 424 init_special_inode(tmp_inode, tmp_inode->i_mode, 425 tmp_inode->i_rdev); 426 } 427} 428 429static int initiate_cifs_search(const int xid, struct file *file) 430{ 431 int rc = 0; 432 char * full_path; 433 struct cifsFileInfo * cifsFile; 434 struct cifs_sb_info *cifs_sb; 435 struct cifsTconInfo *pTcon; 436 437 if (file->private_data == NULL) { 438 file->private_data = 439 kzalloc(sizeof(struct cifsFileInfo),GFP_KERNEL); 440 } 441 442 if (file->private_data == NULL) 443 return -ENOMEM; 444 cifsFile = file->private_data; 445 cifsFile->invalidHandle = TRUE; 446 cifsFile->srch_inf.endOfSearch = FALSE; 447 448 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); 449 if (cifs_sb == NULL) 450 return -EINVAL; 451 452 pTcon = cifs_sb->tcon; 453 if (pTcon == NULL) 454 return -EINVAL; 455 456 full_path = build_path_from_dentry(file->f_path.dentry); 457 458 if (full_path == NULL) { 459 return -ENOMEM; 460 } 461 462 cFYI(1, ("Full path: %s start at: %lld", full_path, file->f_pos)); 463 464ffirst_retry: 465 /* test for Unix extensions */ 466 if (pTcon->ses->capabilities & CAP_UNIX) { 467 cifsFile->srch_inf.info_level = SMB_FIND_FILE_UNIX; 468 } else if ((pTcon->ses->capabilities & 469 (CAP_NT_SMBS | CAP_NT_FIND)) == 0) { 470 cifsFile->srch_inf.info_level = SMB_FIND_FILE_INFO_STANDARD; 471 } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) { 472 cifsFile->srch_inf.info_level = SMB_FIND_FILE_ID_FULL_DIR_INFO; 473 } else { 474 cifsFile->srch_inf.info_level = SMB_FIND_FILE_DIRECTORY_INFO; 475 } 476 477 rc = CIFSFindFirst(xid, pTcon,full_path,cifs_sb->local_nls, 478 &cifsFile->netfid, &cifsFile->srch_inf, 479 cifs_sb->mnt_cifs_flags & 480 CIFS_MOUNT_MAP_SPECIAL_CHR, CIFS_DIR_SEP(cifs_sb)); 481 if (rc == 0) 482 cifsFile->invalidHandle = FALSE; 483 if ((rc == -EOPNOTSUPP) && 484 (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)) { 485 cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_SERVER_INUM; 486 goto ffirst_retry; 487 } 488 kfree(full_path); 489 return rc; 490} 491 492/* return length of unicode string in bytes */ 493static int cifs_unicode_bytelen(char *str) 494{ 495 int len; 496 __le16 * ustr = (__le16 *)str; 497 498 for(len=0;len <= PATH_MAX;len++) { 499 if (ustr[len] == 0) 500 return len << 1; 501 } 502 cFYI(1,("Unicode string longer than PATH_MAX found")); 503 return len << 1; 504} 505 506static char *nxt_dir_entry(char *old_entry, char *end_of_smb, int level) 507{ 508 char * new_entry; 509 FILE_DIRECTORY_INFO * pDirInfo = (FILE_DIRECTORY_INFO *)old_entry; 510 511 if (level == SMB_FIND_FILE_INFO_STANDARD) { 512 FIND_FILE_STANDARD_INFO * pfData; 513 pfData = (FIND_FILE_STANDARD_INFO *)pDirInfo; 514 515 new_entry = old_entry + sizeof(FIND_FILE_STANDARD_INFO) + 516 pfData->FileNameLength; 517 } else 518 new_entry = old_entry + le32_to_cpu(pDirInfo->NextEntryOffset); 519 cFYI(1,("new entry %p old entry %p",new_entry,old_entry)); 520 /* validate that new_entry is not past end of SMB */ 521 if (new_entry >= end_of_smb) { 522 cERROR(1, 523 ("search entry %p began after end of SMB %p old entry %p", 524 new_entry, end_of_smb, old_entry)); 525 return NULL; 526 } else if (((level == SMB_FIND_FILE_INFO_STANDARD) && 527 (new_entry + sizeof(FIND_FILE_STANDARD_INFO) > end_of_smb)) || 528 ((level != SMB_FIND_FILE_INFO_STANDARD) && 529 (new_entry + sizeof(FILE_DIRECTORY_INFO) > end_of_smb))) { 530 cERROR(1,("search entry %p extends after end of SMB %p", 531 new_entry, end_of_smb)); 532 return NULL; 533 } else 534 return new_entry; 535 536} 537 538#define UNICODE_DOT cpu_to_le16(0x2e) 539 540/* return 0 if no match and 1 for . (current directory) and 2 for .. (parent) */ 541static int cifs_entry_is_dot(char *current_entry, struct cifsFileInfo *cfile) 542{ 543 int rc = 0; 544 char * filename = NULL; 545 int len = 0; 546 547 if (cfile->srch_inf.info_level == SMB_FIND_FILE_UNIX) { 548 FILE_UNIX_INFO * pFindData = (FILE_UNIX_INFO *)current_entry; 549 filename = &pFindData->FileName[0]; 550 if (cfile->srch_inf.unicode) { 551 len = cifs_unicode_bytelen(filename); 552 } else { 553 /* BB should we make this strnlen of PATH_MAX? */ 554 len = strnlen(filename, 5); 555 } 556 } else if (cfile->srch_inf.info_level == SMB_FIND_FILE_DIRECTORY_INFO) { 557 FILE_DIRECTORY_INFO * pFindData = 558 (FILE_DIRECTORY_INFO *)current_entry; 559 filename = &pFindData->FileName[0]; 560 len = le32_to_cpu(pFindData->FileNameLength); 561 } else if (cfile->srch_inf.info_level == 562 SMB_FIND_FILE_FULL_DIRECTORY_INFO) { 563 FILE_FULL_DIRECTORY_INFO * pFindData = 564 (FILE_FULL_DIRECTORY_INFO *)current_entry; 565 filename = &pFindData->FileName[0]; 566 len = le32_to_cpu(pFindData->FileNameLength); 567 } else if (cfile->srch_inf.info_level == 568 SMB_FIND_FILE_ID_FULL_DIR_INFO) { 569 SEARCH_ID_FULL_DIR_INFO * pFindData = 570 (SEARCH_ID_FULL_DIR_INFO *)current_entry; 571 filename = &pFindData->FileName[0]; 572 len = le32_to_cpu(pFindData->FileNameLength); 573 } else if (cfile->srch_inf.info_level == 574 SMB_FIND_FILE_BOTH_DIRECTORY_INFO) { 575 FILE_BOTH_DIRECTORY_INFO * pFindData = 576 (FILE_BOTH_DIRECTORY_INFO *)current_entry; 577 filename = &pFindData->FileName[0]; 578 len = le32_to_cpu(pFindData->FileNameLength); 579 } else if (cfile->srch_inf.info_level == SMB_FIND_FILE_INFO_STANDARD) { 580 FIND_FILE_STANDARD_INFO * pFindData = 581 (FIND_FILE_STANDARD_INFO *)current_entry; 582 filename = &pFindData->FileName[0]; 583 len = pFindData->FileNameLength; 584 } else { 585 cFYI(1,("Unknown findfirst level %d",cfile->srch_inf.info_level)); 586 } 587 588 if (filename) { 589 if (cfile->srch_inf.unicode) { 590 __le16 *ufilename = (__le16 *)filename; 591 if (len == 2) { 592 /* check for . */ 593 if (ufilename[0] == UNICODE_DOT) 594 rc = 1; 595 } else if (len == 4) { 596 /* check for .. */ 597 if ((ufilename[0] == UNICODE_DOT) 598 &&(ufilename[1] == UNICODE_DOT)) 599 rc = 2; 600 } 601 } else /* ASCII */ { 602 if (len == 1) { 603 if (filename[0] == '.') 604 rc = 1; 605 } else if (len == 2) { 606 if((filename[0] == '.') && (filename[1] == '.')) 607 rc = 2; 608 } 609 } 610 } 611 612 return rc; 613} 614 615/* Check if directory that we are searching has changed so we can decide 616 whether we can use the cached search results from the previous search */ 617static int is_dir_changed(struct file * file) 618{ 619 struct inode *inode = file->f_path.dentry->d_inode; 620 struct cifsInodeInfo *cifsInfo = CIFS_I(inode); 621 622 if (cifsInfo->time == 0) 623 return 1; /* directory was changed, perhaps due to unlink */ 624 else 625 return 0; 626 627} 628 629/* find the corresponding entry in the search */ 630/* Note that the SMB server returns search entries for . and .. which 631 complicates logic here if we choose to parse for them and we do not 632 assume that they are located in the findfirst return buffer.*/ 633/* We start counting in the buffer with entry 2 and increment for every 634 entry (do not increment for . or .. entry) */ 635static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon, 636 struct file *file, char **ppCurrentEntry, int *num_to_ret) 637{ 638 int rc = 0; 639 int pos_in_buf = 0; 640 loff_t first_entry_in_buffer; 641 loff_t index_to_find = file->f_pos; 642 struct cifsFileInfo * cifsFile = file->private_data; 643 /* check if index in the buffer */ 644 645 if ((cifsFile == NULL) || (ppCurrentEntry == NULL) || 646 (num_to_ret == NULL)) 647 return -ENOENT; 648 649 *ppCurrentEntry = NULL; 650 first_entry_in_buffer = 651 cifsFile->srch_inf.index_of_last_entry - 652 cifsFile->srch_inf.entries_in_buffer; 653 654 /* if first entry in buf is zero then is first buffer 655 in search response data which means it is likely . and .. 656 will be in this buffer, although some servers do not return 657 . and .. for the root of a drive and for those we need 658 to start two entries earlier */ 659 660#ifdef CONFIG_CIFS_DEBUG2 661 dump_cifs_file_struct(file, "In fce "); 662#endif 663 if (((index_to_find < cifsFile->srch_inf.index_of_last_entry) && 664 is_dir_changed(file)) || 665 (index_to_find < first_entry_in_buffer)) { 666 /* close and restart search */ 667 cFYI(1,("search backing up - close and restart search")); 668 cifsFile->invalidHandle = TRUE; 669 CIFSFindClose(xid, pTcon, cifsFile->netfid); 670 kfree(cifsFile->search_resume_name); 671 cifsFile->search_resume_name = NULL; 672 if (cifsFile->srch_inf.ntwrk_buf_start) { 673 cFYI(1,("freeing SMB ff cache buf on search rewind")); 674 if (cifsFile->srch_inf.smallBuf) 675 cifs_small_buf_release(cifsFile->srch_inf. 676 ntwrk_buf_start); 677 else 678 cifs_buf_release(cifsFile->srch_inf. 679 ntwrk_buf_start); 680 } 681 rc = initiate_cifs_search(xid,file); 682 if (rc) { 683 cFYI(1,("error %d reinitiating a search on rewind",rc)); 684 return rc; 685 } 686 } 687 688 while((index_to_find >= cifsFile->srch_inf.index_of_last_entry) && 689 (rc == 0) && (cifsFile->srch_inf.endOfSearch == FALSE)){ 690 cFYI(1,("calling findnext2")); 691 rc = CIFSFindNext(xid,pTcon,cifsFile->netfid, 692 &cifsFile->srch_inf); 693 if (rc) 694 return -ENOENT; 695 } 696 if (index_to_find < cifsFile->srch_inf.index_of_last_entry) { 697 /* we found the buffer that contains the entry */ 698 /* scan and find it */ 699 int i; 700 char * current_entry; 701 char * end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + 702 smbCalcSize((struct smb_hdr *) 703 cifsFile->srch_inf.ntwrk_buf_start); 704 705 current_entry = cifsFile->srch_inf.srch_entries_start; 706 first_entry_in_buffer = cifsFile->srch_inf.index_of_last_entry 707 - cifsFile->srch_inf.entries_in_buffer; 708 pos_in_buf = index_to_find - first_entry_in_buffer; 709 cFYI(1,("found entry - pos_in_buf %d",pos_in_buf)); 710 711 for(i=0;(i<(pos_in_buf)) && (current_entry != NULL);i++) { 712 /* go entry by entry figuring out which is first */ 713 current_entry = nxt_dir_entry(current_entry,end_of_smb, 714 cifsFile->srch_inf.info_level); 715 } 716 if((current_entry == NULL) && (i < pos_in_buf)) { 717 cERROR(1,("reached end of buf searching for pos in buf" 718 " %d index to find %lld rc %d", 719 pos_in_buf,index_to_find,rc)); 720 } 721 rc = 0; 722 *ppCurrentEntry = current_entry; 723 } else { 724 cFYI(1,("index not in buffer - could not findnext into it")); 725 return 0; 726 } 727 728 if(pos_in_buf >= cifsFile->srch_inf.entries_in_buffer) { 729 cFYI(1,("can not return entries pos_in_buf beyond last entry")); 730 *num_to_ret = 0; 731 } else 732 *num_to_ret = cifsFile->srch_inf.entries_in_buffer - pos_in_buf; 733 734 return rc; 735} 736 737/* inode num, inode type and filename returned */ 738static int cifs_get_name_from_search_buf(struct qstr *pqst, 739 char *current_entry, __u16 level, unsigned int unicode, 740 struct cifs_sb_info * cifs_sb, int max_len, ino_t *pinum) 741{ 742 int rc = 0; 743 unsigned int len = 0; 744 char * filename; 745 struct nls_table * nlt = cifs_sb->local_nls; 746 747 *pinum = 0; 748 749 if(level == SMB_FIND_FILE_UNIX) { 750 FILE_UNIX_INFO * pFindData = (FILE_UNIX_INFO *)current_entry; 751 752 filename = &pFindData->FileName[0]; 753 if(unicode) { 754 len = cifs_unicode_bytelen(filename); 755 } else { 756 /* BB should we make this strnlen of PATH_MAX? */ 757 len = strnlen(filename, PATH_MAX); 758 } 759 760 if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) 761 *pinum = pFindData->UniqueId; 762 } else if(level == SMB_FIND_FILE_DIRECTORY_INFO) { 763 FILE_DIRECTORY_INFO * pFindData = 764 (FILE_DIRECTORY_INFO *)current_entry; 765 filename = &pFindData->FileName[0]; 766 len = le32_to_cpu(pFindData->FileNameLength); 767 } else if(level == SMB_FIND_FILE_FULL_DIRECTORY_INFO) { 768 FILE_FULL_DIRECTORY_INFO * pFindData = 769 (FILE_FULL_DIRECTORY_INFO *)current_entry; 770 filename = &pFindData->FileName[0]; 771 len = le32_to_cpu(pFindData->FileNameLength); 772 } else if(level == SMB_FIND_FILE_ID_FULL_DIR_INFO) { 773 SEARCH_ID_FULL_DIR_INFO * pFindData = 774 (SEARCH_ID_FULL_DIR_INFO *)current_entry; 775 filename = &pFindData->FileName[0]; 776 len = le32_to_cpu(pFindData->FileNameLength); 777 *pinum = pFindData->UniqueId; 778 } else if(level == SMB_FIND_FILE_BOTH_DIRECTORY_INFO) { 779 FILE_BOTH_DIRECTORY_INFO * pFindData = 780 (FILE_BOTH_DIRECTORY_INFO *)current_entry; 781 filename = &pFindData->FileName[0]; 782 len = le32_to_cpu(pFindData->FileNameLength); 783 } else if(level == SMB_FIND_FILE_INFO_STANDARD) { 784 FIND_FILE_STANDARD_INFO * pFindData = 785 (FIND_FILE_STANDARD_INFO *)current_entry; 786 filename = &pFindData->FileName[0]; 787 /* one byte length, no name conversion */ 788 len = (unsigned int)pFindData->FileNameLength; 789 } else { 790 cFYI(1,("Unknown findfirst level %d",level)); 791 return -EINVAL; 792 } 793 794 if(len > max_len) { 795 cERROR(1,("bad search response length %d past smb end", len)); 796 return -EINVAL; 797 } 798 799 if(unicode) { 800 /* Note converted filename can be longer than in unicode */ 801 if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR) 802 pqst->len = cifs_convertUCSpath((char *)pqst->name, 803 (__le16 *)filename, len/2, nlt); 804 else 805 pqst->len = cifs_strfromUCS_le((char *)pqst->name, 806 (__le16 *)filename,len/2,nlt); 807 } else { 808 pqst->name = filename; 809 pqst->len = len; 810 } 811 pqst->hash = full_name_hash(pqst->name,pqst->len); 812/* cFYI(1,("filldir on %s",pqst->name)); */ 813 return rc; 814} 815 816static int cifs_filldir(char *pfindEntry, struct file *file, 817 filldir_t filldir, void *direntry, char *scratch_buf, int max_len) 818{ 819 int rc = 0; 820 struct qstr qstring; 821 struct cifsFileInfo * pCifsF; 822 unsigned obj_type; 823 ino_t inum; 824 struct cifs_sb_info * cifs_sb; 825 struct inode *tmp_inode; 826 struct dentry *tmp_dentry; 827 828 /* get filename and len into qstring */ 829 /* get dentry */ 830 /* decide whether to create and populate ionde */ 831 if((direntry == NULL) || (file == NULL)) 832 return -EINVAL; 833 834 pCifsF = file->private_data; 835 836 if((scratch_buf == NULL) || (pfindEntry == NULL) || (pCifsF == NULL)) 837 return -ENOENT; 838 839 rc = cifs_entry_is_dot(pfindEntry,pCifsF); 840 /* skip . and .. since we added them first */ 841 if(rc != 0) 842 return 0; 843 844 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); 845 846 qstring.name = scratch_buf; 847 rc = cifs_get_name_from_search_buf(&qstring,pfindEntry, 848 pCifsF->srch_inf.info_level, 849 pCifsF->srch_inf.unicode,cifs_sb, 850 max_len, 851 &inum /* returned */); 852 853 if(rc) 854 return rc; 855 856 rc = construct_dentry(&qstring,file,&tmp_inode, &tmp_dentry); 857 if((tmp_inode == NULL) || (tmp_dentry == NULL)) 858 return -ENOMEM; 859 860 if(rc) { 861 /* inode created, we need to hash it with right inode number */ 862 if(inum != 0) { 863 tmp_inode->i_ino = inum; 864 } 865 insert_inode_hash(tmp_inode); 866 } 867 868 /* we pass in rc below, indicating whether it is a new inode, 869 so we can figure out whether to invalidate the inode cached 870 data if the file has changed */ 871 if(pCifsF->srch_inf.info_level == SMB_FIND_FILE_UNIX) 872 unix_fill_in_inode(tmp_inode, 873 (FILE_UNIX_INFO *)pfindEntry, 874 &obj_type, rc); 875 else if(pCifsF->srch_inf.info_level == SMB_FIND_FILE_INFO_STANDARD) 876 fill_in_inode(tmp_inode, 0 /* old level 1 buffer type */, 877 pfindEntry, &obj_type, rc); 878 else 879 fill_in_inode(tmp_inode, 1 /* NT */, pfindEntry, &obj_type, rc); 880 881 if(rc) /* new inode - needs to be tied to dentry */ { 882 d_instantiate(tmp_dentry, tmp_inode); 883 if(rc == 2) 884 d_rehash(tmp_dentry); 885 } 886 887 888 rc = filldir(direntry,qstring.name,qstring.len,file->f_pos, 889 tmp_inode->i_ino,obj_type); 890 if(rc) { 891 cFYI(1,("filldir rc = %d",rc)); 892 /* we can not return filldir errors to the caller 893 since they are "normal" when the stat blocksize 894 is too small - we return remapped error instead */ 895 rc = -EOVERFLOW; 896 } 897 898 dput(tmp_dentry); 899 return rc; 900} 901 902static int cifs_save_resume_key(const char *current_entry, 903 struct cifsFileInfo *cifsFile) 904{ 905 int rc = 0; 906 unsigned int len = 0; 907 __u16 level; 908 char * filename; 909 910 if((cifsFile == NULL) || (current_entry == NULL)) 911 return -EINVAL; 912 913 level = cifsFile->srch_inf.info_level; 914 915 if(level == SMB_FIND_FILE_UNIX) { 916 FILE_UNIX_INFO * pFindData = (FILE_UNIX_INFO *)current_entry; 917 918 filename = &pFindData->FileName[0]; 919 if(cifsFile->srch_inf.unicode) { 920 len = cifs_unicode_bytelen(filename); 921 } else { 922 /* BB should we make this strnlen of PATH_MAX? */ 923 len = strnlen(filename, PATH_MAX); 924 } 925 cifsFile->srch_inf.resume_key = pFindData->ResumeKey; 926 } else if(level == SMB_FIND_FILE_DIRECTORY_INFO) { 927 FILE_DIRECTORY_INFO * pFindData = 928 (FILE_DIRECTORY_INFO *)current_entry; 929 filename = &pFindData->FileName[0]; 930 len = le32_to_cpu(pFindData->FileNameLength); 931 cifsFile->srch_inf.resume_key = pFindData->FileIndex; 932 } else if(level == SMB_FIND_FILE_FULL_DIRECTORY_INFO) { 933 FILE_FULL_DIRECTORY_INFO * pFindData = 934 (FILE_FULL_DIRECTORY_INFO *)current_entry; 935 filename = &pFindData->FileName[0]; 936 len = le32_to_cpu(pFindData->FileNameLength); 937 cifsFile->srch_inf.resume_key = pFindData->FileIndex; 938 } else if(level == SMB_FIND_FILE_ID_FULL_DIR_INFO) { 939 SEARCH_ID_FULL_DIR_INFO * pFindData = 940 (SEARCH_ID_FULL_DIR_INFO *)current_entry; 941 filename = &pFindData->FileName[0]; 942 len = le32_to_cpu(pFindData->FileNameLength); 943 cifsFile->srch_inf.resume_key = pFindData->FileIndex; 944 } else if(level == SMB_FIND_FILE_BOTH_DIRECTORY_INFO) { 945 FILE_BOTH_DIRECTORY_INFO * pFindData = 946 (FILE_BOTH_DIRECTORY_INFO *)current_entry; 947 filename = &pFindData->FileName[0]; 948 len = le32_to_cpu(pFindData->FileNameLength); 949 cifsFile->srch_inf.resume_key = pFindData->FileIndex; 950 } else if(level == SMB_FIND_FILE_INFO_STANDARD) { 951 FIND_FILE_STANDARD_INFO * pFindData = 952 (FIND_FILE_STANDARD_INFO *)current_entry; 953 filename = &pFindData->FileName[0]; 954 /* one byte length, no name conversion */ 955 len = (unsigned int)pFindData->FileNameLength; 956 cifsFile->srch_inf.resume_key = pFindData->ResumeKey; 957 } else { 958 cFYI(1,("Unknown findfirst level %d",level)); 959 return -EINVAL; 960 } 961 cifsFile->srch_inf.resume_name_len = len; 962 cifsFile->srch_inf.presume_name = filename; 963 return rc; 964} 965 966int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) 967{ 968 int rc = 0; 969 int xid,i; 970 struct cifs_sb_info *cifs_sb; 971 struct cifsTconInfo *pTcon; 972 struct cifsFileInfo *cifsFile = NULL; 973 char * current_entry; 974 int num_to_fill = 0; 975 char * tmp_buf = NULL; 976 char * end_of_smb; 977 int max_len; 978 979 xid = GetXid(); 980 981 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); 982 pTcon = cifs_sb->tcon; 983 if(pTcon == NULL) 984 return -EINVAL; 985 986 switch ((int) file->f_pos) { 987 case 0: 988 if (filldir(direntry, ".", 1, file->f_pos, 989 file->f_path.dentry->d_inode->i_ino, DT_DIR) < 0) { 990 cERROR(1, ("Filldir for current dir failed")); 991 rc = -ENOMEM; 992 break; 993 } 994 file->f_pos++; 995 case 1: 996 if (filldir(direntry, "..", 2, file->f_pos, 997 file->f_path.dentry->d_parent->d_inode->i_ino, DT_DIR) < 0) { 998 cERROR(1, ("Filldir for parent dir failed")); 999 rc = -ENOMEM; 1000 break; 1001 } 1002 file->f_pos++; 1003 default: 1004 /* 1) If search is active, 1005 is in current search buffer? 1006 if it before then restart search 1007 if after then keep searching till find it */ 1008 1009 if(file->private_data == NULL) { 1010 rc = initiate_cifs_search(xid,file); 1011 cFYI(1,("initiate cifs search rc %d",rc)); 1012 if(rc) { 1013 FreeXid(xid); 1014 return rc; 1015 } 1016 } 1017 if(file->private_data == NULL) { 1018 rc = -EINVAL; 1019 FreeXid(xid); 1020 return rc; 1021 } 1022 cifsFile = file->private_data; 1023 if (cifsFile->srch_inf.endOfSearch) { 1024 if(cifsFile->srch_inf.emptyDir) { 1025 cFYI(1, ("End of search, empty dir")); 1026 rc = 0; 1027 break; 1028 } 1029 } /* else { 1030 cifsFile->invalidHandle = TRUE; 1031 CIFSFindClose(xid, pTcon, cifsFile->netfid); 1032 } 1033 kfree(cifsFile->search_resume_name); 1034 cifsFile->search_resume_name = NULL; */ 1035 1036 rc = find_cifs_entry(xid,pTcon, file, 1037 ¤t_entry,&num_to_fill); 1038 if(rc) { 1039 cFYI(1,("fce error %d",rc)); 1040 goto rddir2_exit; 1041 } else if (current_entry != NULL) { 1042 cFYI(1,("entry %lld found",file->f_pos)); 1043 } else { 1044 cFYI(1,("could not find entry")); 1045 goto rddir2_exit; 1046 } 1047 cFYI(1,("loop through %d times filling dir for net buf %p", 1048 num_to_fill,cifsFile->srch_inf.ntwrk_buf_start)); 1049 max_len = smbCalcSize((struct smb_hdr *) 1050 cifsFile->srch_inf.ntwrk_buf_start); 1051 end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + max_len; 1052 1053 /* To be safe - for UCS to UTF-8 with strings loaded 1054 with the rare long characters alloc more to account for 1055 such multibyte target UTF-8 characters. cifs_unicode.c, 1056 which actually does the conversion, has the same limit */ 1057 tmp_buf = kmalloc((2 * NAME_MAX) + 4, GFP_KERNEL); 1058 for(i=0;(i<num_to_fill) && (rc == 0);i++) { 1059 if(current_entry == NULL) { 1060 /* evaluate whether this case is an error */ 1061 cERROR(1,("past end of SMB num to fill %d i %d", 1062 num_to_fill, i)); 1063 break; 1064 } 1065 /* if buggy server returns . and .. late do 1066 we want to check for that here? */ 1067 rc = cifs_filldir(current_entry, file, 1068 filldir, direntry, tmp_buf, max_len); 1069 if(rc == -EOVERFLOW) { 1070 rc = 0; 1071 break; 1072 } 1073 1074 file->f_pos++; 1075 if(file->f_pos == 1076 cifsFile->srch_inf.index_of_last_entry) { 1077 cFYI(1,("last entry in buf at pos %lld %s", 1078 file->f_pos,tmp_buf)); 1079 cifs_save_resume_key(current_entry,cifsFile); 1080 break; 1081 } else 1082 current_entry = 1083 nxt_dir_entry(current_entry, end_of_smb, 1084 cifsFile->srch_inf.info_level); 1085 } 1086 kfree(tmp_buf); 1087 break; 1088 } /* end switch */ 1089 1090rddir2_exit: 1091 FreeXid(xid); 1092 return rc; 1093} 1094