1 /* $NetBSD: nbfs.c,v 1.6 2006/07/13 15:51:54 bjh21 Exp $ */
4 * Copyright (c) 2006 Ben Harris
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
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
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
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>
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
{
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.
94 nbfs_devopen(struct open_file
*f
, char const *special
, char const *fname
,
97 unsigned int drive
= 0, part
= RAW_PART
;
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')
110 err
= rodisk_open(f
, special
, drive
, part
);
111 if (err
!= 0) return err
;
113 if (**rest
== '.') (*rest
)++;
118 nbfs_fileopen(struct open_file
*f
, char const *tail
)
121 int i
, error
= ENOENT
;
123 if (tail
[0] == '$' && tail
[1] == '.')
125 file
= alloc(strlen(tail
) + 2);
128 for (p
= file
+ 1; *p
!= '\0'; p
++) {
129 if (*p
== '.') *p
= '/';
130 else if (*p
== '/') *p
= '.';
132 if (strcmp(tail
, "$") == 0)
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
];
142 dealloc(file
, strlen(file
) + 1);
147 nbfs_fopen(struct open_file
*f
, char const *special
, char const *path
)
152 err
= nbfs_devopen(f
, special
, path
, &tail
);
153 if (err
!= 0) return err
;
154 err
= nbfs_fileopen(f
, tail
);
156 DEV_CLOSE(f
->f_dev
)(f
);
161 nbfs_fclose(struct open_file
*f
)
165 ferr
= FS_CLOSE(f
->f_ops
)(f
);
166 derr
= DEV_CLOSE(f
->f_dev
)(f
);
167 return ferr
!= 0 ? ferr
: derr
;
171 nbfs_open(struct nbfs_reg
*r
)
174 char const *fname
= (char const *)r
->r1
;
176 char const *special
= (char const *)r
->r6
;
178 struct nbfs_open_file
*nof
= NULL
;
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
);
194 if (S_ISDIR(st
.st_mode
)) r
->r0
|= 0x20000000;
195 r
->r1
= (uint32_t)nof
;
206 dealloc(nof
, sizeof(*nof
));
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
;
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
);
227 nbfs_putbytes(struct nbfs_reg
*r
)
229 static os_error
const err
= {0, "nbfs_putbytes"};
235 nbfs_args(struct nbfs_reg
*r
)
237 static os_error
const err
= {0, "nbfs_args"};
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; */
250 err
= nbfs_fclose(&nof
->f
);
251 if (err
!= 0) return maperr(err
);
252 LIST_REMOVE(nof
, link
);
253 dealloc(nof
, sizeof(*nof
));
258 nbfs_file(struct nbfs_reg
*r
)
261 char const *fname
= (char const *)r
->r1
;
262 void *buf
= (void *)r
->r2
;
263 char const *special
= (char const *)r
->r6
;
268 memset(&f
, 0, sizeof(f
));
269 err
= nbfs_fopen(&f
, special
, fname
);
270 if (err
!= 0 && err
!= ENOENT
)
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 */
284 case 5: /* Read catalogue information */
285 case 255: /* Load file */
287 r
->r0
= r
->r2
= r
->r3
= r
->r4
= r
->r5
= 0;
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
;
295 r
->r5
= fileswitch_ATTR_OWNER_READ
|
296 fileswitch_ATTR_WORLD_READ
;
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 */
319 nbfs_filename_ok(char const *f
)
323 if (strchr(":*#$&@^%\\", *f
++) != NULL
)
328 static os_error
const *
329 nbfs_func_dirents(struct nbfs_reg
*r
)
332 char const *fname
= (char const *)r
->r1
;
333 char const *special
= (char const *)r
->r6
;
337 struct fileswitch_dirent
*fdp
;
339 size_t maxcount
= r
->r3
;
343 size_t buflen
= r
->r5
;
344 char dirbuf
[DIRBLKSIZ
];
345 char *outp
= (char *)r
->r2
;
347 err
= nbfs_fopen(&f
, special
, fname
);
350 err
= FS_STAT(f
.f_ops
)(&f
, &st
);
353 if (!S_ISDIR(st
.st_mode
)) {
357 while (FS_READ(f
.f_ops
)(&f
, dirbuf
, DIRBLKSIZ
, &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
)) {
371 * Skip ., .., and names with characters that RISC
374 if (strcmp(dp
->d_name
, ".") == 0 ||
375 strcmp(dp
->d_name
, "..") == 0 ||
376 !nbfs_filename_ok(dp
->d_name
))
383 entsiz
= strlen(dp
->d_name
) + 1;
384 if (buflen
< entsiz
) goto out
;
385 strcpy(outp
, dp
->d_name
);
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
;
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
] == '.')
408 if (++count
== maxcount
)
424 nbfs_func(struct nbfs_reg
*r
)
426 static os_error error
= {0, "nbfs_func"};
432 return nbfs_func_dirents(r
);
434 case 16: /* Shut down */
437 sprintf(error
.errmess
, "nbfs_func %d not implemented", reason
);
442 #define FSERR(x) (0x10000 | (NBFS_FSNUM << 8) | (x))
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
)
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
;