Blame view

fs/cifs/readdir.c 22.9 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
  /*
   *   fs/cifs/readdir.c
   *
   *   Directory search handling
6dc0f87e3   Steve French   [CIFS] whitespace...
5
   *
ad7a2926b   Steve French   [CIFS] reduce che...
6
   *   Copyright (C) International Business Machines  Corp., 2004, 2008
cda0ec6a8   Christoph Hellwig   cifs: introduce c...
7
   *   Copyright (C) Red Hat, Inc., 2011
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
   *   Author(s): Steve French (sfrench@us.ibm.com)
   *
   *   This library is free software; you can redistribute it and/or modify
   *   it under the terms of the GNU Lesser General Public License as published
   *   by the Free Software Foundation; either version 2.1 of the License, or
   *   (at your option) any later version.
   *
   *   This library is distributed in the hope that it will be useful,
   *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
   *   the GNU Lesser General Public License for more details.
   *
   *   You should have received a copy of the GNU Lesser General Public License
   *   along with this library; if not, write to the Free Software
   *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
   */
  #include <linux/fs.h>
273d81d6a   Dave Kleikamp   [CIFS] Do not ove...
25
  #include <linux/pagemap.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
26
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
27
  #include <linux/stat.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
28
29
30
31
32
33
34
  #include "cifspdu.h"
  #include "cifsglob.h"
  #include "cifsproto.h"
  #include "cifs_unicode.h"
  #include "cifs_debug.h"
  #include "cifs_fs_sb.h"
  #include "cifsfs.h"
f58841666   Jeff Layton   cifs: change cifs...
35
36
37
38
39
40
  /*
   * To be safe - for UCS to UTF-8 with strings loaded with the rare long
   * characters alloc more to account for such multibyte target UTF-8
   * characters.
   */
  #define UNICODE_NAME_MAX ((4 * NAME_MAX) + 2)
3979877e5   Steve French   [CIFS] Support fo...
41
42
  #ifdef CONFIG_CIFS_DEBUG2
  static void dump_cifs_file_struct(struct file *file, char *label)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
43
  {
6dc0f87e3   Steve French   [CIFS] whitespace...
44
  	struct cifsFileInfo *cf;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
45

4523cc304   Steve French   [CIFS] UID/GID ov...
46
  	if (file) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
47
  		cf = file->private_data;
4523cc304   Steve French   [CIFS] UID/GID ov...
48
  		if (cf == NULL) {
b6b38f704   Joe Perches   [CIFS] Neaten cER...
49
  			cFYI(1, "empty cifs private file data");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
50
51
  			return;
  		}
ad7a2926b   Steve French   [CIFS] reduce che...
52
  		if (cf->invalidHandle)
b6b38f704   Joe Perches   [CIFS] Neaten cER...
53
  			cFYI(1, "invalid handle");
ad7a2926b   Steve French   [CIFS] reduce che...
54
  		if (cf->srch_inf.endOfSearch)
b6b38f704   Joe Perches   [CIFS] Neaten cER...
55
  			cFYI(1, "end of search");
ad7a2926b   Steve French   [CIFS] reduce che...
56
  		if (cf->srch_inf.emptyDir)
b6b38f704   Joe Perches   [CIFS] Neaten cER...
57
  			cFYI(1, "empty dir");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
58
  	}
3979877e5   Steve French   [CIFS] Support fo...
59
  }
90c81e0b0   Steve French   [CIFS] clean up s...
60
61
62
63
  #else
  static inline void dump_cifs_file_struct(struct file *file, char *label)
  {
  }
3979877e5   Steve French   [CIFS] Support fo...
64
  #endif /* DEBUG2 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
65

cc0bad755   Jeff Layton   cifs: add new cif...
66
67
68
69
70
71
72
73
74
75
76
  /*
   * Find the dentry that matches "name". If there isn't one, create one. If it's
   * a negative dentry or the uniqueid changed, then drop it and recreate it.
   */
  static struct dentry *
  cifs_readdir_lookup(struct dentry *parent, struct qstr *name,
  		    struct cifs_fattr *fattr)
  {
  	struct dentry *dentry, *alias;
  	struct inode *inode;
  	struct super_block *sb = parent->d_inode->i_sb;
b6b38f704   Joe Perches   [CIFS] Neaten cER...
77
  	cFYI(1, "For %s", name->name);
cc0bad755   Jeff Layton   cifs: add new cif...
78

05507fa2a   Jeff Layton   cifs: fix dentry ...
79
  	if (parent->d_op && parent->d_op->d_hash)
b1e6a015a   Nick Piggin   fs: change d_hash...
80
  		parent->d_op->d_hash(parent, parent->d_inode, name);
05507fa2a   Jeff Layton   cifs: fix dentry ...
81
82
  	else
  		name->hash = full_name_hash(name->name, name->len);
cc0bad755   Jeff Layton   cifs: add new cif...
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
  	dentry = d_lookup(parent, name);
  	if (dentry) {
  		/* FIXME: check for inode number changes? */
  		if (dentry->d_inode != NULL)
  			return dentry;
  		d_drop(dentry);
  		dput(dentry);
  	}
  
  	dentry = d_alloc(parent, name);
  	if (dentry == NULL)
  		return NULL;
  
  	inode = cifs_iget(sb, fattr);
  	if (!inode) {
  		dput(dentry);
  		return NULL;
  	}
cc0bad755   Jeff Layton   cifs: add new cif...
101
102
103
104
105
106
107
108
109
110
  	alias = d_materialise_unique(dentry, inode);
  	if (alias != NULL) {
  		dput(dentry);
  		if (IS_ERR(alias))
  			return NULL;
  		dentry = alias;
  	}
  
  	return dentry;
  }
0b8f18e35   Jeff Layton   cifs: convert cif...
111
112
  static void
  cifs_fill_common_info(struct cifs_fattr *fattr, struct cifs_sb_info *cifs_sb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
113
  {
0b8f18e35   Jeff Layton   cifs: convert cif...
114
115
  	fattr->cf_uid = cifs_sb->mnt_uid;
  	fattr->cf_gid = cifs_sb->mnt_gid;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
116

0b8f18e35   Jeff Layton   cifs: convert cif...
117
118
119
  	if (fattr->cf_cifsattrs & ATTR_DIRECTORY) {
  		fattr->cf_mode = S_IFDIR | cifs_sb->mnt_dir_mode;
  		fattr->cf_dtype = DT_DIR;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
120
  	} else {
0b8f18e35   Jeff Layton   cifs: convert cif...
121
122
  		fattr->cf_mode = S_IFREG | cifs_sb->mnt_file_mode;
  		fattr->cf_dtype = DT_REG;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
123
  	}
0b8f18e35   Jeff Layton   cifs: convert cif...
124
125
  	if (fattr->cf_cifsattrs & ATTR_READONLY)
  		fattr->cf_mode &= ~S_IWUGO;
5bafd7659   Steve French   [CIFS] Add suppor...
126

0b8f18e35   Jeff Layton   cifs: convert cif...
127
128
129
130
131
132
  	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL &&
  	    fattr->cf_cifsattrs & ATTR_SYSTEM) {
  		if (fattr->cf_eof == 0)  {
  			fattr->cf_mode &= ~S_IFMT;
  			fattr->cf_mode |= S_IFIFO;
  			fattr->cf_dtype = DT_FIFO;
3020a1f58   Steve French   [CIFS] Fix schedu...
133
  		} else {
4468eb3fd   Jeff Layton   on non-posix shar...
134
  			/*
0b8f18e35   Jeff Layton   cifs: convert cif...
135
136
137
  			 * trying to get the type and mode via SFU can be slow,
  			 * so just call those regular files for now, and mark
  			 * for reval
4468eb3fd   Jeff Layton   on non-posix shar...
138
  			 */
0b8f18e35   Jeff Layton   cifs: convert cif...
139
  			fattr->cf_flags |= CIFS_FATTR_NEED_REVAL;
4468eb3fd   Jeff Layton   on non-posix shar...
140
141
  		}
  	}
0b8f18e35   Jeff Layton   cifs: convert cif...
142
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
143

15dd47810   Steve French   [CIFS] Remove bui...
144
  static void
0b8f18e35   Jeff Layton   cifs: convert cif...
145
146
147
148
149
150
151
  cifs_dir_info_to_fattr(struct cifs_fattr *fattr, FILE_DIRECTORY_INFO *info,
  		       struct cifs_sb_info *cifs_sb)
  {
  	memset(fattr, 0, sizeof(*fattr));
  	fattr->cf_cifsattrs = le32_to_cpu(info->ExtFileAttributes);
  	fattr->cf_eof = le64_to_cpu(info->EndOfFile);
  	fattr->cf_bytes = le64_to_cpu(info->AllocationSize);
20054bd65   Jeff Layton   cifs: use Creatio...
152
  	fattr->cf_createtime = le64_to_cpu(info->CreationTime);
0b8f18e35   Jeff Layton   cifs: convert cif...
153
154
155
156
157
158
  	fattr->cf_atime = cifs_NTtimeToUnix(info->LastAccessTime);
  	fattr->cf_ctime = cifs_NTtimeToUnix(info->ChangeTime);
  	fattr->cf_mtime = cifs_NTtimeToUnix(info->LastWriteTime);
  
  	cifs_fill_common_info(fattr, cifs_sb);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
159

15dd47810   Steve French   [CIFS] Remove bui...
160
  static void
0b8f18e35   Jeff Layton   cifs: convert cif...
161
162
163
  cifs_std_info_to_fattr(struct cifs_fattr *fattr, FIND_FILE_STANDARD_INFO *info,
  		       struct cifs_sb_info *cifs_sb)
  {
0d424ad0a   Jeff Layton   cifs: add cifs_sb...
164
  	int offset = cifs_sb_master_tcon(cifs_sb)->ses->server->timeAdj;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
165

0b8f18e35   Jeff Layton   cifs: convert cif...
166
167
168
169
170
171
172
173
174
175
176
177
178
  	memset(fattr, 0, sizeof(*fattr));
  	fattr->cf_atime = cnvrtDosUnixTm(info->LastAccessDate,
  					    info->LastAccessTime, offset);
  	fattr->cf_ctime = cnvrtDosUnixTm(info->LastWriteDate,
  					    info->LastWriteTime, offset);
  	fattr->cf_mtime = cnvrtDosUnixTm(info->LastWriteDate,
  					    info->LastWriteTime, offset);
  
  	fattr->cf_cifsattrs = le16_to_cpu(info->Attributes);
  	fattr->cf_bytes = le32_to_cpu(info->AllocationSize);
  	fattr->cf_eof = le32_to_cpu(info->DataSize);
  
  	cifs_fill_common_info(fattr, cifs_sb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
179
  }
0e0d2cf32   Steve French   [CIFS] Remove spa...
180
181
182
183
184
185
186
187
188
189
190
  /* BB eventually need to add the following helper function to
        resolve NT_STATUS_STOPPED_ON_SYMLINK return code when
        we try to do FindFirst on (NTFS) directory symlinks */
  /*
  int get_symlink_reparse_path(char *full_path, struct cifs_sb_info *cifs_sb,
  			     int xid)
  {
  	__u16 fid;
  	int len;
  	int oplock = 0;
  	int rc;
96daf2b09   Steve French   [CIFS] Rename thr...
191
  	struct cifs_tcon *ptcon = cifs_sb_tcon(cifs_sb);
0e0d2cf32   Steve French   [CIFS] Remove spa...
192
193
194
195
196
197
198
199
200
201
202
203
204
205
  	char *tmpbuffer;
  
  	rc = CIFSSMBOpen(xid, ptcon, full_path, FILE_OPEN, GENERIC_READ,
  			OPEN_REPARSE_POINT, &fid, &oplock, NULL,
  			cifs_sb->local_nls,
  			cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
  	if (!rc) {
  		tmpbuffer = kmalloc(maxpath);
  		rc = CIFSSMBQueryReparseLinkInfo(xid, ptcon, full_path,
  				tmpbuffer,
  				maxpath -1,
  				fid,
  				cifs_sb->local_nls);
  		if (CIFSSMBClose(xid, ptcon, fid)) {
b6b38f704   Joe Perches   [CIFS] Neaten cER...
206
  			cFYI(1, "Error closing temporary reparsepoint open");
0e0d2cf32   Steve French   [CIFS] Remove spa...
207
208
209
210
  		}
  	}
  }
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
211
212
213
  static int initiate_cifs_search(const int xid, struct file *file)
  {
  	int rc = 0;
7ffec3724   Jeff Layton   cifs: add refcoun...
214
  	char *full_path = NULL;
3870253ef   Steve French   [CIFS] more white...
215
  	struct cifsFileInfo *cifsFile;
7ffec3724   Jeff Layton   cifs: add refcoun...
216
  	struct cifs_sb_info *cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
59c55ba1f   Jeff Layton   cifs: don't take ...
217
  	struct tcon_link *tlink = NULL;
96daf2b09   Steve French   [CIFS] Rename thr...
218
  	struct cifs_tcon *pTcon;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
219

7ffec3724   Jeff Layton   cifs: add refcoun...
220
  	if (file->private_data == NULL) {
59c55ba1f   Jeff Layton   cifs: don't take ...
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
  		tlink = cifs_sb_tlink(cifs_sb);
  		if (IS_ERR(tlink))
  			return PTR_ERR(tlink);
  
  		cifsFile = kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
  		if (cifsFile == NULL) {
  			rc = -ENOMEM;
  			goto error_exit;
  		}
  		file->private_data = cifsFile;
  		cifsFile->tlink = cifs_get_tlink(tlink);
  		pTcon = tlink_tcon(tlink);
  	} else {
  		cifsFile = file->private_data;
  		pTcon = tlink_tcon(cifsFile->tlink);
7ffec3724   Jeff Layton   cifs: add refcoun...
236
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
237

4b18f2a9c   Steve French   [CIFS] convert us...
238
239
  	cifsFile->invalidHandle = true;
  	cifsFile->srch_inf.endOfSearch = false;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
240

e6a002964   Josef "Jeff" Sipek   [PATCH] cifs: cha...
241
  	full_path = build_path_from_dentry(file->f_path.dentry);
7ffec3724   Jeff Layton   cifs: add refcoun...
242
243
244
245
  	if (full_path == NULL) {
  		rc = -ENOMEM;
  		goto error_exit;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
246

b6b38f704   Joe Perches   [CIFS] Neaten cER...
247
  	cFYI(1, "Full path: %s start at: %lld", full_path, file->f_pos);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
248

75cf6bdc5   Steve French   [PATCH] cifs: Gra...
249
  ffirst_retry:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
250
  	/* test for Unix extensions */
c18c842b1   Steve French   [CIFS] Allow disa...
251
252
  	/* but now check for them on the share/mount not on the SMB session */
  /*	if (pTcon->ses->capabilities & CAP_UNIX) { */
ad7a2926b   Steve French   [CIFS] reduce che...
253
  	if (pTcon->unix_ext)
5bafd7659   Steve French   [CIFS] Add suppor...
254
  		cifsFile->srch_inf.info_level = SMB_FIND_FILE_UNIX;
ad7a2926b   Steve French   [CIFS] reduce che...
255
  	else if ((pTcon->ses->capabilities &
5bafd7659   Steve French   [CIFS] Add suppor...
256
257
  			(CAP_NT_SMBS | CAP_NT_FIND)) == 0) {
  		cifsFile->srch_inf.info_level = SMB_FIND_FILE_INFO_STANDARD;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
258
259
260
261
262
  	} else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
  		cifsFile->srch_inf.info_level = SMB_FIND_FILE_ID_FULL_DIR_INFO;
  	} else /* not srvinos - BB fixme add check for backlevel? */ {
  		cifsFile->srch_inf.info_level = SMB_FIND_FILE_DIRECTORY_INFO;
  	}
3870253ef   Steve French   [CIFS] more white...
263
  	rc = CIFSFindFirst(xid, pTcon, full_path, cifs_sb->local_nls,
737b758c9   Steve French   [PATCH] cifs: cha...
264
  		&cifsFile->netfid, &cifsFile->srch_inf,
3870253ef   Steve French   [CIFS] more white...
265
  		cifs_sb->mnt_cifs_flags &
eafe87012   Steve French   [CIFS] Fix readdi...
266
  			CIFS_MOUNT_MAP_SPECIAL_CHR, CIFS_DIR_SEP(cifs_sb));
4523cc304   Steve French   [CIFS] UID/GID ov...
267
  	if (rc == 0)
4b18f2a9c   Steve French   [CIFS] convert us...
268
  		cifsFile->invalidHandle = false;
e836f015b   Steve French   [CIFS] Remove tra...
269
  	/* BB add following call to handle readdir on new NTFS symlink errors
0e0d2cf32   Steve French   [CIFS] Remove spa...
270
271
272
  	else if STATUS_STOPPED_ON_SYMLINK
  		call get_symlink_reparse_path and retry with new path */
  	else if ((rc == -EOPNOTSUPP) &&
75cf6bdc5   Steve French   [PATCH] cifs: Gra...
273
274
275
276
  		(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)) {
  		cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_SERVER_INUM;
  		goto ffirst_retry;
  	}
7ffec3724   Jeff Layton   cifs: add refcoun...
277
  error_exit:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
278
  	kfree(full_path);
7ffec3724   Jeff Layton   cifs: add refcoun...
279
  	cifs_put_tlink(tlink);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
280
281
282
283
  	return rc;
  }
  
  /* return length of unicode string in bytes */
cda0ec6a8   Christoph Hellwig   cifs: introduce c...
284
  static int cifs_unicode_bytelen(const char *str)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
285
286
  {
  	int len;
cda0ec6a8   Christoph Hellwig   cifs: introduce c...
287
  	const __le16 *ustr = (const __le16 *)str;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
288

3870253ef   Steve French   [CIFS] more white...
289
  	for (len = 0; len <= PATH_MAX; len++) {
4523cc304   Steve French   [CIFS] UID/GID ov...
290
  		if (ustr[len] == 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
291
292
  			return len << 1;
  	}
b6b38f704   Joe Perches   [CIFS] Neaten cER...
293
  	cFYI(1, "Unicode string longer than PATH_MAX found");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
294
295
  	return len << 1;
  }
5bafd7659   Steve French   [CIFS] Add suppor...
296
  static char *nxt_dir_entry(char *old_entry, char *end_of_smb, int level)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
297
  {
3870253ef   Steve French   [CIFS] more white...
298
  	char *new_entry;
ad7a2926b   Steve French   [CIFS] reduce che...
299
  	FILE_DIRECTORY_INFO *pDirInfo = (FILE_DIRECTORY_INFO *)old_entry;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
300

4523cc304   Steve French   [CIFS] UID/GID ov...
301
  	if (level == SMB_FIND_FILE_INFO_STANDARD) {
ad7a2926b   Steve French   [CIFS] reduce che...
302
  		FIND_FILE_STANDARD_INFO *pfData;
5bafd7659   Steve French   [CIFS] Add suppor...
303
304
305
306
307
308
  		pfData = (FIND_FILE_STANDARD_INFO *)pDirInfo;
  
  		new_entry = old_entry + sizeof(FIND_FILE_STANDARD_INFO) +
  				pfData->FileNameLength;
  	} else
  		new_entry = old_entry + le32_to_cpu(pDirInfo->NextEntryOffset);
b6b38f704   Joe Perches   [CIFS] Neaten cER...
309
  	cFYI(1, "new entry %p old entry %p", new_entry, old_entry);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
310
  	/* validate that new_entry is not past end of SMB */
4523cc304   Steve French   [CIFS] UID/GID ov...
311
  	if (new_entry >= end_of_smb) {
b6b38f704   Joe Perches   [CIFS] Neaten cER...
312
313
  		cERROR(1, "search entry %p began after end of SMB %p old entry %p",
  			new_entry, end_of_smb, old_entry);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
314
  		return NULL;
4523cc304   Steve French   [CIFS] UID/GID ov...
315
  	} else if (((level == SMB_FIND_FILE_INFO_STANDARD) &&
3870253ef   Steve French   [CIFS] more white...
316
317
  		    (new_entry + sizeof(FIND_FILE_STANDARD_INFO) > end_of_smb))
  		  || ((level != SMB_FIND_FILE_INFO_STANDARD) &&
5bafd7659   Steve French   [CIFS] Add suppor...
318
  		   (new_entry + sizeof(FILE_DIRECTORY_INFO) > end_of_smb)))  {
b6b38f704   Joe Perches   [CIFS] Neaten cER...
319
320
  		cERROR(1, "search entry %p extends after end of SMB %p",
  			new_entry, end_of_smb);
09d1db5c6   Steve French   [PATCH] cifs: imp...
321
  		return NULL;
3870253ef   Steve French   [CIFS] more white...
322
  	} else
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
323
324
325
  		return new_entry;
  
  }
cda0ec6a8   Christoph Hellwig   cifs: introduce c...
326
327
328
329
330
331
332
333
334
335
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
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
  struct cifs_dirent {
  	const char	*name;
  	size_t		namelen;
  	u32		resume_key;
  	u64		ino;
  };
  
  static void cifs_fill_dirent_unix(struct cifs_dirent *de,
  		const FILE_UNIX_INFO *info, bool is_unicode)
  {
  	de->name = &info->FileName[0];
  	if (is_unicode)
  		de->namelen = cifs_unicode_bytelen(de->name);
  	else
  		de->namelen = strnlen(de->name, PATH_MAX);
  	de->resume_key = info->ResumeKey;
  	de->ino = le64_to_cpu(info->basic.UniqueId);
  }
  
  static void cifs_fill_dirent_dir(struct cifs_dirent *de,
  		const FILE_DIRECTORY_INFO *info)
  {
  	de->name = &info->FileName[0];
  	de->namelen = le32_to_cpu(info->FileNameLength);
  	de->resume_key = info->FileIndex;
  }
  
  static void cifs_fill_dirent_full(struct cifs_dirent *de,
  		const FILE_FULL_DIRECTORY_INFO *info)
  {
  	de->name = &info->FileName[0];
  	de->namelen = le32_to_cpu(info->FileNameLength);
  	de->resume_key = info->FileIndex;
  }
  
  static void cifs_fill_dirent_search(struct cifs_dirent *de,
  		const SEARCH_ID_FULL_DIR_INFO *info)
  {
  	de->name = &info->FileName[0];
  	de->namelen = le32_to_cpu(info->FileNameLength);
  	de->resume_key = info->FileIndex;
  	de->ino = le64_to_cpu(info->UniqueId);
  }
  
  static void cifs_fill_dirent_both(struct cifs_dirent *de,
  		const FILE_BOTH_DIRECTORY_INFO *info)
  {
  	de->name = &info->FileName[0];
  	de->namelen = le32_to_cpu(info->FileNameLength);
  	de->resume_key = info->FileIndex;
  }
  
  static void cifs_fill_dirent_std(struct cifs_dirent *de,
  		const FIND_FILE_STANDARD_INFO *info)
  {
  	de->name = &info->FileName[0];
  	/* one byte length, no endianess conversion */
  	de->namelen = info->FileNameLength;
  	de->resume_key = info->ResumeKey;
  }
  
  static int cifs_fill_dirent(struct cifs_dirent *de, const void *info,
  		u16 level, bool is_unicode)
  {
  	memset(de, 0, sizeof(*de));
  
  	switch (level) {
  	case SMB_FIND_FILE_UNIX:
  		cifs_fill_dirent_unix(de, info, is_unicode);
  		break;
  	case SMB_FIND_FILE_DIRECTORY_INFO:
  		cifs_fill_dirent_dir(de, info);
  		break;
  	case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
  		cifs_fill_dirent_full(de, info);
  		break;
  	case SMB_FIND_FILE_ID_FULL_DIR_INFO:
  		cifs_fill_dirent_search(de, info);
  		break;
  	case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
  		cifs_fill_dirent_both(de, info);
  		break;
  	case SMB_FIND_FILE_INFO_STANDARD:
  		cifs_fill_dirent_std(de, info);
  		break;
  	default:
  		cFYI(1, "Unknown findfirst level %d", level);
  		return -EINVAL;
  	}
  
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
418
419
420
  #define UNICODE_DOT cpu_to_le16(0x2e)
  
  /* return 0 if no match and 1 for . (current directory) and 2 for .. (parent) */
cda0ec6a8   Christoph Hellwig   cifs: introduce c...
421
  static int cifs_entry_is_dot(struct cifs_dirent *de, bool is_unicode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
422
423
  {
  	int rc = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
424

cda0ec6a8   Christoph Hellwig   cifs: introduce c...
425
426
  	if (!de->name)
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
427

cda0ec6a8   Christoph Hellwig   cifs: introduce c...
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
  	if (is_unicode) {
  		__le16 *ufilename = (__le16 *)de->name;
  		if (de->namelen == 2) {
  			/* check for . */
  			if (ufilename[0] == UNICODE_DOT)
  				rc = 1;
  		} else if (de->namelen == 4) {
  			/* check for .. */
  			if (ufilename[0] == UNICODE_DOT &&
  			    ufilename[1] == UNICODE_DOT)
  				rc = 2;
  		}
  	} else /* ASCII */ {
  		if (de->namelen == 1) {
  			if (de->name[0] == '.')
  				rc = 1;
  		} else if (de->namelen == 2) {
  			if (de->name[0] == '.' && de->name[1] == '.')
  				rc = 2;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
447
448
449
450
451
  		}
  	}
  
  	return rc;
  }
eafe87012   Steve French   [CIFS] Fix readdi...
452
453
  /* Check if directory that we are searching has changed so we can decide
     whether we can use the cached search results from the previous search */
3870253ef   Steve French   [CIFS] more white...
454
  static int is_dir_changed(struct file *file)
eafe87012   Steve French   [CIFS] Fix readdi...
455
  {
c33f8d327   Christoph Hellwig   [CIFS] Remove unn...
456
457
  	struct inode *inode = file->f_path.dentry->d_inode;
  	struct cifsInodeInfo *cifsInfo = CIFS_I(inode);
eafe87012   Steve French   [CIFS] Fix readdi...
458

c33f8d327   Christoph Hellwig   [CIFS] Remove unn...
459
  	if (cifsInfo->time == 0)
eafe87012   Steve French   [CIFS] Fix readdi...
460
461
462
463
464
  		return 1; /* directory was changed, perhaps due to unlink */
  	else
  		return 0;
  
  }
0752f1522   Steve French   [CIFS] make sure ...
465
  static int cifs_save_resume_key(const char *current_entry,
eaf35b1ea   Christoph Hellwig   cifs: use cifs_di...
466
  	struct cifsFileInfo *file_info)
0752f1522   Steve French   [CIFS] make sure ...
467
  {
eaf35b1ea   Christoph Hellwig   cifs: use cifs_di...
468
469
  	struct cifs_dirent de;
  	int rc;
0752f1522   Steve French   [CIFS] make sure ...
470

eaf35b1ea   Christoph Hellwig   cifs: use cifs_di...
471
472
473
474
475
476
  	rc = cifs_fill_dirent(&de, current_entry, file_info->srch_inf.info_level,
  			      file_info->srch_inf.unicode);
  	if (!rc) {
  		file_info->srch_inf.presume_name = de.name;
  		file_info->srch_inf.resume_name_len = de.namelen;
  		file_info->srch_inf.resume_key = de.resume_key;
0752f1522   Steve French   [CIFS] make sure ...
477
  	}
0752f1522   Steve French   [CIFS] make sure ...
478
479
  	return rc;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
480
481
482
483
484
485
  /* find the corresponding entry in the search */
  /* Note that the SMB server returns search entries for . and .. which
     complicates logic here if we choose to parse for them and we do not
     assume that they are located in the findfirst return buffer.*/
  /* We start counting in the buffer with entry 2 and increment for every
     entry (do not increment for . or .. entry) */
96daf2b09   Steve French   [CIFS] Rename thr...
486
  static int find_cifs_entry(const int xid, struct cifs_tcon *pTcon,
3870253ef   Steve French   [CIFS] more white...
487
  	struct file *file, char **ppCurrentEntry, int *num_to_ret)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
488
489
490
491
492
  {
  	int rc = 0;
  	int pos_in_buf = 0;
  	loff_t first_entry_in_buffer;
  	loff_t index_to_find = file->f_pos;
3870253ef   Steve French   [CIFS] more white...
493
  	struct cifsFileInfo *cifsFile = file->private_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
494
  	/* check if index in the buffer */
50c2f7538   Steve French   [CIFS] whitespace...
495

3870253ef   Steve French   [CIFS] more white...
496
  	if ((cifsFile == NULL) || (ppCurrentEntry == NULL) ||
eafe87012   Steve French   [CIFS] Fix readdi...
497
  	   (num_to_ret == NULL))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
498
  		return -ENOENT;
50c2f7538   Steve French   [CIFS] whitespace...
499

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
500
  	*ppCurrentEntry = NULL;
3870253ef   Steve French   [CIFS] more white...
501
502
  	first_entry_in_buffer =
  		cifsFile->srch_inf.index_of_last_entry -
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
503
  			cifsFile->srch_inf.entries_in_buffer;
60808233f   Steve French   [CIFS] Readdir fi...
504
505
506
507
508
509
  
  	/* if first entry in buf is zero then is first buffer
  	in search response data which means it is likely . and ..
  	will be in this buffer, although some servers do not return
  	. and .. for the root of a drive and for those we need
  	to start two entries earlier */
3979877e5   Steve French   [CIFS] Support fo...
510
  	dump_cifs_file_struct(file, "In fce ");
3870253ef   Steve French   [CIFS] more white...
511
512
  	if (((index_to_find < cifsFile->srch_inf.index_of_last_entry) &&
  	     is_dir_changed(file)) ||
eafe87012   Steve French   [CIFS] Fix readdi...
513
  	   (index_to_find < first_entry_in_buffer)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
514
  		/* close and restart search */
b6b38f704   Joe Perches   [CIFS] Neaten cER...
515
  		cFYI(1, "search backing up - close and restart search");
4477288a1   Jeff Layton   cifs: convert Glo...
516
  		spin_lock(&cifs_file_list_lock);
77c57ec89   Steve French   [CIFS] don't expl...
517
518
519
  		if (!cifsFile->srch_inf.endOfSearch &&
  		    !cifsFile->invalidHandle) {
  			cifsFile->invalidHandle = true;
4477288a1   Jeff Layton   cifs: convert Glo...
520
  			spin_unlock(&cifs_file_list_lock);
77c57ec89   Steve French   [CIFS] don't expl...
521
  			CIFSFindClose(xid, pTcon, cifsFile->netfid);
ddb4cbfc5   Steve French   [CIFS] Do not att...
522
  		} else
4477288a1   Jeff Layton   cifs: convert Glo...
523
  			spin_unlock(&cifs_file_list_lock);
4523cc304   Steve French   [CIFS] UID/GID ov...
524
  		if (cifsFile->srch_inf.ntwrk_buf_start) {
b6b38f704   Joe Perches   [CIFS] Neaten cER...
525
  			cFYI(1, "freeing SMB ff cache buf on search rewind");
4523cc304   Steve French   [CIFS] UID/GID ov...
526
  			if (cifsFile->srch_inf.smallBuf)
d47d7c1a8   Steve French   [CIFS] CIFS readd...
527
528
529
530
531
  				cifs_small_buf_release(cifsFile->srch_inf.
  						ntwrk_buf_start);
  			else
  				cifs_buf_release(cifsFile->srch_inf.
  						ntwrk_buf_start);
76c510ad2   Shirish Pargaonkar   [CIFS] Fix possib...
532
  			cifsFile->srch_inf.ntwrk_buf_start = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
533
  		}
3870253ef   Steve French   [CIFS] more white...
534
  		rc = initiate_cifs_search(xid, file);
4523cc304   Steve French   [CIFS] UID/GID ov...
535
  		if (rc) {
b6b38f704   Joe Perches   [CIFS] Neaten cER...
536
537
  			cFYI(1, "error %d reinitiating a search on rewind",
  				 rc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
538
539
  			return rc;
  		}
7023676f9   Jeff Layton   cifs: check for N...
540
541
542
543
  		/* FindFirst/Next set last_entry to NULL on malformed reply */
  		if (cifsFile->srch_inf.last_entry)
  			cifs_save_resume_key(cifsFile->srch_inf.last_entry,
  						cifsFile);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
544
  	}
3870253ef   Steve French   [CIFS] more white...
545
  	while ((index_to_find >= cifsFile->srch_inf.index_of_last_entry) &&
4b18f2a9c   Steve French   [CIFS] convert us...
546
  	      (rc == 0) && !cifsFile->srch_inf.endOfSearch) {
b6b38f704   Joe Perches   [CIFS] Neaten cER...
547
  		cFYI(1, "calling findnext2");
3870253ef   Steve French   [CIFS] more white...
548
  		rc = CIFSFindNext(xid, pTcon, cifsFile->netfid,
dfb7533b5   Steve French   [CIFS] Add stats ...
549
  				  &cifsFile->srch_inf);
7023676f9   Jeff Layton   cifs: check for N...
550
551
552
553
  		/* FindFirst/Next set last_entry to NULL on malformed reply */
  		if (cifsFile->srch_inf.last_entry)
  			cifs_save_resume_key(cifsFile->srch_inf.last_entry,
  						cifsFile);
4523cc304   Steve French   [CIFS] UID/GID ov...
554
  		if (rc)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
555
556
  			return -ENOENT;
  	}
4523cc304   Steve French   [CIFS] UID/GID ov...
557
  	if (index_to_find < cifsFile->srch_inf.index_of_last_entry) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
558
559
560
  		/* we found the buffer that contains the entry */
  		/* scan and find it */
  		int i;
3870253ef   Steve French   [CIFS] more white...
561
562
  		char *current_entry;
  		char *end_of_smb = cifsFile->srch_inf.ntwrk_buf_start +
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
563
564
  			smbCalcSize((struct smb_hdr *)
  				cifsFile->srch_inf.ntwrk_buf_start);
60808233f   Steve French   [CIFS] Readdir fi...
565
566
  
  		current_entry = cifsFile->srch_inf.srch_entries_start;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
567
568
569
  		first_entry_in_buffer = cifsFile->srch_inf.index_of_last_entry
  					- cifsFile->srch_inf.entries_in_buffer;
  		pos_in_buf = index_to_find - first_entry_in_buffer;
b6b38f704   Joe Perches   [CIFS] Neaten cER...
570
  		cFYI(1, "found entry - pos_in_buf %d", pos_in_buf);
5bafd7659   Steve French   [CIFS] Add suppor...
571

ad7a2926b   Steve French   [CIFS] reduce che...
572
  		for (i = 0; (i < (pos_in_buf)) && (current_entry != NULL); i++) {
dfb7533b5   Steve French   [CIFS] Add stats ...
573
  			/* go entry by entry figuring out which is first */
3870253ef   Steve French   [CIFS] more white...
574
  			current_entry = nxt_dir_entry(current_entry, end_of_smb,
5bafd7659   Steve French   [CIFS] Add suppor...
575
  						cifsFile->srch_inf.info_level);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
576
  		}
790fe579f   Steve French   [CIFS] more white...
577
  		if ((current_entry == NULL) && (i < pos_in_buf)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
578
  			/* BB fixme - check if we should flag this error */
b6b38f704   Joe Perches   [CIFS] Neaten cER...
579
  			cERROR(1, "reached end of buf searching for pos in buf"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
580
  			  " %d index to find %lld rc %d",
b6b38f704   Joe Perches   [CIFS] Neaten cER...
581
  			  pos_in_buf, index_to_find, rc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
582
583
584
585
  		}
  		rc = 0;
  		*ppCurrentEntry = current_entry;
  	} else {
b6b38f704   Joe Perches   [CIFS] Neaten cER...
586
  		cFYI(1, "index not in buffer - could not findnext into it");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
587
588
  		return 0;
  	}
790fe579f   Steve French   [CIFS] more white...
589
  	if (pos_in_buf >= cifsFile->srch_inf.entries_in_buffer) {
b6b38f704   Joe Perches   [CIFS] Neaten cER...
590
  		cFYI(1, "can not return entries pos_in_buf beyond last");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
591
592
593
  		*num_to_ret = 0;
  	} else
  		*num_to_ret = cifsFile->srch_inf.entries_in_buffer - pos_in_buf;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
594
595
596
  
  	return rc;
  }
9feed6f8f   Christoph Hellwig   cifs: cleanup cif...
597
598
  static int cifs_filldir(char *find_entry, struct file *file, filldir_t filldir,
  		void *dirent, char *scratch_buf, unsigned int max_len)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
599
  {
9feed6f8f   Christoph Hellwig   cifs: cleanup cif...
600
601
602
  	struct cifsFileInfo *file_info = file->private_data;
  	struct super_block *sb = file->f_path.dentry->d_sb;
  	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
cda0ec6a8   Christoph Hellwig   cifs: introduce c...
603
  	struct cifs_dirent de = { NULL, };
cc0bad755   Jeff Layton   cifs: add new cif...
604
  	struct cifs_fattr fattr;
9feed6f8f   Christoph Hellwig   cifs: cleanup cif...
605
606
  	struct dentry *dentry;
  	struct qstr name;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
607
  	int rc = 0;
9feed6f8f   Christoph Hellwig   cifs: cleanup cif...
608
  	ino_t ino;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
609

cda0ec6a8   Christoph Hellwig   cifs: introduce c...
610
611
612
613
  	rc = cifs_fill_dirent(&de, find_entry, file_info->srch_inf.info_level,
  			      file_info->srch_inf.unicode);
  	if (rc)
  		return rc;
5bafd7659   Steve French   [CIFS] Add suppor...
614

f16d59b41   Christoph Hellwig   cifs: use cifs_di...
615
616
617
  	if (de.namelen > max_len) {
  		cERROR(1, "bad search response length %zd past smb end",
  			  de.namelen);
5bafd7659   Steve French   [CIFS] Add suppor...
618
619
  		return -EINVAL;
  	}
60808233f   Steve French   [CIFS] Readdir fi...
620
  	/* skip . and .. since we added them first */
cda0ec6a8   Christoph Hellwig   cifs: introduce c...
621
  	if (cifs_entry_is_dot(&de, file_info->srch_inf.unicode))
60808233f   Steve French   [CIFS] Readdir fi...
622
  		return 0;
f16d59b41   Christoph Hellwig   cifs: use cifs_di...
623
624
  	if (file_info->srch_inf.unicode) {
  		struct nls_table *nlt = cifs_sb->local_nls;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
625

f16d59b41   Christoph Hellwig   cifs: use cifs_di...
626
627
628
629
630
631
632
633
634
635
636
637
  		name.name = scratch_buf;
  		name.len =
  			cifs_from_ucs2((char *)name.name, (__le16 *)de.name,
  				       UNICODE_NAME_MAX,
  				       min(de.namelen, (size_t)max_len), nlt,
  				       cifs_sb->mnt_cifs_flags &
  						CIFS_MOUNT_MAP_SPECIAL_CHR);
  		name.len -= nls_nullsize(nlt);
  	} else {
  		name.name = de.name;
  		name.len = de.namelen;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
638

9feed6f8f   Christoph Hellwig   cifs: cleanup cif...
639
640
  	switch (file_info->srch_inf.info_level) {
  	case SMB_FIND_FILE_UNIX:
cc0bad755   Jeff Layton   cifs: add new cif...
641
  		cifs_unix_basic_to_fattr(&fattr,
9feed6f8f   Christoph Hellwig   cifs: cleanup cif...
642
643
644
645
646
647
648
649
650
651
652
653
654
655
  					 &((FILE_UNIX_INFO *)find_entry)->basic,
  					 cifs_sb);
  		break;
  	case SMB_FIND_FILE_INFO_STANDARD:
  		cifs_std_info_to_fattr(&fattr,
  				       (FIND_FILE_STANDARD_INFO *)find_entry,
  				       cifs_sb);
  		break;
  	default:
  		cifs_dir_info_to_fattr(&fattr,
  				       (FILE_DIRECTORY_INFO *)find_entry,
  				       cifs_sb);
  		break;
  	}
b835bebe9   Steve French   [CIFS] Fix CIFS r...
656

f16d59b41   Christoph Hellwig   cifs: use cifs_di...
657
658
  	if (de.ino && (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)) {
  		fattr.cf_uniqueid = de.ino;
ec06aedd4   Jeff Layton   cifs: clean up ha...
659
  	} else {
0b8f18e35   Jeff Layton   cifs: convert cif...
660
  		fattr.cf_uniqueid = iunique(sb, ROOT_I);
ec06aedd4   Jeff Layton   cifs: clean up ha...
661
662
  		cifs_autodisable_serverino(cifs_sb);
  	}
50c2f7538   Steve French   [CIFS] whitespace...
663

1b12b9c15   Stefan Metzmacher   cifs: use Minshal...
664
665
666
667
668
669
670
671
  	if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) &&
  	    CIFSCouldBeMFSymlink(&fattr))
  		/*
  		 * trying to get the type and mode can be slow,
  		 * so just call those regular files for now, and mark
  		 * for reval
  		 */
  		fattr.cf_flags |= CIFS_FATTR_NEED_REVAL;
0b8f18e35   Jeff Layton   cifs: convert cif...
672
  	ino = cifs_uniqueid_to_ino_t(fattr.cf_uniqueid);
9feed6f8f   Christoph Hellwig   cifs: cleanup cif...
673
  	dentry = cifs_readdir_lookup(file->f_dentry, &name, &fattr);
3870253ef   Steve French   [CIFS] more white...
674

9feed6f8f   Christoph Hellwig   cifs: cleanup cif...
675
676
  	rc = filldir(dirent, name.name, name.len, file->f_pos, ino,
  		     fattr.cf_dtype);
0b8f18e35   Jeff Layton   cifs: convert cif...
677

9feed6f8f   Christoph Hellwig   cifs: cleanup cif...
678
  	dput(dentry);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
679
680
  	return rc;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
681
682
683
684
  
  int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
  {
  	int rc = 0;
3870253ef   Steve French   [CIFS] more white...
685
  	int xid, i;
96daf2b09   Steve French   [CIFS] Rename thr...
686
  	struct cifs_tcon *pTcon;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
687
  	struct cifsFileInfo *cifsFile = NULL;
3870253ef   Steve French   [CIFS] more white...
688
  	char *current_entry;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
689
  	int num_to_fill = 0;
3870253ef   Steve French   [CIFS] more white...
690
  	char *tmp_buf = NULL;
50c2f7538   Steve French   [CIFS] whitespace...
691
  	char *end_of_smb;
18295796a   Jeff Layton   cifs: fix length ...
692
  	unsigned int max_len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
693
694
  
  	xid = GetXid();
6221ddd0f   Suresh Jayaraman   cifs: handle Find...
695
696
697
698
699
700
701
702
703
704
  	/*
  	 * Ensure FindFirst doesn't fail before doing filldir() for '.' and
  	 * '..'. Otherwise we won't be able to notify VFS in case of failure.
  	 */
  	if (file->private_data == NULL) {
  		rc = initiate_cifs_search(xid, file);
  		cFYI(1, "initiate cifs search rc %d", rc);
  		if (rc)
  			goto rddir2_exit;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
705
706
  	switch ((int) file->f_pos) {
  	case 0:
60808233f   Steve French   [CIFS] Readdir fi...
707
  		if (filldir(direntry, ".", 1, file->f_pos,
e6a002964   Josef "Jeff" Sipek   [PATCH] cifs: cha...
708
  		     file->f_path.dentry->d_inode->i_ino, DT_DIR) < 0) {
b6b38f704   Joe Perches   [CIFS] Neaten cER...
709
  			cERROR(1, "Filldir for current dir failed");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
710
711
712
  			rc = -ENOMEM;
  			break;
  		}
60808233f   Steve French   [CIFS] Readdir fi...
713
  		file->f_pos++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
714
  	case 1:
60808233f   Steve French   [CIFS] Readdir fi...
715
  		if (filldir(direntry, "..", 2, file->f_pos,
b85fd6bdc   Al Viro   don't open-code p...
716
  		     parent_ino(file->f_path.dentry), DT_DIR) < 0) {
b6b38f704   Joe Perches   [CIFS] Neaten cER...
717
  			cERROR(1, "Filldir for parent dir failed");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
718
719
720
  			rc = -ENOMEM;
  			break;
  		}
60808233f   Steve French   [CIFS] Readdir fi...
721
722
  		file->f_pos++;
  	default:
3870253ef   Steve French   [CIFS] more white...
723
724
  		/* 1) If search is active,
  			is in current search buffer?
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
725
726
  			if it before then restart search
  			if after then keep searching till find it */
790fe579f   Steve French   [CIFS] more white...
727
  		if (file->private_data == NULL) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
728
729
730
731
732
733
  			rc = -EINVAL;
  			FreeXid(xid);
  			return rc;
  		}
  		cifsFile = file->private_data;
  		if (cifsFile->srch_inf.endOfSearch) {
790fe579f   Steve French   [CIFS] more white...
734
  			if (cifsFile->srch_inf.emptyDir) {
b6b38f704   Joe Perches   [CIFS] Neaten cER...
735
  				cFYI(1, "End of search, empty dir");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
736
737
738
739
  				rc = 0;
  				break;
  			}
  		} /* else {
4b18f2a9c   Steve French   [CIFS] convert us...
740
  			cifsFile->invalidHandle = true;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
741
  			CIFSFindClose(xid, pTcon, cifsFile->netfid);
aaa9bbe03   Steve French   [CIFS] remove unu...
742
  		} */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
743

13cfb7334   Jeff Layton   cifs: have cifsFi...
744
  		pTcon = tlink_tcon(cifsFile->tlink);
3870253ef   Steve French   [CIFS] more white...
745
746
  		rc = find_cifs_entry(xid, pTcon, file,
  				&current_entry, &num_to_fill);
790fe579f   Steve French   [CIFS] more white...
747
  		if (rc) {
b6b38f704   Joe Perches   [CIFS] Neaten cER...
748
  			cFYI(1, "fce error %d", rc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
749
750
  			goto rddir2_exit;
  		} else if (current_entry != NULL) {
b6b38f704   Joe Perches   [CIFS] Neaten cER...
751
  			cFYI(1, "entry %lld found", file->f_pos);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
752
  		} else {
b6b38f704   Joe Perches   [CIFS] Neaten cER...
753
  			cFYI(1, "could not find entry");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
754
755
  			goto rddir2_exit;
  		}
b6b38f704   Joe Perches   [CIFS] Neaten cER...
756
757
  		cFYI(1, "loop through %d times filling dir for net buf %p",
  			num_to_fill, cifsFile->srch_inf.ntwrk_buf_start);
5bafd7659   Steve French   [CIFS] Add suppor...
758
759
760
  		max_len = smbCalcSize((struct smb_hdr *)
  				cifsFile->srch_inf.ntwrk_buf_start);
  		end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + max_len;
f58841666   Jeff Layton   cifs: change cifs...
761
  		tmp_buf = kmalloc(UNICODE_NAME_MAX, GFP_KERNEL);
f55fdcca6   Kulikov Vasiliy   fs: cifs: check k...
762
763
764
765
  		if (tmp_buf == NULL) {
  			rc = -ENOMEM;
  			break;
  		}
790fe579f   Steve French   [CIFS] more white...
766
767
  		for (i = 0; (i < num_to_fill) && (rc == 0); i++) {
  			if (current_entry == NULL) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
768
  				/* evaluate whether this case is an error */
b6b38f704   Joe Perches   [CIFS] Neaten cER...
769
770
  				cERROR(1, "past SMB end,  num to fill %d i %d",
  					  num_to_fill, i);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
771
772
  				break;
  			}
60808233f   Steve French   [CIFS] Readdir fi...
773
774
  			/* if buggy server returns . and .. late do
  			we want to check for that here? */
5bafd7659   Steve French   [CIFS] Add suppor...
775
776
  			rc = cifs_filldir(current_entry, file,
  					filldir, direntry, tmp_buf, max_len);
790fe579f   Steve French   [CIFS] more white...
777
  			if (rc == -EOVERFLOW) {
7ca85ba75   Steve French   [CIFS] Fix readdi...
778
779
780
  				rc = 0;
  				break;
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
781
  			file->f_pos++;
790fe579f   Steve French   [CIFS] more white...
782
  			if (file->f_pos ==
3979877e5   Steve French   [CIFS] Support fo...
783
  				cifsFile->srch_inf.index_of_last_entry) {
b6b38f704   Joe Perches   [CIFS] Neaten cER...
784
785
  				cFYI(1, "last entry in buf at pos %lld %s",
  					file->f_pos, tmp_buf);
790fe579f   Steve French   [CIFS] more white...
786
  				cifs_save_resume_key(current_entry, cifsFile);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
787
  				break;
790fe579f   Steve French   [CIFS] more white...
788
789
  			} else
  				current_entry =
5bafd7659   Steve French   [CIFS] Add suppor...
790
791
  					nxt_dir_entry(current_entry, end_of_smb,
  						cifsFile->srch_inf.info_level);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
792
793
794
795
796
797
  		}
  		kfree(tmp_buf);
  		break;
  	} /* end switch */
  
  rddir2_exit:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
798
799
800
  	FreeXid(xid);
  	return rc;
  }