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