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