readdir.c 33.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 448 449 450
		init_special_inode(tmp_inode, tmp_inode->i_mode,
				   tmp_inode->i_rdev);
	}
}

static int initiate_cifs_search(const int xid, struct file *file)
{
	int rc = 0;
S
Steve French 已提交
451 452
	char *full_path;
	struct cifsFileInfo *cifsFile;
L
Linus Torvalds 已提交
453 454 455
	struct cifs_sb_info *cifs_sb;
	struct cifsTconInfo *pTcon;

456
	if (file->private_data == NULL) {
S
Steve French 已提交
457 458
		file->private_data =
			kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
L
Linus Torvalds 已提交
459 460
	}

461
	if (file->private_data == NULL)
L
Linus Torvalds 已提交
462 463
		return -ENOMEM;
	cifsFile = file->private_data;
464 465
	cifsFile->invalidHandle = true;
	cifsFile->srch_inf.endOfSearch = false;
L
Linus Torvalds 已提交
466

467
	cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
468
	if (cifs_sb == NULL)
L
Linus Torvalds 已提交
469 470 471
		return -EINVAL;

	pTcon = cifs_sb->tcon;
472
	if (pTcon == NULL)
L
Linus Torvalds 已提交
473 474
		return -EINVAL;

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

S
Steve French 已提交
477
	if (full_path == NULL)
L
Linus Torvalds 已提交
478 479
		return -ENOMEM;

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

482
ffirst_retry:
L
Linus Torvalds 已提交
483
	/* test for Unix extensions */
484 485
	/* but now check for them on the share/mount not on the SMB session */
/*	if (pTcon->ses->capabilities & CAP_UNIX) { */
S
Steve French 已提交
486
	if (pTcon->unix_ext)
487
		cifsFile->srch_inf.info_level = SMB_FIND_FILE_UNIX;
S
Steve French 已提交
488
	else if ((pTcon->ses->capabilities &
489 490
			(CAP_NT_SMBS | CAP_NT_FIND)) == 0) {
		cifsFile->srch_inf.info_level = SMB_FIND_FILE_INFO_STANDARD;
L
Linus Torvalds 已提交
491 492 493 494 495 496
	} 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 已提交
497
	rc = CIFSFindFirst(xid, pTcon, full_path, cifs_sb->local_nls,
498
		&cifsFile->netfid, &cifsFile->srch_inf,
S
Steve French 已提交
499
		cifs_sb->mnt_cifs_flags &
500
			CIFS_MOUNT_MAP_SPECIAL_CHR, CIFS_DIR_SEP(cifs_sb));
501
	if (rc == 0)
502
		cifsFile->invalidHandle = false;
S
Steve French 已提交
503
	if ((rc == -EOPNOTSUPP) &&
504 505 506 507
		(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)) {
		cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_SERVER_INUM;
		goto ffirst_retry;
	}
L
Linus Torvalds 已提交
508 509 510 511 512 513 514 515
	kfree(full_path);
	return rc;
}

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

S
Steve French 已提交
518
	for (len = 0; len <= PATH_MAX; len++) {
519
		if (ustr[len] == 0)
L
Linus Torvalds 已提交
520 521
			return len << 1;
	}
S
Steve French 已提交
522
	cFYI(1, ("Unicode string longer than PATH_MAX found"));
L
Linus Torvalds 已提交
523 524 525
	return len << 1;
}

526
static char *nxt_dir_entry(char *old_entry, char *end_of_smb, int level)
L
Linus Torvalds 已提交
527
{
S
Steve French 已提交
528
	char *new_entry;
S
Steve French 已提交
529
	FILE_DIRECTORY_INFO *pDirInfo = (FILE_DIRECTORY_INFO *)old_entry;
L
Linus Torvalds 已提交
530

531
	if (level == SMB_FIND_FILE_INFO_STANDARD) {
S
Steve French 已提交
532
		FIND_FILE_STANDARD_INFO *pfData;
533 534 535 536 537 538
		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 已提交
539
	cFYI(1, ("new entry %p old entry %p", new_entry, old_entry));
L
Linus Torvalds 已提交
540
	/* validate that new_entry is not past end of SMB */
541
	if (new_entry >= end_of_smb) {
542 543
		cERROR(1,
		      ("search entry %p began after end of SMB %p old entry %p",
S
Steve French 已提交
544
			new_entry, end_of_smb, old_entry));
L
Linus Torvalds 已提交
545
		return NULL;
546
	} else if (((level == SMB_FIND_FILE_INFO_STANDARD) &&
S
Steve French 已提交
547 548
		    (new_entry + sizeof(FIND_FILE_STANDARD_INFO) > end_of_smb))
		  || ((level != SMB_FIND_FILE_INFO_STANDARD) &&
549
		   (new_entry + sizeof(FILE_DIRECTORY_INFO) > end_of_smb)))  {
S
Steve French 已提交
550
		cERROR(1, ("search entry %p extends after end of SMB %p",
551 552
			new_entry, end_of_smb));
		return NULL;
S
Steve French 已提交
553
	} else
L
Linus Torvalds 已提交
554 555 556 557 558 559 560 561 562 563
		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 已提交
564 565
	char *filename = NULL;
	int len = 0;
L
Linus Torvalds 已提交
566

567
	if (cfile->srch_inf.info_level == SMB_FIND_FILE_UNIX) {
S
Steve French 已提交
568
		FILE_UNIX_INFO *pFindData = (FILE_UNIX_INFO *)current_entry;
L
Linus Torvalds 已提交
569
		filename = &pFindData->FileName[0];
570
		if (cfile->srch_inf.unicode) {
L
Linus Torvalds 已提交
571 572 573 574 575
			len = cifs_unicode_bytelen(filename);
		} else {
			/* BB should we make this strnlen of PATH_MAX? */
			len = strnlen(filename, 5);
		}
576
	} else if (cfile->srch_inf.info_level == SMB_FIND_FILE_DIRECTORY_INFO) {
S
Steve French 已提交
577
		FILE_DIRECTORY_INFO *pFindData =
L
Linus Torvalds 已提交
578 579 580
			(FILE_DIRECTORY_INFO *)current_entry;
		filename = &pFindData->FileName[0];
		len = le32_to_cpu(pFindData->FileNameLength);
S
Steve French 已提交
581
	} else if (cfile->srch_inf.info_level ==
582
			SMB_FIND_FILE_FULL_DIRECTORY_INFO) {
S
Steve French 已提交
583
		FILE_FULL_DIRECTORY_INFO *pFindData =
L
Linus Torvalds 已提交
584 585 586
			(FILE_FULL_DIRECTORY_INFO *)current_entry;
		filename = &pFindData->FileName[0];
		len = le32_to_cpu(pFindData->FileNameLength);
587
	} else if (cfile->srch_inf.info_level ==
588
			SMB_FIND_FILE_ID_FULL_DIR_INFO) {
S
Steve French 已提交
589
		SEARCH_ID_FULL_DIR_INFO *pFindData =
L
Linus Torvalds 已提交
590 591 592
			(SEARCH_ID_FULL_DIR_INFO *)current_entry;
		filename = &pFindData->FileName[0];
		len = le32_to_cpu(pFindData->FileNameLength);
S
Steve French 已提交
593
	} else if (cfile->srch_inf.info_level ==
594
			SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
S
Steve French 已提交
595
		FILE_BOTH_DIRECTORY_INFO *pFindData =
L
Linus Torvalds 已提交
596 597 598
			(FILE_BOTH_DIRECTORY_INFO *)current_entry;
		filename = &pFindData->FileName[0];
		len = le32_to_cpu(pFindData->FileNameLength);
599
	} else if (cfile->srch_inf.info_level == SMB_FIND_FILE_INFO_STANDARD) {
S
Steve French 已提交
600
		FIND_FILE_STANDARD_INFO *pFindData =
601 602
			(FIND_FILE_STANDARD_INFO *)current_entry;
		filename = &pFindData->FileName[0];
603
		len = pFindData->FileNameLength;
L
Linus Torvalds 已提交
604
	} else {
S
Steve French 已提交
605 606
		cFYI(1, ("Unknown findfirst level %d",
			 cfile->srch_inf.info_level));
L
Linus Torvalds 已提交
607 608
	}

609 610
	if (filename) {
		if (cfile->srch_inf.unicode) {
L
Linus Torvalds 已提交
611
			__le16 *ufilename = (__le16 *)filename;
612
			if (len == 2) {
L
Linus Torvalds 已提交
613
				/* check for . */
614
				if (ufilename[0] == UNICODE_DOT)
L
Linus Torvalds 已提交
615
					rc = 1;
616
			} else if (len == 4) {
L
Linus Torvalds 已提交
617
				/* check for .. */
618
				if ((ufilename[0] == UNICODE_DOT)
S
Steve French 已提交
619
				   && (ufilename[1] == UNICODE_DOT))
L
Linus Torvalds 已提交
620 621 622
					rc = 2;
			}
		} else /* ASCII */ {
623
			if (len == 1) {
S
Steve French 已提交
624
				if (filename[0] == '.')
L
Linus Torvalds 已提交
625
					rc = 1;
626
			} else if (len == 2) {
S
Steve French 已提交
627
				if ((filename[0] == '.') && (filename[1] == '.'))
L
Linus Torvalds 已提交
628 629 630 631 632 633 634 635
					rc = 2;
			}
		}
	}

	return rc;
}

636 637
/* 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 已提交
638
static int is_dir_changed(struct file *file)
639
{
640 641
	struct inode *inode = file->f_path.dentry->d_inode;
	struct cifsInodeInfo *cifsInfo = CIFS_I(inode);
642

643
	if (cifsInfo->time == 0)
644 645 646 647 648 649
		return 1; /* directory was changed, perhaps due to unlink */
	else
		return 0;

}

650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 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
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 已提交
714 715 716 717 718 719 720
/* 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 已提交
721
	struct file *file, char **ppCurrentEntry, int *num_to_ret)
L
Linus Torvalds 已提交
722 723 724 725 726
{
	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 已提交
727
	struct cifsFileInfo *cifsFile = file->private_data;
L
Linus Torvalds 已提交
728
	/* check if index in the buffer */
729

S
Steve French 已提交
730
	if ((cifsFile == NULL) || (ppCurrentEntry == NULL) ||
731
	   (num_to_ret == NULL))
L
Linus Torvalds 已提交
732
		return -ENOENT;
733

L
Linus Torvalds 已提交
734
	*ppCurrentEntry = NULL;
S
Steve French 已提交
735 736
	first_entry_in_buffer =
		cifsFile->srch_inf.index_of_last_entry -
L
Linus Torvalds 已提交
737
			cifsFile->srch_inf.entries_in_buffer;
738 739 740 741 742 743 744

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

745
	dump_cifs_file_struct(file, "In fce ");
S
Steve French 已提交
746 747
	if (((index_to_find < cifsFile->srch_inf.index_of_last_entry) &&
	     is_dir_changed(file)) ||
748
	   (index_to_find < first_entry_in_buffer)) {
L
Linus Torvalds 已提交
749
		/* close and restart search */
S
Steve French 已提交
750
		cFYI(1, ("search backing up - close and restart search"));
751
		write_lock(&GlobalSMBSeslock);
752 753 754
		if (!cifsFile->srch_inf.endOfSearch &&
		    !cifsFile->invalidHandle) {
			cifsFile->invalidHandle = true;
755
			write_unlock(&GlobalSMBSeslock);
756
			CIFSFindClose(xid, pTcon, cifsFile->netfid);
757 758
		} else
			write_unlock(&GlobalSMBSeslock);
759
		if (cifsFile->srch_inf.ntwrk_buf_start) {
S
Steve French 已提交
760
			cFYI(1, ("freeing SMB ff cache buf on search rewind"));
761
			if (cifsFile->srch_inf.smallBuf)
762 763 764 765 766
				cifs_small_buf_release(cifsFile->srch_inf.
						ntwrk_buf_start);
			else
				cifs_buf_release(cifsFile->srch_inf.
						ntwrk_buf_start);
767
			cifsFile->srch_inf.ntwrk_buf_start = NULL;
L
Linus Torvalds 已提交
768
		}
S
Steve French 已提交
769
		rc = initiate_cifs_search(xid, file);
770
		if (rc) {
S
Steve French 已提交
771 772
			cFYI(1, ("error %d reinitiating a search on rewind",
				 rc));
L
Linus Torvalds 已提交
773 774
			return rc;
		}
775
		cifs_save_resume_key(cifsFile->srch_inf.last_entry, cifsFile);
L
Linus Torvalds 已提交
776 777
	}

S
Steve French 已提交
778
	while ((index_to_find >= cifsFile->srch_inf.index_of_last_entry) &&
779
	      (rc == 0) && !cifsFile->srch_inf.endOfSearch) {
S
Steve French 已提交
780
		cFYI(1, ("calling findnext2"));
S
Steve French 已提交
781
		rc = CIFSFindNext(xid, pTcon, cifsFile->netfid,
782
				  &cifsFile->srch_inf);
783
		cifs_save_resume_key(cifsFile->srch_inf.last_entry, cifsFile);
784
		if (rc)
L
Linus Torvalds 已提交
785 786
			return -ENOENT;
	}
787
	if (index_to_find < cifsFile->srch_inf.index_of_last_entry) {
L
Linus Torvalds 已提交
788 789 790
		/* we found the buffer that contains the entry */
		/* scan and find it */
		int i;
S
Steve French 已提交
791 792
		char *current_entry;
		char *end_of_smb = cifsFile->srch_inf.ntwrk_buf_start +
L
Linus Torvalds 已提交
793 794
			smbCalcSize((struct smb_hdr *)
				cifsFile->srch_inf.ntwrk_buf_start);
795 796

		current_entry = cifsFile->srch_inf.srch_entries_start;
L
Linus Torvalds 已提交
797 798 799
		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 已提交
800
		cFYI(1, ("found entry - pos_in_buf %d", pos_in_buf));
801

S
Steve French 已提交
802
		for (i = 0; (i < (pos_in_buf)) && (current_entry != NULL); i++) {
803
			/* go entry by entry figuring out which is first */
S
Steve French 已提交
804
			current_entry = nxt_dir_entry(current_entry, end_of_smb,
805
						cifsFile->srch_inf.info_level);
L
Linus Torvalds 已提交
806
		}
S
Steve French 已提交
807
		if ((current_entry == NULL) && (i < pos_in_buf)) {
L
Linus Torvalds 已提交
808
			/* BB fixme - check if we should flag this error */
S
Steve French 已提交
809
			cERROR(1, ("reached end of buf searching for pos in buf"
L
Linus Torvalds 已提交
810
			  " %d index to find %lld rc %d",
S
Steve French 已提交
811
			  pos_in_buf, index_to_find, rc));
L
Linus Torvalds 已提交
812 813 814 815
		}
		rc = 0;
		*ppCurrentEntry = current_entry;
	} else {
S
Steve French 已提交
816
		cFYI(1, ("index not in buffer - could not findnext into it"));
L
Linus Torvalds 已提交
817 818 819
		return 0;
	}

S
Steve French 已提交
820 821
	if (pos_in_buf >= cifsFile->srch_inf.entries_in_buffer) {
		cFYI(1, ("can not return entries pos_in_buf beyond last"));
L
Linus Torvalds 已提交
822 823 824 825 826 827 828 829 830 831
		*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,
832
	struct cifs_sb_info *cifs_sb, int max_len, __u64 *pinum)
L
Linus Torvalds 已提交
833 834 835
{
	int rc = 0;
	unsigned int len = 0;
S
Steve French 已提交
836 837
	char *filename;
	struct nls_table *nlt = cifs_sb->local_nls;
L
Linus Torvalds 已提交
838 839 840

	*pinum = 0;

S
Steve French 已提交
841
	if (level == SMB_FIND_FILE_UNIX) {
S
Steve French 已提交
842
		FILE_UNIX_INFO *pFindData = (FILE_UNIX_INFO *)current_entry;
L
Linus Torvalds 已提交
843 844

		filename = &pFindData->FileName[0];
S
Steve French 已提交
845
		if (unicode) {
L
Linus Torvalds 已提交
846 847 848 849 850 851
			len = cifs_unicode_bytelen(filename);
		} else {
			/* BB should we make this strnlen of PATH_MAX? */
			len = strnlen(filename, PATH_MAX);
		}

852
		*pinum = le64_to_cpu(pFindData->UniqueId);
S
Steve French 已提交
853
	} else if (level == SMB_FIND_FILE_DIRECTORY_INFO) {
S
Steve French 已提交
854
		FILE_DIRECTORY_INFO *pFindData =
L
Linus Torvalds 已提交
855 856 857
			(FILE_DIRECTORY_INFO *)current_entry;
		filename = &pFindData->FileName[0];
		len = le32_to_cpu(pFindData->FileNameLength);
S
Steve French 已提交
858
	} else if (level == SMB_FIND_FILE_FULL_DIRECTORY_INFO) {
S
Steve French 已提交
859
		FILE_FULL_DIRECTORY_INFO *pFindData =
L
Linus Torvalds 已提交
860 861 862
			(FILE_FULL_DIRECTORY_INFO *)current_entry;
		filename = &pFindData->FileName[0];
		len = le32_to_cpu(pFindData->FileNameLength);
S
Steve French 已提交
863
	} else if (level == SMB_FIND_FILE_ID_FULL_DIR_INFO) {
S
Steve French 已提交
864
		SEARCH_ID_FULL_DIR_INFO *pFindData =
L
Linus Torvalds 已提交
865 866 867
			(SEARCH_ID_FULL_DIR_INFO *)current_entry;
		filename = &pFindData->FileName[0];
		len = le32_to_cpu(pFindData->FileNameLength);
868
		*pinum = le64_to_cpu(pFindData->UniqueId);
S
Steve French 已提交
869
	} else if (level == SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
S
Steve French 已提交
870
		FILE_BOTH_DIRECTORY_INFO *pFindData =
L
Linus Torvalds 已提交
871 872 873
			(FILE_BOTH_DIRECTORY_INFO *)current_entry;
		filename = &pFindData->FileName[0];
		len = le32_to_cpu(pFindData->FileNameLength);
S
Steve French 已提交
874
	} else if (level == SMB_FIND_FILE_INFO_STANDARD) {
S
Steve French 已提交
875
		FIND_FILE_STANDARD_INFO *pFindData =
876 877 878 879
			(FIND_FILE_STANDARD_INFO *)current_entry;
		filename = &pFindData->FileName[0];
		/* one byte length, no name conversion */
		len = (unsigned int)pFindData->FileNameLength;
L
Linus Torvalds 已提交
880
	} else {
S
Steve French 已提交
881
		cFYI(1, ("Unknown findfirst level %d", level));
L
Linus Torvalds 已提交
882 883
		return -EINVAL;
	}
884

S
Steve French 已提交
885
	if (len > max_len) {
S
Steve French 已提交
886
		cERROR(1, ("bad search response length %d past smb end", len));
887 888 889
		return -EINVAL;
	}

S
Steve French 已提交
890
	if (unicode) {
891 892 893 894 895
		pqst->len = cifs_from_ucs2((char *) pqst->name,
					   (__le16 *) filename,
					   UNICODE_NAME_MAX, max_len, nlt,
					   cifs_sb->mnt_cifs_flags &
						CIFS_MOUNT_MAP_SPECIAL_CHR);
L
Linus Torvalds 已提交
896 897 898 899
	} else {
		pqst->name = filename;
		pqst->len = len;
	}
S
Steve French 已提交
900
	pqst->hash = full_name_hash(pqst->name, pqst->len);
S
Steve French 已提交
901
/*	cFYI(1, ("filldir on %s",pqst->name));  */
L
Linus Torvalds 已提交
902 903 904 905
	return rc;
}

static int cifs_filldir(char *pfindEntry, struct file *file,
906
	filldir_t filldir, void *direntry, char *scratch_buf, int max_len)
L
Linus Torvalds 已提交
907 908 909
{
	int rc = 0;
	struct qstr qstring;
S
Steve French 已提交
910
	struct cifsFileInfo *pCifsF;
S
Steve French 已提交
911
	unsigned int obj_type;
912
	__u64  inum;
S
Steve French 已提交
913
	struct cifs_sb_info *cifs_sb;
L
Linus Torvalds 已提交
914 915 916 917 918 919
	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 已提交
920
	if ((direntry == NULL) || (file == NULL))
L
Linus Torvalds 已提交
921 922 923
		return -EINVAL;

	pCifsF = file->private_data;
924

S
Steve French 已提交
925
	if ((scratch_buf == NULL) || (pfindEntry == NULL) || (pCifsF == NULL))
L
Linus Torvalds 已提交
926 927
		return -ENOENT;

S
Steve French 已提交
928
	rc = cifs_entry_is_dot(pfindEntry, pCifsF);
929
	/* skip . and .. since we added them first */
S
Steve French 已提交
930
	if (rc != 0)
931 932
		return 0;

933
	cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
L
Linus Torvalds 已提交
934 935

	qstring.name = scratch_buf;
S
Steve French 已提交
936
	rc = cifs_get_name_from_search_buf(&qstring, pfindEntry,
L
Linus Torvalds 已提交
937
			pCifsF->srch_inf.info_level,
S
Steve French 已提交
938
			pCifsF->srch_inf.unicode, cifs_sb,
939
			max_len,
L
Linus Torvalds 已提交
940 941
			&inum /* returned */);

S
Steve French 已提交
942
	if (rc)
L
Linus Torvalds 已提交
943 944
		return rc;

945 946 947 948 949 950 951 952 953
	/* 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 已提交
954
	if ((tmp_inode == NULL) || (tmp_dentry == NULL))
L
Linus Torvalds 已提交
955 956
		return -ENOMEM;

S
Steve French 已提交
957 958 959
	/* 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 已提交
960
	if (pCifsF->srch_inf.info_level == SMB_FIND_FILE_UNIX)
S
Steve French 已提交
961
		unix_fill_in_inode(tmp_inode,
962 963
				   (FILE_UNIX_INFO *)pfindEntry,
				   &obj_type, rc);
S
Steve French 已提交
964
	else if (pCifsF->srch_inf.info_level == SMB_FIND_FILE_INFO_STANDARD)
965 966 967 968
		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);
969

S
Steve French 已提交
970
	if (rc) /* new inode - needs to be tied to dentry */ {
971
		d_instantiate(tmp_dentry, tmp_inode);
S
Steve French 已提交
972
		if (rc == 2)
973 974
			d_rehash(tmp_dentry);
	}
975

S
Steve French 已提交
976 977 978

	rc = filldir(direntry, qstring.name, qstring.len, file->f_pos,
		     tmp_inode->i_ino, obj_type);
S
Steve French 已提交
979 980
	if (rc) {
		cFYI(1, ("filldir rc = %d", rc));
981 982 983 984
		/* 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 已提交
985 986 987 988 989 990 991 992 993 994
	}

	dput(tmp_dentry);
	return rc;
}


int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
{
	int rc = 0;
S
Steve French 已提交
995
	int xid, i;
L
Linus Torvalds 已提交
996 997 998
	struct cifs_sb_info *cifs_sb;
	struct cifsTconInfo *pTcon;
	struct cifsFileInfo *cifsFile = NULL;
S
Steve French 已提交
999
	char *current_entry;
L
Linus Torvalds 已提交
1000
	int num_to_fill = 0;
S
Steve French 已提交
1001
	char *tmp_buf = NULL;
1002
	char *end_of_smb;
1003
	int max_len;
L
Linus Torvalds 已提交
1004 1005 1006

	xid = GetXid();

1007
	cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
L
Linus Torvalds 已提交
1008
	pTcon = cifs_sb->tcon;
S
Steve French 已提交
1009
	if (pTcon == NULL)
L
Linus Torvalds 已提交
1010 1011 1012 1013
		return -EINVAL;

	switch ((int) file->f_pos) {
	case 0:
1014
		if (filldir(direntry, ".", 1, file->f_pos,
1015
		     file->f_path.dentry->d_inode->i_ino, DT_DIR) < 0) {
1016
			cERROR(1, ("Filldir for current dir failed"));
L
Linus Torvalds 已提交
1017 1018 1019
			rc = -ENOMEM;
			break;
		}
1020
		file->f_pos++;
L
Linus Torvalds 已提交
1021
	case 1:
1022
		if (filldir(direntry, "..", 2, file->f_pos,
1023
		     file->f_path.dentry->d_parent->d_inode->i_ino, DT_DIR) < 0) {
1024
			cERROR(1, ("Filldir for parent dir failed"));
L
Linus Torvalds 已提交
1025 1026 1027
			rc = -ENOMEM;
			break;
		}
1028 1029
		file->f_pos++;
	default:
S
Steve French 已提交
1030 1031
		/* 1) If search is active,
			is in current search buffer?
L
Linus Torvalds 已提交
1032 1033 1034
			if it before then restart search
			if after then keep searching till find it */

S
Steve French 已提交
1035
		if (file->private_data == NULL) {
S
Steve French 已提交
1036
			rc = initiate_cifs_search(xid, file);
S
Steve French 已提交
1037 1038
			cFYI(1, ("initiate cifs search rc %d", rc));
			if (rc) {
L
Linus Torvalds 已提交
1039 1040 1041 1042
				FreeXid(xid);
				return rc;
			}
		}
S
Steve French 已提交
1043
		if (file->private_data == NULL) {
L
Linus Torvalds 已提交
1044 1045 1046 1047 1048 1049
			rc = -EINVAL;
			FreeXid(xid);
			return rc;
		}
		cifsFile = file->private_data;
		if (cifsFile->srch_inf.endOfSearch) {
S
Steve French 已提交
1050
			if (cifsFile->srch_inf.emptyDir) {
L
Linus Torvalds 已提交
1051 1052 1053 1054 1055
				cFYI(1, ("End of search, empty dir"));
				rc = 0;
				break;
			}
		} /* else {
1056
			cifsFile->invalidHandle = true;
L
Linus Torvalds 已提交
1057
			CIFSFindClose(xid, pTcon, cifsFile->netfid);
S
Steve French 已提交
1058
		} */
L
Linus Torvalds 已提交
1059

S
Steve French 已提交
1060 1061
		rc = find_cifs_entry(xid, pTcon, file,
				&current_entry, &num_to_fill);
S
Steve French 已提交
1062 1063
		if (rc) {
			cFYI(1, ("fce error %d", rc));
L
Linus Torvalds 已提交
1064 1065
			goto rddir2_exit;
		} else if (current_entry != NULL) {
S
Steve French 已提交
1066
			cFYI(1, ("entry %lld found", file->f_pos));
L
Linus Torvalds 已提交
1067
		} else {
S
Steve French 已提交
1068
			cFYI(1, ("could not find entry"));
L
Linus Torvalds 已提交
1069 1070
			goto rddir2_exit;
		}
S
Steve French 已提交
1071 1072
		cFYI(1, ("loop through %d times filling dir for net buf %p",
			num_to_fill, cifsFile->srch_inf.ntwrk_buf_start));
1073 1074 1075 1076
		max_len = smbCalcSize((struct smb_hdr *)
				cifsFile->srch_inf.ntwrk_buf_start);
		end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + max_len;

1077
		tmp_buf = kmalloc(UNICODE_NAME_MAX, GFP_KERNEL);
S
Steve French 已提交
1078 1079
		for (i = 0; (i < num_to_fill) && (rc == 0); i++) {
			if (current_entry == NULL) {
L
Linus Torvalds 已提交
1080
				/* evaluate whether this case is an error */
1081
				cERROR(1, ("past SMB end,  num to fill %d i %d",
L
Linus Torvalds 已提交
1082 1083 1084
					  num_to_fill, i));
				break;
			}
1085 1086
			/* if buggy server returns . and .. late do
			we want to check for that here? */
1087 1088
			rc = cifs_filldir(current_entry, file,
					filldir, direntry, tmp_buf, max_len);
S
Steve French 已提交
1089
			if (rc == -EOVERFLOW) {
1090 1091 1092 1093
				rc = 0;
				break;
			}

L
Linus Torvalds 已提交
1094
			file->f_pos++;
S
Steve French 已提交
1095
			if (file->f_pos ==
1096
				cifsFile->srch_inf.index_of_last_entry) {
S
Steve French 已提交
1097 1098 1099
				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 已提交
1100
				break;
S
Steve French 已提交
1101 1102
			} else
				current_entry =
1103 1104
					nxt_dir_entry(current_entry, end_of_smb,
						cifsFile->srch_inf.info_level);
L
Linus Torvalds 已提交
1105 1106 1107 1108 1109 1110 1111 1112 1113
		}
		kfree(tmp_buf);
		break;
	} /* end switch */

rddir2_exit:
	FreeXid(xid);
	return rc;
}