11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  dir.c
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  Copyright (C) 1995, 1996 by Volker Lendecke
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  Modified for big endian by J.F. Chadima and David S. Miller
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  Modified 1997 Peter Waltenberg, Bill Hawes, David Woodhouse for 2.1 dcache
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  Modified 1998, 1999 Wolfram Pienkoss for NLS
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  Modified 1999 Wolfram Pienkoss for directory caching
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  Modified 2000 Ben Harris, University of Cambridge for NFS NS meta-info
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/time.h>
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h>
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/stat.h>
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/vmalloc.h>
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mm.h>
2034286d6662308d82aed891852d04c7c3a2649b16Nick Piggin#include <linux/namei.h>
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/uaccess.h>
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/byteorder.h>
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2432c419d95f3d1da891ab9bd032a214ee05b94ed4Al Viro#include "ncp_fs.h"
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2676f582a8f60a94c116e0b92d07c9047410274b20Al Virostatic void ncp_read_volume_list(struct file *, struct dir_context *,
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				struct ncp_cache_control *);
2876f582a8f60a94c116e0b92d07c9047410274b20Al Virostatic void ncp_do_readdir(struct file *, struct dir_context *,
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				struct ncp_cache_control *);
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3176f582a8f60a94c116e0b92d07c9047410274b20Al Virostatic int ncp_readdir(struct file *, struct dir_context *);
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
33ebfc3b49a7ac25920cb5be5445f602e51d2ea559Al Virostatic int ncp_create(struct inode *, struct dentry *, umode_t, bool);
3400cd8dd3bf95f2cc8435b4cac01d9995635c6d0bAl Virostatic struct dentry *ncp_lookup(struct inode *, struct dentry *, unsigned int);
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ncp_unlink(struct inode *, struct dentry *);
3618bb1db3e7607e4a997d50991a6f9fa5b0f8722cAl Virostatic int ncp_mkdir(struct inode *, struct dentry *, umode_t);
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ncp_rmdir(struct inode *, struct dentry *);
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ncp_rename(struct inode *, struct dentry *,
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  	      struct inode *, struct dentry *);
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ncp_mknod(struct inode * dir, struct dentry *dentry,
411a67aafb5f72a436ca044293309fa7e6351d6a35Al Viro		     umode_t mode, dev_t rdev);
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS)
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsextern int ncp_symlink(struct inode *, struct dentry *, const char *);
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ncp_symlink NULL
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
484b6f5d20b04dcbc3d888555522b90ba6d36c4106Arjan van de Venconst struct file_operations ncp_dir_operations =
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
50ca572727dbb945e443564029a495157fd2e72995jan Blunck	.llseek		= generic_file_llseek,
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.read		= generic_read_dir,
5276f582a8f60a94c116e0b92d07c9047410274b20Al Viro	.iterate	= ncp_readdir,
5393d84b6d99f5ddb911b318990c759a0fefa0f7eaJohn Kacur	.unlocked_ioctl	= ncp_ioctl,
5454f67f631dfc25ca7a8b19200e34013abc974337Petr Vandrovec#ifdef CONFIG_COMPAT
5554f67f631dfc25ca7a8b19200e34013abc974337Petr Vandrovec	.compat_ioctl	= ncp_compat_ioctl,
5654f67f631dfc25ca7a8b19200e34013abc974337Petr Vandrovec#endif
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5992e1d5be91a0e3ffa5c4697eeb09b2aa22792122Arjan van de Venconst struct inode_operations ncp_dir_inode_operations =
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.create		= ncp_create,
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.lookup		= ncp_lookup,
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.unlink		= ncp_unlink,
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.symlink	= ncp_symlink,
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.mkdir		= ncp_mkdir,
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.rmdir		= ncp_rmdir,
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.mknod		= ncp_mknod,
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.rename		= ncp_rename,
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.setattr	= ncp_notify_change,
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Dentry operations routines
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
750b728e1911cbe6e24020727c3870628b9653f32aAl Virostatic int ncp_lookup_validate(struct dentry *, unsigned int);
76da53be12bbb4fabbe2e9f6f908de0cf478b5161dLinus Torvaldsstatic int ncp_hash_dentry(const struct dentry *, struct qstr *);
77da53be12bbb4fabbe2e9f6f908de0cf478b5161dLinus Torvaldsstatic int ncp_compare_dentry(const struct dentry *, const struct dentry *,
78621e155a3591962420eacdd39f6f0aa29ceb221eNick Piggin		unsigned int, const char *, const struct qstr *);
79fe15ce446beb3a33583af81ffe6c9d01a75314edNick Pigginstatic int ncp_delete_dentry(const struct dentry *);
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
810378c4051a621303ae919f1cee832206a4c1aa68Al Viroconst struct dentry_operations ncp_dentry_operations =
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.d_revalidate	= ncp_lookup_validate,
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.d_hash		= ncp_hash_dentry,
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.d_compare	= ncp_compare_dentry,
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.d_delete	= ncp_delete_dentry,
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
892e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec#define ncp_namespace(i)	(NCP_SERVER(i)->name_space[NCP_FINFO(i)->volNumber])
902e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec
912e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovecstatic inline int ncp_preserve_entry_case(struct inode *i, __u32 nscreator)
922e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec{
932e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec#ifdef CONFIG_NCPFS_SMALLDOS
942e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec	int ns = ncp_namespace(i);
952e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec
962e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec	if ((ns == NW_NS_DOS)
972e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec#ifdef CONFIG_NCPFS_OS2_NS
982e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec		|| ((ns == NW_NS_OS2) && (nscreator == NW_NS_DOS))
992e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec#endif /* CONFIG_NCPFS_OS2_NS */
1002e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec	   )
1012e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec		return 0;
1022e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec#endif /* CONFIG_NCPFS_SMALLDOS */
1032e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec	return 1;
1042e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec}
1052e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec
1062e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec#define ncp_preserve_case(i)	(ncp_namespace(i) != NW_NS_DOS)
1072e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec
108621e155a3591962420eacdd39f6f0aa29ceb221eNick Pigginstatic inline int ncp_case_sensitive(const struct inode *i)
1092e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec{
1102e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec#ifdef CONFIG_NCPFS_NFS_NS
111621e155a3591962420eacdd39f6f0aa29ceb221eNick Piggin	return ncp_namespace(i) == NW_NS_NFS;
1122e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec#else
1132e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec	return 0;
1142e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec#endif /* CONFIG_NCPFS_NFS_NS */
1152e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec}
1162e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Note: leave the hash unchanged if the directory
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * is case-sensitive.
120da53be12bbb4fabbe2e9f6f908de0cf478b5161dLinus Torvalds *
121da53be12bbb4fabbe2e9f6f908de0cf478b5161dLinus Torvalds * Accessing the parent inode can be racy under RCU pathwalking.
122da53be12bbb4fabbe2e9f6f908de0cf478b5161dLinus Torvalds * Use ACCESS_ONCE() to make sure we use _one_ particular inode,
123da53be12bbb4fabbe2e9f6f908de0cf478b5161dLinus Torvalds * the callers will handle races.
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
126da53be12bbb4fabbe2e9f6f908de0cf478b5161dLinus Torvaldsncp_hash_dentry(const struct dentry *dentry, struct qstr *this)
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
128da53be12bbb4fabbe2e9f6f908de0cf478b5161dLinus Torvalds	struct inode *inode = ACCESS_ONCE(dentry->d_inode);
129da53be12bbb4fabbe2e9f6f908de0cf478b5161dLinus Torvalds
130da53be12bbb4fabbe2e9f6f908de0cf478b5161dLinus Torvalds	if (!inode)
131da53be12bbb4fabbe2e9f6f908de0cf478b5161dLinus Torvalds		return 0;
132da53be12bbb4fabbe2e9f6f908de0cf478b5161dLinus Torvalds
133b1e6a015a580ad145689ad1d6b4aa0e03e6c868bNick Piggin	if (!ncp_case_sensitive(inode)) {
134621e155a3591962420eacdd39f6f0aa29ceb221eNick Piggin		struct super_block *sb = dentry->d_sb;
1352e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec		struct nls_table *t;
1362e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec		unsigned long hash;
1372e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec		int i;
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
139621e155a3591962420eacdd39f6f0aa29ceb221eNick Piggin		t = NCP_IO_TABLE(sb);
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		hash = init_name_hash();
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (i=0; i<this->len ; i++)
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			hash = partial_name_hash(ncp_tolower(t, this->name[i]),
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds									hash);
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		this->hash = end_name_hash(hash);
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
149da53be12bbb4fabbe2e9f6f908de0cf478b5161dLinus Torvalds/*
150da53be12bbb4fabbe2e9f6f908de0cf478b5161dLinus Torvalds * Accessing the parent inode can be racy under RCU pathwalking.
151da53be12bbb4fabbe2e9f6f908de0cf478b5161dLinus Torvalds * Use ACCESS_ONCE() to make sure we use _one_ particular inode,
152da53be12bbb4fabbe2e9f6f908de0cf478b5161dLinus Torvalds * the callers will handle races.
153da53be12bbb4fabbe2e9f6f908de0cf478b5161dLinus Torvalds */
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
155da53be12bbb4fabbe2e9f6f908de0cf478b5161dLinus Torvaldsncp_compare_dentry(const struct dentry *parent, const struct dentry *dentry,
156621e155a3591962420eacdd39f6f0aa29ceb221eNick Piggin		unsigned int len, const char *str, const struct qstr *name)
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
158da53be12bbb4fabbe2e9f6f908de0cf478b5161dLinus Torvalds	struct inode *pinode;
159da53be12bbb4fabbe2e9f6f908de0cf478b5161dLinus Torvalds
160621e155a3591962420eacdd39f6f0aa29ceb221eNick Piggin	if (len != name->len)
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 1;
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
163da53be12bbb4fabbe2e9f6f908de0cf478b5161dLinus Torvalds	pinode = ACCESS_ONCE(parent->d_inode);
164da53be12bbb4fabbe2e9f6f908de0cf478b5161dLinus Torvalds	if (!pinode)
165da53be12bbb4fabbe2e9f6f908de0cf478b5161dLinus Torvalds		return 1;
166da53be12bbb4fabbe2e9f6f908de0cf478b5161dLinus Torvalds
167621e155a3591962420eacdd39f6f0aa29ceb221eNick Piggin	if (ncp_case_sensitive(pinode))
168621e155a3591962420eacdd39f6f0aa29ceb221eNick Piggin		return strncmp(str, name->name, len);
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
170621e155a3591962420eacdd39f6f0aa29ceb221eNick Piggin	return ncp_strnicmp(NCP_IO_TABLE(pinode->i_sb), str, name->name, len);
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This is the callback from dput() when d_count is going to 0.
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We use this to unhash dentries with bad inodes.
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Closing files can be safely postponed until iput() - it's done there anyway.
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
179fe15ce446beb3a33583af81ffe6c9d01a75314edNick Pigginncp_delete_dentry(const struct dentry * dentry)
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct inode *inode = dentry->d_inode;
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (inode) {
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (is_bad_inode(inode))
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return 1;
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* N.B. Unhash negative dentries? */
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsncp_single_volume(struct ncp_server *server)
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (server->m.mounted_vol[0] != '\0');
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int ncp_is_server_root(struct inode *inode)
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (!ncp_single_volume(NCP_SERVER(inode)) &&
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		inode == inode->i_sb->s_root->d_inode);
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This is the callback when the dcache has a lookup hit.
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_NCPFS_STRONG
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* try to delete a readonly file (NW R bit set) */
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsncp_force_unlink(struct inode *dir, struct dentry* dentry)
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        int res=0x9c,res2;
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct nw_modify_dos_info info;
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__le32 old_nwattr;
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct inode *inode;
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memset(&info, 0, sizeof(info));
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        /* remove the Read-Only flag on the NW server */
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	inode = dentry->d_inode;
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	old_nwattr = NCP_FINFO(inode)->nwattr;
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	info.attributes = old_nwattr & ~(aRONLY|aDELETEINHIBIT|aRENAMEINHIBIT);
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(inode), inode, NULL, DM_ATTRIBUTES, &info);
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (res2)
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto leave_me;
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        /* now try again the delete operation */
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        res = ncp_del_file_or_subdir2(NCP_SERVER(dir), dentry);
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        if (res)  /* delete failed, set R bit again */
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        {
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		info.attributes = old_nwattr;
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(inode), inode, NULL, DM_ATTRIBUTES, &info);
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (res2)
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                        goto leave_me;
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        }
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsleave_me:
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        return(res);
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif	/* CONFIG_NCPFS_STRONG */
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_NCPFS_STRONG
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsncp_force_rename(struct inode *old_dir, struct dentry* old_dentry, char *_old_name,
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                 struct inode *new_dir, struct dentry* new_dentry, char *_new_name)
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct nw_modify_dos_info info;
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        int res=0x90,res2;
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct inode *old_inode = old_dentry->d_inode;
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__le32 old_nwattr = NCP_FINFO(old_inode)->nwattr;
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__le32 new_nwattr = 0; /* shut compiler warning */
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int old_nwattr_changed = 0;
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int new_nwattr_changed = 0;
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memset(&info, 0, sizeof(info));
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        /* remove the Read-Only flag on the NW server */
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	info.attributes = old_nwattr & ~(aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(old_inode), old_inode, NULL, DM_ATTRIBUTES, &info);
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!res2)
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		old_nwattr_changed = 1;
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (new_dentry && new_dentry->d_inode) {
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		new_nwattr = NCP_FINFO(new_dentry->d_inode)->nwattr;
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		info.attributes = new_nwattr & ~(aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(new_dir), new_dir, _new_name, DM_ATTRIBUTES, &info);
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!res2)
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			new_nwattr_changed = 1;
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        /* now try again the rename operation */
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* but only if something really happened */
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (new_nwattr_changed || old_nwattr_changed) {
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	        res = ncp_ren_or_mov_file_or_subdir(NCP_SERVER(old_dir),
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        	                                    old_dir, _old_name,
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                	                            new_dir, _new_name);
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (res)
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto leave_me;
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* file was successfully renamed, so:
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   do not set attributes on old file - it no longer exists
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   copy attributes from old file to new */
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	new_nwattr_changed = old_nwattr_changed;
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	new_nwattr = old_nwattr;
2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	old_nwattr_changed = 0;
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsleave_me:;
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (old_nwattr_changed) {
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		info.attributes = old_nwattr;
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(old_inode), old_inode, NULL, DM_ATTRIBUTES, &info);
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* ignore errors */
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (new_nwattr_changed)	{
2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		info.attributes = new_nwattr;
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(new_dir), new_dir, _new_name, DM_ATTRIBUTES, &info);
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* ignore errors */
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        return(res);
3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif	/* CONFIG_NCPFS_STRONG */
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
3090b728e1911cbe6e24020727c3870628b9653f32aAl Vironcp_lookup_validate(struct dentry *dentry, unsigned int flags)
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ncp_server *server;
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dentry *parent;
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct inode *dir;
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ncp_entry_info finfo;
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int res, val = 0, len;
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__u8 __name[NCP_MAXPATHLEN + 1];
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3180378c4051a621303ae919f1cee832206a4c1aa68Al Viro	if (dentry == dentry->d_sb->s_root)
3190378c4051a621303ae919f1cee832206a4c1aa68Al Viro		return 1;
3200378c4051a621303ae919f1cee832206a4c1aa68Al Viro
3210b728e1911cbe6e24020727c3870628b9653f32aAl Viro	if (flags & LOOKUP_RCU)
32234286d6662308d82aed891852d04c7c3a2649b16Nick Piggin		return -ECHILD;
32334286d6662308d82aed891852d04c7c3a2649b16Nick Piggin
3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	parent = dget_parent(dentry);
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dir = parent->d_inode;
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dentry->d_inode)
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto finished;
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	server = NCP_SERVER(dir);
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Inspired by smbfs:
3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * The default validation is based on dentry age:
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * We set the max age at mount time.  (But each
3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * successful server lookup renews the timestamp.)
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val = NCP_TEST_AGE(server, dentry);
3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (val)
3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto finished;
3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
342d3b73ca1be3236fc33f896af7e2ba637a677d5c9Joe Perches	ncp_dbg(2, "%pd2 not valid, age=%ld, server lookup\n",
34384eb3532b574bb6a65c0aad9591b28b2adcd47d2Al Viro		dentry, NCP_GET_AGE(dentry));
3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	len = sizeof(__name);
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ncp_is_server_root(dir)) {
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		res = ncp_io2vol(server, __name, &len, dentry->d_name.name,
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 dentry->d_name.len, 1);
3492e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec		if (!res) {
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			res = ncp_lookup_volume(server, __name, &(finfo.i));
3512e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec			if (!res)
3522e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec				ncp_update_known_namespace(server, finfo.i.volNumber, NULL);
3532e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec		}
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		res = ncp_io2vol(server, __name, &len, dentry->d_name.name,
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 dentry->d_name.len, !ncp_preserve_case(dir));
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!res)
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			res = ncp_obtain_info(server, dir, __name, &(finfo.i));
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	finfo.volume = finfo.i.volNumber;
361d3b73ca1be3236fc33f896af7e2ba637a677d5c9Joe Perches	ncp_dbg(2, "looked for %pd/%s, res=%d\n",
36284eb3532b574bb6a65c0aad9591b28b2adcd47d2Al Viro		dentry->d_parent, __name, res);
3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * If we didn't find it, or if it has a different dirEntNum to
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * what we remember, it's not valid any more.
3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!res) {
3682e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec		struct inode *inode = dentry->d_inode;
3692e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec
3702e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec		mutex_lock(&inode->i_mutex);
3712e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec		if (finfo.i.dirEntNum == NCP_FINFO(inode)->dirEntNum) {
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ncp_new_dentry(dentry);
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			val=1;
3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else
375d3b73ca1be3236fc33f896af7e2ba637a677d5c9Joe Perches			ncp_dbg(2, "found, but dirEntNum changed\n");
3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3772e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec		ncp_update_inode2(inode, &finfo);
3782e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec		mutex_unlock(&inode->i_mutex);
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfinished:
382d3b73ca1be3236fc33f896af7e2ba637a677d5c9Joe Perches	ncp_dbg(2, "result=%d\n", val);
3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dput(parent);
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return val;
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct dentry *
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsncp_dget_fpos(struct dentry *dentry, struct dentry *parent, unsigned long fpos)
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dentry *dent = dentry;
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (d_validate(dent, parent)) {
3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (dent->d_name.len <= NCP_MAXPATHLEN &&
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    (unsigned long)dent->d_fsdata == fpos) {
3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!dent->d_inode) {
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				dput(dent);
3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				dent = NULL;
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return dent;
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dput(dent);
4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* If a pointer is invalid, we search the dentry. */
4052fd6b7f50797f2e993eea59e0a0b8c6399c811dcNick Piggin	spin_lock(&parent->d_lock);
406821cc3070ff54e39ab6624c843f1905d737d9ac0Al Viro	list_for_each_entry(dent, &parent->d_subdirs, d_u.d_child) {
4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((unsigned long)dent->d_fsdata == fpos) {
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (dent->d_inode)
409dc0474be3e27463d4d4a2793f82366eed906f223Nick Piggin				dget(dent);
4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			else
4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				dent = NULL;
4122fd6b7f50797f2e993eea59e0a0b8c6399c811dcNick Piggin			spin_unlock(&parent->d_lock);
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto out;
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4162fd6b7f50797f2e993eea59e0a0b8c6399c811dcNick Piggin	spin_unlock(&parent->d_lock);
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return NULL;
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout:
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return dent;
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic time_t ncp_obtain_mtime(struct dentry *dentry)
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct inode *inode = dentry->d_inode;
4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ncp_server *server = NCP_SERVER(inode);
4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct nw_info_struct i;
4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!ncp_conn_valid(server) || ncp_is_server_root(inode))
4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ncp_obtain_info(server, inode, NULL, &i))
4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ncp_date_dos2unix(i.modifyTime, i.modifyDate);
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
43876f582a8f60a94c116e0b92d07c9047410274b20Al Virostatic int ncp_readdir(struct file *file, struct dir_context *ctx)
4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
44076f582a8f60a94c116e0b92d07c9047410274b20Al Viro	struct dentry *dentry = file->f_path.dentry;
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct inode *inode = dentry->d_inode;
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct page *page = NULL;
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ncp_server *server = NCP_SERVER(inode);
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	union  ncp_dir_cache *cache = NULL;
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ncp_cache_control ctl;
4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int result, mtime_valid = 0;
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	time_t mtime = 0;
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ctl.page  = NULL;
4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ctl.cache = NULL;
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
452d3b73ca1be3236fc33f896af7e2ba637a677d5c9Joe Perches	ncp_dbg(2, "reading %pD2, pos=%d\n", file, (int)ctx->pos);
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	result = -EIO;
4552e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec	/* Do not generate '.' and '..' when server is dead. */
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!ncp_conn_valid(server))
4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	result = 0;
46076f582a8f60a94c116e0b92d07c9047410274b20Al Viro	if (!dir_emit_dots(file, ctx))
46176f582a8f60a94c116e0b92d07c9047410274b20Al Viro		goto out;
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	page = grab_cache_page(&inode->i_data, 0);
4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!page)
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto read_really;
4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ctl.cache = cache = kmap(page);
4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ctl.head  = cache->head;
4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!PageUptodate(page) || !ctl.head.eof)
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto init_cache;
4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
47376f582a8f60a94c116e0b92d07c9047410274b20Al Viro	if (ctx->pos == 2) {
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (jiffies - ctl.head.time >= NCP_MAX_AGE(server))
4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto init_cache;
4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mtime = ncp_obtain_mtime(dentry);
4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mtime_valid = 1;
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((!mtime) || (mtime != ctl.head.mtime))
4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto init_cache;
4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
48376f582a8f60a94c116e0b92d07c9047410274b20Al Viro	if (ctx->pos > ctl.head.end)
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto finished;
4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
48676f582a8f60a94c116e0b92d07c9047410274b20Al Viro	ctl.fpos = ctx->pos + (NCP_DIRCACHE_START - 2);
4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ctl.ofs  = ctl.fpos / NCP_DIRCACHE_SIZE;
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ctl.idx  = ctl.fpos % NCP_DIRCACHE_SIZE;
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (;;) {
4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ctl.ofs != 0) {
4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ctl.page = find_lock_page(&inode->i_data, ctl.ofs);
4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!ctl.page)
4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto invalid_cache;
4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ctl.cache = kmap(ctl.page);
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!PageUptodate(ctl.page))
4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto invalid_cache;
4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		while (ctl.idx < NCP_DIRCACHE_SIZE) {
5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			struct dentry *dent;
50176f582a8f60a94c116e0b92d07c9047410274b20Al Viro			bool over;
5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dent = ncp_dget_fpos(ctl.cache->dentry[ctl.idx],
50476f582a8f60a94c116e0b92d07c9047410274b20Al Viro						dentry, ctx->pos);
5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!dent)
5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto invalid_cache;
50776f582a8f60a94c116e0b92d07c9047410274b20Al Viro			over = !dir_emit(ctx, dent->d_name.name,
50876f582a8f60a94c116e0b92d07c9047410274b20Al Viro					dent->d_name.len,
5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					dent->d_inode->i_ino, DT_UNKNOWN);
5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dput(dent);
51176f582a8f60a94c116e0b92d07c9047410274b20Al Viro			if (over)
5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto finished;
51376f582a8f60a94c116e0b92d07c9047410274b20Al Viro			ctx->pos += 1;
5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ctl.idx += 1;
51576f582a8f60a94c116e0b92d07c9047410274b20Al Viro			if (ctx->pos > ctl.head.end)
5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto finished;
5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ctl.page) {
5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			kunmap(ctl.page);
5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			SetPageUptodate(ctl.page);
5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			unlock_page(ctl.page);
5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			page_cache_release(ctl.page);
5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ctl.page = NULL;
5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ctl.idx  = 0;
5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ctl.ofs += 1;
5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsinvalid_cache:
5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ctl.page) {
5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kunmap(ctl.page);
5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		unlock_page(ctl.page);
5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		page_cache_release(ctl.page);
5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ctl.page = NULL;
5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ctl.cache = cache;
5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsinit_cache:
5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ncp_invalidate_dircache_entries(dentry);
5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!mtime_valid) {
5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mtime = ncp_obtain_mtime(dentry);
5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mtime_valid = 1;
5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ctl.head.mtime = mtime;
5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ctl.head.time = jiffies;
5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ctl.head.eof = 0;
5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ctl.fpos = 2;
5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ctl.ofs = 0;
5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ctl.idx = NCP_DIRCACHE_START;
5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ctl.filled = 0;
5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ctl.valid  = 1;
5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsread_really:
5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ncp_is_server_root(inode)) {
55276f582a8f60a94c116e0b92d07c9047410274b20Al Viro		ncp_read_volume_list(file, ctx, &ctl);
5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
55476f582a8f60a94c116e0b92d07c9047410274b20Al Viro		ncp_do_readdir(file, ctx, &ctl);
5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ctl.head.end = ctl.fpos - 1;
5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ctl.head.eof = ctl.valid;
5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfinished:
5592e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec	if (ctl.page) {
5602e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec		kunmap(ctl.page);
5612e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec		SetPageUptodate(ctl.page);
5622e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec		unlock_page(ctl.page);
5632e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec		page_cache_release(ctl.page);
5642e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec	}
5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (page) {
5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cache->head = ctl.head;
5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kunmap(page);
5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		SetPageUptodate(page);
5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		unlock_page(page);
5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		page_cache_release(page);
5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout:
5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return result;
5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
57776f582a8f60a94c116e0b92d07c9047410274b20Al Vironcp_fill_cache(struct file *file, struct dir_context *ctx,
5782e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec		struct ncp_cache_control *ctrl, struct ncp_entry_info *entry,
5792e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec		int inval_childs)
5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
58176f582a8f60a94c116e0b92d07c9047410274b20Al Viro	struct dentry *newdent, *dentry = file->f_path.dentry;
5822e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec	struct inode *dir = dentry->d_inode;
5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ncp_cache_control ctl = *ctrl;
5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct qstr qname;
5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int valid = 0;
5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int hashed = 0;
5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ino_t ino = 0;
5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__u8 __name[NCP_MAXPATHLEN + 1];
5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	qname.len = sizeof(__name);
5912e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec	if (ncp_vol2io(NCP_SERVER(dir), __name, &qname.len,
5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			entry->i.entryName, entry->i.nameLen,
5932e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec			!ncp_preserve_entry_case(dir, entry->i.NSCreator)))
5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 1; /* I'm not sure */
5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	qname.name = __name;
5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5984f522a247bc26d4ab5c8fc406ffffa8b3a77abe3Al Viro	newdent = d_hash_and_lookup(dentry, &qname);
5994f522a247bc26d4ab5c8fc406ffffa8b3a77abe3Al Viro	if (unlikely(IS_ERR(newdent)))
6004f522a247bc26d4ab5c8fc406ffffa8b3a77abe3Al Viro		goto end_advance;
6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!newdent) {
6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		newdent = d_alloc(dentry, &qname);
6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!newdent)
6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto end_advance;
6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		hashed = 1;
6072e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec
6082e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec		/* If case sensitivity changed for this volume, all entries below this one
6092e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec		   should be thrown away.  This entry itself is not affected, as its case
6102e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec		   sensitivity is controlled by its own parent. */
6112e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec		if (inval_childs)
6122e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec			shrink_dcache_parent(newdent);
6132e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec
6142e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec		/*
615fb2d5b86aff355a27ebfc132d3c99f4a940cc3feNick Piggin		 * NetWare's OS2 namespace is case preserving yet case
616fb2d5b86aff355a27ebfc132d3c99f4a940cc3feNick Piggin		 * insensitive.  So we update dentry's name as received from
617fb2d5b86aff355a27ebfc132d3c99f4a940cc3feNick Piggin		 * server. Parent dir's i_mutex is locked because we're in
618fb2d5b86aff355a27ebfc132d3c99f4a940cc3feNick Piggin		 * readdir.
6192e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec		 */
620fb2d5b86aff355a27ebfc132d3c99f4a940cc3feNick Piggin		dentry_update_name_case(newdent, &qname);
6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!newdent->d_inode) {
6242e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec		struct inode *inode;
6252e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec
6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		entry->opened = 0;
6272e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec		entry->ino = iunique(dir->i_sb, 2);
6282e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec		inode = ncp_iget(dir->i_sb, entry);
6292e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec		if (inode) {
6302e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec			d_instantiate(newdent, inode);
6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!hashed)
6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				d_rehash(newdent);
6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
6342e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec	} else {
6352e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec		struct inode *inode = newdent->d_inode;
6362e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec
637fb2d5b86aff355a27ebfc132d3c99f4a940cc3feNick Piggin		mutex_lock_nested(&inode->i_mutex, I_MUTEX_CHILD);
6382e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec		ncp_update_inode2(inode, entry);
6392e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec		mutex_unlock(&inode->i_mutex);
6402e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec	}
6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (newdent->d_inode) {
6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ino = newdent->d_inode->i_ino;
6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		newdent->d_fsdata = (void *) ctl.fpos;
6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ncp_new_dentry(newdent);
6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ctl.idx >= NCP_DIRCACHE_SIZE) {
6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ctl.page) {
6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			kunmap(ctl.page);
6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			SetPageUptodate(ctl.page);
6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			unlock_page(ctl.page);
6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			page_cache_release(ctl.page);
6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ctl.cache = NULL;
6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ctl.idx  -= NCP_DIRCACHE_SIZE;
6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ctl.ofs  += 1;
6582e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec		ctl.page  = grab_cache_page(&dir->i_data, ctl.ofs);
6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ctl.page)
6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ctl.cache = kmap(ctl.page);
6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ctl.cache) {
6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ctl.cache->dentry[ctl.idx] = newdent;
6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		valid = 1;
6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dput(newdent);
6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsend_advance:
6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!valid)
6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ctl.valid = 0;
67076f582a8f60a94c116e0b92d07c9047410274b20Al Viro	if (!ctl.filled && (ctl.fpos == ctx->pos)) {
6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!ino)
6722e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec			ino = iunique(dir->i_sb, 2);
67376f582a8f60a94c116e0b92d07c9047410274b20Al Viro		ctl.filled = !dir_emit(ctx, qname.name, qname.len,
67476f582a8f60a94c116e0b92d07c9047410274b20Al Viro				     ino, DT_UNKNOWN);
6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!ctl.filled)
67676f582a8f60a94c116e0b92d07c9047410274b20Al Viro			ctx->pos += 1;
6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ctl.fpos += 1;
6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ctl.idx  += 1;
6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*ctrl = ctl;
6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (ctl.valid || !ctl.filled);
6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
68576f582a8f60a94c116e0b92d07c9047410274b20Al Vironcp_read_volume_list(struct file *file, struct dir_context *ctx,
6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			struct ncp_cache_control *ctl)
6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
68876f582a8f60a94c116e0b92d07c9047410274b20Al Viro	struct dentry *dentry = file->f_path.dentry;
6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct inode *inode = dentry->d_inode;
6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ncp_server *server = NCP_SERVER(inode);
6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ncp_volume_info info;
6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ncp_entry_info entry;
6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
695d3b73ca1be3236fc33f896af7e2ba637a677d5c9Joe Perches	ncp_dbg(1, "pos=%ld\n", (unsigned long)ctx->pos);
6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < NCP_NUMBER_OF_VOLUMES; i++) {
6982e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec		int inval_dentry;
6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ncp_get_volume_info_with_number(server, i, &info) != 0)
7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return;
7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!strlen(info.volume_name))
7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
705d3b73ca1be3236fc33f896af7e2ba637a677d5c9Joe Perches		ncp_dbg(1, "found vol: %s\n", info.volume_name);
7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ncp_lookup_volume(server, info.volume_name,
7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					&entry.i)) {
709d3b73ca1be3236fc33f896af7e2ba637a677d5c9Joe Perches			ncp_dbg(1, "could not lookup vol %s\n",
7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				info.volume_name);
7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
7132e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec		inval_dentry = ncp_update_known_namespace(server, entry.i.volNumber, NULL);
7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		entry.volume = entry.i.volNumber;
71576f582a8f60a94c116e0b92d07c9047410274b20Al Viro		if (!ncp_fill_cache(file, ctx, ctl, &entry, inval_dentry))
7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return;
7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
72176f582a8f60a94c116e0b92d07c9047410274b20Al Vironcp_do_readdir(struct file *file, struct dir_context *ctx,
7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						struct ncp_cache_control *ctl)
7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
72476f582a8f60a94c116e0b92d07c9047410274b20Al Viro	struct dentry *dentry = file->f_path.dentry;
7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct inode *dir = dentry->d_inode;
7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ncp_server *server = NCP_SERVER(dir);
7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct nw_search_sequence seq;
7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ncp_entry_info entry;
7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err;
7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void* buf;
7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int more;
7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	size_t bufsize;
7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
734d3b73ca1be3236fc33f896af7e2ba637a677d5c9Joe Perches	ncp_dbg(1, "%pD2, fpos=%ld\n", file, (unsigned long)ctx->pos);
735e45ca8baa33e0c0228e84126c3a20df3abfd1771Joe Perches	ncp_vdbg("init %pD, volnum=%d, dirent=%u\n",
736e45ca8baa33e0c0228e84126c3a20df3abfd1771Joe Perches		 file, NCP_FINFO(dir)->volNumber, NCP_FINFO(dir)->dirEntNum);
7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err = ncp_initialize_search(server, dir, &seq);
7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (err) {
740d3b73ca1be3236fc33f896af7e2ba637a677d5c9Joe Perches		ncp_dbg(1, "init failed, err=%d\n", err);
7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* We MUST NOT use server->buffer_size handshaked with server if we are
7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   using UDP, as for UDP server uses max. buffer size determined by
7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   MTU, and for TCP server uses hardwired value 65KB (== 66560 bytes).
7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   So we use 128KB, just to be sure, as there is no way how to know
7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   this value in advance. */
7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bufsize = 131072;
7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	buf = vmalloc(bufsize);
7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!buf)
7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	do {
7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int cnt;
7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		char* rpl;
7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		size_t rpls;
7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		err = ncp_search_for_fileset(server, &seq, &more, &cnt, buf, bufsize, &rpl, &rpls);
7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (err)		/* Error */
7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!cnt)		/* prevent endless loop */
7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		while (cnt--) {
7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			size_t onerpl;
7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (rpls < offsetof(struct nw_info_struct, entryName))
7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;	/* short packet */
7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ncp_extract_file_info(rpl, &entry.i);
7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			onerpl = offsetof(struct nw_info_struct, entryName) + entry.i.nameLen;
7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (rpls < onerpl)
7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;	/* short packet */
7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			(void)ncp_obtain_nfs_info(server, &entry.i);
7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rpl += onerpl;
7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rpls -= onerpl;
7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			entry.volume = entry.i.volNumber;
77576f582a8f60a94c116e0b92d07c9047410274b20Al Viro			if (!ncp_fill_cache(file, ctx, ctl, &entry, 0))
7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} while (more);
7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	vfree(buf);
7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return;
7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint ncp_conn_logged_in(struct super_block *sb)
7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ncp_server* server = NCP_SBP(sb);
7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int result;
7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ncp_single_volume(server)) {
7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int len;
7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct dentry* dent;
7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		__u32 volNumber;
7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		__le32 dirEntNum;
7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		__le32 DosDirNum;
7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		__u8 __name[NCP_MAXPATHLEN + 1];
7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		len = sizeof(__name);
7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		result = ncp_io2vol(server, __name, &len, server->m.mounted_vol,
7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				    strlen(server->m.mounted_vol), 1);
7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (result)
8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto out;
8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		result = -ENOENT;
8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ncp_get_volume_root(server, __name, &volNumber, &dirEntNum, &DosDirNum)) {
803e45ca8baa33e0c0228e84126c3a20df3abfd1771Joe Perches			ncp_vdbg("%s not found\n", server->m.mounted_vol);
8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto out;
8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dent = sb->s_root;
8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (dent) {
8081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			struct inode* ino = dent->d_inode;
8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (ino) {
8102e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec				ncp_update_known_namespace(server, volNumber, NULL);
8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				NCP_FINFO(ino)->volNumber = volNumber;
8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				NCP_FINFO(ino)->dirEntNum = dirEntNum;
8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				NCP_FINFO(ino)->DosDirNum = DosDirNum;
8142e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec				result = 0;
8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else {
816d3b73ca1be3236fc33f896af7e2ba637a677d5c9Joe Perches				ncp_dbg(1, "sb->s_root->d_inode == NULL!\n");
8171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
819d3b73ca1be3236fc33f896af7e2ba637a677d5c9Joe Perches			ncp_dbg(1, "sb->s_root == NULL!\n");
8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
8212e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec	} else
8222e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec		result = 0;
8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout:
8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return result;
8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
82800cd8dd3bf95f2cc8435b4cac01d9995635c6d0bAl Virostatic struct dentry *ncp_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ncp_server *server = NCP_SERVER(dir);
8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct inode *inode = NULL;
8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ncp_entry_info finfo;
8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int error, res, len;
8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__u8 __name[NCP_MAXPATHLEN + 1];
8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	error = -EIO;
8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!ncp_conn_valid(server))
8381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto finished;
8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
840e45ca8baa33e0c0228e84126c3a20df3abfd1771Joe Perches	ncp_vdbg("server lookup for %pd2\n", dentry);
8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	len = sizeof(__name);
8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ncp_is_server_root(dir)) {
8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		res = ncp_io2vol(server, __name, &len, dentry->d_name.name,
8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 dentry->d_name.len, 1);
8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!res)
8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			res = ncp_lookup_volume(server, __name, &(finfo.i));
848ffddc5fd19b219f557fd4a81168ce8784a4facedDan Carpenter		if (!res)
849ffddc5fd19b219f557fd4a81168ce8784a4facedDan Carpenter			ncp_update_known_namespace(server, finfo.i.volNumber, NULL);
8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		res = ncp_io2vol(server, __name, &len, dentry->d_name.name,
8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 dentry->d_name.len, !ncp_preserve_case(dir));
8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!res)
8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			res = ncp_obtain_info(server, dir, __name, &(finfo.i));
8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
856e45ca8baa33e0c0228e84126c3a20df3abfd1771Joe Perches	ncp_vdbg("looked for %pd2, res=%d\n", dentry, res);
8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * If we didn't find an entry, make a negative dentry.
8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (res)
8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto add_entry;
8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Create an inode for the entry.
8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	finfo.opened = 0;
8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	finfo.ino = iunique(dir->i_sb, 2);
8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	finfo.volume = finfo.i.volNumber;
8691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	error = -EACCES;
8701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	inode = ncp_iget(dir->i_sb, &finfo);
8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (inode) {
8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ncp_new_dentry(dentry);
8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsadd_entry:
8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		d_add(dentry, inode);
8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		error = 0;
8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfinished:
880e45ca8baa33e0c0228e84126c3a20df3abfd1771Joe Perches	ncp_vdbg("result=%d\n", error);
8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ERR_PTR(error);
8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This code is common to create, mkdir, and mknod.
8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ncp_instantiate(struct inode *dir, struct dentry *dentry,
8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			struct ncp_entry_info *finfo)
8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct inode *inode;
8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int error = -EINVAL;
8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	finfo->ino = iunique(dir->i_sb, 2);
8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	inode = ncp_iget(dir->i_sb, finfo);
8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!inode)
8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out_close;
8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	d_instantiate(dentry,inode);
8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	error = 0;
8991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout:
9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return error;
9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout_close:
903e45ca8baa33e0c0228e84126c3a20df3abfd1771Joe Perches	ncp_vdbg("%pd2 failed, closing file\n", dentry);
9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ncp_close_file(NCP_SERVER(dir), finfo->file_handle);
9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	goto out;
9061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9085eee25cacde61c37f1545a33d7fed88b14349976Al Viroint ncp_create_new(struct inode *dir, struct dentry *dentry, umode_t mode,
9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   dev_t rdev, __le32 attributes)
9101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ncp_server *server = NCP_SERVER(dir);
9121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ncp_entry_info finfo;
9131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int error, result, len;
9141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int opmode;
9151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__u8 __name[NCP_MAXPATHLEN + 1];
9161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
917e45ca8baa33e0c0228e84126c3a20df3abfd1771Joe Perches	ncp_vdbg("creating %pd2, mode=%hx\n", dentry, mode);
9181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ncp_age_dentry(server, dentry);
9201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	len = sizeof(__name);
9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	error = ncp_io2vol(server, __name, &len, dentry->d_name.name,
9221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			   dentry->d_name.len, !ncp_preserve_case(dir));
9231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (error)
9241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
9251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	error = -EACCES;
9271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (S_ISREG(mode) &&
9291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    (server->m.flags & NCP_MOUNT_EXTRAS) &&
9301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    (mode & S_IXUGO))
9311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		attributes |= aSYSTEM | aSHARED;
9321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	result = ncp_open_create_file_or_subdir(server, dir, __name,
9341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				OC_MODE_CREATE | OC_MODE_OPEN | OC_MODE_REPLACE,
9351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				attributes, AR_READ | AR_WRITE, &finfo);
9361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	opmode = O_RDWR;
9371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (result) {
9381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		result = ncp_open_create_file_or_subdir(server, dir, __name,
9391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				OC_MODE_CREATE | OC_MODE_OPEN | OC_MODE_REPLACE,
9401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				attributes, AR_WRITE, &finfo);
9411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (result) {
9421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (result == 0x87)
9431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				error = -ENAMETOOLONG;
9442e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec			else if (result < 0)
9452e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec				error = result;
946d3b73ca1be3236fc33f896af7e2ba637a677d5c9Joe Perches			ncp_dbg(1, "%pd2 failed\n", dentry);
9471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto out;
9481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
9491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		opmode = O_WRONLY;
9501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	finfo.access = opmode;
9521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ncp_is_nfs_extras(server, finfo.volume)) {
9531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		finfo.i.nfs.mode = mode;
9541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		finfo.i.nfs.rdev = new_encode_dev(rdev);
9551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ncp_modify_nfs_info(server, finfo.volume,
9561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					finfo.i.dirEntNum,
9571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					mode, new_encode_dev(rdev)) != 0)
9581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto out;
9591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	error = ncp_instantiate(dir, dentry, &finfo);
9621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout:
9631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return error;
9641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9664acdaf27ebe2034c342f3be57ef49aed1ad885efAl Virostatic int ncp_create(struct inode *dir, struct dentry *dentry, umode_t mode,
967ebfc3b49a7ac25920cb5be5445f602e51d2ea559Al Viro		bool excl)
9681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ncp_create_new(dir, dentry, mode, 0, 0);
9701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
97218bb1db3e7607e4a997d50991a6f9fa5b0f8722cAl Virostatic int ncp_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
9731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ncp_entry_info finfo;
9751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ncp_server *server = NCP_SERVER(dir);
9761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int error, len;
9771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__u8 __name[NCP_MAXPATHLEN + 1];
9781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
979d3b73ca1be3236fc33f896af7e2ba637a677d5c9Joe Perches	ncp_dbg(1, "making %pd2\n", dentry);
9801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ncp_age_dentry(server, dentry);
9821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	len = sizeof(__name);
9831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	error = ncp_io2vol(server, __name, &len, dentry->d_name.name,
9841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			   dentry->d_name.len, !ncp_preserve_case(dir));
9851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (error)
9861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
9871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9882e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec	error = ncp_open_create_file_or_subdir(server, dir, __name,
9891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					   OC_MODE_CREATE, aDIR,
9901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					   cpu_to_le16(0xffff),
9912e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec					   &finfo);
9922e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec	if (error == 0) {
9931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ncp_is_nfs_extras(server, finfo.volume)) {
9941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			mode |= S_IFDIR;
9951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			finfo.i.nfs.mode = mode;
9961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (ncp_modify_nfs_info(server,
9971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						finfo.volume,
9981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						finfo.i.dirEntNum,
9991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						mode, 0) != 0)
10001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto out;
10011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
10021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		error = ncp_instantiate(dir, dentry, &finfo);
10032e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec	} else if (error > 0) {
10042e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec		error = -EACCES;
10051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout:
10071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return error;
10081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ncp_rmdir(struct inode *dir, struct dentry *dentry)
10111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ncp_server *server = NCP_SERVER(dir);
10131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int error, result, len;
10141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__u8 __name[NCP_MAXPATHLEN + 1];
10151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1016d3b73ca1be3236fc33f896af7e2ba637a677d5c9Joe Perches	ncp_dbg(1, "removing %pd2\n", dentry);
10171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	len = sizeof(__name);
10191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	error = ncp_io2vol(server, __name, &len, dentry->d_name.name,
10201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			   dentry->d_name.len, !ncp_preserve_case(dir));
10211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (error)
10221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
10231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	result = ncp_del_file_or_subdir(server, dir, __name);
10251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (result) {
10261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0x00:
10271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			error = 0;
10281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
10291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0x85:	/* unauthorized to delete file */
10301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0x8A:	/* unauthorized to delete file */
10311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			error = -EACCES;
10321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
10331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0x8F:
10341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0x90:	/* read only */
10351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			error = -EPERM;
10361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
10371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0x9F:	/* in use by another client */
10381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			error = -EBUSY;
10391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
10401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0xA0:	/* directory not empty */
10411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			error = -ENOTEMPTY;
10421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
10431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0xFF:	/* someone deleted file */
10441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			error = -ENOENT;
10451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
10461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
10472e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec			error = result < 0 ? result : -EACCES;
10481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
10491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds       	}
10501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout:
10511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return error;
10521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ncp_unlink(struct inode *dir, struct dentry *dentry)
10551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct inode *inode = dentry->d_inode;
10571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ncp_server *server;
10581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int error;
10591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	server = NCP_SERVER(dir);
1061d3b73ca1be3236fc33f896af7e2ba637a677d5c9Joe Perches	ncp_dbg(1, "unlinking %pd2\n", dentry);
10621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
10641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Check whether to close the file ...
10651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
10661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (inode) {
1067e45ca8baa33e0c0228e84126c3a20df3abfd1771Joe Perches		ncp_vdbg("closing file\n");
10681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ncp_make_closed(inode);
10691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	error = ncp_del_file_or_subdir2(server, dentry);
10721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_NCPFS_STRONG
10731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* 9C is Invalid path.. It should be 8F, 90 - read only, but
10741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   it is not :-( */
10751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((error == 0x9C || error == 0x90) && server->m.flags & NCP_MOUNT_STRONG) { /* R/O */
10761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		error = ncp_force_unlink(dir, dentry);
10771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
10791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (error) {
10801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0x00:
1081d3b73ca1be3236fc33f896af7e2ba637a677d5c9Joe Perches			ncp_dbg(1, "removed %pd2\n", dentry);
10821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
10831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0x85:
10841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0x8A:
10851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			error = -EACCES;
10861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
10871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0x8D:	/* some files in use */
10881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0x8E:	/* all files in use */
10891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			error = -EBUSY;
10901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
10911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0x8F:	/* some read only */
10921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0x90:	/* all read only */
10931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0x9C:	/* !!! returned when in-use or read-only by NW4 */
10941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			error = -EPERM;
10951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
10961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0xFF:
10971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			error = -ENOENT;
10981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
10991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
11002e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec			error = error < 0 ? error : -EACCES;
11011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
11021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return error;
11041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ncp_rename(struct inode *old_dir, struct dentry *old_dentry,
11071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      struct inode *new_dir, struct dentry *new_dentry)
11081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ncp_server *server = NCP_SERVER(old_dir);
11101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int error;
11111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int old_len, new_len;
11121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__u8 __old_name[NCP_MAXPATHLEN + 1], __new_name[NCP_MAXPATHLEN + 1];
11131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1114d3b73ca1be3236fc33f896af7e2ba637a677d5c9Joe Perches	ncp_dbg(1, "%pd2 to %pd2\n", old_dentry, new_dentry);
11151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ncp_age_dentry(server, old_dentry);
11171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ncp_age_dentry(server, new_dentry);
11181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	old_len = sizeof(__old_name);
11201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	error = ncp_io2vol(server, __old_name, &old_len,
11211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			   old_dentry->d_name.name, old_dentry->d_name.len,
11221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			   !ncp_preserve_case(old_dir));
11231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (error)
11241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
11251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	new_len = sizeof(__new_name);
11271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	error = ncp_io2vol(server, __new_name, &new_len,
11281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			   new_dentry->d_name.name, new_dentry->d_name.len,
11291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			   !ncp_preserve_case(new_dir));
11301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (error)
11311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
11321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	error = ncp_ren_or_mov_file_or_subdir(server, old_dir, __old_name,
11341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						      new_dir, __new_name);
11351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_NCPFS_STRONG
11361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((error == 0x90 || error == 0x8B || error == -EACCES) &&
11371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			server->m.flags & NCP_MOUNT_STRONG) {	/* RO */
11381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		error = ncp_force_rename(old_dir, old_dentry, __old_name,
11391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 new_dir, new_dentry, __new_name);
11401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
11421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (error) {
11431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0x00:
1144d3b73ca1be3236fc33f896af7e2ba637a677d5c9Joe Perches			ncp_dbg(1, "renamed %pd -> %pd\n",
1145d3b73ca1be3236fc33f896af7e2ba637a677d5c9Joe Perches				old_dentry, new_dentry);
11461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
11471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0x9E:
11481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			error = -ENAMETOOLONG;
11491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
11501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0xFF:
11511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			error = -ENOENT;
11521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
11531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
11542e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec			error = error < 0 ? error : -EACCES;
11551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
11561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout:
11581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return error;
11591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ncp_mknod(struct inode * dir, struct dentry *dentry,
11621a67aafb5f72a436ca044293309fa7e6351d6a35Al Viro		     umode_t mode, dev_t rdev)
11631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!new_valid_dev(rdev))
11651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
11661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ncp_is_nfs_extras(NCP_SERVER(dir), NCP_FINFO(dir)->volNumber)) {
1167d3b73ca1be3236fc33f896af7e2ba637a677d5c9Joe Perches		ncp_dbg(1, "mode = 0%ho\n", mode);
11681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ncp_create_new(dir, dentry, mode, rdev, 0);
11691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -EPERM; /* Strange, but true */
11711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The following routines are taken directly from msdos-fs */
11741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Linear day numbers of the respective 1sts in non-leap years. */
11761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int day_n[] =
11781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 0, 0, 0, 0};
11791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec */
11801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int utc2local(int time)
11821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return time - sys_tz.tz_minuteswest * 60;
11841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int local2utc(int time)
11871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return time + sys_tz.tz_minuteswest * 60;
11891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70). */
11921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
11931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsncp_date_dos2unix(__le16 t, __le16 d)
11941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned short time = le16_to_cpu(t), date = le16_to_cpu(d);
11961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int month, year, secs;
11971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* first subtract and mask after that... Otherwise, if
11991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   date == 0, bad things happen */
12001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	month = ((date >> 5) - 1) & 15;
12011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	year = date >> 9;
12021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	secs = (time & 31) * 2 + 60 * ((time >> 5) & 63) + (time >> 11) * 3600 +
12031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		86400 * ((date & 31) - 1 + day_n[month] + (year / 4) +
12041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		year * 365 - ((year & 3) == 0 && month < 2 ? 1 : 0) + 3653);
12051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* days since 1.1.70 plus 80's leap day */
12061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return local2utc(secs);
12071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Convert linear UNIX date to a MS-DOS time/date pair. */
12111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
12121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsncp_date_unix2dos(int unix_date, __le16 *time, __le16 *date)
12131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
12141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int day, year, nl_day, month;
12151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unix_date = utc2local(unix_date);
12171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*time = cpu_to_le16(
12181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		(unix_date % 60) / 2 + (((unix_date / 60) % 60) << 5) +
12191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		(((unix_date / 3600) % 24) << 11));
12201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	day = unix_date / 86400 - 3652;
12211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	year = day / 365;
12221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((year + 3) / 4 + 365 * year > day)
12231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		year--;
12241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	day -= (year + 3) / 4 + 365 * year;
12251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (day == 59 && !(year & 3)) {
12261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		nl_day = day;
12271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		month = 2;
12281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
12291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		nl_day = (year & 3) || day <= 59 ? day : day - 1;
1230c5df59136a55fe08c21d39321679cbb008479edfRoel Kluin		for (month = 1; month < 12; month++)
12311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (day_n[month] > nl_day)
12321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
12331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*date = cpu_to_le16(nl_day - day_n[month - 1] + 1 + (month << 5) + (year << 9));
12351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1236