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