1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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#include "smb2proto.h"
36
37
38
39
40
41
42#define UNICODE_NAME_MAX ((4 * NAME_MAX) + 2)
43
44#ifdef CONFIG_CIFS_DEBUG2
45static void dump_cifs_file_struct(struct file *file, char *label)
46{
47 struct cifsFileInfo *cf;
48
49 if (file) {
50 cf = file->private_data;
51 if (cf == NULL) {
52 cifs_dbg(FYI, "empty cifs private file data\n");
53 return;
54 }
55 if (cf->invalidHandle)
56 cifs_dbg(FYI, "invalid handle\n");
57 if (cf->srch_inf.endOfSearch)
58 cifs_dbg(FYI, "end of search\n");
59 if (cf->srch_inf.emptyDir)
60 cifs_dbg(FYI, "empty dir\n");
61 }
62}
63#else
64static inline void dump_cifs_file_struct(struct file *file, char *label)
65{
66}
67#endif
68
69
70
71
72
73
74
75
76static void
77cifs_prime_dcache(struct dentry *parent, struct qstr *name,
78 struct cifs_fattr *fattr)
79{
80 struct dentry *dentry, *alias;
81 struct inode *inode;
82 struct super_block *sb = parent->d_sb;
83 struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
84 DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq);
85
86 cifs_dbg(FYI, "%s: for %s\n", __func__, name->name);
87
88 dentry = d_hash_and_lookup(parent, name);
89 if (!dentry) {
90
91
92
93
94
95
96 if (fattr->cf_flags & CIFS_FATTR_NEED_REVAL)
97 return;
98retry:
99 dentry = d_alloc_parallel(parent, name, &wq);
100 }
101 if (IS_ERR(dentry))
102 return;
103 if (!d_in_lookup(dentry)) {
104 inode = d_inode(dentry);
105 if (inode) {
106 if (d_mountpoint(dentry)) {
107 dput(dentry);
108 return;
109 }
110
111
112
113
114
115 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM))
116 fattr->cf_uniqueid = CIFS_I(inode)->uniqueid;
117
118
119
120 if (CIFS_I(inode)->uniqueid == fattr->cf_uniqueid &&
121 (inode->i_mode & S_IFMT) ==
122 (fattr->cf_mode & S_IFMT)) {
123 cifs_fattr_to_inode(inode, fattr);
124 dput(dentry);
125 return;
126 }
127 }
128 d_invalidate(dentry);
129 dput(dentry);
130 goto retry;
131 } else {
132 inode = cifs_iget(sb, fattr);
133 if (!inode)
134 inode = ERR_PTR(-ENOMEM);
135 alias = d_splice_alias(inode, dentry);
136 d_lookup_done(dentry);
137 if (alias && !IS_ERR(alias))
138 dput(alias);
139 }
140 dput(dentry);
141}
142
143static bool reparse_file_needs_reval(const struct cifs_fattr *fattr)
144{
145 if (!(fattr->cf_cifsattrs & ATTR_REPARSE))
146 return false;
147
148
149
150
151
152
153
154 switch (fattr->cf_cifstag) {
155 case IO_REPARSE_TAG_DFS:
156 case IO_REPARSE_TAG_DFSR:
157 case IO_REPARSE_TAG_SYMLINK:
158 case IO_REPARSE_TAG_NFS:
159 case 0:
160 return true;
161 }
162 return false;
163}
164
165static void
166cifs_fill_common_info(struct cifs_fattr *fattr, struct cifs_sb_info *cifs_sb)
167{
168 fattr->cf_uid = cifs_sb->mnt_uid;
169 fattr->cf_gid = cifs_sb->mnt_gid;
170
171 if (fattr->cf_cifsattrs & ATTR_DIRECTORY) {
172 fattr->cf_mode = S_IFDIR | cifs_sb->mnt_dir_mode;
173 fattr->cf_dtype = DT_DIR;
174 } else {
175 fattr->cf_mode = S_IFREG | cifs_sb->mnt_file_mode;
176 fattr->cf_dtype = DT_REG;
177 }
178
179
180
181
182
183
184 if (reparse_file_needs_reval(fattr))
185 fattr->cf_flags |= CIFS_FATTR_NEED_REVAL;
186
187
188 fattr->cf_flags |= CIFS_FATTR_UNKNOWN_NLINK;
189
190 if (fattr->cf_cifsattrs & ATTR_READONLY)
191 fattr->cf_mode &= ~S_IWUGO;
192
193
194
195
196
197
198
199
200 if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) ||
201 (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MODE_FROM_SID))
202 fattr->cf_flags |= CIFS_FATTR_NEED_REVAL;
203
204 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL &&
205 fattr->cf_cifsattrs & ATTR_SYSTEM) {
206 if (fattr->cf_eof == 0) {
207 fattr->cf_mode &= ~S_IFMT;
208 fattr->cf_mode |= S_IFIFO;
209 fattr->cf_dtype = DT_FIFO;
210 } else {
211
212
213
214
215
216 fattr->cf_flags |= CIFS_FATTR_NEED_REVAL;
217 }
218 }
219}
220
221
222static void
223cifs_posix_to_fattr(struct cifs_fattr *fattr, struct smb2_posix_info *info,
224 struct cifs_sb_info *cifs_sb)
225{
226 struct smb2_posix_info_parsed parsed;
227
228 posix_info_parse(info, NULL, &parsed);
229
230 memset(fattr, 0, sizeof(*fattr));
231 fattr->cf_uniqueid = le64_to_cpu(info->Inode);
232 fattr->cf_bytes = le64_to_cpu(info->AllocationSize);
233 fattr->cf_eof = le64_to_cpu(info->EndOfFile);
234
235 fattr->cf_atime = cifs_NTtimeToUnix(info->LastAccessTime);
236 fattr->cf_mtime = cifs_NTtimeToUnix(info->LastWriteTime);
237 fattr->cf_ctime = cifs_NTtimeToUnix(info->CreationTime);
238
239 fattr->cf_nlink = le32_to_cpu(info->HardLinks);
240 fattr->cf_cifsattrs = le32_to_cpu(info->DosAttributes);
241
242
243
244
245
246
247 fattr->cf_mode = le32_to_cpu(info->Mode) & ~S_IFMT;
248
249 cifs_dbg(FYI, "posix fattr: dev %d, reparse %d, mode %o",
250 le32_to_cpu(info->DeviceId),
251 le32_to_cpu(info->ReparseTag),
252 le32_to_cpu(info->Mode));
253
254 if (fattr->cf_cifsattrs & ATTR_DIRECTORY) {
255 fattr->cf_mode |= S_IFDIR;
256 fattr->cf_dtype = DT_DIR;
257 } else {
258
259
260
261
262
263 fattr->cf_mode |= S_IFREG;
264 fattr->cf_dtype = DT_REG;
265 }
266
267 if (reparse_file_needs_reval(fattr))
268 fattr->cf_flags |= CIFS_FATTR_NEED_REVAL;
269
270
271 fattr->cf_uid = cifs_sb->mnt_uid;
272 fattr->cf_gid = cifs_sb->mnt_gid;
273}
274
275static void __dir_info_to_fattr(struct cifs_fattr *fattr, const void *info)
276{
277 const FILE_DIRECTORY_INFO *fi = info;
278
279 memset(fattr, 0, sizeof(*fattr));
280 fattr->cf_cifsattrs = le32_to_cpu(fi->ExtFileAttributes);
281 fattr->cf_eof = le64_to_cpu(fi->EndOfFile);
282 fattr->cf_bytes = le64_to_cpu(fi->AllocationSize);
283 fattr->cf_createtime = le64_to_cpu(fi->CreationTime);
284 fattr->cf_atime = cifs_NTtimeToUnix(fi->LastAccessTime);
285 fattr->cf_ctime = cifs_NTtimeToUnix(fi->ChangeTime);
286 fattr->cf_mtime = cifs_NTtimeToUnix(fi->LastWriteTime);
287}
288
289void
290cifs_dir_info_to_fattr(struct cifs_fattr *fattr, FILE_DIRECTORY_INFO *info,
291 struct cifs_sb_info *cifs_sb)
292{
293 __dir_info_to_fattr(fattr, info);
294 cifs_fill_common_info(fattr, cifs_sb);
295}
296
297static void cifs_fulldir_info_to_fattr(struct cifs_fattr *fattr,
298 SEARCH_ID_FULL_DIR_INFO *info,
299 struct cifs_sb_info *cifs_sb)
300{
301 __dir_info_to_fattr(fattr, info);
302
303
304 if (fattr->cf_cifsattrs & ATTR_REPARSE)
305 fattr->cf_cifstag = le32_to_cpu(info->EaSize);
306 cifs_fill_common_info(fattr, cifs_sb);
307}
308
309static void
310cifs_std_info_to_fattr(struct cifs_fattr *fattr, FIND_FILE_STANDARD_INFO *info,
311 struct cifs_sb_info *cifs_sb)
312{
313 int offset = cifs_sb_master_tcon(cifs_sb)->ses->server->timeAdj;
314
315 memset(fattr, 0, sizeof(*fattr));
316 fattr->cf_atime = cnvrtDosUnixTm(info->LastAccessDate,
317 info->LastAccessTime, offset);
318 fattr->cf_ctime = cnvrtDosUnixTm(info->LastWriteDate,
319 info->LastWriteTime, offset);
320 fattr->cf_mtime = cnvrtDosUnixTm(info->LastWriteDate,
321 info->LastWriteTime, offset);
322
323 fattr->cf_cifsattrs = le16_to_cpu(info->Attributes);
324 fattr->cf_bytes = le32_to_cpu(info->AllocationSize);
325 fattr->cf_eof = le32_to_cpu(info->DataSize);
326
327 cifs_fill_common_info(fattr, cifs_sb);
328}
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362static int
363initiate_cifs_search(const unsigned int xid, struct file *file)
364{
365 __u16 search_flags;
366 int rc = 0;
367 char *full_path = NULL;
368 struct cifsFileInfo *cifsFile;
369 struct cifs_sb_info *cifs_sb = CIFS_FILE_SB(file);
370 struct tcon_link *tlink = NULL;
371 struct cifs_tcon *tcon;
372 struct TCP_Server_Info *server;
373
374 if (file->private_data == NULL) {
375 tlink = cifs_sb_tlink(cifs_sb);
376 if (IS_ERR(tlink))
377 return PTR_ERR(tlink);
378
379 cifsFile = kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
380 if (cifsFile == NULL) {
381 rc = -ENOMEM;
382 goto error_exit;
383 }
384 spin_lock_init(&cifsFile->file_info_lock);
385 file->private_data = cifsFile;
386 cifsFile->tlink = cifs_get_tlink(tlink);
387 tcon = tlink_tcon(tlink);
388 } else {
389 cifsFile = file->private_data;
390 tcon = tlink_tcon(cifsFile->tlink);
391 }
392
393 server = tcon->ses->server;
394
395 if (!server->ops->query_dir_first) {
396 rc = -ENOSYS;
397 goto error_exit;
398 }
399
400 cifsFile->invalidHandle = true;
401 cifsFile->srch_inf.endOfSearch = false;
402
403 full_path = build_path_from_dentry(file_dentry(file));
404 if (full_path == NULL) {
405 rc = -ENOMEM;
406 goto error_exit;
407 }
408
409 cifs_dbg(FYI, "Full path: %s start at: %lld\n", full_path, file->f_pos);
410
411ffirst_retry:
412
413
414
415 if (tcon->unix_ext)
416 cifsFile->srch_inf.info_level = SMB_FIND_FILE_UNIX;
417 else if (tcon->posix_extensions)
418 cifsFile->srch_inf.info_level = SMB_FIND_FILE_POSIX_INFO;
419 else if ((tcon->ses->capabilities &
420 tcon->ses->server->vals->cap_nt_find) == 0) {
421 cifsFile->srch_inf.info_level = SMB_FIND_FILE_INFO_STANDARD;
422 } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
423 cifsFile->srch_inf.info_level = SMB_FIND_FILE_ID_FULL_DIR_INFO;
424 } else {
425 cifsFile->srch_inf.info_level = SMB_FIND_FILE_DIRECTORY_INFO;
426 }
427
428 search_flags = CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME;
429 if (backup_cred(cifs_sb))
430 search_flags |= CIFS_SEARCH_BACKUP_SEARCH;
431
432 rc = server->ops->query_dir_first(xid, tcon, full_path, cifs_sb,
433 &cifsFile->fid, search_flags,
434 &cifsFile->srch_inf);
435
436 if (rc == 0)
437 cifsFile->invalidHandle = false;
438
439
440
441 else if ((rc == -EOPNOTSUPP) &&
442 (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)) {
443 cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_SERVER_INUM;
444 goto ffirst_retry;
445 }
446error_exit:
447 kfree(full_path);
448 cifs_put_tlink(tlink);
449 return rc;
450}
451
452
453static int cifs_unicode_bytelen(const char *str)
454{
455 int len;
456 const __le16 *ustr = (const __le16 *)str;
457
458 for (len = 0; len <= PATH_MAX; len++) {
459 if (ustr[len] == 0)
460 return len << 1;
461 }
462 cifs_dbg(FYI, "Unicode string longer than PATH_MAX found\n");
463 return len << 1;
464}
465
466static char *nxt_dir_entry(char *old_entry, char *end_of_smb, int level)
467{
468 char *new_entry;
469 FILE_DIRECTORY_INFO *pDirInfo = (FILE_DIRECTORY_INFO *)old_entry;
470
471 if (level == SMB_FIND_FILE_INFO_STANDARD) {
472 FIND_FILE_STANDARD_INFO *pfData;
473 pfData = (FIND_FILE_STANDARD_INFO *)pDirInfo;
474
475 new_entry = old_entry + sizeof(FIND_FILE_STANDARD_INFO) +
476 pfData->FileNameLength;
477 } else {
478 u32 next_offset = le32_to_cpu(pDirInfo->NextEntryOffset);
479
480 if (old_entry + next_offset < old_entry) {
481 cifs_dbg(VFS, "invalid offset %u\n", next_offset);
482 return NULL;
483 }
484 new_entry = old_entry + next_offset;
485 }
486 cifs_dbg(FYI, "new entry %p old entry %p\n", new_entry, old_entry);
487
488 if (new_entry >= end_of_smb) {
489 cifs_dbg(VFS, "search entry %p began after end of SMB %p old entry %p\n",
490 new_entry, end_of_smb, old_entry);
491 return NULL;
492 } else if (((level == SMB_FIND_FILE_INFO_STANDARD) &&
493 (new_entry + sizeof(FIND_FILE_STANDARD_INFO) > end_of_smb))
494 || ((level != SMB_FIND_FILE_INFO_STANDARD) &&
495 (new_entry + sizeof(FILE_DIRECTORY_INFO) > end_of_smb))) {
496 cifs_dbg(VFS, "search entry %p extends after end of SMB %p\n",
497 new_entry, end_of_smb);
498 return NULL;
499 } else
500 return new_entry;
501
502}
503
504struct cifs_dirent {
505 const char *name;
506 size_t namelen;
507 u32 resume_key;
508 u64 ino;
509};
510
511static void cifs_fill_dirent_posix(struct cifs_dirent *de,
512 const struct smb2_posix_info *info)
513{
514 struct smb2_posix_info_parsed parsed;
515
516
517 if (posix_info_parse(info, NULL, &parsed) < 0) {
518 cifs_dbg(VFS, "invalid POSIX info payload");
519 return;
520 }
521
522 de->name = parsed.name;
523 de->namelen = parsed.name_len;
524 de->resume_key = info->Ignored;
525 de->ino = le64_to_cpu(info->Inode);
526}
527
528static void cifs_fill_dirent_unix(struct cifs_dirent *de,
529 const FILE_UNIX_INFO *info, bool is_unicode)
530{
531 de->name = &info->FileName[0];
532 if (is_unicode)
533 de->namelen = cifs_unicode_bytelen(de->name);
534 else
535 de->namelen = strnlen(de->name, PATH_MAX);
536 de->resume_key = info->ResumeKey;
537 de->ino = le64_to_cpu(info->basic.UniqueId);
538}
539
540static void cifs_fill_dirent_dir(struct cifs_dirent *de,
541 const FILE_DIRECTORY_INFO *info)
542{
543 de->name = &info->FileName[0];
544 de->namelen = le32_to_cpu(info->FileNameLength);
545 de->resume_key = info->FileIndex;
546}
547
548static void cifs_fill_dirent_full(struct cifs_dirent *de,
549 const FILE_FULL_DIRECTORY_INFO *info)
550{
551 de->name = &info->FileName[0];
552 de->namelen = le32_to_cpu(info->FileNameLength);
553 de->resume_key = info->FileIndex;
554}
555
556static void cifs_fill_dirent_search(struct cifs_dirent *de,
557 const SEARCH_ID_FULL_DIR_INFO *info)
558{
559 de->name = &info->FileName[0];
560 de->namelen = le32_to_cpu(info->FileNameLength);
561 de->resume_key = info->FileIndex;
562 de->ino = le64_to_cpu(info->UniqueId);
563}
564
565static void cifs_fill_dirent_both(struct cifs_dirent *de,
566 const FILE_BOTH_DIRECTORY_INFO *info)
567{
568 de->name = &info->FileName[0];
569 de->namelen = le32_to_cpu(info->FileNameLength);
570 de->resume_key = info->FileIndex;
571}
572
573static void cifs_fill_dirent_std(struct cifs_dirent *de,
574 const FIND_FILE_STANDARD_INFO *info)
575{
576 de->name = &info->FileName[0];
577
578 de->namelen = info->FileNameLength;
579 de->resume_key = info->ResumeKey;
580}
581
582static int cifs_fill_dirent(struct cifs_dirent *de, const void *info,
583 u16 level, bool is_unicode)
584{
585 memset(de, 0, sizeof(*de));
586
587 switch (level) {
588 case SMB_FIND_FILE_POSIX_INFO:
589 cifs_fill_dirent_posix(de, info);
590 break;
591 case SMB_FIND_FILE_UNIX:
592 cifs_fill_dirent_unix(de, info, is_unicode);
593 break;
594 case SMB_FIND_FILE_DIRECTORY_INFO:
595 cifs_fill_dirent_dir(de, info);
596 break;
597 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
598 cifs_fill_dirent_full(de, info);
599 break;
600 case SMB_FIND_FILE_ID_FULL_DIR_INFO:
601 cifs_fill_dirent_search(de, info);
602 break;
603 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
604 cifs_fill_dirent_both(de, info);
605 break;
606 case SMB_FIND_FILE_INFO_STANDARD:
607 cifs_fill_dirent_std(de, info);
608 break;
609 default:
610 cifs_dbg(FYI, "Unknown findfirst level %d\n", level);
611 return -EINVAL;
612 }
613
614 return 0;
615}
616
617#define UNICODE_DOT cpu_to_le16(0x2e)
618
619
620static int cifs_entry_is_dot(struct cifs_dirent *de, bool is_unicode)
621{
622 int rc = 0;
623
624 if (!de->name)
625 return 0;
626
627 if (is_unicode) {
628 __le16 *ufilename = (__le16 *)de->name;
629 if (de->namelen == 2) {
630
631 if (ufilename[0] == UNICODE_DOT)
632 rc = 1;
633 } else if (de->namelen == 4) {
634
635 if (ufilename[0] == UNICODE_DOT &&
636 ufilename[1] == UNICODE_DOT)
637 rc = 2;
638 }
639 } else {
640 if (de->namelen == 1) {
641 if (de->name[0] == '.')
642 rc = 1;
643 } else if (de->namelen == 2) {
644 if (de->name[0] == '.' && de->name[1] == '.')
645 rc = 2;
646 }
647 }
648
649 return rc;
650}
651
652
653
654static int is_dir_changed(struct file *file)
655{
656 struct inode *inode = file_inode(file);
657 struct cifsInodeInfo *cifsInfo = CIFS_I(inode);
658
659 if (cifsInfo->time == 0)
660 return 1;
661 else
662 return 0;
663
664}
665
666static int cifs_save_resume_key(const char *current_entry,
667 struct cifsFileInfo *file_info)
668{
669 struct cifs_dirent de;
670 int rc;
671
672 rc = cifs_fill_dirent(&de, current_entry, file_info->srch_inf.info_level,
673 file_info->srch_inf.unicode);
674 if (!rc) {
675 file_info->srch_inf.presume_name = de.name;
676 file_info->srch_inf.resume_name_len = de.namelen;
677 file_info->srch_inf.resume_key = de.resume_key;
678 }
679 return rc;
680}
681
682
683
684
685
686
687
688
689static int
690find_cifs_entry(const unsigned int xid, struct cifs_tcon *tcon, loff_t pos,
691 struct file *file, char **current_entry, int *num_to_ret)
692{
693 __u16 search_flags;
694 int rc = 0;
695 int pos_in_buf = 0;
696 loff_t first_entry_in_buffer;
697 loff_t index_to_find = pos;
698 struct cifsFileInfo *cfile = file->private_data;
699 struct cifs_sb_info *cifs_sb = CIFS_FILE_SB(file);
700 struct TCP_Server_Info *server = tcon->ses->server;
701
702
703 if (!server->ops->query_dir_first || !server->ops->query_dir_next)
704 return -ENOSYS;
705
706 if ((cfile == NULL) || (current_entry == NULL) || (num_to_ret == NULL))
707 return -ENOENT;
708
709 *current_entry = NULL;
710 first_entry_in_buffer = cfile->srch_inf.index_of_last_entry -
711 cfile->srch_inf.entries_in_buffer;
712
713
714
715
716
717
718
719
720
721 dump_cifs_file_struct(file, "In fce ");
722 if (((index_to_find < cfile->srch_inf.index_of_last_entry) &&
723 is_dir_changed(file)) || (index_to_find < first_entry_in_buffer)) {
724
725 cifs_dbg(FYI, "search backing up - close and restart search\n");
726 spin_lock(&cfile->file_info_lock);
727 if (server->ops->dir_needs_close(cfile)) {
728 cfile->invalidHandle = true;
729 spin_unlock(&cfile->file_info_lock);
730 if (server->ops->close_dir)
731 server->ops->close_dir(xid, tcon, &cfile->fid);
732 } else
733 spin_unlock(&cfile->file_info_lock);
734 if (cfile->srch_inf.ntwrk_buf_start) {
735 cifs_dbg(FYI, "freeing SMB ff cache buf on search rewind\n");
736 if (cfile->srch_inf.smallBuf)
737 cifs_small_buf_release(cfile->srch_inf.
738 ntwrk_buf_start);
739 else
740 cifs_buf_release(cfile->srch_inf.
741 ntwrk_buf_start);
742 cfile->srch_inf.ntwrk_buf_start = NULL;
743 }
744 rc = initiate_cifs_search(xid, file);
745 if (rc) {
746 cifs_dbg(FYI, "error %d reinitiating a search on rewind\n",
747 rc);
748 return rc;
749 }
750
751 if (cfile->srch_inf.last_entry)
752 cifs_save_resume_key(cfile->srch_inf.last_entry, cfile);
753 }
754
755 search_flags = CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME;
756 if (backup_cred(cifs_sb))
757 search_flags |= CIFS_SEARCH_BACKUP_SEARCH;
758
759 while ((index_to_find >= cfile->srch_inf.index_of_last_entry) &&
760 (rc == 0) && !cfile->srch_inf.endOfSearch) {
761 cifs_dbg(FYI, "calling findnext2\n");
762 rc = server->ops->query_dir_next(xid, tcon, &cfile->fid,
763 search_flags,
764 &cfile->srch_inf);
765
766 if (cfile->srch_inf.last_entry)
767 cifs_save_resume_key(cfile->srch_inf.last_entry, cfile);
768 if (rc)
769 return -ENOENT;
770 }
771 if (index_to_find < cfile->srch_inf.index_of_last_entry) {
772
773
774 int i;
775 char *cur_ent;
776 char *end_of_smb;
777
778 if (cfile->srch_inf.ntwrk_buf_start == NULL) {
779 cifs_dbg(VFS, "ntwrk_buf_start is NULL during readdir\n");
780 return -EIO;
781 }
782
783 end_of_smb = cfile->srch_inf.ntwrk_buf_start +
784 server->ops->calc_smb_size(
785 cfile->srch_inf.ntwrk_buf_start,
786 server);
787
788 cur_ent = cfile->srch_inf.srch_entries_start;
789 first_entry_in_buffer = cfile->srch_inf.index_of_last_entry
790 - cfile->srch_inf.entries_in_buffer;
791 pos_in_buf = index_to_find - first_entry_in_buffer;
792 cifs_dbg(FYI, "found entry - pos_in_buf %d\n", pos_in_buf);
793
794 for (i = 0; (i < (pos_in_buf)) && (cur_ent != NULL); i++) {
795
796 cur_ent = nxt_dir_entry(cur_ent, end_of_smb,
797 cfile->srch_inf.info_level);
798 }
799 if ((cur_ent == NULL) && (i < pos_in_buf)) {
800
801 cifs_dbg(VFS, "reached end of buf searching for pos in buf %d index to find %lld rc %d\n",
802 pos_in_buf, index_to_find, rc);
803 }
804 rc = 0;
805 *current_entry = cur_ent;
806 } else {
807 cifs_dbg(FYI, "index not in buffer - could not findnext into it\n");
808 return 0;
809 }
810
811 if (pos_in_buf >= cfile->srch_inf.entries_in_buffer) {
812 cifs_dbg(FYI, "can not return entries pos_in_buf beyond last\n");
813 *num_to_ret = 0;
814 } else
815 *num_to_ret = cfile->srch_inf.entries_in_buffer - pos_in_buf;
816
817 return rc;
818}
819
820static int cifs_filldir(char *find_entry, struct file *file,
821 struct dir_context *ctx,
822 char *scratch_buf, unsigned int max_len)
823{
824 struct cifsFileInfo *file_info = file->private_data;
825 struct super_block *sb = file_inode(file)->i_sb;
826 struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
827 struct cifs_dirent de = { NULL, };
828 struct cifs_fattr fattr;
829 struct qstr name;
830 int rc = 0;
831 ino_t ino;
832
833 rc = cifs_fill_dirent(&de, find_entry, file_info->srch_inf.info_level,
834 file_info->srch_inf.unicode);
835 if (rc)
836 return rc;
837
838 if (de.namelen > max_len) {
839 cifs_dbg(VFS, "bad search response length %zd past smb end\n",
840 de.namelen);
841 return -EINVAL;
842 }
843
844
845 if (cifs_entry_is_dot(&de, file_info->srch_inf.unicode))
846 return 0;
847
848 if (file_info->srch_inf.unicode) {
849 struct nls_table *nlt = cifs_sb->local_nls;
850 int map_type;
851
852 map_type = cifs_remap(cifs_sb);
853 name.name = scratch_buf;
854 name.len =
855 cifs_from_utf16((char *)name.name, (__le16 *)de.name,
856 UNICODE_NAME_MAX,
857 min_t(size_t, de.namelen,
858 (size_t)max_len), nlt, map_type);
859 name.len -= nls_nullsize(nlt);
860 } else {
861 name.name = de.name;
862 name.len = de.namelen;
863 }
864
865 switch (file_info->srch_inf.info_level) {
866 case SMB_FIND_FILE_POSIX_INFO:
867 cifs_posix_to_fattr(&fattr,
868 (struct smb2_posix_info *)find_entry,
869 cifs_sb);
870 break;
871 case SMB_FIND_FILE_UNIX:
872 cifs_unix_basic_to_fattr(&fattr,
873 &((FILE_UNIX_INFO *)find_entry)->basic,
874 cifs_sb);
875 break;
876 case SMB_FIND_FILE_INFO_STANDARD:
877 cifs_std_info_to_fattr(&fattr,
878 (FIND_FILE_STANDARD_INFO *)find_entry,
879 cifs_sb);
880 break;
881 case SMB_FIND_FILE_ID_FULL_DIR_INFO:
882 cifs_fulldir_info_to_fattr(&fattr,
883 (SEARCH_ID_FULL_DIR_INFO *)find_entry,
884 cifs_sb);
885 break;
886 default:
887 cifs_dir_info_to_fattr(&fattr,
888 (FILE_DIRECTORY_INFO *)find_entry,
889 cifs_sb);
890 break;
891 }
892
893 if (de.ino && (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)) {
894 fattr.cf_uniqueid = de.ino;
895 } else {
896 fattr.cf_uniqueid = iunique(sb, ROOT_I);
897 cifs_autodisable_serverino(cifs_sb);
898 }
899
900 if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) &&
901 couldbe_mf_symlink(&fattr))
902
903
904
905
906
907 fattr.cf_flags |= CIFS_FATTR_NEED_REVAL;
908
909 cifs_prime_dcache(file_dentry(file), &name, &fattr);
910
911 ino = cifs_uniqueid_to_ino_t(fattr.cf_uniqueid);
912 return !dir_emit(ctx, name.name, name.len, ino, fattr.cf_dtype);
913}
914
915
916int cifs_readdir(struct file *file, struct dir_context *ctx)
917{
918 int rc = 0;
919 unsigned int xid;
920 int i;
921 struct cifs_tcon *tcon;
922 struct cifsFileInfo *cifsFile = NULL;
923 char *current_entry;
924 int num_to_fill = 0;
925 char *tmp_buf = NULL;
926 char *end_of_smb;
927 unsigned int max_len;
928
929 xid = get_xid();
930
931
932
933
934
935 if (file->private_data == NULL) {
936 rc = initiate_cifs_search(xid, file);
937 cifs_dbg(FYI, "initiate cifs search rc %d\n", rc);
938 if (rc)
939 goto rddir2_exit;
940 }
941
942 if (!dir_emit_dots(file, ctx))
943 goto rddir2_exit;
944
945
946
947
948
949
950 cifsFile = file->private_data;
951 if (cifsFile->srch_inf.endOfSearch) {
952 if (cifsFile->srch_inf.emptyDir) {
953 cifs_dbg(FYI, "End of search, empty dir\n");
954 rc = 0;
955 goto rddir2_exit;
956 }
957 }
958
959
960
961
962 tcon = tlink_tcon(cifsFile->tlink);
963 rc = find_cifs_entry(xid, tcon, ctx->pos, file, ¤t_entry,
964 &num_to_fill);
965 if (rc) {
966 cifs_dbg(FYI, "fce error %d\n", rc);
967 goto rddir2_exit;
968 } else if (current_entry != NULL) {
969 cifs_dbg(FYI, "entry %lld found\n", ctx->pos);
970 } else {
971 cifs_dbg(FYI, "could not find entry\n");
972 goto rddir2_exit;
973 }
974 cifs_dbg(FYI, "loop through %d times filling dir for net buf %p\n",
975 num_to_fill, cifsFile->srch_inf.ntwrk_buf_start);
976 max_len = tcon->ses->server->ops->calc_smb_size(
977 cifsFile->srch_inf.ntwrk_buf_start,
978 tcon->ses->server);
979 end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + max_len;
980
981 tmp_buf = kmalloc(UNICODE_NAME_MAX, GFP_KERNEL);
982 if (tmp_buf == NULL) {
983 rc = -ENOMEM;
984 goto rddir2_exit;
985 }
986
987 for (i = 0; i < num_to_fill; i++) {
988 if (current_entry == NULL) {
989
990 cifs_dbg(VFS, "past SMB end, num to fill %d i %d\n",
991 num_to_fill, i);
992 break;
993 }
994
995
996
997
998 *tmp_buf = 0;
999 rc = cifs_filldir(current_entry, file, ctx,
1000 tmp_buf, max_len);
1001 if (rc) {
1002 if (rc > 0)
1003 rc = 0;
1004 break;
1005 }
1006
1007 ctx->pos++;
1008 if (ctx->pos ==
1009 cifsFile->srch_inf.index_of_last_entry) {
1010 cifs_dbg(FYI, "last entry in buf at pos %lld %s\n",
1011 ctx->pos, tmp_buf);
1012 cifs_save_resume_key(current_entry, cifsFile);
1013 break;
1014 } else
1015 current_entry =
1016 nxt_dir_entry(current_entry, end_of_smb,
1017 cifsFile->srch_inf.info_level);
1018 }
1019 kfree(tmp_buf);
1020
1021rddir2_exit:
1022 free_xid(xid);
1023 return rc;
1024}
1025