readdir.c 34.5 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4
/*
 *   fs/cifs/readdir.c
 *
 *   Directory search handling
S
Steve French 已提交
5
 *
S
Steve French 已提交
6
 *   Copyright (C) International Business Machines  Corp., 2004, 2008
L
Linus Torvalds 已提交
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>
D
Dave Kleikamp 已提交
24
#include <linux/pagemap.h>
L
Linus Torvalds 已提交
25 26 27 28 29 30 31 32 33
#include <linux/stat.h>
#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"

34 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)

41 42
#ifdef CONFIG_CIFS_DEBUG2
static void dump_cifs_file_struct(struct file *file, char *label)
L
Linus Torvalds 已提交
43
{
S
Steve French 已提交
44
	struct cifsFileInfo *cf;
L
Linus Torvalds 已提交
45

46
	if (file) {
L
Linus Torvalds 已提交
47
		cf = file->private_data;
48
		if (cf == NULL) {
S
Steve French 已提交
49
			cFYI(1, ("empty cifs private file data"));
L
Linus Torvalds 已提交
50 51
			return;
		}
S
Steve French 已提交
52
		if (cf->invalidHandle)
S
Steve French 已提交
53
			cFYI(1, ("invalid handle"));
S
Steve French 已提交
54
		if (cf->srch_inf.endOfSearch)
S
Steve French 已提交
55
			cFYI(1, ("end of search"));
S
Steve French 已提交
56
		if (cf->srch_inf.emptyDir)
S
Steve French 已提交
57
			cFYI(1, ("empty dir"));
L
Linus Torvalds 已提交
58
	}
59
}
60 61 62 63
#else
static inline void dump_cifs_file_struct(struct file *file, char *label)
{
}
64
#endif /* DEBUG2 */
L
Linus Torvalds 已提交
65

66
/* Returns 1 if new inode created, 2 if both dentry and inode were */
L
Linus Torvalds 已提交
67
/* Might check in the future if inode number changed so we can rehash inode */
68 69 70
static int
construct_dentry(struct qstr *qstring, struct file *file,
		 struct inode **ptmp_inode, struct dentry **pnew_dentry,
71
		 __u64 *inum)
L
Linus Torvalds 已提交
72
{
73 74
	struct dentry *tmp_dentry = NULL;
	struct super_block *sb = file->f_path.dentry->d_sb;
L
Linus Torvalds 已提交
75 76
	int rc = 0;

S
Steve French 已提交
77
	cFYI(1, ("For %s", qstring->name));
L
Linus Torvalds 已提交
78 79

	qstring->hash = full_name_hash(qstring->name, qstring->len);
80
	tmp_dentry = d_lookup(file->f_path.dentry, qstring);
L
Linus Torvalds 已提交
81
	if (tmp_dentry) {
82 83 84
		/* BB: overwrite old name? i.e. tmp_dentry->d_name and
		 * tmp_dentry->d_name.len??
		 */
S
Steve French 已提交
85 86
		cFYI(0, ("existing dentry with inode 0x%p",
			 tmp_dentry->d_inode));
L
Linus Torvalds 已提交
87
		*ptmp_inode = tmp_dentry->d_inode;
88
		if (*ptmp_inode == NULL) {
89
			*ptmp_inode = cifs_new_inode(sb, inum);
90
			if (*ptmp_inode == NULL)
L
Linus Torvalds 已提交
91 92 93 94
				return rc;
			rc = 1;
		}
	} else {
95
		tmp_dentry = d_alloc(file->f_path.dentry, qstring);
96
		if (tmp_dentry == NULL) {
S
Steve French 已提交
97
			cERROR(1, ("Failed allocating dentry"));
L
Linus Torvalds 已提交
98 99 100 101
			*ptmp_inode = NULL;
			return rc;
		}

102
		if (CIFS_SB(sb)->tcon->nocase)
103 104 105
			tmp_dentry->d_op = &cifs_ci_dentry_ops;
		else
			tmp_dentry->d_op = &cifs_dentry_ops;
106 107

		*ptmp_inode = cifs_new_inode(sb, inum);
108
		if (*ptmp_inode == NULL)
L
Linus Torvalds 已提交
109
			return rc;
110
		rc = 2;
L
Linus Torvalds 已提交
111 112 113 114 115 116 117
	}

	tmp_dentry->d_time = jiffies;
	*pnew_dentry = tmp_dentry;
	return rc;
}

118
static void fill_in_inode(struct inode *tmp_inode, int new_buf_type,
S
Steve French 已提交
119
			  char *buf, unsigned int *pobject_type, int isNewInode)
L
Linus Torvalds 已提交
120
{
S
Steve French 已提交
121 122 123
	loff_t local_size;
	struct timespec local_mtime;

L
Linus Torvalds 已提交
124 125
	struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode);
	struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb);
126 127 128
	__u32 attr;
	__u64 allocation_size;
	__u64 end_of_file;
129
	umode_t default_mode;
L
Linus Torvalds 已提交
130

S
Steve French 已提交
131 132 133 134
	/* save mtime and size */
	local_mtime = tmp_inode->i_mtime;
	local_size  = tmp_inode->i_size;

135
	if (new_buf_type) {
136 137 138 139 140 141
		FILE_DIRECTORY_INFO *pfindData = (FILE_DIRECTORY_INFO *)buf;

		attr = le32_to_cpu(pfindData->ExtFileAttributes);
		allocation_size = le64_to_cpu(pfindData->AllocationSize);
		end_of_file = le64_to_cpu(pfindData->EndOfFile);
		tmp_inode->i_atime =
142
			cifs_NTtimeToUnix(pfindData->LastAccessTime);
143
		tmp_inode->i_mtime =
144
			cifs_NTtimeToUnix(pfindData->LastWriteTime);
145
		tmp_inode->i_ctime =
146
			cifs_NTtimeToUnix(pfindData->ChangeTime);
147
	} else { /* legacy, OS2 and DOS style */
148
		int offset = cifs_sb->tcon->ses->server->timeAdj;
S
Steve French 已提交
149
		FIND_FILE_STANDARD_INFO *pfindData =
150 151
			(FIND_FILE_STANDARD_INFO *)buf;

152 153 154 155 156 157 158 159 160
		tmp_inode->i_mtime = cnvrtDosUnixTm(pfindData->LastWriteDate,
						    pfindData->LastWriteTime,
						    offset);
		tmp_inode->i_atime = cnvrtDosUnixTm(pfindData->LastAccessDate,
						    pfindData->LastAccessTime,
						    offset);
		tmp_inode->i_ctime = cnvrtDosUnixTm(pfindData->LastWriteDate,
						    pfindData->LastWriteTime,
						    offset);
161 162 163 164 165
		attr = le16_to_cpu(pfindData->Attributes);
		allocation_size = le32_to_cpu(pfindData->AllocationSize);
		end_of_file = le32_to_cpu(pfindData->DataSize);
	}

L
Linus Torvalds 已提交
166
	/* Linux can not store file creation time unfortunately so ignore it */
167 168

	cifsInfo->cifsAttrs = attr;
169 170 171 172 173 174 175
#ifdef CONFIG_CIFS_EXPERIMENTAL
	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
		/* get more accurate mode via ACL - so force inode refresh */
		cifsInfo->time = 0;
	} else
#endif /* CONFIG_CIFS_EXPERIMENTAL */
		cifsInfo->time = jiffies;
176

L
Linus Torvalds 已提交
177 178
	/* treat dos attribute of read-only as read-only mode bit e.g. 555? */
	/* 2767 perms - indicate mandatory locking */
S
Steve French 已提交
179
		/* BB fill in uid and gid here? with help from winbind?
L
Linus Torvalds 已提交
180 181 182 183
		   or retrieve from NTFS stream extended attribute */
	if (atomic_read(&cifsInfo->inUse) == 0) {
		tmp_inode->i_uid = cifs_sb->mnt_uid;
		tmp_inode->i_gid = cifs_sb->mnt_gid;
184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200
	}

	if (attr & ATTR_DIRECTORY)
		default_mode = cifs_sb->mnt_dir_mode;
	else
		default_mode = cifs_sb->mnt_file_mode;

	/* set initial permissions */
	if ((atomic_read(&cifsInfo->inUse) == 0) ||
	    (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) == 0)
		tmp_inode->i_mode = default_mode;
	else {
		/* just reenable write bits if !ATTR_READONLY */
		if ((tmp_inode->i_mode & S_IWUGO) == 0 &&
		    (attr & ATTR_READONLY) == 0)
			tmp_inode->i_mode |= (S_IWUGO & default_mode);

201
		tmp_inode->i_mode &= ~S_IFMT;
L
Linus Torvalds 已提交
202 203
	}

204 205 206 207 208 209 210
	/* clear write bits if ATTR_READONLY is set */
	if (attr & ATTR_READONLY)
		tmp_inode->i_mode &= ~S_IWUGO;

	/* set inode type */
	if ((attr & ATTR_SYSTEM) &&
	    (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)) {
211 212
		if (end_of_file == 0)  {
			tmp_inode->i_mode |= S_IFIFO;
213
			*pobject_type = DT_FIFO;
214
		} else {
215 216 217 218
			/*
			 * trying to get the type can be slow, so just call
			 * this a regular file for now, and mark for reval
			 */
S
Steve French 已提交
219
			tmp_inode->i_mode |= S_IFREG;
220
			*pobject_type = DT_REG;
S
Steve French 已提交
221
			cifsInfo->time = 0;
222
		}
L
Linus Torvalds 已提交
223
	} else {
224 225 226 227 228 229 230 231
		if (attr & ATTR_DIRECTORY) {
			tmp_inode->i_mode |= S_IFDIR;
			*pobject_type = DT_DIR;
		} else {
			tmp_inode->i_mode |= S_IFREG;
			*pobject_type = DT_REG;
		}
	}
L
Linus Torvalds 已提交
232 233

	/* can not fill in nlink here as in qpathinfo version and Unx search */
S
Steve French 已提交
234
	if (atomic_read(&cifsInfo->inUse) == 0)
L
Linus Torvalds 已提交
235 236
		atomic_set(&cifsInfo->inUse, 1);

237
	cifsInfo->server_eof = end_of_file;
238
	spin_lock(&tmp_inode->i_lock);
239
	if (is_size_safe_to_change(cifsInfo, end_of_file)) {
S
Steve French 已提交
240
		/* can not safely change the file size here if the
L
Linus Torvalds 已提交
241 242 243 244 245 246 247
		client is writing to it due to potential races */
		i_size_write(tmp_inode, end_of_file);

	/* 512 bytes (2**9) is the fake blocksize that must be used */
	/* for this calculation, even though the reported blocksize is larger */
		tmp_inode->i_blocks = (512 - 1 + allocation_size) >> 9;
	}
248
	spin_unlock(&tmp_inode->i_lock);
L
Linus Torvalds 已提交
249 250 251

	if (allocation_size < end_of_file)
		cFYI(1, ("May be sparse file, allocation less than file size"));
252
	cFYI(1, ("File Size %ld and blocks %llu",
253
		(unsigned long)tmp_inode->i_size,
254
		(unsigned long long)tmp_inode->i_blocks));
L
Linus Torvalds 已提交
255
	if (S_ISREG(tmp_inode->i_mode)) {
S
Steve French 已提交
256
		cFYI(1, ("File inode"));
L
Linus Torvalds 已提交
257
		tmp_inode->i_op = &cifs_file_inode_ops;
258 259
		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) {
			if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
260 261 262
				tmp_inode->i_fop = &cifs_file_direct_nobrl_ops;
			else
				tmp_inode->i_fop = &cifs_file_direct_ops;
263
		} else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
264
			tmp_inode->i_fop = &cifs_file_nobrl_ops;
L
Linus Torvalds 已提交
265 266
		else
			tmp_inode->i_fop = &cifs_file_ops;
267

268
		if ((cifs_sb->tcon) && (cifs_sb->tcon->ses) &&
269
		   (cifs_sb->tcon->ses->server->maxBuf <
D
Dave Kleikamp 已提交
270 271 272 273 274
			PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE))
			tmp_inode->i_data.a_ops = &cifs_addr_ops_smallbuf;
		else
			tmp_inode->i_data.a_ops = &cifs_addr_ops;

275
		if (isNewInode)
276 277 278
			return; /* No sense invalidating pages for new inode
				   since have not started caching readahead file
				   data yet */
S
Steve French 已提交
279 280 281 282 283 284 285 286 287

		if (timespec_equal(&tmp_inode->i_mtime, &local_mtime) &&
			(local_size == tmp_inode->i_size)) {
			cFYI(1, ("inode exists but unchanged"));
		} else {
			/* file may have changed on server */
			cFYI(1, ("invalidate inode, readdir detected change"));
			invalidate_remote_inode(tmp_inode);
		}
L
Linus Torvalds 已提交
288
	} else if (S_ISDIR(tmp_inode->i_mode)) {
S
Steve French 已提交
289
		cFYI(1, ("Directory inode"));
L
Linus Torvalds 已提交
290 291 292
		tmp_inode->i_op = &cifs_dir_inode_ops;
		tmp_inode->i_fop = &cifs_dir_ops;
	} else if (S_ISLNK(tmp_inode->i_mode)) {
S
Steve French 已提交
293
		cFYI(1, ("Symbolic Link inode"));
L
Linus Torvalds 已提交
294 295
		tmp_inode->i_op = &cifs_symlink_inode_ops;
	} else {
S
Steve French 已提交
296
		cFYI(1, ("Init special inode"));
L
Linus Torvalds 已提交
297 298 299 300 301 302
		init_special_inode(tmp_inode, tmp_inode->i_mode,
				   tmp_inode->i_rdev);
	}
}

static void unix_fill_in_inode(struct inode *tmp_inode,
S
Steve French 已提交
303
	FILE_UNIX_INFO *pfindData, unsigned int *pobject_type, int isNewInode)
L
Linus Torvalds 已提交
304
{
S
Steve French 已提交
305 306 307
	loff_t local_size;
	struct timespec local_mtime;

L
Linus Torvalds 已提交
308 309 310 311 312 313 314 315 316
	struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode);
	struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb);

	__u32 type = le32_to_cpu(pfindData->Type);
	__u64 num_of_bytes = le64_to_cpu(pfindData->NumOfBytes);
	__u64 end_of_file = le64_to_cpu(pfindData->EndOfFile);
	cifsInfo->time = jiffies;
	atomic_inc(&cifsInfo->inUse);

S
Steve French 已提交
317 318 319 320
	/* save mtime and size */
	local_mtime = tmp_inode->i_mtime;
	local_size  = tmp_inode->i_size;

L
Linus Torvalds 已提交
321
	tmp_inode->i_atime =
322
	    cifs_NTtimeToUnix(pfindData->LastAccessTime);
L
Linus Torvalds 已提交
323
	tmp_inode->i_mtime =
324
	    cifs_NTtimeToUnix(pfindData->LastModificationTime);
L
Linus Torvalds 已提交
325
	tmp_inode->i_ctime =
326
	    cifs_NTtimeToUnix(pfindData->LastStatusChange);
L
Linus Torvalds 已提交
327 328

	tmp_inode->i_mode = le64_to_cpu(pfindData->Permissions);
329
	/* since we set the inode type below we need to mask off type
S
Steve French 已提交
330 331
	   to avoid strange results if bits above were corrupt */
	tmp_inode->i_mode &= ~S_IFMT;
L
Linus Torvalds 已提交
332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356
	if (type == UNIX_FILE) {
		*pobject_type = DT_REG;
		tmp_inode->i_mode |= S_IFREG;
	} else if (type == UNIX_SYMLINK) {
		*pobject_type = DT_LNK;
		tmp_inode->i_mode |= S_IFLNK;
	} else if (type == UNIX_DIR) {
		*pobject_type = DT_DIR;
		tmp_inode->i_mode |= S_IFDIR;
	} else if (type == UNIX_CHARDEV) {
		*pobject_type = DT_CHR;
		tmp_inode->i_mode |= S_IFCHR;
		tmp_inode->i_rdev = MKDEV(le64_to_cpu(pfindData->DevMajor),
				le64_to_cpu(pfindData->DevMinor) & MINORMASK);
	} else if (type == UNIX_BLOCKDEV) {
		*pobject_type = DT_BLK;
		tmp_inode->i_mode |= S_IFBLK;
		tmp_inode->i_rdev = MKDEV(le64_to_cpu(pfindData->DevMajor),
				le64_to_cpu(pfindData->DevMinor) & MINORMASK);
	} else if (type == UNIX_FIFO) {
		*pobject_type = DT_FIFO;
		tmp_inode->i_mode |= S_IFIFO;
	} else if (type == UNIX_SOCKET) {
		*pobject_type = DT_SOCK;
		tmp_inode->i_mode |= S_IFSOCK;
357 358 359 360
	} else {
		/* safest to just call it a file */
		*pobject_type = DT_REG;
		tmp_inode->i_mode |= S_IFREG;
S
Steve French 已提交
361
		cFYI(1, ("unknown inode type %d", type));
L
Linus Torvalds 已提交
362 363
	}

364 365 366 367 368 369 370 371
	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID)
		tmp_inode->i_uid = cifs_sb->mnt_uid;
	else
		tmp_inode->i_uid = le64_to_cpu(pfindData->Uid);
	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID)
		tmp_inode->i_gid = cifs_sb->mnt_gid;
	else
		tmp_inode->i_gid = le64_to_cpu(pfindData->Gid);
L
Linus Torvalds 已提交
372 373
	tmp_inode->i_nlink = le64_to_cpu(pfindData->Nlinks);

374
	cifsInfo->server_eof = end_of_file;
375
	spin_lock(&tmp_inode->i_lock);
376
	if (is_size_safe_to_change(cifsInfo, end_of_file)) {
S
Steve French 已提交
377
		/* can not safely change the file size here if the
L
Linus Torvalds 已提交
378
		client is writing to it due to potential races */
379
		i_size_write(tmp_inode, end_of_file);
L
Linus Torvalds 已提交
380 381 382 383 384

	/* 512 bytes (2**9) is the fake blocksize that must be used */
	/* for this calculation, not the real blocksize */
		tmp_inode->i_blocks = (512 - 1 + num_of_bytes) >> 9;
	}
385
	spin_unlock(&tmp_inode->i_lock);
L
Linus Torvalds 已提交
386 387 388 389

	if (S_ISREG(tmp_inode->i_mode)) {
		cFYI(1, ("File inode"));
		tmp_inode->i_op = &cifs_file_inode_ops;
390

391 392
		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) {
			if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
393 394 395
				tmp_inode->i_fop = &cifs_file_direct_nobrl_ops;
			else
				tmp_inode->i_fop = &cifs_file_direct_ops;
396
		} else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
397
			tmp_inode->i_fop = &cifs_file_nobrl_ops;
L
Linus Torvalds 已提交
398 399
		else
			tmp_inode->i_fop = &cifs_file_ops;
400

401
		if ((cifs_sb->tcon) && (cifs_sb->tcon->ses) &&
S
Steve French 已提交
402
		   (cifs_sb->tcon->ses->server->maxBuf <
D
Dave Kleikamp 已提交
403 404 405 406
			PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE))
			tmp_inode->i_data.a_ops = &cifs_addr_ops_smallbuf;
		else
			tmp_inode->i_data.a_ops = &cifs_addr_ops;
S
Steve French 已提交
407

408
		if (isNewInode)
S
Steve French 已提交
409 410 411
			return; /* No sense invalidating pages for new inode
				   since we have not started caching readahead
				   file data for it yet */
S
Steve French 已提交
412 413 414 415 416 417 418 419 420

		if (timespec_equal(&tmp_inode->i_mtime, &local_mtime) &&
			(local_size == tmp_inode->i_size)) {
			cFYI(1, ("inode exists but unchanged"));
		} else {
			/* file may have changed on server */
			cFYI(1, ("invalidate inode, readdir detected change"));
			invalidate_remote_inode(tmp_inode);
		}
L
Linus Torvalds 已提交
421 422 423 424 425 426 427 428 429
	} else if (S_ISDIR(tmp_inode->i_mode)) {
		cFYI(1, ("Directory inode"));
		tmp_inode->i_op = &cifs_dir_inode_ops;
		tmp_inode->i_fop = &cifs_dir_ops;
	} else if (S_ISLNK(tmp_inode->i_mode)) {
		cFYI(1, ("Symbolic Link inode"));
		tmp_inode->i_op = &cifs_symlink_inode_ops;
/* tmp_inode->i_fop = *//* do not need to set to anything */
	} else {
S
Steve French 已提交
430
		cFYI(1, ("Special inode"));
L
Linus Torvalds 已提交
431 432 433 434 435
		init_special_inode(tmp_inode, tmp_inode->i_mode,
				   tmp_inode->i_rdev);
	}
}

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
/* 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)) {
			cFYI(1, ("Error closing temporary reparsepoint open)"));
		}
	}
}
 */

L
Linus Torvalds 已提交
468 469 470
static int initiate_cifs_search(const int xid, struct file *file)
{
	int rc = 0;
S
Steve French 已提交
471 472
	char *full_path;
	struct cifsFileInfo *cifsFile;
L
Linus Torvalds 已提交
473 474 475
	struct cifs_sb_info *cifs_sb;
	struct cifsTconInfo *pTcon;

476
	if (file->private_data == NULL) {
S
Steve French 已提交
477 478
		file->private_data =
			kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
L
Linus Torvalds 已提交
479 480
	}

481
	if (file->private_data == NULL)
L
Linus Torvalds 已提交
482 483
		return -ENOMEM;
	cifsFile = file->private_data;
484 485
	cifsFile->invalidHandle = true;
	cifsFile->srch_inf.endOfSearch = false;
L
Linus Torvalds 已提交
486

487
	cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
488
	if (cifs_sb == NULL)
L
Linus Torvalds 已提交
489 490 491
		return -EINVAL;

	pTcon = cifs_sb->tcon;
492
	if (pTcon == NULL)
L
Linus Torvalds 已提交
493 494
		return -EINVAL;

495
	full_path = build_path_from_dentry(file->f_path.dentry);
L
Linus Torvalds 已提交
496

S
Steve French 已提交
497
	if (full_path == NULL)
L
Linus Torvalds 已提交
498 499
		return -ENOMEM;

S
Steve French 已提交
500
	cFYI(1, ("Full path: %s start at: %lld", full_path, file->f_pos));
L
Linus Torvalds 已提交
501

502
ffirst_retry:
L
Linus Torvalds 已提交
503
	/* test for Unix extensions */
504 505
	/* but now check for them on the share/mount not on the SMB session */
/*	if (pTcon->ses->capabilities & CAP_UNIX) { */
S
Steve French 已提交
506
	if (pTcon->unix_ext)
507
		cifsFile->srch_inf.info_level = SMB_FIND_FILE_UNIX;
S
Steve French 已提交
508
	else if ((pTcon->ses->capabilities &
509 510
			(CAP_NT_SMBS | CAP_NT_FIND)) == 0) {
		cifsFile->srch_inf.info_level = SMB_FIND_FILE_INFO_STANDARD;
L
Linus Torvalds 已提交
511 512 513 514 515 516
	} 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;
	}

S
Steve French 已提交
517
	rc = CIFSFindFirst(xid, pTcon, full_path, cifs_sb->local_nls,
518
		&cifsFile->netfid, &cifsFile->srch_inf,
S
Steve French 已提交
519
		cifs_sb->mnt_cifs_flags &
520
			CIFS_MOUNT_MAP_SPECIAL_CHR, CIFS_DIR_SEP(cifs_sb));
521
	if (rc == 0)
522
		cifsFile->invalidHandle = false;
S
Steve French 已提交
523
	/* BB add following call to handle readdir on new NTFS symlink errors
524 525 526
	else if STATUS_STOPPED_ON_SYMLINK
		call get_symlink_reparse_path and retry with new path */
	else if ((rc == -EOPNOTSUPP) &&
527 528 529 530
		(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)) {
		cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_SERVER_INUM;
		goto ffirst_retry;
	}
L
Linus Torvalds 已提交
531 532 533 534 535 536 537 538
	kfree(full_path);
	return rc;
}

/* return length of unicode string in bytes */
static int cifs_unicode_bytelen(char *str)
{
	int len;
539
	__le16 *ustr = (__le16 *)str;
L
Linus Torvalds 已提交
540

S
Steve French 已提交
541
	for (len = 0; len <= PATH_MAX; len++) {
542
		if (ustr[len] == 0)
L
Linus Torvalds 已提交
543 544
			return len << 1;
	}
S
Steve French 已提交
545
	cFYI(1, ("Unicode string longer than PATH_MAX found"));
L
Linus Torvalds 已提交
546 547 548
	return len << 1;
}

549
static char *nxt_dir_entry(char *old_entry, char *end_of_smb, int level)
L
Linus Torvalds 已提交
550
{
S
Steve French 已提交
551
	char *new_entry;
S
Steve French 已提交
552
	FILE_DIRECTORY_INFO *pDirInfo = (FILE_DIRECTORY_INFO *)old_entry;
L
Linus Torvalds 已提交
553

554
	if (level == SMB_FIND_FILE_INFO_STANDARD) {
S
Steve French 已提交
555
		FIND_FILE_STANDARD_INFO *pfData;
556 557 558 559 560 561
		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);
S
Steve French 已提交
562
	cFYI(1, ("new entry %p old entry %p", new_entry, old_entry));
L
Linus Torvalds 已提交
563
	/* validate that new_entry is not past end of SMB */
564
	if (new_entry >= end_of_smb) {
565 566
		cERROR(1,
		      ("search entry %p began after end of SMB %p old entry %p",
S
Steve French 已提交
567
			new_entry, end_of_smb, old_entry));
L
Linus Torvalds 已提交
568
		return NULL;
569
	} else if (((level == SMB_FIND_FILE_INFO_STANDARD) &&
S
Steve French 已提交
570 571
		    (new_entry + sizeof(FIND_FILE_STANDARD_INFO) > end_of_smb))
		  || ((level != SMB_FIND_FILE_INFO_STANDARD) &&
572
		   (new_entry + sizeof(FILE_DIRECTORY_INFO) > end_of_smb)))  {
S
Steve French 已提交
573
		cERROR(1, ("search entry %p extends after end of SMB %p",
574 575
			new_entry, end_of_smb));
		return NULL;
S
Steve French 已提交
576
	} else
L
Linus Torvalds 已提交
577 578 579 580 581 582 583 584 585 586
		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;
S
Steve French 已提交
587 588
	char *filename = NULL;
	int len = 0;
L
Linus Torvalds 已提交
589

590
	if (cfile->srch_inf.info_level == SMB_FIND_FILE_UNIX) {
S
Steve French 已提交
591
		FILE_UNIX_INFO *pFindData = (FILE_UNIX_INFO *)current_entry;
L
Linus Torvalds 已提交
592
		filename = &pFindData->FileName[0];
593
		if (cfile->srch_inf.unicode) {
L
Linus Torvalds 已提交
594 595 596 597 598
			len = cifs_unicode_bytelen(filename);
		} else {
			/* BB should we make this strnlen of PATH_MAX? */
			len = strnlen(filename, 5);
		}
599
	} else if (cfile->srch_inf.info_level == SMB_FIND_FILE_DIRECTORY_INFO) {
S
Steve French 已提交
600
		FILE_DIRECTORY_INFO *pFindData =
L
Linus Torvalds 已提交
601 602 603
			(FILE_DIRECTORY_INFO *)current_entry;
		filename = &pFindData->FileName[0];
		len = le32_to_cpu(pFindData->FileNameLength);
S
Steve French 已提交
604
	} else if (cfile->srch_inf.info_level ==
605
			SMB_FIND_FILE_FULL_DIRECTORY_INFO) {
S
Steve French 已提交
606
		FILE_FULL_DIRECTORY_INFO *pFindData =
L
Linus Torvalds 已提交
607 608 609
			(FILE_FULL_DIRECTORY_INFO *)current_entry;
		filename = &pFindData->FileName[0];
		len = le32_to_cpu(pFindData->FileNameLength);
610
	} else if (cfile->srch_inf.info_level ==
611
			SMB_FIND_FILE_ID_FULL_DIR_INFO) {
S
Steve French 已提交
612
		SEARCH_ID_FULL_DIR_INFO *pFindData =
L
Linus Torvalds 已提交
613 614 615
			(SEARCH_ID_FULL_DIR_INFO *)current_entry;
		filename = &pFindData->FileName[0];
		len = le32_to_cpu(pFindData->FileNameLength);
S
Steve French 已提交
616
	} else if (cfile->srch_inf.info_level ==
617
			SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
S
Steve French 已提交
618
		FILE_BOTH_DIRECTORY_INFO *pFindData =
L
Linus Torvalds 已提交
619 620 621
			(FILE_BOTH_DIRECTORY_INFO *)current_entry;
		filename = &pFindData->FileName[0];
		len = le32_to_cpu(pFindData->FileNameLength);
622
	} else if (cfile->srch_inf.info_level == SMB_FIND_FILE_INFO_STANDARD) {
S
Steve French 已提交
623
		FIND_FILE_STANDARD_INFO *pFindData =
624 625
			(FIND_FILE_STANDARD_INFO *)current_entry;
		filename = &pFindData->FileName[0];
626
		len = pFindData->FileNameLength;
L
Linus Torvalds 已提交
627
	} else {
S
Steve French 已提交
628 629
		cFYI(1, ("Unknown findfirst level %d",
			 cfile->srch_inf.info_level));
L
Linus Torvalds 已提交
630 631
	}

632 633
	if (filename) {
		if (cfile->srch_inf.unicode) {
L
Linus Torvalds 已提交
634
			__le16 *ufilename = (__le16 *)filename;
635
			if (len == 2) {
L
Linus Torvalds 已提交
636
				/* check for . */
637
				if (ufilename[0] == UNICODE_DOT)
L
Linus Torvalds 已提交
638
					rc = 1;
639
			} else if (len == 4) {
L
Linus Torvalds 已提交
640
				/* check for .. */
641
				if ((ufilename[0] == UNICODE_DOT)
S
Steve French 已提交
642
				   && (ufilename[1] == UNICODE_DOT))
L
Linus Torvalds 已提交
643 644 645
					rc = 2;
			}
		} else /* ASCII */ {
646
			if (len == 1) {
S
Steve French 已提交
647
				if (filename[0] == '.')
L
Linus Torvalds 已提交
648
					rc = 1;
649
			} else if (len == 2) {
S
Steve French 已提交
650
				if ((filename[0] == '.') && (filename[1] == '.'))
L
Linus Torvalds 已提交
651 652 653 654 655 656 657 658
					rc = 2;
			}
		}
	}

	return rc;
}

659 660
/* 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 */
S
Steve French 已提交
661
static int is_dir_changed(struct file *file)
662
{
663 664
	struct inode *inode = file->f_path.dentry->d_inode;
	struct cifsInodeInfo *cifsInfo = CIFS_I(inode);
665

666
	if (cifsInfo->time == 0)
667 668 669 670 671 672
		return 1; /* directory was changed, perhaps due to unlink */
	else
		return 0;

}

673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736
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 {
		cFYI(1, ("Unknown findfirst level %d", level));
		return -EINVAL;
	}
	cifsFile->srch_inf.resume_name_len = len;
	cifsFile->srch_inf.presume_name = filename;
	return rc;
}

L
Linus Torvalds 已提交
737 738 739 740 741 742 743
/* 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,
S
Steve French 已提交
744
	struct file *file, char **ppCurrentEntry, int *num_to_ret)
L
Linus Torvalds 已提交
745 746 747 748 749
{
	int rc = 0;
	int pos_in_buf = 0;
	loff_t first_entry_in_buffer;
	loff_t index_to_find = file->f_pos;
S
Steve French 已提交
750
	struct cifsFileInfo *cifsFile = file->private_data;
L
Linus Torvalds 已提交
751
	/* check if index in the buffer */
752

S
Steve French 已提交
753
	if ((cifsFile == NULL) || (ppCurrentEntry == NULL) ||
754
	   (num_to_ret == NULL))
L
Linus Torvalds 已提交
755
		return -ENOENT;
756

L
Linus Torvalds 已提交
757
	*ppCurrentEntry = NULL;
S
Steve French 已提交
758 759
	first_entry_in_buffer =
		cifsFile->srch_inf.index_of_last_entry -
L
Linus Torvalds 已提交
760
			cifsFile->srch_inf.entries_in_buffer;
761 762 763 764 765 766 767

	/* 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 */

768
	dump_cifs_file_struct(file, "In fce ");
S
Steve French 已提交
769 770
	if (((index_to_find < cifsFile->srch_inf.index_of_last_entry) &&
	     is_dir_changed(file)) ||
771
	   (index_to_find < first_entry_in_buffer)) {
L
Linus Torvalds 已提交
772
		/* close and restart search */
S
Steve French 已提交
773
		cFYI(1, ("search backing up - close and restart search"));
774
		write_lock(&GlobalSMBSeslock);
775 776 777
		if (!cifsFile->srch_inf.endOfSearch &&
		    !cifsFile->invalidHandle) {
			cifsFile->invalidHandle = true;
778
			write_unlock(&GlobalSMBSeslock);
779
			CIFSFindClose(xid, pTcon, cifsFile->netfid);
780 781
		} else
			write_unlock(&GlobalSMBSeslock);
782
		if (cifsFile->srch_inf.ntwrk_buf_start) {
S
Steve French 已提交
783
			cFYI(1, ("freeing SMB ff cache buf on search rewind"));
784
			if (cifsFile->srch_inf.smallBuf)
785 786 787 788 789
				cifs_small_buf_release(cifsFile->srch_inf.
						ntwrk_buf_start);
			else
				cifs_buf_release(cifsFile->srch_inf.
						ntwrk_buf_start);
790
			cifsFile->srch_inf.ntwrk_buf_start = NULL;
L
Linus Torvalds 已提交
791
		}
S
Steve French 已提交
792
		rc = initiate_cifs_search(xid, file);
793
		if (rc) {
S
Steve French 已提交
794 795
			cFYI(1, ("error %d reinitiating a search on rewind",
				 rc));
L
Linus Torvalds 已提交
796 797
			return rc;
		}
798
		cifs_save_resume_key(cifsFile->srch_inf.last_entry, cifsFile);
L
Linus Torvalds 已提交
799 800
	}

S
Steve French 已提交
801
	while ((index_to_find >= cifsFile->srch_inf.index_of_last_entry) &&
802
	      (rc == 0) && !cifsFile->srch_inf.endOfSearch) {
S
Steve French 已提交
803
		cFYI(1, ("calling findnext2"));
S
Steve French 已提交
804
		rc = CIFSFindNext(xid, pTcon, cifsFile->netfid,
805
				  &cifsFile->srch_inf);
806
		cifs_save_resume_key(cifsFile->srch_inf.last_entry, cifsFile);
807
		if (rc)
L
Linus Torvalds 已提交
808 809
			return -ENOENT;
	}
810
	if (index_to_find < cifsFile->srch_inf.index_of_last_entry) {
L
Linus Torvalds 已提交
811 812 813
		/* we found the buffer that contains the entry */
		/* scan and find it */
		int i;
S
Steve French 已提交
814 815
		char *current_entry;
		char *end_of_smb = cifsFile->srch_inf.ntwrk_buf_start +
L
Linus Torvalds 已提交
816 817
			smbCalcSize((struct smb_hdr *)
				cifsFile->srch_inf.ntwrk_buf_start);
818 819

		current_entry = cifsFile->srch_inf.srch_entries_start;
L
Linus Torvalds 已提交
820 821 822
		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;
S
Steve French 已提交
823
		cFYI(1, ("found entry - pos_in_buf %d", pos_in_buf));
824

S
Steve French 已提交
825
		for (i = 0; (i < (pos_in_buf)) && (current_entry != NULL); i++) {
826
			/* go entry by entry figuring out which is first */
S
Steve French 已提交
827
			current_entry = nxt_dir_entry(current_entry, end_of_smb,
828
						cifsFile->srch_inf.info_level);
L
Linus Torvalds 已提交
829
		}
S
Steve French 已提交
830
		if ((current_entry == NULL) && (i < pos_in_buf)) {
L
Linus Torvalds 已提交
831
			/* BB fixme - check if we should flag this error */
S
Steve French 已提交
832
			cERROR(1, ("reached end of buf searching for pos in buf"
L
Linus Torvalds 已提交
833
			  " %d index to find %lld rc %d",
S
Steve French 已提交
834
			  pos_in_buf, index_to_find, rc));
L
Linus Torvalds 已提交
835 836 837 838
		}
		rc = 0;
		*ppCurrentEntry = current_entry;
	} else {
S
Steve French 已提交
839
		cFYI(1, ("index not in buffer - could not findnext into it"));
L
Linus Torvalds 已提交
840 841 842
		return 0;
	}

S
Steve French 已提交
843 844
	if (pos_in_buf >= cifsFile->srch_inf.entries_in_buffer) {
		cFYI(1, ("can not return entries pos_in_buf beyond last"));
L
Linus Torvalds 已提交
845 846 847 848 849 850 851 852 853 854
		*num_to_ret = 0;
	} else
		*num_to_ret = cifsFile->srch_inf.entries_in_buffer - pos_in_buf;

	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,
855
	struct cifs_sb_info *cifs_sb, unsigned int max_len, __u64 *pinum)
L
Linus Torvalds 已提交
856 857 858
{
	int rc = 0;
	unsigned int len = 0;
S
Steve French 已提交
859 860
	char *filename;
	struct nls_table *nlt = cifs_sb->local_nls;
L
Linus Torvalds 已提交
861 862 863

	*pinum = 0;

S
Steve French 已提交
864
	if (level == SMB_FIND_FILE_UNIX) {
S
Steve French 已提交
865
		FILE_UNIX_INFO *pFindData = (FILE_UNIX_INFO *)current_entry;
L
Linus Torvalds 已提交
866 867

		filename = &pFindData->FileName[0];
S
Steve French 已提交
868
		if (unicode) {
L
Linus Torvalds 已提交
869 870 871 872 873 874
			len = cifs_unicode_bytelen(filename);
		} else {
			/* BB should we make this strnlen of PATH_MAX? */
			len = strnlen(filename, PATH_MAX);
		}

875
		*pinum = le64_to_cpu(pFindData->UniqueId);
S
Steve French 已提交
876
	} else if (level == SMB_FIND_FILE_DIRECTORY_INFO) {
S
Steve French 已提交
877
		FILE_DIRECTORY_INFO *pFindData =
L
Linus Torvalds 已提交
878 879 880
			(FILE_DIRECTORY_INFO *)current_entry;
		filename = &pFindData->FileName[0];
		len = le32_to_cpu(pFindData->FileNameLength);
S
Steve French 已提交
881
	} else if (level == SMB_FIND_FILE_FULL_DIRECTORY_INFO) {
S
Steve French 已提交
882
		FILE_FULL_DIRECTORY_INFO *pFindData =
L
Linus Torvalds 已提交
883 884 885
			(FILE_FULL_DIRECTORY_INFO *)current_entry;
		filename = &pFindData->FileName[0];
		len = le32_to_cpu(pFindData->FileNameLength);
S
Steve French 已提交
886
	} else if (level == SMB_FIND_FILE_ID_FULL_DIR_INFO) {
S
Steve French 已提交
887
		SEARCH_ID_FULL_DIR_INFO *pFindData =
L
Linus Torvalds 已提交
888 889 890
			(SEARCH_ID_FULL_DIR_INFO *)current_entry;
		filename = &pFindData->FileName[0];
		len = le32_to_cpu(pFindData->FileNameLength);
891
		*pinum = le64_to_cpu(pFindData->UniqueId);
S
Steve French 已提交
892
	} else if (level == SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
S
Steve French 已提交
893
		FILE_BOTH_DIRECTORY_INFO *pFindData =
L
Linus Torvalds 已提交
894 895 896
			(FILE_BOTH_DIRECTORY_INFO *)current_entry;
		filename = &pFindData->FileName[0];
		len = le32_to_cpu(pFindData->FileNameLength);
S
Steve French 已提交
897
	} else if (level == SMB_FIND_FILE_INFO_STANDARD) {
S
Steve French 已提交
898
		FIND_FILE_STANDARD_INFO *pFindData =
899 900 901 902
			(FIND_FILE_STANDARD_INFO *)current_entry;
		filename = &pFindData->FileName[0];
		/* one byte length, no name conversion */
		len = (unsigned int)pFindData->FileNameLength;
L
Linus Torvalds 已提交
903
	} else {
S
Steve French 已提交
904
		cFYI(1, ("Unknown findfirst level %d", level));
L
Linus Torvalds 已提交
905 906
		return -EINVAL;
	}
907

S
Steve French 已提交
908
	if (len > max_len) {
S
Steve French 已提交
909
		cERROR(1, ("bad search response length %d past smb end", len));
910 911 912
		return -EINVAL;
	}

S
Steve French 已提交
913
	if (unicode) {
914 915
		pqst->len = cifs_from_ucs2((char *) pqst->name,
					   (__le16 *) filename,
916 917
					   UNICODE_NAME_MAX,
					   min(len, max_len), nlt,
918 919
					   cifs_sb->mnt_cifs_flags &
						CIFS_MOUNT_MAP_SPECIAL_CHR);
L
Linus Torvalds 已提交
920 921 922 923
	} else {
		pqst->name = filename;
		pqst->len = len;
	}
S
Steve French 已提交
924
	pqst->hash = full_name_hash(pqst->name, pqst->len);
S
Steve French 已提交
925
/*	cFYI(1, ("filldir on %s",pqst->name));  */
L
Linus Torvalds 已提交
926 927 928
	return rc;
}

929 930
static int cifs_filldir(char *pfindEntry, struct file *file, filldir_t filldir,
			void *direntry, char *scratch_buf, unsigned int max_len)
L
Linus Torvalds 已提交
931 932 933
{
	int rc = 0;
	struct qstr qstring;
S
Steve French 已提交
934
	struct cifsFileInfo *pCifsF;
S
Steve French 已提交
935
	unsigned int obj_type;
936
	__u64  inum;
S
Steve French 已提交
937
	struct cifs_sb_info *cifs_sb;
L
Linus Torvalds 已提交
938 939 940 941 942 943
	struct inode *tmp_inode;
	struct dentry *tmp_dentry;

	/* get filename and len into qstring */
	/* get dentry */
	/* decide whether to create and populate ionde */
S
Steve French 已提交
944
	if ((direntry == NULL) || (file == NULL))
L
Linus Torvalds 已提交
945 946 947
		return -EINVAL;

	pCifsF = file->private_data;
948

S
Steve French 已提交
949
	if ((scratch_buf == NULL) || (pfindEntry == NULL) || (pCifsF == NULL))
L
Linus Torvalds 已提交
950 951
		return -ENOENT;

S
Steve French 已提交
952
	rc = cifs_entry_is_dot(pfindEntry, pCifsF);
953
	/* skip . and .. since we added them first */
S
Steve French 已提交
954
	if (rc != 0)
955 956
		return 0;

957
	cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
L
Linus Torvalds 已提交
958 959

	qstring.name = scratch_buf;
S
Steve French 已提交
960
	rc = cifs_get_name_from_search_buf(&qstring, pfindEntry,
L
Linus Torvalds 已提交
961
			pCifsF->srch_inf.info_level,
S
Steve French 已提交
962
			pCifsF->srch_inf.unicode, cifs_sb,
963
			max_len,
L
Linus Torvalds 已提交
964 965
			&inum /* returned */);

S
Steve French 已提交
966
	if (rc)
L
Linus Torvalds 已提交
967 968
		return rc;

969 970 971 972 973 974 975 976 977
	/* only these two infolevels return valid inode numbers */
	if (pCifsF->srch_inf.info_level == SMB_FIND_FILE_UNIX ||
	    pCifsF->srch_inf.info_level == SMB_FIND_FILE_ID_FULL_DIR_INFO)
		rc = construct_dentry(&qstring, file, &tmp_inode, &tmp_dentry,
					&inum);
	else
		rc = construct_dentry(&qstring, file, &tmp_inode, &tmp_dentry,
					NULL);

S
Steve French 已提交
978
	if ((tmp_inode == NULL) || (tmp_dentry == NULL))
L
Linus Torvalds 已提交
979 980
		return -ENOMEM;

S
Steve French 已提交
981 982 983
	/* we pass in rc below, indicating whether it is a new inode,
	   so we can figure out whether to invalidate the inode cached
	   data if the file has changed */
S
Steve French 已提交
984
	if (pCifsF->srch_inf.info_level == SMB_FIND_FILE_UNIX)
S
Steve French 已提交
985
		unix_fill_in_inode(tmp_inode,
986 987
				   (FILE_UNIX_INFO *)pfindEntry,
				   &obj_type, rc);
S
Steve French 已提交
988
	else if (pCifsF->srch_inf.info_level == SMB_FIND_FILE_INFO_STANDARD)
989 990 991 992
		fill_in_inode(tmp_inode, 0 /* old level 1 buffer type */,
				pfindEntry, &obj_type, rc);
	else
		fill_in_inode(tmp_inode, 1 /* NT */, pfindEntry, &obj_type, rc);
993

S
Steve French 已提交
994
	if (rc) /* new inode - needs to be tied to dentry */ {
995
		d_instantiate(tmp_dentry, tmp_inode);
S
Steve French 已提交
996
		if (rc == 2)
997 998
			d_rehash(tmp_dentry);
	}
999

S
Steve French 已提交
1000 1001 1002

	rc = filldir(direntry, qstring.name, qstring.len, file->f_pos,
		     tmp_inode->i_ino, obj_type);
S
Steve French 已提交
1003 1004
	if (rc) {
		cFYI(1, ("filldir rc = %d", rc));
1005 1006 1007 1008
		/* 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 */
		rc = -EOVERFLOW;
L
Linus Torvalds 已提交
1009 1010 1011 1012 1013 1014 1015 1016 1017 1018
	}

	dput(tmp_dentry);
	return rc;
}


int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
{
	int rc = 0;
S
Steve French 已提交
1019
	int xid, i;
L
Linus Torvalds 已提交
1020 1021 1022
	struct cifs_sb_info *cifs_sb;
	struct cifsTconInfo *pTcon;
	struct cifsFileInfo *cifsFile = NULL;
S
Steve French 已提交
1023
	char *current_entry;
L
Linus Torvalds 已提交
1024
	int num_to_fill = 0;
S
Steve French 已提交
1025
	char *tmp_buf = NULL;
1026
	char *end_of_smb;
1027
	unsigned int max_len;
L
Linus Torvalds 已提交
1028 1029 1030

	xid = GetXid();

1031
	cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
L
Linus Torvalds 已提交
1032
	pTcon = cifs_sb->tcon;
S
Steve French 已提交
1033
	if (pTcon == NULL)
L
Linus Torvalds 已提交
1034 1035 1036 1037
		return -EINVAL;

	switch ((int) file->f_pos) {
	case 0:
1038
		if (filldir(direntry, ".", 1, file->f_pos,
1039
		     file->f_path.dentry->d_inode->i_ino, DT_DIR) < 0) {
1040
			cERROR(1, ("Filldir for current dir failed"));
L
Linus Torvalds 已提交
1041 1042 1043
			rc = -ENOMEM;
			break;
		}
1044
		file->f_pos++;
L
Linus Torvalds 已提交
1045
	case 1:
1046
		if (filldir(direntry, "..", 2, file->f_pos,
1047
		     file->f_path.dentry->d_parent->d_inode->i_ino, DT_DIR) < 0) {
1048
			cERROR(1, ("Filldir for parent dir failed"));
L
Linus Torvalds 已提交
1049 1050 1051
			rc = -ENOMEM;
			break;
		}
1052 1053
		file->f_pos++;
	default:
S
Steve French 已提交
1054 1055
		/* 1) If search is active,
			is in current search buffer?
L
Linus Torvalds 已提交
1056 1057 1058
			if it before then restart search
			if after then keep searching till find it */

S
Steve French 已提交
1059
		if (file->private_data == NULL) {
S
Steve French 已提交
1060
			rc = initiate_cifs_search(xid, file);
S
Steve French 已提交
1061 1062
			cFYI(1, ("initiate cifs search rc %d", rc));
			if (rc) {
L
Linus Torvalds 已提交
1063 1064 1065 1066
				FreeXid(xid);
				return rc;
			}
		}
S
Steve French 已提交
1067
		if (file->private_data == NULL) {
L
Linus Torvalds 已提交
1068 1069 1070 1071 1072 1073
			rc = -EINVAL;
			FreeXid(xid);
			return rc;
		}
		cifsFile = file->private_data;
		if (cifsFile->srch_inf.endOfSearch) {
S
Steve French 已提交
1074
			if (cifsFile->srch_inf.emptyDir) {
L
Linus Torvalds 已提交
1075 1076 1077 1078 1079
				cFYI(1, ("End of search, empty dir"));
				rc = 0;
				break;
			}
		} /* else {
1080
			cifsFile->invalidHandle = true;
L
Linus Torvalds 已提交
1081
			CIFSFindClose(xid, pTcon, cifsFile->netfid);
S
Steve French 已提交
1082
		} */
L
Linus Torvalds 已提交
1083

S
Steve French 已提交
1084 1085
		rc = find_cifs_entry(xid, pTcon, file,
				&current_entry, &num_to_fill);
S
Steve French 已提交
1086 1087
		if (rc) {
			cFYI(1, ("fce error %d", rc));
L
Linus Torvalds 已提交
1088 1089
			goto rddir2_exit;
		} else if (current_entry != NULL) {
S
Steve French 已提交
1090
			cFYI(1, ("entry %lld found", file->f_pos));
L
Linus Torvalds 已提交
1091
		} else {
S
Steve French 已提交
1092
			cFYI(1, ("could not find entry"));
L
Linus Torvalds 已提交
1093 1094
			goto rddir2_exit;
		}
S
Steve French 已提交
1095 1096
		cFYI(1, ("loop through %d times filling dir for net buf %p",
			num_to_fill, cifsFile->srch_inf.ntwrk_buf_start));
1097 1098 1099 1100
		max_len = smbCalcSize((struct smb_hdr *)
				cifsFile->srch_inf.ntwrk_buf_start);
		end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + max_len;

1101
		tmp_buf = kmalloc(UNICODE_NAME_MAX, GFP_KERNEL);
S
Steve French 已提交
1102 1103
		for (i = 0; (i < num_to_fill) && (rc == 0); i++) {
			if (current_entry == NULL) {
L
Linus Torvalds 已提交
1104
				/* evaluate whether this case is an error */
1105
				cERROR(1, ("past SMB end,  num to fill %d i %d",
L
Linus Torvalds 已提交
1106 1107 1108
					  num_to_fill, i));
				break;
			}
1109 1110
			/* if buggy server returns . and .. late do
			we want to check for that here? */
1111 1112
			rc = cifs_filldir(current_entry, file,
					filldir, direntry, tmp_buf, max_len);
S
Steve French 已提交
1113
			if (rc == -EOVERFLOW) {
1114 1115 1116 1117
				rc = 0;
				break;
			}

L
Linus Torvalds 已提交
1118
			file->f_pos++;
S
Steve French 已提交
1119
			if (file->f_pos ==
1120
				cifsFile->srch_inf.index_of_last_entry) {
S
Steve French 已提交
1121 1122 1123
				cFYI(1, ("last entry in buf at pos %lld %s",
					file->f_pos, tmp_buf));
				cifs_save_resume_key(current_entry, cifsFile);
L
Linus Torvalds 已提交
1124
				break;
S
Steve French 已提交
1125 1126
			} else
				current_entry =
1127 1128
					nxt_dir_entry(current_entry, end_of_smb,
						cifsFile->srch_inf.info_level);
L
Linus Torvalds 已提交
1129 1130 1131 1132 1133 1134 1135 1136 1137
		}
		kfree(tmp_buf);
		break;
	} /* end switch */

rddir2_exit:
	FreeXid(xid);
	return rc;
}