1/*
2 *   fs/cifs/dir.c
3 *
4 *   vfs operations that deal with dentries
5 *
6 *   Copyright (C) International Business Machines  Corp., 2002,2005
7 *   Author(s): Steve French (sfrench@us.ibm.com)
8 *
9 *   This library is free software; you can redistribute it and/or modify
10 *   it under the terms of the GNU Lesser General Public License as published
11 *   by the Free Software Foundation; either version 2.1 of the License, or
12 *   (at your option) any later version.
13 *
14 *   This library is distributed in the hope that it will be useful,
15 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
16 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
17 *   the GNU Lesser General Public License for more details.
18 *
19 *   You should have received a copy of the GNU Lesser General Public License
20 *   along with this library; if not, write to the Free Software
21 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23#include <linux/fs.h>
24#include <linux/stat.h>
25#include <linux/slab.h>
26#include <linux/namei.h>
27#include "cifsfs.h"
28#include "cifspdu.h"
29#include "cifsglob.h"
30#include "cifsproto.h"
31#include "cifs_debug.h"
32#include "cifs_fs_sb.h"
33
34static void
35renew_parental_timestamps(struct dentry *direntry)
36{
37	/* BB check if there is a way to get the kernel to do this or if we
38	   really need this */
39	do {
40		direntry->d_time = jiffies;
41		direntry = direntry->d_parent;
42	} while (!IS_ROOT(direntry));
43}
44
45/* Note: caller must free return buffer */
46char *
47build_path_from_dentry(struct dentry *direntry)
48{
49	struct dentry *temp;
50	int namelen;
51	int pplen;
52	char *full_path;
53	char dirsep;
54
55	if (direntry == NULL)
56		return NULL;  /* not much we can do if dentry is freed and
57		we need to reopen the file after it was closed implicitly
58		when the server crashed */
59
60	dirsep = CIFS_DIR_SEP(CIFS_SB(direntry->d_sb));
61	pplen = CIFS_SB(direntry->d_sb)->prepathlen;
62cifs_bp_rename_retry:
63	namelen = pplen;
64	for (temp = direntry; !IS_ROOT(temp);) {
65		namelen += (1 + temp->d_name.len);
66		temp = temp->d_parent;
67		if (temp == NULL) {
68			cERROR(1, ("corrupt dentry"));
69			return NULL;
70		}
71	}
72
73	full_path = kmalloc(namelen+1, GFP_KERNEL);
74	if (full_path == NULL)
75		return full_path;
76	full_path[namelen] = 0;	/* trailing null */
77	for (temp = direntry; !IS_ROOT(temp);) {
78		namelen -= 1 + temp->d_name.len;
79		if (namelen < 0) {
80			break;
81		} else {
82			full_path[namelen] = dirsep;
83			strncpy(full_path + namelen + 1, temp->d_name.name,
84				temp->d_name.len);
85			cFYI(0, ("name: %s", full_path + namelen));
86		}
87		temp = temp->d_parent;
88		if (temp == NULL) {
89			cERROR(1, ("corrupt dentry"));
90			kfree(full_path);
91			return NULL;
92		}
93	}
94	if (namelen != pplen) {
95		cERROR(1,
96		       ("did not end path lookup where expected namelen is %d",
97			namelen));
98		/* presumably this is only possible if racing with a rename
99		of one of the parent directories  (we can not lock the dentries
100		above us to prevent this, but retrying should be harmless) */
101		kfree(full_path);
102		goto cifs_bp_rename_retry;
103	}
104	/* DIR_SEP already set for byte  0 / vs \ but not for
105	   subsequent slashes in prepath which currently must
106	   be entered the right way - not sure if there is an alternative
107	   since the '\' is a valid posix character so we can not switch
108	   those safely to '/' if any are found in the middle of the prepath */
109	/* BB test paths to Windows with '/' in the midst of prepath */
110	strncpy(full_path, CIFS_SB(direntry->d_sb)->prepath, pplen);
111	return full_path;
112}
113
114/* char * build_wildcard_path_from_dentry(struct dentry *direntry)
115{
116	if(full_path == NULL)
117		return full_path;
118
119	full_path[namelen] = '\\';
120	full_path[namelen+1] = '*';
121	full_path[namelen+2] = 0;
122BB remove above eight lines BB */
123
124/* Inode operations in similar order to how they appear in Linux file fs.h */
125
126int
127cifs_create(struct inode *inode, struct dentry *direntry, int mode,
128		struct nameidata *nd)
129{
130	int rc = -ENOENT;
131	int xid;
132	int oplock = 0;
133	int desiredAccess = GENERIC_READ | GENERIC_WRITE;
134	__u16 fileHandle;
135	struct cifs_sb_info *cifs_sb;
136	struct cifsTconInfo *pTcon;
137	char *full_path = NULL;
138	FILE_ALL_INFO * buf = NULL;
139	struct inode *newinode = NULL;
140	struct cifsFileInfo * pCifsFile = NULL;
141	struct cifsInodeInfo * pCifsInode;
142	int disposition = FILE_OVERWRITE_IF;
143	int write_only = FALSE;
144
145	xid = GetXid();
146
147	cifs_sb = CIFS_SB(inode->i_sb);
148	pTcon = cifs_sb->tcon;
149
150	full_path = build_path_from_dentry(direntry);
151	if (full_path == NULL) {
152		FreeXid(xid);
153		return -ENOMEM;
154	}
155
156	if (nd && (nd->flags & LOOKUP_OPEN)) {
157		int oflags = nd->intent.open.flags;
158
159		desiredAccess = 0;
160		if (oflags & FMODE_READ)
161			desiredAccess |= GENERIC_READ;
162		if (oflags & FMODE_WRITE) {
163			desiredAccess |= GENERIC_WRITE;
164			if (!(oflags & FMODE_READ))
165				write_only = TRUE;
166		}
167
168		if ((oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
169			disposition = FILE_CREATE;
170		else if ((oflags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC))
171			disposition = FILE_OVERWRITE_IF;
172		else if ((oflags & O_CREAT) == O_CREAT)
173			disposition = FILE_OPEN_IF;
174		else {
175			cFYI(1, ("Create flag not set in create function"));
176		}
177	}
178
179	/* BB add processing to set equivalent of mode - e.g. via CreateX with
180	   ACLs */
181	if (oplockEnabled)
182		oplock = REQ_OPLOCK;
183
184	buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
185	if (buf == NULL) {
186		kfree(full_path);
187		FreeXid(xid);
188		return -ENOMEM;
189	}
190	if (cifs_sb->tcon->ses->capabilities & CAP_NT_SMBS)
191		rc = CIFSSMBOpen(xid, pTcon, full_path, disposition,
192			 desiredAccess, CREATE_NOT_DIR,
193			 &fileHandle, &oplock, buf, cifs_sb->local_nls,
194			 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
195	else
196		rc = -EIO; /* no NT SMB support fall into legacy open below */
197
198	if (rc == -EIO) {
199		/* old server, retry the open legacy style */
200		rc = SMBLegacyOpen(xid, pTcon, full_path, disposition,
201			desiredAccess, CREATE_NOT_DIR,
202			&fileHandle, &oplock, buf, cifs_sb->local_nls,
203			cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
204	}
205	if (rc) {
206		cFYI(1, ("cifs_create returned 0x%x", rc));
207	} else {
208		/* If Open reported that we actually created a file
209		then we now have to set the mode if possible */
210		if ((cifs_sb->tcon->ses->capabilities & CAP_UNIX) &&
211			(oplock & CIFS_CREATE_ACTION)) {
212			mode &= ~current->fs->umask;
213			if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
214				CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode,
215					(__u64)current->fsuid,
216					(__u64)current->fsgid,
217					0 /* dev */,
218					cifs_sb->local_nls,
219					cifs_sb->mnt_cifs_flags &
220						CIFS_MOUNT_MAP_SPECIAL_CHR);
221			} else {
222				CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode,
223					(__u64)-1,
224					(__u64)-1,
225					0 /* dev */,
226					cifs_sb->local_nls,
227					cifs_sb->mnt_cifs_flags &
228						CIFS_MOUNT_MAP_SPECIAL_CHR);
229			}
230		} else {
231			/* BB implement mode setting via Windows security
232			   descriptors e.g. */
233			/* CIFSSMBWinSetPerms(xid,pTcon,path,mode,-1,-1,nls);*/
234
235			/* Could set r/o dos attribute if mode & 0222 == 0 */
236		}
237
238	/* BB server might mask mode so we have to query for Unix case*/
239		if (pTcon->ses->capabilities & CAP_UNIX)
240			rc = cifs_get_inode_info_unix(&newinode, full_path,
241						 inode->i_sb, xid);
242		else {
243			rc = cifs_get_inode_info(&newinode, full_path,
244						 buf, inode->i_sb, xid);
245			if (newinode) {
246				newinode->i_mode = mode;
247				if ((oplock & CIFS_CREATE_ACTION) &&
248				    (cifs_sb->mnt_cifs_flags &
249				     CIFS_MOUNT_SET_UID)) {
250					newinode->i_uid = current->fsuid;
251					newinode->i_gid = current->fsgid;
252				}
253			}
254		}
255
256		if (rc != 0) {
257			cFYI(1,
258			     ("Create worked but get_inode_info failed rc = %d",
259			      rc));
260		} else {
261			if (pTcon->nocase)
262				direntry->d_op = &cifs_ci_dentry_ops;
263			else
264				direntry->d_op = &cifs_dentry_ops;
265			d_instantiate(direntry, newinode);
266		}
267		if ((nd->flags & LOOKUP_OPEN) == FALSE) {
268			/* mknod case - do not leave file open */
269			CIFSSMBClose(xid, pTcon, fileHandle);
270		} else if (newinode) {
271			pCifsFile =
272			   kzalloc(sizeof (struct cifsFileInfo), GFP_KERNEL);
273
274			if (pCifsFile == NULL)
275				goto cifs_create_out;
276			pCifsFile->netfid = fileHandle;
277			pCifsFile->pid = current->tgid;
278			pCifsFile->pInode = newinode;
279			pCifsFile->invalidHandle = FALSE;
280			pCifsFile->closePend     = FALSE;
281			init_MUTEX(&pCifsFile->fh_sem);
282			mutex_init(&pCifsFile->lock_mutex);
283			INIT_LIST_HEAD(&pCifsFile->llist);
284			atomic_set(&pCifsFile->wrtPending, 0);
285
286			/* set the following in open now
287				pCifsFile->pfile = file; */
288			write_lock(&GlobalSMBSeslock);
289			list_add(&pCifsFile->tlist, &pTcon->openFileList);
290			pCifsInode = CIFS_I(newinode);
291			if (pCifsInode) {
292				/* if readable file instance put first in list*/
293				if (write_only == TRUE) {
294					list_add_tail(&pCifsFile->flist,
295						&pCifsInode->openFileList);
296				} else {
297					list_add(&pCifsFile->flist,
298						&pCifsInode->openFileList);
299				}
300				if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
301					pCifsInode->clientCanCacheAll = TRUE;
302					pCifsInode->clientCanCacheRead = TRUE;
303					cFYI(1, ("Exclusive Oplock inode %p",
304						newinode));
305				} else if ((oplock & 0xF) == OPLOCK_READ)
306					pCifsInode->clientCanCacheRead = TRUE;
307			}
308			write_unlock(&GlobalSMBSeslock);
309		}
310	}
311cifs_create_out:
312	kfree(buf);
313	kfree(full_path);
314	FreeXid(xid);
315	return rc;
316}
317
318int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode,
319		dev_t device_number)
320{
321	int rc = -EPERM;
322	int xid;
323	struct cifs_sb_info *cifs_sb;
324	struct cifsTconInfo *pTcon;
325	char *full_path = NULL;
326	struct inode * newinode = NULL;
327
328	if (!old_valid_dev(device_number))
329		return -EINVAL;
330
331	xid = GetXid();
332
333	cifs_sb = CIFS_SB(inode->i_sb);
334	pTcon = cifs_sb->tcon;
335
336	full_path = build_path_from_dentry(direntry);
337	if (full_path == NULL)
338		rc = -ENOMEM;
339	else if (pTcon->ses->capabilities & CAP_UNIX) {
340		mode &= ~current->fs->umask;
341		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
342			rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path,
343				mode, (__u64)current->fsuid,
344				(__u64)current->fsgid,
345				device_number, cifs_sb->local_nls,
346				cifs_sb->mnt_cifs_flags &
347					CIFS_MOUNT_MAP_SPECIAL_CHR);
348		} else {
349			rc = CIFSSMBUnixSetPerms(xid, pTcon,
350				full_path, mode, (__u64)-1, (__u64)-1,
351				device_number, cifs_sb->local_nls,
352				cifs_sb->mnt_cifs_flags &
353					CIFS_MOUNT_MAP_SPECIAL_CHR);
354		}
355
356		if (!rc) {
357			rc = cifs_get_inode_info_unix(&newinode, full_path,
358						inode->i_sb, xid);
359			if (pTcon->nocase)
360				direntry->d_op = &cifs_ci_dentry_ops;
361			else
362				direntry->d_op = &cifs_dentry_ops;
363			if (rc == 0)
364				d_instantiate(direntry, newinode);
365		}
366	} else {
367		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
368			int oplock = 0;
369			u16 fileHandle;
370			FILE_ALL_INFO * buf;
371
372			cFYI(1, ("sfu compat create special file"));
373
374			buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
375			if (buf == NULL) {
376				kfree(full_path);
377				FreeXid(xid);
378				return -ENOMEM;
379			}
380
381			rc = CIFSSMBOpen(xid, pTcon, full_path,
382					 FILE_CREATE, /* fail if exists */
383					 GENERIC_WRITE /* BB would
384					  WRITE_OWNER | WRITE_DAC be better? */,
385					 /* Create a file and set the
386					    file attribute to SYSTEM */
387					 CREATE_NOT_DIR | CREATE_OPTION_SPECIAL,
388					 &fileHandle, &oplock, buf,
389					 cifs_sb->local_nls,
390					 cifs_sb->mnt_cifs_flags &
391					    CIFS_MOUNT_MAP_SPECIAL_CHR);
392
393			if (!rc) {
394				/* BB Do not bother to decode buf since no
395				   local inode yet to put timestamps in,
396				   but we can reuse it safely */
397				int bytes_written;
398				struct win_dev *pdev;
399				pdev = (struct win_dev *)buf;
400				if (S_ISCHR(mode)) {
401					memcpy(pdev->type, "IntxCHR", 8);
402					pdev->major =
403					      cpu_to_le64(MAJOR(device_number));
404					pdev->minor =
405					      cpu_to_le64(MINOR(device_number));
406					rc = CIFSSMBWrite(xid, pTcon,
407						fileHandle,
408						sizeof(struct win_dev),
409						0, &bytes_written, (char *)pdev,
410						NULL, 0);
411				} else if (S_ISBLK(mode)) {
412					memcpy(pdev->type, "IntxBLK", 8);
413					pdev->major =
414					      cpu_to_le64(MAJOR(device_number));
415					pdev->minor =
416					      cpu_to_le64(MINOR(device_number));
417					rc = CIFSSMBWrite(xid, pTcon,
418						fileHandle,
419						sizeof(struct win_dev),
420						0, &bytes_written, (char *)pdev,
421						NULL, 0);
422				} /* else if(S_ISFIFO */
423				CIFSSMBClose(xid, pTcon, fileHandle);
424				d_drop(direntry);
425			}
426			kfree(buf);
427			/* add code here to set EAs */
428		}
429	}
430
431	kfree(full_path);
432	FreeXid(xid);
433	return rc;
434}
435
436
437struct dentry *
438cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
439	    struct nameidata *nd)
440{
441	int xid;
442	int rc = 0; /* to get around spurious gcc warning, set to zero here */
443	struct cifs_sb_info *cifs_sb;
444	struct cifsTconInfo *pTcon;
445	struct inode *newInode = NULL;
446	char *full_path = NULL;
447
448	xid = GetXid();
449
450	cFYI(1,
451	     (" parent inode = 0x%p name is: %s and dentry = 0x%p",
452	      parent_dir_inode, direntry->d_name.name, direntry));
453
454	/* check whether path exists */
455
456	cifs_sb = CIFS_SB(parent_dir_inode->i_sb);
457	pTcon = cifs_sb->tcon;
458
459	/*
460	 * Don't allow the separator character in a path component.
461	 * The VFS will not allow "/", but "\" is allowed by posix.
462	 */
463	if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)) {
464		int i;
465		for (i = 0; i < direntry->d_name.len; i++)
466			if (direntry->d_name.name[i] == '\\') {
467				cFYI(1, ("Invalid file name"));
468				FreeXid(xid);
469				return ERR_PTR(-EINVAL);
470			}
471	}
472
473	/* can not grab the rename sem here since it would
474	deadlock in the cases (beginning of sys_rename itself)
475	in which we already have the sb rename sem */
476	full_path = build_path_from_dentry(direntry);
477	if (full_path == NULL) {
478		FreeXid(xid);
479		return ERR_PTR(-ENOMEM);
480	}
481
482	if (direntry->d_inode != NULL) {
483		cFYI(1, (" non-NULL inode in lookup"));
484	} else {
485		cFYI(1, (" NULL inode in lookup"));
486	}
487	cFYI(1,
488	     (" Full path: %s inode = 0x%p", full_path, direntry->d_inode));
489
490	if (pTcon->ses->capabilities & CAP_UNIX)
491		rc = cifs_get_inode_info_unix(&newInode, full_path,
492					      parent_dir_inode->i_sb, xid);
493	else
494		rc = cifs_get_inode_info(&newInode, full_path, NULL,
495					 parent_dir_inode->i_sb, xid);
496
497	if ((rc == 0) && (newInode != NULL)) {
498		if (pTcon->nocase)
499			direntry->d_op = &cifs_ci_dentry_ops;
500		else
501			direntry->d_op = &cifs_dentry_ops;
502		d_add(direntry, newInode);
503
504		/* since paths are not looked up by component - the parent
505		   directories are presumed to be good here */
506		renew_parental_timestamps(direntry);
507
508	} else if (rc == -ENOENT) {
509		rc = 0;
510		direntry->d_time = jiffies;
511		if (pTcon->nocase)
512			direntry->d_op = &cifs_ci_dentry_ops;
513		else
514			direntry->d_op = &cifs_dentry_ops;
515		d_add(direntry, NULL);
516	/*	if it was once a directory (but how can we tell?) we could do
517		shrink_dcache_parent(direntry); */
518	} else {
519		cERROR(1, ("Error 0x%x on cifs_get_inode_info in lookup of %s",
520			   rc, full_path));
521		/* BB special case check for Access Denied - watch security
522		exposure of returning dir info implicitly via different rc
523		if file exists or not but no access BB */
524	}
525
526	kfree(full_path);
527	FreeXid(xid);
528	return ERR_PTR(rc);
529}
530
531static int
532cifs_d_revalidate(struct dentry *direntry, struct nameidata *nd)
533{
534	int isValid = 1;
535
536	if (direntry->d_inode) {
537		if (cifs_revalidate(direntry)) {
538			return 0;
539		}
540	} else {
541		cFYI(1, ("neg dentry 0x%p name = %s",
542			 direntry, direntry->d_name.name));
543		if (time_after(jiffies, direntry->d_time + HZ) ||
544			!lookupCacheEnabled) {
545			d_drop(direntry);
546			isValid = 0;
547		}
548	}
549
550	return isValid;
551}
552
553/* static int cifs_d_delete(struct dentry *direntry)
554{
555	int rc = 0;
556
557	cFYI(1, ("In cifs d_delete, name = %s", direntry->d_name.name));
558
559	return rc;
560}     */
561
562struct dentry_operations cifs_dentry_ops = {
563	.d_revalidate = cifs_d_revalidate,
564/* d_delete:       cifs_d_delete,      */ /* not needed except for debugging */
565};
566
567static int cifs_ci_hash(struct dentry *dentry, struct qstr *q)
568{
569	struct nls_table *codepage = CIFS_SB(dentry->d_inode->i_sb)->local_nls;
570	unsigned long hash;
571	int i;
572
573	hash = init_name_hash();
574	for (i = 0; i < q->len; i++)
575		hash = partial_name_hash(nls_tolower(codepage, q->name[i]),
576					 hash);
577	q->hash = end_name_hash(hash);
578
579	return 0;
580}
581
582static int cifs_ci_compare(struct dentry *dentry, struct qstr *a,
583			   struct qstr *b)
584{
585	struct nls_table *codepage = CIFS_SB(dentry->d_inode->i_sb)->local_nls;
586
587	if ((a->len == b->len) &&
588	    (nls_strnicmp(codepage, a->name, b->name, a->len) == 0)) {
589		/*
590		 * To preserve case, don't let an existing negative dentry's
591		 * case take precedence.  If a is not a negative dentry, this
592		 * should have no side effects
593		 */
594		memcpy((unsigned char *)a->name, b->name, a->len);
595		return 0;
596	}
597	return 1;
598}
599
600struct dentry_operations cifs_ci_dentry_ops = {
601	.d_revalidate = cifs_d_revalidate,
602	.d_hash = cifs_ci_hash,
603	.d_compare = cifs_ci_compare,
604};
605