1 /*
2  *  dir.c
3  *
4  *  Copyright (C) 1995, 1996 by Volker Lendecke
5  *  Modified for big endian by J.F. Chadima and David S. Miller
6  *  Modified 1997 Peter Waltenberg, Bill Hawes, David Woodhouse for 2.1 dcache
7  *  Modified 1998, 1999 Wolfram Pienkoss for NLS
8  *  Modified 1999 Wolfram Pienkoss for directory caching
9  *  Modified 2000 Ben Harris, University of Cambridge for NFS NS meta-info
10  *
11  */
12 
13 
14 #include <linux/time.h>
15 #include <linux/errno.h>
16 #include <linux/stat.h>
17 #include <linux/kernel.h>
18 #include <linux/vmalloc.h>
19 #include <linux/mm.h>
20 #include <linux/namei.h>
21 #include <asm/uaccess.h>
22 #include <asm/byteorder.h>
23 
24 #include "ncp_fs.h"
25 
26 static void ncp_read_volume_list(struct file *, struct dir_context *,
27 				struct ncp_cache_control *);
28 static void ncp_do_readdir(struct file *, struct dir_context *,
29 				struct ncp_cache_control *);
30 
31 static int ncp_readdir(struct file *, struct dir_context *);
32 
33 static int ncp_create(struct inode *, struct dentry *, umode_t, bool);
34 static struct dentry *ncp_lookup(struct inode *, struct dentry *, unsigned int);
35 static int ncp_unlink(struct inode *, struct dentry *);
36 static int ncp_mkdir(struct inode *, struct dentry *, umode_t);
37 static int ncp_rmdir(struct inode *, struct dentry *);
38 static int ncp_rename(struct inode *, struct dentry *,
39 	  	      struct inode *, struct dentry *);
40 static int ncp_mknod(struct inode * dir, struct dentry *dentry,
41 		     umode_t mode, dev_t rdev);
42 #if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS)
43 extern int ncp_symlink(struct inode *, struct dentry *, const char *);
44 #else
45 #define ncp_symlink NULL
46 #endif
47 
48 const struct file_operations ncp_dir_operations =
49 {
50 	.llseek		= generic_file_llseek,
51 	.read		= generic_read_dir,
52 	.iterate	= ncp_readdir,
53 	.unlocked_ioctl	= ncp_ioctl,
54 #ifdef CONFIG_COMPAT
55 	.compat_ioctl	= ncp_compat_ioctl,
56 #endif
57 };
58 
59 const struct inode_operations ncp_dir_inode_operations =
60 {
61 	.create		= ncp_create,
62 	.lookup		= ncp_lookup,
63 	.unlink		= ncp_unlink,
64 	.symlink	= ncp_symlink,
65 	.mkdir		= ncp_mkdir,
66 	.rmdir		= ncp_rmdir,
67 	.mknod		= ncp_mknod,
68 	.rename		= ncp_rename,
69 	.setattr	= ncp_notify_change,
70 };
71 
72 /*
73  * Dentry operations routines
74  */
75 static int ncp_lookup_validate(struct dentry *, unsigned int);
76 static int ncp_hash_dentry(const struct dentry *, struct qstr *);
77 static int ncp_compare_dentry(const struct dentry *, const struct dentry *,
78 		unsigned int, const char *, const struct qstr *);
79 static int ncp_delete_dentry(const struct dentry *);
80 static void ncp_d_prune(struct dentry *dentry);
81 
82 const struct dentry_operations ncp_dentry_operations =
83 {
84 	.d_revalidate	= ncp_lookup_validate,
85 	.d_hash		= ncp_hash_dentry,
86 	.d_compare	= ncp_compare_dentry,
87 	.d_delete	= ncp_delete_dentry,
88 	.d_prune	= ncp_d_prune,
89 };
90 
91 #define ncp_namespace(i)	(NCP_SERVER(i)->name_space[NCP_FINFO(i)->volNumber])
92 
ncp_preserve_entry_case(struct inode * i,__u32 nscreator)93 static inline int ncp_preserve_entry_case(struct inode *i, __u32 nscreator)
94 {
95 #ifdef CONFIG_NCPFS_SMALLDOS
96 	int ns = ncp_namespace(i);
97 
98 	if ((ns == NW_NS_DOS)
99 #ifdef CONFIG_NCPFS_OS2_NS
100 		|| ((ns == NW_NS_OS2) && (nscreator == NW_NS_DOS))
101 #endif /* CONFIG_NCPFS_OS2_NS */
102 	   )
103 		return 0;
104 #endif /* CONFIG_NCPFS_SMALLDOS */
105 	return 1;
106 }
107 
108 #define ncp_preserve_case(i)	(ncp_namespace(i) != NW_NS_DOS)
109 
ncp_case_sensitive(const struct inode * i)110 static inline int ncp_case_sensitive(const struct inode *i)
111 {
112 #ifdef CONFIG_NCPFS_NFS_NS
113 	return ncp_namespace(i) == NW_NS_NFS;
114 #else
115 	return 0;
116 #endif /* CONFIG_NCPFS_NFS_NS */
117 }
118 
119 /*
120  * Note: leave the hash unchanged if the directory
121  * is case-sensitive.
122  *
123  * Accessing the parent inode can be racy under RCU pathwalking.
124  * Use ACCESS_ONCE() to make sure we use _one_ particular inode,
125  * the callers will handle races.
126  */
127 static int
ncp_hash_dentry(const struct dentry * dentry,struct qstr * this)128 ncp_hash_dentry(const struct dentry *dentry, struct qstr *this)
129 {
130 	struct inode *inode = d_inode_rcu(dentry);
131 
132 	if (!inode)
133 		return 0;
134 
135 	if (!ncp_case_sensitive(inode)) {
136 		struct super_block *sb = dentry->d_sb;
137 		struct nls_table *t;
138 		unsigned long hash;
139 		int i;
140 
141 		t = NCP_IO_TABLE(sb);
142 		hash = init_name_hash();
143 		for (i=0; i<this->len ; i++)
144 			hash = partial_name_hash(ncp_tolower(t, this->name[i]),
145 									hash);
146 		this->hash = end_name_hash(hash);
147 	}
148 	return 0;
149 }
150 
151 /*
152  * Accessing the parent inode can be racy under RCU pathwalking.
153  * Use ACCESS_ONCE() to make sure we use _one_ particular inode,
154  * the callers will handle races.
155  */
156 static int
ncp_compare_dentry(const struct dentry * parent,const struct dentry * dentry,unsigned int len,const char * str,const struct qstr * name)157 ncp_compare_dentry(const struct dentry *parent, const struct dentry *dentry,
158 		unsigned int len, const char *str, const struct qstr *name)
159 {
160 	struct inode *pinode;
161 
162 	if (len != name->len)
163 		return 1;
164 
165 	pinode = d_inode_rcu(parent);
166 	if (!pinode)
167 		return 1;
168 
169 	if (ncp_case_sensitive(pinode))
170 		return strncmp(str, name->name, len);
171 
172 	return ncp_strnicmp(NCP_IO_TABLE(pinode->i_sb), str, name->name, len);
173 }
174 
175 /*
176  * This is the callback from dput() when d_count is going to 0.
177  * We use this to unhash dentries with bad inodes.
178  * Closing files can be safely postponed until iput() - it's done there anyway.
179  */
180 static int
ncp_delete_dentry(const struct dentry * dentry)181 ncp_delete_dentry(const struct dentry * dentry)
182 {
183 	struct inode *inode = d_inode(dentry);
184 
185 	if (inode) {
186 		if (is_bad_inode(inode))
187 			return 1;
188 	} else
189 	{
190 	/* N.B. Unhash negative dentries? */
191 	}
192 	return 0;
193 }
194 
195 static inline int
ncp_single_volume(struct ncp_server * server)196 ncp_single_volume(struct ncp_server *server)
197 {
198 	return (server->m.mounted_vol[0] != '\0');
199 }
200 
ncp_is_server_root(struct inode * inode)201 static inline int ncp_is_server_root(struct inode *inode)
202 {
203 	return !ncp_single_volume(NCP_SERVER(inode)) &&
204 		is_root_inode(inode);
205 }
206 
207 
208 /*
209  * This is the callback when the dcache has a lookup hit.
210  */
211 
212 
213 #ifdef CONFIG_NCPFS_STRONG
214 /* try to delete a readonly file (NW R bit set) */
215 
216 static int
ncp_force_unlink(struct inode * dir,struct dentry * dentry)217 ncp_force_unlink(struct inode *dir, struct dentry* dentry)
218 {
219         int res=0x9c,res2;
220 	struct nw_modify_dos_info info;
221 	__le32 old_nwattr;
222 	struct inode *inode;
223 
224 	memset(&info, 0, sizeof(info));
225 
226         /* remove the Read-Only flag on the NW server */
227 	inode = d_inode(dentry);
228 
229 	old_nwattr = NCP_FINFO(inode)->nwattr;
230 	info.attributes = old_nwattr & ~(aRONLY|aDELETEINHIBIT|aRENAMEINHIBIT);
231 	res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(inode), inode, NULL, DM_ATTRIBUTES, &info);
232 	if (res2)
233 		goto leave_me;
234 
235         /* now try again the delete operation */
236         res = ncp_del_file_or_subdir2(NCP_SERVER(dir), dentry);
237 
238         if (res)  /* delete failed, set R bit again */
239         {
240 		info.attributes = old_nwattr;
241 		res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(inode), inode, NULL, DM_ATTRIBUTES, &info);
242 		if (res2)
243                         goto leave_me;
244         }
245 leave_me:
246         return(res);
247 }
248 #endif	/* CONFIG_NCPFS_STRONG */
249 
250 #ifdef CONFIG_NCPFS_STRONG
251 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)252 ncp_force_rename(struct inode *old_dir, struct dentry* old_dentry, char *_old_name,
253                  struct inode *new_dir, struct dentry* new_dentry, char *_new_name)
254 {
255 	struct nw_modify_dos_info info;
256         int res=0x90,res2;
257 	struct inode *old_inode = d_inode(old_dentry);
258 	__le32 old_nwattr = NCP_FINFO(old_inode)->nwattr;
259 	__le32 new_nwattr = 0; /* shut compiler warning */
260 	int old_nwattr_changed = 0;
261 	int new_nwattr_changed = 0;
262 
263 	memset(&info, 0, sizeof(info));
264 
265         /* remove the Read-Only flag on the NW server */
266 
267 	info.attributes = old_nwattr & ~(aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
268 	res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(old_inode), old_inode, NULL, DM_ATTRIBUTES, &info);
269 	if (!res2)
270 		old_nwattr_changed = 1;
271 	if (new_dentry && d_really_is_positive(new_dentry)) {
272 		new_nwattr = NCP_FINFO(d_inode(new_dentry))->nwattr;
273 		info.attributes = new_nwattr & ~(aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
274 		res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(new_dir), new_dir, _new_name, DM_ATTRIBUTES, &info);
275 		if (!res2)
276 			new_nwattr_changed = 1;
277 	}
278         /* now try again the rename operation */
279 	/* but only if something really happened */
280 	if (new_nwattr_changed || old_nwattr_changed) {
281 	        res = ncp_ren_or_mov_file_or_subdir(NCP_SERVER(old_dir),
282         	                                    old_dir, _old_name,
283                 	                            new_dir, _new_name);
284 	}
285 	if (res)
286 		goto leave_me;
287 	/* file was successfully renamed, so:
288 	   do not set attributes on old file - it no longer exists
289 	   copy attributes from old file to new */
290 	new_nwattr_changed = old_nwattr_changed;
291 	new_nwattr = old_nwattr;
292 	old_nwattr_changed = 0;
293 
294 leave_me:;
295 	if (old_nwattr_changed) {
296 		info.attributes = old_nwattr;
297 		res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(old_inode), old_inode, NULL, DM_ATTRIBUTES, &info);
298 		/* ignore errors */
299 	}
300 	if (new_nwattr_changed)	{
301 		info.attributes = new_nwattr;
302 		res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(new_dir), new_dir, _new_name, DM_ATTRIBUTES, &info);
303 		/* ignore errors */
304 	}
305         return(res);
306 }
307 #endif	/* CONFIG_NCPFS_STRONG */
308 
309 
310 static int
ncp_lookup_validate(struct dentry * dentry,unsigned int flags)311 ncp_lookup_validate(struct dentry *dentry, unsigned int flags)
312 {
313 	struct ncp_server *server;
314 	struct dentry *parent;
315 	struct inode *dir;
316 	struct ncp_entry_info finfo;
317 	int res, val = 0, len;
318 	__u8 __name[NCP_MAXPATHLEN + 1];
319 
320 	if (dentry == dentry->d_sb->s_root)
321 		return 1;
322 
323 	if (flags & LOOKUP_RCU)
324 		return -ECHILD;
325 
326 	parent = dget_parent(dentry);
327 	dir = d_inode(parent);
328 
329 	if (d_really_is_negative(dentry))
330 		goto finished;
331 
332 	server = NCP_SERVER(dir);
333 
334 	/*
335 	 * Inspired by smbfs:
336 	 * The default validation is based on dentry age:
337 	 * We set the max age at mount time.  (But each
338 	 * successful server lookup renews the timestamp.)
339 	 */
340 	val = NCP_TEST_AGE(server, dentry);
341 	if (val)
342 		goto finished;
343 
344 	ncp_dbg(2, "%pd2 not valid, age=%ld, server lookup\n",
345 		dentry, NCP_GET_AGE(dentry));
346 
347 	len = sizeof(__name);
348 	if (ncp_is_server_root(dir)) {
349 		res = ncp_io2vol(server, __name, &len, dentry->d_name.name,
350 				 dentry->d_name.len, 1);
351 		if (!res) {
352 			res = ncp_lookup_volume(server, __name, &(finfo.i));
353 			if (!res)
354 				ncp_update_known_namespace(server, finfo.i.volNumber, NULL);
355 		}
356 	} else {
357 		res = ncp_io2vol(server, __name, &len, dentry->d_name.name,
358 				 dentry->d_name.len, !ncp_preserve_case(dir));
359 		if (!res)
360 			res = ncp_obtain_info(server, dir, __name, &(finfo.i));
361 	}
362 	finfo.volume = finfo.i.volNumber;
363 	ncp_dbg(2, "looked for %pd/%s, res=%d\n",
364 		dentry->d_parent, __name, res);
365 	/*
366 	 * If we didn't find it, or if it has a different dirEntNum to
367 	 * what we remember, it's not valid any more.
368 	 */
369 	if (!res) {
370 		struct inode *inode = d_inode(dentry);
371 
372 		mutex_lock(&inode->i_mutex);
373 		if (finfo.i.dirEntNum == NCP_FINFO(inode)->dirEntNum) {
374 			ncp_new_dentry(dentry);
375 			val=1;
376 		} else
377 			ncp_dbg(2, "found, but dirEntNum changed\n");
378 
379 		ncp_update_inode2(inode, &finfo);
380 		mutex_unlock(&inode->i_mutex);
381 	}
382 
383 finished:
384 	ncp_dbg(2, "result=%d\n", val);
385 	dput(parent);
386 	return val;
387 }
388 
ncp_obtain_mtime(struct dentry * dentry)389 static time_t ncp_obtain_mtime(struct dentry *dentry)
390 {
391 	struct inode *inode = d_inode(dentry);
392 	struct ncp_server *server = NCP_SERVER(inode);
393 	struct nw_info_struct i;
394 
395 	if (!ncp_conn_valid(server) || ncp_is_server_root(inode))
396 		return 0;
397 
398 	if (ncp_obtain_info(server, inode, NULL, &i))
399 		return 0;
400 
401 	return ncp_date_dos2unix(i.modifyTime, i.modifyDate);
402 }
403 
404 static inline void
ncp_invalidate_dircache_entries(struct dentry * parent)405 ncp_invalidate_dircache_entries(struct dentry *parent)
406 {
407 	struct ncp_server *server = NCP_SERVER(d_inode(parent));
408 	struct dentry *dentry;
409 
410 	spin_lock(&parent->d_lock);
411 	list_for_each_entry(dentry, &parent->d_subdirs, d_child) {
412 		dentry->d_fsdata = NULL;
413 		ncp_age_dentry(server, dentry);
414 	}
415 	spin_unlock(&parent->d_lock);
416 }
417 
ncp_readdir(struct file * file,struct dir_context * ctx)418 static int ncp_readdir(struct file *file, struct dir_context *ctx)
419 {
420 	struct dentry *dentry = file->f_path.dentry;
421 	struct inode *inode = d_inode(dentry);
422 	struct page *page = NULL;
423 	struct ncp_server *server = NCP_SERVER(inode);
424 	union  ncp_dir_cache *cache = NULL;
425 	struct ncp_cache_control ctl;
426 	int result, mtime_valid = 0;
427 	time_t mtime = 0;
428 
429 	ctl.page  = NULL;
430 	ctl.cache = NULL;
431 
432 	ncp_dbg(2, "reading %pD2, pos=%d\n", file, (int)ctx->pos);
433 
434 	result = -EIO;
435 	/* Do not generate '.' and '..' when server is dead. */
436 	if (!ncp_conn_valid(server))
437 		goto out;
438 
439 	result = 0;
440 	if (!dir_emit_dots(file, ctx))
441 		goto out;
442 
443 	page = grab_cache_page(&inode->i_data, 0);
444 	if (!page)
445 		goto read_really;
446 
447 	ctl.cache = cache = kmap(page);
448 	ctl.head  = cache->head;
449 
450 	if (!PageUptodate(page) || !ctl.head.eof)
451 		goto init_cache;
452 
453 	if (ctx->pos == 2) {
454 		if (jiffies - ctl.head.time >= NCP_MAX_AGE(server))
455 			goto init_cache;
456 
457 		mtime = ncp_obtain_mtime(dentry);
458 		mtime_valid = 1;
459 		if ((!mtime) || (mtime != ctl.head.mtime))
460 			goto init_cache;
461 	}
462 
463 	if (ctx->pos > ctl.head.end)
464 		goto finished;
465 
466 	ctl.fpos = ctx->pos + (NCP_DIRCACHE_START - 2);
467 	ctl.ofs  = ctl.fpos / NCP_DIRCACHE_SIZE;
468 	ctl.idx  = ctl.fpos % NCP_DIRCACHE_SIZE;
469 
470 	for (;;) {
471 		if (ctl.ofs != 0) {
472 			ctl.page = find_lock_page(&inode->i_data, ctl.ofs);
473 			if (!ctl.page)
474 				goto invalid_cache;
475 			ctl.cache = kmap(ctl.page);
476 			if (!PageUptodate(ctl.page))
477 				goto invalid_cache;
478 		}
479 		while (ctl.idx < NCP_DIRCACHE_SIZE) {
480 			struct dentry *dent;
481 			bool over;
482 
483 			spin_lock(&dentry->d_lock);
484 			if (!(NCP_FINFO(inode)->flags & NCPI_DIR_CACHE)) {
485 				spin_unlock(&dentry->d_lock);
486 				goto invalid_cache;
487 			}
488 			dent = ctl.cache->dentry[ctl.idx];
489 			if (unlikely(!lockref_get_not_dead(&dent->d_lockref))) {
490 				spin_unlock(&dentry->d_lock);
491 				goto invalid_cache;
492 			}
493 			spin_unlock(&dentry->d_lock);
494 			if (d_really_is_negative(dent)) {
495 				dput(dent);
496 				goto invalid_cache;
497 			}
498 			over = !dir_emit(ctx, dent->d_name.name,
499 					dent->d_name.len,
500 					d_inode(dent)->i_ino, DT_UNKNOWN);
501 			dput(dent);
502 			if (over)
503 				goto finished;
504 			ctx->pos += 1;
505 			ctl.idx += 1;
506 			if (ctx->pos > ctl.head.end)
507 				goto finished;
508 		}
509 		if (ctl.page) {
510 			kunmap(ctl.page);
511 			SetPageUptodate(ctl.page);
512 			unlock_page(ctl.page);
513 			page_cache_release(ctl.page);
514 			ctl.page = NULL;
515 		}
516 		ctl.idx  = 0;
517 		ctl.ofs += 1;
518 	}
519 invalid_cache:
520 	if (ctl.page) {
521 		kunmap(ctl.page);
522 		unlock_page(ctl.page);
523 		page_cache_release(ctl.page);
524 		ctl.page = NULL;
525 	}
526 	ctl.cache = cache;
527 init_cache:
528 	ncp_invalidate_dircache_entries(dentry);
529 	if (!mtime_valid) {
530 		mtime = ncp_obtain_mtime(dentry);
531 		mtime_valid = 1;
532 	}
533 	ctl.head.mtime = mtime;
534 	ctl.head.time = jiffies;
535 	ctl.head.eof = 0;
536 	ctl.fpos = 2;
537 	ctl.ofs = 0;
538 	ctl.idx = NCP_DIRCACHE_START;
539 	ctl.filled = 0;
540 	ctl.valid  = 1;
541 read_really:
542 	spin_lock(&dentry->d_lock);
543 	NCP_FINFO(inode)->flags |= NCPI_DIR_CACHE;
544 	spin_unlock(&dentry->d_lock);
545 	if (ncp_is_server_root(inode)) {
546 		ncp_read_volume_list(file, ctx, &ctl);
547 	} else {
548 		ncp_do_readdir(file, ctx, &ctl);
549 	}
550 	ctl.head.end = ctl.fpos - 1;
551 	ctl.head.eof = ctl.valid;
552 finished:
553 	if (ctl.page) {
554 		kunmap(ctl.page);
555 		SetPageUptodate(ctl.page);
556 		unlock_page(ctl.page);
557 		page_cache_release(ctl.page);
558 	}
559 	if (page) {
560 		cache->head = ctl.head;
561 		kunmap(page);
562 		SetPageUptodate(page);
563 		unlock_page(page);
564 		page_cache_release(page);
565 	}
566 out:
567 	return result;
568 }
569 
ncp_d_prune(struct dentry * dentry)570 static void ncp_d_prune(struct dentry *dentry)
571 {
572 	if (!dentry->d_fsdata)	/* not referenced from page cache */
573 		return;
574 	NCP_FINFO(d_inode(dentry->d_parent))->flags &= ~NCPI_DIR_CACHE;
575 }
576 
577 static int
ncp_fill_cache(struct file * file,struct dir_context * ctx,struct ncp_cache_control * ctrl,struct ncp_entry_info * entry,int inval_childs)578 ncp_fill_cache(struct file *file, struct dir_context *ctx,
579 		struct ncp_cache_control *ctrl, struct ncp_entry_info *entry,
580 		int inval_childs)
581 {
582 	struct dentry *newdent, *dentry = file->f_path.dentry;
583 	struct inode *dir = d_inode(dentry);
584 	struct ncp_cache_control ctl = *ctrl;
585 	struct qstr qname;
586 	int valid = 0;
587 	int hashed = 0;
588 	ino_t ino = 0;
589 	__u8 __name[NCP_MAXPATHLEN + 1];
590 
591 	qname.len = sizeof(__name);
592 	if (ncp_vol2io(NCP_SERVER(dir), __name, &qname.len,
593 			entry->i.entryName, entry->i.nameLen,
594 			!ncp_preserve_entry_case(dir, entry->i.NSCreator)))
595 		return 1; /* I'm not sure */
596 
597 	qname.name = __name;
598 
599 	newdent = d_hash_and_lookup(dentry, &qname);
600 	if (unlikely(IS_ERR(newdent)))
601 		goto end_advance;
602 	if (!newdent) {
603 		newdent = d_alloc(dentry, &qname);
604 		if (!newdent)
605 			goto end_advance;
606 	} else {
607 		hashed = 1;
608 
609 		/* If case sensitivity changed for this volume, all entries below this one
610 		   should be thrown away.  This entry itself is not affected, as its case
611 		   sensitivity is controlled by its own parent. */
612 		if (inval_childs)
613 			shrink_dcache_parent(newdent);
614 
615 		/*
616 		 * NetWare's OS2 namespace is case preserving yet case
617 		 * insensitive.  So we update dentry's name as received from
618 		 * server. Parent dir's i_mutex is locked because we're in
619 		 * readdir.
620 		 */
621 		dentry_update_name_case(newdent, &qname);
622 	}
623 
624 	if (d_really_is_negative(newdent)) {
625 		struct inode *inode;
626 
627 		entry->opened = 0;
628 		entry->ino = iunique(dir->i_sb, 2);
629 		inode = ncp_iget(dir->i_sb, entry);
630 		if (inode) {
631 			d_instantiate(newdent, inode);
632 			if (!hashed)
633 				d_rehash(newdent);
634 		} else {
635 			spin_lock(&dentry->d_lock);
636 			NCP_FINFO(dir)->flags &= ~NCPI_DIR_CACHE;
637 			spin_unlock(&dentry->d_lock);
638 		}
639 	} else {
640 		struct inode *inode = d_inode(newdent);
641 
642 		mutex_lock_nested(&inode->i_mutex, I_MUTEX_CHILD);
643 		ncp_update_inode2(inode, entry);
644 		mutex_unlock(&inode->i_mutex);
645 	}
646 
647 	if (ctl.idx >= NCP_DIRCACHE_SIZE) {
648 		if (ctl.page) {
649 			kunmap(ctl.page);
650 			SetPageUptodate(ctl.page);
651 			unlock_page(ctl.page);
652 			page_cache_release(ctl.page);
653 		}
654 		ctl.cache = NULL;
655 		ctl.idx  -= NCP_DIRCACHE_SIZE;
656 		ctl.ofs  += 1;
657 		ctl.page  = grab_cache_page(&dir->i_data, ctl.ofs);
658 		if (ctl.page)
659 			ctl.cache = kmap(ctl.page);
660 	}
661 	if (ctl.cache) {
662 		if (d_really_is_positive(newdent)) {
663 			newdent->d_fsdata = newdent;
664 			ctl.cache->dentry[ctl.idx] = newdent;
665 			ino = d_inode(newdent)->i_ino;
666 			ncp_new_dentry(newdent);
667 		}
668  		valid = 1;
669 	}
670 	dput(newdent);
671 end_advance:
672 	if (!valid)
673 		ctl.valid = 0;
674 	if (!ctl.filled && (ctl.fpos == ctx->pos)) {
675 		if (!ino)
676 			ino = iunique(dir->i_sb, 2);
677 		ctl.filled = !dir_emit(ctx, qname.name, qname.len,
678 				     ino, DT_UNKNOWN);
679 		if (!ctl.filled)
680 			ctx->pos += 1;
681 	}
682 	ctl.fpos += 1;
683 	ctl.idx  += 1;
684 	*ctrl = ctl;
685 	return (ctl.valid || !ctl.filled);
686 }
687 
688 static void
ncp_read_volume_list(struct file * file,struct dir_context * ctx,struct ncp_cache_control * ctl)689 ncp_read_volume_list(struct file *file, struct dir_context *ctx,
690 			struct ncp_cache_control *ctl)
691 {
692 	struct inode *inode = file_inode(file);
693 	struct ncp_server *server = NCP_SERVER(inode);
694 	struct ncp_volume_info info;
695 	struct ncp_entry_info entry;
696 	int i;
697 
698 	ncp_dbg(1, "pos=%ld\n", (unsigned long)ctx->pos);
699 
700 	for (i = 0; i < NCP_NUMBER_OF_VOLUMES; i++) {
701 		int inval_dentry;
702 
703 		if (ncp_get_volume_info_with_number(server, i, &info) != 0)
704 			return;
705 		if (!strlen(info.volume_name))
706 			continue;
707 
708 		ncp_dbg(1, "found vol: %s\n", info.volume_name);
709 
710 		if (ncp_lookup_volume(server, info.volume_name,
711 					&entry.i)) {
712 			ncp_dbg(1, "could not lookup vol %s\n",
713 				info.volume_name);
714 			continue;
715 		}
716 		inval_dentry = ncp_update_known_namespace(server, entry.i.volNumber, NULL);
717 		entry.volume = entry.i.volNumber;
718 		if (!ncp_fill_cache(file, ctx, ctl, &entry, inval_dentry))
719 			return;
720 	}
721 }
722 
723 static void
ncp_do_readdir(struct file * file,struct dir_context * ctx,struct ncp_cache_control * ctl)724 ncp_do_readdir(struct file *file, struct dir_context *ctx,
725 						struct ncp_cache_control *ctl)
726 {
727 	struct inode *dir = file_inode(file);
728 	struct ncp_server *server = NCP_SERVER(dir);
729 	struct nw_search_sequence seq;
730 	struct ncp_entry_info entry;
731 	int err;
732 	void* buf;
733 	int more;
734 	size_t bufsize;
735 
736 	ncp_dbg(1, "%pD2, fpos=%ld\n", file, (unsigned long)ctx->pos);
737 	ncp_vdbg("init %pD, volnum=%d, dirent=%u\n",
738 		 file, NCP_FINFO(dir)->volNumber, NCP_FINFO(dir)->dirEntNum);
739 
740 	err = ncp_initialize_search(server, dir, &seq);
741 	if (err) {
742 		ncp_dbg(1, "init failed, err=%d\n", err);
743 		return;
744 	}
745 	/* We MUST NOT use server->buffer_size handshaked with server if we are
746 	   using UDP, as for UDP server uses max. buffer size determined by
747 	   MTU, and for TCP server uses hardwired value 65KB (== 66560 bytes).
748 	   So we use 128KB, just to be sure, as there is no way how to know
749 	   this value in advance. */
750 	bufsize = 131072;
751 	buf = vmalloc(bufsize);
752 	if (!buf)
753 		return;
754 	do {
755 		int cnt;
756 		char* rpl;
757 		size_t rpls;
758 
759 		err = ncp_search_for_fileset(server, &seq, &more, &cnt, buf, bufsize, &rpl, &rpls);
760 		if (err)		/* Error */
761 			break;
762 		if (!cnt)		/* prevent endless loop */
763 			break;
764 		while (cnt--) {
765 			size_t onerpl;
766 
767 			if (rpls < offsetof(struct nw_info_struct, entryName))
768 				break;	/* short packet */
769 			ncp_extract_file_info(rpl, &entry.i);
770 			onerpl = offsetof(struct nw_info_struct, entryName) + entry.i.nameLen;
771 			if (rpls < onerpl)
772 				break;	/* short packet */
773 			(void)ncp_obtain_nfs_info(server, &entry.i);
774 			rpl += onerpl;
775 			rpls -= onerpl;
776 			entry.volume = entry.i.volNumber;
777 			if (!ncp_fill_cache(file, ctx, ctl, &entry, 0))
778 				break;
779 		}
780 	} while (more);
781 	vfree(buf);
782 	return;
783 }
784 
ncp_conn_logged_in(struct super_block * sb)785 int ncp_conn_logged_in(struct super_block *sb)
786 {
787 	struct ncp_server* server = NCP_SBP(sb);
788 	int result;
789 
790 	if (ncp_single_volume(server)) {
791 		int len;
792 		struct dentry* dent;
793 		__u32 volNumber;
794 		__le32 dirEntNum;
795 		__le32 DosDirNum;
796 		__u8 __name[NCP_MAXPATHLEN + 1];
797 
798 		len = sizeof(__name);
799 		result = ncp_io2vol(server, __name, &len, server->m.mounted_vol,
800 				    strlen(server->m.mounted_vol), 1);
801 		if (result)
802 			goto out;
803 		result = -ENOENT;
804 		if (ncp_get_volume_root(server, __name, &volNumber, &dirEntNum, &DosDirNum)) {
805 			ncp_vdbg("%s not found\n", server->m.mounted_vol);
806 			goto out;
807 		}
808 		dent = sb->s_root;
809 		if (dent) {
810 			struct inode* ino = d_inode(dent);
811 			if (ino) {
812 				ncp_update_known_namespace(server, volNumber, NULL);
813 				NCP_FINFO(ino)->volNumber = volNumber;
814 				NCP_FINFO(ino)->dirEntNum = dirEntNum;
815 				NCP_FINFO(ino)->DosDirNum = DosDirNum;
816 				result = 0;
817 			} else {
818 				ncp_dbg(1, "d_inode(sb->s_root) == NULL!\n");
819 			}
820 		} else {
821 			ncp_dbg(1, "sb->s_root == NULL!\n");
822 		}
823 	} else
824 		result = 0;
825 
826 out:
827 	return result;
828 }
829 
ncp_lookup(struct inode * dir,struct dentry * dentry,unsigned int flags)830 static struct dentry *ncp_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
831 {
832 	struct ncp_server *server = NCP_SERVER(dir);
833 	struct inode *inode = NULL;
834 	struct ncp_entry_info finfo;
835 	int error, res, len;
836 	__u8 __name[NCP_MAXPATHLEN + 1];
837 
838 	error = -EIO;
839 	if (!ncp_conn_valid(server))
840 		goto finished;
841 
842 	ncp_vdbg("server lookup for %pd2\n", dentry);
843 
844 	len = sizeof(__name);
845 	if (ncp_is_server_root(dir)) {
846 		res = ncp_io2vol(server, __name, &len, dentry->d_name.name,
847 				 dentry->d_name.len, 1);
848 		if (!res)
849 			res = ncp_lookup_volume(server, __name, &(finfo.i));
850 		if (!res)
851 			ncp_update_known_namespace(server, finfo.i.volNumber, NULL);
852 	} else {
853 		res = ncp_io2vol(server, __name, &len, dentry->d_name.name,
854 				 dentry->d_name.len, !ncp_preserve_case(dir));
855 		if (!res)
856 			res = ncp_obtain_info(server, dir, __name, &(finfo.i));
857 	}
858 	ncp_vdbg("looked for %pd2, res=%d\n", dentry, res);
859 	/*
860 	 * If we didn't find an entry, make a negative dentry.
861 	 */
862 	if (res)
863 		goto add_entry;
864 
865 	/*
866 	 * Create an inode for the entry.
867 	 */
868 	finfo.opened = 0;
869 	finfo.ino = iunique(dir->i_sb, 2);
870 	finfo.volume = finfo.i.volNumber;
871 	error = -EACCES;
872 	inode = ncp_iget(dir->i_sb, &finfo);
873 
874 	if (inode) {
875 		ncp_new_dentry(dentry);
876 add_entry:
877 		d_add(dentry, inode);
878 		error = 0;
879 	}
880 
881 finished:
882 	ncp_vdbg("result=%d\n", error);
883 	return ERR_PTR(error);
884 }
885 
886 /*
887  * This code is common to create, mkdir, and mknod.
888  */
ncp_instantiate(struct inode * dir,struct dentry * dentry,struct ncp_entry_info * finfo)889 static int ncp_instantiate(struct inode *dir, struct dentry *dentry,
890 			struct ncp_entry_info *finfo)
891 {
892 	struct inode *inode;
893 	int error = -EINVAL;
894 
895 	finfo->ino = iunique(dir->i_sb, 2);
896 	inode = ncp_iget(dir->i_sb, finfo);
897 	if (!inode)
898 		goto out_close;
899 	d_instantiate(dentry,inode);
900 	error = 0;
901 out:
902 	return error;
903 
904 out_close:
905 	ncp_vdbg("%pd2 failed, closing file\n", dentry);
906 	ncp_close_file(NCP_SERVER(dir), finfo->file_handle);
907 	goto out;
908 }
909 
ncp_create_new(struct inode * dir,struct dentry * dentry,umode_t mode,dev_t rdev,__le32 attributes)910 int ncp_create_new(struct inode *dir, struct dentry *dentry, umode_t mode,
911 		   dev_t rdev, __le32 attributes)
912 {
913 	struct ncp_server *server = NCP_SERVER(dir);
914 	struct ncp_entry_info finfo;
915 	int error, result, len;
916 	int opmode;
917 	__u8 __name[NCP_MAXPATHLEN + 1];
918 
919 	ncp_vdbg("creating %pd2, mode=%hx\n", dentry, mode);
920 
921 	ncp_age_dentry(server, dentry);
922 	len = sizeof(__name);
923 	error = ncp_io2vol(server, __name, &len, dentry->d_name.name,
924 			   dentry->d_name.len, !ncp_preserve_case(dir));
925 	if (error)
926 		goto out;
927 
928 	error = -EACCES;
929 
930 	if (S_ISREG(mode) &&
931 	    (server->m.flags & NCP_MOUNT_EXTRAS) &&
932 	    (mode & S_IXUGO))
933 		attributes |= aSYSTEM | aSHARED;
934 
935 	result = ncp_open_create_file_or_subdir(server, dir, __name,
936 				OC_MODE_CREATE | OC_MODE_OPEN | OC_MODE_REPLACE,
937 				attributes, AR_READ | AR_WRITE, &finfo);
938 	opmode = O_RDWR;
939 	if (result) {
940 		result = ncp_open_create_file_or_subdir(server, dir, __name,
941 				OC_MODE_CREATE | OC_MODE_OPEN | OC_MODE_REPLACE,
942 				attributes, AR_WRITE, &finfo);
943 		if (result) {
944 			if (result == 0x87)
945 				error = -ENAMETOOLONG;
946 			else if (result < 0)
947 				error = result;
948 			ncp_dbg(1, "%pd2 failed\n", dentry);
949 			goto out;
950 		}
951 		opmode = O_WRONLY;
952 	}
953 	finfo.access = opmode;
954 	if (ncp_is_nfs_extras(server, finfo.volume)) {
955 		finfo.i.nfs.mode = mode;
956 		finfo.i.nfs.rdev = new_encode_dev(rdev);
957 		if (ncp_modify_nfs_info(server, finfo.volume,
958 					finfo.i.dirEntNum,
959 					mode, new_encode_dev(rdev)) != 0)
960 			goto out;
961 	}
962 
963 	error = ncp_instantiate(dir, dentry, &finfo);
964 out:
965 	return error;
966 }
967 
ncp_create(struct inode * dir,struct dentry * dentry,umode_t mode,bool excl)968 static int ncp_create(struct inode *dir, struct dentry *dentry, umode_t mode,
969 		bool excl)
970 {
971 	return ncp_create_new(dir, dentry, mode, 0, 0);
972 }
973 
ncp_mkdir(struct inode * dir,struct dentry * dentry,umode_t mode)974 static int ncp_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
975 {
976 	struct ncp_entry_info finfo;
977 	struct ncp_server *server = NCP_SERVER(dir);
978 	int error, len;
979 	__u8 __name[NCP_MAXPATHLEN + 1];
980 
981 	ncp_dbg(1, "making %pd2\n", dentry);
982 
983 	ncp_age_dentry(server, dentry);
984 	len = sizeof(__name);
985 	error = ncp_io2vol(server, __name, &len, dentry->d_name.name,
986 			   dentry->d_name.len, !ncp_preserve_case(dir));
987 	if (error)
988 		goto out;
989 
990 	error = ncp_open_create_file_or_subdir(server, dir, __name,
991 					   OC_MODE_CREATE, aDIR,
992 					   cpu_to_le16(0xffff),
993 					   &finfo);
994 	if (error == 0) {
995 		if (ncp_is_nfs_extras(server, finfo.volume)) {
996 			mode |= S_IFDIR;
997 			finfo.i.nfs.mode = mode;
998 			if (ncp_modify_nfs_info(server,
999 						finfo.volume,
1000 						finfo.i.dirEntNum,
1001 						mode, 0) != 0)
1002 				goto out;
1003 		}
1004 		error = ncp_instantiate(dir, dentry, &finfo);
1005 	} else if (error > 0) {
1006 		error = -EACCES;
1007 	}
1008 out:
1009 	return error;
1010 }
1011 
ncp_rmdir(struct inode * dir,struct dentry * dentry)1012 static int ncp_rmdir(struct inode *dir, struct dentry *dentry)
1013 {
1014 	struct ncp_server *server = NCP_SERVER(dir);
1015 	int error, result, len;
1016 	__u8 __name[NCP_MAXPATHLEN + 1];
1017 
1018 	ncp_dbg(1, "removing %pd2\n", dentry);
1019 
1020 	len = sizeof(__name);
1021 	error = ncp_io2vol(server, __name, &len, dentry->d_name.name,
1022 			   dentry->d_name.len, !ncp_preserve_case(dir));
1023 	if (error)
1024 		goto out;
1025 
1026 	result = ncp_del_file_or_subdir(server, dir, __name);
1027 	switch (result) {
1028 		case 0x00:
1029 			error = 0;
1030 			break;
1031 		case 0x85:	/* unauthorized to delete file */
1032 		case 0x8A:	/* unauthorized to delete file */
1033 			error = -EACCES;
1034 			break;
1035 		case 0x8F:
1036 		case 0x90:	/* read only */
1037 			error = -EPERM;
1038 			break;
1039 		case 0x9F:	/* in use by another client */
1040 			error = -EBUSY;
1041 			break;
1042 		case 0xA0:	/* directory not empty */
1043 			error = -ENOTEMPTY;
1044 			break;
1045 		case 0xFF:	/* someone deleted file */
1046 			error = -ENOENT;
1047 			break;
1048 		default:
1049 			error = result < 0 ? result : -EACCES;
1050 			break;
1051        	}
1052 out:
1053 	return error;
1054 }
1055 
ncp_unlink(struct inode * dir,struct dentry * dentry)1056 static int ncp_unlink(struct inode *dir, struct dentry *dentry)
1057 {
1058 	struct inode *inode = d_inode(dentry);
1059 	struct ncp_server *server;
1060 	int error;
1061 
1062 	server = NCP_SERVER(dir);
1063 	ncp_dbg(1, "unlinking %pd2\n", dentry);
1064 
1065 	/*
1066 	 * Check whether to close the file ...
1067 	 */
1068 	if (inode) {
1069 		ncp_vdbg("closing file\n");
1070 		ncp_make_closed(inode);
1071 	}
1072 
1073 	error = ncp_del_file_or_subdir2(server, dentry);
1074 #ifdef CONFIG_NCPFS_STRONG
1075 	/* 9C is Invalid path.. It should be 8F, 90 - read only, but
1076 	   it is not :-( */
1077 	if ((error == 0x9C || error == 0x90) && server->m.flags & NCP_MOUNT_STRONG) { /* R/O */
1078 		error = ncp_force_unlink(dir, dentry);
1079 	}
1080 #endif
1081 	switch (error) {
1082 		case 0x00:
1083 			ncp_dbg(1, "removed %pd2\n", dentry);
1084 			break;
1085 		case 0x85:
1086 		case 0x8A:
1087 			error = -EACCES;
1088 			break;
1089 		case 0x8D:	/* some files in use */
1090 		case 0x8E:	/* all files in use */
1091 			error = -EBUSY;
1092 			break;
1093 		case 0x8F:	/* some read only */
1094 		case 0x90:	/* all read only */
1095 		case 0x9C:	/* !!! returned when in-use or read-only by NW4 */
1096 			error = -EPERM;
1097 			break;
1098 		case 0xFF:
1099 			error = -ENOENT;
1100 			break;
1101 		default:
1102 			error = error < 0 ? error : -EACCES;
1103 			break;
1104 	}
1105 	return error;
1106 }
1107 
ncp_rename(struct inode * old_dir,struct dentry * old_dentry,struct inode * new_dir,struct dentry * new_dentry)1108 static int ncp_rename(struct inode *old_dir, struct dentry *old_dentry,
1109 		      struct inode *new_dir, struct dentry *new_dentry)
1110 {
1111 	struct ncp_server *server = NCP_SERVER(old_dir);
1112 	int error;
1113 	int old_len, new_len;
1114 	__u8 __old_name[NCP_MAXPATHLEN + 1], __new_name[NCP_MAXPATHLEN + 1];
1115 
1116 	ncp_dbg(1, "%pd2 to %pd2\n", old_dentry, new_dentry);
1117 
1118 	ncp_age_dentry(server, old_dentry);
1119 	ncp_age_dentry(server, new_dentry);
1120 
1121 	old_len = sizeof(__old_name);
1122 	error = ncp_io2vol(server, __old_name, &old_len,
1123 			   old_dentry->d_name.name, old_dentry->d_name.len,
1124 			   !ncp_preserve_case(old_dir));
1125 	if (error)
1126 		goto out;
1127 
1128 	new_len = sizeof(__new_name);
1129 	error = ncp_io2vol(server, __new_name, &new_len,
1130 			   new_dentry->d_name.name, new_dentry->d_name.len,
1131 			   !ncp_preserve_case(new_dir));
1132 	if (error)
1133 		goto out;
1134 
1135 	error = ncp_ren_or_mov_file_or_subdir(server, old_dir, __old_name,
1136 						      new_dir, __new_name);
1137 #ifdef CONFIG_NCPFS_STRONG
1138 	if ((error == 0x90 || error == 0x8B || error == -EACCES) &&
1139 			server->m.flags & NCP_MOUNT_STRONG) {	/* RO */
1140 		error = ncp_force_rename(old_dir, old_dentry, __old_name,
1141 					 new_dir, new_dentry, __new_name);
1142 	}
1143 #endif
1144 	switch (error) {
1145 		case 0x00:
1146 			ncp_dbg(1, "renamed %pd -> %pd\n",
1147 				old_dentry, new_dentry);
1148 			break;
1149 		case 0x9E:
1150 			error = -ENAMETOOLONG;
1151 			break;
1152 		case 0xFF:
1153 			error = -ENOENT;
1154 			break;
1155 		default:
1156 			error = error < 0 ? error : -EACCES;
1157 			break;
1158 	}
1159 out:
1160 	return error;
1161 }
1162 
ncp_mknod(struct inode * dir,struct dentry * dentry,umode_t mode,dev_t rdev)1163 static int ncp_mknod(struct inode * dir, struct dentry *dentry,
1164 		     umode_t mode, dev_t rdev)
1165 {
1166 	if (!new_valid_dev(rdev))
1167 		return -EINVAL;
1168 	if (ncp_is_nfs_extras(NCP_SERVER(dir), NCP_FINFO(dir)->volNumber)) {
1169 		ncp_dbg(1, "mode = 0%ho\n", mode);
1170 		return ncp_create_new(dir, dentry, mode, rdev, 0);
1171 	}
1172 	return -EPERM; /* Strange, but true */
1173 }
1174 
1175 /* The following routines are taken directly from msdos-fs */
1176 
1177 /* Linear day numbers of the respective 1sts in non-leap years. */
1178 
1179 static int day_n[] =
1180 {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 0, 0, 0, 0};
1181 /* Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec */
1182 
utc2local(int time)1183 static int utc2local(int time)
1184 {
1185 	return time - sys_tz.tz_minuteswest * 60;
1186 }
1187 
local2utc(int time)1188 static int local2utc(int time)
1189 {
1190 	return time + sys_tz.tz_minuteswest * 60;
1191 }
1192 
1193 /* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70). */
1194 int
ncp_date_dos2unix(__le16 t,__le16 d)1195 ncp_date_dos2unix(__le16 t, __le16 d)
1196 {
1197 	unsigned short time = le16_to_cpu(t), date = le16_to_cpu(d);
1198 	int month, year, secs;
1199 
1200 	/* first subtract and mask after that... Otherwise, if
1201 	   date == 0, bad things happen */
1202 	month = ((date >> 5) - 1) & 15;
1203 	year = date >> 9;
1204 	secs = (time & 31) * 2 + 60 * ((time >> 5) & 63) + (time >> 11) * 3600 +
1205 		86400 * ((date & 31) - 1 + day_n[month] + (year / 4) +
1206 		year * 365 - ((year & 3) == 0 && month < 2 ? 1 : 0) + 3653);
1207 	/* days since 1.1.70 plus 80's leap day */
1208 	return local2utc(secs);
1209 }
1210 
1211 
1212 /* Convert linear UNIX date to a MS-DOS time/date pair. */
1213 void
ncp_date_unix2dos(int unix_date,__le16 * time,__le16 * date)1214 ncp_date_unix2dos(int unix_date, __le16 *time, __le16 *date)
1215 {
1216 	int day, year, nl_day, month;
1217 
1218 	unix_date = utc2local(unix_date);
1219 	*time = cpu_to_le16(
1220 		(unix_date % 60) / 2 + (((unix_date / 60) % 60) << 5) +
1221 		(((unix_date / 3600) % 24) << 11));
1222 	day = unix_date / 86400 - 3652;
1223 	year = day / 365;
1224 	if ((year + 3) / 4 + 365 * year > day)
1225 		year--;
1226 	day -= (year + 3) / 4 + 365 * year;
1227 	if (day == 59 && !(year & 3)) {
1228 		nl_day = day;
1229 		month = 2;
1230 	} else {
1231 		nl_day = (year & 3) || day <= 59 ? day : day - 1;
1232 		for (month = 1; month < 12; month++)
1233 			if (day_n[month] > nl_day)
1234 				break;
1235 	}
1236 	*date = cpu_to_le16(nl_day - day_n[month - 1] + 1 + (month << 5) + (year << 9));
1237 }
1238