linux-old/fs/adfs/dir_fplus.c
<<
>>
Prefs
   1/*
   2 *  linux/fs/adfs/dir_fplus.c
   3 *
   4 *  Copyright (C) 1997-1999 Russell King
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License version 2 as
   8 * published by the Free Software Foundation.
   9 */
  10#include <linux/version.h>
  11#include <linux/errno.h>
  12#include <linux/fs.h>
  13#include <linux/adfs_fs.h>
  14#include <linux/sched.h>
  15#include <linux/stat.h>
  16#include <linux/spinlock.h>
  17
  18#include "adfs.h"
  19#include "dir_fplus.h"
  20
  21static int
  22adfs_fplus_read(struct super_block *sb, unsigned int id, unsigned int sz, struct adfs_dir *dir)
  23{
  24        struct adfs_bigdirheader *h;
  25        struct adfs_bigdirtail *t;
  26        unsigned long block;
  27        unsigned int blk, size;
  28        int i, ret = -EIO;
  29
  30        dir->nr_buffers = 0;
  31
  32        block = __adfs_block_map(sb, id, 0);
  33        if (!block) {
  34                adfs_error(sb, "dir object %X has a hole at offset 0", id);
  35                goto out;
  36        }
  37
  38        dir->bh[0] = sb_bread(sb, block);
  39        if (!dir->bh[0])
  40                goto out;
  41        dir->nr_buffers += 1;
  42
  43        h = (struct adfs_bigdirheader *)dir->bh[0]->b_data;
  44        size = le32_to_cpu(h->bigdirsize);
  45        if (size != sz) {
  46                printk(KERN_WARNING "adfs: adfs_fplus_read: directory header size\n"
  47                                " does not match directory size\n");
  48        }
  49
  50        if (h->bigdirversion[0] != 0 || h->bigdirversion[1] != 0 ||
  51            h->bigdirversion[2] != 0 || size & 2047 ||
  52            h->bigdirstartname != cpu_to_le32(BIGDIRSTARTNAME))
  53                goto out;
  54
  55        size >>= sb->s_blocksize_bits;
  56        for (blk = 1; blk < size; blk++) {
  57                block = __adfs_block_map(sb, id, blk);
  58                if (!block) {
  59                        adfs_error(sb, "dir object %X has a hole at offset %d", id, blk);
  60                        goto out;
  61                }
  62
  63                dir->bh[blk] = sb_bread(sb, block);
  64                if (!dir->bh[blk])
  65                        goto out;
  66                dir->nr_buffers = blk;
  67        }
  68
  69        t = (struct adfs_bigdirtail *)(dir->bh[size - 1]->b_data + (sb->s_blocksize - 8));
  70
  71        if (t->bigdirendname != cpu_to_le32(BIGDIRENDNAME) ||
  72            t->bigdirendmasseq != h->startmasseq ||
  73            t->reserved[0] != 0 || t->reserved[1] != 0)
  74                goto out;
  75
  76        dir->parent_id = le32_to_cpu(h->bigdirparent);
  77        dir->sb = sb;
  78        return 0;
  79out:
  80        for (i = 0; i < dir->nr_buffers; i++)
  81                brelse(dir->bh[i]);
  82        dir->sb = NULL;
  83        return ret;
  84}
  85
  86static int
  87adfs_fplus_setpos(struct adfs_dir *dir, unsigned int fpos)
  88{
  89        struct adfs_bigdirheader *h = (struct adfs_bigdirheader *)dir->bh[0]->b_data;
  90        int ret = -ENOENT;
  91
  92        if (fpos <= le32_to_cpu(h->bigdirentries)) {
  93                dir->pos = fpos;
  94                ret = 0;
  95        }
  96
  97        return ret;
  98}
  99
 100static void
 101dir_memcpy(struct adfs_dir *dir, unsigned int offset, void *to, int len)
 102{
 103        struct super_block *sb = dir->sb;
 104        unsigned int buffer, partial, remainder;
 105
 106        buffer = offset >> sb->s_blocksize_bits;
 107        offset &= sb->s_blocksize - 1;
 108
 109        partial = sb->s_blocksize - offset;
 110
 111        if (partial >= len)
 112                memcpy(to, dir->bh[buffer]->b_data + offset, len);
 113        else {
 114                char *c = (char *)to;
 115
 116                remainder = len - partial;
 117
 118                memcpy(c, dir->bh[buffer]->b_data + offset, partial);
 119                memcpy(c + partial, dir->bh[buffer + 1]->b_data, remainder);
 120        }
 121}
 122
 123static int
 124adfs_fplus_getnext(struct adfs_dir *dir, struct object_info *obj)
 125{
 126        struct adfs_bigdirheader *h = (struct adfs_bigdirheader *)dir->bh[0]->b_data;
 127        struct adfs_bigdirentry bde;
 128        unsigned int offset;
 129        int i, ret = -ENOENT;
 130
 131        if (dir->pos >= le32_to_cpu(h->bigdirentries))
 132                goto out;
 133
 134        offset = offsetof(struct adfs_bigdirheader, bigdirname);
 135        offset += ((le32_to_cpu(h->bigdirnamelen) + 4) & ~3);
 136        offset += dir->pos * sizeof(struct adfs_bigdirentry);
 137
 138        dir_memcpy(dir, offset, &bde, sizeof(struct adfs_bigdirentry));
 139
 140        obj->loadaddr = le32_to_cpu(bde.bigdirload);
 141        obj->execaddr = le32_to_cpu(bde.bigdirexec);
 142        obj->size     = le32_to_cpu(bde.bigdirlen);
 143        obj->file_id  = le32_to_cpu(bde.bigdirindaddr);
 144        obj->attr     = le32_to_cpu(bde.bigdirattr);
 145        obj->name_len = le32_to_cpu(bde.bigdirobnamelen);
 146
 147        offset = offsetof(struct adfs_bigdirheader, bigdirname);
 148        offset += ((le32_to_cpu(h->bigdirnamelen) + 4) & ~3);
 149        offset += le32_to_cpu(h->bigdirentries) * sizeof(struct adfs_bigdirentry);
 150        offset += le32_to_cpu(bde.bigdirobnameptr);
 151
 152        dir_memcpy(dir, offset, obj->name, obj->name_len);
 153        for (i = 0; i < obj->name_len; i++)
 154                if (obj->name[i] == '/')
 155                        obj->name[i] = '.';
 156
 157        dir->pos += 1;
 158        ret = 0;
 159out:
 160        return ret;
 161}
 162
 163static void
 164adfs_fplus_free(struct adfs_dir *dir)
 165{
 166        int i;
 167
 168        for (i = 0; i < dir->nr_buffers; i++)
 169                brelse(dir->bh[i]);
 170        dir->sb = NULL;
 171}
 172
 173struct adfs_dir_ops adfs_fplus_dir_ops = {
 174        adfs_fplus_read,
 175        adfs_fplus_setpos,
 176        adfs_fplus_getnext,
 177        NULL,
 178        NULL,
 179        NULL,
 180        adfs_fplus_free
 181};
 182
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.