Blame view

fs/cifs/readdir.c 25.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
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
   *   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...
24
  #include <linux/pagemap.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
25
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
26
  #include <linux/stat.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
27
28
29
30
31
32
33
  #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...
34
35
36
37
38
39
  /*
   * 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...
40
41
  #ifdef CONFIG_CIFS_DEBUG2
  static void dump_cifs_file_struct(struct file *file, char *label)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
42
  {
6dc0f87e3   Steve French   [CIFS] whitespace...
43
  	struct cifsFileInfo *cf;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
44

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

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

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

0b8f18e35   Jeff Layton   cifs: convert cif...
122
123
124
  	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
125
  	} else {
0b8f18e35   Jeff Layton   cifs: convert cif...
126
127
  		fattr->cf_mode = S_IFREG | cifs_sb->mnt_file_mode;
  		fattr->cf_dtype = DT_REG;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
128
  	}
0b8f18e35   Jeff Layton   cifs: convert cif...
129
130
  	if (fattr->cf_cifsattrs & ATTR_READONLY)
  		fattr->cf_mode &= ~S_IWUGO;
5bafd7659   Steve French   [CIFS] Add suppor...
131

0b8f18e35   Jeff Layton   cifs: convert cif...
132
133
134
135
136
137
  	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...
138
  		} else {
4468eb3fd   Jeff Layton   on non-posix shar...
139
  			/*
0b8f18e35   Jeff Layton   cifs: convert cif...
140
141
142
  			 * 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...
143
  			 */
0b8f18e35   Jeff Layton   cifs: convert cif...
144
  			fattr->cf_flags |= CIFS_FATTR_NEED_REVAL;
4468eb3fd   Jeff Layton   on non-posix shar...
145
146
  		}
  	}
0b8f18e35   Jeff Layton   cifs: convert cif...
147
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
148

15dd47810   Steve French   [CIFS] Remove bui...
149
  static void
0b8f18e35   Jeff Layton   cifs: convert cif...
150
151
152
153
154
155
156
157
158
159
160
161
162
  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);
  	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
163

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

0b8f18e35   Jeff Layton   cifs: convert cif...
170
171
172
173
174
175
176
177
178
179
180
181
182
  	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
183
  }
0e0d2cf32   Steve French   [CIFS] Remove spa...
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
  /* BB eventually need to add the following helper function to
        resolve NT_STATUS_STOPPED_ON_SYMLINK return code when
        we try to do FindFirst on (NTFS) directory symlinks */
  /*
  int get_symlink_reparse_path(char *full_path, struct cifs_sb_info *cifs_sb,
  			     int xid)
  {
  	__u16 fid;
  	int len;
  	int oplock = 0;
  	int rc;
  	struct cifsTconInfo *ptcon = cifs_sb->tcon;
  	char *tmpbuffer;
  
  	rc = CIFSSMBOpen(xid, ptcon, full_path, FILE_OPEN, GENERIC_READ,
  			OPEN_REPARSE_POINT, &fid, &oplock, NULL,
  			cifs_sb->local_nls,
  			cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
  	if (!rc) {
  		tmpbuffer = kmalloc(maxpath);
  		rc = CIFSSMBQueryReparseLinkInfo(xid, ptcon, full_path,
  				tmpbuffer,
  				maxpath -1,
  				fid,
  				cifs_sb->local_nls);
  		if (CIFSSMBClose(xid, ptcon, fid)) {
b6b38f704   Joe Perches   [CIFS] Neaten cER...
210
  			cFYI(1, "Error closing temporary reparsepoint open");
0e0d2cf32   Steve French   [CIFS] Remove spa...
211
212
213
214
  		}
  	}
  }
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
215
216
217
  static int initiate_cifs_search(const int xid, struct file *file)
  {
  	int rc = 0;
3870253ef   Steve French   [CIFS] more white...
218
219
  	char *full_path;
  	struct cifsFileInfo *cifsFile;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
220
221
  	struct cifs_sb_info *cifs_sb;
  	struct cifsTconInfo *pTcon;
4523cc304   Steve French   [CIFS] UID/GID ov...
222
  	if (file->private_data == NULL) {
3870253ef   Steve French   [CIFS] more white...
223
224
  		file->private_data =
  			kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
225
  	}
4523cc304   Steve French   [CIFS] UID/GID ov...
226
  	if (file->private_data == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
227
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
228
  	cifsFile = file->private_data;
4b18f2a9c   Steve French   [CIFS] convert us...
229
230
  	cifsFile->invalidHandle = true;
  	cifsFile->srch_inf.endOfSearch = false;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
231

e6a002964   Josef "Jeff" Sipek   [PATCH] cifs: cha...
232
  	cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
4523cc304   Steve French   [CIFS] UID/GID ov...
233
  	if (cifs_sb == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
234
235
236
  		return -EINVAL;
  
  	pTcon = cifs_sb->tcon;
4523cc304   Steve French   [CIFS] UID/GID ov...
237
  	if (pTcon == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
238
  		return -EINVAL;
e6a002964   Josef "Jeff" Sipek   [PATCH] cifs: cha...
239
  	full_path = build_path_from_dentry(file->f_path.dentry);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
240

ad7a2926b   Steve French   [CIFS] reduce che...
241
  	if (full_path == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
242
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
243

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

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

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

4523cc304   Steve French   [CIFS] UID/GID ov...
296
  	if (level == SMB_FIND_FILE_INFO_STANDARD) {
ad7a2926b   Steve French   [CIFS] reduce che...
297
  		FIND_FILE_STANDARD_INFO *pfData;
5bafd7659   Steve French   [CIFS] Add suppor...
298
299
300
301
302
303
  		pfData = (FIND_FILE_STANDARD_INFO *)pDirInfo;
  
  		new_entry = old_entry + sizeof(FIND_FILE_STANDARD_INFO) +
  				pfData->FileNameLength;
  	} else
  		new_entry = old_entry + le32_to_cpu(pDirInfo->NextEntryOffset);
b6b38f704   Joe Perches   [CIFS] Neaten cER...
304
  	cFYI(1, "new entry %p old entry %p", new_entry, old_entry);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
305
  	/* validate that new_entry is not past end of SMB */
4523cc304   Steve French   [CIFS] UID/GID ov...
306
  	if (new_entry >= end_of_smb) {
b6b38f704   Joe Perches   [CIFS] Neaten cER...
307
308
  		cERROR(1, "search entry %p began after end of SMB %p old entry %p",
  			new_entry, end_of_smb, old_entry);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
309
  		return NULL;
4523cc304   Steve French   [CIFS] UID/GID ov...
310
  	} else if (((level == SMB_FIND_FILE_INFO_STANDARD) &&
3870253ef   Steve French   [CIFS] more white...
311
312
  		    (new_entry + sizeof(FIND_FILE_STANDARD_INFO) > end_of_smb))
  		  || ((level != SMB_FIND_FILE_INFO_STANDARD) &&
5bafd7659   Steve French   [CIFS] Add suppor...
313
  		   (new_entry + sizeof(FILE_DIRECTORY_INFO) > end_of_smb)))  {
b6b38f704   Joe Perches   [CIFS] Neaten cER...
314
315
  		cERROR(1, "search entry %p extends after end of SMB %p",
  			new_entry, end_of_smb);
09d1db5c6   Steve French   [PATCH] cifs: imp...
316
  		return NULL;
3870253ef   Steve French   [CIFS] more white...
317
  	} else
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
318
319
320
321
322
323
324
325
326
327
  		return new_entry;
  
  }
  
  #define UNICODE_DOT cpu_to_le16(0x2e)
  
  /* return 0 if no match and 1 for . (current directory) and 2 for .. (parent) */
  static int cifs_entry_is_dot(char *current_entry, struct cifsFileInfo *cfile)
  {
  	int rc = 0;
3870253ef   Steve French   [CIFS] more white...
328
329
  	char *filename = NULL;
  	int len = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
330

4523cc304   Steve French   [CIFS] UID/GID ov...
331
  	if (cfile->srch_inf.info_level == SMB_FIND_FILE_UNIX) {
ad7a2926b   Steve French   [CIFS] reduce che...
332
  		FILE_UNIX_INFO *pFindData = (FILE_UNIX_INFO *)current_entry;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
333
  		filename = &pFindData->FileName[0];
4523cc304   Steve French   [CIFS] UID/GID ov...
334
  		if (cfile->srch_inf.unicode) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
335
336
337
338
339
  			len = cifs_unicode_bytelen(filename);
  		} else {
  			/* BB should we make this strnlen of PATH_MAX? */
  			len = strnlen(filename, 5);
  		}
4523cc304   Steve French   [CIFS] UID/GID ov...
340
  	} else if (cfile->srch_inf.info_level == SMB_FIND_FILE_DIRECTORY_INFO) {
ad7a2926b   Steve French   [CIFS] reduce che...
341
  		FILE_DIRECTORY_INFO *pFindData =
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
342
343
344
  			(FILE_DIRECTORY_INFO *)current_entry;
  		filename = &pFindData->FileName[0];
  		len = le32_to_cpu(pFindData->FileNameLength);
3870253ef   Steve French   [CIFS] more white...
345
  	} else if (cfile->srch_inf.info_level ==
5bafd7659   Steve French   [CIFS] Add suppor...
346
  			SMB_FIND_FILE_FULL_DIRECTORY_INFO) {
ad7a2926b   Steve French   [CIFS] reduce che...
347
  		FILE_FULL_DIRECTORY_INFO *pFindData =
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
348
349
350
  			(FILE_FULL_DIRECTORY_INFO *)current_entry;
  		filename = &pFindData->FileName[0];
  		len = le32_to_cpu(pFindData->FileNameLength);
4523cc304   Steve French   [CIFS] UID/GID ov...
351
  	} else if (cfile->srch_inf.info_level ==
5bafd7659   Steve French   [CIFS] Add suppor...
352
  			SMB_FIND_FILE_ID_FULL_DIR_INFO) {
ad7a2926b   Steve French   [CIFS] reduce che...
353
  		SEARCH_ID_FULL_DIR_INFO *pFindData =
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
354
355
356
  			(SEARCH_ID_FULL_DIR_INFO *)current_entry;
  		filename = &pFindData->FileName[0];
  		len = le32_to_cpu(pFindData->FileNameLength);
3870253ef   Steve French   [CIFS] more white...
357
  	} else if (cfile->srch_inf.info_level ==
5bafd7659   Steve French   [CIFS] Add suppor...
358
  			SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
ad7a2926b   Steve French   [CIFS] reduce che...
359
  		FILE_BOTH_DIRECTORY_INFO *pFindData =
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
360
361
362
  			(FILE_BOTH_DIRECTORY_INFO *)current_entry;
  		filename = &pFindData->FileName[0];
  		len = le32_to_cpu(pFindData->FileNameLength);
4523cc304   Steve French   [CIFS] UID/GID ov...
363
  	} else if (cfile->srch_inf.info_level == SMB_FIND_FILE_INFO_STANDARD) {
ad7a2926b   Steve French   [CIFS] reduce che...
364
  		FIND_FILE_STANDARD_INFO *pFindData =
5bafd7659   Steve French   [CIFS] Add suppor...
365
366
  			(FIND_FILE_STANDARD_INFO *)current_entry;
  		filename = &pFindData->FileName[0];
5ddaa683a   Steve French   [CIFS] endian err...
367
  		len = pFindData->FileNameLength;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
368
  	} else {
b6b38f704   Joe Perches   [CIFS] Neaten cER...
369
370
  		cFYI(1, "Unknown findfirst level %d",
  			 cfile->srch_inf.info_level);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
371
  	}
4523cc304   Steve French   [CIFS] UID/GID ov...
372
373
  	if (filename) {
  		if (cfile->srch_inf.unicode) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
374
  			__le16 *ufilename = (__le16 *)filename;
4523cc304   Steve French   [CIFS] UID/GID ov...
375
  			if (len == 2) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
376
  				/* check for . */
4523cc304   Steve French   [CIFS] UID/GID ov...
377
  				if (ufilename[0] == UNICODE_DOT)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
378
  					rc = 1;
4523cc304   Steve French   [CIFS] UID/GID ov...
379
  			} else if (len == 4) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
380
  				/* check for .. */
4523cc304   Steve French   [CIFS] UID/GID ov...
381
  				if ((ufilename[0] == UNICODE_DOT)
3870253ef   Steve French   [CIFS] more white...
382
  				   && (ufilename[1] == UNICODE_DOT))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
383
384
385
  					rc = 2;
  			}
  		} else /* ASCII */ {
4523cc304   Steve French   [CIFS] UID/GID ov...
386
  			if (len == 1) {
3870253ef   Steve French   [CIFS] more white...
387
  				if (filename[0] == '.')
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
388
  					rc = 1;
4523cc304   Steve French   [CIFS] UID/GID ov...
389
  			} else if (len == 2) {
790fe579f   Steve French   [CIFS] more white...
390
  				if ((filename[0] == '.') && (filename[1] == '.'))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
391
392
393
394
395
396
397
  					rc = 2;
  			}
  		}
  	}
  
  	return rc;
  }
eafe87012   Steve French   [CIFS] Fix readdi...
398
399
  /* 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...
400
  static int is_dir_changed(struct file *file)
eafe87012   Steve French   [CIFS] Fix readdi...
401
  {
c33f8d327   Christoph Hellwig   [CIFS] Remove unn...
402
403
  	struct inode *inode = file->f_path.dentry->d_inode;
  	struct cifsInodeInfo *cifsInfo = CIFS_I(inode);
eafe87012   Steve French   [CIFS] Fix readdi...
404

c33f8d327   Christoph Hellwig   [CIFS] Remove unn...
405
  	if (cifsInfo->time == 0)
eafe87012   Steve French   [CIFS] Fix readdi...
406
407
408
409
410
  		return 1; /* directory was changed, perhaps due to unlink */
  	else
  		return 0;
  
  }
0752f1522   Steve French   [CIFS] make sure ...
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
  static int cifs_save_resume_key(const char *current_entry,
  	struct cifsFileInfo *cifsFile)
  {
  	int rc = 0;
  	unsigned int len = 0;
  	__u16 level;
  	char *filename;
  
  	if ((cifsFile == NULL) || (current_entry == NULL))
  		return -EINVAL;
  
  	level = cifsFile->srch_inf.info_level;
  
  	if (level == SMB_FIND_FILE_UNIX) {
  		FILE_UNIX_INFO *pFindData = (FILE_UNIX_INFO *)current_entry;
  
  		filename = &pFindData->FileName[0];
  		if (cifsFile->srch_inf.unicode) {
  			len = cifs_unicode_bytelen(filename);
  		} else {
  			/* BB should we make this strnlen of PATH_MAX? */
  			len = strnlen(filename, PATH_MAX);
  		}
  		cifsFile->srch_inf.resume_key = pFindData->ResumeKey;
  	} else if (level == SMB_FIND_FILE_DIRECTORY_INFO) {
  		FILE_DIRECTORY_INFO *pFindData =
  			(FILE_DIRECTORY_INFO *)current_entry;
  		filename = &pFindData->FileName[0];
  		len = le32_to_cpu(pFindData->FileNameLength);
  		cifsFile->srch_inf.resume_key = pFindData->FileIndex;
  	} else if (level == SMB_FIND_FILE_FULL_DIRECTORY_INFO) {
  		FILE_FULL_DIRECTORY_INFO *pFindData =
  			(FILE_FULL_DIRECTORY_INFO *)current_entry;
  		filename = &pFindData->FileName[0];
  		len = le32_to_cpu(pFindData->FileNameLength);
  		cifsFile->srch_inf.resume_key = pFindData->FileIndex;
  	} else if (level == SMB_FIND_FILE_ID_FULL_DIR_INFO) {
  		SEARCH_ID_FULL_DIR_INFO *pFindData =
  			(SEARCH_ID_FULL_DIR_INFO *)current_entry;
  		filename = &pFindData->FileName[0];
  		len = le32_to_cpu(pFindData->FileNameLength);
  		cifsFile->srch_inf.resume_key = pFindData->FileIndex;
  	} else if (level == SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
  		FILE_BOTH_DIRECTORY_INFO *pFindData =
  			(FILE_BOTH_DIRECTORY_INFO *)current_entry;
  		filename = &pFindData->FileName[0];
  		len = le32_to_cpu(pFindData->FileNameLength);
  		cifsFile->srch_inf.resume_key = pFindData->FileIndex;
  	} else if (level == SMB_FIND_FILE_INFO_STANDARD) {
  		FIND_FILE_STANDARD_INFO *pFindData =
  			(FIND_FILE_STANDARD_INFO *)current_entry;
  		filename = &pFindData->FileName[0];
  		/* one byte length, no name conversion */
  		len = (unsigned int)pFindData->FileNameLength;
  		cifsFile->srch_inf.resume_key = pFindData->ResumeKey;
  	} else {
b6b38f704   Joe Perches   [CIFS] Neaten cER...
467
  		cFYI(1, "Unknown findfirst level %d", level);
0752f1522   Steve French   [CIFS] make sure ...
468
469
470
471
472
473
  		return -EINVAL;
  	}
  	cifsFile->srch_inf.resume_name_len = len;
  	cifsFile->srch_inf.presume_name = filename;
  	return rc;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
474
475
476
477
478
479
480
  /* 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 find_cifs_entry(const int xid, struct cifsTconInfo *pTcon,
3870253ef   Steve French   [CIFS] more white...
481
  	struct file *file, char **ppCurrentEntry, int *num_to_ret)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
482
483
484
485
486
  {
  	int rc = 0;
  	int pos_in_buf = 0;
  	loff_t first_entry_in_buffer;
  	loff_t index_to_find = file->f_pos;
3870253ef   Steve French   [CIFS] more white...
487
  	struct cifsFileInfo *cifsFile = file->private_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
488
  	/* check if index in the buffer */
50c2f7538   Steve French   [CIFS] whitespace...
489

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

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

ad7a2926b   Steve French   [CIFS] reduce che...
560
  		for (i = 0; (i < (pos_in_buf)) && (current_entry != NULL); i++) {
dfb7533b5   Steve French   [CIFS] Add stats ...
561
  			/* go entry by entry figuring out which is first */
3870253ef   Steve French   [CIFS] more white...
562
  			current_entry = nxt_dir_entry(current_entry, end_of_smb,
5bafd7659   Steve French   [CIFS] Add suppor...
563
  						cifsFile->srch_inf.info_level);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
564
  		}
790fe579f   Steve French   [CIFS] more white...
565
  		if ((current_entry == NULL) && (i < pos_in_buf)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
566
  			/* BB fixme - check if we should flag this error */
b6b38f704   Joe Perches   [CIFS] Neaten cER...
567
  			cERROR(1, "reached end of buf searching for pos in buf"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
568
  			  " %d index to find %lld rc %d",
b6b38f704   Joe Perches   [CIFS] Neaten cER...
569
  			  pos_in_buf, index_to_find, rc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
570
571
572
573
  		}
  		rc = 0;
  		*ppCurrentEntry = current_entry;
  	} else {
b6b38f704   Joe Perches   [CIFS] Neaten cER...
574
  		cFYI(1, "index not in buffer - could not findnext into it");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
575
576
  		return 0;
  	}
790fe579f   Steve French   [CIFS] more white...
577
  	if (pos_in_buf >= cifsFile->srch_inf.entries_in_buffer) {
b6b38f704   Joe Perches   [CIFS] Neaten cER...
578
  		cFYI(1, "can not return entries pos_in_buf beyond last");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
579
580
581
  		*num_to_ret = 0;
  	} else
  		*num_to_ret = cifsFile->srch_inf.entries_in_buffer - pos_in_buf;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
582
583
584
585
586
587
588
  
  	return rc;
  }
  
  /* inode num, inode type and filename returned */
  static int cifs_get_name_from_search_buf(struct qstr *pqst,
  	char *current_entry, __u16 level, unsigned int unicode,
18295796a   Jeff Layton   cifs: fix length ...
589
  	struct cifs_sb_info *cifs_sb, unsigned int max_len, __u64 *pinum)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
590
591
592
  {
  	int rc = 0;
  	unsigned int len = 0;
3870253ef   Steve French   [CIFS] more white...
593
594
  	char *filename;
  	struct nls_table *nlt = cifs_sb->local_nls;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
595
596
  
  	*pinum = 0;
790fe579f   Steve French   [CIFS] more white...
597
  	if (level == SMB_FIND_FILE_UNIX) {
3870253ef   Steve French   [CIFS] more white...
598
  		FILE_UNIX_INFO *pFindData = (FILE_UNIX_INFO *)current_entry;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
599
600
  
  		filename = &pFindData->FileName[0];
790fe579f   Steve French   [CIFS] more white...
601
  		if (unicode) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
602
603
604
605
606
  			len = cifs_unicode_bytelen(filename);
  		} else {
  			/* BB should we make this strnlen of PATH_MAX? */
  			len = strnlen(filename, PATH_MAX);
  		}
cc0bad755   Jeff Layton   cifs: add new cif...
607
  		*pinum = le64_to_cpu(pFindData->basic.UniqueId);
790fe579f   Steve French   [CIFS] more white...
608
  	} else if (level == SMB_FIND_FILE_DIRECTORY_INFO) {
3870253ef   Steve French   [CIFS] more white...
609
  		FILE_DIRECTORY_INFO *pFindData =
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
610
611
612
  			(FILE_DIRECTORY_INFO *)current_entry;
  		filename = &pFindData->FileName[0];
  		len = le32_to_cpu(pFindData->FileNameLength);
790fe579f   Steve French   [CIFS] more white...
613
  	} else if (level == SMB_FIND_FILE_FULL_DIRECTORY_INFO) {
3870253ef   Steve French   [CIFS] more white...
614
  		FILE_FULL_DIRECTORY_INFO *pFindData =
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
615
616
617
  			(FILE_FULL_DIRECTORY_INFO *)current_entry;
  		filename = &pFindData->FileName[0];
  		len = le32_to_cpu(pFindData->FileNameLength);
790fe579f   Steve French   [CIFS] more white...
618
  	} else if (level == SMB_FIND_FILE_ID_FULL_DIR_INFO) {
3870253ef   Steve French   [CIFS] more white...
619
  		SEARCH_ID_FULL_DIR_INFO *pFindData =
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
620
621
622
  			(SEARCH_ID_FULL_DIR_INFO *)current_entry;
  		filename = &pFindData->FileName[0];
  		len = le32_to_cpu(pFindData->FileNameLength);
85a6dac54   Steve French   [CIFS] Endian con...
623
  		*pinum = le64_to_cpu(pFindData->UniqueId);
790fe579f   Steve French   [CIFS] more white...
624
  	} else if (level == SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
3870253ef   Steve French   [CIFS] more white...
625
  		FILE_BOTH_DIRECTORY_INFO *pFindData =
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
626
627
628
  			(FILE_BOTH_DIRECTORY_INFO *)current_entry;
  		filename = &pFindData->FileName[0];
  		len = le32_to_cpu(pFindData->FileNameLength);
790fe579f   Steve French   [CIFS] more white...
629
  	} else if (level == SMB_FIND_FILE_INFO_STANDARD) {
ad7a2926b   Steve French   [CIFS] reduce che...
630
  		FIND_FILE_STANDARD_INFO *pFindData =
5bafd7659   Steve French   [CIFS] Add suppor...
631
632
633
634
  			(FIND_FILE_STANDARD_INFO *)current_entry;
  		filename = &pFindData->FileName[0];
  		/* one byte length, no name conversion */
  		len = (unsigned int)pFindData->FileNameLength;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
635
  	} else {
b6b38f704   Joe Perches   [CIFS] Neaten cER...
636
  		cFYI(1, "Unknown findfirst level %d", level);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
637
638
  		return -EINVAL;
  	}
5bafd7659   Steve French   [CIFS] Add suppor...
639

790fe579f   Steve French   [CIFS] more white...
640
  	if (len > max_len) {
b6b38f704   Joe Perches   [CIFS] Neaten cER...
641
  		cERROR(1, "bad search response length %d past smb end", len);
5bafd7659   Steve French   [CIFS] Add suppor...
642
643
  		return -EINVAL;
  	}
790fe579f   Steve French   [CIFS] more white...
644
  	if (unicode) {
f58841666   Jeff Layton   cifs: change cifs...
645
646
  		pqst->len = cifs_from_ucs2((char *) pqst->name,
  					   (__le16 *) filename,
18295796a   Jeff Layton   cifs: fix length ...
647
648
  					   UNICODE_NAME_MAX,
  					   min(len, max_len), nlt,
f58841666   Jeff Layton   cifs: change cifs...
649
650
  					   cifs_sb->mnt_cifs_flags &
  						CIFS_MOUNT_MAP_SPECIAL_CHR);
f12f98dba   Jeff Layton   cifs: fix length ...
651
  		pqst->len -= nls_nullsize(nlt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
652
653
654
655
  	} else {
  		pqst->name = filename;
  		pqst->len = len;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
656
657
  	return rc;
  }
18295796a   Jeff Layton   cifs: fix length ...
658
659
  static int cifs_filldir(char *pfindEntry, struct file *file, filldir_t filldir,
  			void *direntry, char *scratch_buf, unsigned int max_len)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
660
661
662
  {
  	int rc = 0;
  	struct qstr qstring;
3870253ef   Steve French   [CIFS] more white...
663
  	struct cifsFileInfo *pCifsF;
0b8f18e35   Jeff Layton   cifs: convert cif...
664
  	u64    inum;
cc0bad755   Jeff Layton   cifs: add new cif...
665
  	ino_t  ino;
0b8f18e35   Jeff Layton   cifs: convert cif...
666
  	struct super_block *sb;
3870253ef   Steve French   [CIFS] more white...
667
  	struct cifs_sb_info *cifs_sb;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
668
  	struct dentry *tmp_dentry;
cc0bad755   Jeff Layton   cifs: add new cif...
669
  	struct cifs_fattr fattr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
670
671
672
673
  
  	/* get filename and len into qstring */
  	/* get dentry */
  	/* decide whether to create and populate ionde */
790fe579f   Steve French   [CIFS] more white...
674
  	if ((direntry == NULL) || (file == NULL))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
675
676
677
  		return -EINVAL;
  
  	pCifsF = file->private_data;
50c2f7538   Steve French   [CIFS] whitespace...
678

790fe579f   Steve French   [CIFS] more white...
679
  	if ((scratch_buf == NULL) || (pfindEntry == NULL) || (pCifsF == NULL))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
680
  		return -ENOENT;
3870253ef   Steve French   [CIFS] more white...
681
  	rc = cifs_entry_is_dot(pfindEntry, pCifsF);
60808233f   Steve French   [CIFS] Readdir fi...
682
  	/* skip . and .. since we added them first */
790fe579f   Steve French   [CIFS] more white...
683
  	if (rc != 0)
60808233f   Steve French   [CIFS] Readdir fi...
684
  		return 0;
0b8f18e35   Jeff Layton   cifs: convert cif...
685
686
  	sb = file->f_path.dentry->d_sb;
  	cifs_sb = CIFS_SB(sb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
687
688
  
  	qstring.name = scratch_buf;
3870253ef   Steve French   [CIFS] more white...
689
  	rc = cifs_get_name_from_search_buf(&qstring, pfindEntry,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
690
  			pCifsF->srch_inf.info_level,
3870253ef   Steve French   [CIFS] more white...
691
  			pCifsF->srch_inf.unicode, cifs_sb,
0b8f18e35   Jeff Layton   cifs: convert cif...
692
  			max_len, &inum /* returned */);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
693

790fe579f   Steve French   [CIFS] more white...
694
  	if (rc)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
695
  		return rc;
0b8f18e35   Jeff Layton   cifs: convert cif...
696
  	if (pCifsF->srch_inf.info_level == SMB_FIND_FILE_UNIX)
cc0bad755   Jeff Layton   cifs: add new cif...
697
698
699
  		cifs_unix_basic_to_fattr(&fattr,
  				 &((FILE_UNIX_INFO *) pfindEntry)->basic,
  				 cifs_sb);
0b8f18e35   Jeff Layton   cifs: convert cif...
700
701
702
703
704
705
  	else if (pCifsF->srch_inf.info_level == SMB_FIND_FILE_INFO_STANDARD)
  		cifs_std_info_to_fattr(&fattr, (FIND_FILE_STANDARD_INFO *)
  					pfindEntry, cifs_sb);
  	else
  		cifs_dir_info_to_fattr(&fattr, (FILE_DIRECTORY_INFO *)
  					pfindEntry, cifs_sb);
b835bebe9   Steve French   [CIFS] Fix CIFS r...
706

ec06aedd4   Jeff Layton   cifs: clean up ha...
707
  	if (inum && (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)) {
0b8f18e35   Jeff Layton   cifs: convert cif...
708
  		fattr.cf_uniqueid = inum;
ec06aedd4   Jeff Layton   cifs: clean up ha...
709
  	} else {
0b8f18e35   Jeff Layton   cifs: convert cif...
710
  		fattr.cf_uniqueid = iunique(sb, ROOT_I);
ec06aedd4   Jeff Layton   cifs: clean up ha...
711
712
  		cifs_autodisable_serverino(cifs_sb);
  	}
50c2f7538   Steve French   [CIFS] whitespace...
713

0b8f18e35   Jeff Layton   cifs: convert cif...
714
715
  	ino = cifs_uniqueid_to_ino_t(fattr.cf_uniqueid);
  	tmp_dentry = cifs_readdir_lookup(file->f_dentry, &qstring, &fattr);
3870253ef   Steve French   [CIFS] more white...
716
717
  
  	rc = filldir(direntry, qstring.name, qstring.len, file->f_pos,
0b8f18e35   Jeff Layton   cifs: convert cif...
718
719
720
721
722
723
724
725
726
727
  		     ino, fattr.cf_dtype);
  
  	/*
  	 * we can not return filldir errors to the caller since they are
  	 * "normal" when the stat blocksize is too small - we return remapped
  	 * error instead
  	 *
  	 * FIXME: This looks bogus. filldir returns -EOVERFLOW in the above
  	 * case already. Why should we be clobbering other errors from it?
  	 */
790fe579f   Steve French   [CIFS] more white...
728
  	if (rc) {
b6b38f704   Joe Perches   [CIFS] Neaten cER...
729
  		cFYI(1, "filldir rc = %d", rc);
7ca85ba75   Steve French   [CIFS] Fix readdi...
730
  		rc = -EOVERFLOW;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
731
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
732
733
734
  	dput(tmp_dentry);
  	return rc;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
735
736
737
738
  
  int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
  {
  	int rc = 0;
3870253ef   Steve French   [CIFS] more white...
739
  	int xid, i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
740
741
742
  	struct cifs_sb_info *cifs_sb;
  	struct cifsTconInfo *pTcon;
  	struct cifsFileInfo *cifsFile = NULL;
3870253ef   Steve French   [CIFS] more white...
743
  	char *current_entry;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
744
  	int num_to_fill = 0;
3870253ef   Steve French   [CIFS] more white...
745
  	char *tmp_buf = NULL;
50c2f7538   Steve French   [CIFS] whitespace...
746
  	char *end_of_smb;
18295796a   Jeff Layton   cifs: fix length ...
747
  	unsigned int max_len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
748
749
  
  	xid = GetXid();
e6a002964   Josef "Jeff" Sipek   [PATCH] cifs: cha...
750
  	cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
751
  	pTcon = cifs_sb->tcon;
790fe579f   Steve French   [CIFS] more white...
752
  	if (pTcon == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
753
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
754
755
  	switch ((int) file->f_pos) {
  	case 0:
60808233f   Steve French   [CIFS] Readdir fi...
756
  		if (filldir(direntry, ".", 1, file->f_pos,
e6a002964   Josef "Jeff" Sipek   [PATCH] cifs: cha...
757
  		     file->f_path.dentry->d_inode->i_ino, DT_DIR) < 0) {
b6b38f704   Joe Perches   [CIFS] Neaten cER...
758
  			cERROR(1, "Filldir for current dir failed");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
759
760
761
  			rc = -ENOMEM;
  			break;
  		}
60808233f   Steve French   [CIFS] Readdir fi...
762
  		file->f_pos++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
763
  	case 1:
60808233f   Steve French   [CIFS] Readdir fi...
764
  		if (filldir(direntry, "..", 2, file->f_pos,
e6a002964   Josef "Jeff" Sipek   [PATCH] cifs: cha...
765
  		     file->f_path.dentry->d_parent->d_inode->i_ino, DT_DIR) < 0) {
b6b38f704   Joe Perches   [CIFS] Neaten cER...
766
  			cERROR(1, "Filldir for parent dir failed");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
767
768
769
  			rc = -ENOMEM;
  			break;
  		}
60808233f   Steve French   [CIFS] Readdir fi...
770
771
  		file->f_pos++;
  	default:
3870253ef   Steve French   [CIFS] more white...
772
773
  		/* 1) If search is active,
  			is in current search buffer?
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
774
775
  			if it before then restart search
  			if after then keep searching till find it */
790fe579f   Steve French   [CIFS] more white...
776
  		if (file->private_data == NULL) {
3870253ef   Steve French   [CIFS] more white...
777
  			rc = initiate_cifs_search(xid, file);
b6b38f704   Joe Perches   [CIFS] Neaten cER...
778
  			cFYI(1, "initiate cifs search rc %d", rc);
790fe579f   Steve French   [CIFS] more white...
779
  			if (rc) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
780
781
782
783
  				FreeXid(xid);
  				return rc;
  			}
  		}
790fe579f   Steve French   [CIFS] more white...
784
  		if (file->private_data == NULL) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
785
786
787
788
789
790
  			rc = -EINVAL;
  			FreeXid(xid);
  			return rc;
  		}
  		cifsFile = file->private_data;
  		if (cifsFile->srch_inf.endOfSearch) {
790fe579f   Steve French   [CIFS] more white...
791
  			if (cifsFile->srch_inf.emptyDir) {
b6b38f704   Joe Perches   [CIFS] Neaten cER...
792
  				cFYI(1, "End of search, empty dir");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
793
794
795
796
  				rc = 0;
  				break;
  			}
  		} /* else {
4b18f2a9c   Steve French   [CIFS] convert us...
797
  			cifsFile->invalidHandle = true;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
798
  			CIFSFindClose(xid, pTcon, cifsFile->netfid);
aaa9bbe03   Steve French   [CIFS] remove unu...
799
  		} */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
800

3870253ef   Steve French   [CIFS] more white...
801
802
  		rc = find_cifs_entry(xid, pTcon, file,
  				&current_entry, &num_to_fill);
790fe579f   Steve French   [CIFS] more white...
803
  		if (rc) {
b6b38f704   Joe Perches   [CIFS] Neaten cER...
804
  			cFYI(1, "fce error %d", rc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
805
806
  			goto rddir2_exit;
  		} else if (current_entry != NULL) {
b6b38f704   Joe Perches   [CIFS] Neaten cER...
807
  			cFYI(1, "entry %lld found", file->f_pos);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
808
  		} else {
b6b38f704   Joe Perches   [CIFS] Neaten cER...
809
  			cFYI(1, "could not find entry");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
810
811
  			goto rddir2_exit;
  		}
b6b38f704   Joe Perches   [CIFS] Neaten cER...
812
813
  		cFYI(1, "loop through %d times filling dir for net buf %p",
  			num_to_fill, cifsFile->srch_inf.ntwrk_buf_start);
5bafd7659   Steve French   [CIFS] Add suppor...
814
815
816
  		max_len = smbCalcSize((struct smb_hdr *)
  				cifsFile->srch_inf.ntwrk_buf_start);
  		end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + max_len;
f58841666   Jeff Layton   cifs: change cifs...
817
  		tmp_buf = kmalloc(UNICODE_NAME_MAX, GFP_KERNEL);
f55fdcca6   Kulikov Vasiliy   fs: cifs: check k...
818
819
820
821
  		if (tmp_buf == NULL) {
  			rc = -ENOMEM;
  			break;
  		}
790fe579f   Steve French   [CIFS] more white...
822
823
  		for (i = 0; (i < num_to_fill) && (rc == 0); i++) {
  			if (current_entry == NULL) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
824
  				/* evaluate whether this case is an error */
b6b38f704   Joe Perches   [CIFS] Neaten cER...
825
826
  				cERROR(1, "past SMB end,  num to fill %d i %d",
  					  num_to_fill, i);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
827
828
  				break;
  			}
60808233f   Steve French   [CIFS] Readdir fi...
829
830
  			/* if buggy server returns . and .. late do
  			we want to check for that here? */
5bafd7659   Steve French   [CIFS] Add suppor...
831
832
  			rc = cifs_filldir(current_entry, file,
  					filldir, direntry, tmp_buf, max_len);
790fe579f   Steve French   [CIFS] more white...
833
  			if (rc == -EOVERFLOW) {
7ca85ba75   Steve French   [CIFS] Fix readdi...
834
835
836
  				rc = 0;
  				break;
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
837
  			file->f_pos++;
790fe579f   Steve French   [CIFS] more white...
838
  			if (file->f_pos ==
3979877e5   Steve French   [CIFS] Support fo...
839
  				cifsFile->srch_inf.index_of_last_entry) {
b6b38f704   Joe Perches   [CIFS] Neaten cER...
840
841
  				cFYI(1, "last entry in buf at pos %lld %s",
  					file->f_pos, tmp_buf);
790fe579f   Steve French   [CIFS] more white...
842
  				cifs_save_resume_key(current_entry, cifsFile);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
843
  				break;
790fe579f   Steve French   [CIFS] more white...
844
845
  			} else
  				current_entry =
5bafd7659   Steve French   [CIFS] Add suppor...
846
847
  					nxt_dir_entry(current_entry, end_of_smb,
  						cifsFile->srch_inf.info_level);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
848
849
850
851
852
853
  		}
  		kfree(tmp_buf);
  		break;
  	} /* end switch */
  
  rddir2_exit:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
854
855
856
  	FreeXid(xid);
  	return rc;
  }