readdir.c 34.0 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
#ifdef CONFIG_CIFS_DEBUG2
static void dump_cifs_file_struct(struct file *file, char *label)
L
Linus Torvalds 已提交
36
{
S
Steve French 已提交
37
	struct cifsFileInfo *cf;
L
Linus Torvalds 已提交
38

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

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

S
Steve French 已提交
70
	cFYI(1, ("For %s", qstring->name));
L
Linus Torvalds 已提交
71 72

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

95
		if (CIFS_SB(sb)->tcon->nocase)
96 97 98
			tmp_dentry->d_op = &cifs_ci_dentry_ops;
		else
			tmp_dentry->d_op = &cifs_dentry_ops;
99 100

		*ptmp_inode = cifs_new_inode(sb, inum);
101
		if (*ptmp_inode == NULL)
L
Linus Torvalds 已提交
102
			return rc;
103
		rc = 2;
L
Linus Torvalds 已提交
104 105 106 107 108 109 110
	}

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

S
Steve French 已提交
111
static void AdjustForTZ(struct cifsTconInfo *tcon, struct inode *inode)
112
{
113
	if ((tcon) && (tcon->ses) && (tcon->ses->server)) {
S
Steve French 已提交
114 115 116
		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;
117 118 119 120 121
	}
	return;
}


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

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

S
Steve French 已提交
135 136 137 138
	/* save mtime and size */
	local_mtime = tmp_inode->i_mtime;
	local_size  = tmp_inode->i_size;

139
	if (new_buf_type) {
140 141 142 143 144 145 146 147 148 149 150 151
		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 */
152
/*		struct timespec ts;*/
S
Steve French 已提交
153
		FIND_FILE_STANDARD_INFO *pfindData =
154 155
			(FIND_FILE_STANDARD_INFO *)buf;

156
		tmp_inode->i_mtime = cnvrtDosUnixTm(
157
				le16_to_cpu(pfindData->LastWriteDate),
158 159 160 161
				le16_to_cpu(pfindData->LastWriteTime));
		tmp_inode->i_atime = cnvrtDosUnixTm(
				le16_to_cpu(pfindData->LastAccessDate),
				le16_to_cpu(pfindData->LastAccessTime));
S
Steve French 已提交
162 163 164
		tmp_inode->i_ctime = cnvrtDosUnixTm(
				le16_to_cpu(pfindData->LastWriteDate),
				le16_to_cpu(pfindData->LastWriteTime));
165
		AdjustForTZ(cifs_sb->tcon, tmp_inode);
166 167 168 169 170
		attr = le16_to_cpu(pfindData->Attributes);
		allocation_size = le32_to_cpu(pfindData->AllocationSize);
		end_of_file = le32_to_cpu(pfindData->DataSize);
	}

L
Linus Torvalds 已提交
171
	/* Linux can not store file creation time unfortunately so ignore it */
172 173

	cifsInfo->cifsAttrs = attr;
174 175 176 177 178 179 180
#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;
181

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

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

206
		tmp_inode->i_mode &= ~S_IFMT;
L
Linus Torvalds 已提交
207 208
	}

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

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

242
	spin_lock(&tmp_inode->i_lock);
243
	if (is_size_safe_to_change(cifsInfo, end_of_file)) {
S
Steve French 已提交
244
		/* can not safely change the file size here if the
L
Linus Torvalds 已提交
245 246 247 248 249 250 251
		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;
	}
252
	spin_unlock(&tmp_inode->i_lock);
L
Linus Torvalds 已提交
253 254 255

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

272
		if ((cifs_sb->tcon) && (cifs_sb->tcon->ses) &&
273
		   (cifs_sb->tcon->ses->server->maxBuf <
D
Dave Kleikamp 已提交
274 275 276 277 278
			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;

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

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

L
Linus Torvalds 已提交
312 313 314 315 316 317 318 319 320
	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 已提交
321 322 323 324
	/* save mtime and size */
	local_mtime = tmp_inode->i_mtime;
	local_size  = tmp_inode->i_size;

L
Linus Torvalds 已提交
325 326 327 328 329 330 331 332
	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);
333
	/* since we set the inode type below we need to mask off type
S
Steve French 已提交
334 335
	   to avoid strange results if bits above were corrupt */
	tmp_inode->i_mode &= ~S_IFMT;
L
Linus Torvalds 已提交
336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360
	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;
361 362 363 364
	} else {
		/* safest to just call it a file */
		*pobject_type = DT_REG;
		tmp_inode->i_mode |= S_IFREG;
S
Steve French 已提交
365
		cFYI(1, ("unknown inode type %d", type));
L
Linus Torvalds 已提交
366 367
	}

368 369 370 371 372 373 374 375
	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 已提交
376 377
	tmp_inode->i_nlink = le64_to_cpu(pfindData->Nlinks);

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

	/* 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;
	}
388
	spin_unlock(&tmp_inode->i_lock);
L
Linus Torvalds 已提交
389 390 391 392

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

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

404
		if ((cifs_sb->tcon) && (cifs_sb->tcon->ses) &&
S
Steve French 已提交
405
		   (cifs_sb->tcon->ses->server->maxBuf <
D
Dave Kleikamp 已提交
406 407 408 409
			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 已提交
410

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

		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 已提交
424 425 426 427 428 429 430 431 432
	} 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 已提交
433
		cFYI(1, ("Special inode"));
L
Linus Torvalds 已提交
434 435 436 437 438 439 440 441
		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 已提交
442 443
	char *full_path;
	struct cifsFileInfo *cifsFile;
L
Linus Torvalds 已提交
444 445 446
	struct cifs_sb_info *cifs_sb;
	struct cifsTconInfo *pTcon;

447
	if (file->private_data == NULL) {
S
Steve French 已提交
448 449
		file->private_data =
			kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
L
Linus Torvalds 已提交
450 451
	}

452
	if (file->private_data == NULL)
L
Linus Torvalds 已提交
453 454
		return -ENOMEM;
	cifsFile = file->private_data;
455 456
	cifsFile->invalidHandle = true;
	cifsFile->srch_inf.endOfSearch = false;
L
Linus Torvalds 已提交
457

458
	cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
459
	if (cifs_sb == NULL)
L
Linus Torvalds 已提交
460 461 462
		return -EINVAL;

	pTcon = cifs_sb->tcon;
463
	if (pTcon == NULL)
L
Linus Torvalds 已提交
464 465
		return -EINVAL;

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

S
Steve French 已提交
468
	if (full_path == NULL)
L
Linus Torvalds 已提交
469 470
		return -ENOMEM;

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

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

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

S
Steve French 已提交
509
	for (len = 0; len <= PATH_MAX; len++) {
510
		if (ustr[len] == 0)
L
Linus Torvalds 已提交
511 512
			return len << 1;
	}
S
Steve French 已提交
513
	cFYI(1, ("Unicode string longer than PATH_MAX found"));
L
Linus Torvalds 已提交
514 515 516
	return len << 1;
}

517
static char *nxt_dir_entry(char *old_entry, char *end_of_smb, int level)
L
Linus Torvalds 已提交
518
{
S
Steve French 已提交
519
	char *new_entry;
S
Steve French 已提交
520
	FILE_DIRECTORY_INFO *pDirInfo = (FILE_DIRECTORY_INFO *)old_entry;
L
Linus Torvalds 已提交
521

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

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

600 601
	if (filename) {
		if (cfile->srch_inf.unicode) {
L
Linus Torvalds 已提交
602
			__le16 *ufilename = (__le16 *)filename;
603
			if (len == 2) {
L
Linus Torvalds 已提交
604
				/* check for . */
605
				if (ufilename[0] == UNICODE_DOT)
L
Linus Torvalds 已提交
606
					rc = 1;
607
			} else if (len == 4) {
L
Linus Torvalds 已提交
608
				/* check for .. */
609
				if ((ufilename[0] == UNICODE_DOT)
S
Steve French 已提交
610
				   && (ufilename[1] == UNICODE_DOT))
L
Linus Torvalds 已提交
611 612 613
					rc = 2;
			}
		} else /* ASCII */ {
614
			if (len == 1) {
S
Steve French 已提交
615
				if (filename[0] == '.')
L
Linus Torvalds 已提交
616
					rc = 1;
617
			} else if (len == 2) {
S
Steve French 已提交
618
				if ((filename[0] == '.') && (filename[1] == '.'))
L
Linus Torvalds 已提交
619 620 621 622 623 624 625 626
					rc = 2;
			}
		}
	}

	return rc;
}

627 628
/* 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 已提交
629
static int is_dir_changed(struct file *file)
630
{
631 632
	struct inode *inode = file->f_path.dentry->d_inode;
	struct cifsInodeInfo *cifsInfo = CIFS_I(inode);
633

634
	if (cifsInfo->time == 0)
635 636 637 638 639 640
		return 1; /* directory was changed, perhaps due to unlink */
	else
		return 0;

}

641 642 643 644 645 646 647 648 649 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
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 已提交
705 706 707 708 709 710 711
/* 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 已提交
712
	struct file *file, char **ppCurrentEntry, int *num_to_ret)
L
Linus Torvalds 已提交
713 714 715 716 717
{
	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 已提交
718
	struct cifsFileInfo *cifsFile = file->private_data;
L
Linus Torvalds 已提交
719
	/* check if index in the buffer */
720

S
Steve French 已提交
721
	if ((cifsFile == NULL) || (ppCurrentEntry == NULL) ||
722
	   (num_to_ret == NULL))
L
Linus Torvalds 已提交
723
		return -ENOENT;
724

L
Linus Torvalds 已提交
725
	*ppCurrentEntry = NULL;
S
Steve French 已提交
726 727
	first_entry_in_buffer =
		cifsFile->srch_inf.index_of_last_entry -
L
Linus Torvalds 已提交
728
			cifsFile->srch_inf.entries_in_buffer;
729 730 731 732 733 734 735

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

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

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

		current_entry = cifsFile->srch_inf.srch_entries_start;
L
Linus Torvalds 已提交
788 789 790
		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 已提交
791
		cFYI(1, ("found entry - pos_in_buf %d", pos_in_buf));
792

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

S
Steve French 已提交
811 812
	if (pos_in_buf >= cifsFile->srch_inf.entries_in_buffer) {
		cFYI(1, ("can not return entries pos_in_buf beyond last"));
L
Linus Torvalds 已提交
813 814 815 816 817 818 819 820 821 822
		*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,
823
	struct cifs_sb_info *cifs_sb, int max_len, __u64 *pinum)
L
Linus Torvalds 已提交
824 825 826
{
	int rc = 0;
	unsigned int len = 0;
S
Steve French 已提交
827 828
	char *filename;
	struct nls_table *nlt = cifs_sb->local_nls;
L
Linus Torvalds 已提交
829 830 831

	*pinum = 0;

S
Steve French 已提交
832
	if (level == SMB_FIND_FILE_UNIX) {
S
Steve French 已提交
833
		FILE_UNIX_INFO *pFindData = (FILE_UNIX_INFO *)current_entry;
L
Linus Torvalds 已提交
834 835

		filename = &pFindData->FileName[0];
S
Steve French 已提交
836
		if (unicode) {
L
Linus Torvalds 已提交
837 838 839 840 841 842
			len = cifs_unicode_bytelen(filename);
		} else {
			/* BB should we make this strnlen of PATH_MAX? */
			len = strnlen(filename, PATH_MAX);
		}

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

S
Steve French 已提交
876
	if (len > max_len) {
S
Steve French 已提交
877
		cERROR(1, ("bad search response length %d past smb end", len));
878 879 880
		return -EINVAL;
	}

S
Steve French 已提交
881
	if (unicode) {
L
Linus Torvalds 已提交
882 883
		/* BB fixme - test with long names */
		/* Note converted filename can be longer than in unicode */
S
Steve French 已提交
884
		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR)
885 886 887 888
			pqst->len = cifs_convertUCSpath((char *)pqst->name,
					(__le16 *)filename, len/2, nlt);
		else
			pqst->len = cifs_strfromUCS_le((char *)pqst->name,
S
Steve French 已提交
889
					(__le16 *)filename, len/2, nlt);
L
Linus Torvalds 已提交
890 891 892 893
	} else {
		pqst->name = filename;
		pqst->len = len;
	}
S
Steve French 已提交
894
	pqst->hash = full_name_hash(pqst->name, pqst->len);
S
Steve French 已提交
895
/*	cFYI(1, ("filldir on %s",pqst->name));  */
L
Linus Torvalds 已提交
896 897 898 899
	return rc;
}

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

	pCifsF = file->private_data;
918

S
Steve French 已提交
919
	if ((scratch_buf == NULL) || (pfindEntry == NULL) || (pCifsF == NULL))
L
Linus Torvalds 已提交
920 921
		return -ENOENT;

S
Steve French 已提交
922
	rc = cifs_entry_is_dot(pfindEntry, pCifsF);
923
	/* skip . and .. since we added them first */
S
Steve French 已提交
924
	if (rc != 0)
925 926
		return 0;

927
	cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
L
Linus Torvalds 已提交
928 929

	qstring.name = scratch_buf;
S
Steve French 已提交
930
	rc = cifs_get_name_from_search_buf(&qstring, pfindEntry,
L
Linus Torvalds 已提交
931
			pCifsF->srch_inf.info_level,
S
Steve French 已提交
932
			pCifsF->srch_inf.unicode, cifs_sb,
933
			max_len,
L
Linus Torvalds 已提交
934 935
			&inum /* returned */);

S
Steve French 已提交
936
	if (rc)
L
Linus Torvalds 已提交
937 938
		return rc;

939 940 941 942 943 944 945 946 947
	/* 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 已提交
948
	if ((tmp_inode == NULL) || (tmp_dentry == NULL))
L
Linus Torvalds 已提交
949 950
		return -ENOMEM;

S
Steve French 已提交
951 952 953
	/* 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 已提交
954
	if (pCifsF->srch_inf.info_level == SMB_FIND_FILE_UNIX)
S
Steve French 已提交
955
		unix_fill_in_inode(tmp_inode,
956 957
				   (FILE_UNIX_INFO *)pfindEntry,
				   &obj_type, rc);
S
Steve French 已提交
958
	else if (pCifsF->srch_inf.info_level == SMB_FIND_FILE_INFO_STANDARD)
959 960 961 962
		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);
963

S
Steve French 已提交
964
	if (rc) /* new inode - needs to be tied to dentry */ {
965
		d_instantiate(tmp_dentry, tmp_inode);
S
Steve French 已提交
966
		if (rc == 2)
967 968
			d_rehash(tmp_dentry);
	}
969

S
Steve French 已提交
970 971 972

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

	dput(tmp_dentry);
	return rc;
}


int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
{
	int rc = 0;
S
Steve French 已提交
989
	int xid, i;
L
Linus Torvalds 已提交
990 991 992
	struct cifs_sb_info *cifs_sb;
	struct cifsTconInfo *pTcon;
	struct cifsFileInfo *cifsFile = NULL;
S
Steve French 已提交
993
	char *current_entry;
L
Linus Torvalds 已提交
994
	int num_to_fill = 0;
S
Steve French 已提交
995
	char *tmp_buf = NULL;
996
	char *end_of_smb;
997
	int max_len;
L
Linus Torvalds 已提交
998 999 1000

	xid = GetXid();

1001
	cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
L
Linus Torvalds 已提交
1002
	pTcon = cifs_sb->tcon;
S
Steve French 已提交
1003
	if (pTcon == NULL)
L
Linus Torvalds 已提交
1004 1005 1006 1007
		return -EINVAL;

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

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

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

1071 1072 1073 1074 1075
		/* 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. cifs_unicode.c,
		which actually does the conversion, has the same limit */
		tmp_buf = kmalloc((2 * NAME_MAX) + 4, GFP_KERNEL);
S
Steve French 已提交
1076 1077
		for (i = 0; (i < num_to_fill) && (rc == 0); i++) {
			if (current_entry == NULL) {
L
Linus Torvalds 已提交
1078
				/* evaluate whether this case is an error */
1079
				cERROR(1, ("past SMB end,  num to fill %d i %d",
L
Linus Torvalds 已提交
1080 1081 1082
					  num_to_fill, i));
				break;
			}
1083 1084
			/* if buggy server returns . and .. late do
			we want to check for that here? */
1085 1086
			rc = cifs_filldir(current_entry, file,
					filldir, direntry, tmp_buf, max_len);
S
Steve French 已提交
1087
			if (rc == -EOVERFLOW) {
1088 1089 1090 1091
				rc = 0;
				break;
			}

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

rddir2_exit:
	FreeXid(xid);
	return rc;
}