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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [uclinux/] [uClinux-2.0.x/] [fs/] [ncpfs/] [dir.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 199 simons
/*
2
 *  dir.c
3
 *
4
 *  Copyright (C) 1995, 1996 by Volker Lendecke
5
 *
6
 */
7
 
8
#include <linux/config.h>
9
 
10
#include <linux/sched.h>
11
#include <linux/errno.h>
12
#include <linux/stat.h>
13
#include <linux/kernel.h>
14
#include <linux/malloc.h>
15
#include <linux/mm.h>
16
#include <linux/ncp_fs.h>
17
#include <asm/segment.h>
18
#include <linux/errno.h>
19
#include <linux/locks.h>
20
#include "ncplib_kernel.h"
21
 
22
struct ncp_dirent {
23
        struct nw_info_struct i;
24
        struct nw_search_sequence s; /* given back for i */
25
        unsigned long f_pos;
26
};
27
 
28
static int
29
ncp_dir_read(struct inode *inode, struct file *filp, char *buf, int count);
30
 
31
static int
32
ncp_readdir(struct inode *inode, struct file *filp,
33
            void *dirent, filldir_t filldir);
34
 
35
static int
36
ncp_read_volume_list(struct ncp_server *server, int start_with,
37
                     int cache_size);
38
 
39
static int
40
ncp_do_readdir(struct ncp_server *server, struct inode *dir, int fpos,
41
               int cache_size, struct ncp_dirent *entry);
42
 
43
static struct inode *
44
ncp_iget(struct inode *dir, struct nw_file_info *finfo);
45
 
46
static struct ncp_inode_info *
47
ncp_find_dir_inode(struct inode *dir, const char *name);
48
 
49
static int
50
ncp_lookup(struct inode *dir, const char *__name,
51
           int len, struct inode **result);
52
 
53
static int
54
ncp_create(struct inode *dir, const char *name, int len, int mode,
55
           struct inode **result);
56
 
57
static int
58
ncp_mkdir(struct inode *dir, const char *name, int len, int mode);
59
 
60
static int
61
ncp_rmdir(struct inode *dir, const char *name, int len);
62
 
63
static int
64
ncp_unlink(struct inode *dir, const char *name, int len);
65
 
66
static int
67
ncp_rename(struct inode *old_dir, const char *old_name, int old_len,
68
           struct inode *new_dir, const char *new_name, int new_len,
69
           int must_be_dir);
70
 
71
static inline void
72
str_upper(char *name)
73
{
74
        while (*name)
75
        {
76
                if (*name >= 'a' && *name <= 'z')
77
                {
78
                        *name -= ('a' - 'A');
79
                }
80
                name++;
81
        }
82
}
83
 
84
static inline void
85
str_lower(char *name)
86
{
87
        while (*name)
88
        {
89
                if (*name >= 'A' && *name <= 'Z')
90
                {
91
                        *name += ('a' - 'A');
92
                }
93
                name ++;
94
        }
95
}
96
 
97
static inline int
98
ncp_namespace(struct inode *i)
99
{
100
        struct ncp_server *server   = NCP_SERVER(i);
101
        struct nw_info_struct *info = NCP_ISTRUCT(i);
102
        return server->name_space[info->volNumber];
103
}
104
 
105
static inline int
106
ncp_preserve_case(struct inode *i)
107
{
108
        return
109
#ifdef CONFIG_NCPFS_OS2_NS
110
        (ncp_namespace(i) == NW_NS_OS2) ||
111
#endif  /* CONFIG_NCPFS_OS2_NS */
112
#ifdef CONFIG_NCPFS_NFS_NS
113
        (ncp_namespace(i) == NW_NS_NFS) ||
114
#endif  /* CONFIG_NCPFS_NFS_NS */
115
        0;
116
}
117
 
118
static struct file_operations ncp_dir_operations = {
119
        NULL,                   /* lseek - default */
120
        ncp_dir_read,           /* read - bad */
121
        NULL,                   /* write - bad */
122
        ncp_readdir,            /* readdir */
123
        NULL,                   /* select - default */
124
        ncp_ioctl,              /* ioctl */
125
        NULL,                   /* mmap */
126
        NULL,                   /* no special open code */
127
        NULL,                   /* no special release code */
128
        NULL                    /* fsync */
129
};
130
 
131
struct inode_operations ncp_dir_inode_operations = {
132
        &ncp_dir_operations,    /* default directory file ops */
133
        ncp_create,             /* create */
134
        ncp_lookup,             /* lookup */
135
        NULL,                   /* link */
136
        ncp_unlink,             /* unlink */
137
        NULL,                   /* symlink */
138
        ncp_mkdir,              /* mkdir */
139
        ncp_rmdir,              /* rmdir */
140
        NULL,                   /* mknod */
141
        ncp_rename,             /* rename */
142
        NULL,                   /* readlink */
143
        NULL,                   /* follow_link */
144
        NULL,                   /* bmap */
145
        NULL,                   /* truncate */
146
        NULL,                   /* permission */
147
        NULL                    /* smap */
148
};
149
 
150
 
151
/* Here we encapsulate the inode number handling that depends upon the
152
 * mount mode: When we mount a complete server, the memory address of
153
 * the ncp_inode_info is used as the inode number. When only a single
154
 * volume is mounted, then the dirEntNum is used as the inode
155
 * number. As this is unique for the complete volume, this should
156
 * enable the NFS exportability of a ncpfs-mounted volume.
157
 */
158
 
159
static inline int
160
ncp_single_volume(struct ncp_server *server)
161
{
162
        return (server->m.mounted_vol[0] != '\0');
163
}
164
 
165
inline ino_t
166
ncp_info_ino(struct ncp_server *server, struct ncp_inode_info *info)
167
{
168
        return ncp_single_volume(server)
169
                ? (info->finfo.i.dirEntNum == server->root.finfo.i.dirEntNum)?0:info->finfo.i.dirEntNum: (ino_t)info;
170
}
171
 
172
static inline int
173
ncp_is_server_root(struct inode *inode)
174
{
175
        struct ncp_server *s = NCP_SERVER(inode);
176
 
177
        return (   (!ncp_single_volume(s))
178
                && (inode->i_ino == ncp_info_ino(s, &(s->root))));
179
}
180
 
181
struct ncp_inode_info *
182
ncp_find_inode(struct inode *inode)
183
{
184
        struct ncp_server *server = NCP_SERVER(inode);
185
        struct ncp_inode_info *root = &(server->root);
186
        struct ncp_inode_info *this = root;
187
 
188
        ino_t ino = inode->i_ino;
189
 
190
        do
191
        {
192
                if (ino == ncp_info_ino(server, this))
193
                {
194
                        return this;
195
                }
196
                this = this->next;
197
        }
198
        while (this != root);
199
 
200
        return NULL;
201
}
202
 
203
static int
204
ncp_dir_read(struct inode *inode, struct file *filp, char *buf, int count)
205
{
206
        return -EISDIR;
207
}
208
 
209
static kdev_t             c_dev = 0;
210
static unsigned long      c_ino = 0;
211
static int                c_size;
212
static int                c_seen_eof;
213
static int                c_last_returned_index;
214
static struct ncp_dirent* c_entry = NULL;
215
static int                c_lock = 0;
216
static struct wait_queue *c_wait = NULL;
217
 
218
static inline void
219
ncp_lock_dircache(void)
220
{
221
        while (c_lock)
222
                sleep_on(&c_wait);
223
        c_lock = 1;
224
}
225
 
226
static inline void
227
ncp_unlock_dircache(void)
228
{
229
        c_lock = 0;
230
        wake_up(&c_wait);
231
}
232
 
233
static int
234
ncp_readdir(struct inode *inode, struct file *filp,
235
            void *dirent, filldir_t filldir)
236
{
237
        int result = 0;
238
        int i = 0;
239
        int index = 0;
240
        struct ncp_dirent *entry = NULL;
241
        struct ncp_server *server = NCP_SERVER(inode);
242
        struct ncp_inode_info *dir = NCP_INOP(inode);
243
 
244
        DDPRINTK("ncp_readdir: filp->f_pos = %d\n", (int)filp->f_pos);
245
        DDPRINTK("ncp_readdir: inode->i_ino = %ld, c_ino = %ld\n",
246
                 inode->i_ino, c_ino);
247
 
248
        if (!inode || !S_ISDIR(inode->i_mode))
249
        {
250
                printk("ncp_readdir: inode is NULL or not a directory\n");
251
                return -EBADF;
252
        }
253
 
254
        if (!ncp_conn_valid(server))
255
        {
256
                return -EIO;
257
        }
258
 
259
        ncp_lock_dircache();
260
 
261
        if (c_entry == NULL)
262
        {
263
                i = sizeof (struct ncp_dirent) * NCP_READDIR_CACHE_SIZE;
264
                c_entry = (struct ncp_dirent *) vmalloc(i);
265
                if (c_entry == NULL)
266
                {
267
                        printk("ncp_readdir: no MEMORY for cache\n");
268
                        result = -ENOMEM;
269
                        goto finished;
270
                }
271
        }
272
 
273
        if (filp->f_pos == 0)
274
        {
275
                ncp_invalid_dir_cache(inode);
276
                if (filldir(dirent,".",1, filp->f_pos,
277
                            ncp_info_ino(server, dir)) < 0)
278
                {
279
                        goto finished;
280
                }
281
                filp->f_pos += 1;
282
        }
283
 
284
        if (filp->f_pos == 1)
285
        {
286
                if (filldir(dirent,"..",2, filp->f_pos,
287
                            ncp_info_ino(server, dir->dir)) < 0)
288
                {
289
                        goto finished;
290
                }
291
                filp->f_pos += 1;
292
        }
293
 
294
        if ((inode->i_dev == c_dev) && (inode->i_ino == c_ino))
295
        {
296
                for (i = 0; i < c_size; i++)
297
                {
298
                        if (filp->f_pos == c_entry[i].f_pos)
299
                        {
300
                                entry = &c_entry[i];
301
                                c_last_returned_index = i;
302
                                index = i;
303
                                break;
304
                        }
305
                }
306
                if ((entry == NULL) && c_seen_eof)
307
                {
308
                        goto finished;
309
                }
310
        }
311
 
312
        if (entry == NULL)
313
        {
314
                int entries;
315
                DDPRINTK("ncp_readdir: Not found in cache.\n");
316
 
317
                if (ncp_is_server_root(inode))
318
                {
319
                        entries = ncp_read_volume_list(server, filp->f_pos,
320
                                                       NCP_READDIR_CACHE_SIZE);
321
                        DPRINTK("ncp_read_volume_list returned %d\n", entries);
322
 
323
                }
324
                else
325
                {
326
                        entries = ncp_do_readdir(server, inode, filp->f_pos,
327
                                                 NCP_READDIR_CACHE_SIZE,
328
                                                 c_entry);
329
                        DPRINTK("ncp_readdir returned %d\n", entries);
330
                }
331
 
332
                if (entries < 0)
333
                {
334
                        c_dev = 0;
335
                        c_ino = 0;
336
                        result = entries;
337
                        goto finished;
338
                }
339
 
340
                if (entries > 0)
341
                {
342
                        c_seen_eof = (entries < NCP_READDIR_CACHE_SIZE);
343
                        c_dev  = inode->i_dev;
344
                        c_ino  = inode->i_ino;
345
                        c_size = entries;
346
                        entry = c_entry;
347
                        c_last_returned_index = 0;
348
                        index = 0;
349
 
350
                        if (!ncp_preserve_case(inode))
351
                        {
352
                                for (i = 0; i < c_size; i++)
353
                                {
354
                                        str_lower(c_entry[i].i.entryName);
355
                                }
356
                        }
357
                }
358
        }
359
 
360
        if (entry == NULL)
361
        {
362
                /* Nothing found, even from a ncp call */
363
                goto finished;
364
        }
365
 
366
        while (index < c_size)
367
        {
368
                ino_t ino;
369
 
370
                if (ncp_single_volume(server))
371
                {
372
                        ino = (ino_t)(entry->i.dirEntNum);
373
                }
374
                else
375
                {
376
                        /* For getwd() we have to return the correct
377
                         * inode in d_ino if the inode is currently in
378
                         * use. Otherwise the inode number does not
379
                         * matter. (You can argue a lot about this..) */
380
                        struct ncp_inode_info *ino_info;
381
                        ino_info = ncp_find_dir_inode(inode,
382
                                                      entry->i.entryName);
383
 
384
                        /* Some programs seem to be confused about a
385
                         * zero inode number, so we set it to one.
386
                         * Thanks to Gordon Chaffee for this one. */
387
                        if (ino_info == NULL)
388
                        {
389
                                ino_info = (struct ncp_inode_info *) 1;
390
                        }
391
                        ino = (ino_t)(ino_info);
392
                }
393
 
394
                DDPRINTK("ncp_readdir: entry->path= %s\n", entry->i.entryName);
395
                DDPRINTK("ncp_readdir: entry->f_pos = %ld\n", entry->f_pos);
396
 
397
                if (filldir(dirent, entry->i.entryName, entry->i.nameLen,
398
                            entry->f_pos, ino) < 0)
399
                {
400
                        break;
401
                }
402
 
403
                if (   (inode->i_dev != c_dev)
404
                    || (inode->i_ino != c_ino)
405
                    || (entry->f_pos != filp->f_pos))
406
                {
407
                        /* Someone has destroyed the cache while we slept
408
                           in filldir */
409
                        break;
410
                }
411
                filp->f_pos += 1;
412
                index += 1;
413
                entry += 1;
414
        }
415
 finished:
416
        ncp_unlock_dircache();
417
        return result;
418
}
419
 
420
static int
421
ncp_read_volume_list(struct ncp_server *server, int fpos, int cache_size)
422
{
423
        struct ncp_dirent *entry = c_entry;
424
 
425
        int total_count = 2;
426
        int i;
427
 
428
#if 1
429
        if (fpos < 2)
430
        {
431
                printk("OOPS, we expect fpos >= 2");
432
                fpos = 2;
433
        }
434
#endif
435
 
436
        for (i=0; i<NCP_NUMBER_OF_VOLUMES; i++)
437
        {
438
                struct ncp_volume_info info;
439
 
440
                if (ncp_get_volume_info_with_number(server, i, &info) != 0)
441
                {
442
                        return (total_count - fpos);
443
                }
444
 
445
                if (strlen(info.volume_name) > 0)
446
                {
447
                        if (total_count < fpos)
448
                        {
449
                                DPRINTK("ncp_read_volumes: skipped vol: %s\n",
450
                                        info.volume_name);
451
                        }
452
                        else if (total_count >= fpos + cache_size)
453
                        {
454
                                return (total_count - fpos);
455
                        }
456
                        else
457
                        {
458
                                DPRINTK("ncp_read_volumes: found vol: %s\n",
459
                                        info.volume_name);
460
 
461
                                if (ncp_lookup_volume(server,
462
                                                      info.volume_name,
463
                                                      &(entry->i)) != 0)
464
                                {
465
                                        DPRINTK("ncpfs: could not lookup vol "
466
                                                "%s\n", info.volume_name);
467
                                        continue;
468
                                }
469
 
470
                                entry->f_pos = total_count;
471
                                entry += 1;
472
                        }
473
                        total_count += 1;
474
                }
475
        }
476
        return (total_count - fpos);
477
}
478
 
479
static int
480
ncp_do_readdir(struct ncp_server *server, struct inode *dir, int fpos,
481
               int cache_size, struct ncp_dirent *entry)
482
{
483
        static struct nw_search_sequence seq;
484
        static struct inode *last_dir;
485
        static int total_count;
486
 
487
#if 1
488
        if (fpos < 2)
489
        {
490
                printk("OOPS, we expect fpos >= 2");
491
                fpos = 2;
492
        }
493
#endif
494
        DPRINTK("ncp_do_readdir: fpos = %d\n", fpos);
495
 
496
        if (fpos == 2)
497
        {
498
                last_dir = NULL;
499
                total_count = 2;
500
        }
501
 
502
        if ((fpos != total_count) || (dir != last_dir))
503
        {
504
                total_count = 2;
505
                last_dir = dir;
506
 
507
                DPRINTK("ncp_do_readdir: re-used seq for %s\n",
508
                        NCP_ISTRUCT(dir)->entryName);
509
 
510
                if (ncp_initialize_search(server, NCP_ISTRUCT(dir), &seq)!=0)
511
                {
512
                        DPRINTK("ncp_init_search failed\n");
513
                        return total_count - fpos;
514
                }
515
        }
516
 
517
        while (total_count < fpos + cache_size)
518
        {
519
                if (ncp_search_for_file_or_subdir(server, &seq,
520
                                                  &(entry->i)) != 0)
521
                {
522
                        return total_count - fpos;
523
                }
524
 
525
                if (total_count < fpos)
526
                {
527
                        DPRINTK("ncp_do_readdir: skipped file: %s\n",
528
                                entry->i.entryName);
529
                }
530
                else
531
                {
532
                        DDPRINTK("ncp_do_r: file: %s, f_pos=%d,total_count=%d",
533
                                 entry->i.entryName, fpos, total_count);
534
                        entry->s = seq;
535
                        entry->f_pos = total_count;
536
                        entry += 1;
537
                }
538
                total_count += 1;
539
        }
540
        return (total_count - fpos);
541
}
542
 
543
void
544
ncp_init_dir_cache(void)
545
{
546
        c_dev   = 0;
547
        c_ino   = 0;
548
        c_entry = NULL;
549
}
550
 
551
void
552
ncp_invalid_dir_cache(struct inode *ino)
553
{
554
        if ((ino->i_dev == c_dev) && (ino->i_ino == c_ino))
555
        {
556
                c_dev = 0;
557
                c_ino = 0;
558
                c_seen_eof = 0;
559
        }
560
}
561
 
562
void
563
ncp_free_dir_cache(void)
564
{
565
        DPRINTK("ncp_free_dir_cache: enter\n");
566
 
567
        if (c_entry == NULL)
568
        {
569
                return;
570
        }
571
 
572
        vfree(c_entry);
573
        c_entry = NULL;
574
 
575
        DPRINTK("ncp_free_dir_cache: exit\n");
576
}
577
 
578
 
579
static struct inode *
580
ncp_iget(struct inode *dir, struct nw_file_info *finfo)
581
{
582
        struct inode *inode;
583
        struct ncp_inode_info *new_inode_info;
584
        struct ncp_inode_info *root;
585
 
586
        if (dir == NULL)
587
        {
588
                printk("ncp_iget: dir is NULL\n");
589
                return NULL;
590
        }
591
 
592
        if (finfo == NULL)
593
        {
594
                printk("ncp_iget: finfo is NULL\n");
595
                return NULL;
596
        }
597
 
598
        new_inode_info = ncp_kmalloc(sizeof(struct ncp_inode_info),
599
                                     GFP_KERNEL);
600
 
601
        if (new_inode_info == NULL)
602
        {
603
                printk("ncp_iget: could not alloc mem for %s\n",
604
                       finfo->i.entryName);
605
                return NULL;
606
        }
607
 
608
        new_inode_info->state = NCP_INODE_LOOKED_UP;
609
        new_inode_info->nused = 0;
610
        new_inode_info->dir   = NCP_INOP(dir);
611
        new_inode_info->finfo = *finfo;
612
 
613
        NCP_INOP(dir)->nused += 1;
614
 
615
        /* We have to link the new inode_info into the doubly linked
616
           list of inode_infos to make a complete linear search
617
           possible. */
618
 
619
        root = &(NCP_SERVER(dir)->root);
620
 
621
        new_inode_info->prev = root;
622
        new_inode_info->next = root->next;
623
        root->next->prev = new_inode_info;
624
        root->next = new_inode_info;
625
 
626
        if (!(inode = iget(dir->i_sb, ncp_info_ino(NCP_SERVER(dir),
627
                                                   new_inode_info))))
628
        {
629
                printk("ncp_iget: iget failed!");
630
                return NULL;
631
        }
632
 
633
        return inode;
634
}
635
 
636
void
637
ncp_free_inode_info(struct ncp_inode_info *i)
638
{
639
        if (i == NULL)
640
        {
641
                printk("ncp_free_inode: i == NULL\n");
642
                return;
643
        }
644
 
645
        i->state = NCP_INODE_CACHED;
646
        while ((i->nused == 0) && (i->state == NCP_INODE_CACHED))
647
        {
648
                struct ncp_inode_info *dir = i->dir;
649
 
650
                i->next->prev = i->prev;
651
                i->prev->next = i->next;
652
 
653
                DDPRINTK("ncp_free_inode_info: freeing %s\n",
654
                         i->finfo.i.entryName);
655
 
656
                ncp_kfree_s(i, sizeof(struct ncp_inode_info));
657
 
658
                if (dir == i) return;
659
 
660
                (dir->nused)--;
661
                i = dir;
662
        }
663
}
664
 
665
void
666
ncp_init_root(struct ncp_server *server)
667
{
668
        struct ncp_inode_info *root = &(server->root);
669
        struct nw_info_struct *i = &(root->finfo.i);
670
        unsigned short dummy;
671
 
672
        DPRINTK("ncp_init_root: server %s\n", server->m.server_name);
673
        DPRINTK("ncp_init_root: i = %x\n", (int)i);
674
 
675
        root->finfo.opened = 0;
676
        i->attributes  = aDIR;
677
        i->dataStreamSize = 1024;
678
        i->dirEntNum = i->DosDirNum = 0;
679
        i->volNumber = NCP_NUMBER_OF_VOLUMES+1; /* illegal volnum */
680
        ncp_date_unix2dos(0, &(i->creationTime), &(i->creationDate));
681
        ncp_date_unix2dos(0, &(i->modifyTime), &(i->modifyDate));
682
        ncp_date_unix2dos(0, &dummy, &(i->lastAccessDate));
683
        i->nameLen = 0;
684
        i->entryName[0] = '\0';
685
 
686
        root->state = NCP_INODE_LOOKED_UP;
687
        root->nused = 1;
688
        root->dir   = root;
689
        root->next = root->prev = root;
690
        return;
691
}
692
 
693
int
694
ncp_conn_logged_in(struct ncp_server *server)
695
{
696
        if (server->m.mounted_vol[0] == '\0')
697
        {
698
                return 0;
699
        }
700
 
701
        str_upper(server->m.mounted_vol);
702
        if (ncp_lookup_volume(server, server->m.mounted_vol,
703
                              &(server->root.finfo.i)) != 0)
704
        {
705
                return -ENOENT;
706
        }
707
        str_lower(server->root.finfo.i.entryName);
708
 
709
        return 0;
710
}
711
 
712
void
713
ncp_free_all_inodes(struct ncp_server *server)
714
{
715
        /* Here nothing should be to do. I do not know whether it's
716
           better to leave some memory allocated or be stuck in an
717
           endless loop */
718
#if 1
719
        struct ncp_inode_info *root = &(server->root);
720
 
721
        if (root->next != root)
722
        {
723
                printk("ncp_free_all_inodes: INODES LEFT!!!\n");
724
        }
725
 
726
        while (root->next != root)
727
        {
728
                printk("ncp_free_all_inodes: freeing inode\n");
729
                ncp_free_inode_info(root->next);
730
                /* In case we have an endless loop.. */
731
                schedule();
732
        }
733
#endif        
734
 
735
        return;
736
}
737
 
738
/* We will search the inode that belongs to this name, currently by a
739
   complete linear search through the inodes belonging to this
740
   filesystem. This has to be fixed. */
741
static struct ncp_inode_info *
742
ncp_find_dir_inode(struct inode *dir, const char *name)
743
{
744
        struct ncp_server *server = NCP_SERVER(dir);
745
        struct nw_info_struct *dir_info = NCP_ISTRUCT(dir);
746
        struct ncp_inode_info *result = &(server->root);
747
 
748
        if (name == NULL)
749
        {
750
                return NULL;
751
        }
752
 
753
        do
754
        {
755
                if (   (result->dir->finfo.i.dirEntNum == dir_info->dirEntNum)
756
                    && (result->dir->finfo.i.volNumber == dir_info->volNumber)
757
                    && (strcmp(result->finfo.i.entryName, name) == 0)
758
                    /* The root dir is never looked up using this
759
                     * routine.  Without the following test a root
760
                     * directory 'sys' in a volume named 'sys' could
761
                     * never be looked up, because
762
                     * server->root->dir==server->root. */
763
                    && (result != &(server->root)))
764
                {
765
                        return result;
766
                }
767
                result = result->next;
768
 
769
        }
770
        while (result != &(server->root));
771
 
772
        return NULL;
773
}
774
 
775
static int
776
ncp_lookup(struct inode *dir, const char *__name, int len,
777
           struct inode **result)
778
{
779
        struct nw_file_info finfo;
780
        struct ncp_server *server;
781
        struct ncp_inode_info *result_info;
782
        int found_in_cache;
783
        int down_case = 0;
784
        char name[len+1];
785
 
786
        *result = NULL;
787
 
788
        if (!dir || !S_ISDIR(dir->i_mode))
789
        {
790
                printk("ncp_lookup: inode is NULL or not a directory.\n");
791
                iput(dir);
792
                return -ENOENT;
793
        }
794
 
795
        server = NCP_SERVER(dir);
796
 
797
        if (!ncp_conn_valid(server))
798
        {
799
                iput(dir);
800
                return -EIO;
801
        }
802
 
803
        DPRINTK("ncp_lookup: %s, len %d\n", __name, len);
804
 
805
        /* Fast cheat for . */
806
        if (len == 0 || (len == 1 && __name[0] == '.'))
807
        {
808
                *result = dir;
809
                return 0;
810
        }
811
 
812
        /* ..and for .. */
813
        if (len == 2 && __name[0] == '.' && __name[1] == '.')
814
        {
815
                struct ncp_inode_info *parent = NCP_INOP(dir)->dir;
816
 
817
                if (parent->state == NCP_INODE_CACHED)
818
                {
819
                        parent->state = NCP_INODE_LOOKED_UP;
820
                }
821
 
822
                *result = iget(dir->i_sb, ncp_info_ino(server, parent));
823
                iput(dir);
824
                if (*result == 0)
825
                {
826
                        return -EACCES;
827
                }
828
                else
829
                {
830
                        return 0;
831
                }
832
        }
833
 
834
        memcpy(name, __name, len);
835
        name[len] = 0;
836
        lock_super(dir->i_sb);
837
        result_info = ncp_find_dir_inode(dir, name);
838
 
839
        if (result_info != 0)
840
        {
841
                if (result_info->state == NCP_INODE_CACHED)
842
                {
843
                        result_info->state = NCP_INODE_LOOKED_UP;
844
                }
845
 
846
                /* Here we convert the inode_info address into an
847
                   inode number */
848
 
849
                *result = iget(dir->i_sb, ncp_info_ino(server, result_info));
850
                unlock_super(dir->i_sb);
851
                iput(dir);
852
 
853
                if (*result == NULL)
854
                {
855
                        return -EACCES;
856
                }
857
 
858
                return 0;
859
        }
860
 
861
        /* If the file is in the dir cache, we do not have to ask the
862
           server. */
863
 
864
        found_in_cache = 0;
865
        ncp_lock_dircache();
866
 
867
        if ((dir->i_dev == c_dev) && (dir->i_ino == c_ino))
868
        {
869
                int first = c_last_returned_index;
870
                int i;
871
 
872
                i = first;
873
                do
874
                {
875
                        DDPRINTK("ncp_lookup: trying index: %d, name: %s\n",
876
                                 i, c_entry[i].i.entryName);
877
 
878
                        if (strcmp(c_entry[i].i.entryName, name) == 0)
879
                        {
880
                                DPRINTK("ncp_lookup: found in cache!\n");
881
                                finfo.i = c_entry[i].i;
882
                                found_in_cache = 1;
883
                                break;
884
                        }
885
                        i = (i + 1) % c_size;
886
                }
887
                while (i != first);
888
        }
889
        ncp_unlock_dircache();
890
 
891
        if (found_in_cache == 0)
892
        {
893
                int res;
894
 
895
                DDPRINTK("ncp_lookup: do_lookup on %s/%s\n",
896
                         NCP_ISTRUCT(dir)->entryName, name);
897
 
898
                if (ncp_is_server_root(dir))
899
                {
900
                        str_upper(name);
901
                        down_case = 1;
902
                        res = ncp_lookup_volume(server, name, &(finfo.i));
903
                }
904
                else
905
                {
906
                        if (!ncp_preserve_case(dir))
907
                        {
908
                                str_upper(name);
909
                                down_case = 1;
910
                        }
911
                        res = ncp_obtain_info(server,
912
                                              NCP_ISTRUCT(dir)->volNumber,
913
                                              NCP_ISTRUCT(dir)->dirEntNum,
914
                                              name, &(finfo.i));
915
                }
916
                if (res != 0)
917
                {
918
                        unlock_super(dir->i_sb);
919
                        iput(dir);
920
                        return -ENOENT;
921
                }
922
        }
923
 
924
        finfo.opened = 0;
925
 
926
        if (down_case != 0)
927
        {
928
                str_lower(finfo.i.entryName);
929
        }
930
 
931
        if (!(*result = ncp_iget(dir, &finfo)))
932
        {
933
                unlock_super(dir->i_sb);
934
                iput(dir);
935
                return -EACCES;
936
        }
937
 
938
        unlock_super(dir->i_sb);
939
        iput(dir);
940
        return 0;
941
}
942
 
943
static int
944
ncp_create(struct inode *dir, const char *name, int len, int mode,
945
           struct inode **result)
946
{
947
        struct nw_file_info finfo;
948
        __u8 _name[len+1];
949
        int error;
950
 
951
        *result = NULL;
952
 
953
        if (!dir || !S_ISDIR(dir->i_mode))
954
        {
955
                printk("ncp_create: inode is NULL or not a directory\n");
956
                iput(dir);
957
                return -ENOENT;
958
        }
959
        if (!ncp_conn_valid(NCP_SERVER(dir)))
960
        {
961
                iput(dir);
962
                return -EIO;
963
        }
964
 
965
        strncpy(_name, name, len);
966
        _name[len] = '\0';
967
 
968
        if (!ncp_preserve_case(dir))
969
        {
970
                str_upper(_name);
971
        }
972
 
973
        lock_super(dir->i_sb);
974
        if ((error = ncp_open_create_file_or_subdir(NCP_SERVER(dir),
975
                                           NCP_ISTRUCT(dir), _name,
976
                                           OC_MODE_CREATE|OC_MODE_OPEN|
977
                                           OC_MODE_REPLACE,
978
                                           0, AR_READ|AR_WRITE,
979
                                           &finfo)) != 0)
980
        {
981
                unlock_super(dir->i_sb);
982
                iput(dir);
983
                if (error == 0x87) {
984
                        return -ENAMETOOLONG;
985
                }
986
                return -EACCES;
987
        }
988
 
989
        ncp_invalid_dir_cache(dir);
990
 
991
        if (!ncp_preserve_case(dir))
992
        {
993
                str_lower(finfo.i.entryName);
994
        }
995
 
996
        finfo.access = O_RDWR;
997
 
998
        if (!(*result = ncp_iget(dir, &finfo)) < 0)
999
        {
1000
                ncp_close_file(NCP_SERVER(dir), finfo.file_handle);
1001
                unlock_super(dir->i_sb);
1002
                iput(dir);
1003
                return -EINVAL;
1004
        }
1005
 
1006
        unlock_super(dir->i_sb);
1007
        iput(dir);
1008
        return 0;
1009
}
1010
 
1011
static int
1012
ncp_mkdir(struct inode *dir, const char *name, int len, int mode)
1013
{
1014
        int error;
1015
        struct nw_file_info new_dir;
1016
        __u8 _name[len+1];
1017
 
1018
        if (   (name[0] == '.')
1019
            && (   (len == 1)
1020
                || (   (len == 2)
1021
                    && (name[1] == '.'))))
1022
        {
1023
                iput(dir);
1024
                return -EEXIST;
1025
        }
1026
 
1027
        strncpy(_name, name, len);
1028
        _name[len] = '\0';
1029
 
1030
        if (!ncp_preserve_case(dir))
1031
        {
1032
                str_upper(_name);
1033
        }
1034
 
1035
        if (!dir || !S_ISDIR(dir->i_mode))
1036
        {
1037
                printk("ncp_mkdir: inode is NULL or not a directory\n");
1038
                iput(dir);
1039
                return -ENOENT;
1040
        }
1041
        if (!ncp_conn_valid(NCP_SERVER(dir)))
1042
        {
1043
                iput(dir);
1044
                return -EIO;
1045
        }
1046
 
1047
        if (ncp_open_create_file_or_subdir(NCP_SERVER(dir),
1048
                                           NCP_ISTRUCT(dir), _name,
1049
                                           OC_MODE_CREATE, aDIR, 0xffff,
1050
                                           &new_dir) != 0)
1051
        {
1052
                error = -EACCES;
1053
        }
1054
        else
1055
        {
1056
                error = 0;
1057
                ncp_invalid_dir_cache(dir);
1058
        }
1059
 
1060
        iput(dir);
1061
        return error;
1062
}
1063
 
1064
static int
1065
ncp_rmdir(struct inode *dir, const char *name, int len)
1066
{
1067
        int error;
1068
        __u8 _name[len+1];
1069
 
1070
        if (!dir || !S_ISDIR(dir->i_mode))
1071
        {
1072
                printk("ncp_rmdir: inode is NULL or not a directory\n");
1073
                iput(dir);
1074
                return -ENOENT;
1075
        }
1076
        if (!ncp_conn_valid(NCP_SERVER(dir)))
1077
        {
1078
                iput(dir);
1079
                return -EIO;
1080
        }
1081
        if (ncp_find_dir_inode(dir, name) != NULL)
1082
        {
1083
                error = -EBUSY;
1084
        }
1085
        else
1086
        {
1087
 
1088
                strncpy(_name, name, len);
1089
                _name[len] = '\0';
1090
 
1091
                if (!ncp_preserve_case(dir))
1092
                {
1093
                        str_upper(_name);
1094
                }
1095
 
1096
                if ((error = ncp_del_file_or_subdir(NCP_SERVER(dir),
1097
                                                    NCP_ISTRUCT(dir),
1098
                                                    _name)) == 0)
1099
                {
1100
                        ncp_invalid_dir_cache(dir);
1101
                }
1102
                else
1103
                {
1104
                        error = -EACCES;
1105
                }
1106
        }
1107
        iput(dir);
1108
        return error;
1109
}
1110
 
1111
 
1112
#ifdef CONFIG_NCPFS_STRONG
1113
/* try to delete a readonly file (NW R bit set) */
1114
 
1115
static int
1116
ncp_force_unlink(struct inode *dir,char *name,int len)
1117
{
1118
        int res=0x9c,res2;
1119
        struct inode *_inode;
1120
        struct iattr ia;
1121
 
1122
        /* remove the Read-Only flag on the NW server */
1123
 
1124
        dir->i_count++;
1125
        res2=ncp_lookup(dir,name,len,&_inode);
1126
        if (res2)
1127
        {
1128
                goto leave_me; /* abort operation */
1129
        }
1130
        memset(&ia,0,sizeof(struct iattr));
1131
        ia.ia_mode = _inode->i_mode;
1132
        ia.ia_mode |= NCP_SERVER(dir)->m.file_mode & 0222;  /* set write bits */
1133
        ia.ia_valid = ATTR_MODE;
1134
 
1135
        res2=ncp_notify_change(_inode,&ia);
1136
        if (res2)
1137
        {
1138
                iput(_inode);
1139
                goto leave_me;
1140
        }
1141
 
1142
        /* now try again the delete operation */
1143
 
1144
        res2 = ncp_del_file_or_subdir(NCP_SERVER(dir),NCP_ISTRUCT(dir),name);
1145
 
1146
        res=res2; /* save status to use as return value */
1147
 
1148
        res=res2;
1149
        if (res2)  /* delete failed, set R bit again */
1150
        {
1151
                memset(&ia,0,sizeof(struct iattr));
1152
                ia.ia_mode = _inode->i_mode;
1153
                ia.ia_mode &= ~(NCP_SERVER(dir)->m.file_mode & 0222);  /* clear write bits */
1154
                ia.ia_valid = ATTR_MODE;
1155
 
1156
                res2=ncp_notify_change(_inode,&ia);
1157
                if (res2)
1158
                {
1159
                        iput(_inode);
1160
                        goto leave_me;
1161
                }
1162
        }
1163
        iput(_inode);
1164
 
1165
 leave_me:
1166
        return(res);
1167
}
1168
#endif  /* CONFIG_NCPFS_STRONG */
1169
 
1170
static int
1171
ncp_unlink(struct inode *dir, const char *name, int len)
1172
{
1173
        int error;
1174
        __u8 _name[len+1];
1175
 
1176
        if (!dir || !S_ISDIR(dir->i_mode))
1177
        {
1178
                printk("ncp_unlink: inode is NULL or not a directory\n");
1179
                iput(dir);
1180
                return -ENOENT;
1181
        }
1182
        if (!ncp_conn_valid(NCP_SERVER(dir)))
1183
        {
1184
                iput(dir);
1185
                return -EIO;
1186
        }
1187
        if (ncp_find_dir_inode(dir, name) != NULL)
1188
        {
1189
                error = -EBUSY;
1190
        }
1191
        else
1192
        {
1193
                strncpy(_name, name, len);
1194
                _name[len] = '\0';
1195
 
1196
                if (!ncp_preserve_case(dir))
1197
                {
1198
                        str_upper(_name);
1199
                }
1200
 
1201
                error = ncp_del_file_or_subdir(NCP_SERVER(dir),
1202
                                               NCP_ISTRUCT(dir),
1203
                                               _name);
1204
#ifdef CONFIG_NCPFS_STRONG
1205
                if (error == 0x9c && NCP_SERVER(dir)->m.flags & NCP_MOUNT_STRONG)  /* readonly */
1206
                {
1207
                        error = ncp_force_unlink(dir,_name,len); /* special treatment */
1208
                }
1209
#endif  /* CONFIG_NCPFS_STRONG */
1210
 
1211
                if (error == 0) {
1212
                        ncp_invalid_dir_cache(dir);
1213
                } else if (error == 0xFF) {
1214
                        error = -ENOENT;
1215
                } else {
1216
                        error = -EACCES;
1217
                }
1218
        }
1219
        iput(dir);
1220
        return error;
1221
}
1222
 
1223
#ifdef CONFIG_NCPFS_STRONG
1224
static int
1225
ncp_force_rename(struct inode *old_dir, const char *old_name, char *_old_name, int old_len,
1226
                 struct inode *new_dir, const char *new_name, char *_new_name, int new_len)
1227
{
1228
        int res=0x90,res2;
1229
        char _rename_old[old_len+1];
1230
        char _rename_new[new_len+1];
1231
        struct inode *_inode,*x_dir;
1232
        struct iattr ia;
1233
 
1234
        strncpy(_rename_old,old_name,old_len);
1235
        _rename_old[old_len] = 0;
1236
        strncpy(_rename_new,new_name,new_len);
1237
        _rename_new[new_len] = 0;
1238
 
1239
        /* remove the Read-Only flag on the NW server */
1240
 
1241
        old_dir->i_count++;
1242
        res2=ncp_lookup(old_dir,_rename_old,old_len,&_inode);
1243
        if (res2)
1244
        {
1245
                goto leave_me;
1246
        }
1247
        memset(&ia,0,sizeof(struct iattr));
1248
        ia.ia_mode = _inode->i_mode;
1249
        ia.ia_mode |= NCP_SERVER(old_dir)->m.file_mode & 0222;  /* set write bits */
1250
        ia.ia_valid = ATTR_MODE;
1251
 
1252
        res2=ncp_notify_change(_inode,&ia);
1253
        if (res2)
1254
        {
1255
                iput(_inode);
1256
                goto leave_me;
1257
        }
1258
 
1259
        /* now try again the rename operation */
1260
        res2 = ncp_ren_or_mov_file_or_subdir(NCP_SERVER(old_dir),
1261
                                             NCP_ISTRUCT(old_dir), _old_name,
1262
                                             NCP_ISTRUCT(new_dir), _new_name);
1263
 
1264
        res=res2;
1265
        if (!res2)  /* rename succeeded, get a new inode for the new file */
1266
        {
1267
                x_dir=new_dir;
1268
                new_dir->i_count++;
1269
                iput(_inode);
1270
                res2=ncp_lookup(new_dir,_rename_new,new_len,&_inode);
1271
                if (res2)
1272
                {
1273
                        goto leave_me;
1274
                }
1275
        }
1276
        else
1277
        {
1278
                x_dir=old_dir;
1279
        }
1280
 
1281
        memset(&ia,0,sizeof(struct iattr));
1282
        ia.ia_mode = _inode->i_mode;
1283
        ia.ia_mode &= ~(NCP_SERVER(x_dir)->m.file_mode & 0222);  /* clear write bits */
1284
        ia.ia_valid = ATTR_MODE;
1285
 
1286
        res2=ncp_notify_change(_inode,&ia);
1287
        iput(_inode);
1288
        if (res2)
1289
        {
1290
                printk(KERN_INFO "ncpfs: ncp_notify_change (2) failed: %08x\n",res2);
1291
                goto leave_me;
1292
        }
1293
 
1294
 leave_me:
1295
        return(res);
1296
}
1297
#endif  /* CONFIG_NCPFS_STRONG */
1298
 
1299
 
1300
static int
1301
ncp_rename(struct inode *old_dir, const char *old_name, int old_len,
1302
           struct inode *new_dir, const char *new_name, int new_len,
1303
           int must_be_dir)
1304
{
1305
        int res;
1306
        char _old_name[old_len+1];
1307
        char _new_name[new_len+1];
1308
 
1309
        if (!old_dir || !S_ISDIR(old_dir->i_mode))
1310
        {
1311
                printk("ncp_rename: old inode is NULL or not a directory\n");
1312
                res = -ENOENT;
1313
                goto finished;
1314
        }
1315
 
1316
        if (!ncp_conn_valid(NCP_SERVER(old_dir)))
1317
        {
1318
                res = -EIO;
1319
                goto finished;
1320
        }
1321
 
1322
        if (!new_dir || !S_ISDIR(new_dir->i_mode))
1323
        {
1324
                printk("ncp_rename: new inode is NULL or not a directory\n");
1325
                res = -ENOENT;
1326
                goto finished;
1327
        }
1328
 
1329
        if (   (ncp_find_dir_inode(old_dir, old_name) != NULL)
1330
            || (ncp_find_dir_inode(new_dir, new_name) != NULL))
1331
        {
1332
                res = -EBUSY;
1333
                goto finished;
1334
        }
1335
 
1336
        strncpy(_old_name, old_name, old_len);
1337
        _old_name[old_len] = '\0';
1338
 
1339
        if (!ncp_preserve_case(old_dir))
1340
        {
1341
                str_upper(_old_name);
1342
        }
1343
 
1344
        strncpy(_new_name, new_name, new_len);
1345
        _new_name[new_len] = '\0';
1346
 
1347
        if (!ncp_preserve_case(new_dir))
1348
        {
1349
                str_upper(_new_name);
1350
        }
1351
 
1352
        res = ncp_ren_or_mov_file_or_subdir(NCP_SERVER(old_dir),
1353
                                            NCP_ISTRUCT(old_dir), _old_name,
1354
                                            NCP_ISTRUCT(new_dir), _new_name);
1355
 
1356
#ifdef CONFIG_NCPFS_STRONG
1357
        if (res == 0x90 && NCP_SERVER(old_dir)->m.flags & NCP_MOUNT_STRONG) /* file is readonly */
1358
        {
1359
                res=ncp_force_rename(old_dir,old_name,_old_name,old_len,new_dir,new_name,_new_name,new_len);
1360
        }
1361
#endif  /* CONFIG_NCPFS_STRONG */
1362
 
1363
        if (res == 0)
1364
        {
1365
                ncp_invalid_dir_cache(old_dir);
1366
                ncp_invalid_dir_cache(new_dir);
1367
        }
1368
        else
1369
        {
1370
                if (res == 0x9E)
1371
                        res = -ENAMETOOLONG;
1372
                else if (res == 0xFF)
1373
                        res = -ENOENT;
1374
                else
1375
                        res = -EACCES;
1376
        }
1377
 
1378
 finished:
1379
        iput(old_dir);
1380
        iput(new_dir);
1381
        return res;
1382
}
1383
 
1384
/* The following routines are taken directly from msdos-fs */
1385
 
1386
/* Linear day numbers of the respective 1sts in non-leap years. */
1387
 
1388
static int day_n[] = { 0,31,59,90,120,151,181,212,243,273,304,334,0,0,0,0 };
1389
                  /* JanFebMarApr May Jun Jul Aug Sep Oct Nov Dec */
1390
 
1391
 
1392
extern struct timezone sys_tz;
1393
 
1394
static int
1395
utc2local(int time)
1396
{
1397
        return time - sys_tz.tz_minuteswest*60 + sys_tz.tz_dsttime*3600;
1398
}
1399
 
1400
static int
1401
local2utc(int time)
1402
{
1403
        return time + sys_tz.tz_minuteswest*60 - sys_tz.tz_dsttime*3600;
1404
}
1405
 
1406
/* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70). */
1407
 
1408
int
1409
ncp_date_dos2unix(unsigned short time,unsigned short date)
1410
{
1411
        int month,year,secs;
1412
 
1413
        month = ((date >> 5) & 15)-1;
1414
        year = date >> 9;
1415
        secs = (time & 31)*2+60*((time >> 5) & 63)+(time >> 11)*3600+86400*
1416
            ((date & 31)-1+day_n[month]+(year/4)+year*365-((year & 3) == 0 &&
1417
            month < 2 ? 1 : 0)+3653);
1418
                        /* days since 1.1.70 plus 80's leap day */
1419
        return local2utc(secs);
1420
}
1421
 
1422
 
1423
/* Convert linear UNIX date to a MS-DOS time/date pair. */
1424
void
1425
ncp_date_unix2dos(int unix_date,unsigned short *time, unsigned short *date)
1426
{
1427
        int day,year,nl_day,month;
1428
 
1429
        unix_date = utc2local(unix_date);
1430
        *time = (unix_date % 60)/2+(((unix_date/60) % 60) << 5)+
1431
            (((unix_date/3600) % 24) << 11);
1432
        day = unix_date/86400-3652;
1433
        year = day/365;
1434
        if ((year+3)/4+365*year > day) year--;
1435
        day -= (year+3)/4+365*year;
1436
        if (day == 59 && !(year & 3)) {
1437
                nl_day = day;
1438
                month = 2;
1439
        }
1440
        else {
1441
                nl_day = (year & 3) || day <= 59 ? day : day-1;
1442
                for (month = 0; month < 12; month++)
1443
                        if (day_n[month] > nl_day) break;
1444
        }
1445
        *date = nl_day-day_n[month-1]+1+(month << 5)+(year << 9);
1446
}

powered by: WebSVN 2.1.0

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