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