OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [tags/] [LINUX_2_4_26_OR32/] [linux/] [linux-2.4/] [fs/] [ncpfs/] [dir.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 *  dir.c
3
 *
4
 *  Copyright (C) 1995, 1996 by Volker Lendecke
5
 *  Modified for big endian by J.F. Chadima and David S. Miller
6
 *  Modified 1997 Peter Waltenberg, Bill Hawes, David Woodhouse for 2.1 dcache
7
 *  Modified 1998, 1999 Wolfram Pienkoss for NLS
8
 *  Modified 1999 Wolfram Pienkoss for directory caching
9
 *
10
 */
11
 
12
#include <linux/config.h>
13
 
14
#include <linux/sched.h>
15
#include <linux/errno.h>
16
#include <linux/stat.h>
17
#include <linux/kernel.h>
18
#include <linux/slab.h>
19
#include <linux/vmalloc.h>
20
#include <linux/mm.h>
21
#include <asm/uaccess.h>
22
#include <asm/byteorder.h>
23
#include <linux/locks.h>
24
#include <linux/smp_lock.h>
25
 
26
#include <linux/ncp_fs.h>
27
 
28
#include "ncplib_kernel.h"
29
 
30
static void ncp_read_volume_list(struct file *, void *, filldir_t,
31
                                struct ncp_cache_control *);
32
static void ncp_do_readdir(struct file *, void *, filldir_t,
33
                                struct ncp_cache_control *);
34
 
35
static int ncp_readdir(struct file *, void *, filldir_t);
36
 
37
static int ncp_create(struct inode *, struct dentry *, int);
38
static struct dentry *ncp_lookup(struct inode *, struct dentry *);
39
static int ncp_unlink(struct inode *, struct dentry *);
40
static int ncp_mkdir(struct inode *, struct dentry *, int);
41
static int ncp_rmdir(struct inode *, struct dentry *);
42
static int ncp_rename(struct inode *, struct dentry *,
43
                      struct inode *, struct dentry *);
44
#ifdef CONFIG_NCPFS_EXTRAS
45
extern int ncp_symlink(struct inode *, struct dentry *, const char *);
46
#endif
47
 
48
struct file_operations ncp_dir_operations =
49
{
50
        read:           generic_read_dir,
51
        readdir:        ncp_readdir,
52
        ioctl:          ncp_ioctl,
53
};
54
 
55
struct inode_operations ncp_dir_inode_operations =
56
{
57
        create:         ncp_create,
58
        lookup:         ncp_lookup,
59
        unlink:         ncp_unlink,
60
#ifdef CONFIG_NCPFS_EXTRAS
61
        symlink:        ncp_symlink,
62
#endif
63
        mkdir:          ncp_mkdir,
64
        rmdir:          ncp_rmdir,
65
        rename:         ncp_rename,
66
        setattr:        ncp_notify_change,
67
};
68
 
69
/*
70
 * Dentry operations routines
71
 */
72
static int ncp_lookup_validate(struct dentry *, int);
73
static int ncp_hash_dentry(struct dentry *, struct qstr *);
74
static int ncp_compare_dentry (struct dentry *, struct qstr *, struct qstr *);
75
static int ncp_delete_dentry(struct dentry *);
76
 
77
static struct dentry_operations ncp_dentry_operations =
78
{
79
        d_revalidate:   ncp_lookup_validate,
80
        d_hash:         ncp_hash_dentry,
81
        d_compare:      ncp_compare_dentry,
82
        d_delete:       ncp_delete_dentry,
83
};
84
 
85
struct dentry_operations ncp_root_dentry_operations =
86
{
87
        d_hash:         ncp_hash_dentry,
88
        d_compare:      ncp_compare_dentry,
89
        d_delete:       ncp_delete_dentry,
90
};
91
 
92
 
93
/*
94
 * Note: leave the hash unchanged if the directory
95
 * is case-sensitive.
96
 */
97
static int
98
ncp_hash_dentry(struct dentry *dentry, struct qstr *this)
99
{
100
        struct nls_table *t;
101
        unsigned long hash;
102
        int i;
103
 
104
        t = NCP_IO_TABLE(dentry);
105
 
106
        if (!ncp_case_sensitive(dentry->d_inode)) {
107
                hash = init_name_hash();
108
                for (i=0; i<this->len ; i++)
109
                        hash = partial_name_hash(ncp_tolower(t, this->name[i]),
110
                                                                        hash);
111
                this->hash = end_name_hash(hash);
112
        }
113
        return 0;
114
}
115
 
116
static int
117
ncp_compare_dentry(struct dentry *dentry, struct qstr *a, struct qstr *b)
118
{
119
        if (a->len != b->len)
120
                return 1;
121
 
122
        if (ncp_case_sensitive(dentry->d_inode))
123
                return strncmp(a->name, b->name, a->len);
124
 
125
        return ncp_strnicmp(NCP_IO_TABLE(dentry), a->name, b->name, a->len);
126
}
127
 
128
/*
129
 * This is the callback from dput() when d_count is going to 0.
130
 * We use this to unhash dentries with bad inodes.
131
 * Closing files can be safely postponed until iput() - it's done there anyway.
132
 */
133
static int
134
ncp_delete_dentry(struct dentry * dentry)
135
{
136
        struct inode *inode = dentry->d_inode;
137
 
138
        if (inode) {
139
                if (is_bad_inode(inode))
140
                        return 1;
141
        } else
142
        {
143
        /* N.B. Unhash negative dentries? */
144
        }
145
        return 0;
146
}
147
 
148
static inline int
149
ncp_single_volume(struct ncp_server *server)
150
{
151
        return (server->m.mounted_vol[0] != '\0');
152
}
153
 
154
static inline int ncp_is_server_root(struct inode *inode)
155
{
156
        return (!ncp_single_volume(NCP_SERVER(inode)) &&
157
                inode == inode->i_sb->s_root->d_inode);
158
}
159
 
160
 
161
/*
162
 * This is the callback when the dcache has a lookup hit.
163
 */
164
 
165
 
166
#ifdef CONFIG_NCPFS_STRONG
167
/* try to delete a readonly file (NW R bit set) */
168
 
169
static int
170
ncp_force_unlink(struct inode *dir, struct dentry* dentry)
171
{
172
        int res=0x9c,res2;
173
        struct nw_modify_dos_info info;
174
        __u32 old_nwattr;
175
        struct inode *inode;
176
 
177
        memset(&info, 0, sizeof(info));
178
 
179
        /* remove the Read-Only flag on the NW server */
180
        inode = dentry->d_inode;
181
 
182
        old_nwattr = NCP_FINFO(inode)->nwattr;
183
        info.attributes = old_nwattr & ~(aRONLY|aDELETEINHIBIT|aRENAMEINHIBIT);
184
        res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(inode), inode, NULL, DM_ATTRIBUTES, &info);
185
        if (res2)
186
                goto leave_me;
187
 
188
        /* now try again the delete operation */
189
        res = ncp_del_file_or_subdir2(NCP_SERVER(dir), dentry);
190
 
191
        if (res)  /* delete failed, set R bit again */
192
        {
193
                info.attributes = old_nwattr;
194
                res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(inode), inode, NULL, DM_ATTRIBUTES, &info);
195
                if (res2)
196
                        goto leave_me;
197
        }
198
leave_me:
199
        return(res);
200
}
201
#endif  /* CONFIG_NCPFS_STRONG */
202
 
203
#ifdef CONFIG_NCPFS_STRONG
204
static int
205
ncp_force_rename(struct inode *old_dir, struct dentry* old_dentry, char *_old_name,
206
                 struct inode *new_dir, struct dentry* new_dentry, char *_new_name)
207
{
208
        struct nw_modify_dos_info info;
209
        int res=0x90,res2;
210
        struct inode *old_inode = old_dentry->d_inode;
211
        __u32 old_nwattr = NCP_FINFO(old_inode)->nwattr;
212
        __u32 new_nwattr = 0; /* shut compiler warning */
213
        int old_nwattr_changed = 0;
214
        int new_nwattr_changed = 0;
215
 
216
        memset(&info, 0, sizeof(info));
217
 
218
        /* remove the Read-Only flag on the NW server */
219
 
220
        info.attributes = old_nwattr & ~(aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
221
        res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(old_inode), old_inode, NULL, DM_ATTRIBUTES, &info);
222
        if (!res2)
223
                old_nwattr_changed = 1;
224
        if (new_dentry && new_dentry->d_inode) {
225
                new_nwattr = NCP_FINFO(new_dentry->d_inode)->nwattr;
226
                info.attributes = new_nwattr & ~(aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
227
                res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(new_dir), new_dir, _new_name, DM_ATTRIBUTES, &info);
228
                if (!res2)
229
                        new_nwattr_changed = 1;
230
        }
231
        /* now try again the rename operation */
232
        /* but only if something really happened */
233
        if (new_nwattr_changed || old_nwattr_changed) {
234
                res = ncp_ren_or_mov_file_or_subdir(NCP_SERVER(old_dir),
235
                                                    old_dir, _old_name,
236
                                                    new_dir, _new_name);
237
        }
238
        if (res)
239
                goto leave_me;
240
        /* file was successfully renamed, so:
241
           do not set attributes on old file - it no longer exists
242
           copy attributes from old file to new */
243
        new_nwattr_changed = old_nwattr_changed;
244
        new_nwattr = old_nwattr;
245
        old_nwattr_changed = 0;
246
 
247
leave_me:;
248
        if (old_nwattr_changed) {
249
                info.attributes = old_nwattr;
250
                res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(old_inode), old_inode, NULL, DM_ATTRIBUTES, &info);
251
                /* ignore errors */
252
        }
253
        if (new_nwattr_changed) {
254
                info.attributes = new_nwattr;
255
                res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(new_dir), new_dir, _new_name, DM_ATTRIBUTES, &info);
256
                /* ignore errors */
257
        }
258
        return(res);
259
}
260
#endif  /* CONFIG_NCPFS_STRONG */
261
 
262
 
263
static int
264
__ncp_lookup_validate(struct dentry * dentry, int flags)
265
{
266
        struct ncp_server *server;
267
        struct inode *dir = dentry->d_parent->d_inode;
268
        struct ncp_entry_info finfo;
269
        int res, val = 0, len;
270
        __u8 __name[NCP_MAXPATHLEN + 1];
271
 
272
        if (!dentry->d_inode || !dir)
273
                goto finished;
274
 
275
        server = NCP_SERVER(dir);
276
 
277
        if (!ncp_conn_valid(server))
278
                goto finished;
279
 
280
        /*
281
         * Inspired by smbfs:
282
         * The default validation is based on dentry age:
283
         * We set the max age at mount time.  (But each
284
         * successful server lookup renews the timestamp.)
285
         */
286
        val = NCP_TEST_AGE(server, dentry);
287
        if (val)
288
                goto finished;
289
 
290
        DDPRINTK("ncp_lookup_validate: %s/%s not valid, age=%ld, server lookup\n",
291
                dentry->d_parent->d_name.name, dentry->d_name.name,
292
                NCP_GET_AGE(dentry));
293
 
294
        len = sizeof(__name);
295
        if (ncp_is_server_root(dir)) {
296
                res = ncp_io2vol(server, __name, &len, dentry->d_name.name,
297
                                                dentry->d_name.len, 1);
298
                if (!res)
299
                        res = ncp_lookup_volume(server, __name, &(finfo.i));
300
        } else {
301
                res = ncp_io2vol(server, __name, &len, dentry->d_name.name,
302
                                                dentry->d_name.len, !ncp_preserve_case(dir));
303
                if (!res)
304
                        res = ncp_obtain_info(server, dir, __name, &(finfo.i));
305
        }
306
        DDPRINTK("ncp_lookup_validate: looked for %s/%s, res=%d\n",
307
                dentry->d_parent->d_name.name, __name, res);
308
        /*
309
         * If we didn't find it, or if it has a different dirEntNum to
310
         * what we remember, it's not valid any more.
311
         */
312
        if (!res) {
313
                if (finfo.i.dirEntNum == NCP_FINFO(dentry->d_inode)->dirEntNum) {
314
                        ncp_new_dentry(dentry);
315
                        val=1;
316
                } else
317
                        DDPRINTK("ncp_lookup_validate: found, but dirEntNum changed\n");
318
 
319
                ncp_update_inode2(dentry->d_inode, &finfo);
320
        }
321
 
322
finished:
323
        DDPRINTK("ncp_lookup_validate: result=%d\n", val);
324
        return val;
325
}
326
 
327
static int
328
ncp_lookup_validate(struct dentry * dentry, int flags)
329
{
330
        int res;
331
        lock_kernel();
332
        res = __ncp_lookup_validate(dentry, flags);
333
        unlock_kernel();
334
        return res;
335
}
336
 
337
static struct dentry *
338
ncp_dget_fpos(struct dentry *dentry, struct dentry *parent, unsigned long fpos)
339
{
340
        struct dentry *dent = dentry;
341
        struct list_head *next;
342
 
343
        if (d_validate(dent, parent)) {
344
                if (dent->d_name.len <= NCP_MAXPATHLEN &&
345
                    (unsigned long)dent->d_fsdata == fpos) {
346
                        if (!dent->d_inode) {
347
                                dput(dent);
348
                                dent = NULL;
349
                        }
350
                        return dent;
351
                }
352
                dput(dent);
353
        }
354
 
355
        /* If a pointer is invalid, we search the dentry. */
356
        spin_lock(&dcache_lock);
357
        next = parent->d_subdirs.next;
358
        while (next != &parent->d_subdirs) {
359
                dent = list_entry(next, struct dentry, d_child);
360
                if ((unsigned long)dent->d_fsdata == fpos) {
361
                        if (dent->d_inode)
362
                                dget_locked(dent);
363
                        else
364
                                dent = NULL;
365
                        spin_unlock(&dcache_lock);
366
                        goto out;
367
                }
368
                next = next->next;
369
        }
370
        spin_unlock(&dcache_lock);
371
        return NULL;
372
 
373
out:
374
        return dent;
375
}
376
 
377
static time_t ncp_obtain_mtime(struct dentry *dentry)
378
{
379
        struct inode *inode = dentry->d_inode;
380
        struct ncp_server *server = NCP_SERVER(inode);
381
        struct nw_info_struct i;
382
 
383
        if (!ncp_conn_valid(server) || ncp_is_server_root(inode))
384
                return 0;
385
 
386
        if (ncp_obtain_info(server, inode, NULL, &i))
387
                return 0;
388
 
389
        return ncp_date_dos2unix(le16_to_cpu(i.modifyTime),
390
                                                le16_to_cpu(i.modifyDate));
391
}
392
 
393
static int ncp_readdir(struct file *filp, void *dirent, filldir_t filldir)
394
{
395
        struct dentry *dentry = filp->f_dentry;
396
        struct inode *inode = dentry->d_inode;
397
        struct page *page = NULL;
398
        struct ncp_server *server = NCP_SERVER(inode);
399
        union  ncp_dir_cache *cache = NULL;
400
        struct ncp_cache_control ctl;
401
        int result, mtime_valid = 0;
402
        time_t mtime = 0;
403
 
404
        ctl.page  = NULL;
405
        ctl.cache = NULL;
406
 
407
        DDPRINTK("ncp_readdir: reading %s/%s, pos=%d\n",
408
                dentry->d_parent->d_name.name, dentry->d_name.name,
409
                (int) filp->f_pos);
410
 
411
        result = -EIO;
412
        if (!ncp_conn_valid(server))
413
                goto out;
414
 
415
        result = 0;
416
        if (filp->f_pos == 0) {
417
                if (filldir(dirent, ".", 1, 0, inode->i_ino, DT_DIR))
418
                        goto out;
419
                filp->f_pos = 1;
420
        }
421
        if (filp->f_pos == 1) {
422
                if (filldir(dirent, "..", 2, 1,
423
                                dentry->d_parent->d_inode->i_ino, DT_DIR))
424
                        goto out;
425
                filp->f_pos = 2;
426
        }
427
 
428
        page = grab_cache_page(&inode->i_data, 0);
429
        if (!page)
430
                goto read_really;
431
 
432
        ctl.cache = cache = kmap(page);
433
        ctl.head  = cache->head;
434
 
435
        if (!Page_Uptodate(page) || !ctl.head.eof)
436
                goto init_cache;
437
 
438
        if (filp->f_pos == 2) {
439
                if (jiffies - ctl.head.time >= NCP_MAX_AGE(server))
440
                        goto init_cache;
441
 
442
                mtime = ncp_obtain_mtime(dentry);
443
                mtime_valid = 1;
444
                if ((!mtime) || (mtime != ctl.head.mtime))
445
                        goto init_cache;
446
        }
447
 
448
        if (filp->f_pos > ctl.head.end)
449
                goto finished;
450
 
451
        ctl.fpos = filp->f_pos + (NCP_DIRCACHE_START - 2);
452
        ctl.ofs  = ctl.fpos / NCP_DIRCACHE_SIZE;
453
        ctl.idx  = ctl.fpos % NCP_DIRCACHE_SIZE;
454
 
455
        for (;;) {
456
                if (ctl.ofs != 0) {
457
                        ctl.page = find_lock_page(&inode->i_data, ctl.ofs);
458
                        if (!ctl.page)
459
                                goto invalid_cache;
460
                        ctl.cache = kmap(ctl.page);
461
                        if (!Page_Uptodate(ctl.page))
462
                                goto invalid_cache;
463
                }
464
                while (ctl.idx < NCP_DIRCACHE_SIZE) {
465
                        struct dentry *dent;
466
                        int res;
467
 
468
                        dent = ncp_dget_fpos(ctl.cache->dentry[ctl.idx],
469
                                                dentry, filp->f_pos);
470
                        if (!dent)
471
                                goto invalid_cache;
472
                        res = filldir(dirent, dent->d_name.name,
473
                                        dent->d_name.len, filp->f_pos,
474
                                        dent->d_inode->i_ino, DT_UNKNOWN);
475
                        dput(dent);
476
                        if (res)
477
                                goto finished;
478
                        filp->f_pos += 1;
479
                        ctl.idx += 1;
480
                        if (filp->f_pos > ctl.head.end)
481
                                goto finished;
482
                }
483
                if (ctl.page) {
484
                        kunmap(ctl.page);
485
                        SetPageUptodate(ctl.page);
486
                        UnlockPage(ctl.page);
487
                        page_cache_release(ctl.page);
488
                        ctl.page = NULL;
489
                }
490
                ctl.idx  = 0;
491
                ctl.ofs += 1;
492
        }
493
invalid_cache:
494
        if (ctl.page) {
495
                kunmap(ctl.page);
496
                UnlockPage(ctl.page);
497
                page_cache_release(ctl.page);
498
                ctl.page = NULL;
499
        }
500
        ctl.cache = cache;
501
init_cache:
502
        ncp_invalidate_dircache_entries(dentry);
503
        if (!mtime_valid) {
504
                mtime = ncp_obtain_mtime(dentry);
505
                mtime_valid = 1;
506
        }
507
        ctl.head.mtime = mtime;
508
        ctl.head.time = jiffies;
509
        ctl.head.eof = 0;
510
        ctl.fpos = 2;
511
        ctl.ofs = 0;
512
        ctl.idx = NCP_DIRCACHE_START;
513
        ctl.filled = 0;
514
        ctl.valid  = 1;
515
read_really:
516
        if (ncp_is_server_root(inode)) {
517
                ncp_read_volume_list(filp, dirent, filldir, &ctl);
518
        } else {
519
                ncp_do_readdir(filp, dirent, filldir, &ctl);
520
        }
521
        ctl.head.end = ctl.fpos - 1;
522
        ctl.head.eof = ctl.valid;
523
finished:
524
        if (page) {
525
                cache->head = ctl.head;
526
                kunmap(page);
527
                SetPageUptodate(page);
528
                UnlockPage(page);
529
                page_cache_release(page);
530
        }
531
        if (ctl.page) {
532
                kunmap(ctl.page);
533
                SetPageUptodate(ctl.page);
534
                UnlockPage(ctl.page);
535
                page_cache_release(ctl.page);
536
        }
537
out:
538
        return result;
539
}
540
 
541
static int
542
ncp_fill_cache(struct file *filp, void *dirent, filldir_t filldir,
543
                struct ncp_cache_control *ctrl, struct ncp_entry_info *entry)
544
{
545
        struct dentry *newdent, *dentry = filp->f_dentry;
546
        struct inode *newino, *inode = dentry->d_inode;
547
        struct ncp_cache_control ctl = *ctrl;
548
        struct qstr qname;
549
        int valid = 0;
550
        int hashed = 0;
551
        ino_t ino = 0;
552
        __u8 __name[NCP_MAXPATHLEN + 1];
553
 
554
        qname.len = sizeof(__name);
555
        if (ncp_vol2io(NCP_SERVER(inode), __name, &qname.len,
556
                        entry->i.entryName, entry->i.nameLen,
557
                        !ncp_preserve_entry_case(inode, entry->i.NSCreator)))
558
                return 1; /* I'm not sure */
559
 
560
        qname.name = __name;
561
        qname.hash = full_name_hash(qname.name, qname.len);
562
 
563
        if (dentry->d_op && dentry->d_op->d_hash)
564
                if (dentry->d_op->d_hash(dentry, &qname) != 0)
565
                        goto end_advance;
566
 
567
        newdent = d_lookup(dentry, &qname);
568
 
569
        if (!newdent) {
570
                newdent = d_alloc(dentry, &qname);
571
                if (!newdent)
572
                        goto end_advance;
573
        } else {
574
                hashed = 1;
575
                memcpy((char *) newdent->d_name.name, qname.name,
576
                                                        newdent->d_name.len);
577
        }
578
 
579
        if (!newdent->d_inode) {
580
                entry->opened = 0;
581
                entry->ino = iunique(inode->i_sb, 2);
582
                newino = ncp_iget(inode->i_sb, entry);
583
                if (newino) {
584
                        newdent->d_op = &ncp_dentry_operations;
585
                        d_instantiate(newdent, newino);
586
                        if (!hashed)
587
                                d_rehash(newdent);
588
                }
589
        } else
590
                ncp_update_inode2(newdent->d_inode, entry);
591
 
592
        if (newdent->d_inode) {
593
                ino = newdent->d_inode->i_ino;
594
                newdent->d_fsdata = (void *) ctl.fpos;
595
                ncp_new_dentry(newdent);
596
        }
597
 
598
        if (ctl.idx >= NCP_DIRCACHE_SIZE) {
599
                if (ctl.page) {
600
                        kunmap(ctl.page);
601
                        SetPageUptodate(ctl.page);
602
                        UnlockPage(ctl.page);
603
                        page_cache_release(ctl.page);
604
                }
605
                ctl.cache = NULL;
606
                ctl.idx  -= NCP_DIRCACHE_SIZE;
607
                ctl.ofs  += 1;
608
                ctl.page  = grab_cache_page(&inode->i_data, ctl.ofs);
609
                if (ctl.page)
610
                        ctl.cache = kmap(ctl.page);
611
        }
612
        if (ctl.cache) {
613
                ctl.cache->dentry[ctl.idx] = newdent;
614
                valid = 1;
615
        }
616
        dput(newdent);
617
end_advance:
618
        if (!valid)
619
                ctl.valid = 0;
620
        if (!ctl.filled && (ctl.fpos == filp->f_pos)) {
621
                if (!ino)
622
                        ino = find_inode_number(dentry, &qname);
623
                if (!ino)
624
                        ino = iunique(inode->i_sb, 2);
625
                ctl.filled = filldir(dirent, qname.name, qname.len,
626
                                     filp->f_pos, ino, DT_UNKNOWN);
627
                if (!ctl.filled)
628
                        filp->f_pos += 1;
629
        }
630
        ctl.fpos += 1;
631
        ctl.idx  += 1;
632
        *ctrl = ctl;
633
        return (ctl.valid || !ctl.filled);
634
}
635
 
636
static void
637
ncp_read_volume_list(struct file *filp, void *dirent, filldir_t filldir,
638
                        struct ncp_cache_control *ctl)
639
{
640
        struct dentry *dentry = filp->f_dentry;
641
        struct inode *inode = dentry->d_inode;
642
        struct ncp_server *server = NCP_SERVER(inode);
643
        struct ncp_volume_info info;
644
        struct ncp_entry_info entry;
645
        int i;
646
 
647
        DPRINTK("ncp_read_volume_list: pos=%ld\n",
648
                        (unsigned long) filp->f_pos);
649
 
650
        for (i = 0; i < NCP_NUMBER_OF_VOLUMES; i++) {
651
 
652
                if (ncp_get_volume_info_with_number(server, i, &info) != 0)
653
                        return;
654
                if (!strlen(info.volume_name))
655
                        continue;
656
 
657
                DPRINTK("ncp_read_volume_list: found vol: %s\n",
658
                        info.volume_name);
659
 
660
                if (ncp_lookup_volume(server, info.volume_name,
661
                                        &entry.i)) {
662
                        DPRINTK("ncpfs: could not lookup vol %s\n",
663
                                info.volume_name);
664
                        continue;
665
                }
666
                if (!ncp_fill_cache(filp, dirent, filldir, ctl, &entry))
667
                        return;
668
        }
669
}
670
 
671
static void
672
ncp_do_readdir(struct file *filp, void *dirent, filldir_t filldir,
673
                                                struct ncp_cache_control *ctl)
674
{
675
        struct dentry *dentry = filp->f_dentry;
676
        struct inode *dir = dentry->d_inode;
677
        struct ncp_server *server = NCP_SERVER(dir);
678
        struct nw_search_sequence seq;
679
        struct ncp_entry_info entry;
680
        int err;
681
 
682
        DPRINTK("ncp_do_readdir: %s/%s, fpos=%ld\n",
683
                dentry->d_parent->d_name.name, dentry->d_name.name,
684
                (unsigned long) filp->f_pos);
685
        PPRINTK("ncp_do_readdir: init %s, volnum=%d, dirent=%u\n",
686
                dentry->d_name.name, NCP_FINFO(dir)->volNumber,
687
                NCP_FINFO(dir)->dirEntNum);
688
 
689
        err = ncp_initialize_search(server, dir, &seq);
690
        if (err) {
691
                DPRINTK("ncp_do_readdir: init failed, err=%d\n", err);
692
                return;
693
        }
694
        for (;;) {
695
                err = ncp_search_for_file_or_subdir(server, &seq, &entry.i);
696
                if (err) {
697
                        DPRINTK("ncp_do_readdir: search failed, err=%d\n", err);
698
                        return;
699
                }
700
                if (!ncp_fill_cache(filp, dirent, filldir, ctl, &entry))
701
                        return;
702
        }
703
}
704
 
705
int ncp_conn_logged_in(struct super_block *sb)
706
{
707
        struct ncp_server* server = NCP_SBP(sb);
708
        struct nw_info_struct i;
709
        int result;
710
 
711
        if (ncp_single_volume(server)) {
712
                int len;
713
                struct dentry* dent;
714
                __u8 __name[NCP_MAXPATHLEN + 1];
715
 
716
                len = sizeof(__name);
717
                result = ncp_io2vol(server, __name, &len, server->m.mounted_vol,
718
                                    strlen(server->m.mounted_vol), 1);
719
                if (result)
720
                        goto out;
721
                result = -ENOENT;
722
                if (ncp_lookup_volume(server, __name, &i)) {
723
                        PPRINTK("ncp_conn_logged_in: %s not found\n",
724
                                server->m.mounted_vol);
725
                        goto out;
726
                }
727
                dent = sb->s_root;
728
                if (dent) {
729
                        struct inode* ino = dent->d_inode;
730
                        if (ino) {
731
                                NCP_FINFO(ino)->volNumber = i.volNumber;
732
                                NCP_FINFO(ino)->dirEntNum = i.dirEntNum;
733
                                NCP_FINFO(ino)->DosDirNum = i.DosDirNum;
734
                        } else {
735
                                DPRINTK("ncpfs: sb->s_root->d_inode == NULL!\n");
736
                        }
737
                } else {
738
                        DPRINTK("ncpfs: sb->s_root == NULL!\n");
739
                }
740
        }
741
        result = 0;
742
 
743
out:
744
        return result;
745
}
746
 
747
static struct dentry *ncp_lookup(struct inode *dir, struct dentry *dentry)
748
{
749
        struct ncp_server *server = NCP_SERVER(dir);
750
        struct inode *inode = NULL;
751
        struct ncp_entry_info finfo;
752
        int error, res, len;
753
        __u8 __name[NCP_MAXPATHLEN + 1];
754
 
755
        error = -EIO;
756
        if (!ncp_conn_valid(server))
757
                goto finished;
758
 
759
        PPRINTK("ncp_lookup: server lookup for %s/%s\n",
760
                dentry->d_parent->d_name.name, dentry->d_name.name);
761
 
762
        len = sizeof(__name);
763
        if (ncp_is_server_root(dir)) {
764
                res = ncp_io2vol(server, __name, &len, dentry->d_name.name,
765
                                 dentry->d_name.len, 1);
766
                if (!res)
767
                        res = ncp_lookup_volume(server, __name, &(finfo.i));
768
        } else {
769
                res = ncp_io2vol(server, __name, &len, dentry->d_name.name,
770
                                 dentry->d_name.len, !ncp_preserve_case(dir));
771
                if (!res)
772
                        res = ncp_obtain_info(server, dir, __name, &(finfo.i));
773
        }
774
        PPRINTK("ncp_lookup: looked for %s/%s, res=%d\n",
775
                dentry->d_parent->d_name.name, __name, res);
776
        /*
777
         * If we didn't find an entry, make a negative dentry.
778
         */
779
        if (res)
780
                goto add_entry;
781
 
782
        /*
783
         * Create an inode for the entry.
784
         */
785
        finfo.opened = 0;
786
        finfo.ino = iunique(dir->i_sb, 2);
787
        error = -EACCES;
788
        inode = ncp_iget(dir->i_sb, &finfo);
789
 
790
        if (inode) {
791
                ncp_new_dentry(dentry);
792
add_entry:
793
                dentry->d_op = &ncp_dentry_operations;
794
                d_add(dentry, inode);
795
                error = 0;
796
        }
797
 
798
finished:
799
        PPRINTK("ncp_lookup: result=%d\n", error);
800
        return ERR_PTR(error);
801
}
802
 
803
/*
804
 * This code is common to create, mkdir, and mknod.
805
 */
806
static int ncp_instantiate(struct inode *dir, struct dentry *dentry,
807
                        struct ncp_entry_info *finfo)
808
{
809
        struct inode *inode;
810
        int error = -EINVAL;
811
 
812
        finfo->ino = iunique(dir->i_sb, 2);
813
        inode = ncp_iget(dir->i_sb, finfo);
814
        if (!inode)
815
                goto out_close;
816
        d_instantiate(dentry,inode);
817
        error = 0;
818
out:
819
        return error;
820
 
821
out_close:
822
        PPRINTK("ncp_instantiate: %s/%s failed, closing file\n",
823
                dentry->d_parent->d_name.name, dentry->d_name.name);
824
        ncp_close_file(NCP_SERVER(dir), finfo->file_handle);
825
        goto out;
826
}
827
 
828
int ncp_create_new(struct inode *dir, struct dentry *dentry, int mode,
829
                int attributes)
830
{
831
        struct ncp_server *server = NCP_SERVER(dir);
832
        struct ncp_entry_info finfo;
833
        int error, result, len;
834
        int opmode;
835
        __u8 __name[NCP_MAXPATHLEN + 1];
836
 
837
        PPRINTK("ncp_create_new: creating %s/%s, mode=%x\n",
838
                dentry->d_parent->d_name.name, dentry->d_name.name, mode);
839
        error = -EIO;
840
        if (!ncp_conn_valid(server))
841
                goto out;
842
 
843
        ncp_age_dentry(server, dentry);
844
        len = sizeof(__name);
845
        error = ncp_io2vol(server, __name, &len, dentry->d_name.name,
846
                           dentry->d_name.len, !ncp_preserve_case(dir));
847
        if (error)
848
                goto out;
849
 
850
        error = -EACCES;
851
 
852
        if (S_ISREG(mode) &&
853
            (server->m.flags & NCP_MOUNT_EXTRAS) &&
854
            (mode & S_IXUGO))
855
                attributes |= aSYSTEM | aSHARED;
856
 
857
        result = ncp_open_create_file_or_subdir(server, dir, __name,
858
                                OC_MODE_CREATE | OC_MODE_OPEN | OC_MODE_REPLACE,
859
                                attributes, AR_READ | AR_WRITE, &finfo);
860
        opmode = O_RDWR;
861
        if (result) {
862
                result = ncp_open_create_file_or_subdir(server, dir, __name,
863
                                OC_MODE_CREATE | OC_MODE_OPEN | OC_MODE_REPLACE,
864
                                attributes, AR_WRITE, &finfo);
865
                if (result) {
866
                        if (result == 0x87)
867
                                error = -ENAMETOOLONG;
868
                        DPRINTK("ncp_create: %s/%s failed\n",
869
                                dentry->d_parent->d_name.name, dentry->d_name.name);
870
                        goto out;
871
                }
872
                opmode = O_WRONLY;
873
        }
874
        finfo.access = opmode;
875
        error = ncp_instantiate(dir, dentry, &finfo);
876
out:
877
        return error;
878
}
879
 
880
static int ncp_create(struct inode *dir, struct dentry *dentry, int mode)
881
{
882
        return ncp_create_new(dir, dentry, mode, 0);
883
}
884
 
885
static int ncp_mkdir(struct inode *dir, struct dentry *dentry, int mode)
886
{
887
        struct ncp_entry_info finfo;
888
        struct ncp_server *server = NCP_SERVER(dir);
889
        int error, len;
890
        __u8 __name[NCP_MAXPATHLEN + 1];
891
 
892
        DPRINTK("ncp_mkdir: making %s/%s\n",
893
                dentry->d_parent->d_name.name, dentry->d_name.name);
894
        error = -EIO;
895
        if (!ncp_conn_valid(server))
896
                goto out;
897
 
898
        ncp_age_dentry(server, dentry);
899
        len = sizeof(__name);
900
        error = ncp_io2vol(server, __name, &len, dentry->d_name.name,
901
                           dentry->d_name.len, !ncp_preserve_case(dir));
902
        if (error)
903
                goto out;
904
 
905
        error = -EACCES;
906
        if (ncp_open_create_file_or_subdir(server, dir, __name,
907
                                           OC_MODE_CREATE, aDIR, 0xffff,
908
                                           &finfo) == 0)
909
        {
910
                error = ncp_instantiate(dir, dentry, &finfo);
911
        }
912
out:
913
        return error;
914
}
915
 
916
static int ncp_rmdir(struct inode *dir, struct dentry *dentry)
917
{
918
        struct ncp_server *server = NCP_SERVER(dir);
919
        int error, result, len;
920
        __u8 __name[NCP_MAXPATHLEN + 1];
921
 
922
        DPRINTK("ncp_rmdir: removing %s/%s\n",
923
                dentry->d_parent->d_name.name, dentry->d_name.name);
924
 
925
        error = -EIO;
926
        if (!ncp_conn_valid(server))
927
                goto out;
928
 
929
        error = -EBUSY;
930
        if (!d_unhashed(dentry))
931
                goto out;
932
 
933
        len = sizeof(__name);
934
        error = ncp_io2vol(server, __name, &len, dentry->d_name.name,
935
                           dentry->d_name.len, !ncp_preserve_case(dir));
936
        if (error)
937
                goto out;
938
 
939
        result = ncp_del_file_or_subdir(server, dir, __name);
940
        switch (result) {
941
                case 0x00:
942
                        error = 0;
943
                        break;
944
                case 0x85:      /* unauthorized to delete file */
945
                case 0x8A:      /* unauthorized to delete file */
946
                        error = -EACCES;
947
                        break;
948
                case 0x8F:
949
                case 0x90:      /* read only */
950
                        error = -EPERM;
951
                        break;
952
                case 0x9F:      /* in use by another client */
953
                        error = -EBUSY;
954
                        break;
955
                case 0xA0:      /* directory not empty */
956
                        error = -ENOTEMPTY;
957
                        break;
958
                case 0xFF:      /* someone deleted file */
959
                        error = -ENOENT;
960
                        break;
961
                default:
962
                        error = -EACCES;
963
                        break;
964
        }
965
out:
966
        return error;
967
}
968
 
969
static int ncp_unlink(struct inode *dir, struct dentry *dentry)
970
{
971
        struct inode *inode = dentry->d_inode;
972
        struct ncp_server *server = NCP_SERVER(dir);
973
        int error;
974
 
975
        DPRINTK("ncp_unlink: unlinking %s/%s\n",
976
                dentry->d_parent->d_name.name, dentry->d_name.name);
977
 
978
        error = -EIO;
979
        if (!ncp_conn_valid(server))
980
                goto out;
981
 
982
        /*
983
         * Check whether to close the file ...
984
         */
985
        if (inode) {
986
                PPRINTK("ncp_unlink: closing file\n");
987
                ncp_make_closed(inode);
988
        }
989
 
990
        error = ncp_del_file_or_subdir2(server, dentry);
991
#ifdef CONFIG_NCPFS_STRONG
992
        /* 9C is Invalid path.. It should be 8F, 90 - read only, but
993
           it is not :-( */
994
        if ((error == 0x9C || error == 0x90) && server->m.flags & NCP_MOUNT_STRONG) { /* R/O */
995
                error = ncp_force_unlink(dir, dentry);
996
        }
997
#endif
998
        switch (error) {
999
                case 0x00:
1000
                        DPRINTK("ncp: removed %s/%s\n",
1001
                                dentry->d_parent->d_name.name, dentry->d_name.name);
1002
                        break;
1003
                case 0x85:
1004
                case 0x8A:
1005
                        error = -EACCES;
1006
                        break;
1007
                case 0x8D:      /* some files in use */
1008
                case 0x8E:      /* all files in use */
1009
                        error = -EBUSY;
1010
                        break;
1011
                case 0x8F:      /* some read only */
1012
                case 0x90:      /* all read only */
1013
                case 0x9C:      /* !!! returned when in-use or read-only by NW4 */
1014
                        error = -EPERM;
1015
                        break;
1016
                case 0xFF:
1017
                        error = -ENOENT;
1018
                        break;
1019
                default:
1020
                        error = -EACCES;
1021
                        break;
1022
        }
1023
 
1024
out:
1025
        return error;
1026
}
1027
 
1028
static int ncp_rename(struct inode *old_dir, struct dentry *old_dentry,
1029
                      struct inode *new_dir, struct dentry *new_dentry)
1030
{
1031
        struct ncp_server *server = NCP_SERVER(old_dir);
1032
        int error;
1033
        int old_len, new_len;
1034
        __u8 __old_name[NCP_MAXPATHLEN + 1], __new_name[NCP_MAXPATHLEN + 1];
1035
 
1036
        DPRINTK("ncp_rename: %s/%s to %s/%s\n",
1037
                old_dentry->d_parent->d_name.name, old_dentry->d_name.name,
1038
                new_dentry->d_parent->d_name.name, new_dentry->d_name.name);
1039
 
1040
        error = -EIO;
1041
        if (!ncp_conn_valid(server))
1042
                goto out;
1043
 
1044
        ncp_age_dentry(server, old_dentry);
1045
        ncp_age_dentry(server, new_dentry);
1046
 
1047
        old_len = sizeof(__old_name);
1048
        error = ncp_io2vol(server, __old_name, &old_len,
1049
                           old_dentry->d_name.name, old_dentry->d_name.len,
1050
                           !ncp_preserve_case(old_dir));
1051
        if (error)
1052
                goto out;
1053
 
1054
        new_len = sizeof(__new_name);
1055
        error = ncp_io2vol(server, __new_name, &new_len,
1056
                           new_dentry->d_name.name, new_dentry->d_name.len,
1057
                           !ncp_preserve_case(new_dir));
1058
        if (error)
1059
                goto out;
1060
 
1061
        error = ncp_ren_or_mov_file_or_subdir(server, old_dir, __old_name,
1062
                                                      new_dir, __new_name);
1063
#ifdef CONFIG_NCPFS_STRONG
1064
        if ((error == 0x90 || error == 0x8B || error == -EACCES) &&
1065
                        server->m.flags & NCP_MOUNT_STRONG) {   /* RO */
1066
                error = ncp_force_rename(old_dir, old_dentry, __old_name,
1067
                                         new_dir, new_dentry, __new_name);
1068
        }
1069
#endif
1070
        switch (error) {
1071
                case 0x00:
1072
                        DPRINTK("ncp renamed %s -> %s.\n",
1073
                                old_dentry->d_name.name,new_dentry->d_name.name);
1074
                        break;
1075
                case 0x9E:
1076
                        error = -ENAMETOOLONG;
1077
                        break;
1078
                case 0xFF:
1079
                        error = -ENOENT;
1080
                        break;
1081
                default:
1082
                        error = -EACCES;
1083
                        break;
1084
        }
1085
out:
1086
        return error;
1087
}
1088
 
1089
/* The following routines are taken directly from msdos-fs */
1090
 
1091
/* Linear day numbers of the respective 1sts in non-leap years. */
1092
 
1093
static int day_n[] =
1094
{0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 0, 0, 0, 0};
1095
/* Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec */
1096
 
1097
 
1098
extern struct timezone sys_tz;
1099
 
1100
static int utc2local(int time)
1101
{
1102
        return time - sys_tz.tz_minuteswest * 60;
1103
}
1104
 
1105
static int local2utc(int time)
1106
{
1107
        return time + sys_tz.tz_minuteswest * 60;
1108
}
1109
 
1110
/* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70). */
1111
int
1112
ncp_date_dos2unix(unsigned short time, unsigned short date)
1113
{
1114
        int month, year, secs;
1115
 
1116
        /* first subtract and mask after that... Otherwise, if
1117
           date == 0, bad things happen */
1118
        month = ((date >> 5) - 1) & 15;
1119
        year = date >> 9;
1120
        secs = (time & 31) * 2 + 60 * ((time >> 5) & 63) + (time >> 11) * 3600 +
1121
                86400 * ((date & 31) - 1 + day_n[month] + (year / 4) +
1122
                year * 365 - ((year & 3) == 0 && month < 2 ? 1 : 0) + 3653);
1123
        /* days since 1.1.70 plus 80's leap day */
1124
        return local2utc(secs);
1125
}
1126
 
1127
 
1128
/* Convert linear UNIX date to a MS-DOS time/date pair. */
1129
void
1130
ncp_date_unix2dos(int unix_date, unsigned short *time, unsigned short *date)
1131
{
1132
        int day, year, nl_day, month;
1133
 
1134
        unix_date = utc2local(unix_date);
1135
        *time = (unix_date % 60) / 2 + (((unix_date / 60) % 60) << 5) +
1136
            (((unix_date / 3600) % 24) << 11);
1137
        day = unix_date / 86400 - 3652;
1138
        year = day / 365;
1139
        if ((year + 3) / 4 + 365 * year > day)
1140
                year--;
1141
        day -= (year + 3) / 4 + 365 * year;
1142
        if (day == 59 && !(year & 3)) {
1143
                nl_day = day;
1144
                month = 2;
1145
        } else {
1146
                nl_day = (year & 3) || day <= 59 ? day : day - 1;
1147
                for (month = 0; month < 12; month++)
1148
                        if (day_n[month] > nl_day)
1149
                                break;
1150
        }
1151
        *date = nl_day - day_n[month - 1] + 1 + (month << 5) + (year << 9);
1152
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.