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