~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/fs/ncpfs/dir.c

Version: ~ [ linux-5.3-rc4 ] ~ [ linux-5.2.8 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.66 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.138 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.189 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.189 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.71 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-3.9.11 ] ~ [ linux-3.8.13 ] ~ [ linux-3.7.10 ] ~ [ linux-3.6.11 ] ~ [ linux-3.5.7 ] ~ [ linux-3.4.113 ] ~ [ linux-3.3.8 ] ~ [ linux-3.2.102 ] ~ [ linux-3.1.10 ] ~ [ linux-3.0.101 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp