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