readdir.c 34.9 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;
}

S
Steve French 已提交
118
static void AdjustForTZ(struct cifsTconInfo *tcon, struct inode *inode)
119
{
120
	if ((tcon) && (tcon->ses) && (tcon->ses->server)) {
S
Steve French 已提交
121 122 123
		inode->i_ctime.tv_sec += tcon->ses->server->timeAdj;
		inode->i_mtime.tv_sec += tcon->ses->server->timeAdj;
		inode->i_atime.tv_sec += tcon->ses->server->timeAdj;
124 125 126 127 128
	}
	return;
}


129
static void fill_in_inode(struct inode *tmp_inode, int new_buf_type,
S
Steve French 已提交
130
			  char *buf, unsigned int *pobject_type, int isNewInode)
L
Linus Torvalds 已提交
131
{
S
Steve French 已提交
132 133 134
	loff_t local_size;
	struct timespec local_mtime;

L
Linus Torvalds 已提交
135 136
	struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode);
	struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb);
137 138 139
	__u32 attr;
	__u64 allocation_size;
	__u64 end_of_file;
140
	umode_t default_mode;
L
Linus Torvalds 已提交
141

S
Steve French 已提交
142 143 144 145
	/* save mtime and size */
	local_mtime = tmp_inode->i_mtime;
	local_size  = tmp_inode->i_size;

146
	if (new_buf_type) {
147 148 149 150 151 152 153 154 155 156 157 158
		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 =
		      cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime));
		tmp_inode->i_mtime =
		      cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime));
		tmp_inode->i_ctime =
		      cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime));
	} else { /* legacy, OS2 and DOS style */
159
/*		struct timespec ts;*/
S
Steve French 已提交
160
		FIND_FILE_STANDARD_INFO *pfindData =
161 162
			(FIND_FILE_STANDARD_INFO *)buf;

163
		tmp_inode->i_mtime = cnvrtDosUnixTm(
164
				le16_to_cpu(pfindData->LastWriteDate),
165 166 167 168
				le16_to_cpu(pfindData->LastWriteTime));
		tmp_inode->i_atime = cnvrtDosUnixTm(
				le16_to_cpu(pfindData->LastAccessDate),
				le16_to_cpu(pfindData->LastAccessTime));
S
Steve French 已提交
169 170 171
		tmp_inode->i_ctime = cnvrtDosUnixTm(
				le16_to_cpu(pfindData->LastWriteDate),
				le16_to_cpu(pfindData->LastWriteTime));
172
		AdjustForTZ(cifs_sb->tcon, tmp_inode);
173 174 175 176 177
		attr = le16_to_cpu(pfindData->Attributes);
		allocation_size = le32_to_cpu(pfindData->AllocationSize);
		end_of_file = le32_to_cpu(pfindData->DataSize);
	}

L
Linus Torvalds 已提交
178
	/* Linux can not store file creation time unfortunately so ignore it */
179 180

	cifsInfo->cifsAttrs = attr;
181 182 183 184 185 186 187
#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;
188

L
Linus Torvalds 已提交
189 190
	/* treat dos attribute of read-only as read-only mode bit e.g. 555? */
	/* 2767 perms - indicate mandatory locking */
S
Steve French 已提交
191
		/* BB fill in uid and gid here? with help from winbind?
L
Linus Torvalds 已提交
192 193 194 195
		   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;
196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212
	}

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

213
		tmp_inode->i_mode &= ~S_IFMT;
L
Linus Torvalds 已提交
214 215
	}

216 217 218 219 220 221 222
	/* 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)) {
223 224
		if (end_of_file == 0)  {
			tmp_inode->i_mode |= S_IFIFO;
225
			*pobject_type = DT_FIFO;
226
		} else {
227 228 229 230
			/*
			 * trying to get the type can be slow, so just call
			 * this a regular file for now, and mark for reval
			 */
S
Steve French 已提交
231
			tmp_inode->i_mode |= S_IFREG;
232
			*pobject_type = DT_REG;
S
Steve French 已提交
233
			cifsInfo->time = 0;
234
		}
L
Linus Torvalds 已提交
235
	} else {
236 237 238 239 240 241 242 243
		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 已提交
244 245

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

249
	cifsInfo->server_eof = end_of_file;
250
	spin_lock(&tmp_inode->i_lock);
251
	if (is_size_safe_to_change(cifsInfo, end_of_file)) {
S
Steve French 已提交
252
		/* can not safely change the file size here if the
L
Linus Torvalds 已提交
253 254 255 256 257 258 259
		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;
	}
260
	spin_unlock(&tmp_inode->i_lock);
L
Linus Torvalds 已提交
261 262 263

	if (allocation_size < end_of_file)
		cFYI(1, ("May be sparse file, allocation less than file size"));
264
	cFYI(1, ("File Size %ld and blocks %llu",
265
		(unsigned long)tmp_inode->i_size,
266
		(unsigned long long)tmp_inode->i_blocks));
L
Linus Torvalds 已提交
267
	if (S_ISREG(tmp_inode->i_mode)) {
S
Steve French 已提交
268
		cFYI(1, ("File inode"));
L
Linus Torvalds 已提交
269
		tmp_inode->i_op = &cifs_file_inode_ops;
270 271
		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) {
			if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
272 273 274
				tmp_inode->i_fop = &cifs_file_direct_nobrl_ops;
			else
				tmp_inode->i_fop = &cifs_file_direct_ops;
275
		} else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
276
			tmp_inode->i_fop = &cifs_file_nobrl_ops;
L
Linus Torvalds 已提交
277 278
		else
			tmp_inode->i_fop = &cifs_file_ops;
279

280
		if ((cifs_sb->tcon) && (cifs_sb->tcon->ses) &&
281
		   (cifs_sb->tcon->ses->server->maxBuf <
D
Dave Kleikamp 已提交
282 283 284 285 286
			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;

287
		if (isNewInode)
288 289 290
			return; /* No sense invalidating pages for new inode
				   since have not started caching readahead file
				   data yet */
S
Steve French 已提交
291 292 293 294 295 296 297 298 299

		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 已提交
300
	} else if (S_ISDIR(tmp_inode->i_mode)) {
S
Steve French 已提交
301
		cFYI(1, ("Directory inode"));
L
Linus Torvalds 已提交
302 303 304
		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 已提交
305
		cFYI(1, ("Symbolic Link inode"));
L
Linus Torvalds 已提交
306 307
		tmp_inode->i_op = &cifs_symlink_inode_ops;
	} else {
S
Steve French 已提交
308
		cFYI(1, ("Init special inode"));
L
Linus Torvalds 已提交
309 310 311 312 313 314
		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 已提交
315
	FILE_UNIX_INFO *pfindData, unsigned int *pobject_type, int isNewInode)
L
Linus Torvalds 已提交
316
{
S
Steve French 已提交
317 318 319
	loff_t local_size;
	struct timespec local_mtime;

L
Linus Torvalds 已提交
320 321 322 323 324 325 326 327 328
	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 已提交
329 330 331 332
	/* save mtime and size */
	local_mtime = tmp_inode->i_mtime;
	local_size  = tmp_inode->i_size;

L
Linus Torvalds 已提交
333 334 335 336 337 338 339 340
	tmp_inode->i_atime =
	    cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime));
	tmp_inode->i_mtime =
	    cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastModificationTime));
	tmp_inode->i_ctime =
	    cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastStatusChange));

	tmp_inode->i_mode = le64_to_cpu(pfindData->Permissions);
341
	/* since we set the inode type below we need to mask off type
S
Steve French 已提交
342 343
	   to avoid strange results if bits above were corrupt */
	tmp_inode->i_mode &= ~S_IFMT;
L
Linus Torvalds 已提交
344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368
	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;
369 370 371 372
	} else {
		/* safest to just call it a file */
		*pobject_type = DT_REG;
		tmp_inode->i_mode |= S_IFREG;
S
Steve French 已提交
373
		cFYI(1, ("unknown inode type %d", type));
L
Linus Torvalds 已提交
374 375
	}

376 377 378 379 380 381 382 383
	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 已提交
384 385
	tmp_inode->i_nlink = le64_to_cpu(pfindData->Nlinks);

386
	cifsInfo->server_eof = end_of_file;
387
	spin_lock(&tmp_inode->i_lock);
388
	if (is_size_safe_to_change(cifsInfo, end_of_file)) {
S
Steve French 已提交
389
		/* can not safely change the file size here if the
L
Linus Torvalds 已提交
390
		client is writing to it due to potential races */
391
		i_size_write(tmp_inode, end_of_file);
L
Linus Torvalds 已提交
392 393 394 395 396

	/* 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;
	}
397
	spin_unlock(&tmp_inode->i_lock);
L
Linus Torvalds 已提交
398 399 400 401

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

403 404
		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) {
			if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
405 406 407
				tmp_inode->i_fop = &cifs_file_direct_nobrl_ops;
			else
				tmp_inode->i_fop = &cifs_file_direct_ops;
408
		} else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
409
			tmp_inode->i_fop = &cifs_file_nobrl_ops;
L
Linus Torvalds 已提交
410 411
		else
			tmp_inode->i_fop = &cifs_file_ops;
412

413
		if ((cifs_sb->tcon) && (cifs_sb->tcon->ses) &&
S
Steve French 已提交
414
		   (cifs_sb->tcon->ses->server->maxBuf <
D
Dave Kleikamp 已提交
415 416 417 418
			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 已提交
419

420
		if (isNewInode)
S
Steve French 已提交
421 422 423
			return; /* No sense invalidating pages for new inode
				   since we have not started caching readahead
				   file data for it yet */
S
Steve French 已提交
424 425 426 427 428 429 430 431 432

		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 已提交
433 434 435 436 437 438 439 440 441
	} 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 已提交
442
		cFYI(1, ("Special inode"));
L
Linus Torvalds 已提交
443 444 445 446 447
		init_special_inode(tmp_inode, tmp_inode->i_mode,
				   tmp_inode->i_rdev);
	}
}

448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479
/* 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 已提交
480 481 482
static int initiate_cifs_search(const int xid, struct file *file)
{
	int rc = 0;
S
Steve French 已提交
483 484
	char *full_path;
	struct cifsFileInfo *cifsFile;
L
Linus Torvalds 已提交
485 486 487
	struct cifs_sb_info *cifs_sb;
	struct cifsTconInfo *pTcon;

488
	if (file->private_data == NULL) {
S
Steve French 已提交
489 490
		file->private_data =
			kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
L
Linus Torvalds 已提交
491 492
	}

493
	if (file->private_data == NULL)
L
Linus Torvalds 已提交
494 495
		return -ENOMEM;
	cifsFile = file->private_data;
496 497
	cifsFile->invalidHandle = true;
	cifsFile->srch_inf.endOfSearch = false;
L
Linus Torvalds 已提交
498

499
	cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
500
	if (cifs_sb == NULL)
L
Linus Torvalds 已提交
501 502 503
		return -EINVAL;

	pTcon = cifs_sb->tcon;
504
	if (pTcon == NULL)
L
Linus Torvalds 已提交
505 506
		return -EINVAL;

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

S
Steve French 已提交
509
	if (full_path == NULL)
L
Linus Torvalds 已提交
510 511
		return -ENOMEM;

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

514
ffirst_retry:
L
Linus Torvalds 已提交
515
	/* test for Unix extensions */
516 517
	/* but now check for them on the share/mount not on the SMB session */
/*	if (pTcon->ses->capabilities & CAP_UNIX) { */
S
Steve French 已提交
518
	if (pTcon->unix_ext)
519
		cifsFile->srch_inf.info_level = SMB_FIND_FILE_UNIX;
S
Steve French 已提交
520
	else if ((pTcon->ses->capabilities &
521 522
			(CAP_NT_SMBS | CAP_NT_FIND)) == 0) {
		cifsFile->srch_inf.info_level = SMB_FIND_FILE_INFO_STANDARD;
L
Linus Torvalds 已提交
523 524 525 526 527 528
	} 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 已提交
529
	rc = CIFSFindFirst(xid, pTcon, full_path, cifs_sb->local_nls,
530
		&cifsFile->netfid, &cifsFile->srch_inf,
S
Steve French 已提交
531
		cifs_sb->mnt_cifs_flags &
532
			CIFS_MOUNT_MAP_SPECIAL_CHR, CIFS_DIR_SEP(cifs_sb));
533
	if (rc == 0)
534
		cifsFile->invalidHandle = false;
535 536 537 538
	/* BB add following call to handle readdir on new NTFS symlink errors 
	else if STATUS_STOPPED_ON_SYMLINK
		call get_symlink_reparse_path and retry with new path */
	else if ((rc == -EOPNOTSUPP) &&
539 540 541 542
		(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)) {
		cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_SERVER_INUM;
		goto ffirst_retry;
	}
L
Linus Torvalds 已提交
543 544 545 546 547 548 549 550
	kfree(full_path);
	return rc;
}

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

S
Steve French 已提交
553
	for (len = 0; len <= PATH_MAX; len++) {
554
		if (ustr[len] == 0)
L
Linus Torvalds 已提交
555 556
			return len << 1;
	}
S
Steve French 已提交
557
	cFYI(1, ("Unicode string longer than PATH_MAX found"));
L
Linus Torvalds 已提交
558 559 560
	return len << 1;
}

561
static char *nxt_dir_entry(char *old_entry, char *end_of_smb, int level)
L
Linus Torvalds 已提交
562
{
S
Steve French 已提交
563
	char *new_entry;
S
Steve French 已提交
564
	FILE_DIRECTORY_INFO *pDirInfo = (FILE_DIRECTORY_INFO *)old_entry;
L
Linus Torvalds 已提交
565

566
	if (level == SMB_FIND_FILE_INFO_STANDARD) {
S
Steve French 已提交
567
		FIND_FILE_STANDARD_INFO *pfData;
568 569 570 571 572 573
		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 已提交
574
	cFYI(1, ("new entry %p old entry %p", new_entry, old_entry));
L
Linus Torvalds 已提交
575
	/* validate that new_entry is not past end of SMB */
576
	if (new_entry >= end_of_smb) {
577 578
		cERROR(1,
		      ("search entry %p began after end of SMB %p old entry %p",
S
Steve French 已提交
579
			new_entry, end_of_smb, old_entry));
L
Linus Torvalds 已提交
580
		return NULL;
581
	} else if (((level == SMB_FIND_FILE_INFO_STANDARD) &&
S
Steve French 已提交
582 583
		    (new_entry + sizeof(FIND_FILE_STANDARD_INFO) > end_of_smb))
		  || ((level != SMB_FIND_FILE_INFO_STANDARD) &&
584
		   (new_entry + sizeof(FILE_DIRECTORY_INFO) > end_of_smb)))  {
S
Steve French 已提交
585
		cERROR(1, ("search entry %p extends after end of SMB %p",
586 587
			new_entry, end_of_smb));
		return NULL;
S
Steve French 已提交
588
	} else
L
Linus Torvalds 已提交
589 590 591 592 593 594 595 596 597 598
		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 已提交
599 600
	char *filename = NULL;
	int len = 0;
L
Linus Torvalds 已提交
601

602
	if (cfile->srch_inf.info_level == SMB_FIND_FILE_UNIX) {
S
Steve French 已提交
603
		FILE_UNIX_INFO *pFindData = (FILE_UNIX_INFO *)current_entry;
L
Linus Torvalds 已提交
604
		filename = &pFindData->FileName[0];
605
		if (cfile->srch_inf.unicode) {
L
Linus Torvalds 已提交
606 607 608 609 610
			len = cifs_unicode_bytelen(filename);
		} else {
			/* BB should we make this strnlen of PATH_MAX? */
			len = strnlen(filename, 5);
		}
611
	} else if (cfile->srch_inf.info_level == SMB_FIND_FILE_DIRECTORY_INFO) {
S
Steve French 已提交
612
		FILE_DIRECTORY_INFO *pFindData =
L
Linus Torvalds 已提交
613 614 615
			(FILE_DIRECTORY_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_FULL_DIRECTORY_INFO) {
S
Steve French 已提交
618
		FILE_FULL_DIRECTORY_INFO *pFindData =
L
Linus Torvalds 已提交
619 620 621
			(FILE_FULL_DIRECTORY_INFO *)current_entry;
		filename = &pFindData->FileName[0];
		len = le32_to_cpu(pFindData->FileNameLength);
622
	} else if (cfile->srch_inf.info_level ==
623
			SMB_FIND_FILE_ID_FULL_DIR_INFO) {
S
Steve French 已提交
624
		SEARCH_ID_FULL_DIR_INFO *pFindData =
L
Linus Torvalds 已提交
625 626 627
			(SEARCH_ID_FULL_DIR_INFO *)current_entry;
		filename = &pFindData->FileName[0];
		len = le32_to_cpu(pFindData->FileNameLength);
S
Steve French 已提交
628
	} else if (cfile->srch_inf.info_level ==
629
			SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
S
Steve French 已提交
630
		FILE_BOTH_DIRECTORY_INFO *pFindData =
L
Linus Torvalds 已提交
631 632 633
			(FILE_BOTH_DIRECTORY_INFO *)current_entry;
		filename = &pFindData->FileName[0];
		len = le32_to_cpu(pFindData->FileNameLength);
634
	} else if (cfile->srch_inf.info_level == SMB_FIND_FILE_INFO_STANDARD) {
S
Steve French 已提交
635
		FIND_FILE_STANDARD_INFO *pFindData =
636 637
			(FIND_FILE_STANDARD_INFO *)current_entry;
		filename = &pFindData->FileName[0];
638
		len = pFindData->FileNameLength;
L
Linus Torvalds 已提交
639
	} else {
S
Steve French 已提交
640 641
		cFYI(1, ("Unknown findfirst level %d",
			 cfile->srch_inf.info_level));
L
Linus Torvalds 已提交
642 643
	}

644 645
	if (filename) {
		if (cfile->srch_inf.unicode) {
L
Linus Torvalds 已提交
646
			__le16 *ufilename = (__le16 *)filename;
647
			if (len == 2) {
L
Linus Torvalds 已提交
648
				/* check for . */
649
				if (ufilename[0] == UNICODE_DOT)
L
Linus Torvalds 已提交
650
					rc = 1;
651
			} else if (len == 4) {
L
Linus Torvalds 已提交
652
				/* check for .. */
653
				if ((ufilename[0] == UNICODE_DOT)
S
Steve French 已提交
654
				   && (ufilename[1] == UNICODE_DOT))
L
Linus Torvalds 已提交
655 656 657
					rc = 2;
			}
		} else /* ASCII */ {
658
			if (len == 1) {
S
Steve French 已提交
659
				if (filename[0] == '.')
L
Linus Torvalds 已提交
660
					rc = 1;
661
			} else if (len == 2) {
S
Steve French 已提交
662
				if ((filename[0] == '.') && (filename[1] == '.'))
L
Linus Torvalds 已提交
663 664 665 666 667 668 669 670
					rc = 2;
			}
		}
	}

	return rc;
}

671 672
/* 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 已提交
673
static int is_dir_changed(struct file *file)
674
{
675 676
	struct inode *inode = file->f_path.dentry->d_inode;
	struct cifsInodeInfo *cifsInfo = CIFS_I(inode);
677

678
	if (cifsInfo->time == 0)
679 680 681 682 683 684
		return 1; /* directory was changed, perhaps due to unlink */
	else
		return 0;

}

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 737 738 739 740 741 742 743 744 745 746 747 748
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 已提交
749 750 751 752 753 754 755
/* 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 已提交
756
	struct file *file, char **ppCurrentEntry, int *num_to_ret)
L
Linus Torvalds 已提交
757 758 759 760 761
{
	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 已提交
762
	struct cifsFileInfo *cifsFile = file->private_data;
L
Linus Torvalds 已提交
763
	/* check if index in the buffer */
764

S
Steve French 已提交
765
	if ((cifsFile == NULL) || (ppCurrentEntry == NULL) ||
766
	   (num_to_ret == NULL))
L
Linus Torvalds 已提交
767
		return -ENOENT;
768

L
Linus Torvalds 已提交
769
	*ppCurrentEntry = NULL;
S
Steve French 已提交
770 771
	first_entry_in_buffer =
		cifsFile->srch_inf.index_of_last_entry -
L
Linus Torvalds 已提交
772
			cifsFile->srch_inf.entries_in_buffer;
773 774 775 776 777 778 779

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

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

S
Steve French 已提交
813
	while ((index_to_find >= cifsFile->srch_inf.index_of_last_entry) &&
814
	      (rc == 0) && !cifsFile->srch_inf.endOfSearch) {
S
Steve French 已提交
815
		cFYI(1, ("calling findnext2"));
S
Steve French 已提交
816
		rc = CIFSFindNext(xid, pTcon, cifsFile->netfid,
817
				  &cifsFile->srch_inf);
818
		cifs_save_resume_key(cifsFile->srch_inf.last_entry, cifsFile);
819
		if (rc)
L
Linus Torvalds 已提交
820 821
			return -ENOENT;
	}
822
	if (index_to_find < cifsFile->srch_inf.index_of_last_entry) {
L
Linus Torvalds 已提交
823 824 825
		/* we found the buffer that contains the entry */
		/* scan and find it */
		int i;
S
Steve French 已提交
826 827
		char *current_entry;
		char *end_of_smb = cifsFile->srch_inf.ntwrk_buf_start +
L
Linus Torvalds 已提交
828 829
			smbCalcSize((struct smb_hdr *)
				cifsFile->srch_inf.ntwrk_buf_start);
830 831

		current_entry = cifsFile->srch_inf.srch_entries_start;
L
Linus Torvalds 已提交
832 833 834
		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 已提交
835
		cFYI(1, ("found entry - pos_in_buf %d", pos_in_buf));
836

S
Steve French 已提交
837
		for (i = 0; (i < (pos_in_buf)) && (current_entry != NULL); i++) {
838
			/* go entry by entry figuring out which is first */
S
Steve French 已提交
839
			current_entry = nxt_dir_entry(current_entry, end_of_smb,
840
						cifsFile->srch_inf.info_level);
L
Linus Torvalds 已提交
841
		}
S
Steve French 已提交
842
		if ((current_entry == NULL) && (i < pos_in_buf)) {
L
Linus Torvalds 已提交
843
			/* BB fixme - check if we should flag this error */
S
Steve French 已提交
844
			cERROR(1, ("reached end of buf searching for pos in buf"
L
Linus Torvalds 已提交
845
			  " %d index to find %lld rc %d",
S
Steve French 已提交
846
			  pos_in_buf, index_to_find, rc));
L
Linus Torvalds 已提交
847 848 849 850
		}
		rc = 0;
		*ppCurrentEntry = current_entry;
	} else {
S
Steve French 已提交
851
		cFYI(1, ("index not in buffer - could not findnext into it"));
L
Linus Torvalds 已提交
852 853 854
		return 0;
	}

S
Steve French 已提交
855 856
	if (pos_in_buf >= cifsFile->srch_inf.entries_in_buffer) {
		cFYI(1, ("can not return entries pos_in_buf beyond last"));
L
Linus Torvalds 已提交
857 858 859 860 861 862 863 864 865 866
		*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,
867
	struct cifs_sb_info *cifs_sb, unsigned int max_len, __u64 *pinum)
L
Linus Torvalds 已提交
868 869 870
{
	int rc = 0;
	unsigned int len = 0;
S
Steve French 已提交
871 872
	char *filename;
	struct nls_table *nlt = cifs_sb->local_nls;
L
Linus Torvalds 已提交
873 874 875

	*pinum = 0;

S
Steve French 已提交
876
	if (level == SMB_FIND_FILE_UNIX) {
S
Steve French 已提交
877
		FILE_UNIX_INFO *pFindData = (FILE_UNIX_INFO *)current_entry;
L
Linus Torvalds 已提交
878 879

		filename = &pFindData->FileName[0];
S
Steve French 已提交
880
		if (unicode) {
L
Linus Torvalds 已提交
881 882 883 884 885 886
			len = cifs_unicode_bytelen(filename);
		} else {
			/* BB should we make this strnlen of PATH_MAX? */
			len = strnlen(filename, PATH_MAX);
		}

887
		*pinum = le64_to_cpu(pFindData->UniqueId);
S
Steve French 已提交
888
	} else if (level == SMB_FIND_FILE_DIRECTORY_INFO) {
S
Steve French 已提交
889
		FILE_DIRECTORY_INFO *pFindData =
L
Linus Torvalds 已提交
890 891 892
			(FILE_DIRECTORY_INFO *)current_entry;
		filename = &pFindData->FileName[0];
		len = le32_to_cpu(pFindData->FileNameLength);
S
Steve French 已提交
893
	} else if (level == SMB_FIND_FILE_FULL_DIRECTORY_INFO) {
S
Steve French 已提交
894
		FILE_FULL_DIRECTORY_INFO *pFindData =
L
Linus Torvalds 已提交
895 896 897
			(FILE_FULL_DIRECTORY_INFO *)current_entry;
		filename = &pFindData->FileName[0];
		len = le32_to_cpu(pFindData->FileNameLength);
S
Steve French 已提交
898
	} else if (level == SMB_FIND_FILE_ID_FULL_DIR_INFO) {
S
Steve French 已提交
899
		SEARCH_ID_FULL_DIR_INFO *pFindData =
L
Linus Torvalds 已提交
900 901 902
			(SEARCH_ID_FULL_DIR_INFO *)current_entry;
		filename = &pFindData->FileName[0];
		len = le32_to_cpu(pFindData->FileNameLength);
903
		*pinum = le64_to_cpu(pFindData->UniqueId);
S
Steve French 已提交
904
	} else if (level == SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
S
Steve French 已提交
905
		FILE_BOTH_DIRECTORY_INFO *pFindData =
L
Linus Torvalds 已提交
906 907 908
			(FILE_BOTH_DIRECTORY_INFO *)current_entry;
		filename = &pFindData->FileName[0];
		len = le32_to_cpu(pFindData->FileNameLength);
S
Steve French 已提交
909
	} else if (level == SMB_FIND_FILE_INFO_STANDARD) {
S
Steve French 已提交
910
		FIND_FILE_STANDARD_INFO *pFindData =
911 912 913 914
			(FIND_FILE_STANDARD_INFO *)current_entry;
		filename = &pFindData->FileName[0];
		/* one byte length, no name conversion */
		len = (unsigned int)pFindData->FileNameLength;
L
Linus Torvalds 已提交
915
	} else {
S
Steve French 已提交
916
		cFYI(1, ("Unknown findfirst level %d", level));
L
Linus Torvalds 已提交
917 918
		return -EINVAL;
	}
919

S
Steve French 已提交
920
	if (len > max_len) {
S
Steve French 已提交
921
		cERROR(1, ("bad search response length %d past smb end", len));
922 923 924
		return -EINVAL;
	}

S
Steve French 已提交
925
	if (unicode) {
926 927
		pqst->len = cifs_from_ucs2((char *) pqst->name,
					   (__le16 *) filename,
928 929
					   UNICODE_NAME_MAX,
					   min(len, max_len), nlt,
930 931
					   cifs_sb->mnt_cifs_flags &
						CIFS_MOUNT_MAP_SPECIAL_CHR);
L
Linus Torvalds 已提交
932 933 934 935
	} else {
		pqst->name = filename;
		pqst->len = len;
	}
S
Steve French 已提交
936
	pqst->hash = full_name_hash(pqst->name, pqst->len);
S
Steve French 已提交
937
/*	cFYI(1, ("filldir on %s",pqst->name));  */
L
Linus Torvalds 已提交
938 939 940
	return rc;
}

941 942
static int cifs_filldir(char *pfindEntry, struct file *file, filldir_t filldir,
			void *direntry, char *scratch_buf, unsigned int max_len)
L
Linus Torvalds 已提交
943 944 945
{
	int rc = 0;
	struct qstr qstring;
S
Steve French 已提交
946
	struct cifsFileInfo *pCifsF;
S
Steve French 已提交
947
	unsigned int obj_type;
948
	__u64  inum;
S
Steve French 已提交
949
	struct cifs_sb_info *cifs_sb;
L
Linus Torvalds 已提交
950 951 952 953 954 955
	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 已提交
956
	if ((direntry == NULL) || (file == NULL))
L
Linus Torvalds 已提交
957 958 959
		return -EINVAL;

	pCifsF = file->private_data;
960

S
Steve French 已提交
961
	if ((scratch_buf == NULL) || (pfindEntry == NULL) || (pCifsF == NULL))
L
Linus Torvalds 已提交
962 963
		return -ENOENT;

S
Steve French 已提交
964
	rc = cifs_entry_is_dot(pfindEntry, pCifsF);
965
	/* skip . and .. since we added them first */
S
Steve French 已提交
966
	if (rc != 0)
967 968
		return 0;

969
	cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
L
Linus Torvalds 已提交
970 971

	qstring.name = scratch_buf;
S
Steve French 已提交
972
	rc = cifs_get_name_from_search_buf(&qstring, pfindEntry,
L
Linus Torvalds 已提交
973
			pCifsF->srch_inf.info_level,
S
Steve French 已提交
974
			pCifsF->srch_inf.unicode, cifs_sb,
975
			max_len,
L
Linus Torvalds 已提交
976 977
			&inum /* returned */);

S
Steve French 已提交
978
	if (rc)
L
Linus Torvalds 已提交
979 980
		return rc;

981 982 983 984 985 986 987 988 989
	/* 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 已提交
990
	if ((tmp_inode == NULL) || (tmp_dentry == NULL))
L
Linus Torvalds 已提交
991 992
		return -ENOMEM;

S
Steve French 已提交
993 994 995
	/* 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 已提交
996
	if (pCifsF->srch_inf.info_level == SMB_FIND_FILE_UNIX)
S
Steve French 已提交
997
		unix_fill_in_inode(tmp_inode,
998 999
				   (FILE_UNIX_INFO *)pfindEntry,
				   &obj_type, rc);
S
Steve French 已提交
1000
	else if (pCifsF->srch_inf.info_level == SMB_FIND_FILE_INFO_STANDARD)
1001 1002 1003 1004
		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);
1005

S
Steve French 已提交
1006
	if (rc) /* new inode - needs to be tied to dentry */ {
1007
		d_instantiate(tmp_dentry, tmp_inode);
S
Steve French 已提交
1008
		if (rc == 2)
1009 1010
			d_rehash(tmp_dentry);
	}
1011

S
Steve French 已提交
1012 1013 1014

	rc = filldir(direntry, qstring.name, qstring.len, file->f_pos,
		     tmp_inode->i_ino, obj_type);
S
Steve French 已提交
1015 1016
	if (rc) {
		cFYI(1, ("filldir rc = %d", rc));
1017 1018 1019 1020
		/* 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 已提交
1021 1022 1023 1024 1025 1026 1027 1028 1029 1030
	}

	dput(tmp_dentry);
	return rc;
}


int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
{
	int rc = 0;
S
Steve French 已提交
1031
	int xid, i;
L
Linus Torvalds 已提交
1032 1033 1034
	struct cifs_sb_info *cifs_sb;
	struct cifsTconInfo *pTcon;
	struct cifsFileInfo *cifsFile = NULL;
S
Steve French 已提交
1035
	char *current_entry;
L
Linus Torvalds 已提交
1036
	int num_to_fill = 0;
S
Steve French 已提交
1037
	char *tmp_buf = NULL;
1038
	char *end_of_smb;
1039
	unsigned int max_len;
L
Linus Torvalds 已提交
1040 1041 1042

	xid = GetXid();

1043
	cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
L
Linus Torvalds 已提交
1044
	pTcon = cifs_sb->tcon;
S
Steve French 已提交
1045
	if (pTcon == NULL)
L
Linus Torvalds 已提交
1046 1047 1048 1049
		return -EINVAL;

	switch ((int) file->f_pos) {
	case 0:
1050
		if (filldir(direntry, ".", 1, file->f_pos,
1051
		     file->f_path.dentry->d_inode->i_ino, DT_DIR) < 0) {
1052
			cERROR(1, ("Filldir for current dir failed"));
L
Linus Torvalds 已提交
1053 1054 1055
			rc = -ENOMEM;
			break;
		}
1056
		file->f_pos++;
L
Linus Torvalds 已提交
1057
	case 1:
1058
		if (filldir(direntry, "..", 2, file->f_pos,
1059
		     file->f_path.dentry->d_parent->d_inode->i_ino, DT_DIR) < 0) {
1060
			cERROR(1, ("Filldir for parent dir failed"));
L
Linus Torvalds 已提交
1061 1062 1063
			rc = -ENOMEM;
			break;
		}
1064 1065
		file->f_pos++;
	default:
S
Steve French 已提交
1066 1067
		/* 1) If search is active,
			is in current search buffer?
L
Linus Torvalds 已提交
1068 1069 1070
			if it before then restart search
			if after then keep searching till find it */

S
Steve French 已提交
1071
		if (file->private_data == NULL) {
S
Steve French 已提交
1072
			rc = initiate_cifs_search(xid, file);
S
Steve French 已提交
1073 1074
			cFYI(1, ("initiate cifs search rc %d", rc));
			if (rc) {
L
Linus Torvalds 已提交
1075 1076 1077 1078
				FreeXid(xid);
				return rc;
			}
		}
S
Steve French 已提交
1079
		if (file->private_data == NULL) {
L
Linus Torvalds 已提交
1080 1081 1082 1083 1084 1085
			rc = -EINVAL;
			FreeXid(xid);
			return rc;
		}
		cifsFile = file->private_data;
		if (cifsFile->srch_inf.endOfSearch) {
S
Steve French 已提交
1086
			if (cifsFile->srch_inf.emptyDir) {
L
Linus Torvalds 已提交
1087 1088 1089 1090 1091
				cFYI(1, ("End of search, empty dir"));
				rc = 0;
				break;
			}
		} /* else {
1092
			cifsFile->invalidHandle = true;
L
Linus Torvalds 已提交
1093
			CIFSFindClose(xid, pTcon, cifsFile->netfid);
S
Steve French 已提交
1094
		} */
L
Linus Torvalds 已提交
1095

S
Steve French 已提交
1096 1097
		rc = find_cifs_entry(xid, pTcon, file,
				&current_entry, &num_to_fill);
S
Steve French 已提交
1098 1099
		if (rc) {
			cFYI(1, ("fce error %d", rc));
L
Linus Torvalds 已提交
1100 1101
			goto rddir2_exit;
		} else if (current_entry != NULL) {
S
Steve French 已提交
1102
			cFYI(1, ("entry %lld found", file->f_pos));
L
Linus Torvalds 已提交
1103
		} else {
S
Steve French 已提交
1104
			cFYI(1, ("could not find entry"));
L
Linus Torvalds 已提交
1105 1106
			goto rddir2_exit;
		}
S
Steve French 已提交
1107 1108
		cFYI(1, ("loop through %d times filling dir for net buf %p",
			num_to_fill, cifsFile->srch_inf.ntwrk_buf_start));
1109 1110 1111 1112
		max_len = smbCalcSize((struct smb_hdr *)
				cifsFile->srch_inf.ntwrk_buf_start);
		end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + max_len;

1113
		tmp_buf = kmalloc(UNICODE_NAME_MAX, GFP_KERNEL);
S
Steve French 已提交
1114 1115
		for (i = 0; (i < num_to_fill) && (rc == 0); i++) {
			if (current_entry == NULL) {
L
Linus Torvalds 已提交
1116
				/* evaluate whether this case is an error */
1117
				cERROR(1, ("past SMB end,  num to fill %d i %d",
L
Linus Torvalds 已提交
1118 1119 1120
					  num_to_fill, i));
				break;
			}
1121 1122
			/* if buggy server returns . and .. late do
			we want to check for that here? */
1123 1124
			rc = cifs_filldir(current_entry, file,
					filldir, direntry, tmp_buf, max_len);
S
Steve French 已提交
1125
			if (rc == -EOVERFLOW) {
1126 1127 1128 1129
				rc = 0;
				break;
			}

L
Linus Torvalds 已提交
1130
			file->f_pos++;
S
Steve French 已提交
1131
			if (file->f_pos ==
1132
				cifsFile->srch_inf.index_of_last_entry) {
S
Steve French 已提交
1133 1134 1135
				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 已提交
1136
				break;
S
Steve French 已提交
1137 1138
			} else
				current_entry =
1139 1140
					nxt_dir_entry(current_entry, end_of_smb,
						cifsFile->srch_inf.info_level);
L
Linus Torvalds 已提交
1141 1142 1143 1144 1145 1146 1147 1148 1149
		}
		kfree(tmp_buf);
		break;
	} /* end switch */

rddir2_exit:
	FreeXid(xid);
	return rc;
}