xref: /netbsd-src/sys/fs/adosfs/advfsops.c (revision b5ffb2e0d69029911b676d573c889e1b9b7934b7)
1 /*	$NetBSD: advfsops.c,v 1.80 2021/12/05 04:47:17 msaitoh Exp $	*/
2 
3 /*
4  * Copyright (c) 1994 Christian E. Hopps
5  * Copyright (c) 1996 Matthias Scheler
6  * All rights reserved.
7  *
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. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *      This product includes software developed by Christian E. Hopps.
19  * 4. The name of the author may not be used to endorse or promote products
20  *    derived from this software without specific prior written permission
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include <sys/cdefs.h>
35 __KERNEL_RCSID(0, "$NetBSD: advfsops.c,v 1.80 2021/12/05 04:47:17 msaitoh Exp $");
36 
37 #if defined(_KERNEL_OPT)
38 #include "opt_compat_netbsd.h"
39 #endif
40 
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/sysctl.h>
44 #include <sys/vnode.h>
45 #include <sys/mount.h>
46 #include <sys/proc.h>
47 #include <sys/time.h>
48 #include <sys/malloc.h>
49 #include <sys/pool.h>
50 #include <sys/disklabel.h>
51 #include <sys/disk.h>
52 #include <miscfs/genfs/genfs.h>
53 #include <miscfs/specfs/specdev.h> /* XXX */
54 #include <sys/fcntl.h>
55 #include <sys/namei.h>
56 #include <sys/ioctl.h>
57 #include <sys/queue.h>
58 #include <sys/buf.h>
59 #include <sys/conf.h>
60 #include <sys/kauth.h>
61 #include <sys/module.h>
62 #include <fs/adosfs/adosfs.h>
63 
64 MODULE(MODULE_CLASS_VFS, adosfs, NULL);
65 
66 VFS_PROTOS(adosfs);
67 
68 int adosfs_mountfs(struct vnode *, struct mount *, struct lwp *);
69 int adosfs_loadbitmap(struct adosfsmount *);
70 
71 struct pool adosfs_node_pool;
72 
73 MALLOC_JUSTDEFINE(M_ANODE, "adosfs anode","adosfs anode structures and tables");
74 
75 static const struct genfs_ops adosfs_genfsops = {
76 	.gop_size = genfs_size,
77 };
78 
79 int (**adosfs_vnodeop_p)(void *);
80 
81 int
adosfs_mount(struct mount * mp,const char * path,void * data,size_t * data_len)82 adosfs_mount(struct mount *mp, const char *path, void *data, size_t *data_len)
83 {
84 	struct lwp *l = curlwp;
85 	struct vnode *devvp;
86 	struct adosfs_args *args = data;
87 	struct adosfsmount *amp;
88 	int error;
89 	mode_t accessmode;
90 
91 	if (args == NULL)
92 		return EINVAL;
93 	if (*data_len < sizeof *args)
94 		return EINVAL;
95 
96 	if (mp->mnt_flag & MNT_GETARGS) {
97 		amp = VFSTOADOSFS(mp);
98 		if (amp == NULL)
99 			return EIO;
100 		args->uid = amp->uid;
101 		args->gid = amp->gid;
102 		args->mask = amp->mask;
103 		args->fspec = NULL;
104 		*data_len = sizeof *args;
105 		return 0;
106 	}
107 
108 	if ((mp->mnt_flag & MNT_RDONLY) == 0)
109 		return (EROFS);
110 
111 	if ((mp->mnt_flag & MNT_UPDATE) && args->fspec == NULL)
112 		return EOPNOTSUPP;
113 
114 	/*
115 	 * Not an update, or updating the name: look up the name
116 	 * and verify that it refers to a sensible block device.
117 	 */
118 	error = namei_simple_user(args->fspec,
119 				NSM_FOLLOW_NOEMULROOT, &devvp);
120 	if (error != 0)
121 		return (error);
122 
123 	if (devvp->v_type != VBLK) {
124 		vrele(devvp);
125 		return (ENOTBLK);
126 	}
127 	if (bdevsw_lookup(devvp->v_rdev) == NULL) {
128 		vrele(devvp);
129 		return (ENXIO);
130 	}
131 	/*
132 	 * If mount by non-root, then verify that user has necessary
133 	 * permissions on the device.
134 	 */
135 	accessmode = VREAD;
136 	if ((mp->mnt_flag & MNT_RDONLY) == 0)
137 		accessmode |= VWRITE;
138 	vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
139 	error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_MOUNT,
140 	    KAUTH_REQ_SYSTEM_MOUNT_DEVICE, mp, devvp, KAUTH_ARG(accessmode));
141 	VOP_UNLOCK(devvp);
142 	if (error) {
143 		vrele(devvp);
144 		return (error);
145 	}
146 /* MNT_UPDATE? */
147 	if ((error = adosfs_mountfs(devvp, mp, l)) != 0) {
148 		vrele(devvp);
149 		return (error);
150 	}
151 	amp = VFSTOADOSFS(mp);
152 	amp->uid = args->uid;
153 	amp->gid = args->gid;
154 	amp->mask = args->mask;
155 	return set_statvfs_info(path, UIO_USERSPACE, args->fspec, UIO_USERSPACE,
156 	    mp->mnt_op->vfs_name, mp, l);
157 }
158 
159 int
adosfs_mountfs(struct vnode * devvp,struct mount * mp,struct lwp * l)160 adosfs_mountfs(struct vnode *devvp, struct mount *mp, struct lwp *l)
161 {
162 	struct disklabel dl;
163 	struct partition *parp;
164 	struct adosfsmount *amp;
165 	struct buf *bp;
166 	struct vnode *rvp;
167 	size_t bitmap_sz = 0;
168 	int error;
169 	uint64_t numsecs;
170 	unsigned secsize;
171 	unsigned long secsperblk, blksperdisk, resvblks;
172 
173 	amp = NULL;
174 
175 	if ((error = vinvalbuf(devvp, V_SAVE, l->l_cred, l, 0, 0)) != 0)
176 		return (error);
177 
178 	/*
179 	 * open blkdev and read boot and root block
180 	 */
181 	vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
182 	if ((error = VOP_OPEN(devvp, FREAD, NOCRED)) != 0) {
183 		VOP_UNLOCK(devvp);
184 		return (error);
185 	}
186 
187 	error = getdisksize(devvp, &numsecs, &secsize);
188 	if (error)
189 		goto fail;
190 
191 	amp = kmem_zalloc(sizeof(struct adosfsmount), KM_SLEEP);
192 
193 	/*
194 	 * compute filesystem parameters from disklabel
195 	 * on arch/amiga the disklabel is computed from the native
196 	 * partition tables
197 	 * - p_fsize is the filesystem block size
198 	 * - p_frag is the number of sectors per filesystem block
199 	 * - p_cpg is the number of reserved blocks (boot blocks)
200 	 * - p_psize is reduced by the number of preallocated blocks
201 	 *           at the end of a partition
202 	 *
203 	 * XXX
204 	 * - bsize and secsperblk could be computed from the first sector
205 	 *   of the root block
206 	 * - resvblks (the number of boot blocks) can only be guessed
207 	 *   by scanning for the root block as its position moves
208 	 *   with resvblks
209 	 */
210 	error = VOP_IOCTL(devvp, DIOCGDINFO, &dl, FREAD, NOCRED);
211 	VOP_UNLOCK(devvp);
212 	if (error)
213 		goto fail;
214 	parp = &dl.d_partitions[DISKPART(devvp->v_rdev)];
215 	if (dl.d_type == DKTYPE_FLOPPY) {
216 		amp->bsize = secsize;
217 		secsperblk = 1;
218 		resvblks   = 2;
219 	} else if (parp->p_fsize > 0 && parp->p_frag > 0) {
220 		amp->bsize = parp->p_fsize * parp->p_frag;
221 		secsperblk = parp->p_frag;
222 		resvblks   = parp->p_cpg;
223 	} else {
224 		error = EINVAL;
225 		goto fail;
226 	}
227 	blksperdisk = numsecs / secsperblk;
228 
229 
230 	/* The filesystem variant ('dostype') is stored in the boot block */
231 	bp = NULL;
232 	if ((error = bread(devvp, (daddr_t)BBOFF,
233 			   amp->bsize, 0, &bp)) != 0) {
234 		goto fail;
235 	}
236 	amp->dostype = adoswordn(bp, 0);
237 	brelse(bp, 0);
238 
239 	/* basic sanity checks */
240 	if (amp->dostype < 0x444f5300 || amp->dostype > 0x444f5305) {
241 		error = EINVAL;
242 		goto fail;
243 	}
244 
245 	amp->rootb = (blksperdisk - 1 + resvblks) / 2;
246 	amp->numblks = blksperdisk - resvblks;
247 
248 	amp->nwords = amp->bsize >> 2;
249 	amp->dbsize = amp->bsize - (IS_FFS(amp) ? 0 : OFS_DATA_OFFSET);
250 	amp->devvp = devvp;
251 
252 	amp->mp = mp;
253 	mp->mnt_data = amp;
254 	mp->mnt_stat.f_fsidx.__fsid_val[0] = (long)devvp->v_rdev;
255 	mp->mnt_stat.f_fsidx.__fsid_val[1] = makefstype(MOUNT_ADOSFS);
256 	mp->mnt_stat.f_fsid = mp->mnt_stat.f_fsidx.__fsid_val[0];
257 	mp->mnt_stat.f_namemax = ADMAXNAMELEN;
258 	mp->mnt_fs_bshift = ffs(amp->bsize) - 1;
259 	mp->mnt_dev_bshift = DEV_BSHIFT;
260 	mp->mnt_flag |= MNT_LOCAL;
261 
262 	/*
263 	 * get the root anode, if not a valid fs this will fail.
264 	 */
265 	if ((error = VFS_ROOT(mp, LK_EXCLUSIVE, &rvp)) != 0)
266 		goto fail;
267 	/* allocate and load bitmap, set free space */
268 	bitmap_sz = ((amp->numblks + 31) / 32) * sizeof(*amp->bitmap);
269 	amp->bitmap = kmem_alloc(bitmap_sz, KM_SLEEP);
270 	adosfs_loadbitmap(amp);
271 	if (mp->mnt_flag & MNT_RDONLY) {
272 		/*
273 		 * Don't need the bitmap any more if it's read-only.
274 		 */
275 		kmem_free(amp->bitmap, bitmap_sz);
276 		amp->bitmap = NULL;
277 	}
278 	vput(rvp);
279 
280 	return(0);
281 
282 fail:
283 	vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
284 	(void) VOP_CLOSE(devvp, FREAD, NOCRED);
285 	VOP_UNLOCK(devvp);
286 	if (amp && amp->bitmap)
287 		kmem_free(amp->bitmap, bitmap_sz);
288 	if (amp)
289 		kmem_free(amp, sizeof(*amp));
290 	return (error);
291 }
292 
293 int
adosfs_start(struct mount * mp,int flags)294 adosfs_start(struct mount *mp, int flags)
295 {
296 
297 	return (0);
298 }
299 
300 int
adosfs_unmount(struct mount * mp,int mntflags)301 adosfs_unmount(struct mount *mp, int mntflags)
302 {
303 	struct adosfsmount *amp;
304 	int error, flags;
305 
306 	flags = 0;
307 	if (mntflags & MNT_FORCE)
308 		flags |= FORCECLOSE;
309 	if ((error = vflush(mp, NULLVP, flags)) != 0)
310 		return (error);
311 	amp = VFSTOADOSFS(mp);
312 	if (amp->devvp->v_type != VBAD)
313 		spec_node_setmountedfs(amp->devvp, NULL);
314 	vn_lock(amp->devvp, LK_EXCLUSIVE | LK_RETRY);
315 	error = VOP_CLOSE(amp->devvp, FREAD, NOCRED);
316 	vput(amp->devvp);
317 	if (amp->bitmap) {
318 		size_t bitmap_sz = ((amp->numblks + 31) / 32) *
319 		    sizeof(*amp->bitmap);
320 		kmem_free(amp->bitmap, bitmap_sz);
321 	}
322 	kmem_free(amp, sizeof(*amp));
323 	mp->mnt_data = NULL;
324 	mp->mnt_flag &= ~MNT_LOCAL;
325 	return (error);
326 }
327 
328 int
adosfs_root(struct mount * mp,int lktype,struct vnode ** vpp)329 adosfs_root(struct mount *mp, int lktype, struct vnode **vpp)
330 {
331 	struct vnode *nvp;
332 	int error;
333 
334 	error = VFS_VGET(mp, (ino_t)VFSTOADOSFS(mp)->rootb, lktype, &nvp);
335 	if (error != 0)
336 		return (error);
337 	/* XXX verify it's a root block? */
338 	*vpp = nvp;
339 	return (0);
340 }
341 
342 int
adosfs_statvfs(struct mount * mp,struct statvfs * sbp)343 adosfs_statvfs(struct mount *mp, struct statvfs *sbp)
344 {
345 	struct adosfsmount *amp;
346 
347 	amp = VFSTOADOSFS(mp);
348 	sbp->f_bsize = amp->bsize;
349 	sbp->f_frsize = amp->bsize;
350 	sbp->f_iosize = amp->dbsize;
351 	sbp->f_blocks = amp->numblks;
352 	sbp->f_bfree = amp->freeblks;
353 	sbp->f_bavail = amp->freeblks;
354 	sbp->f_bresvd = 0;
355 	sbp->f_files = 0;		/* who knows */
356 	sbp->f_ffree = 0;		/* " " */
357 	sbp->f_favail = 0;		/* " " */
358 	sbp->f_fresvd = 0;
359 	copy_statvfs_info(sbp, mp);
360 	return (0);
361 }
362 
363 /*
364  * lookup an anode, if not found, create
365  * return locked and referenced
366  */
367 int
adosfs_vget(struct mount * mp,ino_t an,int lktype,struct vnode ** vpp)368 adosfs_vget(struct mount *mp, ino_t an, int lktype, struct vnode **vpp)
369 {
370 	u_long block;
371 	int error;
372 
373 	block = an;
374 	KASSERT(block == an);
375 	error = vcache_get(mp, &block, sizeof(block), vpp);
376 	if (error)
377 		return error;
378 	error = vn_lock(*vpp, lktype);
379 	if (error) {
380 		vrele(*vpp);
381 		*vpp = NULL;
382 		return error;
383 	}
384 	return 0;
385 }
386 
387 /*
388  * Initialize this vnode / anode pair.
389  * Caller assures no other thread will try to load this inode.
390  */
391 int
adosfs_loadvnode(struct mount * mp,struct vnode * vp,const void * key,size_t key_len,const void ** new_key)392 adosfs_loadvnode(struct mount *mp, struct vnode *vp,
393     const void *key, size_t key_len, const void **new_key)
394 {
395 	struct adosfsmount *amp;
396 	struct anode *ap;
397 	struct buf *bp;
398 	u_long an;
399 	char *nam, *tmp;
400 	int namlen, error;
401 
402 	KASSERT(key_len == sizeof(an));
403 	memcpy(&an, key, key_len);
404 	amp = VFSTOADOSFS(mp);
405 
406 	if ((error = bread(amp->devvp, an * amp->bsize / DEV_BSIZE,
407 			   amp->bsize, 0, &bp)) != 0)
408 		return error;
409 
410 	ap = pool_get(&adosfs_node_pool, PR_WAITOK);
411 	memset(ap, 0, sizeof(struct anode));
412 	ap->vp = vp;
413 	ap->amp = amp;
414 	ap->block = an;
415 	ap->nwords = amp->nwords;
416 
417 	/*
418 	 * get type and fill rest in based on that.
419 	 */
420 	switch (ap->type = adosfs_getblktype(amp, bp)) {
421 	case AROOT:
422 		vp->v_type = VDIR;
423 		vp->v_vflag |= VV_ROOT;
424 		ap->mtimev.days = adoswordn(bp, ap->nwords - 10);
425 		ap->mtimev.mins = adoswordn(bp, ap->nwords - 9);
426 		ap->mtimev.ticks = adoswordn(bp, ap->nwords - 8);
427 		ap->created.days = adoswordn(bp, ap->nwords - 7);
428 		ap->created.mins = adoswordn(bp, ap->nwords - 6);
429 		ap->created.ticks = adoswordn(bp, ap->nwords - 5);
430 		break;
431 	case ALDIR:
432 	case ADIR:
433 		vp->v_type = VDIR;
434 		break;
435 	case ALFILE:
436 	case AFILE:
437 		vp->v_type = VREG;
438 		ap->fsize = adoswordn(bp, ap->nwords - 47);
439 		break;
440 	case ASLINK:		/* XXX soft link */
441 		vp->v_type = VLNK;
442 		/*
443 		 * convert from BCPL string and
444 		 * from: "part:dir/file" to: "/part/dir/file"
445 		 */
446 		nam = (char *)bp->b_data + (6 * sizeof(long));
447 		namlen = strlen(nam);
448 		tmp = nam;
449 		while (*tmp && *tmp != ':')
450 			tmp++;
451 		if (*tmp == 0) {
452 			ap->slinkto = malloc(namlen + 1, M_ANODE, M_WAITOK);
453 			memcpy(ap->slinkto, nam, namlen);
454 		} else if (*nam == ':') {
455 			ap->slinkto = malloc(namlen + 1, M_ANODE, M_WAITOK);
456 			memcpy(ap->slinkto, nam, namlen);
457 			ap->slinkto[0] = '/';
458 		} else {
459 			ap->slinkto = malloc(namlen + 2, M_ANODE, M_WAITOK);
460 			ap->slinkto[0] = '/';
461 			memcpy(&ap->slinkto[1], nam, namlen);
462 			ap->slinkto[tmp - nam + 1] = '/';
463 			namlen++;
464 		}
465 		ap->slinkto[namlen] = 0;
466 		ap->fsize = namlen;
467 		break;
468 	default:
469 		error = EINVAL;
470 		goto bad;
471 	}
472 
473 	/*
474 	 * Get appropriate data from this block;  hard link needs
475 	 * to get other data from the "real" block.
476 	 */
477 
478 	/*
479 	 * copy in name (from original block)
480 	 */
481 	nam = (char *)bp->b_data + (ap->nwords - 20) * sizeof(u_int32_t);
482 	namlen = *(u_char *)nam++;
483 	if (namlen > 30) {
484 #ifdef DIAGNOSTIC
485 		printf("adosfs: aget: name length too long blk %llu\n",
486 		    (unsigned long long)an);
487 #endif
488 		error = EINVAL;
489 		goto bad;
490 	}
491 	memcpy(ap->name, nam, namlen);
492 	ap->name[namlen] = 0;
493 
494 	/*
495 	 * if dir alloc hash table and copy it in
496 	 */
497 	if (vp->v_type == VDIR) {
498 		int i;
499 
500 		ap->tab = malloc(ANODETABSZ(ap) * 2, M_ANODE, M_WAITOK);
501 		ap->ntabent = ANODETABENT(ap);
502 		ap->tabi = (int *)&ap->tab[ap->ntabent];
503 		memset(ap->tabi, 0, ANODETABSZ(ap));
504 		for (i = 0; i < ap->ntabent; i++)
505 			ap->tab[i] = adoswordn(bp, i + 6);
506 	}
507 
508 	/*
509 	 * misc.
510 	 */
511 	ap->pblock = adoswordn(bp, ap->nwords - 3);
512 	ap->hashf = adoswordn(bp, ap->nwords - 4);
513 	ap->linknext = adoswordn(bp, ap->nwords - 10);
514 	ap->linkto = adoswordn(bp, ap->nwords - 11);
515 
516 	/*
517 	 * setup last indirect block cache.
518 	 */
519 	ap->lastlindblk = 0;
520 	if (ap->type == AFILE)  {
521 		ap->lastindblk = ap->block;
522 		if (adoswordn(bp, ap->nwords - 10))
523 			ap->linkto = ap->block;
524 	} else if (ap->type == ALFILE) {
525 		ap->lastindblk = ap->linkto;
526 		brelse(bp, 0);
527 		bp = NULL;
528 		error = bread(amp->devvp, ap->linkto * amp->bsize / DEV_BSIZE,
529 		    amp->bsize, 0, &bp);
530 		if (error)
531 			goto bad;
532 		ap->fsize = adoswordn(bp, ap->nwords - 47);
533 	}
534 
535 	if (ap->type == AROOT) {
536 		ap->adprot = 15;
537 		ap->uid = amp->uid;
538 		ap->gid = amp->gid;
539 	} else {
540 		ap->adprot = adoswordn(bp, ap->nwords - 48) ^ 15;
541 		/*
542 		 * ADOS directories do not have a `x' protection bit as
543 		 * it is known in VFS; this functionality is fulfilled
544 		 * by the ADOS `r' bit.
545 		 *
546 		 * To retain the ADOS behaviour, fake execute permissions
547 		 * in that case.
548 		 */
549 		if ((ap->type == ADIR || ap->type == ALDIR) &&
550 		    (ap->adprot & 0x00000008) == 0)
551 			ap->adprot &= ~0x00000002;
552 
553 		/*
554 		 * Get uid/gid from extensions in file header
555 		 * (really need to know if this is a muFS partition)
556 		 */
557 		ap->uid = (adoswordn(bp, ap->nwords - 49) >> 16) & 0xffff;
558 		ap->gid = adoswordn(bp, ap->nwords - 49) & 0xffff;
559 		if (ap->uid || ap->gid) {
560 			if (ap->uid == 0xffff)
561 				ap->uid = 0;
562 			if (ap->gid == 0xffff)
563 				ap->gid = 0;
564 			ap->adprot |= 0x40000000;	/* Kludge */
565 		}
566 		else {
567 			/*
568 			 * uid & gid extension don't exist,
569 			 * so use the mount-point uid/gid
570 			 */
571 			ap->uid = amp->uid;
572 			ap->gid = amp->gid;
573 		}
574 	}
575 	ap->mtime.days = adoswordn(bp, ap->nwords - 23);
576 	ap->mtime.mins = adoswordn(bp, ap->nwords - 22);
577 	ap->mtime.ticks = adoswordn(bp, ap->nwords - 21);
578 
579 	brelse(bp, 0);
580 	vp->v_tag = VT_ADOSFS;
581 	vp->v_op = adosfs_vnodeop_p;
582 	vp->v_data = ap;
583 	genfs_node_init(vp, &adosfs_genfsops);
584 	uvm_vnp_setsize(vp, ap->fsize);
585 	*new_key = &ap->block;
586 	return 0;
587 
588 bad:
589 	if (bp)
590 		brelse(bp, 0);
591 	pool_put(&adosfs_node_pool, ap);
592 	return error;
593 }
594 
595 /*
596  * Load the bitmap into memory, and count the number of available
597  * blocks.
598  * The bitmap will be released if the filesystem is read-only;  it's
599  * only needed to find the free space.
600  */
601 int
adosfs_loadbitmap(struct adosfsmount * amp)602 adosfs_loadbitmap(struct adosfsmount *amp)
603 {
604 	struct buf *bp, *mapbp;
605 	u_long bn;
606 	int blkix, endix, mapix;
607 	int bmsize;
608 	int error;
609 
610 	bp = mapbp = NULL;
611 	bn = amp->rootb;
612 	if ((error = bread(amp->devvp, bn * amp->bsize / DEV_BSIZE, amp->bsize,
613 	    0, &bp)) != 0) {
614 		return (error);
615 	}
616 	blkix = amp->nwords - 49;
617 	endix = amp->nwords - 24;
618 	mapix = 0;
619 	bmsize = (amp->numblks + 31) / 32;
620 	while (mapix < bmsize) {
621 		int n;
622 		u_long bits;
623 
624 		if (adoswordn(bp, blkix) == 0)
625 			break;
626 		if (mapbp != NULL)
627 			brelse(mapbp, 0);
628 		if ((error = bread(amp->devvp,
629 		    adoswordn(bp, blkix) * amp->bsize / DEV_BSIZE, amp->bsize,
630 		     0, &mapbp)) != 0)
631 			break;
632 		if (adoscksum(mapbp, amp->nwords)) {
633 #ifdef DIAGNOSTIC
634 			printf("adosfs: loadbitmap - cksum of blk %d failed\n",
635 			    adoswordn(bp, blkix));
636 #endif
637 			/* XXX Force read-only?  Set free space 0? */
638 			break;
639 		}
640 		n = 1;
641 		while (n < amp->nwords && mapix < bmsize) {
642 			amp->bitmap[mapix++] = bits = adoswordn(mapbp, n);
643 			++n;
644 			if (mapix == bmsize && amp->numblks & 31)
645 				bits &= ~(0xffffffff << (amp->numblks & 31));
646 			while (bits) {
647 				if (bits & 1)
648 					++amp->freeblks;
649 				bits >>= 1;
650 			}
651 		}
652 		++blkix;
653 		if (mapix < bmsize && blkix == endix) {
654 			bn = adoswordn(bp, blkix);
655 			brelse(bp, 0);
656 			if ((error = bread(amp->devvp, bn * amp->bsize / DEV_BSIZE,
657 			    amp->bsize, 0, &bp)) != 0)
658 				break;
659 			/*
660 			 * Why is there no checksum on these blocks?
661 			 */
662 			blkix = 0;
663 			endix = amp->nwords - 1;
664 		}
665 	}
666 	if (bp)
667 		brelse(bp, 0);
668 	if (mapbp)
669 		brelse(mapbp, 0);
670 	return (error);
671 }
672 
673 
674 /*
675  * File handle to vnode
676  *
677  * Have to be really careful about stale file handles:
678  * - check that the inode number is in range
679  * - call iget() to get the locked inode
680  * - check for an unallocated inode (i_mode == 0)
681  * - check that the generation number matches
682  */
683 
684 struct ifid {
685 	ushort	ifid_len;
686 	ushort	ifid_pad;
687 	int	ifid_ino;
688 	long	ifid_start;
689 };
690 
691 int
adosfs_fhtovp(struct mount * mp,struct fid * fhp,int lktype,struct vnode ** vpp)692 adosfs_fhtovp(struct mount *mp, struct fid *fhp, int lktype,
693     struct vnode **vpp)
694 {
695 	struct ifid ifh;
696 #if 0
697 	struct anode *ap;
698 #endif
699 	struct vnode *nvp;
700 	int error;
701 
702 	if (fhp->fid_len != sizeof(struct ifid))
703 		return EINVAL;
704 
705 #ifdef ADOSFS_DIAGNOSTIC
706 	printf("adfhtovp(%p, %p, %p)\n", mp, fhp, vpp);
707 #endif
708 
709 	memcpy(&ifh, fhp, sizeof(ifh));
710 
711 	if ((error = VFS_VGET(mp, ifh.ifid_ino, lktype, &nvp)) != 0) {
712 		*vpp = NULLVP;
713 		return (error);
714 	}
715 #if 0
716 	ap = VTOA(nvp);
717 	if (ap->inode.iso_mode == 0) {
718 		vput(nvp);
719 		*vpp = NULLVP;
720 		return (ESTALE);
721 	}
722 #endif
723 	*vpp = nvp;
724 	return(0);
725 }
726 
727 int
adosfs_vptofh(struct vnode * vp,struct fid * fhp,size_t * fh_size)728 adosfs_vptofh(struct vnode *vp, struct fid *fhp, size_t *fh_size)
729 {
730 	struct anode *ap = VTOA(vp);
731 	struct ifid ifh;
732 
733 	if (*fh_size < sizeof(struct ifid)) {
734 		*fh_size = sizeof(struct ifid);
735 		return E2BIG;
736 	}
737 	*fh_size = sizeof(struct ifid);
738 
739 	memset(&ifh, 0, sizeof(ifh));
740 	ifh.ifid_len = sizeof(struct ifid);
741 	ifh.ifid_ino = ap->block;
742 	ifh.ifid_start = ap->block;
743 	memcpy(fhp, &ifh, sizeof(ifh));
744 
745 #ifdef ADOSFS_DIAGNOSTIC
746 	printf("advptofh(%p, %p)\n", vp, fhp);
747 #endif
748 	return(0);
749 }
750 
751 int
adosfs_sync(struct mount * mp,int waitfor,kauth_cred_t uc)752 adosfs_sync(struct mount *mp, int waitfor, kauth_cred_t uc)
753 {
754 #ifdef ADOSFS_DIAGNOSTIC
755 	printf("ad_sync(%p, %d)\n", mp, waitfor);
756 #endif
757 	return(0);
758 }
759 
760 void
adosfs_init(void)761 adosfs_init(void)
762 {
763 
764 	malloc_type_attach(M_ANODE);
765 	pool_init(&adosfs_node_pool, sizeof(struct anode), 0, 0, 0, "adosndpl",
766 	    &pool_allocator_nointr, IPL_NONE);
767 }
768 
769 void
adosfs_done(void)770 adosfs_done(void)
771 {
772 
773 	pool_destroy(&adosfs_node_pool);
774 	malloc_type_detach(M_ANODE);
775 }
776 
777 /*
778  * vfs generic function call table
779  */
780 
781 extern const struct vnodeopv_desc adosfs_vnodeop_opv_desc;
782 
783 const struct vnodeopv_desc *adosfs_vnodeopv_descs[] = {
784 	&adosfs_vnodeop_opv_desc,
785 	NULL,
786 };
787 
788 struct vfsops adosfs_vfsops = {
789 	.vfs_name = MOUNT_ADOSFS,
790 	.vfs_min_mount_data = sizeof (struct adosfs_args),
791 	.vfs_mount = adosfs_mount,
792 	.vfs_start = adosfs_start,
793 	.vfs_unmount = adosfs_unmount,
794 	.vfs_root = adosfs_root,
795 	.vfs_quotactl = (void *)eopnotsupp,
796 	.vfs_statvfs = adosfs_statvfs,
797 	.vfs_sync = adosfs_sync,
798 	.vfs_vget = adosfs_vget,
799 	.vfs_loadvnode = adosfs_loadvnode,
800 	.vfs_fhtovp = adosfs_fhtovp,
801 	.vfs_vptofh = adosfs_vptofh,
802 	.vfs_init = adosfs_init,
803 	.vfs_done = adosfs_done,
804 	.vfs_snapshot = (void *)eopnotsupp,
805 	.vfs_extattrctl = vfs_stdextattrctl,
806 	.vfs_suspendctl = genfs_suspendctl,
807 	.vfs_renamelock_enter = genfs_renamelock_enter,
808 	.vfs_renamelock_exit = genfs_renamelock_exit,
809 	.vfs_fsync = (void *)eopnotsupp,
810 	.vfs_opv_descs = adosfs_vnodeopv_descs
811 };
812 
813 SYSCTL_SETUP(adosfs_sysctl_setup, "adosfs sysctl")
814 {	sysctl_createv(clog, 0, NULL, NULL,
815 	       CTLFLAG_PERMANENT,
816 	       CTLTYPE_NODE, "adosfs",
817 	       SYSCTL_DESCR("AmigaDOS file system"),
818 	       NULL, 0, NULL, 0,
819 	       CTL_VFS, 16, CTL_EOL);
820 }
821 
822 static int
adosfs_modcmd(modcmd_t cmd,void * arg)823 adosfs_modcmd(modcmd_t cmd, void *arg)
824 {
825 	int error;
826 
827 	switch (cmd) {
828 	case MODULE_CMD_INIT:
829 		error = vfs_attach(&adosfs_vfsops);
830 		if (error != 0)
831 			break;
832 		/*
833 		 * XXX the "16" above could be dynamic, thereby eliminating
834 		 * one more instance of the "number to vfs" mapping problem,
835 		 * but "16" is the order as taken from sys/mount.h
836 		 */
837 		break;
838 	case MODULE_CMD_FINI:
839 		error = vfs_detach(&adosfs_vfsops);
840 		if (error != 0)
841 			break;
842 		break;
843 	default:
844 		error = ENOTTY;
845 		break;
846 	}
847 
848 	return (error);
849 }
850