Blame view

fs/ncpfs/dir.c 30.9 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
11
  /*
   *  dir.c
   *
   *  Copyright (C) 1995, 1996 by Volker Lendecke
   *  Modified for big endian by J.F. Chadima and David S. Miller
   *  Modified 1997 Peter Waltenberg, Bill Hawes, David Woodhouse for 2.1 dcache
   *  Modified 1998, 1999 Wolfram Pienkoss for NLS
   *  Modified 1999 Wolfram Pienkoss for directory caching
   *  Modified 2000 Ben Harris, University of Cambridge for NFS NS meta-info
   *
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
12
13
14
15
16
  
  #include <linux/time.h>
  #include <linux/errno.h>
  #include <linux/stat.h>
  #include <linux/kernel.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
17
18
  #include <linux/vmalloc.h>
  #include <linux/mm.h>
34286d666   Nick Piggin   fs: rcu-walk awar...
19
  #include <linux/namei.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
20
21
  #include <asm/uaccess.h>
  #include <asm/byteorder.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
22

32c419d95   Al Viro   move internal-onl...
23
  #include "ncp_fs.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
24

76f582a8f   Al Viro   [readdir] convert...
25
  static void ncp_read_volume_list(struct file *, struct dir_context *,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
26
  				struct ncp_cache_control *);
76f582a8f   Al Viro   [readdir] convert...
27
  static void ncp_do_readdir(struct file *, struct dir_context *,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
28
  				struct ncp_cache_control *);
76f582a8f   Al Viro   [readdir] convert...
29
  static int ncp_readdir(struct file *, struct dir_context *);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
30

ebfc3b49a   Al Viro   don't pass nameid...
31
  static int ncp_create(struct inode *, struct dentry *, umode_t, bool);
00cd8dd3b   Al Viro   stop passing name...
32
  static struct dentry *ncp_lookup(struct inode *, struct dentry *, unsigned int);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
33
  static int ncp_unlink(struct inode *, struct dentry *);
18bb1db3e   Al Viro   switch vfs_mkdir(...
34
  static int ncp_mkdir(struct inode *, struct dentry *, umode_t);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
35
36
  static int ncp_rmdir(struct inode *, struct dentry *);
  static int ncp_rename(struct inode *, struct dentry *,
1cd66c93b   Miklos Szeredi   fs: make remainin...
37
  		      struct inode *, struct dentry *, unsigned int);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
38
  static int ncp_mknod(struct inode * dir, struct dentry *dentry,
1a67aafb5   Al Viro   switch ->mknod() ...
39
  		     umode_t mode, dev_t rdev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
40
41
42
43
44
45
  #if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS)
  extern int ncp_symlink(struct inode *, struct dentry *, const char *);
  #else
  #define ncp_symlink NULL
  #endif
  		      
4b6f5d20b   Arjan van de Ven   [PATCH] Make most...
46
  const struct file_operations ncp_dir_operations =
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
47
  {
ca572727d   jan Blunck   fs/: do not fallb...
48
  	.llseek		= generic_file_llseek,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
49
  	.read		= generic_read_dir,
76f582a8f   Al Viro   [readdir] convert...
50
  	.iterate	= ncp_readdir,
93d84b6d9   John Kacur   ncpfs: BKL ioctl ...
51
  	.unlocked_ioctl	= ncp_ioctl,
54f67f631   Petr Vandrovec   [PATCH] Move ncpf...
52
53
54
  #ifdef CONFIG_COMPAT
  	.compat_ioctl	= ncp_compat_ioctl,
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
55
  };
92e1d5be9   Arjan van de Ven   [PATCH] mark stru...
56
  const struct inode_operations ncp_dir_inode_operations =
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
57
58
59
60
61
62
63
64
  {
  	.create		= ncp_create,
  	.lookup		= ncp_lookup,
  	.unlink		= ncp_unlink,
  	.symlink	= ncp_symlink,
  	.mkdir		= ncp_mkdir,
  	.rmdir		= ncp_rmdir,
  	.mknod		= ncp_mknod,
2773bf00a   Miklos Szeredi   fs: rename "renam...
65
  	.rename		= ncp_rename,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
66
67
68
69
70
71
  	.setattr	= ncp_notify_change,
  };
  
  /*
   * Dentry operations routines
   */
0b728e191   Al Viro   stop passing name...
72
  static int ncp_lookup_validate(struct dentry *, unsigned int);
da53be12b   Linus Torvalds   Don't pass inode ...
73
  static int ncp_hash_dentry(const struct dentry *, struct qstr *);
6fa67e707   Al Viro   get rid of 'paren...
74
  static int ncp_compare_dentry(const struct dentry *,
621e155a3   Nick Piggin   fs: change d_comp...
75
  		unsigned int, const char *, const struct qstr *);
fe15ce446   Nick Piggin   fs: change d_dele...
76
  static int ncp_delete_dentry(const struct dentry *);
5e993e253   Al Viro   ncpfs: get rid of...
77
  static void ncp_d_prune(struct dentry *dentry);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
78

0378c4051   Al Viro   switch ncpfs
79
  const struct dentry_operations ncp_dentry_operations =
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
80
81
82
83
84
  {
  	.d_revalidate	= ncp_lookup_validate,
  	.d_hash		= ncp_hash_dentry,
  	.d_compare	= ncp_compare_dentry,
  	.d_delete	= ncp_delete_dentry,
5e993e253   Al Viro   ncpfs: get rid of...
85
  	.d_prune	= ncp_d_prune,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
86
  };
2e54eb96e   Petr Vandrovec   BKL: Remove BKL f...
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
  #define ncp_namespace(i)	(NCP_SERVER(i)->name_space[NCP_FINFO(i)->volNumber])
  
  static inline int ncp_preserve_entry_case(struct inode *i, __u32 nscreator)
  {
  #ifdef CONFIG_NCPFS_SMALLDOS
  	int ns = ncp_namespace(i);
  
  	if ((ns == NW_NS_DOS)
  #ifdef CONFIG_NCPFS_OS2_NS
  		|| ((ns == NW_NS_OS2) && (nscreator == NW_NS_DOS))
  #endif /* CONFIG_NCPFS_OS2_NS */
  	   )
  		return 0;
  #endif /* CONFIG_NCPFS_SMALLDOS */
  	return 1;
  }
  
  #define ncp_preserve_case(i)	(ncp_namespace(i) != NW_NS_DOS)
621e155a3   Nick Piggin   fs: change d_comp...
105
  static inline int ncp_case_sensitive(const struct inode *i)
2e54eb96e   Petr Vandrovec   BKL: Remove BKL f...
106
107
  {
  #ifdef CONFIG_NCPFS_NFS_NS
621e155a3   Nick Piggin   fs: change d_comp...
108
  	return ncp_namespace(i) == NW_NS_NFS;
2e54eb96e   Petr Vandrovec   BKL: Remove BKL f...
109
110
111
112
  #else
  	return 0;
  #endif /* CONFIG_NCPFS_NFS_NS */
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
113
114
115
  /*
   * Note: leave the hash unchanged if the directory
   * is case-sensitive.
da53be12b   Linus Torvalds   Don't pass inode ...
116
117
118
119
   *
   * Accessing the parent inode can be racy under RCU pathwalking.
   * Use ACCESS_ONCE() to make sure we use _one_ particular inode,
   * the callers will handle races.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
120
121
   */
  static int 
da53be12b   Linus Torvalds   Don't pass inode ...
122
  ncp_hash_dentry(const struct dentry *dentry, struct qstr *this)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
123
  {
2b0143b5c   David Howells   VFS: normal files...
124
  	struct inode *inode = d_inode_rcu(dentry);
da53be12b   Linus Torvalds   Don't pass inode ...
125
126
127
  
  	if (!inode)
  		return 0;
b1e6a015a   Nick Piggin   fs: change d_hash...
128
  	if (!ncp_case_sensitive(inode)) {
2e54eb96e   Petr Vandrovec   BKL: Remove BKL f...
129
130
131
  		struct nls_table *t;
  		unsigned long hash;
  		int i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
132

9a232de49   Miklos Szeredi   ncpfs: fix unused...
133
  		t = NCP_IO_TABLE(dentry->d_sb);
8387ff257   Linus Torvalds   vfs: make the str...
134
  		hash = init_name_hash(dentry);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
135
136
137
138
139
140
141
  		for (i=0; i<this->len ; i++)
  			hash = partial_name_hash(ncp_tolower(t, this->name[i]),
  									hash);
  		this->hash = end_name_hash(hash);
  	}
  	return 0;
  }
da53be12b   Linus Torvalds   Don't pass inode ...
142
143
144
145
146
  /*
   * Accessing the parent inode can be racy under RCU pathwalking.
   * Use ACCESS_ONCE() to make sure we use _one_ particular inode,
   * the callers will handle races.
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
147
  static int
6fa67e707   Al Viro   get rid of 'paren...
148
  ncp_compare_dentry(const struct dentry *dentry,
621e155a3   Nick Piggin   fs: change d_comp...
149
  		unsigned int len, const char *str, const struct qstr *name)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
150
  {
da53be12b   Linus Torvalds   Don't pass inode ...
151
  	struct inode *pinode;
621e155a3   Nick Piggin   fs: change d_comp...
152
  	if (len != name->len)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
153
  		return 1;
6fa67e707   Al Viro   get rid of 'paren...
154
  	pinode = d_inode_rcu(dentry->d_parent);
da53be12b   Linus Torvalds   Don't pass inode ...
155
156
  	if (!pinode)
  		return 1;
621e155a3   Nick Piggin   fs: change d_comp...
157
158
  	if (ncp_case_sensitive(pinode))
  		return strncmp(str, name->name, len);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
159

621e155a3   Nick Piggin   fs: change d_comp...
160
  	return ncp_strnicmp(NCP_IO_TABLE(pinode->i_sb), str, name->name, len);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
161
162
163
164
165
166
167
168
  }
  
  /*
   * This is the callback from dput() when d_count is going to 0.
   * We use this to unhash dentries with bad inodes.
   * Closing files can be safely postponed until iput() - it's done there anyway.
   */
  static int
fe15ce446   Nick Piggin   fs: change d_dele...
169
  ncp_delete_dentry(const struct dentry * dentry)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
170
  {
2b0143b5c   David Howells   VFS: normal files...
171
  	struct inode *inode = d_inode(dentry);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
  
  	if (inode) {
  		if (is_bad_inode(inode))
  			return 1;
  	} else
  	{
  	/* N.B. Unhash negative dentries? */
  	}
  	return 0;
  }
  
  static inline int
  ncp_single_volume(struct ncp_server *server)
  {
  	return (server->m.mounted_vol[0] != '\0');
  }
  
  static inline int ncp_is_server_root(struct inode *inode)
  {
a7400222e   Al Viro   new helper: is_ro...
191
192
  	return !ncp_single_volume(NCP_SERVER(inode)) &&
  		is_root_inode(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
  }
  
  
  /*
   * This is the callback when the dcache has a lookup hit.
   */
  
  
  #ifdef CONFIG_NCPFS_STRONG
  /* try to delete a readonly file (NW R bit set) */
  
  static int
  ncp_force_unlink(struct inode *dir, struct dentry* dentry)
  {
          int res=0x9c,res2;
  	struct nw_modify_dos_info info;
  	__le32 old_nwattr;
  	struct inode *inode;
  
  	memset(&info, 0, sizeof(info));
  	
          /* remove the Read-Only flag on the NW server */
2b0143b5c   David Howells   VFS: normal files...
215
  	inode = d_inode(dentry);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
  
  	old_nwattr = NCP_FINFO(inode)->nwattr;
  	info.attributes = old_nwattr & ~(aRONLY|aDELETEINHIBIT|aRENAMEINHIBIT);
  	res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(inode), inode, NULL, DM_ATTRIBUTES, &info);
  	if (res2)
  		goto leave_me;
  
          /* now try again the delete operation */
          res = ncp_del_file_or_subdir2(NCP_SERVER(dir), dentry);
  
          if (res)  /* delete failed, set R bit again */
          {
  		info.attributes = old_nwattr;
  		res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(inode), inode, NULL, DM_ATTRIBUTES, &info);
  		if (res2)
                          goto leave_me;
          }
  leave_me:
          return(res);
  }
  #endif	/* CONFIG_NCPFS_STRONG */
  
  #ifdef CONFIG_NCPFS_STRONG
  static int
  ncp_force_rename(struct inode *old_dir, struct dentry* old_dentry, char *_old_name,
                   struct inode *new_dir, struct dentry* new_dentry, char *_new_name)
  {
  	struct nw_modify_dos_info info;
          int res=0x90,res2;
2b0143b5c   David Howells   VFS: normal files...
245
  	struct inode *old_inode = d_inode(old_dentry);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
246
247
248
249
250
251
252
253
254
255
256
257
258
  	__le32 old_nwattr = NCP_FINFO(old_inode)->nwattr;
  	__le32 new_nwattr = 0; /* shut compiler warning */
  	int old_nwattr_changed = 0;
  	int new_nwattr_changed = 0;
  
  	memset(&info, 0, sizeof(info));
  	
          /* remove the Read-Only flag on the NW server */
  
  	info.attributes = old_nwattr & ~(aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
  	res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(old_inode), old_inode, NULL, DM_ATTRIBUTES, &info);
  	if (!res2)
  		old_nwattr_changed = 1;
2b0143b5c   David Howells   VFS: normal files...
259
260
  	if (new_dentry && d_really_is_positive(new_dentry)) {
  		new_nwattr = NCP_FINFO(d_inode(new_dentry))->nwattr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
  		info.attributes = new_nwattr & ~(aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
  		res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(new_dir), new_dir, _new_name, DM_ATTRIBUTES, &info);
  		if (!res2)
  			new_nwattr_changed = 1;
  	}
          /* now try again the rename operation */
  	/* but only if something really happened */
  	if (new_nwattr_changed || old_nwattr_changed) {
  	        res = ncp_ren_or_mov_file_or_subdir(NCP_SERVER(old_dir),
          	                                    old_dir, _old_name,
                  	                            new_dir, _new_name);
  	} 
  	if (res)
  		goto leave_me;
  	/* file was successfully renamed, so:
  	   do not set attributes on old file - it no longer exists
  	   copy attributes from old file to new */
  	new_nwattr_changed = old_nwattr_changed;
  	new_nwattr = old_nwattr;
  	old_nwattr_changed = 0;
  	
  leave_me:;
  	if (old_nwattr_changed) {
  		info.attributes = old_nwattr;
  		res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(old_inode), old_inode, NULL, DM_ATTRIBUTES, &info);
  		/* ignore errors */
  	}
  	if (new_nwattr_changed)	{
  		info.attributes = new_nwattr;
  		res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(new_dir), new_dir, _new_name, DM_ATTRIBUTES, &info);
  		/* ignore errors */
  	}
          return(res);
  }
  #endif	/* CONFIG_NCPFS_STRONG */
  
  
  static int
0b728e191   Al Viro   stop passing name...
299
  ncp_lookup_validate(struct dentry *dentry, unsigned int flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
300
301
302
303
304
305
306
  {
  	struct ncp_server *server;
  	struct dentry *parent;
  	struct inode *dir;
  	struct ncp_entry_info finfo;
  	int res, val = 0, len;
  	__u8 __name[NCP_MAXPATHLEN + 1];
0378c4051   Al Viro   switch ncpfs
307
308
  	if (dentry == dentry->d_sb->s_root)
  		return 1;
0b728e191   Al Viro   stop passing name...
309
  	if (flags & LOOKUP_RCU)
34286d666   Nick Piggin   fs: rcu-walk awar...
310
  		return -ECHILD;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
311
  	parent = dget_parent(dentry);
2b0143b5c   David Howells   VFS: normal files...
312
  	dir = d_inode(parent);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
313

2b0143b5c   David Howells   VFS: normal files...
314
  	if (d_really_is_negative(dentry))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
315
316
317
  		goto finished;
  
  	server = NCP_SERVER(dir);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
318
319
320
321
322
323
324
325
326
  	/*
  	 * Inspired by smbfs:
  	 * The default validation is based on dentry age:
  	 * We set the max age at mount time.  (But each
  	 * successful server lookup renews the timestamp.)
  	 */
  	val = NCP_TEST_AGE(server, dentry);
  	if (val)
  		goto finished;
d3b73ca1b   Joe Perches   ncpfs: convert DP...
327
328
  	ncp_dbg(2, "%pd2 not valid, age=%ld, server lookup
  ",
84eb3532b   Al Viro   ncpfs: switch to ...
329
  		dentry, NCP_GET_AGE(dentry));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
330
331
332
333
334
  
  	len = sizeof(__name);
  	if (ncp_is_server_root(dir)) {
  		res = ncp_io2vol(server, __name, &len, dentry->d_name.name,
  				 dentry->d_name.len, 1);
2e54eb96e   Petr Vandrovec   BKL: Remove BKL f...
335
  		if (!res) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
336
  			res = ncp_lookup_volume(server, __name, &(finfo.i));
2e54eb96e   Petr Vandrovec   BKL: Remove BKL f...
337
338
339
  			if (!res)
  				ncp_update_known_namespace(server, finfo.i.volNumber, NULL);
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
340
341
342
343
344
345
346
  	} else {
  		res = ncp_io2vol(server, __name, &len, dentry->d_name.name,
  				 dentry->d_name.len, !ncp_preserve_case(dir));
  		if (!res)
  			res = ncp_obtain_info(server, dir, __name, &(finfo.i));
  	}
  	finfo.volume = finfo.i.volNumber;
d3b73ca1b   Joe Perches   ncpfs: convert DP...
347
348
  	ncp_dbg(2, "looked for %pd/%s, res=%d
  ",
84eb3532b   Al Viro   ncpfs: switch to ...
349
  		dentry->d_parent, __name, res);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
350
351
352
353
354
  	/*
  	 * If we didn't find it, or if it has a different dirEntNum to
  	 * what we remember, it's not valid any more.
  	 */
  	if (!res) {
2b0143b5c   David Howells   VFS: normal files...
355
  		struct inode *inode = d_inode(dentry);
2e54eb96e   Petr Vandrovec   BKL: Remove BKL f...
356

5955102c9   Al Viro   wrappers for ->i_...
357
  		inode_lock(inode);
2e54eb96e   Petr Vandrovec   BKL: Remove BKL f...
358
  		if (finfo.i.dirEntNum == NCP_FINFO(inode)->dirEntNum) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
359
360
361
  			ncp_new_dentry(dentry);
  			val=1;
  		} else
d3b73ca1b   Joe Perches   ncpfs: convert DP...
362
363
  			ncp_dbg(2, "found, but dirEntNum changed
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
364

2e54eb96e   Petr Vandrovec   BKL: Remove BKL f...
365
  		ncp_update_inode2(inode, &finfo);
5955102c9   Al Viro   wrappers for ->i_...
366
  		inode_unlock(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
367
368
369
  	}
  
  finished:
d3b73ca1b   Joe Perches   ncpfs: convert DP...
370
371
  	ncp_dbg(2, "result=%d
  ", val);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
372
373
374
  	dput(parent);
  	return val;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
375
376
  static time_t ncp_obtain_mtime(struct dentry *dentry)
  {
2b0143b5c   David Howells   VFS: normal files...
377
  	struct inode *inode = d_inode(dentry);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
378
379
380
381
382
383
384
385
386
387
388
  	struct ncp_server *server = NCP_SERVER(inode);
  	struct nw_info_struct i;
  
  	if (!ncp_conn_valid(server) || ncp_is_server_root(inode))
  		return 0;
  
  	if (ncp_obtain_info(server, inode, NULL, &i))
  		return 0;
  
  	return ncp_date_dos2unix(i.modifyTime, i.modifyDate);
  }
5e993e253   Al Viro   ncpfs: get rid of...
389
390
391
  static inline void
  ncp_invalidate_dircache_entries(struct dentry *parent)
  {
2b0143b5c   David Howells   VFS: normal files...
392
  	struct ncp_server *server = NCP_SERVER(d_inode(parent));
5e993e253   Al Viro   ncpfs: get rid of...
393
394
395
396
397
398
399
400
401
  	struct dentry *dentry;
  
  	spin_lock(&parent->d_lock);
  	list_for_each_entry(dentry, &parent->d_subdirs, d_child) {
  		dentry->d_fsdata = NULL;
  		ncp_age_dentry(server, dentry);
  	}
  	spin_unlock(&parent->d_lock);
  }
76f582a8f   Al Viro   [readdir] convert...
402
  static int ncp_readdir(struct file *file, struct dir_context *ctx)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
403
  {
76f582a8f   Al Viro   [readdir] convert...
404
  	struct dentry *dentry = file->f_path.dentry;
2b0143b5c   David Howells   VFS: normal files...
405
  	struct inode *inode = d_inode(dentry);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
406
407
408
409
410
411
  	struct page *page = NULL;
  	struct ncp_server *server = NCP_SERVER(inode);
  	union  ncp_dir_cache *cache = NULL;
  	struct ncp_cache_control ctl;
  	int result, mtime_valid = 0;
  	time_t mtime = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
412
413
  	ctl.page  = NULL;
  	ctl.cache = NULL;
d3b73ca1b   Joe Perches   ncpfs: convert DP...
414
415
  	ncp_dbg(2, "reading %pD2, pos=%d
  ", file, (int)ctx->pos);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
416
417
  
  	result = -EIO;
2e54eb96e   Petr Vandrovec   BKL: Remove BKL f...
418
  	/* Do not generate '.' and '..' when server is dead. */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
419
420
421
422
  	if (!ncp_conn_valid(server))
  		goto out;
  
  	result = 0;
76f582a8f   Al Viro   [readdir] convert...
423
424
  	if (!dir_emit_dots(file, ctx))
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
425
426
427
428
429
430
431
432
433
434
  
  	page = grab_cache_page(&inode->i_data, 0);
  	if (!page)
  		goto read_really;
  
  	ctl.cache = cache = kmap(page);
  	ctl.head  = cache->head;
  
  	if (!PageUptodate(page) || !ctl.head.eof)
  		goto init_cache;
76f582a8f   Al Viro   [readdir] convert...
435
  	if (ctx->pos == 2) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
436
437
438
439
440
441
442
443
  		if (jiffies - ctl.head.time >= NCP_MAX_AGE(server))
  			goto init_cache;
  
  		mtime = ncp_obtain_mtime(dentry);
  		mtime_valid = 1;
  		if ((!mtime) || (mtime != ctl.head.mtime))
  			goto init_cache;
  	}
76f582a8f   Al Viro   [readdir] convert...
444
  	if (ctx->pos > ctl.head.end)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
445
  		goto finished;
76f582a8f   Al Viro   [readdir] convert...
446
  	ctl.fpos = ctx->pos + (NCP_DIRCACHE_START - 2);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
447
448
449
450
451
452
453
454
455
456
457
458
459
460
  	ctl.ofs  = ctl.fpos / NCP_DIRCACHE_SIZE;
  	ctl.idx  = ctl.fpos % NCP_DIRCACHE_SIZE;
  
  	for (;;) {
  		if (ctl.ofs != 0) {
  			ctl.page = find_lock_page(&inode->i_data, ctl.ofs);
  			if (!ctl.page)
  				goto invalid_cache;
  			ctl.cache = kmap(ctl.page);
  			if (!PageUptodate(ctl.page))
  				goto invalid_cache;
  		}
  		while (ctl.idx < NCP_DIRCACHE_SIZE) {
  			struct dentry *dent;
76f582a8f   Al Viro   [readdir] convert...
461
  			bool over;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
462

5e993e253   Al Viro   ncpfs: get rid of...
463
464
465
466
467
468
469
470
471
472
473
  			spin_lock(&dentry->d_lock);
  			if (!(NCP_FINFO(inode)->flags & NCPI_DIR_CACHE)) { 
  				spin_unlock(&dentry->d_lock);
  				goto invalid_cache;
  			}
  			dent = ctl.cache->dentry[ctl.idx];
  			if (unlikely(!lockref_get_not_dead(&dent->d_lockref))) {
  				spin_unlock(&dentry->d_lock);
  				goto invalid_cache;
  			}
  			spin_unlock(&dentry->d_lock);
2b0143b5c   David Howells   VFS: normal files...
474
  			if (d_really_is_negative(dent)) {
5e993e253   Al Viro   ncpfs: get rid of...
475
  				dput(dent);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
476
  				goto invalid_cache;
5e993e253   Al Viro   ncpfs: get rid of...
477
  			}
76f582a8f   Al Viro   [readdir] convert...
478
479
  			over = !dir_emit(ctx, dent->d_name.name,
  					dent->d_name.len,
2b0143b5c   David Howells   VFS: normal files...
480
  					d_inode(dent)->i_ino, DT_UNKNOWN);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
481
  			dput(dent);
76f582a8f   Al Viro   [readdir] convert...
482
  			if (over)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
483
  				goto finished;
76f582a8f   Al Viro   [readdir] convert...
484
  			ctx->pos += 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
485
  			ctl.idx += 1;
76f582a8f   Al Viro   [readdir] convert...
486
  			if (ctx->pos > ctl.head.end)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
487
488
489
490
491
492
  				goto finished;
  		}
  		if (ctl.page) {
  			kunmap(ctl.page);
  			SetPageUptodate(ctl.page);
  			unlock_page(ctl.page);
09cbfeaf1   Kirill A. Shutemov   mm, fs: get rid o...
493
  			put_page(ctl.page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
494
495
496
497
498
499
500
501
502
  			ctl.page = NULL;
  		}
  		ctl.idx  = 0;
  		ctl.ofs += 1;
  	}
  invalid_cache:
  	if (ctl.page) {
  		kunmap(ctl.page);
  		unlock_page(ctl.page);
09cbfeaf1   Kirill A. Shutemov   mm, fs: get rid o...
503
  		put_page(ctl.page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
  		ctl.page = NULL;
  	}
  	ctl.cache = cache;
  init_cache:
  	ncp_invalidate_dircache_entries(dentry);
  	if (!mtime_valid) {
  		mtime = ncp_obtain_mtime(dentry);
  		mtime_valid = 1;
  	}
  	ctl.head.mtime = mtime;
  	ctl.head.time = jiffies;
  	ctl.head.eof = 0;
  	ctl.fpos = 2;
  	ctl.ofs = 0;
  	ctl.idx = NCP_DIRCACHE_START;
  	ctl.filled = 0;
  	ctl.valid  = 1;
  read_really:
5e993e253   Al Viro   ncpfs: get rid of...
522
523
524
  	spin_lock(&dentry->d_lock);
  	NCP_FINFO(inode)->flags |= NCPI_DIR_CACHE;
  	spin_unlock(&dentry->d_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
525
  	if (ncp_is_server_root(inode)) {
76f582a8f   Al Viro   [readdir] convert...
526
  		ncp_read_volume_list(file, ctx, &ctl);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
527
  	} else {
76f582a8f   Al Viro   [readdir] convert...
528
  		ncp_do_readdir(file, ctx, &ctl);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
529
530
531
532
  	}
  	ctl.head.end = ctl.fpos - 1;
  	ctl.head.eof = ctl.valid;
  finished:
2e54eb96e   Petr Vandrovec   BKL: Remove BKL f...
533
534
535
536
  	if (ctl.page) {
  		kunmap(ctl.page);
  		SetPageUptodate(ctl.page);
  		unlock_page(ctl.page);
09cbfeaf1   Kirill A. Shutemov   mm, fs: get rid o...
537
  		put_page(ctl.page);
2e54eb96e   Petr Vandrovec   BKL: Remove BKL f...
538
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
539
540
541
542
543
  	if (page) {
  		cache->head = ctl.head;
  		kunmap(page);
  		SetPageUptodate(page);
  		unlock_page(page);
09cbfeaf1   Kirill A. Shutemov   mm, fs: get rid o...
544
  		put_page(page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
545
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
546
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
547
548
  	return result;
  }
5e993e253   Al Viro   ncpfs: get rid of...
549
550
551
552
  static void ncp_d_prune(struct dentry *dentry)
  {
  	if (!dentry->d_fsdata)	/* not referenced from page cache */
  		return;
2b0143b5c   David Howells   VFS: normal files...
553
  	NCP_FINFO(d_inode(dentry->d_parent))->flags &= ~NCPI_DIR_CACHE;
5e993e253   Al Viro   ncpfs: get rid of...
554
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
555
  static int
76f582a8f   Al Viro   [readdir] convert...
556
  ncp_fill_cache(struct file *file, struct dir_context *ctx,
2e54eb96e   Petr Vandrovec   BKL: Remove BKL f...
557
558
  		struct ncp_cache_control *ctrl, struct ncp_entry_info *entry,
  		int inval_childs)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
559
  {
76f582a8f   Al Viro   [readdir] convert...
560
  	struct dentry *newdent, *dentry = file->f_path.dentry;
2b0143b5c   David Howells   VFS: normal files...
561
  	struct inode *dir = d_inode(dentry);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
562
563
564
565
566
567
568
569
  	struct ncp_cache_control ctl = *ctrl;
  	struct qstr qname;
  	int valid = 0;
  	int hashed = 0;
  	ino_t ino = 0;
  	__u8 __name[NCP_MAXPATHLEN + 1];
  
  	qname.len = sizeof(__name);
2e54eb96e   Petr Vandrovec   BKL: Remove BKL f...
570
  	if (ncp_vol2io(NCP_SERVER(dir), __name, &qname.len,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
571
  			entry->i.entryName, entry->i.nameLen,
2e54eb96e   Petr Vandrovec   BKL: Remove BKL f...
572
  			!ncp_preserve_entry_case(dir, entry->i.NSCreator)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
573
574
575
  		return 1; /* I'm not sure */
  
  	qname.name = __name;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
576

4f522a247   Al Viro   d_hash_and_lookup...
577
  	newdent = d_hash_and_lookup(dentry, &qname);
a1c83681d   Viresh Kumar   fs: Drop unlikely...
578
  	if (IS_ERR(newdent))
4f522a247   Al Viro   d_hash_and_lookup...
579
  		goto end_advance;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
580
581
582
583
584
585
  	if (!newdent) {
  		newdent = d_alloc(dentry, &qname);
  		if (!newdent)
  			goto end_advance;
  	} else {
  		hashed = 1;
2e54eb96e   Petr Vandrovec   BKL: Remove BKL f...
586
587
588
589
590
591
592
593
  
  		/* If case sensitivity changed for this volume, all entries below this one
  		   should be thrown away.  This entry itself is not affected, as its case
  		   sensitivity is controlled by its own parent. */
  		if (inval_childs)
  			shrink_dcache_parent(newdent);
  
  		/*
fb2d5b86a   Nick Piggin   fs: name case upd...
594
595
596
597
  		 * NetWare's OS2 namespace is case preserving yet case
  		 * insensitive.  So we update dentry's name as received from
  		 * server. Parent dir's i_mutex is locked because we're in
  		 * readdir.
2e54eb96e   Petr Vandrovec   BKL: Remove BKL f...
598
  		 */
fb2d5b86a   Nick Piggin   fs: name case upd...
599
  		dentry_update_name_case(newdent, &qname);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
600
  	}
2b0143b5c   David Howells   VFS: normal files...
601
  	if (d_really_is_negative(newdent)) {
2e54eb96e   Petr Vandrovec   BKL: Remove BKL f...
602
  		struct inode *inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
603
  		entry->opened = 0;
2e54eb96e   Petr Vandrovec   BKL: Remove BKL f...
604
605
606
  		entry->ino = iunique(dir->i_sb, 2);
  		inode = ncp_iget(dir->i_sb, entry);
  		if (inode) {
2e54eb96e   Petr Vandrovec   BKL: Remove BKL f...
607
  			d_instantiate(newdent, inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
608
609
  			if (!hashed)
  				d_rehash(newdent);
5e993e253   Al Viro   ncpfs: get rid of...
610
611
  		} else {
  			spin_lock(&dentry->d_lock);
803c00123   Al Viro   ncpfs: fix a brai...
612
  			NCP_FINFO(dir)->flags &= ~NCPI_DIR_CACHE;
5e993e253   Al Viro   ncpfs: get rid of...
613
  			spin_unlock(&dentry->d_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
614
  		}
2e54eb96e   Petr Vandrovec   BKL: Remove BKL f...
615
  	} else {
2b0143b5c   David Howells   VFS: normal files...
616
  		struct inode *inode = d_inode(newdent);
2e54eb96e   Petr Vandrovec   BKL: Remove BKL f...
617

5955102c9   Al Viro   wrappers for ->i_...
618
  		inode_lock_nested(inode, I_MUTEX_CHILD);
2e54eb96e   Petr Vandrovec   BKL: Remove BKL f...
619
  		ncp_update_inode2(inode, entry);
5955102c9   Al Viro   wrappers for ->i_...
620
  		inode_unlock(inode);
2e54eb96e   Petr Vandrovec   BKL: Remove BKL f...
621
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
622

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
623
624
625
626
627
  	if (ctl.idx >= NCP_DIRCACHE_SIZE) {
  		if (ctl.page) {
  			kunmap(ctl.page);
  			SetPageUptodate(ctl.page);
  			unlock_page(ctl.page);
09cbfeaf1   Kirill A. Shutemov   mm, fs: get rid o...
628
  			put_page(ctl.page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
629
630
631
632
  		}
  		ctl.cache = NULL;
  		ctl.idx  -= NCP_DIRCACHE_SIZE;
  		ctl.ofs  += 1;
2e54eb96e   Petr Vandrovec   BKL: Remove BKL f...
633
  		ctl.page  = grab_cache_page(&dir->i_data, ctl.ofs);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
634
635
636
637
  		if (ctl.page)
  			ctl.cache = kmap(ctl.page);
  	}
  	if (ctl.cache) {
2b0143b5c   David Howells   VFS: normal files...
638
  		if (d_really_is_positive(newdent)) {
5e993e253   Al Viro   ncpfs: get rid of...
639
640
  			newdent->d_fsdata = newdent;
  			ctl.cache->dentry[ctl.idx] = newdent;
2b0143b5c   David Howells   VFS: normal files...
641
  			ino = d_inode(newdent)->i_ino;
5e993e253   Al Viro   ncpfs: get rid of...
642
643
644
  			ncp_new_dentry(newdent);
  		}
   		valid = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
645
646
647
648
649
  	}
  	dput(newdent);
  end_advance:
  	if (!valid)
  		ctl.valid = 0;
76f582a8f   Al Viro   [readdir] convert...
650
  	if (!ctl.filled && (ctl.fpos == ctx->pos)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
651
  		if (!ino)
2e54eb96e   Petr Vandrovec   BKL: Remove BKL f...
652
  			ino = iunique(dir->i_sb, 2);
76f582a8f   Al Viro   [readdir] convert...
653
654
  		ctl.filled = !dir_emit(ctx, qname.name, qname.len,
  				     ino, DT_UNKNOWN);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
655
  		if (!ctl.filled)
76f582a8f   Al Viro   [readdir] convert...
656
  			ctx->pos += 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
657
658
659
660
661
662
663
664
  	}
  	ctl.fpos += 1;
  	ctl.idx  += 1;
  	*ctrl = ctl;
  	return (ctl.valid || !ctl.filled);
  }
  
  static void
76f582a8f   Al Viro   [readdir] convert...
665
  ncp_read_volume_list(struct file *file, struct dir_context *ctx,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
666
667
  			struct ncp_cache_control *ctl)
  {
a67f797db   Al Viro   ncpfs: use file_i...
668
  	struct inode *inode = file_inode(file);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
669
670
671
672
  	struct ncp_server *server = NCP_SERVER(inode);
  	struct ncp_volume_info info;
  	struct ncp_entry_info entry;
  	int i;
d3b73ca1b   Joe Perches   ncpfs: convert DP...
673
674
  	ncp_dbg(1, "pos=%ld
  ", (unsigned long)ctx->pos);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
675
676
  
  	for (i = 0; i < NCP_NUMBER_OF_VOLUMES; i++) {
2e54eb96e   Petr Vandrovec   BKL: Remove BKL f...
677
  		int inval_dentry;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
678
679
680
681
682
  
  		if (ncp_get_volume_info_with_number(server, i, &info) != 0)
  			return;
  		if (!strlen(info.volume_name))
  			continue;
d3b73ca1b   Joe Perches   ncpfs: convert DP...
683
684
  		ncp_dbg(1, "found vol: %s
  ", info.volume_name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
685
686
687
  
  		if (ncp_lookup_volume(server, info.volume_name,
  					&entry.i)) {
d3b73ca1b   Joe Perches   ncpfs: convert DP...
688
689
  			ncp_dbg(1, "could not lookup vol %s
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
690
691
692
  				info.volume_name);
  			continue;
  		}
2e54eb96e   Petr Vandrovec   BKL: Remove BKL f...
693
  		inval_dentry = ncp_update_known_namespace(server, entry.i.volNumber, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
694
  		entry.volume = entry.i.volNumber;
76f582a8f   Al Viro   [readdir] convert...
695
  		if (!ncp_fill_cache(file, ctx, ctl, &entry, inval_dentry))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
696
697
698
699
700
  			return;
  	}
  }
  
  static void
76f582a8f   Al Viro   [readdir] convert...
701
  ncp_do_readdir(struct file *file, struct dir_context *ctx,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
702
703
  						struct ncp_cache_control *ctl)
  {
a67f797db   Al Viro   ncpfs: use file_i...
704
  	struct inode *dir = file_inode(file);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
705
706
707
708
709
710
711
  	struct ncp_server *server = NCP_SERVER(dir);
  	struct nw_search_sequence seq;
  	struct ncp_entry_info entry;
  	int err;
  	void* buf;
  	int more;
  	size_t bufsize;
d3b73ca1b   Joe Perches   ncpfs: convert DP...
712
713
  	ncp_dbg(1, "%pD2, fpos=%ld
  ", file, (unsigned long)ctx->pos);
e45ca8baa   Joe Perches   ncpfs: convert PP...
714
715
716
  	ncp_vdbg("init %pD, volnum=%d, dirent=%u
  ",
  		 file, NCP_FINFO(dir)->volNumber, NCP_FINFO(dir)->dirEntNum);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
717
718
719
  
  	err = ncp_initialize_search(server, dir, &seq);
  	if (err) {
d3b73ca1b   Joe Perches   ncpfs: convert DP...
720
721
  		ncp_dbg(1, "init failed, err=%d
  ", err);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
722
723
  		return;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
  	/* We MUST NOT use server->buffer_size handshaked with server if we are
  	   using UDP, as for UDP server uses max. buffer size determined by
  	   MTU, and for TCP server uses hardwired value 65KB (== 66560 bytes). 
  	   So we use 128KB, just to be sure, as there is no way how to know
  	   this value in advance. */
  	bufsize = 131072;
  	buf = vmalloc(bufsize);
  	if (!buf)
  		return;
  	do {
  		int cnt;
  		char* rpl;
  		size_t rpls;
  
  		err = ncp_search_for_fileset(server, &seq, &more, &cnt, buf, bufsize, &rpl, &rpls);
  		if (err)		/* Error */
  			break;
  		if (!cnt)		/* prevent endless loop */
  			break;
  		while (cnt--) {
  			size_t onerpl;
  			
  			if (rpls < offsetof(struct nw_info_struct, entryName))
  				break;	/* short packet */
  			ncp_extract_file_info(rpl, &entry.i);
  			onerpl = offsetof(struct nw_info_struct, entryName) + entry.i.nameLen;
  			if (rpls < onerpl)
  				break;	/* short packet */
  			(void)ncp_obtain_nfs_info(server, &entry.i);
  			rpl += onerpl;
  			rpls -= onerpl;
  			entry.volume = entry.i.volNumber;
76f582a8f   Al Viro   [readdir] convert...
756
  			if (!ncp_fill_cache(file, ctx, ctl, &entry, 0))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
757
758
759
760
  				break;
  		}
  	} while (more);
  	vfree(buf);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
  	return;
  }
  
  int ncp_conn_logged_in(struct super_block *sb)
  {
  	struct ncp_server* server = NCP_SBP(sb);
  	int result;
  
  	if (ncp_single_volume(server)) {
  		int len;
  		struct dentry* dent;
  		__u32 volNumber;
  		__le32 dirEntNum;
  		__le32 DosDirNum;
  		__u8 __name[NCP_MAXPATHLEN + 1];
  
  		len = sizeof(__name);
  		result = ncp_io2vol(server, __name, &len, server->m.mounted_vol,
  				    strlen(server->m.mounted_vol), 1);
  		if (result)
  			goto out;
  		result = -ENOENT;
  		if (ncp_get_volume_root(server, __name, &volNumber, &dirEntNum, &DosDirNum)) {
e45ca8baa   Joe Perches   ncpfs: convert PP...
784
785
  			ncp_vdbg("%s not found
  ", server->m.mounted_vol);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
786
787
788
789
  			goto out;
  		}
  		dent = sb->s_root;
  		if (dent) {
2b0143b5c   David Howells   VFS: normal files...
790
  			struct inode* ino = d_inode(dent);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
791
  			if (ino) {
2e54eb96e   Petr Vandrovec   BKL: Remove BKL f...
792
  				ncp_update_known_namespace(server, volNumber, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
793
794
795
  				NCP_FINFO(ino)->volNumber = volNumber;
  				NCP_FINFO(ino)->dirEntNum = dirEntNum;
  				NCP_FINFO(ino)->DosDirNum = DosDirNum;
2e54eb96e   Petr Vandrovec   BKL: Remove BKL f...
796
  				result = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
797
  			} else {
2b0143b5c   David Howells   VFS: normal files...
798
799
  				ncp_dbg(1, "d_inode(sb->s_root) == NULL!
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
800
801
  			}
  		} else {
d3b73ca1b   Joe Perches   ncpfs: convert DP...
802
803
  			ncp_dbg(1, "sb->s_root == NULL!
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
804
  		}
2e54eb96e   Petr Vandrovec   BKL: Remove BKL f...
805
806
  	} else
  		result = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
807
808
809
810
  
  out:
  	return result;
  }
00cd8dd3b   Al Viro   stop passing name...
811
  static struct dentry *ncp_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
812
813
814
815
816
817
  {
  	struct ncp_server *server = NCP_SERVER(dir);
  	struct inode *inode = NULL;
  	struct ncp_entry_info finfo;
  	int error, res, len;
  	__u8 __name[NCP_MAXPATHLEN + 1];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
818
819
820
  	error = -EIO;
  	if (!ncp_conn_valid(server))
  		goto finished;
e45ca8baa   Joe Perches   ncpfs: convert PP...
821
822
  	ncp_vdbg("server lookup for %pd2
  ", dentry);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
823
824
825
826
827
828
829
  
  	len = sizeof(__name);
  	if (ncp_is_server_root(dir)) {
  		res = ncp_io2vol(server, __name, &len, dentry->d_name.name,
  				 dentry->d_name.len, 1);
  		if (!res)
  			res = ncp_lookup_volume(server, __name, &(finfo.i));
ffddc5fd1   Dan Carpenter   fs/ncpfs/dir.c: f...
830
831
  		if (!res)
  			ncp_update_known_namespace(server, finfo.i.volNumber, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
832
833
834
835
836
837
  	} else {
  		res = ncp_io2vol(server, __name, &len, dentry->d_name.name,
  				 dentry->d_name.len, !ncp_preserve_case(dir));
  		if (!res)
  			res = ncp_obtain_info(server, dir, __name, &(finfo.i));
  	}
e45ca8baa   Joe Perches   ncpfs: convert PP...
838
839
  	ncp_vdbg("looked for %pd2, res=%d
  ", dentry, res);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
  	/*
  	 * If we didn't find an entry, make a negative dentry.
  	 */
  	if (res)
  		goto add_entry;
  
  	/*
  	 * Create an inode for the entry.
  	 */
  	finfo.opened = 0;
  	finfo.ino = iunique(dir->i_sb, 2);
  	finfo.volume = finfo.i.volNumber;
  	error = -EACCES;
  	inode = ncp_iget(dir->i_sb, &finfo);
  
  	if (inode) {
  		ncp_new_dentry(dentry);
  add_entry:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
858
859
860
861
862
  		d_add(dentry, inode);
  		error = 0;
  	}
  
  finished:
e45ca8baa   Joe Perches   ncpfs: convert PP...
863
864
  	ncp_vdbg("result=%d
  ", error);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
  	return ERR_PTR(error);
  }
  
  /*
   * This code is common to create, mkdir, and mknod.
   */
  static int ncp_instantiate(struct inode *dir, struct dentry *dentry,
  			struct ncp_entry_info *finfo)
  {
  	struct inode *inode;
  	int error = -EINVAL;
  
  	finfo->ino = iunique(dir->i_sb, 2);
  	inode = ncp_iget(dir->i_sb, finfo);
  	if (!inode)
  		goto out_close;
  	d_instantiate(dentry,inode);
  	error = 0;
  out:
  	return error;
  
  out_close:
e45ca8baa   Joe Perches   ncpfs: convert PP...
887
888
  	ncp_vdbg("%pd2 failed, closing file
  ", dentry);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
889
890
891
  	ncp_close_file(NCP_SERVER(dir), finfo->file_handle);
  	goto out;
  }
5eee25cac   Al Viro   ncpfs: propagate ...
892
  int ncp_create_new(struct inode *dir, struct dentry *dentry, umode_t mode,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
893
894
895
896
897
898
899
900
  		   dev_t rdev, __le32 attributes)
  {
  	struct ncp_server *server = NCP_SERVER(dir);
  	struct ncp_entry_info finfo;
  	int error, result, len;
  	int opmode;
  	__u8 __name[NCP_MAXPATHLEN + 1];
  	
e45ca8baa   Joe Perches   ncpfs: convert PP...
901
902
  	ncp_vdbg("creating %pd2, mode=%hx
  ", dentry, mode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
903

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
  	ncp_age_dentry(server, dentry);
  	len = sizeof(__name);
  	error = ncp_io2vol(server, __name, &len, dentry->d_name.name,
  			   dentry->d_name.len, !ncp_preserve_case(dir));
  	if (error)
  		goto out;
  
  	error = -EACCES;
  	
  	if (S_ISREG(mode) && 
  	    (server->m.flags & NCP_MOUNT_EXTRAS) && 
  	    (mode & S_IXUGO))
  		attributes |= aSYSTEM | aSHARED;
  	
  	result = ncp_open_create_file_or_subdir(server, dir, __name,
  				OC_MODE_CREATE | OC_MODE_OPEN | OC_MODE_REPLACE,
  				attributes, AR_READ | AR_WRITE, &finfo);
  	opmode = O_RDWR;
  	if (result) {
  		result = ncp_open_create_file_or_subdir(server, dir, __name,
  				OC_MODE_CREATE | OC_MODE_OPEN | OC_MODE_REPLACE,
  				attributes, AR_WRITE, &finfo);
  		if (result) {
  			if (result == 0x87)
  				error = -ENAMETOOLONG;
2e54eb96e   Petr Vandrovec   BKL: Remove BKL f...
929
930
  			else if (result < 0)
  				error = result;
d3b73ca1b   Joe Perches   ncpfs: convert DP...
931
932
  			ncp_dbg(1, "%pd2 failed
  ", dentry);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
  			goto out;
  		}
  		opmode = O_WRONLY;
  	}
  	finfo.access = opmode;
  	if (ncp_is_nfs_extras(server, finfo.volume)) {
  		finfo.i.nfs.mode = mode;
  		finfo.i.nfs.rdev = new_encode_dev(rdev);
  		if (ncp_modify_nfs_info(server, finfo.volume,
  					finfo.i.dirEntNum,
  					mode, new_encode_dev(rdev)) != 0)
  			goto out;
  	}
  
  	error = ncp_instantiate(dir, dentry, &finfo);
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
949
950
  	return error;
  }
4acdaf27e   Al Viro   switch ->create()...
951
  static int ncp_create(struct inode *dir, struct dentry *dentry, umode_t mode,
ebfc3b49a   Al Viro   don't pass nameid...
952
  		bool excl)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
953
954
955
  {
  	return ncp_create_new(dir, dentry, mode, 0, 0);
  }
18bb1db3e   Al Viro   switch vfs_mkdir(...
956
  static int ncp_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
957
958
959
960
961
  {
  	struct ncp_entry_info finfo;
  	struct ncp_server *server = NCP_SERVER(dir);
  	int error, len;
  	__u8 __name[NCP_MAXPATHLEN + 1];
d3b73ca1b   Joe Perches   ncpfs: convert DP...
962
963
  	ncp_dbg(1, "making %pd2
  ", dentry);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
964

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
965
966
967
968
969
970
  	ncp_age_dentry(server, dentry);
  	len = sizeof(__name);
  	error = ncp_io2vol(server, __name, &len, dentry->d_name.name,
  			   dentry->d_name.len, !ncp_preserve_case(dir));
  	if (error)
  		goto out;
2e54eb96e   Petr Vandrovec   BKL: Remove BKL f...
971
  	error = ncp_open_create_file_or_subdir(server, dir, __name,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
972
973
  					   OC_MODE_CREATE, aDIR,
  					   cpu_to_le16(0xffff),
2e54eb96e   Petr Vandrovec   BKL: Remove BKL f...
974
975
  					   &finfo);
  	if (error == 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
976
977
978
979
980
981
982
983
984
985
  		if (ncp_is_nfs_extras(server, finfo.volume)) {
  			mode |= S_IFDIR;
  			finfo.i.nfs.mode = mode;
  			if (ncp_modify_nfs_info(server,
  						finfo.volume,
  						finfo.i.dirEntNum,
  						mode, 0) != 0)
  				goto out;
  		}
  		error = ncp_instantiate(dir, dentry, &finfo);
2e54eb96e   Petr Vandrovec   BKL: Remove BKL f...
986
987
  	} else if (error > 0) {
  		error = -EACCES;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
988
989
  	}
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
990
991
992
993
994
995
996
997
  	return error;
  }
  
  static int ncp_rmdir(struct inode *dir, struct dentry *dentry)
  {
  	struct ncp_server *server = NCP_SERVER(dir);
  	int error, result, len;
  	__u8 __name[NCP_MAXPATHLEN + 1];
d3b73ca1b   Joe Perches   ncpfs: convert DP...
998
999
  	ncp_dbg(1, "removing %pd2
  ", dentry);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1000

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
  	len = sizeof(__name);
  	error = ncp_io2vol(server, __name, &len, dentry->d_name.name,
  			   dentry->d_name.len, !ncp_preserve_case(dir));
  	if (error)
  		goto out;
  
  	result = ncp_del_file_or_subdir(server, dir, __name);
  	switch (result) {
  		case 0x00:
  			error = 0;
  			break;
  		case 0x85:	/* unauthorized to delete file */
  		case 0x8A:	/* unauthorized to delete file */
  			error = -EACCES;
  			break;
  		case 0x8F:
  		case 0x90:	/* read only */
  			error = -EPERM;
  			break;
  		case 0x9F:	/* in use by another client */
  			error = -EBUSY;
  			break;
  		case 0xA0:	/* directory not empty */
  			error = -ENOTEMPTY;
  			break;
  		case 0xFF:	/* someone deleted file */
  			error = -ENOENT;
  			break;
  		default:
2e54eb96e   Petr Vandrovec   BKL: Remove BKL f...
1030
  			error = result < 0 ? result : -EACCES;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1031
1032
1033
  			break;
         	}
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1034
1035
1036
1037
1038
  	return error;
  }
  
  static int ncp_unlink(struct inode *dir, struct dentry *dentry)
  {
2b0143b5c   David Howells   VFS: normal files...
1039
  	struct inode *inode = d_inode(dentry);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1040
1041
  	struct ncp_server *server;
  	int error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1042
  	server = NCP_SERVER(dir);
d3b73ca1b   Joe Perches   ncpfs: convert DP...
1043
1044
  	ncp_dbg(1, "unlinking %pd2
  ", dentry);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1045
  	
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1046
1047
1048
1049
  	/*
  	 * Check whether to close the file ...
  	 */
  	if (inode) {
e45ca8baa   Joe Perches   ncpfs: convert PP...
1050
1051
  		ncp_vdbg("closing file
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
  		ncp_make_closed(inode);
  	}
  
  	error = ncp_del_file_or_subdir2(server, dentry);
  #ifdef CONFIG_NCPFS_STRONG
  	/* 9C is Invalid path.. It should be 8F, 90 - read only, but
  	   it is not :-( */
  	if ((error == 0x9C || error == 0x90) && server->m.flags & NCP_MOUNT_STRONG) { /* R/O */
  		error = ncp_force_unlink(dir, dentry);
  	}
  #endif
  	switch (error) {
  		case 0x00:
d3b73ca1b   Joe Perches   ncpfs: convert DP...
1065
1066
  			ncp_dbg(1, "removed %pd2
  ", dentry);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
  			break;
  		case 0x85:
  		case 0x8A:
  			error = -EACCES;
  			break;
  		case 0x8D:	/* some files in use */
  		case 0x8E:	/* all files in use */
  			error = -EBUSY;
  			break;
  		case 0x8F:	/* some read only */
  		case 0x90:	/* all read only */
  		case 0x9C:	/* !!! returned when in-use or read-only by NW4 */
  			error = -EPERM;
  			break;
  		case 0xFF:
  			error = -ENOENT;
  			break;
  		default:
2e54eb96e   Petr Vandrovec   BKL: Remove BKL f...
1085
  			error = error < 0 ? error : -EACCES;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1086
1087
  			break;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1088
1089
1090
1091
  	return error;
  }
  
  static int ncp_rename(struct inode *old_dir, struct dentry *old_dentry,
1cd66c93b   Miklos Szeredi   fs: make remainin...
1092
1093
  		      struct inode *new_dir, struct dentry *new_dentry,
  		      unsigned int flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1094
1095
1096
1097
1098
  {
  	struct ncp_server *server = NCP_SERVER(old_dir);
  	int error;
  	int old_len, new_len;
  	__u8 __old_name[NCP_MAXPATHLEN + 1], __new_name[NCP_MAXPATHLEN + 1];
1cd66c93b   Miklos Szeredi   fs: make remainin...
1099
1100
  	if (flags)
  		return -EINVAL;
d3b73ca1b   Joe Perches   ncpfs: convert DP...
1101
1102
  	ncp_dbg(1, "%pd2 to %pd2
  ", old_dentry, new_dentry);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1103

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
  	ncp_age_dentry(server, old_dentry);
  	ncp_age_dentry(server, new_dentry);
  
  	old_len = sizeof(__old_name);
  	error = ncp_io2vol(server, __old_name, &old_len,
  			   old_dentry->d_name.name, old_dentry->d_name.len,
  			   !ncp_preserve_case(old_dir));
  	if (error)
  		goto out;
  
  	new_len = sizeof(__new_name);
  	error = ncp_io2vol(server, __new_name, &new_len,
  			   new_dentry->d_name.name, new_dentry->d_name.len,
  			   !ncp_preserve_case(new_dir));
  	if (error)
  		goto out;
  
  	error = ncp_ren_or_mov_file_or_subdir(server, old_dir, __old_name,
  						      new_dir, __new_name);
  #ifdef CONFIG_NCPFS_STRONG
  	if ((error == 0x90 || error == 0x8B || error == -EACCES) &&
  			server->m.flags & NCP_MOUNT_STRONG) {	/* RO */
  		error = ncp_force_rename(old_dir, old_dentry, __old_name,
  					 new_dir, new_dentry, __new_name);
  	}
  #endif
  	switch (error) {
  		case 0x00:
d3b73ca1b   Joe Perches   ncpfs: convert DP...
1132
1133
1134
  			ncp_dbg(1, "renamed %pd -> %pd
  ",
  				old_dentry, new_dentry);
3f4a94941   Al Viro   ncpfs: successful...
1135
1136
  			ncp_d_prune(old_dentry);
  			ncp_d_prune(new_dentry);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1137
1138
1139
1140
1141
1142
1143
1144
  			break;
  		case 0x9E:
  			error = -ENAMETOOLONG;
  			break;
  		case 0xFF:
  			error = -ENOENT;
  			break;
  		default:
2e54eb96e   Petr Vandrovec   BKL: Remove BKL f...
1145
  			error = error < 0 ? error : -EACCES;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1146
1147
1148
  			break;
  	}
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1149
1150
1151
1152
  	return error;
  }
  
  static int ncp_mknod(struct inode * dir, struct dentry *dentry,
1a67aafb5   Al Viro   switch ->mknod() ...
1153
  		     umode_t mode, dev_t rdev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1154
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1155
  	if (ncp_is_nfs_extras(NCP_SERVER(dir), NCP_FINFO(dir)->volNumber)) {
d3b73ca1b   Joe Perches   ncpfs: convert DP...
1156
1157
  		ncp_dbg(1, "mode = 0%ho
  ", mode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
  		return ncp_create_new(dir, dentry, mode, rdev, 0);
  	}
  	return -EPERM; /* Strange, but true */
  }
  
  /* The following routines are taken directly from msdos-fs */
  
  /* Linear day numbers of the respective 1sts in non-leap years. */
  
  static int day_n[] =
  {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 0, 0, 0, 0};
  /* Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
  static int utc2local(int time)
  {
  	return time - sys_tz.tz_minuteswest * 60;
  }
  
  static int local2utc(int time)
  {
  	return time + sys_tz.tz_minuteswest * 60;
  }
  
  /* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70). */
  int
  ncp_date_dos2unix(__le16 t, __le16 d)
  {
  	unsigned short time = le16_to_cpu(t), date = le16_to_cpu(d);
  	int month, year, secs;
  
  	/* first subtract and mask after that... Otherwise, if
  	   date == 0, bad things happen */
  	month = ((date >> 5) - 1) & 15;
  	year = date >> 9;
  	secs = (time & 31) * 2 + 60 * ((time >> 5) & 63) + (time >> 11) * 3600 +
  		86400 * ((date & 31) - 1 + day_n[month] + (year / 4) + 
  		year * 365 - ((year & 3) == 0 && month < 2 ? 1 : 0) + 3653);
  	/* days since 1.1.70 plus 80's leap day */
  	return local2utc(secs);
  }
  
  
  /* Convert linear UNIX date to a MS-DOS time/date pair. */
  void
  ncp_date_unix2dos(int unix_date, __le16 *time, __le16 *date)
  {
  	int day, year, nl_day, month;
  
  	unix_date = utc2local(unix_date);
  	*time = cpu_to_le16(
  		(unix_date % 60) / 2 + (((unix_date / 60) % 60) << 5) +
  		(((unix_date / 3600) % 24) << 11));
  	day = unix_date / 86400 - 3652;
  	year = day / 365;
  	if ((year + 3) / 4 + 365 * year > day)
  		year--;
  	day -= (year + 3) / 4 + 365 * year;
  	if (day == 59 && !(year & 3)) {
  		nl_day = day;
  		month = 2;
  	} else {
  		nl_day = (year & 3) || day <= 59 ? day : day - 1;
c5df59136   Roel Kluin   ncpfs: read buffe...
1219
  		for (month = 1; month < 12; month++)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1220
1221
1222
1223
1224
  			if (day_n[month] > nl_day)
  				break;
  	}
  	*date = cpu_to_le16(nl_day - day_n[month - 1] + 1 + (month << 5) + (year << 9));
  }