Blame view

fs/cifs/readdir.c 24.7 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) {
f96637be0   Joe Perches   [CIFS] cifs: Rena...
49
50
  			cifs_dbg(FYI, "empty cifs private file data
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
51
52
  			return;
  		}
ad7a2926b   Steve French   [CIFS] reduce che...
53
  		if (cf->invalidHandle)
f96637be0   Joe Perches   [CIFS] cifs: Rena...
54
55
  			cifs_dbg(FYI, "invalid handle
  ");
ad7a2926b   Steve French   [CIFS] reduce che...
56
  		if (cf->srch_inf.endOfSearch)
f96637be0   Joe Perches   [CIFS] cifs: Rena...
57
58
  			cifs_dbg(FYI, "end of search
  ");
ad7a2926b   Steve French   [CIFS] reduce che...
59
  		if (cf->srch_inf.emptyDir)
f96637be0   Joe Perches   [CIFS] cifs: Rena...
60
61
  			cifs_dbg(FYI, "empty dir
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
62
  	}
3979877e5   Steve French   [CIFS] Support fo...
63
  }
90c81e0b0   Steve French   [CIFS] clean up s...
64
65
66
67
  #else
  static inline void dump_cifs_file_struct(struct file *file, char *label)
  {
  }
3979877e5   Steve French   [CIFS] Support fo...
68
  #endif /* DEBUG2 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
69

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

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

4f522a247   Al Viro   d_hash_and_lookup...
90
  	dentry = d_hash_and_lookup(parent, name);
3125d2650   Al Viro   cifs: switch to -...
91
92
93
94
95
96
97
98
99
100
101
102
  	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...
103
  	if (IS_ERR(dentry))
4f522a247   Al Viro   d_hash_and_lookup...
104
  		return;
3125d2650   Al Viro   cifs: switch to -...
105
  	if (!d_in_lookup(dentry)) {
2b0143b5c   David Howells   VFS: normal files...
106
  		inode = d_inode(dentry);
2f2591a34   Jeff Layton   cifs: don't compa...
107
  		if (inode) {
3125d2650   Al Viro   cifs: switch to -...
108
109
110
111
  			if (d_mountpoint(dentry)) {
  				dput(dentry);
  				return;
  			}
2f2591a34   Jeff Layton   cifs: don't compa...
112
113
114
115
116
117
118
  			/*
  			 * 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...
119
120
121
122
123
  			/* 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...
124
  				cifs_fattr_to_inode(inode, fattr);
3125d2650   Al Viro   cifs: switch to -...
125
126
  				dput(dentry);
  				return;
2f2591a34   Jeff Layton   cifs: don't compa...
127
  			}
cd60042cc   Jeff Layton   cifs: always upda...
128
  		}
5542aa2fa   Eric W. Biederman   vfs: Make d_inval...
129
  		d_invalidate(dentry);
cc0bad755   Jeff Layton   cifs: add new cif...
130
  		dput(dentry);
3125d2650   Al Viro   cifs: switch to -...
131
132
133
134
135
136
137
138
139
  		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...
140
  	}
eb1b3fa5c   Jeff Layton   cifs: rename cifs...
141
  	dput(dentry);
cc0bad755   Jeff Layton   cifs: add new cif...
142
  }
0b8f18e35   Jeff Layton   cifs: convert cif...
143
144
  static void
  cifs_fill_common_info(struct cifs_fattr *fattr, struct cifs_sb_info *cifs_sb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
145
  {
0b8f18e35   Jeff Layton   cifs: convert cif...
146
147
  	fattr->cf_uid = cifs_sb->mnt_uid;
  	fattr->cf_gid = cifs_sb->mnt_gid;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
148

0b8f18e35   Jeff Layton   cifs: convert cif...
149
150
151
  	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
152
  	} else {
0b8f18e35   Jeff Layton   cifs: convert cif...
153
154
  		fattr->cf_mode = S_IFREG | cifs_sb->mnt_file_mode;
  		fattr->cf_dtype = DT_REG;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
155
  	}
eb85d94bd   Pavel Shilovsky   CIFS: Fix symboli...
156
157
158
159
160
161
162
  	/*
  	 * 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.
  	 */
  	if (fattr->cf_cifsattrs & ATTR_REPARSE)
  		fattr->cf_flags |= CIFS_FATTR_NEED_REVAL;
74d290da4   Jim McDonough   [CIFS] Provide sa...
163
164
  	/* non-unix readdir doesn't provide nlink */
  	fattr->cf_flags |= CIFS_FATTR_UNKNOWN_NLINK;
0b8f18e35   Jeff Layton   cifs: convert cif...
165
166
  	if (fattr->cf_cifsattrs & ATTR_READONLY)
  		fattr->cf_mode &= ~S_IWUGO;
5bafd7659   Steve French   [CIFS] Add suppor...
167

ccb5c001b   Jeff Layton   cifs: ensure we r...
168
169
170
171
172
173
174
175
176
  	/*
  	 * 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.
  	 */
  	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL)
  		fattr->cf_flags |= CIFS_FATTR_NEED_REVAL;
0b8f18e35   Jeff Layton   cifs: convert cif...
177
178
179
180
181
182
  	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...
183
  		} else {
4468eb3fd   Jeff Layton   on non-posix shar...
184
  			/*
0b8f18e35   Jeff Layton   cifs: convert cif...
185
186
187
  			 * 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...
188
  			 */
0b8f18e35   Jeff Layton   cifs: convert cif...
189
  			fattr->cf_flags |= CIFS_FATTR_NEED_REVAL;
4468eb3fd   Jeff Layton   on non-posix shar...
190
191
  		}
  	}
0b8f18e35   Jeff Layton   cifs: convert cif...
192
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
193

c052e2b42   Shirish Pargaonkar   cifs: obtain file...
194
  void
0b8f18e35   Jeff Layton   cifs: convert cif...
195
196
197
198
199
200
201
  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...
202
  	fattr->cf_createtime = le64_to_cpu(info->CreationTime);
0b8f18e35   Jeff Layton   cifs: convert cif...
203
204
205
206
207
208
  	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
209

15dd47810   Steve French   [CIFS] Remove bui...
210
  static void
0b8f18e35   Jeff Layton   cifs: convert cif...
211
212
213
  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...
214
  	int offset = cifs_sb_master_tcon(cifs_sb)->ses->server->timeAdj;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
215

0b8f18e35   Jeff Layton   cifs: convert cif...
216
217
218
219
220
221
222
223
224
225
226
227
228
  	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
229
  }
0e0d2cf32   Steve French   [CIFS] Remove spa...
230
231
232
233
234
  /* 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/...
235
  			     unsigned int xid)
0e0d2cf32   Steve French   [CIFS] Remove spa...
236
237
238
239
240
  {
  	__u16 fid;
  	int len;
  	int oplock = 0;
  	int rc;
96daf2b09   Steve French   [CIFS] Rename thr...
241
  	struct cifs_tcon *ptcon = cifs_sb_tcon(cifs_sb);
0e0d2cf32   Steve French   [CIFS] Remove spa...
242
243
244
245
246
  	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...
247
  			cifs_remap(cifs_sb);
0e0d2cf32   Steve French   [CIFS] Remove spa...
248
249
250
251
252
253
254
255
  	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...
256
257
  			cifs_dbg(FYI, "Error closing temporary reparsepoint open
  ");
0e0d2cf32   Steve French   [CIFS] Remove spa...
258
259
260
261
  		}
  	}
  }
   */
92fc65a74   Pavel Shilovsky   CIFS: Move readdi...
262
263
  static int
  initiate_cifs_search(const unsigned int xid, struct file *file)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
264
  {
2608bee74   Shirish Pargaonkar   cifs: Include bac...
265
  	__u16 search_flags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
266
  	int rc = 0;
7ffec3724   Jeff Layton   cifs: add refcoun...
267
  	char *full_path = NULL;
3870253ef   Steve French   [CIFS] more white...
268
  	struct cifsFileInfo *cifsFile;
7119e220a   Al Viro   cifs: get rid of ...
269
  	struct cifs_sb_info *cifs_sb = CIFS_FILE_SB(file);
59c55ba1f   Jeff Layton   cifs: don't take ...
270
  	struct tcon_link *tlink = NULL;
29e20f9c6   Pavel Shilovsky   CIFS: Make CAP_* ...
271
  	struct cifs_tcon *tcon;
92fc65a74   Pavel Shilovsky   CIFS: Move readdi...
272
  	struct TCP_Server_Info *server;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
273

7ffec3724   Jeff Layton   cifs: add refcoun...
274
  	if (file->private_data == NULL) {
59c55ba1f   Jeff Layton   cifs: don't take ...
275
276
277
278
279
280
281
282
283
  		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;
  		}
9e255997c   Rabin Vincent   cifs: initialize ...
284
  		spin_lock_init(&cifsFile->file_info_lock);
59c55ba1f   Jeff Layton   cifs: don't take ...
285
286
  		file->private_data = cifsFile;
  		cifsFile->tlink = cifs_get_tlink(tlink);
29e20f9c6   Pavel Shilovsky   CIFS: Make CAP_* ...
287
  		tcon = tlink_tcon(tlink);
59c55ba1f   Jeff Layton   cifs: don't take ...
288
289
  	} else {
  		cifsFile = file->private_data;
29e20f9c6   Pavel Shilovsky   CIFS: Make CAP_* ...
290
  		tcon = tlink_tcon(cifsFile->tlink);
7ffec3724   Jeff Layton   cifs: add refcoun...
291
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
292

92fc65a74   Pavel Shilovsky   CIFS: Move readdi...
293
294
295
296
297
298
  	server = tcon->ses->server;
  
  	if (!server->ops->query_dir_first) {
  		rc = -ENOSYS;
  		goto error_exit;
  	}
4b18f2a9c   Steve French   [CIFS] convert us...
299
300
  	cifsFile->invalidHandle = true;
  	cifsFile->srch_inf.endOfSearch = false;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
301

1f1735cb7   Goldwyn Rodrigues   cifs: Use file_de...
302
  	full_path = build_path_from_dentry(file_dentry(file));
7ffec3724   Jeff Layton   cifs: add refcoun...
303
304
305
306
  	if (full_path == NULL) {
  		rc = -ENOMEM;
  		goto error_exit;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
307

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

75cf6bdc5   Steve French   [PATCH] cifs: Gra...
311
  ffirst_retry:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
312
  	/* test for Unix extensions */
c18c842b1   Steve French   [CIFS] Allow disa...
313
  	/* but now check for them on the share/mount not on the SMB session */
29e20f9c6   Pavel Shilovsky   CIFS: Make CAP_* ...
314
315
  	/* if (cap_unix(tcon->ses) { */
  	if (tcon->unix_ext)
5bafd7659   Steve French   [CIFS] Add suppor...
316
  		cifsFile->srch_inf.info_level = SMB_FIND_FILE_UNIX;
29e20f9c6   Pavel Shilovsky   CIFS: Make CAP_* ...
317
318
  	else if ((tcon->ses->capabilities &
  		  tcon->ses->server->vals->cap_nt_find) == 0) {
5bafd7659   Steve French   [CIFS] Add suppor...
319
  		cifsFile->srch_inf.info_level = SMB_FIND_FILE_INFO_STANDARD;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
320
321
322
323
324
  	} 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...
325
326
327
  	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...
328
329
330
  	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...
331
  	if (rc == 0)
4b18f2a9c   Steve French   [CIFS] convert us...
332
  		cifsFile->invalidHandle = false;
e836f015b   Steve French   [CIFS] Remove tra...
333
  	/* BB add following call to handle readdir on new NTFS symlink errors
0e0d2cf32   Steve French   [CIFS] Remove spa...
334
335
336
  	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...
337
338
339
340
  		(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...
341
  error_exit:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
342
  	kfree(full_path);
7ffec3724   Jeff Layton   cifs: add refcoun...
343
  	cifs_put_tlink(tlink);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
344
345
346
347
  	return rc;
  }
  
  /* return length of unicode string in bytes */
cda0ec6a8   Christoph Hellwig   cifs: introduce c...
348
  static int cifs_unicode_bytelen(const char *str)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
349
350
  {
  	int len;
cda0ec6a8   Christoph Hellwig   cifs: introduce c...
351
  	const __le16 *ustr = (const __le16 *)str;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
352

3870253ef   Steve French   [CIFS] more white...
353
  	for (len = 0; len <= PATH_MAX; len++) {
4523cc304   Steve French   [CIFS] UID/GID ov...
354
  		if (ustr[len] == 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
355
356
  			return len << 1;
  	}
f96637be0   Joe Perches   [CIFS] cifs: Rena...
357
358
  	cifs_dbg(FYI, "Unicode string longer than PATH_MAX found
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
359
360
  	return len << 1;
  }
5bafd7659   Steve French   [CIFS] Add suppor...
361
  static char *nxt_dir_entry(char *old_entry, char *end_of_smb, int level)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
362
  {
3870253ef   Steve French   [CIFS] more white...
363
  	char *new_entry;
ad7a2926b   Steve French   [CIFS] reduce che...
364
  	FILE_DIRECTORY_INFO *pDirInfo = (FILE_DIRECTORY_INFO *)old_entry;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
365

4523cc304   Steve French   [CIFS] UID/GID ov...
366
  	if (level == SMB_FIND_FILE_INFO_STANDARD) {
ad7a2926b   Steve French   [CIFS] reduce che...
367
  		FIND_FILE_STANDARD_INFO *pfData;
5bafd7659   Steve French   [CIFS] Add suppor...
368
369
370
371
372
373
  		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);
f96637be0   Joe Perches   [CIFS] cifs: Rena...
374
375
  	cifs_dbg(FYI, "new entry %p old entry %p
  ", new_entry, old_entry);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
376
  	/* validate that new_entry is not past end of SMB */
4523cc304   Steve French   [CIFS] UID/GID ov...
377
  	if (new_entry >= end_of_smb) {
f96637be0   Joe Perches   [CIFS] cifs: Rena...
378
379
380
  		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
381
  		return NULL;
4523cc304   Steve French   [CIFS] UID/GID ov...
382
  	} else if (((level == SMB_FIND_FILE_INFO_STANDARD) &&
3870253ef   Steve French   [CIFS] more white...
383
384
  		    (new_entry + sizeof(FIND_FILE_STANDARD_INFO) > end_of_smb))
  		  || ((level != SMB_FIND_FILE_INFO_STANDARD) &&
5bafd7659   Steve French   [CIFS] Add suppor...
385
  		   (new_entry + sizeof(FILE_DIRECTORY_INFO) > end_of_smb)))  {
f96637be0   Joe Perches   [CIFS] cifs: Rena...
386
387
388
  		cifs_dbg(VFS, "search entry %p extends after end of SMB %p
  ",
  			 new_entry, end_of_smb);
09d1db5c6   Steve French   [PATCH] cifs: imp...
389
  		return NULL;
3870253ef   Steve French   [CIFS] more white...
390
  	} else
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
391
392
393
  		return new_entry;
  
  }
cda0ec6a8   Christoph Hellwig   cifs: introduce c...
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
  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:
f96637be0   Joe Perches   [CIFS] cifs: Rena...
480
481
  		cifs_dbg(FYI, "Unknown findfirst level %d
  ", level);
cda0ec6a8   Christoph Hellwig   cifs: introduce c...
482
483
484
485
486
  		return -EINVAL;
  	}
  
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
487
488
489
  #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...
490
  static int cifs_entry_is_dot(struct cifs_dirent *de, bool is_unicode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
491
492
  {
  	int rc = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
493

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

cda0ec6a8   Christoph Hellwig   cifs: introduce c...
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
  	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
516
517
518
519
520
  		}
  	}
  
  	return rc;
  }
eafe87012   Steve French   [CIFS] Fix readdi...
521
522
  /* 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...
523
  static int is_dir_changed(struct file *file)
eafe87012   Steve French   [CIFS] Fix readdi...
524
  {
496ad9aa8   Al Viro   new helper: file_...
525
  	struct inode *inode = file_inode(file);
c33f8d327   Christoph Hellwig   [CIFS] Remove unn...
526
  	struct cifsInodeInfo *cifsInfo = CIFS_I(inode);
eafe87012   Steve French   [CIFS] Fix readdi...
527

c33f8d327   Christoph Hellwig   [CIFS] Remove unn...
528
  	if (cifsInfo->time == 0)
eafe87012   Steve French   [CIFS] Fix readdi...
529
530
531
532
533
  		return 1; /* directory was changed, perhaps due to unlink */
  	else
  		return 0;
  
  }
0752f1522   Steve French   [CIFS] make sure ...
534
  static int cifs_save_resume_key(const char *current_entry,
eaf35b1ea   Christoph Hellwig   cifs: use cifs_di...
535
  	struct cifsFileInfo *file_info)
0752f1522   Steve French   [CIFS] make sure ...
536
  {
eaf35b1ea   Christoph Hellwig   cifs: use cifs_di...
537
538
  	struct cifs_dirent de;
  	int rc;
0752f1522   Steve French   [CIFS] make sure ...
539

eaf35b1ea   Christoph Hellwig   cifs: use cifs_di...
540
541
542
543
544
545
  	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 ...
546
  	}
0752f1522   Steve French   [CIFS] make sure ...
547
548
  	return rc;
  }
92fc65a74   Pavel Shilovsky   CIFS: Move readdi...
549
550
551
552
553
554
555
556
  /*
   * 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...
557
  find_cifs_entry(const unsigned int xid, struct cifs_tcon *tcon, loff_t pos,
92fc65a74   Pavel Shilovsky   CIFS: Move readdi...
558
  		struct file *file, char **current_entry, int *num_to_ret)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
559
  {
2608bee74   Shirish Pargaonkar   cifs: Include bac...
560
  	__u16 search_flags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
561
562
563
  	int rc = 0;
  	int pos_in_buf = 0;
  	loff_t first_entry_in_buffer;
be4ccdcc2   Al Viro   [readdir] convert...
564
  	loff_t index_to_find = pos;
92fc65a74   Pavel Shilovsky   CIFS: Move readdi...
565
  	struct cifsFileInfo *cfile = file->private_data;
7119e220a   Al Viro   cifs: get rid of ...
566
  	struct cifs_sb_info *cifs_sb = CIFS_FILE_SB(file);
92fc65a74   Pavel Shilovsky   CIFS: Move readdi...
567
  	struct TCP_Server_Info *server = tcon->ses->server;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
568
  	/* check if index in the buffer */
50c2f7538   Steve French   [CIFS] whitespace...
569

92fc65a74   Pavel Shilovsky   CIFS: Move readdi...
570
571
572
573
  	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
574
  		return -ENOENT;
50c2f7538   Steve French   [CIFS] whitespace...
575

92fc65a74   Pavel Shilovsky   CIFS: Move readdi...
576
577
578
  	*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...
579

92fc65a74   Pavel Shilovsky   CIFS: Move readdi...
580
581
582
583
584
585
586
  	/*
  	 * 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...
587

3979877e5   Steve French   [CIFS] Support fo...
588
  	dump_cifs_file_struct(file, "In fce ");
92fc65a74   Pavel Shilovsky   CIFS: Move readdi...
589
590
  	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
591
  		/* close and restart search */
f96637be0   Joe Perches   [CIFS] cifs: Rena...
592
593
  		cifs_dbg(FYI, "search backing up - close and restart search
  ");
3afca265b   Steve French   Clarify locking o...
594
  		spin_lock(&cfile->file_info_lock);
52755808d   Pavel Shilovsky   CIFS: Fix SMB2 re...
595
  		if (server->ops->dir_needs_close(cfile)) {
92fc65a74   Pavel Shilovsky   CIFS: Move readdi...
596
  			cfile->invalidHandle = true;
3afca265b   Steve French   Clarify locking o...
597
  			spin_unlock(&cfile->file_info_lock);
f736906a7   Pavel Shilovsky   CIFS: Fix wrong r...
598
599
  			if (server->ops->close_dir)
  				server->ops->close_dir(xid, tcon, &cfile->fid);
ddb4cbfc5   Steve French   [CIFS] Do not att...
600
  		} else
3afca265b   Steve French   Clarify locking o...
601
  			spin_unlock(&cfile->file_info_lock);
92fc65a74   Pavel Shilovsky   CIFS: Move readdi...
602
  		if (cfile->srch_inf.ntwrk_buf_start) {
f96637be0   Joe Perches   [CIFS] cifs: Rena...
603
604
  			cifs_dbg(FYI, "freeing SMB ff cache buf on search rewind
  ");
92fc65a74   Pavel Shilovsky   CIFS: Move readdi...
605
606
  			if (cfile->srch_inf.smallBuf)
  				cifs_small_buf_release(cfile->srch_inf.
d47d7c1a8   Steve French   [CIFS] CIFS readd...
607
608
  						ntwrk_buf_start);
  			else
92fc65a74   Pavel Shilovsky   CIFS: Move readdi...
609
  				cifs_buf_release(cfile->srch_inf.
d47d7c1a8   Steve French   [CIFS] CIFS readd...
610
  						ntwrk_buf_start);
92fc65a74   Pavel Shilovsky   CIFS: Move readdi...
611
  			cfile->srch_inf.ntwrk_buf_start = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
612
  		}
3870253ef   Steve French   [CIFS] more white...
613
  		rc = initiate_cifs_search(xid, file);
4523cc304   Steve French   [CIFS] UID/GID ov...
614
  		if (rc) {
f96637be0   Joe Perches   [CIFS] cifs: Rena...
615
616
  			cifs_dbg(FYI, "error %d reinitiating a search on rewind
  ",
b6b38f704   Joe Perches   [CIFS] Neaten cER...
617
  				 rc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
618
619
  			return rc;
  		}
7023676f9   Jeff Layton   cifs: check for N...
620
  		/* FindFirst/Next set last_entry to NULL on malformed reply */
92fc65a74   Pavel Shilovsky   CIFS: Move readdi...
621
622
  		if (cfile->srch_inf.last_entry)
  			cifs_save_resume_key(cfile->srch_inf.last_entry, cfile);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
623
  	}
2608bee74   Shirish Pargaonkar   cifs: Include bac...
624
625
626
  	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...
627
628
  	while ((index_to_find >= cfile->srch_inf.index_of_last_entry) &&
  	       (rc == 0) && !cfile->srch_inf.endOfSearch) {
f96637be0   Joe Perches   [CIFS] cifs: Rena...
629
630
  		cifs_dbg(FYI, "calling findnext2
  ");
92fc65a74   Pavel Shilovsky   CIFS: Move readdi...
631
632
633
  		rc = server->ops->query_dir_next(xid, tcon, &cfile->fid,
  						 search_flags,
  						 &cfile->srch_inf);
7023676f9   Jeff Layton   cifs: check for N...
634
  		/* FindFirst/Next set last_entry to NULL on malformed reply */
92fc65a74   Pavel Shilovsky   CIFS: Move readdi...
635
636
  		if (cfile->srch_inf.last_entry)
  			cifs_save_resume_key(cfile->srch_inf.last_entry, cfile);
4523cc304   Steve French   [CIFS] UID/GID ov...
637
  		if (rc)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
638
639
  			return -ENOENT;
  	}
92fc65a74   Pavel Shilovsky   CIFS: Move readdi...
640
  	if (index_to_find < cfile->srch_inf.index_of_last_entry) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
641
642
643
  		/* we found the buffer that contains the entry */
  		/* scan and find it */
  		int i;
92fc65a74   Pavel Shilovsky   CIFS: Move readdi...
644
645
646
647
648
649
650
651
  		char *cur_ent;
  		char *end_of_smb = cfile->srch_inf.ntwrk_buf_start +
  			server->ops->calc_smb_size(
  					cfile->srch_inf.ntwrk_buf_start);
  
  		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
652
  		pos_in_buf = index_to_find - first_entry_in_buffer;
f96637be0   Joe Perches   [CIFS] cifs: Rena...
653
654
  		cifs_dbg(FYI, "found entry - pos_in_buf %d
  ", pos_in_buf);
5bafd7659   Steve French   [CIFS] Add suppor...
655

92fc65a74   Pavel Shilovsky   CIFS: Move readdi...
656
  		for (i = 0; (i < (pos_in_buf)) && (cur_ent != NULL); i++) {
dfb7533b5   Steve French   [CIFS] Add stats ...
657
  			/* go entry by entry figuring out which is first */
92fc65a74   Pavel Shilovsky   CIFS: Move readdi...
658
659
  			cur_ent = nxt_dir_entry(cur_ent, end_of_smb,
  						cfile->srch_inf.info_level);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
660
  		}
92fc65a74   Pavel Shilovsky   CIFS: Move readdi...
661
  		if ((cur_ent == NULL) && (i < pos_in_buf)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
662
  			/* BB fixme - check if we should flag this error */
f96637be0   Joe Perches   [CIFS] cifs: Rena...
663
664
665
  			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
666
667
  		}
  		rc = 0;
92fc65a74   Pavel Shilovsky   CIFS: Move readdi...
668
  		*current_entry = cur_ent;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
669
  	} else {
f96637be0   Joe Perches   [CIFS] cifs: Rena...
670
671
  		cifs_dbg(FYI, "index not in buffer - could not findnext into it
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
672
673
  		return 0;
  	}
92fc65a74   Pavel Shilovsky   CIFS: Move readdi...
674
  	if (pos_in_buf >= cfile->srch_inf.entries_in_buffer) {
f96637be0   Joe Perches   [CIFS] cifs: Rena...
675
676
  		cifs_dbg(FYI, "can not return entries pos_in_buf beyond last
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
677
678
  		*num_to_ret = 0;
  	} else
92fc65a74   Pavel Shilovsky   CIFS: Move readdi...
679
  		*num_to_ret = cfile->srch_inf.entries_in_buffer - pos_in_buf;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
680
681
682
  
  	return rc;
  }
be4ccdcc2   Al Viro   [readdir] convert...
683
684
685
  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
686
  {
9feed6f8f   Christoph Hellwig   cifs: cleanup cif...
687
  	struct cifsFileInfo *file_info = file->private_data;
7119e220a   Al Viro   cifs: get rid of ...
688
  	struct super_block *sb = file_inode(file)->i_sb;
9feed6f8f   Christoph Hellwig   cifs: cleanup cif...
689
  	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
cda0ec6a8   Christoph Hellwig   cifs: introduce c...
690
  	struct cifs_dirent de = { NULL, };
cc0bad755   Jeff Layton   cifs: add new cif...
691
  	struct cifs_fattr fattr;
9feed6f8f   Christoph Hellwig   cifs: cleanup cif...
692
  	struct qstr name;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
693
  	int rc = 0;
9feed6f8f   Christoph Hellwig   cifs: cleanup cif...
694
  	ino_t ino;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
695

cda0ec6a8   Christoph Hellwig   cifs: introduce c...
696
697
698
699
  	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...
700

f16d59b41   Christoph Hellwig   cifs: use cifs_di...
701
  	if (de.namelen > max_len) {
f96637be0   Joe Perches   [CIFS] cifs: Rena...
702
703
704
  		cifs_dbg(VFS, "bad search response length %zd past smb end
  ",
  			 de.namelen);
5bafd7659   Steve French   [CIFS] Add suppor...
705
706
  		return -EINVAL;
  	}
60808233f   Steve French   [CIFS] Readdir fi...
707
  	/* skip . and .. since we added them first */
cda0ec6a8   Christoph Hellwig   cifs: introduce c...
708
  	if (cifs_entry_is_dot(&de, file_info->srch_inf.unicode))
60808233f   Steve French   [CIFS] Readdir fi...
709
  		return 0;
f16d59b41   Christoph Hellwig   cifs: use cifs_di...
710
711
  	if (file_info->srch_inf.unicode) {
  		struct nls_table *nlt = cifs_sb->local_nls;
b693855fe   Steve French   Allow conversion ...
712
  		int map_type;
2baa26825   Steve French   Remap reserved po...
713
  		map_type = cifs_remap(cifs_sb);
f16d59b41   Christoph Hellwig   cifs: use cifs_di...
714
715
  		name.name = scratch_buf;
  		name.len =
acbbb76a2   Steve French   CIFS: Rename *UCS...
716
717
718
  			cifs_from_utf16((char *)name.name, (__le16 *)de.name,
  					UNICODE_NAME_MAX,
  					min_t(size_t, de.namelen,
b693855fe   Steve French   Allow conversion ...
719
  					      (size_t)max_len), nlt, map_type);
f16d59b41   Christoph Hellwig   cifs: use cifs_di...
720
721
722
723
724
  		name.len -= nls_nullsize(nlt);
  	} else {
  		name.name = de.name;
  		name.len = de.namelen;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
725

9feed6f8f   Christoph Hellwig   cifs: cleanup cif...
726
727
  	switch (file_info->srch_inf.info_level) {
  	case SMB_FIND_FILE_UNIX:
cc0bad755   Jeff Layton   cifs: add new cif...
728
  		cifs_unix_basic_to_fattr(&fattr,
9feed6f8f   Christoph Hellwig   cifs: cleanup cif...
729
730
731
732
733
734
735
736
737
738
739
740
741
742
  					 &((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...
743

f16d59b41   Christoph Hellwig   cifs: use cifs_di...
744
745
  	if (de.ino && (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)) {
  		fattr.cf_uniqueid = de.ino;
ec06aedd4   Jeff Layton   cifs: clean up ha...
746
  	} else {
0b8f18e35   Jeff Layton   cifs: convert cif...
747
  		fattr.cf_uniqueid = iunique(sb, ROOT_I);
ec06aedd4   Jeff Layton   cifs: clean up ha...
748
749
  		cifs_autodisable_serverino(cifs_sb);
  	}
50c2f7538   Steve French   [CIFS] whitespace...
750

1b12b9c15   Stefan Metzmacher   cifs: use Minshal...
751
  	if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) &&
cb084b1a9   Sachin Prabhu   cifs: Rename MF s...
752
  	    couldbe_mf_symlink(&fattr))
1b12b9c15   Stefan Metzmacher   cifs: use Minshal...
753
754
755
756
757
758
  		/*
  		 * 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...
759
  	cifs_prime_dcache(file_dentry(file), &name, &fattr);
3870253ef   Steve French   [CIFS] more white...
760

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

be4ccdcc2   Al Viro   [readdir] convert...
765
  int cifs_readdir(struct file *file, struct dir_context *ctx)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
766
767
  {
  	int rc = 0;
6d5786a34   Pavel Shilovsky   CIFS: Rename Get/...
768
769
  	unsigned int xid;
  	int i;
92fc65a74   Pavel Shilovsky   CIFS: Move readdi...
770
  	struct cifs_tcon *tcon;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
771
  	struct cifsFileInfo *cifsFile = NULL;
3870253ef   Steve French   [CIFS] more white...
772
  	char *current_entry;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
773
  	int num_to_fill = 0;
3870253ef   Steve French   [CIFS] more white...
774
  	char *tmp_buf = NULL;
50c2f7538   Steve French   [CIFS] whitespace...
775
  	char *end_of_smb;
18295796a   Jeff Layton   cifs: fix length ...
776
  	unsigned int max_len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
777

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

6221ddd0f   Suresh Jayaraman   cifs: handle Find...
780
781
782
783
784
785
  	/*
  	 * 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);
f96637be0   Joe Perches   [CIFS] cifs: Rena...
786
787
  		cifs_dbg(FYI, "initiate cifs search rc %d
  ", rc);
6221ddd0f   Suresh Jayaraman   cifs: handle Find...
788
789
790
  		if (rc)
  			goto rddir2_exit;
  	}
be4ccdcc2   Al Viro   [readdir] convert...
791
792
  	if (!dir_emit_dots(file, ctx))
  		goto rddir2_exit;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
793

be4ccdcc2   Al Viro   [readdir] convert...
794
795
796
797
  	/* 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...
798
799
800
801
802
803
  	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
804
805
  			goto rddir2_exit;
  		}
be4ccdcc2   Al Viro   [readdir] convert...
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
  	} /* else {
  		cifsFile->invalidHandle = true;
  		tcon->ses->server->close(xid, tcon, &cifsFile->fid);
  	} */
  
  	tcon = tlink_tcon(cifsFile->tlink);
  	rc = find_cifs_entry(xid, tcon, ctx->pos, file, &current_entry,
  			     &num_to_fill);
  	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 {
  		cifs_dbg(FYI, "could not find entry
  ");
  		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(
  			cifsFile->srch_inf.ntwrk_buf_start);
  	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...
845
846
  			break;
  		}
be4ccdcc2   Al Viro   [readdir] convert...
847
848
849
850
  		/*
  		 * if buggy server returns . and .. late do we want to
  		 * check for that here?
  		 */
01b9b0b28   Vasily Averin   cifs_dbg() output...
851
  		*tmp_buf = 0;
be4ccdcc2   Al Viro   [readdir] convert...
852
853
854
855
  		rc = cifs_filldir(current_entry, file, ctx,
  				  tmp_buf, max_len);
  		if (rc) {
  			if (rc > 0)
7ca85ba75   Steve French   [CIFS] Fix readdi...
856
  				rc = 0;
be4ccdcc2   Al Viro   [readdir] convert...
857
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
858
  		}
be4ccdcc2   Al Viro   [readdir] convert...
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
  
  		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
874
875
  
  rddir2_exit:
6d5786a34   Pavel Shilovsky   CIFS: Rename Get/...
876
  	free_xid(xid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
877
878
  	return rc;
  }