Project

General

Profile

Statistics
| Branch: | Revision:

root / prex-0.9.0 / usr / server / fs / arfs / arfs_vnops.c @ 03e9c04a

History | View | Annotate | Download (8.37 KB)

1 03e9c04a Brad Neuman
/*
2
 * Copyright (c) 2006-2007, Kohsuke Ohtani
3
 * All rights reserved.
4
 *
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions
7
 * are met:
8
 * 1. Redistributions of source code must retain the above copyright
9
 *    notice, this list of conditions and the following disclaimer.
10
 * 2. Redistributions in binary form must reproduce the above copyright
11
 *    notice, this list of conditions and the following disclaimer in the
12
 *    documentation and/or other materials provided with the distribution.
13
 * 3. Neither the name of the author nor the names of any co-contributors
14
 *    may be used to endorse or promote products derived from this software
15
 *    without specific prior written permission.
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27
 * SUCH DAMAGE.
28
 */
29
30
/*
31
 * arfs_vnops.c - vnode operations for archive file system.
32
 */
33
34
/**
35
 * General design:
36
 *
37
 * ARFS (ARchive File System) is the read-only file system which
38
 * handles the generic archive (*.a) file as a file system image.
39
 * The file system is typically used for the boot time file system,
40
 * and it's mounted to the ram disk device mapped to the pre-loaded
41
 * archive file image. All files are placed in one single directory.
42
 */
43
44
#include <sys/prex.h>
45
#include <sys/stat.h>
46
#include <sys/vnode.h>
47
#include <sys/file.h>
48
#include <sys/mount.h>
49
#include <sys/param.h>
50
#include <sys/dirent.h>
51
#include <sys/buf.h>
52
53
#include <ctype.h>
54
#include <unistd.h>
55
#include <errno.h>
56
#include <string.h>
57
#include <stdlib.h>
58
#include <limits.h>
59
#include <fcntl.h>
60
#include <ar.h>
61
62
#include "arfs.h"
63
64
#define arfs_open        ((vnop_open_t)vop_nullop)
65
#define arfs_close        ((vnop_close_t)vop_nullop)
66
static int arfs_read        (vnode_t, file_t, void *, size_t, size_t *);
67
#define arfs_write        ((vnop_write_t)vop_nullop)
68
static int arfs_seek        (vnode_t, file_t, off_t, off_t);
69
#define arfs_ioctl        ((vnop_ioctl_t)vop_einval)
70
#define arfs_fsync        ((vnop_fsync_t)vop_nullop)
71
static int arfs_readdir        (vnode_t, file_t, struct dirent *);
72
static int arfs_lookup        (vnode_t, char *, vnode_t);
73
#define arfs_create        ((vnop_create_t)vop_einval)
74
#define arfs_remove        ((vnop_remove_t)vop_einval)
75
#define arfs_rename        ((vnop_rename_t)vop_einval)
76
#define arfs_mkdir        ((vnop_mkdir_t)vop_einval)
77
#define arfs_rmdir        ((vnop_rmdir_t)vop_einval)
78
#define arfs_getattr        ((vnop_getattr_t)vop_nullop)
79
#define arfs_setattr        ((vnop_setattr_t)vop_nullop)
80
#define arfs_inactive        ((vnop_inactive_t)vop_nullop)
81
#define arfs_truncate        ((vnop_truncate_t)vop_nullop)
82
83
static char iobuf[BSIZE*2];
84
85
#if CONFIG_FS_THREADS > 1
86
static mutex_t arfs_lock = MUTEX_INITIALIZER;
87
#endif
88
89
/*
90
 * vnode operations
91
 */
92
const struct vnops arfs_vnops = {
93
        arfs_open,                /* open */
94
        arfs_close,                /* close */
95
        arfs_read,                /* read */
96
        arfs_write,                /* write */
97
        arfs_seek,                /* seek */
98
        arfs_ioctl,                /* ioctl */
99
        arfs_fsync,                /* fsync */
100
        arfs_readdir,                /* readdir */
101
        arfs_lookup,                /* lookup */
102
        arfs_create,                /* create */
103
        arfs_remove,                /* remove */
104
        arfs_rename,                /* remame */
105
        arfs_mkdir,                /* mkdir */
106
        arfs_rmdir,                /* rmdir */
107
        arfs_getattr,                /* getattr */
108
        arfs_setattr,                /* setattr */
109
        arfs_inactive,                /* inactive */
110
        arfs_truncate,                /* truncate */
111
};
112
113
/*
114
 * Read blocks.
115
 * iobuf is filled by read data.
116
 */
117
static int
118
arfs_readblk(mount_t mp, int blkno)
119
{
120
        struct buf *bp;
121
        int error;
122
123
        /*
124
         * Read two blocks for archive header
125
         */
126
        if ((error = bread(mp->m_dev, blkno, &bp)) != 0)
127
                return error;
128
        memcpy(iobuf, bp->b_data, BSIZE);
129
        brelse(bp);
130
131
        if ((error = bread(mp->m_dev, blkno + 1, &bp)) != 0)
132
                return error;
133
        memcpy(iobuf + BSIZE, bp->b_data, BSIZE);
134
        brelse(bp);
135
136
        return 0;
137
}
138
139
/*
140
 * Lookup vnode for the specified file/directory.
141
 * The vnode is filled properly.
142
 */
143
static int
144
arfs_lookup(vnode_t dvp, char *name, vnode_t vp)
145
{
146
        struct ar_hdr *hdr;
147
        int blkno, error;
148
        off_t off;
149
        size_t size;
150
        mount_t mp;
151
        char *p;
152
153
        DPRINTF(("arfs_lookup: name=%s\n", name));
154
        if (*name == '\0')
155
                return ENOENT;
156
157
        mutex_lock(&arfs_lock);
158
159
        error = ENOENT;
160
        mp = vp->v_mount;
161
        blkno = 0;
162
        off = SARMAG;        /* offset in archive image */
163
        for (;;) {
164
                /* Read two blocks for archive header */
165
                if (arfs_readblk(mp, blkno) != 0)
166
                        goto out;
167
168
                /* Check file header */
169
                hdr = (struct ar_hdr *)(iobuf + (off % BSIZE));
170
                if (strncmp(hdr->ar_fmag, ARFMAG, sizeof(ARFMAG) - 1))
171
                        goto out;
172
173
                /* Get file size */
174
                size = (size_t)atol((char *)&hdr->ar_size);
175
                if (size == 0)
176
                        goto out;
177
178
                /* Convert archive name */
179
                if ((p = memchr(&hdr->ar_name, '/', 16)) != NULL)
180
                        *p = '\0';
181
182
                if (strncmp(name, (char *)&hdr->ar_name, 16) == 0)
183
                        break;
184
185
                /* Proceed to next archive header */
186
                off += (sizeof(struct ar_hdr) + size);
187
                off += (off % 2); /* Pad to even boundary */
188
189
                blkno = (int)(off / BSIZE);
190
        }
191
        vp->v_type = VREG;
192
193
        /* No write access */
194
        vp->v_mode = (mode_t)(S_IRUSR | S_IXUSR);
195
        vp->v_size = size;
196
        vp->v_blkno = blkno;
197
        vp->v_data = (void *)(off + sizeof(struct ar_hdr));
198
        error = 0;
199
 out:
200
        mutex_unlock(&arfs_lock);
201
        DPRINTF(("arfs_lookup: error=%d\n\n", error));
202
        return error;
203
}
204
205
static int
206
arfs_read(vnode_t vp, file_t fp, void *buf, size_t size, size_t *result)
207
{
208
        off_t off, file_pos, buf_pos;
209
        int blkno, error;
210
        size_t nr_read, nr_copy;
211
        mount_t mp;
212
        struct buf *bp;
213
214
        DPRINTF(("arfs_read: start size=%d\n", size));
215
        mutex_lock(&arfs_lock);
216
217
        *result = 0;
218
        mp = vp->v_mount;
219
220
        /* Check if current file position is already end of file. */
221
        file_pos = fp->f_offset;
222
        if (file_pos >= (off_t)vp->v_size) {
223
                error = 0;
224
                goto out;
225
        }
226
        /* Get the actual read size. */
227
        if (vp->v_size - file_pos < size)
228
                size = vp->v_size - file_pos;
229
230
        /* Read and copy data */
231
        off = (off_t)vp->v_data;
232
        nr_read = 0;
233
        for (;;) {
234
                DPRINTF(("arfs_read: file_pos=%d buf=%x size=%d\n",
235
                         file_pos, buf, size));
236
237
                blkno = (off + file_pos) / BSIZE;
238
                buf_pos = (off + file_pos) % BSIZE;
239
                if ((error = bread(mp->m_dev, blkno, &bp)) != 0)
240
                        goto out;
241
                nr_copy = BSIZE;
242
                if (buf_pos > 0)
243
                        nr_copy -= buf_pos;
244
                if (buf_pos + size < BSIZE)
245
                        nr_copy = size;
246
                ASSERT(nr_copy > 0);
247
                memcpy(buf, bp->b_data + buf_pos, nr_copy);
248
                brelse(bp);
249
250
                file_pos += nr_copy;
251
                DPRINTF(("arfs_read: file_pos=%d nr_copy=%d\n",
252
                         file_pos, nr_copy));
253
254
                nr_read += nr_copy;
255
                size -= nr_copy;
256
                if (size <= 0)
257
                        break;
258
                buf = (void *)((u_long)buf + nr_copy);
259
                buf_pos = 0;
260
        }
261
        fp->f_offset = file_pos;
262
        *result = nr_read;
263
        error = 0;
264
 out:
265
        mutex_unlock(&arfs_lock);
266
        DPRINTF(("arfs_read: error=%d\n\n", error));
267
        return error;
268
}
269
270
/*
271
 * Check if the seek offset is valid.
272
 */
273
static int
274
arfs_seek(vnode_t vp, file_t fp, off_t oldoff, off_t newoff)
275
{
276
277
        if (newoff > (off_t)vp->v_size)
278
                return -1;
279
280
        return 0;
281
}
282
283
static int
284
arfs_readdir(vnode_t vp, file_t fp, struct dirent *dir)
285
{
286
        struct ar_hdr *hdr;
287
        int blkno, i, error;
288
        off_t off;
289
        size_t size;
290
        mount_t mp;
291
        char *p;
292
293
        DPRINTF(("arfs_readdir: start\n"));
294
        mutex_lock(&arfs_lock);
295
296
        i = 0;
297
        mp = vp->v_mount;
298
        blkno = 0;
299
        off = SARMAG;        /* offset in archive image */
300
        for (;;) {
301
                /* Read two blocks for archive header */
302
                if ((error = arfs_readblk(mp, blkno)) != 0)
303
                        goto out;
304
305
                hdr = (struct ar_hdr *)(iobuf + (off % BSIZE));
306
307
                /* Get file size */
308
                size = (size_t)atol((char *)&hdr->ar_size);
309
                if (size == 0) {
310
                        error = ENOENT;
311
                        goto out;
312
                }
313
                if (i == fp->f_offset)
314
                        break;
315
316
                /* Proceed to next archive header */
317
                off += (sizeof(struct ar_hdr) + size);
318
                off += (off % 2); /* Pad to even boundary */
319
320
                blkno = off / BSIZE;
321
                i++;
322
        }
323
324
        /* Convert archive name */
325
        if ((p = memchr(&hdr->ar_name, '/', 16)) != NULL)
326
                *p = '\0';
327
328
        strlcpy((char *)&dir->d_name, (char *)&hdr->ar_name,
329
                sizeof(dir->d_name));
330
        dir->d_namlen = (uint16_t)strlen(dir->d_name);
331
        dir->d_fileno = (uint32_t)fp->f_offset;
332
        dir->d_type = DT_REG;
333
334
        fp->f_offset++;
335
        error = 0;
336
 out:
337
        mutex_unlock(&arfs_lock);
338
        return error;
339
}
340
341
342
int
343
arfs_init(void)
344
{
345
        return 0;
346
}