dir.c 16.4 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4
/*
 *   fs/cifs/dir.c
 *
 *   vfs operations that deal with dentries
S
Steve French 已提交
5
 *
6
 *   Copyright (C) International Business Machines  Corp., 2002,2005
L
Linus Torvalds 已提交
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
 *   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>
#include <linux/stat.h>
#include <linux/slab.h>
#include <linux/namei.h>
#include "cifsfs.h"
#include "cifspdu.h"
#include "cifsglob.h"
#include "cifsproto.h"
#include "cifs_debug.h"
#include "cifs_fs_sb.h"

34
static void
L
Linus Torvalds 已提交
35 36
renew_parental_timestamps(struct dentry *direntry)
{
S
Steve French 已提交
37 38
	/* BB check if there is a way to get the kernel to do this or if we
	   really need this */
L
Linus Torvalds 已提交
39 40 41
	do {
		direntry->d_time = jiffies;
		direntry = direntry->d_parent;
S
Steve French 已提交
42
	} while (!IS_ROOT(direntry));
L
Linus Torvalds 已提交
43 44 45 46 47 48 49
}

/* Note: caller must free return buffer */
char *
build_path_from_dentry(struct dentry *direntry)
{
	struct dentry *temp;
50 51
	int namelen;
	int pplen;
L
Linus Torvalds 已提交
52
	char *full_path;
53
	char dirsep;
L
Linus Torvalds 已提交
54

S
Steve French 已提交
55
	if (direntry == NULL)
L
Linus Torvalds 已提交
56 57 58 59
		return NULL;  /* not much we can do if dentry is freed and
		we need to reopen the file after it was closed implicitly
		when the server crashed */

60
	dirsep = CIFS_DIR_SEP(CIFS_SB(direntry->d_sb));
61
	pplen = CIFS_SB(direntry->d_sb)->prepathlen;
L
Linus Torvalds 已提交
62
cifs_bp_rename_retry:
S
Steve French 已提交
63
	namelen = pplen;
L
Linus Torvalds 已提交
64 65 66
	for (temp = direntry; !IS_ROOT(temp);) {
		namelen += (1 + temp->d_name.len);
		temp = temp->d_parent;
S
Steve French 已提交
67 68
		if (temp == NULL) {
			cERROR(1, ("corrupt dentry"));
L
Linus Torvalds 已提交
69 70 71 72 73
			return NULL;
		}
	}

	full_path = kmalloc(namelen+1, GFP_KERNEL);
S
Steve French 已提交
74
	if (full_path == NULL)
L
Linus Torvalds 已提交
75 76 77 78 79 80 81
		return full_path;
	full_path[namelen] = 0;	/* trailing null */
	for (temp = direntry; !IS_ROOT(temp);) {
		namelen -= 1 + temp->d_name.len;
		if (namelen < 0) {
			break;
		} else {
82
			full_path[namelen] = dirsep;
L
Linus Torvalds 已提交
83 84
			strncpy(full_path + namelen + 1, temp->d_name.name,
				temp->d_name.len);
85
			cFYI(0, ("name: %s", full_path + namelen));
L
Linus Torvalds 已提交
86 87
		}
		temp = temp->d_parent;
S
Steve French 已提交
88 89
		if (temp == NULL) {
			cERROR(1, ("corrupt dentry"));
L
Linus Torvalds 已提交
90 91 92 93
			kfree(full_path);
			return NULL;
		}
	}
94
	if (namelen != pplen) {
L
Linus Torvalds 已提交
95
		cERROR(1,
96
		       ("did not end path lookup where expected namelen is %d",
L
Linus Torvalds 已提交
97
			namelen));
S
Steve French 已提交
98
		/* presumably this is only possible if racing with a rename
L
Linus Torvalds 已提交
99 100 101 102 103
		of one of the parent directories  (we can not lock the dentries
		above us to prevent this, but retrying should be harmless) */
		kfree(full_path);
		goto cifs_bp_rename_retry;
	}
104 105 106 107 108 109
	/* DIR_SEP already set for byte  0 / vs \ but not for
	   subsequent slashes in prepath which currently must
	   be entered the right way - not sure if there is an alternative
	   since the '\' is a valid posix character so we can not switch
	   those safely to '/' if any are found in the middle of the prepath */
	/* BB test paths to Windows with '/' in the midst of prepath */
S
Steve French 已提交
110
	strncpy(full_path, CIFS_SB(direntry->d_sb)->prepath, pplen);
L
Linus Torvalds 已提交
111 112 113
	return full_path;
}

114
/* char * build_wildcard_path_from_dentry(struct dentry *direntry)
L
Linus Torvalds 已提交
115 116 117 118 119 120
{
	if(full_path == NULL)
		return full_path;

	full_path[namelen] = '\\';
	full_path[namelen+1] = '*';
121 122
	full_path[namelen+2] = 0;
BB remove above eight lines BB */
L
Linus Torvalds 已提交
123

124
/* Inode operations in similar order to how they appear in Linux file fs.h */
L
Linus Torvalds 已提交
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150

int
cifs_create(struct inode *inode, struct dentry *direntry, int mode,
		struct nameidata *nd)
{
	int rc = -ENOENT;
	int xid;
	int oplock = 0;
	int desiredAccess = GENERIC_READ | GENERIC_WRITE;
	__u16 fileHandle;
	struct cifs_sb_info *cifs_sb;
	struct cifsTconInfo *pTcon;
	char *full_path = NULL;
	FILE_ALL_INFO * buf = NULL;
	struct inode *newinode = NULL;
	struct cifsFileInfo * pCifsFile = NULL;
	struct cifsInodeInfo * pCifsInode;
	int disposition = FILE_OVERWRITE_IF;
	int write_only = FALSE;

	xid = GetXid();

	cifs_sb = CIFS_SB(inode->i_sb);
	pTcon = cifs_sb->tcon;

	full_path = build_path_from_dentry(direntry);
S
Steve French 已提交
151
	if (full_path == NULL) {
L
Linus Torvalds 已提交
152 153 154 155
		FreeXid(xid);
		return -ENOMEM;
	}

S
Steve French 已提交
156
	if (nd && (nd->flags & LOOKUP_OPEN)) {
M
Miklos Szeredi 已提交
157 158 159 160 161 162 163 164 165
		int oflags = nd->intent.open.flags;

		desiredAccess = 0;
		if (oflags & FMODE_READ)
			desiredAccess |= GENERIC_READ;
		if (oflags & FMODE_WRITE) {
			desiredAccess |= GENERIC_WRITE;
			if (!(oflags & FMODE_READ))
				write_only = TRUE;
L
Linus Torvalds 已提交
166 167
		}

S
Steve French 已提交
168
		if ((oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
L
Linus Torvalds 已提交
169
			disposition = FILE_CREATE;
S
Steve French 已提交
170
		else if ((oflags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC))
L
Linus Torvalds 已提交
171
			disposition = FILE_OVERWRITE_IF;
S
Steve French 已提交
172
		else if ((oflags & O_CREAT) == O_CREAT)
L
Linus Torvalds 已提交
173 174
			disposition = FILE_OPEN_IF;
		else {
S
Steve French 已提交
175
			cFYI(1, ("Create flag not set in create function"));
L
Linus Torvalds 已提交
176 177 178
		}
	}

S
Steve French 已提交
179 180
	/* BB add processing to set equivalent of mode - e.g. via CreateX with
	   ACLs */
L
Linus Torvalds 已提交
181 182 183
	if (oplockEnabled)
		oplock = REQ_OPLOCK;

S
Steve French 已提交
184 185
	buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
	if (buf == NULL) {
L
Linus Torvalds 已提交
186 187 188 189
		kfree(full_path);
		FreeXid(xid);
		return -ENOMEM;
	}
S
Steve French 已提交
190
	if (cifs_sb->tcon->ses->capabilities & CAP_NT_SMBS)
191
		rc = CIFSSMBOpen(xid, pTcon, full_path, disposition,
L
Linus Torvalds 已提交
192
			 desiredAccess, CREATE_NOT_DIR,
193 194
			 &fileHandle, &oplock, buf, cifs_sb->local_nls,
			 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
195 196 197
	else
		rc = -EIO; /* no NT SMB support fall into legacy open below */

S
Steve French 已提交
198
	if (rc == -EIO) {
199 200 201 202 203
		/* old server, retry the open legacy style */
		rc = SMBLegacyOpen(xid, pTcon, full_path, disposition,
			desiredAccess, CREATE_NOT_DIR,
			&fileHandle, &oplock, buf, cifs_sb->local_nls,
			cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
S
Steve French 已提交
204
	}
L
Linus Torvalds 已提交
205
	if (rc) {
206
		cFYI(1, ("cifs_create returned 0x%x", rc));
L
Linus Torvalds 已提交
207 208 209 210 211
	} else {
		/* If Open reported that we actually created a file
		then we now have to set the mode if possible */
		if ((cifs_sb->tcon->ses->capabilities & CAP_UNIX) &&
			(oplock & CIFS_CREATE_ACTION))
S
Steve French 已提交
212
			if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
L
Linus Torvalds 已提交
213
				CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode,
214 215
					(__u64)current->fsuid,
					(__u64)current->fsgid,
L
Linus Torvalds 已提交
216
					0 /* dev */,
S
Steve French 已提交
217 218
					cifs_sb->local_nls,
					cifs_sb->mnt_cifs_flags &
219
						CIFS_MOUNT_MAP_SPECIAL_CHR);
L
Linus Torvalds 已提交
220 221 222 223 224
			} else {
				CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode,
					(__u64)-1,
					(__u64)-1,
					0 /* dev */,
225
					cifs_sb->local_nls,
S
Steve French 已提交
226
					cifs_sb->mnt_cifs_flags &
227
						CIFS_MOUNT_MAP_SPECIAL_CHR);
L
Linus Torvalds 已提交
228 229
			}
		else {
S
Steve French 已提交
230 231 232 233 234
			/* BB implement mode setting via Windows security
			   descriptors e.g. */
			/* CIFSSMBWinSetPerms(xid,pTcon,path,mode,-1,-1,nls);*/

			/* Could set r/o dos attribute if mode & 0222 == 0 */
L
Linus Torvalds 已提交
235 236 237 238 239
		}

	/* BB server might mask mode so we have to query for Unix case*/
		if (pTcon->ses->capabilities & CAP_UNIX)
			rc = cifs_get_inode_info_unix(&newinode, full_path,
S
Steve French 已提交
240
						 inode->i_sb, xid);
L
Linus Torvalds 已提交
241 242
		else {
			rc = cifs_get_inode_info(&newinode, full_path,
S
Steve French 已提交
243 244
						 buf, inode->i_sb, xid);
			if (newinode) {
L
Linus Torvalds 已提交
245
				newinode->i_mode = mode;
S
Steve French 已提交
246 247
				if ((oplock & CIFS_CREATE_ACTION) &&
				    (cifs_sb->mnt_cifs_flags &
248 249 250 251 252
				     CIFS_MOUNT_SET_UID)) {
					newinode->i_uid = current->fsuid;
					newinode->i_gid = current->fsgid;
				}
			}
L
Linus Torvalds 已提交
253 254 255
		}

		if (rc != 0) {
256 257
			cFYI(1,
			     ("Create worked but get_inode_info failed rc = %d",
L
Linus Torvalds 已提交
258 259
			      rc));
		} else {
260 261 262 263
			if (pTcon->nocase)
				direntry->d_op = &cifs_ci_dentry_ops;
			else
				direntry->d_op = &cifs_dentry_ops;
L
Linus Torvalds 已提交
264 265
			d_instantiate(direntry, newinode);
		}
S
Steve French 已提交
266
		if ((nd->flags & LOOKUP_OPEN) == FALSE) {
L
Linus Torvalds 已提交
267 268
			/* mknod case - do not leave file open */
			CIFSSMBClose(xid, pTcon, fileHandle);
S
Steve French 已提交
269
		} else if (newinode) {
270
			pCifsFile =
271
			   kzalloc(sizeof (struct cifsFileInfo), GFP_KERNEL);
S
Steve French 已提交
272

S
Steve French 已提交
273
			if (pCifsFile == NULL)
274 275 276 277 278 279 280
				goto cifs_create_out;
			pCifsFile->netfid = fileHandle;
			pCifsFile->pid = current->tgid;
			pCifsFile->pInode = newinode;
			pCifsFile->invalidHandle = FALSE;
			pCifsFile->closePend     = FALSE;
			init_MUTEX(&pCifsFile->fh_sem);
281
			mutex_init(&pCifsFile->lock_mutex);
282
			INIT_LIST_HEAD(&pCifsFile->llist);
S
Steve French 已提交
283
			atomic_set(&pCifsFile->wrtPending, 0);
284

S
Steve French 已提交
285
			/* set the following in open now
286 287
				pCifsFile->pfile = file; */
			write_lock(&GlobalSMBSeslock);
S
Steve French 已提交
288
			list_add(&pCifsFile->tlist, &pTcon->openFileList);
289
			pCifsInode = CIFS_I(newinode);
S
Steve French 已提交
290
			if (pCifsInode) {
L
Linus Torvalds 已提交
291
				/* if readable file instance put first in list*/
292
				if (write_only == TRUE) {
S
Steve French 已提交
293
					list_add_tail(&pCifsFile->flist,
294 295 296 297
						&pCifsInode->openFileList);
				} else {
					list_add(&pCifsFile->flist,
						&pCifsInode->openFileList);
L
Linus Torvalds 已提交
298
				}
S
Steve French 已提交
299
				if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
300 301
					pCifsInode->clientCanCacheAll = TRUE;
					pCifsInode->clientCanCacheRead = TRUE;
S
Steve French 已提交
302
					cFYI(1, ("Exclusive Oplock inode %p",
303
						newinode));
S
Steve French 已提交
304
				} else if ((oplock & 0xF) == OPLOCK_READ)
305
					pCifsInode->clientCanCacheRead = TRUE;
L
Linus Torvalds 已提交
306
			}
307
			write_unlock(&GlobalSMBSeslock);
L
Linus Torvalds 已提交
308
		}
S
Steve French 已提交
309
	}
310 311 312
cifs_create_out:
	kfree(buf);
	kfree(full_path);
L
Linus Torvalds 已提交
313 314 315 316
	FreeXid(xid);
	return rc;
}

S
Steve French 已提交
317 318
int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode,
		dev_t device_number)
L
Linus Torvalds 已提交
319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335
{
	int rc = -EPERM;
	int xid;
	struct cifs_sb_info *cifs_sb;
	struct cifsTconInfo *pTcon;
	char *full_path = NULL;
	struct inode * newinode = NULL;

	if (!old_valid_dev(device_number))
		return -EINVAL;

	xid = GetXid();

	cifs_sb = CIFS_SB(inode->i_sb);
	pTcon = cifs_sb->tcon;

	full_path = build_path_from_dentry(direntry);
S
Steve French 已提交
336
	if (full_path == NULL)
L
Linus Torvalds 已提交
337
		rc = -ENOMEM;
338
	else if (pTcon->ses->capabilities & CAP_UNIX) {
S
Steve French 已提交
339
		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
L
Linus Torvalds 已提交
340
			rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path,
S
Steve French 已提交
341 342
				mode, (__u64)current->fsuid,
				(__u64)current->fsgid,
343
				device_number, cifs_sb->local_nls,
S
Steve French 已提交
344
				cifs_sb->mnt_cifs_flags &
345
					CIFS_MOUNT_MAP_SPECIAL_CHR);
L
Linus Torvalds 已提交
346 347 348
		} else {
			rc = CIFSSMBUnixSetPerms(xid, pTcon,
				full_path, mode, (__u64)-1, (__u64)-1,
349
				device_number, cifs_sb->local_nls,
S
Steve French 已提交
350
				cifs_sb->mnt_cifs_flags &
351
					CIFS_MOUNT_MAP_SPECIAL_CHR);
L
Linus Torvalds 已提交
352 353
		}

S
Steve French 已提交
354
		if (!rc) {
L
Linus Torvalds 已提交
355
			rc = cifs_get_inode_info_unix(&newinode, full_path,
S
Steve French 已提交
356
						inode->i_sb, xid);
357 358 359 360
			if (pTcon->nocase)
				direntry->d_op = &cifs_ci_dentry_ops;
			else
				direntry->d_op = &cifs_dentry_ops;
S
Steve French 已提交
361
			if (rc == 0)
L
Linus Torvalds 已提交
362 363
				d_instantiate(direntry, newinode);
		}
364
	} else {
S
Steve French 已提交
365
		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
366 367 368
			int oplock = 0;
			u16 fileHandle;
			FILE_ALL_INFO * buf;
369

S
Steve French 已提交
370
			cFYI(1, ("sfu compat create special file"));
371

S
Steve French 已提交
372 373
			buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
			if (buf == NULL) {
374 375 376 377 378 379 380
				kfree(full_path);
				FreeXid(xid);
				return -ENOMEM;
			}

			rc = CIFSSMBOpen(xid, pTcon, full_path,
					 FILE_CREATE, /* fail if exists */
S
Steve French 已提交
381
					 GENERIC_WRITE /* BB would
382 383 384 385 386 387
					  WRITE_OWNER | WRITE_DAC be better? */,
					 /* Create a file and set the
					    file attribute to SYSTEM */
					 CREATE_NOT_DIR | CREATE_OPTION_SPECIAL,
					 &fileHandle, &oplock, buf,
					 cifs_sb->local_nls,
S
Steve French 已提交
388
					 cifs_sb->mnt_cifs_flags &
389 390
					    CIFS_MOUNT_MAP_SPECIAL_CHR);

391 392
			/* BB FIXME - add handling for backlevel servers
			   which need legacy open and check for all
S
Steve French 已提交
393 394
			   calls to SMBOpen for fallback to SMBLeagcyOpen */
			if (!rc) {
395
				/* BB Do not bother to decode buf since no
396 397 398 399 400
				   local inode yet to put timestamps in,
				   but we can reuse it safely */
				int bytes_written;
				struct win_dev *pdev;
				pdev = (struct win_dev *)buf;
S
Steve French 已提交
401
				if (S_ISCHR(mode)) {
402 403 404
					memcpy(pdev->type, "IntxCHR", 8);
					pdev->major =
					      cpu_to_le64(MAJOR(device_number));
S
Steve French 已提交
405
					pdev->minor =
406 407 408 409 410 411
					      cpu_to_le64(MINOR(device_number));
					rc = CIFSSMBWrite(xid, pTcon,
						fileHandle,
						sizeof(struct win_dev),
						0, &bytes_written, (char *)pdev,
						NULL, 0);
S
Steve French 已提交
412
				} else if (S_ISBLK(mode)) {
413 414 415 416 417 418 419 420 421 422 423
					memcpy(pdev->type, "IntxBLK", 8);
					pdev->major =
					      cpu_to_le64(MAJOR(device_number));
					pdev->minor =
					      cpu_to_le64(MINOR(device_number));
					rc = CIFSSMBWrite(xid, pTcon,
						fileHandle,
						sizeof(struct win_dev),
						0, &bytes_written, (char *)pdev,
						NULL, 0);
				} /* else if(S_ISFIFO */
424 425 426 427
				CIFSSMBClose(xid, pTcon, fileHandle);
				d_drop(direntry);
			}
			kfree(buf);
428 429
			/* add code here to set EAs */
		}
L
Linus Torvalds 已提交
430 431
	}

432
	kfree(full_path);
L
Linus Torvalds 已提交
433 434 435 436 437 438
	FreeXid(xid);
	return rc;
}


struct dentry *
S
Steve French 已提交
439 440
cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
	    struct nameidata *nd)
L
Linus Torvalds 已提交
441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459
{
	int xid;
	int rc = 0; /* to get around spurious gcc warning, set to zero here */
	struct cifs_sb_info *cifs_sb;
	struct cifsTconInfo *pTcon;
	struct inode *newInode = NULL;
	char *full_path = NULL;

	xid = GetXid();

	cFYI(1,
	     (" parent inode = 0x%p name is: %s and dentry = 0x%p",
	      parent_dir_inode, direntry->d_name.name, direntry));

	/* check whether path exists */

	cifs_sb = CIFS_SB(parent_dir_inode->i_sb);
	pTcon = cifs_sb->tcon;

460 461 462 463 464 465 466 467 468 469 470 471 472 473
	/*
	 * Don't allow the separator character in a path component.
	 * The VFS will not allow "/", but "\" is allowed by posix.
	 */
	if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)) {
		int i;
		for (i = 0; i < direntry->d_name.len; i++)
			if (direntry->d_name.name[i] == '\\') {
				cFYI(1, ("Invalid file name"));
				FreeXid(xid);
				return ERR_PTR(-EINVAL);
			}
	}

L
Linus Torvalds 已提交
474 475 476 477
	/* can not grab the rename sem here since it would
	deadlock in the cases (beginning of sys_rename itself)
	in which we already have the sb rename sem */
	full_path = build_path_from_dentry(direntry);
S
Steve French 已提交
478
	if (full_path == NULL) {
L
Linus Torvalds 已提交
479 480 481 482 483 484 485 486 487 488 489 490 491 492
		FreeXid(xid);
		return ERR_PTR(-ENOMEM);
	}

	if (direntry->d_inode != NULL) {
		cFYI(1, (" non-NULL inode in lookup"));
	} else {
		cFYI(1, (" NULL inode in lookup"));
	}
	cFYI(1,
	     (" Full path: %s inode = 0x%p", full_path, direntry->d_inode));

	if (pTcon->ses->capabilities & CAP_UNIX)
		rc = cifs_get_inode_info_unix(&newInode, full_path,
S
Steve French 已提交
493
					      parent_dir_inode->i_sb, xid);
L
Linus Torvalds 已提交
494 495
	else
		rc = cifs_get_inode_info(&newInode, full_path, NULL,
S
Steve French 已提交
496
					 parent_dir_inode->i_sb, xid);
L
Linus Torvalds 已提交
497 498

	if ((rc == 0) && (newInode != NULL)) {
499 500 501 502
		if (pTcon->nocase)
			direntry->d_op = &cifs_ci_dentry_ops;
		else
			direntry->d_op = &cifs_dentry_ops;
L
Linus Torvalds 已提交
503 504
		d_add(direntry, newInode);

S
Steve French 已提交
505
		/* since paths are not looked up by component - the parent
506
		   directories are presumed to be good here */
L
Linus Torvalds 已提交
507 508 509 510
		renew_parental_timestamps(direntry);

	} else if (rc == -ENOENT) {
		rc = 0;
511 512 513 514 515
		direntry->d_time = jiffies;
		if (pTcon->nocase)
			direntry->d_op = &cifs_ci_dentry_ops;
		else
			direntry->d_op = &cifs_dentry_ops;
L
Linus Torvalds 已提交
516
		d_add(direntry, NULL);
S
Steve French 已提交
517 518
	/*	if it was once a directory (but how can we tell?) we could do
		shrink_dcache_parent(direntry); */
L
Linus Torvalds 已提交
519
	} else {
S
Steve French 已提交
520
		cERROR(1, ("Error 0x%x on cifs_get_inode_info in lookup of %s",
S
Steve French 已提交
521 522 523
			   rc, full_path));
		/* BB special case check for Access Denied - watch security
		exposure of returning dir info implicitly via different rc
L
Linus Torvalds 已提交
524 525 526
		if file exists or not but no access BB */
	}

527
	kfree(full_path);
L
Linus Torvalds 已提交
528 529 530 531 532 533 534 535 536 537 538 539 540 541
	FreeXid(xid);
	return ERR_PTR(rc);
}

static int
cifs_d_revalidate(struct dentry *direntry, struct nameidata *nd)
{
	int isValid = 1;

	if (direntry->d_inode) {
		if (cifs_revalidate(direntry)) {
			return 0;
		}
	} else {
542 543
		cFYI(1, ("neg dentry 0x%p name = %s",
			 direntry, direntry->d_name.name));
S
Steve French 已提交
544
		if (time_after(jiffies, direntry->d_time + HZ) ||
545 546 547
			!lookupCacheEnabled) {
			d_drop(direntry);
			isValid = 0;
S
Steve French 已提交
548
		}
L
Linus Torvalds 已提交
549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564
	}

	return isValid;
}

/* static int cifs_d_delete(struct dentry *direntry)
{
	int rc = 0;

	cFYI(1, ("In cifs d_delete, name = %s", direntry->d_name.name));

	return rc;
}     */

struct dentry_operations cifs_dentry_ops = {
	.d_revalidate = cifs_d_revalidate,
S
Steve French 已提交
565
/* d_delete:       cifs_d_delete,      */ /* not needed except for debugging */
L
Linus Torvalds 已提交
566
};
567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605

static int cifs_ci_hash(struct dentry *dentry, struct qstr *q)
{
	struct nls_table *codepage = CIFS_SB(dentry->d_inode->i_sb)->local_nls;
	unsigned long hash;
	int i;

	hash = init_name_hash();
	for (i = 0; i < q->len; i++)
		hash = partial_name_hash(nls_tolower(codepage, q->name[i]),
					 hash);
	q->hash = end_name_hash(hash);

	return 0;
}

static int cifs_ci_compare(struct dentry *dentry, struct qstr *a,
			   struct qstr *b)
{
	struct nls_table *codepage = CIFS_SB(dentry->d_inode->i_sb)->local_nls;

	if ((a->len == b->len) &&
	    (nls_strnicmp(codepage, a->name, b->name, a->len) == 0)) {
		/*
		 * To preserve case, don't let an existing negative dentry's
		 * case take precedence.  If a is not a negative dentry, this
		 * should have no side effects
		 */
		memcpy((unsigned char *)a->name, b->name, a->len);
		return 0;
	}
	return 1;
}

struct dentry_operations cifs_ci_dentry_ops = {
	.d_revalidate = cifs_d_revalidate,
	.d_hash = cifs_ci_hash,
	.d_compare = cifs_ci_compare,
};