scoutos / prex-0.9.0 / usr / server / fs / arfs / arfs_vnops.c @ 03e9c04a
History | View | Annotate | Download (8.37 KB)
1 |
/*
|
---|---|
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 |
} |