readdir.c 34.1 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 60 61 62 63 64 65 66 67 68

/* Returns one if new inode created (which therefore needs to be hashed) */
/* Might check in the future if inode number changed so we can rehash inode */
static int construct_dentry(struct qstr *qstring, struct file *file,
	struct inode **ptmp_inode, struct dentry **pnew_dentry)
{
	struct dentry *tmp_dentry;
	struct cifs_sb_info *cifs_sb;
	struct cifsTconInfo *pTcon;
	int rc = 0;

S
Steve French 已提交
69
	cFYI(1, ("For %s", qstring->name));
70
	cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
L
Linus Torvalds 已提交
71 72 73
	pTcon = cifs_sb->tcon;

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

96
		*ptmp_inode = new_inode(file->f_path.dentry->d_sb);
97 98 99 100
		if (pTcon->nocase)
			tmp_dentry->d_op = &cifs_ci_dentry_ops;
		else
			tmp_dentry->d_op = &cifs_dentry_ops;
101
		if (*ptmp_inode == NULL)
L
Linus Torvalds 已提交
102
			return rc;
103
		if (file->f_path.dentry->d_sb->s_flags & MS_NOATIME)
S
Steve French 已提交
104
			(*ptmp_inode)->i_flags |= S_NOATIME | S_NOCMTIME;
105
		rc = 2;
L
Linus Torvalds 已提交
106 107 108 109 110 111 112
	}

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

	return rc;
}

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

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

}

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

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

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

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

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

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

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

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

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

	*pinum = 0;

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

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

S
Steve French 已提交
841
		/* BB fixme - hash low and high 32 bits if not 64 bit arch BB */
S
Steve French 已提交
842
		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)
L
Linus Torvalds 已提交
843
			*pinum = 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 859
			(SEARCH_ID_FULL_DIR_INFO *)current_entry;
		filename = &pFindData->FileName[0];
		len = le32_to_cpu(pFindData->FileNameLength);
		*pinum = 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;
L
Linus Torvalds 已提交
906
	ino_t  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;

S
Steve French 已提交
939
	rc = construct_dentry(&qstring, file, &tmp_inode, &tmp_dentry);
S
Steve French 已提交
940
	if ((tmp_inode == NULL) || (tmp_dentry == NULL))
L
Linus Torvalds 已提交
941 942
		return -ENOMEM;

S
Steve French 已提交
943
	if (rc) {
L
Linus Torvalds 已提交
944
		/* inode created, we need to hash it with right inode number */
S
Steve French 已提交
945
		if (inum != 0) {
S
Steve French 已提交
946 947
			/* BB fixme - hash the 2 32 quantities bits together if
			 *  necessary BB */
L
Linus Torvalds 已提交
948 949 950 951 952
			tmp_inode->i_ino = inum;
		}
		insert_inode_hash(tmp_inode);
	}

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

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

S
Steve French 已提交
972 973 974

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

	dput(tmp_dentry);
	return rc;
}


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

	xid = GetXid();

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

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

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

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

1073 1074 1075 1076 1077
		/* 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 已提交
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;
}