Blame view

fs/cifs/readdir.c 29.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"
3d519bd12   Aurelien Aptel   cifs: plumb smb2 ...
35
  #include "smb2proto.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
36

f58841666   Jeff Layton   cifs: change cifs...
37
38
39
40
41
42
  /*
   * 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...
43
44
  #ifdef CONFIG_CIFS_DEBUG2
  static void dump_cifs_file_struct(struct file *file, char *label)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
45
  {
6dc0f87e3   Steve French   [CIFS] whitespace...
46
  	struct cifsFileInfo *cf;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
47

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

cc0bad755   Jeff Layton   cifs: add new cif...
72
  /*
eb1b3fa5c   Jeff Layton   cifs: rename cifs...
73
74
   * Attempt to preload the dcache with the results from the FIND_FIRST/NEXT
   *
cc0bad755   Jeff Layton   cifs: add new cif...
75
   * Find the dentry that matches "name". If there isn't one, create one. If it's
9e6d722f3   Nakajima Akira   cifs: make new in...
76
77
   * a negative dentry or the uniqueid or filetype(mode) changed,
   * then drop it and recreate it.
cc0bad755   Jeff Layton   cifs: add new cif...
78
   */
eb1b3fa5c   Jeff Layton   cifs: rename cifs...
79
80
  static void
  cifs_prime_dcache(struct dentry *parent, struct qstr *name,
cc0bad755   Jeff Layton   cifs: add new cif...
81
82
83
84
  		    struct cifs_fattr *fattr)
  {
  	struct dentry *dentry, *alias;
  	struct inode *inode;
fc64005c9   Al Viro   don't bother with...
85
  	struct super_block *sb = parent->d_sb;
2f2591a34   Jeff Layton   cifs: don't compa...
86
  	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
3125d2650   Al Viro   cifs: switch to -...
87
  	DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq);
cc0bad755   Jeff Layton   cifs: add new cif...
88

f96637be0   Joe Perches   [CIFS] cifs: Rena...
89
90
  	cifs_dbg(FYI, "%s: for %s
  ", __func__, name->name);
cc0bad755   Jeff Layton   cifs: add new cif...
91

4f522a247   Al Viro   d_hash_and_lookup...
92
  	dentry = d_hash_and_lookup(parent, name);
3125d2650   Al Viro   cifs: switch to -...
93
94
95
96
97
98
99
100
101
102
103
104
  	if (!dentry) {
  		/*
  		 * If we know that the inode will need to be revalidated
  		 * immediately, then don't create a new dentry for it.
  		 * We'll end up doing an on the wire call either way and
  		 * this spares us an invalidation.
  		 */
  		if (fattr->cf_flags & CIFS_FATTR_NEED_REVAL)
  			return;
  retry:
  		dentry = d_alloc_parallel(parent, name, &wq);
  	}
a1c83681d   Viresh Kumar   fs: Drop unlikely...
105
  	if (IS_ERR(dentry))
4f522a247   Al Viro   d_hash_and_lookup...
106
  		return;
3125d2650   Al Viro   cifs: switch to -...
107
  	if (!d_in_lookup(dentry)) {
2b0143b5c   David Howells   VFS: normal files...
108
  		inode = d_inode(dentry);
2f2591a34   Jeff Layton   cifs: don't compa...
109
  		if (inode) {
3125d2650   Al Viro   cifs: switch to -...
110
111
112
113
  			if (d_mountpoint(dentry)) {
  				dput(dentry);
  				return;
  			}
2f2591a34   Jeff Layton   cifs: don't compa...
114
115
116
117
118
119
120
  			/*
  			 * If we're generating inode numbers, then we don't
  			 * want to clobber the existing one with the one that
  			 * the readdir code created.
  			 */
  			if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM))
  				fattr->cf_uniqueid = CIFS_I(inode)->uniqueid;
9e6d722f3   Nakajima Akira   cifs: make new in...
121
122
123
124
125
  			/* update inode in place
  			 * if both i_ino and i_mode didn't change */
  			if (CIFS_I(inode)->uniqueid == fattr->cf_uniqueid &&
  			    (inode->i_mode & S_IFMT) ==
  			    (fattr->cf_mode & S_IFMT)) {
2f2591a34   Jeff Layton   cifs: don't compa...
126
  				cifs_fattr_to_inode(inode, fattr);
3125d2650   Al Viro   cifs: switch to -...
127
128
  				dput(dentry);
  				return;
2f2591a34   Jeff Layton   cifs: don't compa...
129
  			}
cd60042cc   Jeff Layton   cifs: always upda...
130
  		}
5542aa2fa   Eric W. Biederman   vfs: Make d_inval...
131
  		d_invalidate(dentry);
cc0bad755   Jeff Layton   cifs: add new cif...
132
  		dput(dentry);
3125d2650   Al Viro   cifs: switch to -...
133
134
135
136
137
138
139
140
141
  		goto retry;
  	} else {
  		inode = cifs_iget(sb, fattr);
  		if (!inode)
  			inode = ERR_PTR(-ENOMEM);
  		alias = d_splice_alias(inode, dentry);
  		d_lookup_done(dentry);
  		if (alias && !IS_ERR(alias))
  			dput(alias);
cc0bad755   Jeff Layton   cifs: add new cif...
142
  	}
eb1b3fa5c   Jeff Layton   cifs: rename cifs...
143
  	dput(dentry);
cc0bad755   Jeff Layton   cifs: add new cif...
144
  }
046aca3c2   Paulo Alcantara (SUSE)   cifs: Optimize re...
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
  static bool reparse_file_needs_reval(const struct cifs_fattr *fattr)
  {
  	if (!(fattr->cf_cifsattrs & ATTR_REPARSE))
  		return false;
  	/*
  	 * The DFS tags should be only intepreted by server side as per
  	 * MS-FSCC 2.1.2.1, but let's include them anyway.
  	 *
  	 * Besides, if cf_cifstag is unset (0), then we still need it to be
  	 * revalidated to know exactly what reparse point it is.
  	 */
  	switch (fattr->cf_cifstag) {
  	case IO_REPARSE_TAG_DFS:
  	case IO_REPARSE_TAG_DFSR:
  	case IO_REPARSE_TAG_SYMLINK:
  	case IO_REPARSE_TAG_NFS:
  	case 0:
  		return true;
  	}
  	return false;
  }
0b8f18e35   Jeff Layton   cifs: convert cif...
166
167
  static void
  cifs_fill_common_info(struct cifs_fattr *fattr, struct cifs_sb_info *cifs_sb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
168
  {
0b8f18e35   Jeff Layton   cifs: convert cif...
169
170
  	fattr->cf_uid = cifs_sb->mnt_uid;
  	fattr->cf_gid = cifs_sb->mnt_gid;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
171

13909d96c   Steve French   SMB3: add support...
172
173
174
175
176
177
178
179
  	/*
  	 * The IO_REPARSE_TAG_LX_ tags originally were used by WSL but they
  	 * are preferred by the Linux client in some cases since, unlike
  	 * the NFS reparse tag (or EAs), they don't require an extra query
  	 * to determine which type of special file they represent.
  	 * TODO: go through all documented  reparse tags to see if we can
  	 * reasonably map some of them to directories vs. files vs. symlinks
  	 */
0b8f18e35   Jeff Layton   cifs: convert cif...
180
181
182
  	if (fattr->cf_cifsattrs & ATTR_DIRECTORY) {
  		fattr->cf_mode = S_IFDIR | cifs_sb->mnt_dir_mode;
  		fattr->cf_dtype = DT_DIR;
13909d96c   Steve French   SMB3: add support...
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
  	} else if (fattr->cf_cifstag == IO_REPARSE_TAG_LX_SYMLINK) {
  		fattr->cf_mode |= S_IFLNK | cifs_sb->mnt_file_mode;
  		fattr->cf_dtype = DT_LNK;
  	} else if (fattr->cf_cifstag == IO_REPARSE_TAG_LX_FIFO) {
  		fattr->cf_mode |= S_IFIFO | cifs_sb->mnt_file_mode;
  		fattr->cf_dtype = DT_FIFO;
  	} else if (fattr->cf_cifstag == IO_REPARSE_TAG_AF_UNIX) {
  		fattr->cf_mode |= S_IFSOCK | cifs_sb->mnt_file_mode;
  		fattr->cf_dtype = DT_SOCK;
  	} else if (fattr->cf_cifstag == IO_REPARSE_TAG_LX_CHR) {
  		fattr->cf_mode |= S_IFCHR | cifs_sb->mnt_file_mode;
  		fattr->cf_dtype = DT_CHR;
  	} else if (fattr->cf_cifstag == IO_REPARSE_TAG_LX_BLK) {
  		fattr->cf_mode |= S_IFBLK | cifs_sb->mnt_file_mode;
  		fattr->cf_dtype = DT_BLK;
  	} else { /* TODO: should we mark some other reparse points (like DFSR) as directories? */
0b8f18e35   Jeff Layton   cifs: convert cif...
199
200
  		fattr->cf_mode = S_IFREG | cifs_sb->mnt_file_mode;
  		fattr->cf_dtype = DT_REG;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
201
  	}
eb85d94bd   Pavel Shilovsky   CIFS: Fix symboli...
202
203
204
205
206
  	/*
  	 * We need to revalidate it further to make a decision about whether it
  	 * is a symbolic link, DFS referral or a reparse point with a direct
  	 * access like junctions, deduplicated files, NFS symlinks.
  	 */
046aca3c2   Paulo Alcantara (SUSE)   cifs: Optimize re...
207
  	if (reparse_file_needs_reval(fattr))
eb85d94bd   Pavel Shilovsky   CIFS: Fix symboli...
208
  		fattr->cf_flags |= CIFS_FATTR_NEED_REVAL;
74d290da4   Jim McDonough   [CIFS] Provide sa...
209
210
  	/* non-unix readdir doesn't provide nlink */
  	fattr->cf_flags |= CIFS_FATTR_UNKNOWN_NLINK;
0b8f18e35   Jeff Layton   cifs: convert cif...
211
212
  	if (fattr->cf_cifsattrs & ATTR_READONLY)
  		fattr->cf_mode &= ~S_IWUGO;
5bafd7659   Steve French   [CIFS] Add suppor...
213

ccb5c001b   Jeff Layton   cifs: ensure we r...
214
215
216
217
218
219
220
  	/*
  	 * We of course don't get ACL info in FIND_FIRST/NEXT results, so
  	 * mark it for revalidation so that "ls -l" will look right. It might
  	 * be super-slow, but if we don't do this then the ownership of files
  	 * may look wrong since the inodes may not have timed out by the time
  	 * "ls" does a stat() call on them.
  	 */
e3e056c35   Aurelien Aptel   cifs: fix mode bi...
221
222
  	if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) ||
  	    (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MODE_FROM_SID))
ccb5c001b   Jeff Layton   cifs: ensure we r...
223
  		fattr->cf_flags |= CIFS_FATTR_NEED_REVAL;
0b8f18e35   Jeff Layton   cifs: convert cif...
224
225
226
227
228
229
  	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...
230
  		} else {
4468eb3fd   Jeff Layton   on non-posix shar...
231
  			/*
0b8f18e35   Jeff Layton   cifs: convert cif...
232
233
234
  			 * 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...
235
  			 */
0b8f18e35   Jeff Layton   cifs: convert cif...
236
  			fattr->cf_flags |= CIFS_FATTR_NEED_REVAL;
4468eb3fd   Jeff Layton   on non-posix shar...
237
238
  		}
  	}
0b8f18e35   Jeff Layton   cifs: convert cif...
239
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
240

3d519bd12   Aurelien Aptel   cifs: plumb smb2 ...
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
266
267
  /* Fill a cifs_fattr struct with info from SMB_FIND_FILE_POSIX_INFO. */
  static void
  cifs_posix_to_fattr(struct cifs_fattr *fattr, struct smb2_posix_info *info,
  		    struct cifs_sb_info *cifs_sb)
  {
  	struct smb2_posix_info_parsed parsed;
  
  	posix_info_parse(info, NULL, &parsed);
  
  	memset(fattr, 0, sizeof(*fattr));
  	fattr->cf_uniqueid = le64_to_cpu(info->Inode);
  	fattr->cf_bytes = le64_to_cpu(info->AllocationSize);
  	fattr->cf_eof = le64_to_cpu(info->EndOfFile);
  
  	fattr->cf_atime = cifs_NTtimeToUnix(info->LastAccessTime);
  	fattr->cf_mtime = cifs_NTtimeToUnix(info->LastWriteTime);
  	fattr->cf_ctime = cifs_NTtimeToUnix(info->CreationTime);
  
  	fattr->cf_nlink = le32_to_cpu(info->HardLinks);
  	fattr->cf_cifsattrs = le32_to_cpu(info->DosAttributes);
  
  	/*
  	 * Since we set the inode type below we need to mask off
  	 * to avoid strange results if bits set above.
  	 * XXX: why not make server&client use the type bits?
  	 */
  	fattr->cf_mode = le32_to_cpu(info->Mode) & ~S_IFMT;
a0a3036b8   Joe Perches   cifs: Standardize...
268
269
  	cifs_dbg(FYI, "posix fattr: dev %d, reparse %d, mode %o
  ",
3d519bd12   Aurelien Aptel   cifs: plumb smb2 ...
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
  		 le32_to_cpu(info->DeviceId),
  		 le32_to_cpu(info->ReparseTag),
  		 le32_to_cpu(info->Mode));
  
  	if (fattr->cf_cifsattrs & ATTR_DIRECTORY) {
  		fattr->cf_mode |= S_IFDIR;
  		fattr->cf_dtype = DT_DIR;
  	} else {
  		/*
  		 * mark anything that is not a dir as regular
  		 * file. special files should have the REPARSE
  		 * attribute and will be marked as needing revaluation
  		 */
  		fattr->cf_mode |= S_IFREG;
  		fattr->cf_dtype = DT_REG;
  	}
  
  	if (reparse_file_needs_reval(fattr))
  		fattr->cf_flags |= CIFS_FATTR_NEED_REVAL;
9934430e2   Steve French   SMB3.1.1: Fix ids...
289
290
  	sid_to_id(cifs_sb, &parsed.owner, fattr, SIDOWNER);
  	sid_to_id(cifs_sb, &parsed.group, fattr, SIDGROUP);
3d519bd12   Aurelien Aptel   cifs: plumb smb2 ...
291
  }
046aca3c2   Paulo Alcantara (SUSE)   cifs: Optimize re...
292
293
294
295
296
297
298
299
300
301
302
303
304
  static void __dir_info_to_fattr(struct cifs_fattr *fattr, const void *info)
  {
  	const FILE_DIRECTORY_INFO *fi = info;
  
  	memset(fattr, 0, sizeof(*fattr));
  	fattr->cf_cifsattrs = le32_to_cpu(fi->ExtFileAttributes);
  	fattr->cf_eof = le64_to_cpu(fi->EndOfFile);
  	fattr->cf_bytes = le64_to_cpu(fi->AllocationSize);
  	fattr->cf_createtime = le64_to_cpu(fi->CreationTime);
  	fattr->cf_atime = cifs_NTtimeToUnix(fi->LastAccessTime);
  	fattr->cf_ctime = cifs_NTtimeToUnix(fi->ChangeTime);
  	fattr->cf_mtime = cifs_NTtimeToUnix(fi->LastWriteTime);
  }
c052e2b42   Shirish Pargaonkar   cifs: obtain file...
305
  void
0b8f18e35   Jeff Layton   cifs: convert cif...
306
307
308
  cifs_dir_info_to_fattr(struct cifs_fattr *fattr, FILE_DIRECTORY_INFO *info,
  		       struct cifs_sb_info *cifs_sb)
  {
046aca3c2   Paulo Alcantara (SUSE)   cifs: Optimize re...
309
310
311
  	__dir_info_to_fattr(fattr, info);
  	cifs_fill_common_info(fattr, cifs_sb);
  }
0b8f18e35   Jeff Layton   cifs: convert cif...
312

046aca3c2   Paulo Alcantara (SUSE)   cifs: Optimize re...
313
314
315
316
317
318
319
320
321
  static void cifs_fulldir_info_to_fattr(struct cifs_fattr *fattr,
  				       SEARCH_ID_FULL_DIR_INFO *info,
  				       struct cifs_sb_info *cifs_sb)
  {
  	__dir_info_to_fattr(fattr, info);
  
  	/* See MS-FSCC 2.4.18 FileIdFullDirectoryInformation */
  	if (fattr->cf_cifsattrs & ATTR_REPARSE)
  		fattr->cf_cifstag = le32_to_cpu(info->EaSize);
0b8f18e35   Jeff Layton   cifs: convert cif...
322
323
  	cifs_fill_common_info(fattr, cifs_sb);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
324

15dd47810   Steve French   [CIFS] Remove bui...
325
  static void
0b8f18e35   Jeff Layton   cifs: convert cif...
326
327
328
  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...
329
  	int offset = cifs_sb_master_tcon(cifs_sb)->ses->server->timeAdj;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
330

0b8f18e35   Jeff Layton   cifs: convert cif...
331
332
333
334
335
336
337
338
339
340
341
342
343
  	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
344
  }
0e0d2cf32   Steve French   [CIFS] Remove spa...
345
346
347
348
349
  /* 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,
6d5786a34   Pavel Shilovsky   CIFS: Rename Get/...
350
  			     unsigned int xid)
0e0d2cf32   Steve French   [CIFS] Remove spa...
351
352
353
354
355
  {
  	__u16 fid;
  	int len;
  	int oplock = 0;
  	int rc;
96daf2b09   Steve French   [CIFS] Rename thr...
356
  	struct cifs_tcon *ptcon = cifs_sb_tcon(cifs_sb);
0e0d2cf32   Steve French   [CIFS] Remove spa...
357
358
359
360
361
  	char *tmpbuffer;
  
  	rc = CIFSSMBOpen(xid, ptcon, full_path, FILE_OPEN, GENERIC_READ,
  			OPEN_REPARSE_POINT, &fid, &oplock, NULL,
  			cifs_sb->local_nls,
2baa26825   Steve French   Remap reserved po...
362
  			cifs_remap(cifs_sb);
0e0d2cf32   Steve French   [CIFS] Remove spa...
363
364
365
366
367
368
369
370
  	if (!rc) {
  		tmpbuffer = kmalloc(maxpath);
  		rc = CIFSSMBQueryReparseLinkInfo(xid, ptcon, full_path,
  				tmpbuffer,
  				maxpath -1,
  				fid,
  				cifs_sb->local_nls);
  		if (CIFSSMBClose(xid, ptcon, fid)) {
f96637be0   Joe Perches   [CIFS] cifs: Rena...
371
372
  			cifs_dbg(FYI, "Error closing temporary reparsepoint open
  ");
0e0d2cf32   Steve French   [CIFS] Remove spa...
373
374
375
376
  		}
  	}
  }
   */
92fc65a74   Pavel Shilovsky   CIFS: Move readdi...
377
  static int
d1542cf61   Ronnie Sahlberg   cifs: compute ful...
378
379
  initiate_cifs_search(const unsigned int xid, struct file *file,
  		     char *full_path)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
380
  {
2608bee74   Shirish Pargaonkar   cifs: Include bac...
381
  	__u16 search_flags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
382
  	int rc = 0;
3870253ef   Steve French   [CIFS] more white...
383
  	struct cifsFileInfo *cifsFile;
7119e220a   Al Viro   cifs: get rid of ...
384
  	struct cifs_sb_info *cifs_sb = CIFS_FILE_SB(file);
59c55ba1f   Jeff Layton   cifs: don't take ...
385
  	struct tcon_link *tlink = NULL;
29e20f9c6   Pavel Shilovsky   CIFS: Make CAP_* ...
386
  	struct cifs_tcon *tcon;
92fc65a74   Pavel Shilovsky   CIFS: Move readdi...
387
  	struct TCP_Server_Info *server;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
388

7ffec3724   Jeff Layton   cifs: add refcoun...
389
  	if (file->private_data == NULL) {
59c55ba1f   Jeff Layton   cifs: don't take ...
390
391
392
393
394
395
396
397
398
  		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;
  		}
81ddd8c0c   Rabin Vincent   cifs: initialize ...
399
  		spin_lock_init(&cifsFile->file_info_lock);
59c55ba1f   Jeff Layton   cifs: don't take ...
400
401
  		file->private_data = cifsFile;
  		cifsFile->tlink = cifs_get_tlink(tlink);
29e20f9c6   Pavel Shilovsky   CIFS: Make CAP_* ...
402
  		tcon = tlink_tcon(tlink);
59c55ba1f   Jeff Layton   cifs: don't take ...
403
404
  	} else {
  		cifsFile = file->private_data;
29e20f9c6   Pavel Shilovsky   CIFS: Make CAP_* ...
405
  		tcon = tlink_tcon(cifsFile->tlink);
7ffec3724   Jeff Layton   cifs: add refcoun...
406
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
407

92fc65a74   Pavel Shilovsky   CIFS: Move readdi...
408
409
410
411
412
413
  	server = tcon->ses->server;
  
  	if (!server->ops->query_dir_first) {
  		rc = -ENOSYS;
  		goto error_exit;
  	}
4b18f2a9c   Steve French   [CIFS] convert us...
414
415
  	cifsFile->invalidHandle = true;
  	cifsFile->srch_inf.endOfSearch = false;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
416

f96637be0   Joe Perches   [CIFS] cifs: Rena...
417
418
  	cifs_dbg(FYI, "Full path: %s start at: %lld
  ", full_path, file->f_pos);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
419

75cf6bdc5   Steve French   [PATCH] cifs: Gra...
420
  ffirst_retry:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
421
  	/* test for Unix extensions */
c18c842b1   Steve French   [CIFS] Allow disa...
422
  	/* but now check for them on the share/mount not on the SMB session */
29e20f9c6   Pavel Shilovsky   CIFS: Make CAP_* ...
423
424
  	/* if (cap_unix(tcon->ses) { */
  	if (tcon->unix_ext)
5bafd7659   Steve French   [CIFS] Add suppor...
425
  		cifsFile->srch_inf.info_level = SMB_FIND_FILE_UNIX;
3d519bd12   Aurelien Aptel   cifs: plumb smb2 ...
426
427
  	else if (tcon->posix_extensions)
  		cifsFile->srch_inf.info_level = SMB_FIND_FILE_POSIX_INFO;
29e20f9c6   Pavel Shilovsky   CIFS: Make CAP_* ...
428
429
  	else if ((tcon->ses->capabilities &
  		  tcon->ses->server->vals->cap_nt_find) == 0) {
5bafd7659   Steve French   [CIFS] Add suppor...
430
  		cifsFile->srch_inf.info_level = SMB_FIND_FILE_INFO_STANDARD;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
431
432
433
434
435
  	} 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;
  	}
2608bee74   Shirish Pargaonkar   cifs: Include bac...
436
437
438
  	search_flags = CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME;
  	if (backup_cred(cifs_sb))
  		search_flags |= CIFS_SEARCH_BACKUP_SEARCH;
92fc65a74   Pavel Shilovsky   CIFS: Move readdi...
439
440
441
  	rc = server->ops->query_dir_first(xid, tcon, full_path, cifs_sb,
  					  &cifsFile->fid, search_flags,
  					  &cifsFile->srch_inf);
4523cc304   Steve French   [CIFS] UID/GID ov...
442
  	if (rc == 0)
4b18f2a9c   Steve French   [CIFS] convert us...
443
  		cifsFile->invalidHandle = false;
e836f015b   Steve French   [CIFS] Remove tra...
444
  	/* BB add following call to handle readdir on new NTFS symlink errors
0e0d2cf32   Steve French   [CIFS] Remove spa...
445
446
447
  	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...
448
449
450
451
  		(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...
452
  error_exit:
7ffec3724   Jeff Layton   cifs: add refcoun...
453
  	cifs_put_tlink(tlink);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
454
455
456
457
  	return rc;
  }
  
  /* return length of unicode string in bytes */
cda0ec6a8   Christoph Hellwig   cifs: introduce c...
458
  static int cifs_unicode_bytelen(const char *str)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
459
460
  {
  	int len;
cda0ec6a8   Christoph Hellwig   cifs: introduce c...
461
  	const __le16 *ustr = (const __le16 *)str;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
462

3870253ef   Steve French   [CIFS] more white...
463
  	for (len = 0; len <= PATH_MAX; len++) {
4523cc304   Steve French   [CIFS] UID/GID ov...
464
  		if (ustr[len] == 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
465
466
  			return len << 1;
  	}
f96637be0   Joe Perches   [CIFS] cifs: Rena...
467
468
  	cifs_dbg(FYI, "Unicode string longer than PATH_MAX found
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
469
470
  	return len << 1;
  }
5bafd7659   Steve French   [CIFS] Add suppor...
471
  static char *nxt_dir_entry(char *old_entry, char *end_of_smb, int level)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
472
  {
3870253ef   Steve French   [CIFS] more white...
473
  	char *new_entry;
ad7a2926b   Steve French   [CIFS] reduce che...
474
  	FILE_DIRECTORY_INFO *pDirInfo = (FILE_DIRECTORY_INFO *)old_entry;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
475

4523cc304   Steve French   [CIFS] UID/GID ov...
476
  	if (level == SMB_FIND_FILE_INFO_STANDARD) {
ad7a2926b   Steve French   [CIFS] reduce che...
477
  		FIND_FILE_STANDARD_INFO *pfData;
5bafd7659   Steve French   [CIFS] Add suppor...
478
479
480
481
  		pfData = (FIND_FILE_STANDARD_INFO *)pDirInfo;
  
  		new_entry = old_entry + sizeof(FIND_FILE_STANDARD_INFO) +
  				pfData->FileNameLength;
8ad8aa353   Dan Carpenter   cifs: prevent int...
482
483
484
485
  	} else {
  		u32 next_offset = le32_to_cpu(pDirInfo->NextEntryOffset);
  
  		if (old_entry + next_offset < old_entry) {
a0a3036b8   Joe Perches   cifs: Standardize...
486
487
  			cifs_dbg(VFS, "Invalid offset %u
  ", next_offset);
8ad8aa353   Dan Carpenter   cifs: prevent int...
488
489
490
491
  			return NULL;
  		}
  		new_entry = old_entry + next_offset;
  	}
f96637be0   Joe Perches   [CIFS] cifs: Rena...
492
493
  	cifs_dbg(FYI, "new entry %p old entry %p
  ", new_entry, old_entry);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
494
  	/* validate that new_entry is not past end of SMB */
4523cc304   Steve French   [CIFS] UID/GID ov...
495
  	if (new_entry >= end_of_smb) {
f96637be0   Joe Perches   [CIFS] cifs: Rena...
496
497
498
  		cifs_dbg(VFS, "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
499
  		return NULL;
4523cc304   Steve French   [CIFS] UID/GID ov...
500
  	} else if (((level == SMB_FIND_FILE_INFO_STANDARD) &&
3870253ef   Steve French   [CIFS] more white...
501
502
  		    (new_entry + sizeof(FIND_FILE_STANDARD_INFO) > end_of_smb))
  		  || ((level != SMB_FIND_FILE_INFO_STANDARD) &&
5bafd7659   Steve French   [CIFS] Add suppor...
503
  		   (new_entry + sizeof(FILE_DIRECTORY_INFO) > end_of_smb)))  {
f96637be0   Joe Perches   [CIFS] cifs: Rena...
504
505
506
  		cifs_dbg(VFS, "search entry %p extends after end of SMB %p
  ",
  			 new_entry, end_of_smb);
09d1db5c6   Steve French   [PATCH] cifs: imp...
507
  		return NULL;
3870253ef   Steve French   [CIFS] more white...
508
  	} else
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
509
510
511
  		return new_entry;
  
  }
cda0ec6a8   Christoph Hellwig   cifs: introduce c...
512
513
514
515
516
517
  struct cifs_dirent {
  	const char	*name;
  	size_t		namelen;
  	u32		resume_key;
  	u64		ino;
  };
3d519bd12   Aurelien Aptel   cifs: plumb smb2 ...
518
519
520
521
522
523
524
  static void cifs_fill_dirent_posix(struct cifs_dirent *de,
  				   const struct smb2_posix_info *info)
  {
  	struct smb2_posix_info_parsed parsed;
  
  	/* payload should have already been checked at this point */
  	if (posix_info_parse(info, NULL, &parsed) < 0) {
a0a3036b8   Joe Perches   cifs: Standardize...
525
526
  		cifs_dbg(VFS, "Invalid POSIX info payload
  ");
3d519bd12   Aurelien Aptel   cifs: plumb smb2 ...
527
528
529
530
531
532
533
534
  		return;
  	}
  
  	de->name = parsed.name;
  	de->namelen = parsed.name_len;
  	de->resume_key = info->Ignored;
  	de->ino = le64_to_cpu(info->Inode);
  }
cda0ec6a8   Christoph Hellwig   cifs: introduce c...
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
  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) {
3d519bd12   Aurelien Aptel   cifs: plumb smb2 ...
595
596
597
  	case SMB_FIND_FILE_POSIX_INFO:
  		cifs_fill_dirent_posix(de, info);
  		break;
cda0ec6a8   Christoph Hellwig   cifs: introduce c...
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
  	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:
f96637be0   Joe Perches   [CIFS] cifs: Rena...
617
618
  		cifs_dbg(FYI, "Unknown findfirst level %d
  ", level);
cda0ec6a8   Christoph Hellwig   cifs: introduce c...
619
620
621
622
623
  		return -EINVAL;
  	}
  
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
624
625
626
  #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...
627
  static int cifs_entry_is_dot(struct cifs_dirent *de, bool is_unicode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
628
629
  {
  	int rc = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
630

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

cda0ec6a8   Christoph Hellwig   cifs: introduce c...
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
  	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
653
654
655
656
657
  		}
  	}
  
  	return rc;
  }
eafe87012   Steve French   [CIFS] Fix readdi...
658
659
  /* 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...
660
  static int is_dir_changed(struct file *file)
eafe87012   Steve French   [CIFS] Fix readdi...
661
  {
496ad9aa8   Al Viro   new helper: file_...
662
  	struct inode *inode = file_inode(file);
c33f8d327   Christoph Hellwig   [CIFS] Remove unn...
663
  	struct cifsInodeInfo *cifsInfo = CIFS_I(inode);
eafe87012   Steve French   [CIFS] Fix readdi...
664

c33f8d327   Christoph Hellwig   [CIFS] Remove unn...
665
  	if (cifsInfo->time == 0)
eafe87012   Steve French   [CIFS] Fix readdi...
666
667
668
669
670
  		return 1; /* directory was changed, perhaps due to unlink */
  	else
  		return 0;
  
  }
0752f1522   Steve French   [CIFS] make sure ...
671
  static int cifs_save_resume_key(const char *current_entry,
eaf35b1ea   Christoph Hellwig   cifs: use cifs_di...
672
  	struct cifsFileInfo *file_info)
0752f1522   Steve French   [CIFS] make sure ...
673
  {
eaf35b1ea   Christoph Hellwig   cifs: use cifs_di...
674
675
  	struct cifs_dirent de;
  	int rc;
0752f1522   Steve French   [CIFS] make sure ...
676

eaf35b1ea   Christoph Hellwig   cifs: use cifs_di...
677
678
679
680
681
682
  	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 ...
683
  	}
0752f1522   Steve French   [CIFS] make sure ...
684
685
  	return rc;
  }
92fc65a74   Pavel Shilovsky   CIFS: Move readdi...
686
687
688
689
690
691
692
693
  /*
   * 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).
   */
  static int
be4ccdcc2   Al Viro   [readdir] convert...
694
  find_cifs_entry(const unsigned int xid, struct cifs_tcon *tcon, loff_t pos,
d1542cf61   Ronnie Sahlberg   cifs: compute ful...
695
696
  		struct file *file, char *full_path,
  		char **current_entry, int *num_to_ret)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
697
  {
2608bee74   Shirish Pargaonkar   cifs: Include bac...
698
  	__u16 search_flags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
699
700
701
  	int rc = 0;
  	int pos_in_buf = 0;
  	loff_t first_entry_in_buffer;
be4ccdcc2   Al Viro   [readdir] convert...
702
  	loff_t index_to_find = pos;
92fc65a74   Pavel Shilovsky   CIFS: Move readdi...
703
  	struct cifsFileInfo *cfile = file->private_data;
7119e220a   Al Viro   cifs: get rid of ...
704
  	struct cifs_sb_info *cifs_sb = CIFS_FILE_SB(file);
92fc65a74   Pavel Shilovsky   CIFS: Move readdi...
705
  	struct TCP_Server_Info *server = tcon->ses->server;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
706
  	/* check if index in the buffer */
50c2f7538   Steve French   [CIFS] whitespace...
707

92fc65a74   Pavel Shilovsky   CIFS: Move readdi...
708
709
710
711
  	if (!server->ops->query_dir_first || !server->ops->query_dir_next)
  		return -ENOSYS;
  
  	if ((cfile == NULL) || (current_entry == NULL) || (num_to_ret == NULL))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
712
  		return -ENOENT;
50c2f7538   Steve French   [CIFS] whitespace...
713

92fc65a74   Pavel Shilovsky   CIFS: Move readdi...
714
715
716
  	*current_entry = NULL;
  	first_entry_in_buffer = cfile->srch_inf.index_of_last_entry -
  					cfile->srch_inf.entries_in_buffer;
60808233f   Steve French   [CIFS] Readdir fi...
717

92fc65a74   Pavel Shilovsky   CIFS: Move readdi...
718
719
720
721
722
723
724
  	/*
  	 * 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.
  	 */
60808233f   Steve French   [CIFS] Readdir fi...
725

3979877e5   Steve French   [CIFS] Support fo...
726
  	dump_cifs_file_struct(file, "In fce ");
92fc65a74   Pavel Shilovsky   CIFS: Move readdi...
727
728
  	if (((index_to_find < cfile->srch_inf.index_of_last_entry) &&
  	     is_dir_changed(file)) || (index_to_find < first_entry_in_buffer)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
729
  		/* close and restart search */
f96637be0   Joe Perches   [CIFS] cifs: Rena...
730
731
  		cifs_dbg(FYI, "search backing up - close and restart search
  ");
3afca265b   Steve French   Clarify locking o...
732
  		spin_lock(&cfile->file_info_lock);
52755808d   Pavel Shilovsky   CIFS: Fix SMB2 re...
733
  		if (server->ops->dir_needs_close(cfile)) {
92fc65a74   Pavel Shilovsky   CIFS: Move readdi...
734
  			cfile->invalidHandle = true;
3afca265b   Steve French   Clarify locking o...
735
  			spin_unlock(&cfile->file_info_lock);
f736906a7   Pavel Shilovsky   CIFS: Fix wrong r...
736
737
  			if (server->ops->close_dir)
  				server->ops->close_dir(xid, tcon, &cfile->fid);
ddb4cbfc5   Steve French   [CIFS] Do not att...
738
  		} else
3afca265b   Steve French   Clarify locking o...
739
  			spin_unlock(&cfile->file_info_lock);
92fc65a74   Pavel Shilovsky   CIFS: Move readdi...
740
  		if (cfile->srch_inf.ntwrk_buf_start) {
f96637be0   Joe Perches   [CIFS] cifs: Rena...
741
742
  			cifs_dbg(FYI, "freeing SMB ff cache buf on search rewind
  ");
92fc65a74   Pavel Shilovsky   CIFS: Move readdi...
743
744
  			if (cfile->srch_inf.smallBuf)
  				cifs_small_buf_release(cfile->srch_inf.
d47d7c1a8   Steve French   [CIFS] CIFS readd...
745
746
  						ntwrk_buf_start);
  			else
92fc65a74   Pavel Shilovsky   CIFS: Move readdi...
747
  				cifs_buf_release(cfile->srch_inf.
d47d7c1a8   Steve French   [CIFS] CIFS readd...
748
  						ntwrk_buf_start);
92fc65a74   Pavel Shilovsky   CIFS: Move readdi...
749
  			cfile->srch_inf.ntwrk_buf_start = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
750
  		}
d1542cf61   Ronnie Sahlberg   cifs: compute ful...
751
  		rc = initiate_cifs_search(xid, file, full_path);
4523cc304   Steve French   [CIFS] UID/GID ov...
752
  		if (rc) {
f96637be0   Joe Perches   [CIFS] cifs: Rena...
753
754
  			cifs_dbg(FYI, "error %d reinitiating a search on rewind
  ",
b6b38f704   Joe Perches   [CIFS] Neaten cER...
755
  				 rc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
756
757
  			return rc;
  		}
7023676f9   Jeff Layton   cifs: check for N...
758
  		/* FindFirst/Next set last_entry to NULL on malformed reply */
92fc65a74   Pavel Shilovsky   CIFS: Move readdi...
759
760
  		if (cfile->srch_inf.last_entry)
  			cifs_save_resume_key(cfile->srch_inf.last_entry, cfile);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
761
  	}
2608bee74   Shirish Pargaonkar   cifs: Include bac...
762
763
764
  	search_flags = CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME;
  	if (backup_cred(cifs_sb))
  		search_flags |= CIFS_SEARCH_BACKUP_SEARCH;
92fc65a74   Pavel Shilovsky   CIFS: Move readdi...
765
766
  	while ((index_to_find >= cfile->srch_inf.index_of_last_entry) &&
  	       (rc == 0) && !cfile->srch_inf.endOfSearch) {
f96637be0   Joe Perches   [CIFS] cifs: Rena...
767
768
  		cifs_dbg(FYI, "calling findnext2
  ");
92fc65a74   Pavel Shilovsky   CIFS: Move readdi...
769
770
771
  		rc = server->ops->query_dir_next(xid, tcon, &cfile->fid,
  						 search_flags,
  						 &cfile->srch_inf);
7023676f9   Jeff Layton   cifs: check for N...
772
  		/* FindFirst/Next set last_entry to NULL on malformed reply */
92fc65a74   Pavel Shilovsky   CIFS: Move readdi...
773
774
  		if (cfile->srch_inf.last_entry)
  			cifs_save_resume_key(cfile->srch_inf.last_entry, cfile);
4523cc304   Steve French   [CIFS] UID/GID ov...
775
  		if (rc)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
776
777
  			return -ENOENT;
  	}
92fc65a74   Pavel Shilovsky   CIFS: Move readdi...
778
  	if (index_to_find < cfile->srch_inf.index_of_last_entry) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
779
780
781
  		/* we found the buffer that contains the entry */
  		/* scan and find it */
  		int i;
92fc65a74   Pavel Shilovsky   CIFS: Move readdi...
782
  		char *cur_ent;
59a63e479   Ronnie Sahlberg   cifs: check ntwrk...
783
784
785
786
787
788
789
790
791
  		char *end_of_smb;
  
  		if (cfile->srch_inf.ntwrk_buf_start == NULL) {
  			cifs_dbg(VFS, "ntwrk_buf_start is NULL during readdir
  ");
  			return -EIO;
  		}
  
  		end_of_smb = cfile->srch_inf.ntwrk_buf_start +
92fc65a74   Pavel Shilovsky   CIFS: Move readdi...
792
  			server->ops->calc_smb_size(
9ec672bd1   Ronnie Sahlberg   cifs: update calc...
793
794
  					cfile->srch_inf.ntwrk_buf_start,
  					server);
92fc65a74   Pavel Shilovsky   CIFS: Move readdi...
795
796
797
798
  
  		cur_ent = cfile->srch_inf.srch_entries_start;
  		first_entry_in_buffer = cfile->srch_inf.index_of_last_entry
  					- cfile->srch_inf.entries_in_buffer;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
799
  		pos_in_buf = index_to_find - first_entry_in_buffer;
f96637be0   Joe Perches   [CIFS] cifs: Rena...
800
801
  		cifs_dbg(FYI, "found entry - pos_in_buf %d
  ", pos_in_buf);
5bafd7659   Steve French   [CIFS] Add suppor...
802

92fc65a74   Pavel Shilovsky   CIFS: Move readdi...
803
  		for (i = 0; (i < (pos_in_buf)) && (cur_ent != NULL); i++) {
dfb7533b5   Steve French   [CIFS] Add stats ...
804
  			/* go entry by entry figuring out which is first */
92fc65a74   Pavel Shilovsky   CIFS: Move readdi...
805
806
  			cur_ent = nxt_dir_entry(cur_ent, end_of_smb,
  						cfile->srch_inf.info_level);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
807
  		}
92fc65a74   Pavel Shilovsky   CIFS: Move readdi...
808
  		if ((cur_ent == NULL) && (i < pos_in_buf)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
809
  			/* BB fixme - check if we should flag this error */
f96637be0   Joe Perches   [CIFS] cifs: Rena...
810
811
812
  			cifs_dbg(VFS, "reached end of buf searching for pos in buf %d index to find %lld rc %d
  ",
  				 pos_in_buf, index_to_find, rc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
813
814
  		}
  		rc = 0;
92fc65a74   Pavel Shilovsky   CIFS: Move readdi...
815
  		*current_entry = cur_ent;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
816
  	} else {
f96637be0   Joe Perches   [CIFS] cifs: Rena...
817
818
  		cifs_dbg(FYI, "index not in buffer - could not findnext into it
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
819
820
  		return 0;
  	}
92fc65a74   Pavel Shilovsky   CIFS: Move readdi...
821
  	if (pos_in_buf >= cfile->srch_inf.entries_in_buffer) {
f96637be0   Joe Perches   [CIFS] cifs: Rena...
822
823
  		cifs_dbg(FYI, "can not return entries pos_in_buf beyond last
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
824
825
  		*num_to_ret = 0;
  	} else
92fc65a74   Pavel Shilovsky   CIFS: Move readdi...
826
  		*num_to_ret = cfile->srch_inf.entries_in_buffer - pos_in_buf;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
827
828
829
  
  	return rc;
  }
be4ccdcc2   Al Viro   [readdir] convert...
830
831
832
  static int cifs_filldir(char *find_entry, struct file *file,
  		struct dir_context *ctx,
  		char *scratch_buf, unsigned int max_len)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
833
  {
9feed6f8f   Christoph Hellwig   cifs: cleanup cif...
834
  	struct cifsFileInfo *file_info = file->private_data;
7119e220a   Al Viro   cifs: get rid of ...
835
  	struct super_block *sb = file_inode(file)->i_sb;
9feed6f8f   Christoph Hellwig   cifs: cleanup cif...
836
  	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
cda0ec6a8   Christoph Hellwig   cifs: introduce c...
837
  	struct cifs_dirent de = { NULL, };
cc0bad755   Jeff Layton   cifs: add new cif...
838
  	struct cifs_fattr fattr;
9feed6f8f   Christoph Hellwig   cifs: cleanup cif...
839
  	struct qstr name;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
840
  	int rc = 0;
9feed6f8f   Christoph Hellwig   cifs: cleanup cif...
841
  	ino_t ino;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
842

cda0ec6a8   Christoph Hellwig   cifs: introduce c...
843
844
845
846
  	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...
847

f16d59b41   Christoph Hellwig   cifs: use cifs_di...
848
  	if (de.namelen > max_len) {
f96637be0   Joe Perches   [CIFS] cifs: Rena...
849
850
851
  		cifs_dbg(VFS, "bad search response length %zd past smb end
  ",
  			 de.namelen);
5bafd7659   Steve French   [CIFS] Add suppor...
852
853
  		return -EINVAL;
  	}
60808233f   Steve French   [CIFS] Readdir fi...
854
  	/* skip . and .. since we added them first */
cda0ec6a8   Christoph Hellwig   cifs: introduce c...
855
  	if (cifs_entry_is_dot(&de, file_info->srch_inf.unicode))
60808233f   Steve French   [CIFS] Readdir fi...
856
  		return 0;
f16d59b41   Christoph Hellwig   cifs: use cifs_di...
857
858
  	if (file_info->srch_inf.unicode) {
  		struct nls_table *nlt = cifs_sb->local_nls;
b693855fe   Steve French   Allow conversion ...
859
  		int map_type;
2baa26825   Steve French   Remap reserved po...
860
  		map_type = cifs_remap(cifs_sb);
f16d59b41   Christoph Hellwig   cifs: use cifs_di...
861
862
  		name.name = scratch_buf;
  		name.len =
acbbb76a2   Steve French   CIFS: Rename *UCS...
863
864
865
  			cifs_from_utf16((char *)name.name, (__le16 *)de.name,
  					UNICODE_NAME_MAX,
  					min_t(size_t, de.namelen,
b693855fe   Steve French   Allow conversion ...
866
  					      (size_t)max_len), nlt, map_type);
f16d59b41   Christoph Hellwig   cifs: use cifs_di...
867
868
869
870
871
  		name.len -= nls_nullsize(nlt);
  	} else {
  		name.name = de.name;
  		name.len = de.namelen;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
872

9feed6f8f   Christoph Hellwig   cifs: cleanup cif...
873
  	switch (file_info->srch_inf.info_level) {
3d519bd12   Aurelien Aptel   cifs: plumb smb2 ...
874
875
876
877
878
  	case SMB_FIND_FILE_POSIX_INFO:
  		cifs_posix_to_fattr(&fattr,
  				    (struct smb2_posix_info *)find_entry,
  				    cifs_sb);
  		break;
9feed6f8f   Christoph Hellwig   cifs: cleanup cif...
879
  	case SMB_FIND_FILE_UNIX:
cc0bad755   Jeff Layton   cifs: add new cif...
880
  		cifs_unix_basic_to_fattr(&fattr,
9feed6f8f   Christoph Hellwig   cifs: cleanup cif...
881
882
883
884
885
886
887
888
  					 &((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;
046aca3c2   Paulo Alcantara (SUSE)   cifs: Optimize re...
889
890
891
892
893
  	case SMB_FIND_FILE_ID_FULL_DIR_INFO:
  		cifs_fulldir_info_to_fattr(&fattr,
  					   (SEARCH_ID_FULL_DIR_INFO *)find_entry,
  					   cifs_sb);
  		break;
9feed6f8f   Christoph Hellwig   cifs: cleanup cif...
894
895
896
897
898
899
  	default:
  		cifs_dir_info_to_fattr(&fattr,
  				       (FILE_DIRECTORY_INFO *)find_entry,
  				       cifs_sb);
  		break;
  	}
b835bebe9   Steve French   [CIFS] Fix CIFS r...
900

f16d59b41   Christoph Hellwig   cifs: use cifs_di...
901
902
  	if (de.ino && (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)) {
  		fattr.cf_uniqueid = de.ino;
ec06aedd4   Jeff Layton   cifs: clean up ha...
903
  	} else {
0b8f18e35   Jeff Layton   cifs: convert cif...
904
  		fattr.cf_uniqueid = iunique(sb, ROOT_I);
ec06aedd4   Jeff Layton   cifs: clean up ha...
905
906
  		cifs_autodisable_serverino(cifs_sb);
  	}
50c2f7538   Steve French   [CIFS] whitespace...
907

1b12b9c15   Stefan Metzmacher   cifs: use Minshal...
908
  	if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) &&
cb084b1a9   Sachin Prabhu   cifs: Rename MF s...
909
  	    couldbe_mf_symlink(&fattr))
1b12b9c15   Stefan Metzmacher   cifs: use Minshal...
910
911
912
913
914
915
  		/*
  		 * 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;
1f1735cb7   Goldwyn Rodrigues   cifs: Use file_de...
916
  	cifs_prime_dcache(file_dentry(file), &name, &fattr);
3870253ef   Steve French   [CIFS] more white...
917

eb1b3fa5c   Jeff Layton   cifs: rename cifs...
918
  	ino = cifs_uniqueid_to_ino_t(fattr.cf_uniqueid);
be4ccdcc2   Al Viro   [readdir] convert...
919
  	return !dir_emit(ctx, name.name, name.len, ino, fattr.cf_dtype);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
920
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
921

be4ccdcc2   Al Viro   [readdir] convert...
922
  int cifs_readdir(struct file *file, struct dir_context *ctx)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
923
924
  {
  	int rc = 0;
6d5786a34   Pavel Shilovsky   CIFS: Rename Get/...
925
926
  	unsigned int xid;
  	int i;
92fc65a74   Pavel Shilovsky   CIFS: Move readdi...
927
  	struct cifs_tcon *tcon;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
928
  	struct cifsFileInfo *cifsFile = NULL;
3870253ef   Steve French   [CIFS] more white...
929
  	char *current_entry;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
930
  	int num_to_fill = 0;
3870253ef   Steve French   [CIFS] more white...
931
  	char *tmp_buf = NULL;
50c2f7538   Steve French   [CIFS] whitespace...
932
  	char *end_of_smb;
18295796a   Jeff Layton   cifs: fix length ...
933
  	unsigned int max_len;
d1542cf61   Ronnie Sahlberg   cifs: compute ful...
934
  	char *full_path = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
935

6d5786a34   Pavel Shilovsky   CIFS: Rename Get/...
936
  	xid = get_xid();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
937

d1542cf61   Ronnie Sahlberg   cifs: compute ful...
938
939
940
941
942
  	full_path = build_path_from_dentry(file_dentry(file));
  	if (full_path == NULL) {
  		rc = -ENOMEM;
  		goto rddir2_exit;
  	}
6221ddd0f   Suresh Jayaraman   cifs: handle Find...
943
944
945
946
947
  	/*
  	 * 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) {
d1542cf61   Ronnie Sahlberg   cifs: compute ful...
948
  		rc = initiate_cifs_search(xid, file, full_path);
f96637be0   Joe Perches   [CIFS] cifs: Rena...
949
950
  		cifs_dbg(FYI, "initiate cifs search rc %d
  ", rc);
6221ddd0f   Suresh Jayaraman   cifs: handle Find...
951
952
953
  		if (rc)
  			goto rddir2_exit;
  	}
be4ccdcc2   Al Viro   [readdir] convert...
954
955
  	if (!dir_emit_dots(file, ctx))
  		goto rddir2_exit;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
956

be4ccdcc2   Al Viro   [readdir] convert...
957
958
959
960
  	/* 1) If search is active,
  		is in current search buffer?
  		if it before then restart search
  		if after then keep searching till find it */
be4ccdcc2   Al Viro   [readdir] convert...
961
962
963
964
965
966
  	cifsFile = file->private_data;
  	if (cifsFile->srch_inf.endOfSearch) {
  		if (cifsFile->srch_inf.emptyDir) {
  			cifs_dbg(FYI, "End of search, empty dir
  ");
  			rc = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
967
968
  			goto rddir2_exit;
  		}
be4ccdcc2   Al Viro   [readdir] convert...
969
970
971
972
973
974
  	} /* else {
  		cifsFile->invalidHandle = true;
  		tcon->ses->server->close(xid, tcon, &cifsFile->fid);
  	} */
  
  	tcon = tlink_tcon(cifsFile->tlink);
d1542cf61   Ronnie Sahlberg   cifs: compute ful...
975
976
  	rc = find_cifs_entry(xid, tcon, ctx->pos, file, full_path,
  			     &current_entry, &num_to_fill);
be4ccdcc2   Al Viro   [readdir] convert...
977
978
979
980
981
982
983
984
  	if (rc) {
  		cifs_dbg(FYI, "fce error %d
  ", rc);
  		goto rddir2_exit;
  	} else if (current_entry != NULL) {
  		cifs_dbg(FYI, "entry %lld found
  ", ctx->pos);
  	} else {
a0a3036b8   Joe Perches   cifs: Standardize...
985
986
  		cifs_dbg(FYI, "Could not find entry
  ");
be4ccdcc2   Al Viro   [readdir] convert...
987
988
989
990
991
992
  		goto rddir2_exit;
  	}
  	cifs_dbg(FYI, "loop through %d times filling dir for net buf %p
  ",
  		 num_to_fill, cifsFile->srch_inf.ntwrk_buf_start);
  	max_len = tcon->ses->server->ops->calc_smb_size(
9ec672bd1   Ronnie Sahlberg   cifs: update calc...
993
994
  			cifsFile->srch_inf.ntwrk_buf_start,
  			tcon->ses->server);
be4ccdcc2   Al Viro   [readdir] convert...
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
  	end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + max_len;
  
  	tmp_buf = kmalloc(UNICODE_NAME_MAX, GFP_KERNEL);
  	if (tmp_buf == NULL) {
  		rc = -ENOMEM;
  		goto rddir2_exit;
  	}
  
  	for (i = 0; i < num_to_fill; i++) {
  		if (current_entry == NULL) {
  			/* evaluate whether this case is an error */
  			cifs_dbg(VFS, "past SMB end,  num to fill %d i %d
  ",
  				 num_to_fill, i);
f55fdcca6   Kulikov Vasiliy   fs: cifs: check k...
1009
1010
  			break;
  		}
be4ccdcc2   Al Viro   [readdir] convert...
1011
1012
1013
1014
  		/*
  		 * if buggy server returns . and .. late do we want to
  		 * check for that here?
  		 */
01b9b0b28   Vasily Averin   cifs_dbg() output...
1015
  		*tmp_buf = 0;
be4ccdcc2   Al Viro   [readdir] convert...
1016
1017
1018
1019
  		rc = cifs_filldir(current_entry, file, ctx,
  				  tmp_buf, max_len);
  		if (rc) {
  			if (rc > 0)
7ca85ba75   Steve French   [CIFS] Fix readdi...
1020
  				rc = 0;
be4ccdcc2   Al Viro   [readdir] convert...
1021
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1022
  		}
be4ccdcc2   Al Viro   [readdir] convert...
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
  
  		ctx->pos++;
  		if (ctx->pos ==
  			cifsFile->srch_inf.index_of_last_entry) {
  			cifs_dbg(FYI, "last entry in buf at pos %lld %s
  ",
  				 ctx->pos, tmp_buf);
  			cifs_save_resume_key(current_entry, cifsFile);
  			break;
  		} else
  			current_entry =
  				nxt_dir_entry(current_entry, end_of_smb,
  					cifsFile->srch_inf.info_level);
  	}
  	kfree(tmp_buf);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1038
1039
  
  rddir2_exit:
d1542cf61   Ronnie Sahlberg   cifs: compute ful...
1040
  	kfree(full_path);
6d5786a34   Pavel Shilovsky   CIFS: Rename Get/...
1041
  	free_xid(xid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1042
1043
  	return rc;
  }