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