Expand PMF_FN_* macros.
[netbsd-mini2440.git] / sys / arch / acorn32 / stand / nbfs / nbfs.c
blobf8a78d19f82bffb6cc4451939e122bea5d77378f
1 /* $NetBSD: nbfs.c,v 1.6 2006/07/13 15:51:54 bjh21 Exp $ */
3 /*-
4 * Copyright (c) 2006 Ben Harris
5 * Copyright (c) 1993
6 * The Regents of the University of California. All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
34 * Copyright (c) 1996
35 * Matthias Drochner. All rights reserved.
37 * Redistribution and use in source and binary forms, with or without
38 * modification, are permitted provided that the following conditions
39 * are met:
40 * 1. Redistributions of source code must retain the above copyright
41 * notice, this list of conditions and the following disclaimer.
42 * 2. Redistributions in binary form must reproduce the above copyright
43 * notice, this list of conditions and the following disclaimer in the
44 * documentation and/or other materials provided with the distribution.
46 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
47 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
48 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
49 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
50 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
51 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
52 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
53 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
54 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
55 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
58 #include <sys/types.h>
59 #include <sys/param.h>
60 #include <sys/disklabel.h>
61 #include <sys/queue.h>
62 #include <ufs/ufs/dinode.h>
63 #include <ufs/ufs/dir.h>
64 #include <lib/libkern/libkern.h>
65 #include <lib/libsa/stand.h>
66 #include <lib/libsa/lfs.h>
67 #include <lib/libsa/ufs.h>
68 #include <riscoscalls.h>
69 #include <riscosdisk.h>
71 #include "nbfs.h"
73 struct fs_ops file_system[] = {
74 FS_OPS(ffsv1), FS_OPS(ffsv2), FS_OPS(lfsv1), FS_OPS(lfsv2)
77 int nfsys = __arraycount(file_system);
79 struct nbfs_open_file {
80 struct open_file f;
81 int fileswitch_handle;
82 LIST_ENTRY(nbfs_open_file) link;
85 static LIST_HEAD(, nbfs_open_file) nbfs_open_files;
87 static os_error const *maperr(int saerr);
90 * Given a RISC OS special field and pathname, open the relevant
91 * device and return a pointer to the remainder of the pathname.
93 static int
94 nbfs_devopen(struct open_file *f, char const *special, char const *fname,
95 char const **rest)
97 unsigned int drive = 0, part = RAW_PART;
98 int err;
100 if (*fname++ != ':')
101 return EINVAL;
102 while (isdigit((unsigned char)*fname))
103 drive = drive * 10 + *fname++ - '0';
104 if (islower((unsigned char)*fname))
105 part = *fname++ - 'a';
106 else if (isupper((unsigned char)*fname))
107 part = *fname++ - 'A';
108 if (*fname != '.' && *fname != '\0')
109 return EINVAL;
110 err = rodisk_open(f, special, drive, part);
111 if (err != 0) return err;
112 *rest = fname;
113 if (**rest == '.') (*rest)++;
114 return 0;
117 static int
118 nbfs_fileopen(struct open_file *f, char const *tail)
120 char *file, *p;
121 int i, error = ENOENT;
123 if (tail[0] == '$' && tail[1] == '.')
124 tail += 2;
125 file = alloc(strlen(tail) + 2);
126 strcpy(file, "/");
127 strcat(file, tail);
128 for (p = file + 1; *p != '\0'; p++) {
129 if (*p == '.') *p = '/';
130 else if (*p == '/') *p = '.';
132 if (strcmp(tail, "$") == 0)
133 strcpy(file, "/");
135 for (i = 0; i < nfsys; i++) {
136 error = FS_OPEN(&file_system[i])(file, f);
137 if (error == 0 || error == ENOENT) {
138 f->f_ops = &file_system[i];
139 break;
142 dealloc(file, strlen(file) + 1);
143 return error;
146 static int
147 nbfs_fopen(struct open_file *f, char const *special, char const *path)
149 char const *tail;
150 int err;
152 err = nbfs_devopen(f, special, path, &tail);
153 if (err != 0) return err;
154 err = nbfs_fileopen(f, tail);
155 if (err != 0)
156 DEV_CLOSE(f->f_dev)(f);
157 return err;
160 static int
161 nbfs_fclose(struct open_file *f)
163 int ferr, derr;
165 ferr = FS_CLOSE(f->f_ops)(f);
166 derr = DEV_CLOSE(f->f_dev)(f);
167 return ferr != 0 ? ferr : derr;
170 os_error const *
171 nbfs_open(struct nbfs_reg *r)
173 int reason = r->r0;
174 char const *fname = (char const *)r->r1;
175 int fh = r->r3;
176 char const *special = (char const *)r->r6;
177 int err;
178 struct nbfs_open_file *nof = NULL;
179 struct stat st;
181 switch (reason) {
182 case 0: /* Open for read */
183 case 1: /* Create and open for update */
184 case 2: /* Open for update */
185 nof = alloc(sizeof(*nof));
186 memset(nof, 0, sizeof(*nof));
187 err = nbfs_fopen(&nof->f, special, fname);
188 if (err != 0) goto fail;
189 err = FS_STAT(nof->f.f_ops)(&nof->f, &st);
190 if (err != 0) goto fail;
191 nof->fileswitch_handle = fh;
192 LIST_INSERT_HEAD(&nbfs_open_files, nof, link);
193 r->r0 = 0x40000000;
194 if (S_ISDIR(st.st_mode)) r->r0 |= 0x20000000;
195 r->r1 = (uint32_t)nof;
196 r->r2 = DEV_BSIZE;
197 r->r3 = st.st_size;
198 r->r4 = st.st_size;
199 return NULL;
200 default:
201 err = EINVAL;
202 goto fail;
204 fail:
205 if (nof != NULL)
206 dealloc(nof, sizeof(*nof));
207 return maperr(err);
210 os_error const *
211 nbfs_getbytes(struct nbfs_reg *r)
213 struct nbfs_open_file *nof = (struct nbfs_open_file *)r->r1;
214 void *buf = (void *)r->r2;
215 size_t size = r->r3;
216 off_t off = r->r4;
217 int err;
219 err = FS_SEEK(nof->f.f_ops)(&nof->f, off, SEEK_SET);
220 if (err == -1) return maperr(err);
221 err = FS_READ(nof->f.f_ops)(&nof->f, buf, size, NULL);
222 if (err != 0) return maperr(err);
223 return NULL;
226 os_error const *
227 nbfs_putbytes(struct nbfs_reg *r)
229 static os_error const err = {0, "nbfs_putbytes"};
231 return &err;
234 os_error const *
235 nbfs_args(struct nbfs_reg *r)
237 static os_error const err = {0, "nbfs_args"};
239 return &err;
242 os_error const *
243 nbfs_close(struct nbfs_reg *r)
245 struct nbfs_open_file *nof = (struct nbfs_open_file *)r->r1;
246 /* uint32_t loadaddr = r->r2; */
247 /* uint32_t execaddr = r->r3; */
248 int err;
250 err = nbfs_fclose(&nof->f);
251 if (err != 0) return maperr(err);
252 LIST_REMOVE(nof, link);
253 dealloc(nof, sizeof(*nof));
254 return NULL;
257 os_error const *
258 nbfs_file(struct nbfs_reg *r)
260 int reason = r->r0;
261 char const *fname = (char const *)r->r1;
262 void *buf = (void *)r->r2;
263 char const *special = (char const *)r->r6;
264 struct open_file f;
265 int err;
266 struct stat st;
268 memset(&f, 0, sizeof(f));
269 err = nbfs_fopen(&f, special, fname);
270 if (err != 0 && err != ENOENT)
271 return maperr(err);
272 switch (reason) {
273 case 0: /* Save file */
274 case 1: /* Write catalogue information */
275 case 2: /* Write load address */
276 case 3: /* Write execution address */
277 case 4: /* Write attributes */
278 case 6: /* Delete object */
279 case 7: /* Create file */
280 case 8: /* Create directory */
281 nbfs_fclose(&f);
282 err = EROFS;
283 goto fail;
284 case 5: /* Read catalogue information */
285 case 255: /* Load file */
286 if (err == ENOENT)
287 r->r0 = r->r2 = r->r3 = r->r4 = r->r5 = 0;
288 else {
289 err = FS_STAT(f.f_ops)(&f, &st);
290 if (err != 0) goto fail;
291 r->r0 = S_ISDIR(st.st_mode) ?
292 fileswitch_IS_DIR : fileswitch_IS_FILE;
293 r->r2 = r->r3 = 0;
294 r->r4 = st.st_size;
295 r->r5 = fileswitch_ATTR_OWNER_READ |
296 fileswitch_ATTR_WORLD_READ;
297 if (reason == 255) {
298 err = FS_READ(f.f_ops)
299 (&f, buf, st.st_size, NULL);
300 if (err != 0) goto fail;
301 /* R6 should really be the leaf name */
302 r->r6 = r->r1;
305 break;
306 default:
307 nbfs_fclose(&f);
308 err = EINVAL;
309 goto fail;
311 nbfs_fclose(&f);
312 return NULL;
313 fail:
314 nbfs_fclose(&f);
315 return maperr(err);
318 static int
319 nbfs_filename_ok(char const *f)
322 while (*f)
323 if (strchr(":*#$&@^%\\", *f++) != NULL)
324 return 0;
325 return 1;
328 static os_error const *
329 nbfs_func_dirents(struct nbfs_reg *r)
331 int reason = r->r0;
332 char const *fname = (char const *)r->r1;
333 char const *special = (char const *)r->r6;
334 struct open_file f;
335 struct stat st;
336 int err;
337 struct fileswitch_dirent *fdp;
338 size_t resid;
339 size_t maxcount = r->r3;
340 size_t count = 0;
341 size_t skip = r->r4;
342 ssize_t off = 0;
343 size_t buflen = r->r5;
344 char dirbuf[DIRBLKSIZ];
345 char *outp = (char *)r->r2;
347 err = nbfs_fopen(&f, special, fname);
348 if (err != 0)
349 return maperr(err);
350 err = FS_STAT(f.f_ops)(&f, &st);
351 if (err != 0)
352 goto fail;
353 if (!S_ISDIR(st.st_mode)) {
354 err = ENOTDIR;
355 goto fail;
357 while (FS_READ(f.f_ops)(&f, dirbuf, DIRBLKSIZ, &resid) == 0 &&
358 resid == 0) {
359 struct direct *dp, *edp;
361 dp = (struct direct *) dirbuf;
362 edp = (struct direct *) (dirbuf + DIRBLKSIZ);
364 for (; dp < edp; dp = (void *)((char *)dp + dp->d_reclen)) {
365 size_t entsiz = 0;
366 int i;
368 if (dp->d_ino == 0)
369 continue;
371 * Skip ., .., and names with characters that RISC
372 * OS doesn't allow.
374 if (strcmp(dp->d_name, ".") == 0 ||
375 strcmp(dp->d_name, "..") == 0 ||
376 !nbfs_filename_ok(dp->d_name))
377 continue;
378 if (off++ < skip)
379 continue;
381 switch (reason) {
382 case 14:
383 entsiz = strlen(dp->d_name) + 1;
384 if (buflen < entsiz) goto out;
385 strcpy(outp, dp->d_name);
386 break;
387 case 15:
388 entsiz = ALIGN(offsetof(
389 struct fileswitch_dirent, name)
390 + strlen(dp->d_name) + 1);
391 if (buflen < entsiz) goto out;
393 fdp = (struct fileswitch_dirent *)outp;
394 fdp->loadaddr = 0;
395 fdp->execaddr = 0;
396 fdp->length = 0;
397 fdp->attr = 0;
398 fdp->objtype = dp->d_type == DT_DIR ?
399 fileswitch_IS_DIR : fileswitch_IS_FILE;
400 strcpy(fdp->name, dp->d_name);
401 for (i = 0; fdp->name[i] != '\0'; i++)
402 if (fdp->name[i] == '.')
403 fdp->name[i] = '/';
404 break;
406 outp += entsiz;
407 buflen -= entsiz;
408 if (++count == maxcount)
409 goto out;
412 off = -1;
413 out:
414 nbfs_fclose(&f);
415 r->r3 = count;
416 r->r4 = off;
417 return NULL;
418 fail:
419 nbfs_fclose(&f);
420 return maperr(err);
423 os_error const *
424 nbfs_func(struct nbfs_reg *r)
426 static os_error error = {0, "nbfs_func"};
427 int reason = r->r0;
429 switch (reason) {
430 case 14:
431 case 15:
432 return nbfs_func_dirents(r);
434 case 16: /* Shut down */
435 return NULL;
436 default:
437 sprintf(error.errmess, "nbfs_func %d not implemented", reason);
438 return &error;
442 #define FSERR(x) (0x10000 | (NBFS_FSNUM << 8) | (x))
444 static struct {
445 int saerr;
446 os_error roerr;
447 } const errmap[] = {
448 { ECTLR, { FSERR(ECTLR), "Bad parent filing system" } },
449 { EUNIT, { FSERR(0xAC), "Bad drive number" } },
450 { EPART, { FSERR(EPART), "Bad partition" } },
451 { ERDLAB, { FSERR(ERDLAB), "Can't read disk label" } },
452 { EUNLAB, { FSERR(EUNLAB), "Unlabeled" } },
453 { ENOENT, { FSERR(0xD6), "No such file or directory" } },
454 { EIO, { FSERR(EIO), "Input/output error" } },
455 { EINVAL, { FSERR(EINVAL), "Invalid argument" } },
456 { ENOTDIR, { FSERR(ENOTDIR), "Not a directory" } },
457 { EROFS, { FSERR(0xC9), "Read-only file system" } },
460 static os_error const *maperr(int err)
462 int i;
463 static const os_error defaulterr = { FSERR(0), "Unknown NBFS error" };
465 for (i = 0; i < sizeof(errmap) / sizeof(errmap[0]); i++)
466 if (err == errmap[i].saerr)
467 return &errmap[i].roerr;
468 return &defaulterr;