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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [fs/] [smbfs/] [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 Paal-Kr. Engstad and Volker Lendecke
5
 *  Copyright (C) 1997 by Volker Lendecke
6
 *
7
 *  Please add a note about your changes to smbfs in the ChangeLog file.
8
 */
9
 
10
#include <linux/sched.h>
11
#include <linux/errno.h>
12
#include <linux/kernel.h>
13
#include <linux/smp_lock.h>
14
#include <linux/ctype.h>
15
 
16
#include <linux/smb_fs.h>
17
#include <linux/smb_mount.h>
18
#include <linux/smbno.h>
19
 
20
#include "smb_debug.h"
21
#include "proto.h"
22
 
23
static int smb_readdir(struct file *, void *, filldir_t);
24
static int smb_dir_open(struct inode *, struct file *);
25
 
26
static struct dentry *smb_lookup(struct inode *, struct dentry *);
27
static int smb_create(struct inode *, struct dentry *, int);
28
static int smb_mkdir(struct inode *, struct dentry *, int);
29
static int smb_rmdir(struct inode *, struct dentry *);
30
static int smb_unlink(struct inode *, struct dentry *);
31
static int smb_rename(struct inode *, struct dentry *,
32
                      struct inode *, struct dentry *);
33
static int smb_make_node(struct inode *,struct dentry *, int, int);
34
static int smb_link(struct dentry *, struct inode *, struct dentry *);
35
 
36
struct file_operations smb_dir_operations =
37
{
38
        read:           generic_read_dir,
39
        readdir:        smb_readdir,
40
        ioctl:          smb_ioctl,
41
        open:           smb_dir_open,
42
};
43
 
44
struct inode_operations smb_dir_inode_operations =
45
{
46
        create:         smb_create,
47
        lookup:         smb_lookup,
48
        unlink:         smb_unlink,
49
        mkdir:          smb_mkdir,
50
        rmdir:          smb_rmdir,
51
        rename:         smb_rename,
52
        revalidate:     smb_revalidate_inode,
53
        setattr:        smb_notify_change,
54
};
55
 
56
struct inode_operations smb_dir_inode_operations_unix =
57
{
58
        create:         smb_create,
59
        lookup:         smb_lookup,
60
        unlink:         smb_unlink,
61
        mkdir:          smb_mkdir,
62
        rmdir:          smb_rmdir,
63
        rename:         smb_rename,
64
        revalidate:     smb_revalidate_inode,
65
        setattr:        smb_notify_change,
66
        symlink:        smb_symlink,
67
        mknod:          smb_make_node,
68
        link:           smb_link,
69
};
70
 
71
/*
72
 * Read a directory, using filldir to fill the dirent memory.
73
 * smb_proc_readdir does the actual reading from the smb server.
74
 *
75
 * The cache code is almost directly taken from ncpfs
76
 */
77
static int
78
smb_readdir(struct file *filp, void *dirent, filldir_t filldir)
79
{
80
        struct dentry *dentry = filp->f_dentry;
81
        struct inode *dir = dentry->d_inode;
82
        struct smb_sb_info *server = server_from_dentry(dentry);
83
        union  smb_dir_cache *cache = NULL;
84
        struct smb_cache_control ctl;
85
        struct page *page = NULL;
86
        int result;
87
 
88
        ctl.page  = NULL;
89
        ctl.cache = NULL;
90
 
91
        VERBOSE("reading %s/%s, f_pos=%d\n",
92
                DENTRY_PATH(dentry),  (int) filp->f_pos);
93
 
94
        result = 0;
95
        switch ((unsigned int) filp->f_pos) {
96
        case 0:
97
                if (filldir(dirent, ".", 1, 0, dir->i_ino, DT_DIR) < 0)
98
                        goto out;
99
                filp->f_pos = 1;
100
                /* fallthrough */
101
        case 1:
102
                if (filldir(dirent, "..", 2, 1,
103
                            dentry->d_parent->d_inode->i_ino, DT_DIR) < 0)
104
                        goto out;
105
                filp->f_pos = 2;
106
        }
107
 
108
        /*
109
         * Make sure our inode is up-to-date.
110
         */
111
        result = smb_revalidate_inode(dentry);
112
        if (result)
113
                goto out;
114
 
115
 
116
        page = grab_cache_page(&dir->i_data, 0);
117
        if (!page)
118
                goto read_really;
119
 
120
        ctl.cache = cache = kmap(page);
121
        ctl.head  = cache->head;
122
 
123
        if (!Page_Uptodate(page) || !ctl.head.eof) {
124
                VERBOSE("%s/%s, page uptodate=%d, eof=%d\n",
125
                         DENTRY_PATH(dentry), Page_Uptodate(page),ctl.head.eof);
126
                goto init_cache;
127
        }
128
 
129
        if (filp->f_pos == 2) {
130
                if (jiffies - ctl.head.time >= SMB_MAX_AGE(server))
131
                        goto init_cache;
132
 
133
                /*
134
                 * N.B. ncpfs checks mtime of dentry too here, we don't.
135
                 *   1. common smb servers do not update mtime on dir changes
136
                 *   2. it requires an extra smb request
137
                 *      (revalidate has the same timeout as ctl.head.time)
138
                 *
139
                 * Instead smbfs invalidates its own cache on local changes
140
                 * and remote changes are not seen until timeout.
141
                 */
142
        }
143
 
144
        if (filp->f_pos > ctl.head.end)
145
                goto finished;
146
 
147
        ctl.fpos = filp->f_pos + (SMB_DIRCACHE_START - 2);
148
        ctl.ofs  = ctl.fpos / SMB_DIRCACHE_SIZE;
149
        ctl.idx  = ctl.fpos % SMB_DIRCACHE_SIZE;
150
 
151
        for (;;) {
152
                if (ctl.ofs != 0) {
153
                        ctl.page = find_lock_page(&dir->i_data, ctl.ofs);
154
                        if (!ctl.page)
155
                                goto invalid_cache;
156
                        ctl.cache = kmap(ctl.page);
157
                        if (!Page_Uptodate(ctl.page))
158
                                goto invalid_cache;
159
                }
160
                while (ctl.idx < SMB_DIRCACHE_SIZE) {
161
                        struct dentry *dent;
162
                        int res;
163
 
164
                        dent = smb_dget_fpos(ctl.cache->dentry[ctl.idx],
165
                                             dentry, filp->f_pos);
166
                        if (!dent)
167
                                goto invalid_cache;
168
 
169
                        res = filldir(dirent, dent->d_name.name,
170
                                      dent->d_name.len, filp->f_pos,
171
                                      dent->d_inode->i_ino, DT_UNKNOWN);
172
                        dput(dent);
173
                        if (res)
174
                                goto finished;
175
                        filp->f_pos += 1;
176
                        ctl.idx += 1;
177
                        if (filp->f_pos > ctl.head.end)
178
                                goto finished;
179
                }
180
                if (ctl.page) {
181
                        kunmap(ctl.page);
182
                        SetPageUptodate(ctl.page);
183
                        UnlockPage(ctl.page);
184
                        page_cache_release(ctl.page);
185
                        ctl.page = NULL;
186
                }
187
                ctl.idx  = 0;
188
                ctl.ofs += 1;
189
        }
190
invalid_cache:
191
        if (ctl.page) {
192
                kunmap(ctl.page);
193
                UnlockPage(ctl.page);
194
                page_cache_release(ctl.page);
195
                ctl.page = NULL;
196
        }
197
        ctl.cache = cache;
198
init_cache:
199
        smb_invalidate_dircache_entries(dentry);
200
        ctl.head.time = jiffies;
201
        ctl.head.eof = 0;
202
        ctl.fpos = 2;
203
        ctl.ofs = 0;
204
        ctl.idx = SMB_DIRCACHE_START;
205
        ctl.filled = 0;
206
        ctl.valid  = 1;
207
read_really:
208
        result = server->ops->readdir(filp, dirent, filldir, &ctl);
209
        if (ctl.idx == -1)
210
                goto invalid_cache;     /* retry */
211
        ctl.head.end = ctl.fpos - 1;
212
        ctl.head.eof = ctl.valid;
213
finished:
214
        if (page) {
215
                cache->head = ctl.head;
216
                kunmap(page);
217
                SetPageUptodate(page);
218
                UnlockPage(page);
219
                page_cache_release(page);
220
        }
221
        if (ctl.page) {
222
                kunmap(ctl.page);
223
                SetPageUptodate(ctl.page);
224
                UnlockPage(ctl.page);
225
                page_cache_release(ctl.page);
226
        }
227
out:
228
        return result;
229
}
230
 
231
static int
232
smb_dir_open(struct inode *dir, struct file *file)
233
{
234
        struct dentry *dentry = file->f_dentry;
235
        struct smb_sb_info *server;
236
        int error = 0;
237
 
238
        VERBOSE("(%s/%s)\n", dentry->d_parent->d_name.name,
239
                file->f_dentry->d_name.name);
240
 
241
        /*
242
         * Directory timestamps in the core protocol aren't updated
243
         * when a file is added, so we give them a very short TTL.
244
         */
245
        lock_kernel();
246
        server = server_from_dentry(dentry);
247
        if (server->opt.protocol < SMB_PROTOCOL_LANMAN2) {
248
                unsigned long age = jiffies - dir->u.smbfs_i.oldmtime;
249
                if (age > 2*HZ)
250
                        smb_invalid_dir_cache(dir);
251
        }
252
 
253
        /*
254
         * Note: in order to allow the smbmount process to open the
255
         * mount point, we only revalidate if the connection is valid or
256
         * if the process is trying to access something other than the root.
257
         */
258
        if (server->state == CONN_VALID || !IS_ROOT(dentry))
259
                error = smb_revalidate_inode(dentry);
260
        unlock_kernel();
261
        return error;
262
}
263
 
264
/*
265
 * Dentry operations routines
266
 */
267
static int smb_lookup_validate(struct dentry *, int);
268
static int smb_hash_dentry(struct dentry *, struct qstr *);
269
static int smb_compare_dentry(struct dentry *, struct qstr *, struct qstr *);
270
static int smb_delete_dentry(struct dentry *);
271
 
272
static struct dentry_operations smbfs_dentry_operations =
273
{
274
        d_revalidate:   smb_lookup_validate,
275
        d_hash:         smb_hash_dentry,
276
        d_compare:      smb_compare_dentry,
277
        d_delete:       smb_delete_dentry,
278
};
279
 
280
static struct dentry_operations smbfs_dentry_operations_case =
281
{
282
        d_revalidate:   smb_lookup_validate,
283
        d_delete:       smb_delete_dentry,
284
};
285
 
286
 
287
/*
288
 * This is the callback when the dcache has a lookup hit.
289
 */
290
static int
291
smb_lookup_validate(struct dentry * dentry, int flags)
292
{
293
        struct smb_sb_info *server = server_from_dentry(dentry);
294
        struct inode * inode = dentry->d_inode;
295
        unsigned long age = jiffies - dentry->d_time;
296
        int valid;
297
 
298
        /*
299
         * The default validation is based on dentry age:
300
         * we believe in dentries for a few seconds.  (But each
301
         * successful server lookup renews the timestamp.)
302
         */
303
        valid = (age <= SMB_MAX_AGE(server));
304
#ifdef SMBFS_DEBUG_VERBOSE
305
        if (!valid)
306
                VERBOSE("%s/%s not valid, age=%lu\n",
307
                        DENTRY_PATH(dentry), age);
308
#endif
309
 
310
        if (inode) {
311
                lock_kernel();
312
                if (is_bad_inode(inode)) {
313
                        PARANOIA("%s/%s has dud inode\n", DENTRY_PATH(dentry));
314
                        valid = 0;
315
                } else if (!valid)
316
                        valid = (smb_revalidate_inode(dentry) == 0);
317
                unlock_kernel();
318
        } else {
319
                /*
320
                 * What should we do for negative dentries?
321
                 */
322
        }
323
        return valid;
324
}
325
 
326
static int
327
smb_hash_dentry(struct dentry *dir, struct qstr *this)
328
{
329
        unsigned long hash;
330
        int i;
331
 
332
        hash = init_name_hash();
333
        for (i=0; i < this->len ; i++)
334
                hash = partial_name_hash(tolower(this->name[i]), hash);
335
        this->hash = end_name_hash(hash);
336
 
337
        return 0;
338
}
339
 
340
static int
341
smb_compare_dentry(struct dentry *dir, struct qstr *a, struct qstr *b)
342
{
343
        int i, result = 1;
344
 
345
        if (a->len != b->len)
346
                goto out;
347
        for (i=0; i < a->len; i++) {
348
                if (tolower(a->name[i]) != tolower(b->name[i]))
349
                        goto out;
350
        }
351
        result = 0;
352
out:
353
        return result;
354
}
355
 
356
/*
357
 * This is the callback from dput() when d_count is going to 0.
358
 * We use this to unhash dentries with bad inodes.
359
 */
360
static int
361
smb_delete_dentry(struct dentry * dentry)
362
{
363
        if (dentry->d_inode) {
364
                if (is_bad_inode(dentry->d_inode)) {
365
                        PARANOIA("bad inode, unhashing %s/%s\n",
366
                                 DENTRY_PATH(dentry));
367
                        return 1;
368
                }
369
        } else {
370
                /* N.B. Unhash negative dentries? */
371
        }
372
        return 0;
373
}
374
 
375
/*
376
 * Initialize a new dentry
377
 */
378
void
379
smb_new_dentry(struct dentry *dentry)
380
{
381
        struct smb_sb_info *server = server_from_dentry(dentry);
382
 
383
        if (server->mnt->flags & SMB_MOUNT_CASE)
384
                dentry->d_op = &smbfs_dentry_operations_case;
385
        else
386
                dentry->d_op = &smbfs_dentry_operations;
387
        dentry->d_time = jiffies;
388
}
389
 
390
 
391
/*
392
 * Whenever a lookup succeeds, we know the parent directories
393
 * are all valid, so we want to update the dentry timestamps.
394
 * N.B. Move this to dcache?
395
 */
396
void
397
smb_renew_times(struct dentry * dentry)
398
{
399
        for (;;) {
400
                dentry->d_time = jiffies;
401
                if (IS_ROOT(dentry))
402
                        break;
403
                dentry = dentry->d_parent;
404
        }
405
}
406
 
407
static struct dentry *
408
smb_lookup(struct inode *dir, struct dentry *dentry)
409
{
410
        struct smb_fattr finfo;
411
        struct inode *inode;
412
        int error;
413
        struct smb_sb_info *server;
414
 
415
        error = -ENAMETOOLONG;
416
        if (dentry->d_name.len > SMB_MAXNAMELEN)
417
                goto out;
418
 
419
        error = smb_proc_getattr(dentry, &finfo);
420
#ifdef SMBFS_PARANOIA
421
        if (error && error != -ENOENT)
422
                PARANOIA("find %s/%s failed, error=%d\n",
423
                         DENTRY_PATH(dentry), error);
424
#endif
425
 
426
        inode = NULL;
427
        if (error == -ENOENT)
428
                goto add_entry;
429
        if (!error) {
430
                error = -EACCES;
431
                finfo.f_ino = iunique(dentry->d_sb, 2);
432
                inode = smb_iget(dir->i_sb, &finfo);
433
                if (inode) {
434
        add_entry:
435
                        server = server_from_dentry(dentry);
436
                        if (server->mnt->flags & SMB_MOUNT_CASE)
437
                                dentry->d_op = &smbfs_dentry_operations_case;
438
                        else
439
                                dentry->d_op = &smbfs_dentry_operations;
440
 
441
                        d_add(dentry, inode);
442
                        smb_renew_times(dentry);
443
                        error = 0;
444
                }
445
        }
446
out:
447
        return ERR_PTR(error);
448
}
449
 
450
/*
451
 * This code is common to all routines creating a new inode.
452
 */
453
static int
454
smb_instantiate(struct dentry *dentry, __u16 fileid, int have_id)
455
{
456
        struct smb_sb_info *server = server_from_dentry(dentry);
457
        struct inode *inode;
458
        int error;
459
        struct smb_fattr fattr;
460
 
461
        VERBOSE("file %s/%s, fileid=%u\n", DENTRY_PATH(dentry), fileid);
462
 
463
        error = smb_proc_getattr(dentry, &fattr);
464
        if (error)
465
                goto out_close;
466
 
467
        smb_renew_times(dentry);
468
        fattr.f_ino = iunique(dentry->d_sb, 2);
469
        inode = smb_iget(dentry->d_sb, &fattr);
470
        if (!inode)
471
                goto out_no_inode;
472
 
473
        if (have_id) {
474
                inode->u.smbfs_i.fileid = fileid;
475
                inode->u.smbfs_i.access = SMB_O_RDWR;
476
                inode->u.smbfs_i.open = server->generation;
477
        }
478
        d_instantiate(dentry, inode);
479
out:
480
        return error;
481
 
482
out_no_inode:
483
        error = -EACCES;
484
out_close:
485
        if (have_id) {
486
                PARANOIA("%s/%s failed, error=%d, closing %u\n",
487
                         DENTRY_PATH(dentry), error, fileid);
488
                smb_close_fileid(dentry, fileid);
489
        }
490
        goto out;
491
}
492
 
493
/* N.B. How should the mode argument be used? */
494
static int
495
smb_create(struct inode *dir, struct dentry *dentry, int mode)
496
{
497
        struct smb_sb_info *server = server_from_dentry(dentry);
498
        __u16 fileid;
499
        int error;
500
        struct iattr attr;
501
 
502
        VERBOSE("creating %s/%s, mode=%d\n", DENTRY_PATH(dentry), mode);
503
 
504
        smb_invalid_dir_cache(dir);
505
        error = smb_proc_create(dentry, 0, CURRENT_TIME, &fileid);
506
        if (!error) {
507
                if (server->opt.capabilities & SMB_CAP_UNIX) {
508
                        /* Set attributes for new file */
509
                        attr.ia_valid = ATTR_MODE;
510
                        attr.ia_mode = mode;
511
                        error = smb_proc_setattr_unix(dentry, &attr, 0, 0);
512
                }
513
                error = smb_instantiate(dentry, fileid, 1);
514
        } else {
515
                PARANOIA("%s/%s failed, error=%d\n",
516
                         DENTRY_PATH(dentry), error);
517
        }
518
        return error;
519
}
520
 
521
/* N.B. How should the mode argument be used? */
522
static int
523
smb_mkdir(struct inode *dir, struct dentry *dentry, int mode)
524
{
525
        struct smb_sb_info *server = server_from_dentry(dentry);
526
        int error;
527
        struct iattr attr;
528
 
529
        smb_invalid_dir_cache(dir);
530
        error = smb_proc_mkdir(dentry);
531
        if (!error) {
532
                if (server->opt.capabilities & SMB_CAP_UNIX) {
533
                        /* Set attributes for new directory */
534
                        attr.ia_valid = ATTR_MODE;
535
                        attr.ia_mode = mode;
536
                        error = smb_proc_setattr_unix(dentry, &attr, 0, 0);
537
                }
538
                error = smb_instantiate(dentry, 0, 0);
539
        }
540
        return error;
541
}
542
 
543
static int
544
smb_rmdir(struct inode *dir, struct dentry *dentry)
545
{
546
        struct inode *inode = dentry->d_inode;
547
        int error;
548
 
549
        /*
550
         * Close the directory if it's open.
551
         */
552
        smb_close(inode);
553
 
554
        /*
555
         * Check that nobody else is using the directory..
556
         */
557
        error = -EBUSY;
558
        if (!d_unhashed(dentry))
559
                goto out;
560
 
561
        smb_invalid_dir_cache(dir);
562
        error = smb_proc_rmdir(dentry);
563
 
564
out:
565
        return error;
566
}
567
 
568
static int
569
smb_unlink(struct inode *dir, struct dentry *dentry)
570
{
571
        int error;
572
 
573
        /*
574
         * Close the file if it's open.
575
         */
576
        smb_close(dentry->d_inode);
577
 
578
        smb_invalid_dir_cache(dir);
579
        error = smb_proc_unlink(dentry);
580
        if (!error)
581
                smb_renew_times(dentry);
582
        return error;
583
}
584
 
585
static int
586
smb_rename(struct inode *old_dir, struct dentry *old_dentry,
587
           struct inode *new_dir, struct dentry *new_dentry)
588
{
589
        int error;
590
 
591
        /*
592
         * Close any open files, and check whether to delete the
593
         * target before attempting the rename.
594
         */
595
        if (old_dentry->d_inode)
596
                smb_close(old_dentry->d_inode);
597
        if (new_dentry->d_inode) {
598
                smb_close(new_dentry->d_inode);
599
                error = smb_proc_unlink(new_dentry);
600
                if (error) {
601
                        VERBOSE("unlink %s/%s, error=%d\n",
602
                                DENTRY_PATH(new_dentry), error);
603
                        goto out;
604
                }
605
                /* FIXME */
606
                d_delete(new_dentry);
607
        }
608
 
609
        smb_invalid_dir_cache(old_dir);
610
        smb_invalid_dir_cache(new_dir);
611
        error = smb_proc_mv(old_dentry, new_dentry);
612
        if (!error) {
613
                smb_renew_times(old_dentry);
614
                smb_renew_times(new_dentry);
615
        }
616
out:
617
        return error;
618
}
619
 
620
/*
621
 * FIXME: samba servers won't let you create device nodes unless uid/gid
622
 * matches the connection credentials (and we don't know which those are ...)
623
 */
624
static int
625
smb_make_node(struct inode *dir, struct dentry *dentry, int mode, int dev)
626
{
627
        int error;
628
        struct iattr attr;
629
 
630
        attr.ia_valid = ATTR_MODE | ATTR_UID | ATTR_GID;
631
        attr.ia_mode = mode;
632
        attr.ia_uid = current->euid;
633
        attr.ia_gid = current->egid;
634
 
635
        smb_invalid_dir_cache(dir);
636
        error = smb_proc_setattr_unix(dentry, &attr, MAJOR(dev), MINOR(dev));
637
        if (!error) {
638
                error = smb_instantiate(dentry, 0, 0);
639
        }
640
        return error;
641
}
642
 
643
/*
644
 * dentry = existing file
645
 * new_dentry = new file
646
 */
647
static int
648
smb_link(struct dentry *dentry, struct inode *dir, struct dentry *new_dentry)
649
{
650
        int error;
651
 
652
        DEBUG1("smb_link old=%s/%s new=%s/%s\n",
653
               DENTRY_PATH(dentry), DENTRY_PATH(new_dentry));
654
        smb_invalid_dir_cache(dir);
655
        error = smb_proc_link(server_from_dentry(dentry), dentry, new_dentry);
656
        if (!error) {
657
                smb_renew_times(dentry);
658
                error = smb_instantiate(new_dentry, 0, 0);
659
        }
660
        return error;
661
}

powered by: WebSVN 2.1.0

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