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 u32 next_offset = le32_to_cpu(pDirInfo->NextEntryOffset);
381
382 if (old_entry + next_offset < old_entry) {
383 cifs_dbg(VFS, "invalid offset %u\n", next_offset);
384 return NULL;
385 }
386 new_entry = old_entry + next_offset;
387 }
388 cifs_dbg(FYI, "new entry %p old entry %p\n", new_entry, old_entry);
389
390 if (new_entry >= end_of_smb) {
391 cifs_dbg(VFS, "search entry %p began after end of SMB %p old entry %p\n",
392 new_entry, end_of_smb, old_entry);
393 return NULL;
394 } else if (((level == SMB_FIND_FILE_INFO_STANDARD) &&
395 (new_entry + sizeof(FIND_FILE_STANDARD_INFO) > end_of_smb))
396 || ((level != SMB_FIND_FILE_INFO_STANDARD) &&
397 (new_entry + sizeof(FILE_DIRECTORY_INFO) > end_of_smb))) {
398 cifs_dbg(VFS, "search entry %p extends after end of SMB %p\n",
399 new_entry, end_of_smb);
400 return NULL;
401 } else
402 return new_entry;
403
404}
405
406struct cifs_dirent {
407 const char *name;
408 size_t namelen;
409 u32 resume_key;
410 u64 ino;
411};
412
413static void cifs_fill_dirent_unix(struct cifs_dirent *de,
414 const FILE_UNIX_INFO *info, bool is_unicode)
415{
416 de->name = &info->FileName[0];
417 if (is_unicode)
418 de->namelen = cifs_unicode_bytelen(de->name);
419 else
420 de->namelen = strnlen(de->name, PATH_MAX);
421 de->resume_key = info->ResumeKey;
422 de->ino = le64_to_cpu(info->basic.UniqueId);
423}
424
425static void cifs_fill_dirent_dir(struct cifs_dirent *de,
426 const FILE_DIRECTORY_INFO *info)
427{
428 de->name = &info->FileName[0];
429 de->namelen = le32_to_cpu(info->FileNameLength);
430 de->resume_key = info->FileIndex;
431}
432
433static void cifs_fill_dirent_full(struct cifs_dirent *de,
434 const FILE_FULL_DIRECTORY_INFO *info)
435{
436 de->name = &info->FileName[0];
437 de->namelen = le32_to_cpu(info->FileNameLength);
438 de->resume_key = info->FileIndex;
439}
440
441static void cifs_fill_dirent_search(struct cifs_dirent *de,
442 const SEARCH_ID_FULL_DIR_INFO *info)
443{
444 de->name = &info->FileName[0];
445 de->namelen = le32_to_cpu(info->FileNameLength);
446 de->resume_key = info->FileIndex;
447 de->ino = le64_to_cpu(info->UniqueId);
448}
449
450static void cifs_fill_dirent_both(struct cifs_dirent *de,
451 const FILE_BOTH_DIRECTORY_INFO *info)
452{
453 de->name = &info->FileName[0];
454 de->namelen = le32_to_cpu(info->FileNameLength);
455 de->resume_key = info->FileIndex;
456}
457
458static void cifs_fill_dirent_std(struct cifs_dirent *de,
459 const FIND_FILE_STANDARD_INFO *info)
460{
461 de->name = &info->FileName[0];
462
463 de->namelen = info->FileNameLength;
464 de->resume_key = info->ResumeKey;
465}
466
467static int cifs_fill_dirent(struct cifs_dirent *de, const void *info,
468 u16 level, bool is_unicode)
469{
470 memset(de, 0, sizeof(*de));
471
472 switch (level) {
473 case SMB_FIND_FILE_UNIX:
474 cifs_fill_dirent_unix(de, info, is_unicode);
475 break;
476 case SMB_FIND_FILE_DIRECTORY_INFO:
477 cifs_fill_dirent_dir(de, info);
478 break;
479 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
480 cifs_fill_dirent_full(de, info);
481 break;
482 case SMB_FIND_FILE_ID_FULL_DIR_INFO:
483 cifs_fill_dirent_search(de, info);
484 break;
485 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
486 cifs_fill_dirent_both(de, info);
487 break;
488 case SMB_FIND_FILE_INFO_STANDARD:
489 cifs_fill_dirent_std(de, info);
490 break;
491 default:
492 cifs_dbg(FYI, "Unknown findfirst level %d\n", level);
493 return -EINVAL;
494 }
495
496 return 0;
497}
498
499#define UNICODE_DOT cpu_to_le16(0x2e)
500
501
502static int cifs_entry_is_dot(struct cifs_dirent *de, bool is_unicode)
503{
504 int rc = 0;
505
506 if (!de->name)
507 return 0;
508
509 if (is_unicode) {
510 __le16 *ufilename = (__le16 *)de->name;
511 if (de->namelen == 2) {
512
513 if (ufilename[0] == UNICODE_DOT)
514 rc = 1;
515 } else if (de->namelen == 4) {
516
517 if (ufilename[0] == UNICODE_DOT &&
518 ufilename[1] == UNICODE_DOT)
519 rc = 2;
520 }
521 } else {
522 if (de->namelen == 1) {
523 if (de->name[0] == '.')
524 rc = 1;
525 } else if (de->namelen == 2) {
526 if (de->name[0] == '.' && de->name[1] == '.')
527 rc = 2;
528 }
529 }
530
531 return rc;
532}
533
534
535
536static int is_dir_changed(struct file *file)
537{
538 struct inode *inode = file_inode(file);
539 struct cifsInodeInfo *cifsInfo = CIFS_I(inode);
540
541 if (cifsInfo->time == 0)
542 return 1;
543 else
544 return 0;
545
546}
547
548static int cifs_save_resume_key(const char *current_entry,
549 struct cifsFileInfo *file_info)
550{
551 struct cifs_dirent de;
552 int rc;
553
554 rc = cifs_fill_dirent(&de, current_entry, file_info->srch_inf.info_level,
555 file_info->srch_inf.unicode);
556 if (!rc) {
557 file_info->srch_inf.presume_name = de.name;
558 file_info->srch_inf.resume_name_len = de.namelen;
559 file_info->srch_inf.resume_key = de.resume_key;
560 }
561 return rc;
562}
563
564
565
566
567
568
569
570
571static int
572find_cifs_entry(const unsigned int xid, struct cifs_tcon *tcon, loff_t pos,
573 struct file *file, char **current_entry, int *num_to_ret)
574{
575 __u16 search_flags;
576 int rc = 0;
577 int pos_in_buf = 0;
578 loff_t first_entry_in_buffer;
579 loff_t index_to_find = pos;
580 struct cifsFileInfo *cfile = file->private_data;
581 struct cifs_sb_info *cifs_sb = CIFS_FILE_SB(file);
582 struct TCP_Server_Info *server = tcon->ses->server;
583
584
585 if (!server->ops->query_dir_first || !server->ops->query_dir_next)
586 return -ENOSYS;
587
588 if ((cfile == NULL) || (current_entry == NULL) || (num_to_ret == NULL))
589 return -ENOENT;
590
591 *current_entry = NULL;
592 first_entry_in_buffer = cfile->srch_inf.index_of_last_entry -
593 cfile->srch_inf.entries_in_buffer;
594
595
596
597
598
599
600
601
602
603 dump_cifs_file_struct(file, "In fce ");
604 if (((index_to_find < cfile->srch_inf.index_of_last_entry) &&
605 is_dir_changed(file)) || (index_to_find < first_entry_in_buffer)) {
606
607 cifs_dbg(FYI, "search backing up - close and restart search\n");
608 spin_lock(&cfile->file_info_lock);
609 if (server->ops->dir_needs_close(cfile)) {
610 cfile->invalidHandle = true;
611 spin_unlock(&cfile->file_info_lock);
612 if (server->ops->close_dir)
613 server->ops->close_dir(xid, tcon, &cfile->fid);
614 } else
615 spin_unlock(&cfile->file_info_lock);
616 if (cfile->srch_inf.ntwrk_buf_start) {
617 cifs_dbg(FYI, "freeing SMB ff cache buf on search rewind\n");
618 if (cfile->srch_inf.smallBuf)
619 cifs_small_buf_release(cfile->srch_inf.
620 ntwrk_buf_start);
621 else
622 cifs_buf_release(cfile->srch_inf.
623 ntwrk_buf_start);
624 cfile->srch_inf.ntwrk_buf_start = NULL;
625 }
626 rc = initiate_cifs_search(xid, file);
627 if (rc) {
628 cifs_dbg(FYI, "error %d reinitiating a search on rewind\n",
629 rc);
630 return rc;
631 }
632
633 if (cfile->srch_inf.last_entry)
634 cifs_save_resume_key(cfile->srch_inf.last_entry, cfile);
635 }
636
637 search_flags = CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME;
638 if (backup_cred(cifs_sb))
639 search_flags |= CIFS_SEARCH_BACKUP_SEARCH;
640
641 while ((index_to_find >= cfile->srch_inf.index_of_last_entry) &&
642 (rc == 0) && !cfile->srch_inf.endOfSearch) {
643 cifs_dbg(FYI, "calling findnext2\n");
644 rc = server->ops->query_dir_next(xid, tcon, &cfile->fid,
645 search_flags,
646 &cfile->srch_inf);
647
648 if (cfile->srch_inf.last_entry)
649 cifs_save_resume_key(cfile->srch_inf.last_entry, cfile);
650 if (rc)
651 return -ENOENT;
652 }
653 if (index_to_find < cfile->srch_inf.index_of_last_entry) {
654
655
656 int i;
657 char *cur_ent;
658 char *end_of_smb;
659
660 if (cfile->srch_inf.ntwrk_buf_start == NULL) {
661 cifs_dbg(VFS, "ntwrk_buf_start is NULL during readdir\n");
662 return -EIO;
663 }
664
665 end_of_smb = cfile->srch_inf.ntwrk_buf_start +
666 server->ops->calc_smb_size(
667 cfile->srch_inf.ntwrk_buf_start,
668 server);
669
670 cur_ent = cfile->srch_inf.srch_entries_start;
671 first_entry_in_buffer = cfile->srch_inf.index_of_last_entry
672 - cfile->srch_inf.entries_in_buffer;
673 pos_in_buf = index_to_find - first_entry_in_buffer;
674 cifs_dbg(FYI, "found entry - pos_in_buf %d\n", pos_in_buf);
675
676 for (i = 0; (i < (pos_in_buf)) && (cur_ent != NULL); i++) {
677
678 cur_ent = nxt_dir_entry(cur_ent, end_of_smb,
679 cfile->srch_inf.info_level);
680 }
681 if ((cur_ent == NULL) && (i < pos_in_buf)) {
682
683 cifs_dbg(VFS, "reached end of buf searching for pos in buf %d index to find %lld rc %d\n",
684 pos_in_buf, index_to_find, rc);
685 }
686 rc = 0;
687 *current_entry = cur_ent;
688 } else {
689 cifs_dbg(FYI, "index not in buffer - could not findnext into it\n");
690 return 0;
691 }
692
693 if (pos_in_buf >= cfile->srch_inf.entries_in_buffer) {
694 cifs_dbg(FYI, "can not return entries pos_in_buf beyond last\n");
695 *num_to_ret = 0;
696 } else
697 *num_to_ret = cfile->srch_inf.entries_in_buffer - pos_in_buf;
698
699 return rc;
700}
701
702static int cifs_filldir(char *find_entry, struct file *file,
703 struct dir_context *ctx,
704 char *scratch_buf, unsigned int max_len)
705{
706 struct cifsFileInfo *file_info = file->private_data;
707 struct super_block *sb = file_inode(file)->i_sb;
708 struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
709 struct cifs_dirent de = { NULL, };
710 struct cifs_fattr fattr;
711 struct qstr name;
712 int rc = 0;
713 ino_t ino;
714
715 rc = cifs_fill_dirent(&de, find_entry, file_info->srch_inf.info_level,
716 file_info->srch_inf.unicode);
717 if (rc)
718 return rc;
719
720 if (de.namelen > max_len) {
721 cifs_dbg(VFS, "bad search response length %zd past smb end\n",
722 de.namelen);
723 return -EINVAL;
724 }
725
726
727 if (cifs_entry_is_dot(&de, file_info->srch_inf.unicode))
728 return 0;
729
730 if (file_info->srch_inf.unicode) {
731 struct nls_table *nlt = cifs_sb->local_nls;
732 int map_type;
733
734 map_type = cifs_remap(cifs_sb);
735 name.name = scratch_buf;
736 name.len =
737 cifs_from_utf16((char *)name.name, (__le16 *)de.name,
738 UNICODE_NAME_MAX,
739 min_t(size_t, de.namelen,
740 (size_t)max_len), nlt, map_type);
741 name.len -= nls_nullsize(nlt);
742 } else {
743 name.name = de.name;
744 name.len = de.namelen;
745 }
746
747 switch (file_info->srch_inf.info_level) {
748 case SMB_FIND_FILE_UNIX:
749 cifs_unix_basic_to_fattr(&fattr,
750 &((FILE_UNIX_INFO *)find_entry)->basic,
751 cifs_sb);
752 break;
753 case SMB_FIND_FILE_INFO_STANDARD:
754 cifs_std_info_to_fattr(&fattr,
755 (FIND_FILE_STANDARD_INFO *)find_entry,
756 cifs_sb);
757 break;
758 default:
759 cifs_dir_info_to_fattr(&fattr,
760 (FILE_DIRECTORY_INFO *)find_entry,
761 cifs_sb);
762 break;
763 }
764
765 if (de.ino && (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)) {
766 fattr.cf_uniqueid = de.ino;
767 } else {
768 fattr.cf_uniqueid = iunique(sb, ROOT_I);
769 cifs_autodisable_serverino(cifs_sb);
770 }
771
772 if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) &&
773 couldbe_mf_symlink(&fattr))
774
775
776
777
778
779 fattr.cf_flags |= CIFS_FATTR_NEED_REVAL;
780
781 cifs_prime_dcache(file_dentry(file), &name, &fattr);
782
783 ino = cifs_uniqueid_to_ino_t(fattr.cf_uniqueid);
784 return !dir_emit(ctx, name.name, name.len, ino, fattr.cf_dtype);
785}
786
787
788int cifs_readdir(struct file *file, struct dir_context *ctx)
789{
790 int rc = 0;
791 unsigned int xid;
792 int i;
793 struct cifs_tcon *tcon;
794 struct cifsFileInfo *cifsFile = NULL;
795 char *current_entry;
796 int num_to_fill = 0;
797 char *tmp_buf = NULL;
798 char *end_of_smb;
799 unsigned int max_len;
800
801 xid = get_xid();
802
803
804
805
806
807 if (file->private_data == NULL) {
808 rc = initiate_cifs_search(xid, file);
809 cifs_dbg(FYI, "initiate cifs search rc %d\n", rc);
810 if (rc)
811 goto rddir2_exit;
812 }
813
814 if (!dir_emit_dots(file, ctx))
815 goto rddir2_exit;
816
817
818
819
820
821
822 cifsFile = file->private_data;
823 if (cifsFile->srch_inf.endOfSearch) {
824 if (cifsFile->srch_inf.emptyDir) {
825 cifs_dbg(FYI, "End of search, empty dir\n");
826 rc = 0;
827 goto rddir2_exit;
828 }
829 }
830
831
832
833
834 tcon = tlink_tcon(cifsFile->tlink);
835 rc = find_cifs_entry(xid, tcon, ctx->pos, file, ¤t_entry,
836 &num_to_fill);
837 if (rc) {
838 cifs_dbg(FYI, "fce error %d\n", rc);
839 goto rddir2_exit;
840 } else if (current_entry != NULL) {
841 cifs_dbg(FYI, "entry %lld found\n", ctx->pos);
842 } else {
843 cifs_dbg(FYI, "could not find entry\n");
844 goto rddir2_exit;
845 }
846 cifs_dbg(FYI, "loop through %d times filling dir for net buf %p\n",
847 num_to_fill, cifsFile->srch_inf.ntwrk_buf_start);
848 max_len = tcon->ses->server->ops->calc_smb_size(
849 cifsFile->srch_inf.ntwrk_buf_start,
850 tcon->ses->server);
851 end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + max_len;
852
853 tmp_buf = kmalloc(UNICODE_NAME_MAX, GFP_KERNEL);
854 if (tmp_buf == NULL) {
855 rc = -ENOMEM;
856 goto rddir2_exit;
857 }
858
859 for (i = 0; i < num_to_fill; i++) {
860 if (current_entry == NULL) {
861
862 cifs_dbg(VFS, "past SMB end, num to fill %d i %d\n",
863 num_to_fill, i);
864 break;
865 }
866
867
868
869
870 *tmp_buf = 0;
871 rc = cifs_filldir(current_entry, file, ctx,
872 tmp_buf, max_len);
873 if (rc) {
874 if (rc > 0)
875 rc = 0;
876 break;
877 }
878
879 ctx->pos++;
880 if (ctx->pos ==
881 cifsFile->srch_inf.index_of_last_entry) {
882 cifs_dbg(FYI, "last entry in buf at pos %lld %s\n",
883 ctx->pos, tmp_buf);
884 cifs_save_resume_key(current_entry, cifsFile);
885 break;
886 } else
887 current_entry =
888 nxt_dir_entry(current_entry, end_of_smb,
889 cifsFile->srch_inf.info_level);
890 }
891 kfree(tmp_buf);
892
893rddir2_exit:
894 free_xid(xid);
895 return rc;
896}
897