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 *);
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 *, const struct dentry *,
78 unsigned int, const char *, const struct qstr *);
79static int ncp_delete_dentry(const struct dentry *);
80
81const 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
91static 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
100 )
101 return 0;
102#endif
103 return 1;
104}
105
106#define ncp_preserve_case(i) (ncp_namespace(i) != NW_NS_DOS)
107
108static 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
115}
116
117
118
119
120
121
122
123
124
125static int
126ncp_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
151
152
153
154static int
155ncp_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
175
176
177
178static int
179ncp_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
189 }
190 return 0;
191}
192
193static inline int
194ncp_single_volume(struct ncp_server *server)
195{
196 return (server->m.mounted_vol[0] != '\0');
197}
198
199static 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
208
209
210
211#ifdef CONFIG_NCPFS_STRONG
212
213
214static int
215ncp_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
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
234 res = ncp_del_file_or_subdir2(NCP_SERVER(dir), dentry);
235
236 if (res)
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 }
243leave_me:
244 return(res);
245}
246#endif
247
248#ifdef CONFIG_NCPFS_STRONG
249static int
250ncp_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;
258 int old_nwattr_changed = 0;
259 int new_nwattr_changed = 0;
260
261 memset(&info, 0, sizeof(info));
262
263
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
277
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
286
287
288 new_nwattr_changed = old_nwattr_changed;
289 new_nwattr = old_nwattr;
290 old_nwattr_changed = 0;
291
292leave_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
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
302 }
303 return(res);
304}
305#endif
306
307
308static int
309ncp_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
334
335
336
337
338 val = NCP_TEST_AGE(server, dentry);
339 if (val)
340 goto finished;
341
342 ncp_dbg(2, "%pd2 not valid, age=%ld, server lookup\n",
343 dentry, NCP_GET_AGE(dentry));
344
345 len = sizeof(__name);
346 if (ncp_is_server_root(dir)) {
347 res = ncp_io2vol(server, __name, &len, dentry->d_name.name,
348 dentry->d_name.len, 1);
349 if (!res) {
350 res = ncp_lookup_volume(server, __name, &(finfo.i));
351 if (!res)
352 ncp_update_known_namespace(server, finfo.i.volNumber, NULL);
353 }
354 } else {
355 res = ncp_io2vol(server, __name, &len, dentry->d_name.name,
356 dentry->d_name.len, !ncp_preserve_case(dir));
357 if (!res)
358 res = ncp_obtain_info(server, dir, __name, &(finfo.i));
359 }
360 finfo.volume = finfo.i.volNumber;
361 ncp_dbg(2, "looked for %pd/%s, res=%d\n",
362 dentry->d_parent, __name, res);
363
364
365
366
367 if (!res) {
368 struct inode *inode = dentry->d_inode;
369
370 mutex_lock(&inode->i_mutex);
371 if (finfo.i.dirEntNum == NCP_FINFO(inode)->dirEntNum) {
372 ncp_new_dentry(dentry);
373 val=1;
374 } else
375 ncp_dbg(2, "found, but dirEntNum changed\n");
376
377 ncp_update_inode2(inode, &finfo);
378 mutex_unlock(&inode->i_mutex);
379 }
380
381finished:
382 ncp_dbg(2, "result=%d\n", val);
383 dput(parent);
384 return val;
385}
386
387static struct dentry *
388ncp_dget_fpos(struct dentry *dentry, struct dentry *parent, unsigned long fpos)
389{
390 struct dentry *dent = dentry;
391
392 if (d_validate(dent, parent)) {
393 if (dent->d_name.len <= NCP_MAXPATHLEN &&
394 (unsigned long)dent->d_fsdata == fpos) {
395 if (!dent->d_inode) {
396 dput(dent);
397 dent = NULL;
398 }
399 return dent;
400 }
401 dput(dent);
402 }
403
404
405 spin_lock(&parent->d_lock);
406 list_for_each_entry(dent, &parent->d_subdirs, d_u.d_child) {
407 if ((unsigned long)dent->d_fsdata == fpos) {
408 if (dent->d_inode)
409 dget(dent);
410 else
411 dent = NULL;
412 spin_unlock(&parent->d_lock);
413 goto out;
414 }
415 }
416 spin_unlock(&parent->d_lock);
417 return NULL;
418
419out:
420 return dent;
421}
422
423static time_t ncp_obtain_mtime(struct dentry *dentry)
424{
425 struct inode *inode = dentry->d_inode;
426 struct ncp_server *server = NCP_SERVER(inode);
427 struct nw_info_struct i;
428
429 if (!ncp_conn_valid(server) || ncp_is_server_root(inode))
430 return 0;
431
432 if (ncp_obtain_info(server, inode, NULL, &i))
433 return 0;
434
435 return ncp_date_dos2unix(i.modifyTime, i.modifyDate);
436}
437
438static int ncp_readdir(struct file *file, struct dir_context *ctx)
439{
440 struct dentry *dentry = file->f_path.dentry;
441 struct inode *inode = dentry->d_inode;
442 struct page *page = NULL;
443 struct ncp_server *server = NCP_SERVER(inode);
444 union ncp_dir_cache *cache = NULL;
445 struct ncp_cache_control ctl;
446 int result, mtime_valid = 0;
447 time_t mtime = 0;
448
449 ctl.page = NULL;
450 ctl.cache = NULL;
451
452 ncp_dbg(2, "reading %pD2, pos=%d\n", file, (int)ctx->pos);
453
454 result = -EIO;
455
456 if (!ncp_conn_valid(server))
457 goto out;
458
459 result = 0;
460 if (!dir_emit_dots(file, ctx))
461 goto out;
462
463 page = grab_cache_page(&inode->i_data, 0);
464 if (!page)
465 goto read_really;
466
467 ctl.cache = cache = kmap(page);
468 ctl.head = cache->head;
469
470 if (!PageUptodate(page) || !ctl.head.eof)
471 goto init_cache;
472
473 if (ctx->pos == 2) {
474 if (jiffies - ctl.head.time >= NCP_MAX_AGE(server))
475 goto init_cache;
476
477 mtime = ncp_obtain_mtime(dentry);
478 mtime_valid = 1;
479 if ((!mtime) || (mtime != ctl.head.mtime))
480 goto init_cache;
481 }
482
483 if (ctx->pos > ctl.head.end)
484 goto finished;
485
486 ctl.fpos = ctx->pos + (NCP_DIRCACHE_START - 2);
487 ctl.ofs = ctl.fpos / NCP_DIRCACHE_SIZE;
488 ctl.idx = ctl.fpos % NCP_DIRCACHE_SIZE;
489
490 for (;;) {
491 if (ctl.ofs != 0) {
492 ctl.page = find_lock_page(&inode->i_data, ctl.ofs);
493 if (!ctl.page)
494 goto invalid_cache;
495 ctl.cache = kmap(ctl.page);
496 if (!PageUptodate(ctl.page))
497 goto invalid_cache;
498 }
499 while (ctl.idx < NCP_DIRCACHE_SIZE) {
500 struct dentry *dent;
501 bool over;
502
503 dent = ncp_dget_fpos(ctl.cache->dentry[ctl.idx],
504 dentry, ctx->pos);
505 if (!dent)
506 goto invalid_cache;
507 over = !dir_emit(ctx, dent->d_name.name,
508 dent->d_name.len,
509 dent->d_inode->i_ino, DT_UNKNOWN);
510 dput(dent);
511 if (over)
512 goto finished;
513 ctx->pos += 1;
514 ctl.idx += 1;
515 if (ctx->pos > ctl.head.end)
516 goto finished;
517 }
518 if (ctl.page) {
519 kunmap(ctl.page);
520 SetPageUptodate(ctl.page);
521 unlock_page(ctl.page);
522 page_cache_release(ctl.page);
523 ctl.page = NULL;
524 }
525 ctl.idx = 0;
526 ctl.ofs += 1;
527 }
528invalid_cache:
529 if (ctl.page) {
530 kunmap(ctl.page);
531 unlock_page(ctl.page);
532 page_cache_release(ctl.page);
533 ctl.page = NULL;
534 }
535 ctl.cache = cache;
536init_cache:
537 ncp_invalidate_dircache_entries(dentry);
538 if (!mtime_valid) {
539 mtime = ncp_obtain_mtime(dentry);
540 mtime_valid = 1;
541 }
542 ctl.head.mtime = mtime;
543 ctl.head.time = jiffies;
544 ctl.head.eof = 0;
545 ctl.fpos = 2;
546 ctl.ofs = 0;
547 ctl.idx = NCP_DIRCACHE_START;
548 ctl.filled = 0;
549 ctl.valid = 1;
550read_really:
551 if (ncp_is_server_root(inode)) {
552 ncp_read_volume_list(file, ctx, &ctl);
553 } else {
554 ncp_do_readdir(file, ctx, &ctl);
555 }
556 ctl.head.end = ctl.fpos - 1;
557 ctl.head.eof = ctl.valid;
558finished:
559 if (ctl.page) {
560 kunmap(ctl.page);
561 SetPageUptodate(ctl.page);
562 unlock_page(ctl.page);
563 page_cache_release(ctl.page);
564 }
565 if (page) {
566 cache->head = ctl.head;
567 kunmap(page);
568 SetPageUptodate(page);
569 unlock_page(page);
570 page_cache_release(page);
571 }
572out:
573 return result;
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 = dentry->d_inode;
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 (unlikely(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 (!newdent->d_inode) {
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 }
634 } else {
635 struct inode *inode = newdent->d_inode;
636
637 mutex_lock_nested(&inode->i_mutex, I_MUTEX_CHILD);
638 ncp_update_inode2(inode, entry);
639 mutex_unlock(&inode->i_mutex);
640 }
641
642 if (newdent->d_inode) {
643 ino = newdent->d_inode->i_ino;
644 newdent->d_fsdata = (void *) ctl.fpos;
645 ncp_new_dentry(newdent);
646 }
647
648 if (ctl.idx >= NCP_DIRCACHE_SIZE) {
649 if (ctl.page) {
650 kunmap(ctl.page);
651 SetPageUptodate(ctl.page);
652 unlock_page(ctl.page);
653 page_cache_release(ctl.page);
654 }
655 ctl.cache = NULL;
656 ctl.idx -= NCP_DIRCACHE_SIZE;
657 ctl.ofs += 1;
658 ctl.page = grab_cache_page(&dir->i_data, ctl.ofs);
659 if (ctl.page)
660 ctl.cache = kmap(ctl.page);
661 }
662 if (ctl.cache) {
663 ctl.cache->dentry[ctl.idx] = newdent;
664 valid = 1;
665 }
666 dput(newdent);
667end_advance:
668 if (!valid)
669 ctl.valid = 0;
670 if (!ctl.filled && (ctl.fpos == ctx->pos)) {
671 if (!ino)
672 ino = iunique(dir->i_sb, 2);
673 ctl.filled = !dir_emit(ctx, qname.name, qname.len,
674 ino, DT_UNKNOWN);
675 if (!ctl.filled)
676 ctx->pos += 1;
677 }
678 ctl.fpos += 1;
679 ctl.idx += 1;
680 *ctrl = ctl;
681 return (ctl.valid || !ctl.filled);
682}
683
684static void
685ncp_read_volume_list(struct file *file, struct dir_context *ctx,
686 struct ncp_cache_control *ctl)
687{
688 struct dentry *dentry = file->f_path.dentry;
689 struct inode *inode = dentry->d_inode;
690 struct ncp_server *server = NCP_SERVER(inode);
691 struct ncp_volume_info info;
692 struct ncp_entry_info entry;
693 int i;
694
695 ncp_dbg(1, "pos=%ld\n", (unsigned long)ctx->pos);
696
697 for (i = 0; i < NCP_NUMBER_OF_VOLUMES; i++) {
698 int inval_dentry;
699
700 if (ncp_get_volume_info_with_number(server, i, &info) != 0)
701 return;
702 if (!strlen(info.volume_name))
703 continue;
704
705 ncp_dbg(1, "found vol: %s\n", info.volume_name);
706
707 if (ncp_lookup_volume(server, info.volume_name,
708 &entry.i)) {
709 ncp_dbg(1, "could not lookup vol %s\n",
710 info.volume_name);
711 continue;
712 }
713 inval_dentry = ncp_update_known_namespace(server, entry.i.volNumber, NULL);
714 entry.volume = entry.i.volNumber;
715 if (!ncp_fill_cache(file, ctx, ctl, &entry, inval_dentry))
716 return;
717 }
718}
719
720static void
721ncp_do_readdir(struct file *file, struct dir_context *ctx,
722 struct ncp_cache_control *ctl)
723{
724 struct dentry *dentry = file->f_path.dentry;
725 struct inode *dir = dentry->d_inode;
726 struct ncp_server *server = NCP_SERVER(dir);
727 struct nw_search_sequence seq;
728 struct ncp_entry_info entry;
729 int err;
730 void* buf;
731 int more;
732 size_t bufsize;
733
734 ncp_dbg(1, "%pD2, fpos=%ld\n", file, (unsigned long)ctx->pos);
735 ncp_vdbg("init %pD, volnum=%d, dirent=%u\n",
736 file, NCP_FINFO(dir)->volNumber, NCP_FINFO(dir)->dirEntNum);
737
738 err = ncp_initialize_search(server, dir, &seq);
739 if (err) {
740 ncp_dbg(1, "init failed, err=%d\n", err);
741 return;
742 }
743
744
745
746
747
748 bufsize = 131072;
749 buf = vmalloc(bufsize);
750 if (!buf)
751 return;
752 do {
753 int cnt;
754 char* rpl;
755 size_t rpls;
756
757 err = ncp_search_for_fileset(server, &seq, &more, &cnt, buf, bufsize, &rpl, &rpls);
758 if (err)
759 break;
760 if (!cnt)
761 break;
762 while (cnt--) {
763 size_t onerpl;
764
765 if (rpls < offsetof(struct nw_info_struct, entryName))
766 break;
767 ncp_extract_file_info(rpl, &entry.i);
768 onerpl = offsetof(struct nw_info_struct, entryName) + entry.i.nameLen;
769 if (rpls < onerpl)
770 break;
771 (void)ncp_obtain_nfs_info(server, &entry.i);
772 rpl += onerpl;
773 rpls -= onerpl;
774 entry.volume = entry.i.volNumber;
775 if (!ncp_fill_cache(file, ctx, ctl, &entry, 0))
776 break;
777 }
778 } while (more);
779 vfree(buf);
780 return;
781}
782
783int ncp_conn_logged_in(struct super_block *sb)
784{
785 struct ncp_server* server = NCP_SBP(sb);
786 int result;
787
788 if (ncp_single_volume(server)) {
789 int len;
790 struct dentry* dent;
791 __u32 volNumber;
792 __le32 dirEntNum;
793 __le32 DosDirNum;
794 __u8 __name[NCP_MAXPATHLEN + 1];
795
796 len = sizeof(__name);
797 result = ncp_io2vol(server, __name, &len, server->m.mounted_vol,
798 strlen(server->m.mounted_vol), 1);
799 if (result)
800 goto out;
801 result = -ENOENT;
802 if (ncp_get_volume_root(server, __name, &volNumber, &dirEntNum, &DosDirNum)) {
803 ncp_vdbg("%s not found\n", server->m.mounted_vol);
804 goto out;
805 }
806 dent = sb->s_root;
807 if (dent) {
808 struct inode* ino = dent->d_inode;
809 if (ino) {
810 ncp_update_known_namespace(server, volNumber, NULL);
811 NCP_FINFO(ino)->volNumber = volNumber;
812 NCP_FINFO(ino)->dirEntNum = dirEntNum;
813 NCP_FINFO(ino)->DosDirNum = DosDirNum;
814 result = 0;
815 } else {
816 ncp_dbg(1, "sb->s_root->d_inode == NULL!\n");
817 }
818 } else {
819 ncp_dbg(1, "sb->s_root == NULL!\n");
820 }
821 } else
822 result = 0;
823
824out:
825 return result;
826}
827
828static struct dentry *ncp_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
829{
830 struct ncp_server *server = NCP_SERVER(dir);
831 struct inode *inode = NULL;
832 struct ncp_entry_info finfo;
833 int error, res, len;
834 __u8 __name[NCP_MAXPATHLEN + 1];
835
836 error = -EIO;
837 if (!ncp_conn_valid(server))
838 goto finished;
839
840 ncp_vdbg("server lookup for %pd2\n", dentry);
841
842 len = sizeof(__name);
843 if (ncp_is_server_root(dir)) {
844 res = ncp_io2vol(server, __name, &len, dentry->d_name.name,
845 dentry->d_name.len, 1);
846 if (!res)
847 res = ncp_lookup_volume(server, __name, &(finfo.i));
848 if (!res)
849 ncp_update_known_namespace(server, finfo.i.volNumber, NULL);
850 } else {
851 res = ncp_io2vol(server, __name, &len, dentry->d_name.name,
852 dentry->d_name.len, !ncp_preserve_case(dir));
853 if (!res)
854 res = ncp_obtain_info(server, dir, __name, &(finfo.i));
855 }
856 ncp_vdbg("looked for %pd2, res=%d\n", dentry, res);
857
858
859
860 if (res)
861 goto add_entry;
862
863
864
865
866 finfo.opened = 0;
867 finfo.ino = iunique(dir->i_sb, 2);
868 finfo.volume = finfo.i.volNumber;
869 error = -EACCES;
870 inode = ncp_iget(dir->i_sb, &finfo);
871
872 if (inode) {
873 ncp_new_dentry(dentry);
874add_entry:
875 d_add(dentry, inode);
876 error = 0;
877 }
878
879finished:
880 ncp_vdbg("result=%d\n", error);
881 return ERR_PTR(error);
882}
883
884
885
886
887static int ncp_instantiate(struct inode *dir, struct dentry *dentry,
888 struct ncp_entry_info *finfo)
889{
890 struct inode *inode;
891 int error = -EINVAL;
892
893 finfo->ino = iunique(dir->i_sb, 2);
894 inode = ncp_iget(dir->i_sb, finfo);
895 if (!inode)
896 goto out_close;
897 d_instantiate(dentry,inode);
898 error = 0;
899out:
900 return error;
901
902out_close:
903 ncp_vdbg("%pd2 failed, closing file\n", dentry);
904 ncp_close_file(NCP_SERVER(dir), finfo->file_handle);
905 goto out;
906}
907
908int ncp_create_new(struct inode *dir, struct dentry *dentry, umode_t mode,
909 dev_t rdev, __le32 attributes)
910{
911 struct ncp_server *server = NCP_SERVER(dir);
912 struct ncp_entry_info finfo;
913 int error, result, len;
914 int opmode;
915 __u8 __name[NCP_MAXPATHLEN + 1];
916
917 ncp_vdbg("creating %pd2, mode=%hx\n", dentry, mode);
918
919 ncp_age_dentry(server, dentry);
920 len = sizeof(__name);
921 error = ncp_io2vol(server, __name, &len, dentry->d_name.name,
922 dentry->d_name.len, !ncp_preserve_case(dir));
923 if (error)
924 goto out;
925
926 error = -EACCES;
927
928 if (S_ISREG(mode) &&
929 (server->m.flags & NCP_MOUNT_EXTRAS) &&
930 (mode & S_IXUGO))
931 attributes |= aSYSTEM | aSHARED;
932
933 result = ncp_open_create_file_or_subdir(server, dir, __name,
934 OC_MODE_CREATE | OC_MODE_OPEN | OC_MODE_REPLACE,
935 attributes, AR_READ | AR_WRITE, &finfo);
936 opmode = O_RDWR;
937 if (result) {
938 result = ncp_open_create_file_or_subdir(server, dir, __name,
939 OC_MODE_CREATE | OC_MODE_OPEN | OC_MODE_REPLACE,
940 attributes, AR_WRITE, &finfo);
941 if (result) {
942 if (result == 0x87)
943 error = -ENAMETOOLONG;
944 else if (result < 0)
945 error = result;
946 ncp_dbg(1, "%pd2 failed\n", dentry);
947 goto out;
948 }
949 opmode = O_WRONLY;
950 }
951 finfo.access = opmode;
952 if (ncp_is_nfs_extras(server, finfo.volume)) {
953 finfo.i.nfs.mode = mode;
954 finfo.i.nfs.rdev = new_encode_dev(rdev);
955 if (ncp_modify_nfs_info(server, finfo.volume,
956 finfo.i.dirEntNum,
957 mode, new_encode_dev(rdev)) != 0)
958 goto out;
959 }
960
961 error = ncp_instantiate(dir, dentry, &finfo);
962out:
963 return error;
964}
965
966static int ncp_create(struct inode *dir, struct dentry *dentry, umode_t mode,
967 bool excl)
968{
969 return ncp_create_new(dir, dentry, mode, 0, 0);
970}
971
972static int ncp_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
973{
974 struct ncp_entry_info finfo;
975 struct ncp_server *server = NCP_SERVER(dir);
976 int error, len;
977 __u8 __name[NCP_MAXPATHLEN + 1];
978
979 ncp_dbg(1, "making %pd2\n", dentry);
980
981 ncp_age_dentry(server, dentry);
982 len = sizeof(__name);
983 error = ncp_io2vol(server, __name, &len, dentry->d_name.name,
984 dentry->d_name.len, !ncp_preserve_case(dir));
985 if (error)
986 goto out;
987
988 error = ncp_open_create_file_or_subdir(server, dir, __name,
989 OC_MODE_CREATE, aDIR,
990 cpu_to_le16(0xffff),
991 &finfo);
992 if (error == 0) {
993 if (ncp_is_nfs_extras(server, finfo.volume)) {
994 mode |= S_IFDIR;
995 finfo.i.nfs.mode = mode;
996 if (ncp_modify_nfs_info(server,
997 finfo.volume,
998 finfo.i.dirEntNum,
999 mode, 0) != 0)
1000 goto out;
1001 }
1002 error = ncp_instantiate(dir, dentry, &finfo);
1003 } else if (error > 0) {
1004 error = -EACCES;
1005 }
1006out:
1007 return error;
1008}
1009
1010static int ncp_rmdir(struct inode *dir, struct dentry *dentry)
1011{
1012 struct ncp_server *server = NCP_SERVER(dir);
1013 int error, result, len;
1014 __u8 __name[NCP_MAXPATHLEN + 1];
1015
1016 ncp_dbg(1, "removing %pd2\n", dentry);
1017
1018 len = sizeof(__name);
1019 error = ncp_io2vol(server, __name, &len, dentry->d_name.name,
1020 dentry->d_name.len, !ncp_preserve_case(dir));
1021 if (error)
1022 goto out;
1023
1024 result = ncp_del_file_or_subdir(server, dir, __name);
1025 switch (result) {
1026 case 0x00:
1027 error = 0;
1028 break;
1029 case 0x85:
1030 case 0x8A:
1031 error = -EACCES;
1032 break;
1033 case 0x8F:
1034 case 0x90:
1035 error = -EPERM;
1036 break;
1037 case 0x9F:
1038 error = -EBUSY;
1039 break;
1040 case 0xA0:
1041 error = -ENOTEMPTY;
1042 break;
1043 case 0xFF:
1044 error = -ENOENT;
1045 break;
1046 default:
1047 error = result < 0 ? result : -EACCES;
1048 break;
1049 }
1050out:
1051 return error;
1052}
1053
1054static int ncp_unlink(struct inode *dir, struct dentry *dentry)
1055{
1056 struct inode *inode = dentry->d_inode;
1057 struct ncp_server *server;
1058 int error;
1059
1060 server = NCP_SERVER(dir);
1061 ncp_dbg(1, "unlinking %pd2\n", dentry);
1062
1063
1064
1065
1066 if (inode) {
1067 ncp_vdbg("closing file\n");
1068 ncp_make_closed(inode);
1069 }
1070
1071 error = ncp_del_file_or_subdir2(server, dentry);
1072#ifdef CONFIG_NCPFS_STRONG
1073
1074
1075 if ((error == 0x9C || error == 0x90) && server->m.flags & NCP_MOUNT_STRONG) {
1076 error = ncp_force_unlink(dir, dentry);
1077 }
1078#endif
1079 switch (error) {
1080 case 0x00:
1081 ncp_dbg(1, "removed %pd2\n", dentry);
1082 break;
1083 case 0x85:
1084 case 0x8A:
1085 error = -EACCES;
1086 break;
1087 case 0x8D:
1088 case 0x8E:
1089 error = -EBUSY;
1090 break;
1091 case 0x8F:
1092 case 0x90:
1093 case 0x9C:
1094 error = -EPERM;
1095 break;
1096 case 0xFF:
1097 error = -ENOENT;
1098 break;
1099 default:
1100 error = error < 0 ? error : -EACCES;
1101 break;
1102 }
1103 return error;
1104}
1105
1106static int ncp_rename(struct inode *old_dir, struct dentry *old_dentry,
1107 struct inode *new_dir, struct dentry *new_dentry)
1108{
1109 struct ncp_server *server = NCP_SERVER(old_dir);
1110 int error;
1111 int old_len, new_len;
1112 __u8 __old_name[NCP_MAXPATHLEN + 1], __new_name[NCP_MAXPATHLEN + 1];
1113
1114 ncp_dbg(1, "%pd2 to %pd2\n", old_dentry, new_dentry);
1115
1116 ncp_age_dentry(server, old_dentry);
1117 ncp_age_dentry(server, new_dentry);
1118
1119 old_len = sizeof(__old_name);
1120 error = ncp_io2vol(server, __old_name, &old_len,
1121 old_dentry->d_name.name, old_dentry->d_name.len,
1122 !ncp_preserve_case(old_dir));
1123 if (error)
1124 goto out;
1125
1126 new_len = sizeof(__new_name);
1127 error = ncp_io2vol(server, __new_name, &new_len,
1128 new_dentry->d_name.name, new_dentry->d_name.len,
1129 !ncp_preserve_case(new_dir));
1130 if (error)
1131 goto out;
1132
1133 error = ncp_ren_or_mov_file_or_subdir(server, old_dir, __old_name,
1134 new_dir, __new_name);
1135#ifdef CONFIG_NCPFS_STRONG
1136 if ((error == 0x90 || error == 0x8B || error == -EACCES) &&
1137 server->m.flags & NCP_MOUNT_STRONG) {
1138 error = ncp_force_rename(old_dir, old_dentry, __old_name,
1139 new_dir, new_dentry, __new_name);
1140 }
1141#endif
1142 switch (error) {
1143 case 0x00:
1144 ncp_dbg(1, "renamed %pd -> %pd\n",
1145 old_dentry, new_dentry);
1146 break;
1147 case 0x9E:
1148 error = -ENAMETOOLONG;
1149 break;
1150 case 0xFF:
1151 error = -ENOENT;
1152 break;
1153 default:
1154 error = error < 0 ? error : -EACCES;
1155 break;
1156 }
1157out:
1158 return error;
1159}
1160
1161static int ncp_mknod(struct inode * dir, struct dentry *dentry,
1162 umode_t mode, dev_t rdev)
1163{
1164 if (!new_valid_dev(rdev))
1165 return -EINVAL;
1166 if (ncp_is_nfs_extras(NCP_SERVER(dir), NCP_FINFO(dir)->volNumber)) {
1167 ncp_dbg(1, "mode = 0%ho\n", mode);
1168 return ncp_create_new(dir, dentry, mode, rdev, 0);
1169 }
1170 return -EPERM;
1171}
1172
1173
1174
1175
1176
1177static int day_n[] =
1178{0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 0, 0, 0, 0};
1179
1180
1181static int utc2local(int time)
1182{
1183 return time - sys_tz.tz_minuteswest * 60;
1184}
1185
1186static int local2utc(int time)
1187{
1188 return time + sys_tz.tz_minuteswest * 60;
1189}
1190
1191
1192int
1193ncp_date_dos2unix(__le16 t, __le16 d)
1194{
1195 unsigned short time = le16_to_cpu(t), date = le16_to_cpu(d);
1196 int month, year, secs;
1197
1198
1199
1200 month = ((date >> 5) - 1) & 15;
1201 year = date >> 9;
1202 secs = (time & 31) * 2 + 60 * ((time >> 5) & 63) + (time >> 11) * 3600 +
1203 86400 * ((date & 31) - 1 + day_n[month] + (year / 4) +
1204 year * 365 - ((year & 3) == 0 && month < 2 ? 1 : 0) + 3653);
1205
1206 return local2utc(secs);
1207}
1208
1209
1210
1211void
1212ncp_date_unix2dos(int unix_date, __le16 *time, __le16 *date)
1213{
1214 int day, year, nl_day, month;
1215
1216 unix_date = utc2local(unix_date);
1217 *time = cpu_to_le16(
1218 (unix_date % 60) / 2 + (((unix_date / 60) % 60) << 5) +
1219 (((unix_date / 3600) % 24) << 11));
1220 day = unix_date / 86400 - 3652;
1221 year = day / 365;
1222 if ((year + 3) / 4 + 365 * year > day)
1223 year--;
1224 day -= (year + 3) / 4 + 365 * year;
1225 if (day == 59 && !(year & 3)) {
1226 nl_day = day;
1227 month = 2;
1228 } else {
1229 nl_day = (year & 3) || day <= 59 ? day : day - 1;
1230 for (month = 1; month < 12; month++)
1231 if (day_n[month] > nl_day)
1232 break;
1233 }
1234 *date = cpu_to_le16(nl_day - day_n[month - 1] + 1 + (month << 5) + (year << 9));
1235}
1236