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