Import makefs from NetBSD

Change-Id: I0ebcc9d0168df9d26cfb0af0fce2bc894ce688af
This commit is contained in:
Jean-Baptiste Boric 2015-09-10 23:45:24 +02:00 committed by Lionel Sambuc
parent 22ad44d6a9
commit 9f988b7934
122 changed files with 50035 additions and 3 deletions

View file

@ -181,6 +181,9 @@
./sbin/mkfs.mfs minix-sys ./sbin/mkfs.mfs minix-sys
./sbin/mknod minix-sys ./sbin/mknod minix-sys
./sbin/newfs_ext2fs minix-sys ./sbin/newfs_ext2fs minix-sys
./sbin/newfs_msdos minix-sys
./sbin/newfs_udf minix-sys
./sbin/newfs_v7fs minix-sys
./sbin/nologin minix-sys ./sbin/nologin minix-sys
./sbin/ping minix-sys ./sbin/ping minix-sys
./sbin/poweroff minix-sys ./sbin/poweroff minix-sys
@ -906,6 +909,12 @@
./usr/include/fs minix-sys ./usr/include/fs minix-sys
./usr/include/fs/puffs minix-sys ./usr/include/fs/puffs minix-sys
./usr/include/fs/puffs/puffs_msgif.h minix-sys ./usr/include/fs/puffs/puffs_msgif.h minix-sys
./usr/include/fs/udf minix-sys
./usr/include/fs/udf/ecma167-udf.h minix-sys
./usr/include/fs/udf/udf_mount.h minix-sys
./usr/include/fs/v7fs minix-sys
./usr/include/fs/v7fs/v7fs_args.h minix-sys
./usr/include/fs/v7fs/v7fs.h minix-sys
./usr/include/fstab.h minix-sys ./usr/include/fstab.h minix-sys
./usr/include/fts.h minix-sys ./usr/include/fts.h minix-sys
./usr/include/ftw.h minix-sys ./usr/include/ftw.h minix-sys
@ -5251,11 +5260,15 @@
./usr/man/man8/link.8 minix-sys ./usr/man/man8/link.8 minix-sys
./usr/man/man8/loadramdisk.8 minix-sys ./usr/man/man8/loadramdisk.8 minix-sys
./usr/man/man8/MAKEDEV.8 minix-sys ./usr/man/man8/MAKEDEV.8 minix-sys
./usr/man/man8/makefs.8 minix-sys
./usr/man/man8/makewhatis.8 minix-sys ./usr/man/man8/makewhatis.8 minix-sys
./usr/man/man8/mknod.8 minix-sys ./usr/man/man8/mknod.8 minix-sys
./usr/man/man8/mtree.8 minix-sys ./usr/man/man8/mtree.8 minix-sys
./usr/man/man8/netconf.8 minix-sys ./usr/man/man8/netconf.8 minix-sys
./usr/man/man8/newfs_ext2fs.8 minix-sys ./usr/man/man8/newfs_ext2fs.8 minix-sys
./usr/man/man8/newfs_msdos.8 minix-sys
./usr/man/man8/newfs_udf.8 minix-sys
./usr/man/man8/newfs_v7fs.8 minix-sys
./usr/man/man8/newroot.8 minix-sys obsolete ./usr/man/man8/newroot.8 minix-sys obsolete
./usr/man/man8/nologin.8 minix-sys ./usr/man/man8/nologin.8 minix-sys
./usr/man/man8/nonamed.8 minix-sys ./usr/man/man8/nonamed.8 minix-sys
@ -5340,6 +5353,7 @@
./usr/sbin/installboot_nbsd minix-sys ./usr/sbin/installboot_nbsd minix-sys
./usr/sbin/kernel minix-sys ./usr/sbin/kernel minix-sys
./usr/sbin/link minix-sys ./usr/sbin/link minix-sys
./usr/sbin/makefs minix-sys
./usr/sbin/mkfs.mfsv3 minix-sys ./usr/sbin/mkfs.mfsv3 minix-sys
./usr/sbin/mkproto minix-sys ./usr/sbin/mkproto minix-sys
./usr/sbin/mtree minix-sys ./usr/sbin/mtree minix-sys

View file

@ -15,7 +15,7 @@ SUBDIR= \
shutdown \ shutdown \
# support for various file systems # support for various file systems
SUBDIR+= newfs_ext2fs fsck_ext2fs SUBDIR+= newfs_ext2fs fsck_ext2fs newfs_msdos newfs_udf newfs_v7fs
.if !defined(__MINIX) .if !defined(__MINIX)
SUBDIR+= newfs fsck_ffs fsdb dump restore clri tunefs resize_ffs SUBDIR+= newfs fsck_ffs fsdb dump restore clri tunefs resize_ffs
SUBDIR+= newfs_lfs fsck_lfs dump_lfs resize_lfs SUBDIR+= newfs_lfs fsck_lfs dump_lfs resize_lfs

89
sbin/mount/fattr.c Normal file
View file

@ -0,0 +1,89 @@
/* $NetBSD: fattr.c,v 1.10 2009/06/19 12:55:45 stacktic Exp $ */
/*-
* Copyright (c) 2000 The NetBSD Foundation, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: fattr.c,v 1.10 2009/06/19 12:55:45 stacktic Exp $");
#endif /* not lint */
#include <sys/param.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <err.h>
#include <grp.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "mountprog.h"
int
a_num(const char *s, const char *id_type)
{
int id;
char *ep;
id = strtol(s, &ep, 0);
if (*ep || s == ep || id < 0)
errx(1, "unknown %s id: %s", id_type, s);
return id;
}
gid_t
a_gid(const char *s)
{
struct group *gr;
if ((gr = getgrnam(s)) != NULL)
return gr->gr_gid;
return a_num(s, "group");
}
uid_t
a_uid(const char *s)
{
struct passwd *pw;
if ((pw = getpwnam(s)) != NULL)
return pw->pw_uid;
return a_num(s, "user");
}
mode_t
a_mask(const char *s)
{
int rv;
char *ep;
rv = strtol(s, &ep, 8);
if (s == ep || *ep || rv < 0)
errx(1, "invalid file mode: %s", s);
return rv;
}

37
sbin/mount/mountprog.h Normal file
View file

@ -0,0 +1,37 @@
/* $NetBSD: mountprog.h,v 1.1 2008/08/05 20:57:45 pooka Exp $ */
/*-
* Copyright (c) 2000, 2008 The NetBSD Foundation, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
int a_num(const char *, const char *);
gid_t a_gid(const char *);
uid_t a_uid(const char *);
mode_t a_mask(const char *);
int checkvfsname(const char *, const char **);
const char ** makevfslist(const char *);
void pathadj(const char *, char *);

25
sbin/newfs_msdos/Makefile Normal file
View file

@ -0,0 +1,25 @@
# $NetBSD: Makefile,v 1.6 2013/01/21 20:28:38 christos Exp $
# From: $FreeBSD: src/sbin/newfs_msdos/Makefile,v 1.5 2001/03/26 14:33:18 ru Exp $
.include <bsd.own.mk>
PROG= newfs_msdos
MAN= newfs_msdos.8
SRCS= newfs_msdos.c partutil.c mkfs_msdos.c
LDADD+= -lutil
DPADD+= ${LIBUTIL}
LDADD+=-lprop
DPADD+=${LIBPROP}
FSCK=${NETBSDSRCDIR}/sbin/fsck
CPPFLAGS+=-I${.CURDIR} -I${FSCK}
.PATH: ${FSCK}
.if ${MACHINE} == "pc98"
CFLAGS+= -DPC98
.endif
.include <bsd.prog.mk>

View file

@ -0,0 +1,976 @@
/* $NetBSD: mkfs_msdos.c,v 1.8 2013/10/19 01:09:59 christos Exp $ */
/*
* Copyright (c) 1998 Robert Nordier
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#if HAVE_NBTOOL_CONFIG_H
#include "nbtool_config.h"
#endif
#include <sys/cdefs.h>
#ifndef lint
#if 0
static const char rcsid[] =
"$FreeBSD: src/sbin/newfs_msdos/newfs_msdos.c,v 1.15 2000/10/10 01:49:37 wollman Exp $";
#else
__RCSID("$NetBSD: mkfs_msdos.c,v 1.8 2013/10/19 01:09:59 christos Exp $");
#endif
#endif /* not lint */
#include <sys/types.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/time.h>
#ifndef MAKEFS
#include <sys/mount.h>
#include <sys/disk.h>
#endif
#include <ctype.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <paths.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <signal.h>
#include <util.h>
#include <disktab.h>
#ifndef MAKEFS
#include "partutil.h"
#endif
#include "mkfs_msdos.h"
#define MAXU16 0xffff /* maximum unsigned 16-bit quantity */
#define BPN 4 /* bits per nibble */
#define NPB 2 /* nibbles per byte */
#define DOSMAGIC 0xaa55 /* DOS magic number */
#define MINBPS 512 /* minimum bytes per sector */
#define MAXSPC 128 /* maximum sectors per cluster */
#define MAXNFT 16 /* maximum number of FATs */
#define DEFBLK 4096 /* default block size */
#define DEFBLK16 2048 /* default block size FAT16 */
#define DEFRDE 512 /* default root directory entries */
#define RESFTE 2 /* reserved FAT entries */
#define MINCLS12 1 /* minimum FAT12 clusters */
#define MINCLS16 0xff5 /* minimum FAT16 clusters */
#define MINCLS32 0xfff5 /* minimum FAT32 clusters */
#define MAXCLS12 0xff4 /* maximum FAT12 clusters */
#define MAXCLS16 0xfff4 /* maximum FAT16 clusters */
#define MAXCLS32 0xffffff4 /* maximum FAT32 clusters */
#define mincls(fat_type) ((fat_type) == 12 ? MINCLS12 : \
(fat_type) == 16 ? MINCLS16 : \
MINCLS32)
#define maxcls(fat_type) ((fat_type) == 12 ? MAXCLS12 : \
(fat_type) == 16 ? MAXCLS16 : \
MAXCLS32)
#define mk1(p, x) \
(p) = (u_int8_t)(x)
#define mk2(p, x) \
(p)[0] = (u_int8_t)(x), \
(p)[1] = (u_int8_t)((x) >> 010)
#define mk4(p, x) \
(p)[0] = (u_int8_t)(x), \
(p)[1] = (u_int8_t)((x) >> 010), \
(p)[2] = (u_int8_t)((x) >> 020), \
(p)[3] = (u_int8_t)((x) >> 030)
struct bs {
u_int8_t jmp[3]; /* bootstrap entry point */
u_int8_t oem[8]; /* OEM name and version */
};
struct bsbpb {
u_int8_t bps[2]; /* bytes per sector */
u_int8_t spc; /* sectors per cluster */
u_int8_t res[2]; /* reserved sectors */
u_int8_t nft; /* number of FATs */
u_int8_t rde[2]; /* root directory entries */
u_int8_t sec[2]; /* total sectors */
u_int8_t mid; /* media descriptor */
u_int8_t spf[2]; /* sectors per FAT */
u_int8_t spt[2]; /* sectors per track */
u_int8_t hds[2]; /* drive heads */
u_int8_t hid[4]; /* hidden sectors */
u_int8_t bsec[4]; /* big total sectors */
};
struct bsxbpb {
u_int8_t bspf[4]; /* big sectors per FAT */
u_int8_t xflg[2]; /* FAT control flags */
u_int8_t vers[2]; /* file system version */
u_int8_t rdcl[4]; /* root directory start cluster */
u_int8_t infs[2]; /* file system info sector */
u_int8_t bkbs[2]; /* backup boot sector */
u_int8_t rsvd[12]; /* reserved */
};
struct bsx {
u_int8_t drv; /* drive number */
u_int8_t rsvd; /* reserved */
u_int8_t sig; /* extended boot signature */
u_int8_t volid[4]; /* volume ID number */
u_int8_t label[11]; /* volume label */
u_int8_t type[8]; /* file system type */
};
struct de {
u_int8_t namext[11]; /* name and extension */
u_int8_t attr; /* attributes */
u_int8_t rsvd[10]; /* reserved */
u_int8_t time[2]; /* creation time */
u_int8_t date[2]; /* creation date */
u_int8_t clus[2]; /* starting cluster */
u_int8_t size[4]; /* size */
};
struct bpb {
u_int bps; /* bytes per sector */
u_int spc; /* sectors per cluster */
u_int res; /* reserved sectors */
u_int nft; /* number of FATs */
u_int rde; /* root directory entries */
u_int sec; /* total sectors */
u_int mid; /* media descriptor */
u_int spf; /* sectors per FAT */
u_int spt; /* sectors per track */
u_int hds; /* drive heads */
u_int hid; /* hidden sectors */
u_int bsec; /* big total sectors */
u_int bspf; /* big sectors per FAT */
u_int rdcl; /* root directory start cluster */
u_int infs; /* file system info sector */
u_int bkbs; /* backup boot sector */
};
#define INIT(a, b, c, d, e, f, g, h, i, j) \
{ .bps = a, .spc = b, .res = c, .nft = d, .rde = e, \
.sec = f, .mid = g, .spf = h, .spt = i, .hds = j, }
static struct {
const char *name;
struct bpb bpb;
} stdfmt[] = {
{"160", INIT(512, 1, 1, 2, 64, 320, 0xfe, 1, 8, 1)},
{"180", INIT(512, 1, 1, 2, 64, 360, 0xfc, 2, 9, 1)},
{"320", INIT(512, 2, 1, 2, 112, 640, 0xff, 1, 8, 2)},
{"360", INIT(512, 2, 1, 2, 112, 720, 0xfd, 2, 9, 2)},
{"640", INIT(512, 2, 1, 2, 112, 1280, 0xfb, 2, 8, 2)},
{"720", INIT(512, 2, 1, 2, 112, 1440, 0xf9, 3, 9, 2)},
{"1200", INIT(512, 1, 1, 2, 224, 2400, 0xf9, 7, 15, 2)},
{"1232", INIT(1024,1, 1, 2, 192, 1232, 0xfe, 2, 8, 2)},
{"1440", INIT(512, 1, 1, 2, 224, 2880, 0xf0, 9, 18, 2)},
{"2880", INIT(512, 2, 1, 2, 240, 5760, 0xf0, 9, 36, 2)}
};
static u_int8_t bootcode[] = {
0xfa, /* cli */
0x31, 0xc0, /* xor ax,ax */
0x8e, 0xd0, /* mov ss,ax */
0xbc, 0x00, 0x7c, /* mov sp,7c00h */
0xfb, /* sti */
0x8e, 0xd8, /* mov ds,ax */
0xe8, 0x00, 0x00, /* call $ + 3 */
0x5e, /* pop si */
0x83, 0xc6, 0x19, /* add si,+19h */
0xbb, 0x07, 0x00, /* mov bx,0007h */
0xfc, /* cld */
0xac, /* lodsb */
0x84, 0xc0, /* test al,al */
0x74, 0x06, /* jz $ + 8 */
0xb4, 0x0e, /* mov ah,0eh */
0xcd, 0x10, /* int 10h */
0xeb, 0xf5, /* jmp $ - 9 */
0x30, 0xe4, /* xor ah,ah */
0xcd, 0x16, /* int 16h */
0xcd, 0x19, /* int 19h */
0x0d, 0x0a,
'N', 'o', 'n', '-', 's', 'y', 's', 't',
'e', 'm', ' ', 'd', 'i', 's', 'k',
0x0d, 0x0a,
'P', 'r', 'e', 's', 's', ' ', 'a', 'n',
'y', ' ', 'k', 'e', 'y', ' ', 't', 'o',
' ', 'r', 'e', 'b', 'o', 'o', 't',
0x0d, 0x0a,
0
};
static int got_siginfo = 0; /* received a SIGINFO */
#ifndef MAKEFS
static int check_mounted(const char *, mode_t);
#endif
static int getstdfmt(const char *, struct bpb *);
static int getbpbinfo(int, const char *, const char *, int, struct bpb *, int);
static void print_bpb(struct bpb *);
static int ckgeom(const char *, u_int, const char *);
static int oklabel(const char *);
static void mklabel(u_int8_t *, const char *);
static void setstr(u_int8_t *, const char *, size_t);
static void infohandler(int sig);
int
mkfs_msdos(const char *fname, const char *dtype, const struct msdos_options *op)
{
char buf[MAXPATHLEN];
struct stat sb;
struct timeval tv;
struct bpb bpb;
struct tm *tm;
struct bs *bs;
struct bsbpb *bsbpb;
struct bsxbpb *bsxbpb;
struct bsx *bsx;
struct de *de;
u_int8_t *img;
const char *bname;
ssize_t n;
time_t now;
u_int bss, rds, cls, dir, lsn, x, x1, x2;
int ch, fd, fd1;
struct msdos_options o = *op;
int oflags = O_RDWR | O_CREAT;
if (o.block_size && o.sectors_per_cluster) {
warnx("Cannot specify both block size and sectors per cluster");
return -1;
}
if (o.OEM_string && strlen(o.OEM_string) > 8) {
warnx("%s: bad OEM string", o.OEM_string);
return -1;
}
if (o.create_size) {
if (o.no_create) {
warnx("create (-C) is incompatible with -N");
return -1;
}
if (o.offset == 0)
oflags |= O_TRUNC;
fd = open(fname, oflags, 0644);
if (fd == -1) {
warnx("failed to create %s", fname);
return -1;
}
(void)lseek(fd, o.create_size - 1, SEEK_SET);
if (write(fd, "\0", 1) != 1) {
warn("failed to set file size");
return -1;
}
(void)lseek(fd, 0, SEEK_SET);
} else if ((fd = open(fname, o.no_create ? O_RDONLY : O_RDWR)) == -1 ||
fstat(fd, &sb)) {
warn("%s", fname);
return -1;
}
#ifndef MAKEFS
if (!o.no_create)
if (check_mounted(fname, sb.st_mode) == -1)
return -1;
#endif
if (!S_ISCHR(sb.st_mode) && !o.create_size) {
warnx("warning, %s is not a character device", fname);
return -1;
}
if (o.offset && o.offset != lseek(fd, o.offset, SEEK_SET)) {
warnx("cannot seek to %jd", (intmax_t)o.offset);
return -1;
}
memset(&bpb, 0, sizeof(bpb));
if (o.floppy) {
if (getstdfmt(o.floppy, &bpb) == -1)
return -1;
bpb.bsec = bpb.sec;
bpb.sec = 0;
bpb.bspf = bpb.spf;
bpb.spf = 0;
}
if (o.drive_heads)
bpb.hds = o.drive_heads;
if (o.sectors_per_track)
bpb.spt = o.sectors_per_track;
if (o.bytes_per_sector)
bpb.bps = o.bytes_per_sector;
if (o.size)
bpb.bsec = o.size;
if (o.hidden_sectors_set)
bpb.hid = o.hidden_sectors;
if (!(o.floppy || (o.drive_heads && o.sectors_per_track &&
o.bytes_per_sector && o.size && o.hidden_sectors_set))) {
if (getbpbinfo(fd, fname, dtype, o.hidden_sectors_set, &bpb,
o.create_size != 0) == -1)
return -1;
bpb.bsec -= (o.offset / bpb.bps);
if (bpb.spc == 0) { /* set defaults */
if (bpb.bsec <= 6000) /* about 3MB -> 512 bytes */
bpb.spc = 1;
else if (bpb.bsec <= (1<<17)) /* 64M -> 4k */
bpb.spc = 8;
else if (bpb.bsec <= (1<<19)) /* 256M -> 8k */
bpb.spc = 16;
else if (bpb.bsec <= (1<<21)) /* 1G -> 16k */
bpb.spc = 32;
else
bpb.spc = 64; /* otherwise 32k */
}
}
if (o.volume_label && !oklabel(o.volume_label)) {
warnx("%s: bad volume label", o.volume_label);
return -1;
}
switch (o.fat_type) {
case 0:
if (o.floppy)
o.fat_type = 12;
else if (!o.directory_entries && (o.info_sector || o.backup_sector))
o.fat_type = 32;
break;
case 12:
case 16:
if (o.info_sector) {
warnx("Cannot specify info sector with FAT%u", o.fat_type);
return -1;
}
if (o.backup_sector) {
warnx("Cannot specify backup sector with FAT%u", o.fat_type);
return -1;
}
break;
case 32:
if (o.directory_entries) {
warnx("Cannot specify directory entries with FAT32");
return -1;
}
break;
default:
warnx("%d: bad FAT type", o.fat_type);
return -1;
}
if (!powerof2(bpb.bps)) {
warnx("bytes/sector (%u) is not a power of 2", bpb.bps);
return -1;
}
if (bpb.bps < MINBPS) {
warnx("bytes/sector (%u) is too small; minimum is %u",
bpb.bps, MINBPS);
return -1;
}
if (o.floppy && o.fat_type == 32)
bpb.rde = 0;
if (o.block_size) {
if (!powerof2(o.block_size)) {
warnx("block size (%u) is not a power of 2", o.block_size);
return -1;
}
if (o.block_size < bpb.bps) {
warnx("block size (%u) is too small; minimum is %u",
o.block_size, bpb.bps);
return -1;
}
if (o.block_size > bpb.bps * MAXSPC) {
warnx("block size (%u) is too large; maximum is %u",
o.block_size, bpb.bps * MAXSPC);
return -1;
}
bpb.spc = o.block_size / bpb.bps;
}
if (o.sectors_per_cluster) {
if (!powerof2(o.sectors_per_cluster)) {
warnx("sectors/cluster (%u) is not a power of 2",
o.sectors_per_cluster);
return -1;
}
bpb.spc = o.sectors_per_cluster;
}
if (o.reserved_sectors)
bpb.res = o.reserved_sectors;
if (o.num_FAT) {
if (o.num_FAT > MAXNFT) {
warnx("number of FATs (%u) is too large; maximum is %u",
o.num_FAT, MAXNFT);
return -1;
}
bpb.nft = o.num_FAT;
}
if (o.directory_entries)
bpb.rde = o.directory_entries;
if (o.media_descriptor_set) {
if (o.media_descriptor < 0xf0) {
warnx("illegal media descriptor (%#x)", o.media_descriptor);
return -1;
}
bpb.mid = o.media_descriptor;
}
if (o.sectors_per_fat)
bpb.bspf = o.sectors_per_fat;
if (o.info_sector)
bpb.infs = o.info_sector;
if (o.backup_sector)
bpb.bkbs = o.backup_sector;
bss = 1;
bname = NULL;
fd1 = -1;
if (o.bootstrap) {
bname = o.bootstrap;
if (!strchr(bname, '/')) {
snprintf(buf, sizeof(buf), "/boot/%s", bname);
if (!(bname = strdup(buf))) {
warn(NULL);
return -1;
}
}
if ((fd1 = open(bname, O_RDONLY)) == -1 || fstat(fd1, &sb)) {
warn("%s", bname);
return -1;
}
if (!S_ISREG(sb.st_mode) || sb.st_size % bpb.bps ||
sb.st_size < bpb.bps || sb.st_size > bpb.bps * MAXU16) {
warnx("%s: inappropriate file type or format", bname);
return -1;
}
bss = sb.st_size / bpb.bps;
}
if (!bpb.nft)
bpb.nft = 2;
if (!o.fat_type) {
if (bpb.bsec < (bpb.res ? bpb.res : bss) +
howmany((RESFTE + (bpb.spc ? MINCLS16 : MAXCLS12 + 1)) *
((bpb.spc ? 16 : 12) / BPN), bpb.bps * NPB) *
bpb.nft +
howmany(bpb.rde ? bpb.rde : DEFRDE,
bpb.bps / sizeof(struct de)) +
(bpb.spc ? MINCLS16 : MAXCLS12 + 1) *
(bpb.spc ? bpb.spc : howmany(DEFBLK, bpb.bps)))
o.fat_type = 12;
else if (bpb.rde || bpb.bsec <
(bpb.res ? bpb.res : bss) +
howmany((RESFTE + MAXCLS16) * 2, bpb.bps) * bpb.nft +
howmany(DEFRDE, bpb.bps / sizeof(struct de)) +
(MAXCLS16 + 1) *
(bpb.spc ? bpb.spc : howmany(8192, bpb.bps)))
o.fat_type = 16;
else
o.fat_type = 32;
}
x = bss;
if (o.fat_type == 32) {
if (!bpb.infs) {
if (x == MAXU16 || x == bpb.bkbs) {
warnx("no room for info sector");
return -1;
}
bpb.infs = x;
}
if (bpb.infs != MAXU16 && x <= bpb.infs)
x = bpb.infs + 1;
if (!bpb.bkbs) {
if (x == MAXU16) {
warnx("no room for backup sector");
return -1;
}
bpb.bkbs = x;
} else if (bpb.bkbs != MAXU16 && bpb.bkbs == bpb.infs) {
warnx("backup sector would overwrite info sector");
return -1;
}
if (bpb.bkbs != MAXU16 && x <= bpb.bkbs)
x = bpb.bkbs + 1;
}
if (!bpb.res)
bpb.res = o.fat_type == 32 ? MAX(x, MAX(16384 / bpb.bps, 4)) : x;
else if (bpb.res < x) {
warnx("too few reserved sectors (need %d have %d)", x, bpb.res);
return -1;
}
if (o.fat_type != 32 && !bpb.rde)
bpb.rde = DEFRDE;
rds = howmany(bpb.rde, bpb.bps / sizeof(struct de));
if (!bpb.spc)
for (bpb.spc = howmany(o.fat_type == 16 ? DEFBLK16 : DEFBLK, bpb.bps);
bpb.spc < MAXSPC &&
bpb.res +
howmany((RESFTE + maxcls(o.fat_type)) * (o.fat_type / BPN),
bpb.bps * NPB) * bpb.nft +
rds +
(u_int64_t)(maxcls(o.fat_type) + 1) * bpb.spc <= bpb.bsec;
bpb.spc <<= 1);
if (o.fat_type != 32 && bpb.bspf > MAXU16) {
warnx("too many sectors/FAT for FAT12/16");
return -1;
}
x1 = bpb.res + rds;
x = bpb.bspf ? bpb.bspf : 1;
if (x1 + (u_int64_t)x * bpb.nft > bpb.bsec) {
warnx("meta data exceeds file system size");
return -1;
}
x1 += x * bpb.nft;
x = (u_int64_t)(bpb.bsec - x1) * bpb.bps * NPB /
(bpb.spc * bpb.bps * NPB + o.fat_type / BPN * bpb.nft);
x2 = howmany((RESFTE + MIN(x, maxcls(o.fat_type))) * (o.fat_type / BPN),
bpb.bps * NPB);
if (!bpb.bspf) {
bpb.bspf = x2;
x1 += (bpb.bspf - 1) * bpb.nft;
}
cls = (bpb.bsec - x1) / bpb.spc;
x = (u_int64_t)bpb.bspf * bpb.bps * NPB / (o.fat_type / BPN) - RESFTE;
if (cls > x)
cls = x;
if (bpb.bspf < x2) {
warnx("warning: sectors/FAT limits file system to %u clusters",
cls);
return -1;
}
if (cls < mincls(o.fat_type)) {
warnx("%u clusters too few clusters for FAT%u, need %u", cls,
o.fat_type, mincls(o.fat_type));
return -1;
}
if (cls > maxcls(o.fat_type)) {
cls = maxcls(o.fat_type);
bpb.bsec = x1 + (cls + 1) * bpb.spc - 1;
warnx("warning: FAT type limits file system to %u sectors",
bpb.bsec);
return -1;
}
printf("%s: %u sector%s in %u FAT%u cluster%s "
"(%u bytes/cluster)\n", fname, cls * bpb.spc,
cls * bpb.spc == 1 ? "" : "s", cls, o.fat_type,
cls == 1 ? "" : "s", bpb.bps * bpb.spc);
if (!bpb.mid)
bpb.mid = !bpb.hid ? 0xf0 : 0xf8;
if (o.fat_type == 32)
bpb.rdcl = RESFTE;
if (bpb.hid + bpb.bsec <= MAXU16) {
bpb.sec = bpb.bsec;
bpb.bsec = 0;
}
if (o.fat_type != 32) {
bpb.spf = bpb.bspf;
bpb.bspf = 0;
}
ch = 0;
if (o.fat_type == 12)
ch = 1; /* 001 Primary DOS with 12 bit FAT */
else if (o.fat_type == 16) {
if (bpb.bsec == 0)
ch = 4; /* 004 Primary DOS with 16 bit FAT <32M */
else
ch = 6; /* 006 Primary 'big' DOS, 16-bit FAT (> 32MB) */
/*
* XXX: what about:
* 014 DOS (16-bit FAT) - LBA
* ?
*/
} else if (o.fat_type == 32) {
ch = 11; /* 011 Primary DOS with 32 bit FAT */
/*
* XXX: what about:
* 012 Primary DOS with 32 bit FAT - LBA
* ?
*/
}
if (ch != 0)
printf("MBR type: %d\n", ch);
print_bpb(&bpb);
if (!o.no_create) {
gettimeofday(&tv, NULL);
now = tv.tv_sec;
tm = localtime(&now);
if (!(img = malloc(bpb.bps)))
err(1, NULL);
dir = bpb.res + (bpb.spf ? bpb.spf : bpb.bspf) * bpb.nft;
#ifdef SIGINFO
signal(SIGINFO, infohandler);
#endif
for (lsn = 0; lsn < dir + (o.fat_type == 32 ? bpb.spc : rds); lsn++) {
if (got_siginfo) {
fprintf(stderr,"%s: writing sector %u of %u (%u%%)\n",
fname,lsn,(dir + (o.fat_type == 32 ? bpb.spc : rds)),
(lsn*100)/(dir + (o.fat_type == 32 ? bpb.spc : rds)));
got_siginfo = 0;
}
x = lsn;
if (o.bootstrap &&
o.fat_type == 32 && bpb.bkbs != MAXU16 &&
bss <= bpb.bkbs && x >= bpb.bkbs) {
x -= bpb.bkbs;
if (!x && lseek(fd1, o.offset, SEEK_SET)) {
warn("%s", bname);
return -1;
}
}
if (o.bootstrap && x < bss) {
if ((n = read(fd1, img, bpb.bps)) == -1) {
warn("%s", bname);
return -1;
}
if ((size_t)n != bpb.bps) {
warnx("%s: can't read sector %u", bname, x);
return -1;
}
} else
memset(img, 0, bpb.bps);
if (!lsn ||
(o.fat_type == 32 && bpb.bkbs != MAXU16 && lsn == bpb.bkbs)) {
x1 = sizeof(struct bs);
bsbpb = (struct bsbpb *)(img + x1);
mk2(bsbpb->bps, bpb.bps);
mk1(bsbpb->spc, bpb.spc);
mk2(bsbpb->res, bpb.res);
mk1(bsbpb->nft, bpb.nft);
mk2(bsbpb->rde, bpb.rde);
mk2(bsbpb->sec, bpb.sec);
mk1(bsbpb->mid, bpb.mid);
mk2(bsbpb->spf, bpb.spf);
mk2(bsbpb->spt, bpb.spt);
mk2(bsbpb->hds, bpb.hds);
mk4(bsbpb->hid, bpb.hid);
mk4(bsbpb->bsec, bpb.bsec);
x1 += sizeof(struct bsbpb);
if (o.fat_type == 32) {
bsxbpb = (struct bsxbpb *)(img + x1);
mk4(bsxbpb->bspf, bpb.bspf);
mk2(bsxbpb->xflg, 0);
mk2(bsxbpb->vers, 0);
mk4(bsxbpb->rdcl, bpb.rdcl);
mk2(bsxbpb->infs, bpb.infs);
mk2(bsxbpb->bkbs, bpb.bkbs);
x1 += sizeof(struct bsxbpb);
}
bsx = (struct bsx *)(img + x1);
mk1(bsx->sig, 0x29);
if (o.volume_id_set)
x = o.volume_id;
else
x = (((u_int)(1 + tm->tm_mon) << 8 |
(u_int)tm->tm_mday) +
((u_int)tm->tm_sec << 8 |
(u_int)(tv.tv_usec / 10))) << 16 |
((u_int)(1900 + tm->tm_year) +
((u_int)tm->tm_hour << 8 |
(u_int)tm->tm_min));
mk4(bsx->volid, x);
mklabel(bsx->label, o.volume_label ? o.volume_label : "NO NAME");
snprintf(buf, sizeof(buf), "FAT%u", o.fat_type);
setstr(bsx->type, buf, sizeof(bsx->type));
if (!o.bootstrap) {
x1 += sizeof(struct bsx);
bs = (struct bs *)img;
mk1(bs->jmp[0], 0xeb);
mk1(bs->jmp[1], x1 - 2);
mk1(bs->jmp[2], 0x90);
setstr(bs->oem, o.OEM_string ? o.OEM_string : "NetBSD",
sizeof(bs->oem));
memcpy(img + x1, bootcode, sizeof(bootcode));
mk2(img + MINBPS - 2, DOSMAGIC);
}
} else if (o.fat_type == 32 && bpb.infs != MAXU16 &&
(lsn == bpb.infs ||
(bpb.bkbs != MAXU16 &&
lsn == bpb.bkbs + bpb.infs))) {
mk4(img, 0x41615252);
mk4(img + MINBPS - 28, 0x61417272);
mk4(img + MINBPS - 24, 0xffffffff);
mk4(img + MINBPS - 20, bpb.rdcl);
mk2(img + MINBPS - 2, DOSMAGIC);
} else if (lsn >= bpb.res && lsn < dir &&
!((lsn - bpb.res) %
(bpb.spf ? bpb.spf : bpb.bspf))) {
mk1(img[0], bpb.mid);
for (x = 1; x < o.fat_type * (o.fat_type == 32 ? 3U : 2U) / 8U; x++)
mk1(img[x], o.fat_type == 32 && x % 4 == 3 ? 0x0f : 0xff);
} else if (lsn == dir && o.volume_label) {
de = (struct de *)img;
mklabel(de->namext, o.volume_label);
mk1(de->attr, 050);
x = (u_int)tm->tm_hour << 11 |
(u_int)tm->tm_min << 5 |
(u_int)tm->tm_sec >> 1;
mk2(de->time, x);
x = (u_int)(tm->tm_year - 80) << 9 |
(u_int)(tm->tm_mon + 1) << 5 |
(u_int)tm->tm_mday;
mk2(de->date, x);
}
if ((n = write(fd, img, bpb.bps)) == -1) {
warn("%s", fname);
return -1;
}
if ((size_t)n != bpb.bps) {
warnx("%s: can't write sector %u", fname, lsn);
return -1;
}
}
}
return 0;
}
#ifndef MAKEFS
/*
* return -1 with error if file system is mounted.
*/
static int
check_mounted(const char *fname, mode_t mode)
{
struct statvfs *mp;
const char *s1, *s2;
size_t len;
int n, r;
if (!(n = getmntinfo(&mp, MNT_NOWAIT))) {
warn("getmntinfo");
return -1;
}
len = strlen(_PATH_DEV);
s1 = fname;
if (!strncmp(s1, _PATH_DEV, len))
s1 += len;
r = S_ISCHR(mode) && s1 != fname && *s1 == 'r';
for (; n--; mp++) {
s2 = mp->f_mntfromname;
if (!strncmp(s2, _PATH_DEV, len))
s2 += len;
if ((r && s2 != mp->f_mntfromname && !strcmp(s1 + 1, s2)) ||
!strcmp(s1, s2)) {
warnx("%s is mounted on %s", fname, mp->f_mntonname);
return -1;
}
}
return 0;
}
#endif
/*
* Get a standard format.
*/
static int
getstdfmt(const char *fmt, struct bpb *bpb)
{
u_int x, i;
x = sizeof(stdfmt) / sizeof(stdfmt[0]);
for (i = 0; i < x && strcmp(fmt, stdfmt[i].name); i++);
if (i == x) {
warnx("%s: unknown standard format", fmt);
return -1;
}
*bpb = stdfmt[i].bpb;
return 0;
}
/*
* Get disk slice, partition, and geometry information.
*/
static int
getbpbinfo(int fd, const char *fname, const char *dtype, int iflag,
struct bpb *bpb, int create)
{
const char *s1, *s2;
int part;
part = -1;
s1 = fname;
if ((s2 = strrchr(s1, '/')))
s1 = s2 + 1;
for (s2 = s1; *s2 && !isdigit((unsigned char)*s2); s2++);
if (!*s2 || s2 == s1)
s2 = NULL;
else
while (isdigit((unsigned char)*++s2));
s1 = s2;
#ifndef MAKEFS
int maxpartitions = getmaxpartitions();
// XXX: Does not work with wedges
if (s2 && *s2 >= 'a' && *s2 <= 'a' + maxpartitions - 1) {
part = *s2++ - 'a';
}
#endif
if (((part != -1) && ((!iflag && part != -1) || !bpb->bsec)) ||
!bpb->bps || !bpb->spt || !bpb->hds) {
u_int sector_size;
u_int nsectors;
u_int ntracks;
u_int size;
#ifndef MAKEFS
struct disk_geom geo;
struct dkwedge_info dkw;
if (!create && getdiskinfo(fname, fd, NULL, &geo, &dkw) != -1) {
sector_size = geo.dg_secsize = 512;
nsectors = geo.dg_nsectors = 63;
ntracks = geo.dg_ntracks = 255;
size = dkw.dkw_size;
} else
#endif
{
struct stat st;
if (fstat(fd, &st) == -1) {
warnx("Can't get disk size for `%s'", fname);
return -1;
}
/* create a fake geometry for a file image */
sector_size = 512;
nsectors = 63;
ntracks = 255;
size = st.st_size / sector_size;
}
if (!bpb->bps) {
if (ckgeom(fname, sector_size, "bytes/sector") == -1)
return -1;
bpb->bps = sector_size;
}
if (nsectors > 63) {
/*
* The kernel doesn't accept BPB with spt > 63.
* (see sys/fs/msdosfs/msdosfs_vfsops.c:msdosfs_mountfs())
* If values taken from disklabel don't match these
* restrictions, use popular BIOS default values instead.
*/
nsectors = 63;
}
if (!bpb->spt) {
if (ckgeom(fname, nsectors, "sectors/track") == -1)
return -1;
bpb->spt = nsectors;
}
if (!bpb->hds)
if (ckgeom(fname, ntracks, "drive heads") == -1)
return -1;
bpb->hds = ntracks;
if (!bpb->bsec)
bpb->bsec = size;
}
return 0;
}
/*
* Print out BPB values.
*/
static void
print_bpb(struct bpb *bpb)
{
printf("bps=%u spc=%u res=%u nft=%u", bpb->bps, bpb->spc, bpb->res,
bpb->nft);
if (bpb->rde)
printf(" rde=%u", bpb->rde);
if (bpb->sec)
printf(" sec=%u", bpb->sec);
printf(" mid=%#x", bpb->mid);
if (bpb->spf)
printf(" spf=%u", bpb->spf);
printf(" spt=%u hds=%u hid=%u", bpb->spt, bpb->hds, bpb->hid);
if (bpb->bsec)
printf(" bsec=%u", bpb->bsec);
if (!bpb->spf) {
printf(" bspf=%u rdcl=%u", bpb->bspf, bpb->rdcl);
printf(" infs=");
printf(bpb->infs == MAXU16 ? "%#x" : "%u", bpb->infs);
printf(" bkbs=");
printf(bpb->bkbs == MAXU16 ? "%#x" : "%u", bpb->bkbs);
}
printf("\n");
}
/*
* Check a disk geometry value.
*/
static int
ckgeom(const char *fname, u_int val, const char *msg)
{
if (!val) {
warnx("%s: no default %s", fname, msg);
return -1;
}
if (val > MAXU16) {
warnx("%s: illegal %s", fname, msg);
return -1;
}
return 0;
}
/*
* Check a volume label.
*/
static int
oklabel(const char *src)
{
int c, i;
for (i = 0; i <= 11; i++) {
c = (u_char)*src++;
if (c < ' ' + !i || strchr("\"*+,./:;<=>?[\\]|", c))
break;
}
return i && !c;
}
/*
* Make a volume label.
*/
static void
mklabel(u_int8_t *dest, const char *src)
{
int c, i;
for (i = 0; i < 11; i++) {
c = *src ? toupper((unsigned char)*src++) : ' ';
*dest++ = !i && c == '\xe5' ? 5 : c;
}
}
/*
* Copy string, padding with spaces.
*/
static void
setstr(u_int8_t *dest, const char *src, size_t len)
{
while (len--)
*dest++ = *src ? *src++ : ' ';
}
static void
infohandler(int sig)
{
got_siginfo = 1;
}

View file

@ -0,0 +1,71 @@
/* $NetBSD: mkfs_msdos.h,v 1.2 2013/01/23 15:29:15 christos Exp $ */
/*-
* Copyright (c) 2013 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Christos Zoulas.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of The NetBSD Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/types.h>
#include <stdbool.h>
#define ALLOPTS \
AOPT('@', off_t, offset, 0, "Offset in device") \
AOPT('B', char *, bootstrap, -1, "Bootstrap file") \
AOPT('C', off_t, create_size, 0, "Create file") \
AOPT('F', uint8_t, fat_type, 12, "FAT type (12, 16, or 32)") \
AOPT('I', uint32_t, volume_id, 0, "Volume ID") \
AOPT('L', char *, volume_label, -1, "Volume Label") \
AOPT('N', bool, no_create, -2, "Don't create filesystem, print params only") \
AOPT('O', char *, OEM_string, -1, "OEM string") \
AOPT('S', uint16_t, bytes_per_sector, 1, "Bytes per sector") \
AOPT('a', uint32_t, sectors_per_fat, 1, "Sectors per FAT") \
AOPT('b', uint32_t, block_size, 1, "Block size") \
AOPT('c', uint8_t, sectors_per_cluster, 1, "Sectors per cluster") \
AOPT('e', uint16_t, directory_entries, 1, "Directory entries") \
AOPT('f', char *, floppy, -1, "Standard format floppies (160,180,320,360,640,720,1200,1232,1440,2880)") \
AOPT('h', uint16_t, drive_heads, 1, "Drive heads") \
AOPT('i', uint16_t, info_sector, 1, "Info sector") \
AOPT('k', uint16_t, backup_sector, 1, "Backup sector") \
AOPT('m', uint8_t, media_descriptor, 0, "Media descriptor") \
AOPT('n', uint8_t, num_FAT, 1, "Number of FATs") \
AOPT('o', uint32_t, hidden_sectors, 0, "Hidden sectors") \
AOPT('r', uint16_t, reserved_sectors, 1, "Reserved sectors") \
AOPT('s', uint32_t, size, 1, "File System size") \
AOPT('u', uint16_t, sectors_per_track, 1, "Sectors per track")
struct msdos_options {
#define AOPT(_opt, _type, _name, _min, _desc) _type _name;
ALLOPTS
#undef AOPT
uint32_t volume_id_set:1;
uint32_t media_descriptor_set:1;
uint32_t hidden_sectors_set:1;
};
int mkfs_msdos(const char *, const char *, const struct msdos_options *);

View file

@ -0,0 +1,241 @@
.\" $NetBSD: newfs_msdos.8,v 1.18 2013/07/20 21:39:58 wiz Exp $
.\"
.\" Copyright (c) 1998 Robert Nordier
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in
.\" the documentation and/or other materials provided with the
.\" distribution.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS
.\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
.\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY
.\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
.\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
.\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
.\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
.\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
.\" From: $FreeBSD: src/sbin/newfs_msdos/newfs_msdos.8,v 1.13 2001/08/14 10:01:48 ru Exp $
.\"
.Dd March 26, 2009
.Dt NEWFS_MSDOS 8
.Os
.Sh NAME
.Nm newfs_msdos
.Nd construct a new MS-DOS (FAT) file system
.Sh SYNOPSIS
.Nm
.Op Fl N
.Op Fl @ Ar offset
.Op Fl B Ar boot
.Op Fl C Ar create-size
.Op Fl F Ar FAT-type
.Op Fl I Ar volid
.Op Fl L Ar label
.Op Fl O Ar OEM
.Op Fl S Ar sector-size
.Op Fl a Ar FAT-size
.Op Fl b Ar block-size
.Op Fl c Ar cluster-size
.Op Fl e Ar dirents
.Op Fl f Ar format
.Op Fl h Ar heads
.Op Fl i Ar info
.Op Fl k Ar backup
.Op Fl m Ar media
.Op Fl n Ar FATs
.Op Fl o Ar hidden
.Op Fl r Ar reserved
.Op Fl s Ar total
.Op Fl u Ar track-size
.Ar special
.Op Ar disktype
.Sh DESCRIPTION
The
.Nm
utility creates a FAT12, FAT16, or FAT32 file system on device or file named
.Ar special ,
using
.Xr disktab 5
entry
.Ar disktype
to determine geometry, if required.
.Pp
The options are as follow:
.Bl -tag -width indent
.It Fl N
Don't create a file system: just print out parameters.
.It Fl @ Ar offset
Build the filesystem at the specified offset in bytes in the device or file.
A suffix s, k, m, g (lower or upper case)
appended to the offset specifies that the
number is in sectors, kilobytes, megabytes or gigabytes, respectively.
.It Fl B Ar boot
Get bootstrap from file.
.It Fl C Ar create-size
Create the image file with the specified size.
A suffix character appended to the size is interpreted as for the
.Fl @
option.
The file is created by truncating any existing file with the
same name, seeking just before the required size and writing
a single 0 byte.
As a consequence, the space occupied on disk
may be smaller than the size specified as a parameter.
.It Fl F Ar FAT-type
FAT type (one of 12, 16, or 32).
.It Fl I Ar volid
Volume ID.
.It Fl L Ar label
Volume label (up to 11 characters).
The label should consist of only those characters permitted
in regular DOS (8+3) filenames.
The default is
.Qq Li "NO_NAME" .
.It Fl O Ar OEM
OEM string (up to 8 characters).
The default is
.Qq Li "NetBSD" .
.It Fl S Ar sector-size
Number of bytes per sector.
Acceptable values are powers of 2 in the range 512 through 32768.
.It Fl a Ar FAT-size
Number of sectors per FAT.
.It Fl b Ar block-size
File system block size (bytes per cluster).
This should resolve to an acceptable number of sectors
per cluster (see below).
.It Fl c Ar cluster-size
Sectors per cluster.
Acceptable values are powers of 2 in the range 1 through 128.
If the block or cluster size are not specified, the code
uses a cluster between 512 bytes and 32K depending on
the filesystem size.
.It Fl e Ar dirents
Number of root directory entries (FAT12 and FAT16 only).
.It Fl f Ar format
Specify a standard (floppy disk) format.
The standard formats are (capacities in kilobytes):
160, 180, 320, 360, 640, 720, 1200, 1232, 1440, 2880.
.It Fl h Ar heads
Number of drive heads.
.It Fl i Ar info
Location of the file system info sector (FAT32 only).
A value of 0xffff signifies no info sector.
.It Fl k Ar backup
Location of the backup boot sector (FAT32 only).
A value of 0xffff signifies no backup sector.
.It Fl m Ar media
Media descriptor (acceptable range 0xf0 to 0xff).
.It Fl n Ar FATs
Number of FATs.
Acceptable values are 1 to 16 inclusive.
The default is 2.
.It Fl o Ar hidden
Number of hidden sectors.
.It Fl r Ar reserved
Number of reserved sectors.
.It Fl s Ar total
File system size.
.It Fl u Ar track-size
Number of sectors per track.
.El
.Pp
If
.Nm
receives a
.Dv SIGINFO
signal
(see the
.Sy status
argument for
.Xr stty 1 ) ,
a line will be written to the standard error output indicating
the name of the device currently being formatted, the sector
number being written, and the total number of sectors to be written.
.Sh NOTES
If some parameters (e.g. size, number of sectors, etc.) are not specified
through options or disktype, the program tries to generate them
automatically.
In particular, the size is determined as the
device or file size minus the offset specified with the
.Fl @
option.
When the geometry is not available, it is assumed to be
63 sectors, 255 heads.
The size is then rounded to become
a multiple of the track size and avoid complaints by some filesystem code.
.Pp
FAT file system parameters occupy a "Boot Sector BPB (BIOS Parameter
Block)" in the first of the "reserved" sectors which precede the actual
file system.
For reference purposes, this structure is presented below.
.Bd -literal
struct bsbpb {
u_int16_t bps; /* [-S] bytes per sector */
u_int8_t spc; /* [-c] sectors per cluster */
u_int16_t res; /* [-r] reserved sectors */
u_int8_t nft; /* [-n] number of FATs */
u_int16_t rde; /* [-e] root directory entries */
u_int16_t sec; /* [-s] total sectors */
u_int8_t mid; /* [-m] media descriptor */
u_int16_t spf; /* [-a] sectors per FAT */
u_int16_t spt; /* [-u] sectors per track */
u_int16_t hds; /* [-h] drive heads */
u_int32_t hid; /* [-o] hidden sectors */
u_int32_t bsec; /* [-s] big total sectors */
};
/* FAT32 extensions */
struct bsxbpb {
u_int32_t bspf; /* [-a] big sectors per FAT */
u_int16_t xflg; /* control flags */
u_int16_t vers; /* file system version */
u_int32_t rdcl; /* root directory start cluster */
u_int16_t infs; /* [-i] file system info sector */
u_int16_t bkbs; /* [-k] backup boot sector */
};
.Ed
.Sh EXAMPLES
.Bd -literal -offset indent
newfs_msdos /dev/rwd1a
.Ed
.Pp
Create a file system, using default parameters, on
.Pa /dev/rwd1a .
.Bd -literal -offset indent
newfs_msdos -f 1440 -L foo /dev/rfd0a
.Ed
.Pp
Create a standard 1.44M file system, with volume label
.Ar foo ,
on
.Pa /dev/rfd0a .
Create a 30MB image file, with the FAT partition starting
63 sectors within the image file:
.Bd -literal -offset indent
newfs_msdos -C 30M -@63s ./somefile
.Ed
.Sh DIAGNOSTICS
Exit status is 0 on success and 1 on error.
.Sh SEE ALSO
.Xr disktab 5 ,
.Xr disklabel 8 ,
.Xr fdisk 8 ,
.Xr newfs 8
.Sh HISTORY
The
.Nm
command first appeared in
.Nx 1.3 .
.Sh AUTHORS
.An Robert Nordier Aq Mt rnordier@FreeBSD.org .

View file

@ -0,0 +1,253 @@
/* $NetBSD: newfs_msdos.c,v 1.42 2013/01/23 15:29:15 christos Exp $ */
/*
* Copyright (c) 1998 Robert Nordier
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
#ifndef lint
#if 0
static const char rcsid[] =
"$FreeBSD: src/sbin/newfs_msdos/newfs_msdos.c,v 1.15 2000/10/10 01:49:37 wollman Exp $";
#else
__RCSID("$NetBSD: newfs_msdos.c,v 1.42 2013/01/23 15:29:15 christos Exp $");
#endif
#endif /* not lint */
#include <sys/param.h>
#include <stdio.h>
#include <string.h>
#include <err.h>
#include <stdlib.h>
#include <unistd.h>
#include <paths.h>
#include <errno.h>
#include "mkfs_msdos.h"
#define argto1(arg, lo, msg) argtou(arg, lo, 0xff, msg)
#define argto2(arg, lo, msg) argtou(arg, lo, 0xffff, msg)
#define argto4(arg, lo, msg) argtou(arg, lo, 0xffffffff, msg)
#define argtox(arg, lo, msg) argtou(arg, lo, UINT_MAX, msg)
__dead static void usage(void);
static u_int argtou(const char *, u_int, u_int, const char *);
static off_t argtooff(const char *, const char *);
/*
* Construct a FAT12, FAT16, or FAT32 file system.
*/
int
main(int argc, char *argv[])
{
static const char opts[] = "@:NB:C:F:I:L:O:S:a:b:c:e:f:h:i:k:m:n:o:r:s:u:";
struct msdos_options o;
char *fname, *dtype;
char buf[MAXPATHLEN];
int ch;
memset(&o, 0, sizeof(o));
while ((ch = getopt(argc, argv, opts)) != -1)
switch (ch) {
case '@':
o.offset = argtooff(optarg, "offset");
break;
case 'N':
o.no_create = 1;
break;
case 'B':
o.bootstrap = optarg;
break;
case 'C':
o.create_size = argtooff(optarg, "create size");
break;
case 'F':
o.fat_type = atoi(optarg);
break;
case 'I':
o.volume_id = argto4(optarg, 0, "volume ID");
o.volume_id_set = 1;
break;
case 'L':
o.volume_label = optarg;
break;
case 'O':
o.OEM_string = optarg;
break;
case 'S':
o.bytes_per_sector = argto2(optarg, 1, "bytes/sector");
break;
case 'a':
o.sectors_per_fat = argto4(optarg, 1, "sectors/FAT");
break;
case 'b':
o.block_size = argtox(optarg, 1, "block size");
break;
case 'c':
o.sectors_per_cluster = argto1(optarg, 1, "sectors/cluster");
break;
case 'e':
o.directory_entries = argto2(optarg, 1, "directory entries");
break;
case 'f':
o.floppy = optarg;
break;
case 'h':
o.drive_heads = argto2(optarg, 1, "drive heads");
break;
case 'i':
o.info_sector = argto2(optarg, 1, "info sector");
break;
case 'k':
o.backup_sector = argto2(optarg, 1, "backup sector");
break;
case 'm':
o.media_descriptor = argto1(optarg, 0, "media descriptor");
o.media_descriptor_set = 1;
break;
case 'n':
o.num_FAT = argto1(optarg, 1, "number of FATs");
break;
case 'o':
o.hidden_sectors = argto4(optarg, 0, "hidden sectors");
o.hidden_sectors_set = 1;
break;
case 'r':
o.reserved_sectors = argto2(optarg, 1, "reserved sectors");
break;
case 's':
o.size = argto4(optarg, 1, "file system size");
break;
case 'u':
o.sectors_per_track = argto2(optarg, 1, "sectors/track");
break;
default:
usage();
}
argc -= optind;
argv += optind;
if (argc < 1 || argc > 2)
usage();
fname = *argv++;
if (!strchr(fname, '/') && !o.create_size) {
snprintf(buf, sizeof(buf), "%sr%s", _PATH_DEV, fname);
if (!(fname = strdup(buf)))
err(1, NULL);
}
dtype = *argv;
return mkfs_msdos(fname, dtype, &o);
}
/*
* Convert and check a numeric option argument.
*/
static u_int
argtou(const char *arg, u_int lo, u_int hi, const char *msg)
{
char *s;
u_long x;
errno = 0;
x = strtoul(arg, &s, 0);
if (errno || !*arg || *s || x < lo || x > hi)
errx(1, "%s: bad %s", arg, msg);
return x;
}
/*
* Same for off_t, with optional skmgpP suffix
*/
static off_t
argtooff(const char *arg, const char *msg)
{
char *s;
off_t x;
errno = 0;
x = strtoll(arg, &s, 0);
/* allow at most one extra char */
if (errno || x < 0 || (s[0] && s[1]) )
errx(1, "%s: bad %s", arg, msg);
if (*s) { /* the extra char is the multiplier */
switch (*s) {
default:
errx(1, "%s: bad %s", arg, msg);
/* notreached */
case 's': /* sector */
case 'S':
x <<= 9; /* times 512 */
break;
case 'k': /* kilobyte */
case 'K':
x <<= 10; /* times 1024 */
break;
case 'm': /* megabyte */
case 'M':
x <<= 20; /* times 1024*1024 */
break;
case 'g': /* gigabyte */
case 'G':
x <<= 30; /* times 1024*1024*1024 */
break;
case 'p': /* partition start */
case 'P': /* partition start */
case 'l': /* partition length */
case 'L': /* partition length */
errx(1, "%s: not supported yet %s", arg, msg);
return -1;
/* notreached */
}
}
return x;
}
/*
* Print usage message.
*/
static void
usage(void)
{
fprintf(stderr,
"usage: %s [ -options ] special [disktype]\n", getprogname());
fprintf(stderr, "where the options are:\n");
static struct {
char o;
const char *h;
} opts[] = {
#define AOPT(_opt, _type, _name, _min, _desc) { _opt, _desc },
ALLOPTS
#undef AOPT
};
for (size_t i = 0; i < __arraycount(opts); i++)
fprintf(stderr, "\t-%c %s\n", opts[i].o, opts[i].h);
exit(1);
}

17
sbin/newfs_udf/Makefile Normal file
View file

@ -0,0 +1,17 @@
# $NetBSD: Makefile,v 1.4 2013/07/18 12:44:21 reinoud Exp $
.include <bsd.own.mk>
PROG= newfs_udf
MAN= newfs_udf.8
SRCS= newfs_udf.c udf_create.c udf_write.c udf_osta.c fattr.c
MOUNT= ${NETBSDSRCDIR}/sbin/mount
KUDF= ${NETBSDSRCDIR}/sys/fs/udf
CPPFLAGS+= -I${MOUNT} -I${KUDF} -I${NETBSDSRCDIR}/sys
.PATH: ${MOUNT} ${KUDF}
DPADD+=${LIBUTIL}
LDADD+=-lutil
.include <bsd.prog.mk>

191
sbin/newfs_udf/newfs_udf.8 Normal file
View file

@ -0,0 +1,191 @@
.\" $NetBSD: newfs_udf.8,v 1.18 2013/08/06 12:15:20 wiz Exp $
.\"
.\" Copyright (c) 2008 Reinoud Zandijk
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in
.\" the documentation and/or other materials provided with the
.\" distribution.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS
.\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
.\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY
.\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
.\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
.\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
.\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
.\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
.\"
.Dd August 2, 2013
.Dt NEWFS_UDF 8
.Os
.Sh NAME
.Nm newfs_udf
.Nd construct a new UDF file system
.Sh SYNOPSIS
.Nm
.Op Fl cFM
.Op Fl B Ar blockingsize
.Op Fl L Ar loglabel
.Op Fl P Ar discid
.Op Fl p Ar percentage
.Op Fl S Ar sectorsize
.Op Fl s Ar size
.Op Fl t Ar gmtoff
.Op Fl V Ar max_udf
.Op Fl v Ar min_udf
.Ar special
.Sh DESCRIPTION
The
.Nm
utility creates an UDF file system on device
.Ar special
suitable for the media currently inserted.
.Pp
The options are as follow:
.Bl -tag -width indent
.It Fl B Ar blockingsize
When creating image files, specify the blocking size or packetsize of the media
to
.Ar blockingsize .
.It Fl c
Perform a crude surface check first to weed out disc faults on rewritable
media.
.It Fl F
Force file system construction on non-empty recordable media or create an
image file.
.It Fl L Ar loglabel
Set the disc logical label to the specified
.Ar loglabel .
.It Fl M
Disable metadata partition creation when selected UDF version or media dictates
this.
For strict conformance and interchange, don't disable this unless
its causing problems.
.It Fl P Ar discid
Set the physical disc label to the specified
.Ar discid .
.Pp
Prepend
.Ar discid
with volsetname separated with a ':' if wanted.
For strict conformance and interchange, don't set this manually unless it has
a unique hex number in the first 8 character positions.
.It Fl p Ar percentage
Percentage of partition to be initially reserved for metadata on the Metadata
partition.
It defaults to 20 %.
.It Fl S Ar sectorsize
Set the sectorsize for image files.
For strict conformance and interchange, don't set this manually.
.It Fl s Ar size
For image files, set the file size to the humanized size
.Ar size .
.It Fl t Ar gmtoff
Use the specified
.Ar gmtoff
as gmt time offset for recording times on the disc.
.It Fl V Ar max_udf
Select
.Ar max_udf
as the maximum UDF version to be supported.
For UDF version 2.50, use
.Dq 0x250
or
.Dq 2.50 .
.It Fl v Ar min_udf
Select
.Ar min_udf
as the minimum UDF version to be supported.
For UDF version 2.01, use
.Dq 0x201
or
.Dq 2.01 .
.El
.Sh NOTES
The UDF file system is defined for the entire optical medium.
It can only function on the entire CD/DVD/BD so the raw partition
has to be specified for read/write actions.
For
.Nm
this means specifying the raw device with the raw partition, i.e.
.Pa /dev/rcd0d
or
.Pa /dev/rcd0c .
.Pp
Some rewritable optical media needs to be formatted first before it can be
used by UDF.
This can be done using
.Xr mmcformat 8 .
.Pp
The default UDF version is version 2.01.
.Sh EXAMPLES
Create a file system, using the specified names on the device
.Pa /dev/rcd0d
with the default UDF version :
.Bd -literal -offset indent
newfs_udf -P "Encyclopedia:copy-nr-1" -L "volume 2" /dev/rcd0d
.Ed
.Pp
Create a 4.8 GiB sparse file and configure it using
.Xr vnconfig 8
to be a 2048 sector size disc and create a new UDF file system on
.Pa /dev/rvnd0d
:
.Bd -literal -offset indent
dd if=/dev/zero of=bigdisk.2048.udf seek=9999999 count=1
vnconfig -c vnd0 bigdisk.2048.udf 2048/1/1/1
newfs_udf -L bigdisk /dev/rvnd0d
.Ed
.Pp
Create a 2 GiB file and create a new UDF file system on it using the default
512 byte sector size :
.Bd -literal -offset indent
newfs_udf -L bigdisk2 -F -s 2G bigdisk2.iso
.Ed
.Pp
Create a 200 MiB file and create a new UDF file system on it using a sector size
of 2048 :
.Bd -literal -offset indent
newfs_udf -L bigdisk2 -F -s 200M -S 2048 bigdisk3.iso
.Ed
.Pp
Create a new UDF file system on the inserted USB stick using its
native sectorsize of 512 :
.Bd -literal -offset indent
newfs_udf -L "My USB stick" /dev/rsd0d
.Ed
.Sh SEE ALSO
.Xr disktab 5 ,
.Xr disklabel 8 ,
.Xr mmcformat 8 ,
.Xr newfs 8
.Sh HISTORY
The
.Nm
command first appeared in
.Nx 5.0 .
.Sh AUTHORS
.An Reinoud Zandijk Aq Mt reinoud@NetBSD.org
.Sh BUGS
The
.Ar P
and the
.Ar S
arguments have changed meaning.
The meaning of
.Ar S
has been merged into
.Ar P
since
.Nx 6.1 .

896
sbin/newfs_udf/newfs_udf.c Normal file
View file

@ -0,0 +1,896 @@
/* $NetBSD: newfs_udf.c,v 1.18 2013/08/09 15:11:08 reinoud Exp $ */
/*
* Copyright (c) 2006, 2008, 2013 Reinoud Zandijk
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/*
* TODO
* - implement metadata formatting for BD-R
* - implement support for a read-only companion partition?
*/
#define _EXPOSE_MMC
#if 0
# define DEBUG
#endif
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <inttypes.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <util.h>
#include <time.h>
#include <assert.h>
#include <err.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/cdio.h>
#include <sys/disklabel.h>
#include <sys/dkio.h>
#include <sys/param.h>
#include <sys/queue.h>
#include <fs/udf/ecma167-udf.h>
#include <fs/udf/udf_mount.h>
#include "mountprog.h"
#include "udf_create.h"
#include "udf_write.h"
#include "newfs_udf.h"
/* prototypes */
int newfs_udf(int argc, char **argv);
static void usage(void) __attribute__((__noreturn__));
/* queue for temporary storage of sectors to be written out */
struct wrsect {
uint64_t sectornr;
uint8_t *sector_data;
TAILQ_ENTRY(wrsect) next;
};
/* write queue and track blocking skew */
TAILQ_HEAD(wrsect_list, wrsect) write_queue;
/* global variables describing disc and format requests */
int fd; /* device: file descriptor */
char *dev; /* device: name */
struct mmc_discinfo mmc_discinfo; /* device: disc info */
char *format_str; /* format: string representation */
int format_flags; /* format: attribute flags */
int media_accesstype; /* derived from current mmc cap */
int check_surface; /* for rewritables */
int imagefile_secsize; /* for files */
int emul_packetsize; /* for discs and files */
int wrtrack_skew;
int meta_perc = UDF_META_PERC;
float meta_fract = (float) UDF_META_PERC / 100.0;
/* --------------------------------------------------------------------- */
/*
* write queue implementation
*/
int
udf_write_sector(void *sector, uint64_t location)
{
struct wrsect *pos, *seekpos;
/* search location */
TAILQ_FOREACH_REVERSE(seekpos, &write_queue, wrsect_list, next) {
if (seekpos->sectornr <= location)
break;
}
if ((seekpos == NULL) || (seekpos->sectornr != location)) {
pos = calloc(1, sizeof(struct wrsect));
if (pos == NULL)
return ENOMEM;
/* allocate space for copy of sector data */
pos->sector_data = calloc(1, context.sector_size);
if (pos->sector_data == NULL)
return ENOMEM;
pos->sectornr = location;
if (seekpos) {
TAILQ_INSERT_AFTER(&write_queue, seekpos, pos, next);
} else {
TAILQ_INSERT_HEAD(&write_queue, pos, next);
}
} else {
pos = seekpos;
}
memcpy(pos->sector_data, sector, context.sector_size);
return 0;
}
/*
* Now all write requests are queued in the TAILQ, write them out to the
* disc/file image. Special care needs to be taken for devices that are only
* strict overwritable i.e. only in packet size chunks
*
* XXX support for growing vnd?
*/
int
writeout_write_queue(void)
{
struct wrsect *pos;
uint64_t offset;
uint64_t line_start, new_line_start;
uint32_t line_len, line_offset, relpos;
uint32_t blockingnr;
uint8_t *linebuf, *adr;
blockingnr = layout.blockingnr;
line_len = blockingnr * context.sector_size;
line_offset = wrtrack_skew * context.sector_size;
linebuf = malloc(line_len);
if (linebuf == NULL)
return ENOMEM;
pos = TAILQ_FIRST(&write_queue);
bzero(linebuf, line_len);
/*
* Always writing out in whole lines now; this is slightly wastefull
* on logical overwrite volumes but it reduces complexity and the loss
* is near zero compared to disc size.
*/
line_start = (pos->sectornr - wrtrack_skew) / blockingnr;
TAILQ_FOREACH(pos, &write_queue, next) {
new_line_start = (pos->sectornr - wrtrack_skew) / blockingnr;
if (new_line_start != line_start) {
/* write out */
offset = (uint64_t) line_start * line_len + line_offset;
#ifdef DEBUG
printf("WRITEOUT %08"PRIu64" + %02d -- "
"[%08"PRIu64"..%08"PRIu64"]\n",
offset / context.sector_size, blockingnr,
offset / context.sector_size,
offset / context.sector_size + blockingnr-1);
#endif
if (pwrite(fd, linebuf, line_len, offset) < 0) {
perror("Writing failed");
return errno;
}
line_start = new_line_start;
bzero(linebuf, line_len);
}
relpos = (pos->sectornr - wrtrack_skew) % blockingnr;
adr = linebuf + relpos * context.sector_size;
memcpy(adr, pos->sector_data, context.sector_size);
}
/* writeout last chunk */
offset = (uint64_t) line_start * line_len + line_offset;
#ifdef DEBUG
printf("WRITEOUT %08"PRIu64" + %02d -- [%08"PRIu64"..%08"PRIu64"]\n",
offset / context.sector_size, blockingnr,
offset / context.sector_size,
offset / context.sector_size + blockingnr-1);
#endif
if (pwrite(fd, linebuf, line_len, offset) < 0) {
perror("Writing failed");
return errno;
}
/* success */
return 0;
}
/* --------------------------------------------------------------------- */
/*
* mmc_discinfo and mmc_trackinfo readers modified from origional in udf main
* code in sys/fs/udf/
*/
#ifdef DEBUG
static void
udf_dump_discinfo(struct mmc_discinfo *di)
{
char bits[128];
printf("Device/media info :\n");
printf("\tMMC profile 0x%02x\n", di->mmc_profile);
printf("\tderived class %d\n", di->mmc_class);
printf("\tsector size %d\n", di->sector_size);
printf("\tdisc state %d\n", di->disc_state);
printf("\tlast ses state %d\n", di->last_session_state);
printf("\tbg format state %d\n", di->bg_format_state);
printf("\tfrst track %d\n", di->first_track);
printf("\tfst on last ses %d\n", di->first_track_last_session);
printf("\tlst on last ses %d\n", di->last_track_last_session);
printf("\tlink block penalty %d\n", di->link_block_penalty);
snprintb(bits, sizeof(bits), MMC_DFLAGS_FLAGBITS, (uint64_t) di->disc_flags);
printf("\tdisc flags %s\n", bits);
printf("\tdisc id %x\n", di->disc_id);
printf("\tdisc barcode %"PRIx64"\n", di->disc_barcode);
printf("\tnum sessions %d\n", di->num_sessions);
printf("\tnum tracks %d\n", di->num_tracks);
snprintb(bits, sizeof(bits), MMC_CAP_FLAGBITS, di->mmc_cur);
printf("\tcapabilities cur %s\n", bits);
snprintb(bits, sizeof(bits), MMC_CAP_FLAGBITS, di->mmc_cap);
printf("\tcapabilities cap %s\n", bits);
printf("\n");
printf("\tlast_possible_lba %d\n", di->last_possible_lba);
printf("\n");
}
#else
#define udf_dump_discinfo(a);
#endif
/* --------------------------------------------------------------------- */
static int
udf_update_discinfo(struct mmc_discinfo *di)
{
struct stat st;
struct disklabel disklab;
struct partition *dp;
off_t size, sectors, secsize;
int partnr, error;
memset(di, 0, sizeof(struct mmc_discinfo));
/* check if we're on a MMC capable device, i.e. CD/DVD */
error = ioctl(fd, MMCGETDISCINFO, di);
if (error == 0)
return 0;
/* (re)fstat the file */
fstat(fd, &st);
if (S_ISREG(st.st_mode)) {
/* file support; we pick the minimum sector size allowed */
size = st.st_size;
secsize = imagefile_secsize;
sectors = size / secsize;
} else {
/*
* disc partition support; note we can't use DIOCGPART in
* userland so get disc label and use the stat info to get the
* partition number.
*/
if (ioctl(fd, DIOCGDINFO, &disklab) == -1) {
/* failed to get disclabel! */
perror("disklabel");
return errno;
}
/* get disk partition it refers to */
fstat(fd, &st);
partnr = DISKPART(st.st_rdev);
dp = &disklab.d_partitions[partnr];
/* TODO problem with last_possible_lba on resizable VND */
if (dp->p_size == 0) {
perror("faulty disklabel partition returned, "
"check label\n");
return EIO;
}
sectors = dp->p_size;
secsize = disklab.d_secsize;
}
/* set up a disc info profile for partitions */
di->mmc_profile = 0x01; /* disc type */
di->mmc_class = MMC_CLASS_DISC;
di->disc_state = MMC_STATE_CLOSED;
di->last_session_state = MMC_STATE_CLOSED;
di->bg_format_state = MMC_BGFSTATE_COMPLETED;
di->link_block_penalty = 0;
di->mmc_cur = MMC_CAP_RECORDABLE | MMC_CAP_REWRITABLE |
MMC_CAP_ZEROLINKBLK | MMC_CAP_HW_DEFECTFREE;
di->mmc_cap = di->mmc_cur;
di->disc_flags = MMC_DFLAGS_UNRESTRICTED;
di->last_possible_lba = sectors - 1;
di->sector_size = secsize;
di->num_sessions = 1;
di->num_tracks = 1;
di->first_track = 1;
di->first_track_last_session = di->last_track_last_session = 1;
return 0;
}
int
udf_update_trackinfo(struct mmc_discinfo *di, struct mmc_trackinfo *ti)
{
int error, class;
class = di->mmc_class;
if (class != MMC_CLASS_DISC) {
/* tracknr specified in struct ti */
error = ioctl(fd, MMCGETTRACKINFO, ti);
return error;
}
/* discs partition support */
if (ti->tracknr != 1)
return EIO;
/* create fake ti (TODO check for resized vnds) */
ti->sessionnr = 1;
ti->track_mode = 0; /* XXX */
ti->data_mode = 0; /* XXX */
ti->flags = MMC_TRACKINFO_LRA_VALID | MMC_TRACKINFO_NWA_VALID;
ti->track_start = 0;
ti->packet_size = emul_packetsize;
/* TODO support for resizable vnd */
ti->track_size = di->last_possible_lba;
ti->next_writable = di->last_possible_lba;
ti->last_recorded = ti->next_writable;
ti->free_blocks = 0;
return 0;
}
static int
udf_setup_writeparams(struct mmc_discinfo *di)
{
struct mmc_writeparams mmc_writeparams;
int error;
if (di->mmc_class == MMC_CLASS_DISC)
return 0;
/*
* only CD burning normally needs setting up, but other disc types
* might need other settings to be made. The MMC framework will set up
* the nessisary recording parameters according to the disc
* characteristics read in. Modifications can be made in the discinfo
* structure passed to change the nature of the disc.
*/
memset(&mmc_writeparams, 0, sizeof(struct mmc_writeparams));
mmc_writeparams.mmc_class = di->mmc_class;
mmc_writeparams.mmc_cur = di->mmc_cur;
/*
* UDF dictates first track to determine track mode for the whole
* disc. [UDF 1.50/6.10.1.1, UDF 1.50/6.10.2.1]
* To prevent problems with a `reserved' track in front we start with
* the 2nd track and if that is not valid, go for the 1st.
*/
mmc_writeparams.tracknr = 2;
mmc_writeparams.data_mode = MMC_DATAMODE_DEFAULT; /* XA disc */
mmc_writeparams.track_mode = MMC_TRACKMODE_DEFAULT; /* data */
error = ioctl(fd, MMCSETUPWRITEPARAMS, &mmc_writeparams);
if (error) {
mmc_writeparams.tracknr = 1;
error = ioctl(fd, MMCSETUPWRITEPARAMS, &mmc_writeparams);
}
return error;
}
static void
udf_synchronise_caches(void)
{
struct mmc_op mmc_op;
bzero(&mmc_op, sizeof(struct mmc_op));
mmc_op.operation = MMC_OP_SYNCHRONISECACHE;
/* this device might not know this ioct, so just be ignorant */
(void) ioctl(fd, MMCOP, &mmc_op);
}
/* --------------------------------------------------------------------- */
static int
udf_prepare_disc(void)
{
struct mmc_trackinfo ti;
struct mmc_op op;
int tracknr, error;
/* If the last track is damaged, repair it */
ti.tracknr = mmc_discinfo.last_track_last_session;
error = udf_update_trackinfo(&mmc_discinfo, &ti);
if (error)
return error;
if (ti.flags & MMC_TRACKINFO_DAMAGED) {
/*
* Need to repair last track before anything can be done.
* this is an optional command, so ignore its error but report
* warning.
*/
memset(&op, 0, sizeof(op));
op.operation = MMC_OP_REPAIRTRACK;
op.mmc_profile = mmc_discinfo.mmc_profile;
op.tracknr = ti.tracknr;
error = ioctl(fd, MMCOP, &op);
if (error)
(void)printf("Drive can't explicitly repair last "
"damaged track, but it might autorepair\n");
}
/* last track (if any) might not be damaged now, operations are ok now */
/* setup write parameters from discinfo */
error = udf_setup_writeparams(&mmc_discinfo);
if (error)
return error;
/* if the drive is not sequential, we're done */
if ((mmc_discinfo.mmc_cur & MMC_CAP_SEQUENTIAL) == 0)
return 0;
#ifdef notyet
/* if last track is not the reserved but an empty track, unreserve it */
if (ti.flags & MMC_TRACKINFO_BLANK) {
if (ti.flags & MMC_TRACKINFO_RESERVED == 0) {
memset(&op, 0, sizeof(op));
op.operation = MMC_OP_UNRESERVETRACK;
op.mmc_profile = mmc_discinfo.mmc_profile;
op.tracknr = ti.tracknr;
error = ioctl(fd, MMCOP, &op);
if (error)
return error;
/* update discinfo since it changed by the operation */
error = udf_update_discinfo(&mmc_discinfo);
if (error)
return error;
}
}
#endif
/* close the last session if its still open */
if (mmc_discinfo.last_session_state == MMC_STATE_INCOMPLETE) {
printf("Closing last open session if present\n");
/* close all associated tracks */
tracknr = mmc_discinfo.first_track_last_session;
while (tracknr <= mmc_discinfo.last_track_last_session) {
ti.tracknr = tracknr;
error = udf_update_trackinfo(&mmc_discinfo, &ti);
if (error)
return error;
printf("\tClosing open track %d\n", tracknr);
memset(&op, 0, sizeof(op));
op.operation = MMC_OP_CLOSETRACK;
op.mmc_profile = mmc_discinfo.mmc_profile;
op.tracknr = tracknr;
error = ioctl(fd, MMCOP, &op);
if (error)
return error;
tracknr ++;
}
printf("Closing session\n");
memset(&op, 0, sizeof(op));
op.operation = MMC_OP_CLOSESESSION;
op.mmc_profile = mmc_discinfo.mmc_profile;
op.sessionnr = mmc_discinfo.num_sessions;
error = ioctl(fd, MMCOP, &op);
if (error)
return error;
/* update discinfo since it changed by the operations */
error = udf_update_discinfo(&mmc_discinfo);
if (error)
return error;
}
if (format_flags & FORMAT_TRACK512) {
/* get last track again */
ti.tracknr = mmc_discinfo.last_track_last_session;
error = udf_update_trackinfo(&mmc_discinfo, &ti);
if (error)
return error;
/* Split up the space at 512 for iso cd9660 hooking */
memset(&op, 0, sizeof(op));
op.operation = MMC_OP_RESERVETRACK_NWA; /* UPTO nwa */
op.mmc_profile = mmc_discinfo.mmc_profile;
op.extent = 512; /* size */
error = ioctl(fd, MMCOP, &op);
if (error)
return error;
}
return 0;
}
/* --------------------------------------------------------------------- */
int
udf_surface_check(void)
{
uint32_t loc, block_bytes;
uint32_t sector_size, blockingnr, bpos;
uint8_t *buffer;
int error, num_errors;
sector_size = context.sector_size;
blockingnr = layout.blockingnr;
block_bytes = layout.blockingnr * sector_size;
if ((buffer = malloc(block_bytes)) == NULL)
return ENOMEM;
/* set all one to not kill Flash memory? */
for (bpos = 0; bpos < block_bytes; bpos++)
buffer[bpos] = 0x00;
printf("\nChecking disc surface : phase 1 - writing\n");
num_errors = 0;
loc = layout.first_lba;
while (loc <= layout.last_lba) {
/* write blockingnr sectors */
error = pwrite(fd, buffer, block_bytes, loc*sector_size);
printf(" %08d + %d (%02d %%)\r", loc, blockingnr,
(int)((100.0 * loc)/layout.last_lba));
fflush(stdout);
if (error == -1) {
/* block is bad */
printf("BAD block at %08d + %d \n",
loc, layout.blockingnr);
if ((error = udf_register_bad_block(loc))) {
free(buffer);
return error;
}
num_errors ++;
}
loc += layout.blockingnr;
}
printf("\nChecking disc surface : phase 2 - reading\n");
num_errors = 0;
loc = layout.first_lba;
while (loc <= layout.last_lba) {
/* read blockingnr sectors */
error = pread(fd, buffer, block_bytes, loc*sector_size);
printf(" %08d + %d (%02d %%)\r", loc, blockingnr,
(int)((100.0 * loc)/layout.last_lba));
fflush(stdout);
if (error == -1) {
/* block is bad */
printf("BAD block at %08d + %d \n",
loc, layout.blockingnr);
if ((error = udf_register_bad_block(loc))) {
free(buffer);
return error;
}
num_errors ++;
}
loc += layout.blockingnr;
}
printf("Scan complete : %d bad blocks found\n", num_errors);
free(buffer);
return 0;
}
/* --------------------------------------------------------------------- */
static int
udf_do_newfs(void)
{
int error;
error = udf_do_newfs_prefix();
if (error)
return error;
error = udf_do_rootdir();
if (error)
return error;
error = udf_do_newfs_postfix();
return error;
}
/* --------------------------------------------------------------------- */
static void
usage(void)
{
(void)fprintf(stderr, "Usage: %s [-cFM] [-L loglabel] "
"[-P discid] [-S sectorsize] [-s size] [-p perc] "
"[-t gmtoff] [-v min_udf] [-V max_udf] special\n", getprogname());
exit(EXIT_FAILURE);
}
int
main(int argc, char **argv)
{
struct tm *tm;
struct stat st;
time_t now;
off_t setsize;
char scrap[255], *colon;
int ch, req_enable, req_disable, force;
int error;
setprogname(argv[0]);
/* initialise */
format_str = strdup("");
req_enable = req_disable = 0;
format_flags = FORMAT_INVALID;
force = 0;
check_surface = 0;
setsize = 0;
imagefile_secsize = 512; /* minimum allowed sector size */
emul_packetsize = 32; /* reasonable default */
srandom((unsigned long) time(NULL));
udf_init_create_context();
context.app_name = "*NetBSD newfs";
context.app_version_main = APP_VERSION_MAIN;
context.app_version_sub = APP_VERSION_SUB;
context.impl_name = IMPL_NAME;
/* minimum and maximum UDF versions we advise */
context.min_udf = 0x201;
context.max_udf = 0x201;
/* use user's time zone as default */
(void)time(&now);
tm = localtime(&now);
context.gmtoff = tm->tm_gmtoff;
/* process options */
while ((ch = getopt(argc, argv, "cFL:Mp:P:s:S:B:t:v:V:")) != -1) {
switch (ch) {
case 'c' :
check_surface = 1;
break;
case 'F' :
force = 1;
break;
case 'L' :
if (context.logvol_name) free(context.logvol_name);
context.logvol_name = strdup(optarg);
break;
case 'M' :
req_disable |= FORMAT_META;
break;
case 'p' :
meta_perc = a_num(optarg, "meta_perc");
/* limit to `sensible` values */
meta_perc = MIN(meta_perc, 99);
meta_perc = MAX(meta_perc, 1);
meta_fract = (float) meta_perc/100.0;
break;
case 'v' :
context.min_udf = a_udf_version(optarg, "min_udf");
if (context.min_udf > context.max_udf)
context.max_udf = context.min_udf;
break;
case 'V' :
context.max_udf = a_udf_version(optarg, "max_udf");
if (context.min_udf > context.max_udf)
context.min_udf = context.max_udf;
break;
case 'P' :
/* check if there is a ':' in the name */
if ((colon = strstr(optarg, ":"))) {
if (context.volset_name)
free(context.volset_name);
*colon = 0;
context.volset_name = strdup(optarg);
optarg = colon+1;
}
if (context.primary_name)
free(context.primary_name);
if ((strstr(optarg, ":"))) {
perror("primary name can't have ':' in its name");
return EXIT_FAILURE;
}
context.primary_name = strdup(optarg);
break;
case 's' :
/* support for files, set file size */
/* XXX support for formatting recordables on vnd/file? */
if (dehumanize_number(optarg, &setsize) < 0) {
perror("can't parse size argument");
return EXIT_FAILURE;
}
setsize = MAX(0, setsize);
break;
case 'S' :
imagefile_secsize = a_num(optarg, "secsize");
imagefile_secsize = MAX(512, imagefile_secsize);
break;
case 'B' :
emul_packetsize = a_num(optarg,
"blockingnr, packetsize");
emul_packetsize = MAX(emul_packetsize, 1);
emul_packetsize = MIN(emul_packetsize, 32);
break;
case 't' :
/* time zone overide */
context.gmtoff = a_num(optarg, "gmtoff");
break;
default :
usage();
/* NOTREACHED */
}
}
if (optind + 1 != argc)
usage();
/* get device and directory specifier */
dev = argv[optind];
/* open device */
if ((fd = open(dev, O_RDWR, 0)) == -1) {
/* check if we need to create a file */
fd = open(dev, O_RDONLY, 0);
if (fd > 0) {
perror("device is there but can't be opened for read/write");
return EXIT_FAILURE;
}
if (!force) {
perror("can't open device");
return EXIT_FAILURE;
}
if (setsize == 0) {
perror("need to create image file but no size specified");
return EXIT_FAILURE;
}
/* need to create a file */
fd = open(dev, O_RDWR | O_CREAT | O_TRUNC, 0777);
if (fd == -1) {
perror("can't create image file");
return EXIT_FAILURE;
}
}
/* stat the device */
if (fstat(fd, &st) != 0) {
perror("can't stat the device");
close(fd);
return EXIT_FAILURE;
}
if (S_ISREG(st.st_mode)) {
if (setsize == 0)
setsize = st.st_size;
/* sanitise arguments */
imagefile_secsize &= ~511;
setsize &= ~(imagefile_secsize-1);
if (ftruncate(fd, setsize)) {
perror("can't resize file");
return EXIT_FAILURE;
}
}
/* formatting can only be done on raw devices */
if (!S_ISREG(st.st_mode) && !S_ISCHR(st.st_mode)) {
printf("%s is not a raw device\n", dev);
close(fd);
return EXIT_FAILURE;
}
/* just in case something went wrong, synchronise the drive's cache */
udf_synchronise_caches();
/* get 'disc' information */
error = udf_update_discinfo(&mmc_discinfo);
if (error) {
perror("can't retrieve discinfo");
close(fd);
return EXIT_FAILURE;
}
/* derive disc identifiers when not specified and check given */
error = udf_proces_names();
if (error) {
/* error message has been printed */
close(fd);
return EXIT_FAILURE;
}
/* derive newfs disc format from disc profile */
error = udf_derive_format(req_enable, req_disable, force);
if (error) {
/* error message has been printed */
close(fd);
return EXIT_FAILURE;
}
udf_dump_discinfo(&mmc_discinfo);
printf("Formatting disc compatible with UDF version %x to %x\n\n",
context.min_udf, context.max_udf);
(void)snprintb(scrap, sizeof(scrap), FORMAT_FLAGBITS,
(uint64_t) format_flags);
printf("UDF properties %s\n", scrap);
printf("Volume set `%s'\n", context.volset_name);
printf("Primary volume `%s`\n", context.primary_name);
printf("Logical volume `%s`\n", context.logvol_name);
if (format_flags & FORMAT_META)
printf("Metadata percentage %d %%\n", meta_perc);
printf("\n");
/* prepare disc if nessisary (recordables mainly) */
error = udf_prepare_disc();
if (error) {
perror("preparing disc failed");
close(fd);
return EXIT_FAILURE;
};
/* setup sector writeout queue's */
TAILQ_INIT(&write_queue);
/* perform the newfs itself */
error = udf_do_newfs();
if (!error) {
/* write out sectors */
error = writeout_write_queue();
}
/* in any case, synchronise the drive's cache to prevent lockups */
udf_synchronise_caches();
close(fd);
if (error)
return EXIT_FAILURE;
return EXIT_SUCCESS;
}
/* --------------------------------------------------------------------- */

View file

@ -0,0 +1,67 @@
/*
* Copyright (c) 2006, 2008, 2013 Reinoud Zandijk
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef _FS_UDF_NEWFS_UDF_H_
#define _FS_UDF_NEWFS_UDF_H_
/* general settings */
#define UDF_512_TRACK 0 /* NOT recommended */
#define UDF_META_PERC 20 /* picked */
/* Identifying myself */
#define APP_VERSION_MAIN 0
#define APP_VERSION_SUB 5
#define IMPL_NAME "*NetBSD userland UDF"
/* global variables describing disc and format requests */
extern int fd; /* device: file descriptor */
extern char *dev; /* device: name */
extern struct mmc_discinfo mmc_discinfo;/* device: disc info */
extern char *format_str; /* format: string representation */
extern int format_flags; /* format: attribute flags */
extern int media_accesstype; /* derived from current mmc cap */
extern int check_surface; /* for rewritables */
extern int wrtrack_skew;
extern int meta_perc;
extern float meta_fract;
/* shared structure between udf_create.c users */
struct udf_create_context context;
struct udf_disclayout layout;
/* prototypes */
int udf_write_sector(void *sector, uint64_t location);
int udf_update_trackinfo(struct mmc_discinfo *di, struct mmc_trackinfo *ti);
/* tmp */
int writeout_write_queue(void);
int udf_surface_check(void);
#endif /* _FS_UDF_UDF_WRITE_H_ */

2392
sbin/newfs_udf/udf_create.c Normal file

File diff suppressed because it is too large Load diff

283
sbin/newfs_udf/udf_create.h Normal file
View file

@ -0,0 +1,283 @@
/* $NetBSD: udf_create.h,v 1.7 2013/08/09 15:11:08 reinoud Exp $ */
/*
* Copyright (c) 2006, 2008 Reinoud Zandijk
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef _FS_UDF_UDF_CREATE_H_
#define _FS_UDF_UDF_CREATE_H_
#include <sys/types.h>
#include <sys/stat.h>
#if !HAVE_NBTOOL_CONFIG_H
#include <fs/udf/ecma167-udf.h>
#else
#include "../../sys/fs/udf/ecma167-udf.h"
#endif
#include "udf_bswap.h"
#include "udf_osta.h"
/* format flags indicating properties of disc to create */
#define FORMAT_WRITEONCE 0x00001
#define FORMAT_SEQUENTIAL 0x00002
#define FORMAT_REWRITABLE 0x00004
#define FORMAT_SPARABLE 0x00008
#define FORMAT_META 0x00010
#define FORMAT_LOW 0x00020
#define FORMAT_VAT 0x00040
#define FORMAT_WORM 0x00080
#define FORMAT_TRACK512 0x00100
#define FORMAT_INVALID 0x00200
#define FORMAT_READONLY 0x00400
#define FORMAT_FLAGBITS \
"\10\1WRITEONCE\2SEQUENTIAL\3REWRITABLE\4SPARABLE\5META\6LOW" \
"\7VAT\10WORM\11TRACK512\12INVALID\13READONLY"
/* structure space */
#define UDF_ANCHORS 4 /* 256, 512, N-256, N */
#define UDF_PARTITIONS 4 /* overkill */
#define UDF_PMAPS 4 /* overkill */
/* misc constants */
#define UDF_MAX_NAMELEN 255 /* as per SPEC */
/* translation constants */
#define UDF_VTOP_RAWPART UDF_PMAPS /* [0..UDF_PMAPS> are normal */
/* virtual to physical mapping types */
#define UDF_VTOP_TYPE_RAW 0
#define UDF_VTOP_TYPE_UNKNOWN 0
#define UDF_VTOP_TYPE_PHYS 1
#define UDF_VTOP_TYPE_VIRT 2
#define UDF_VTOP_TYPE_SPARABLE 3
#define UDF_VTOP_TYPE_META 4
#define UDF_TRANS_ZERO ((uint64_t) -1)
#define UDF_TRANS_UNMAPPED ((uint64_t) -2)
#define UDF_TRANS_INTERN ((uint64_t) -3)
#define UDF_MAX_SECTOR ((uint64_t) -10) /* high water mark */
/* handys */
#define UDF_ROUNDUP(val, gran) \
((uint64_t) (gran) * (((uint64_t)(val) + (gran)-1) / (gran)))
#define UDF_ROUNDDOWN(val, gran) \
((uint64_t) (gran) * (((uint64_t)(val)) / (gran)))
/* disc offsets for various structures and their sizes */
struct udf_disclayout {
uint32_t wrtrack_skew;
uint32_t iso9660_vrs;
uint32_t anchors[UDF_ANCHORS];
uint32_t vds_size, vds1, vds2;
uint32_t lvis_size, lvis;
uint32_t first_lba, last_lba;
uint32_t sector_size;
uint32_t blockingnr, align_blockingnr, sparable_blockingnr;
uint32_t meta_blockingnr, meta_alignment;
/* sparables */
uint32_t sparable_blocks;
uint32_t sparable_area, sparable_area_size;
uint32_t sparing_table_dscr_lbas;
uint32_t spt_1, spt_2;
/* bitmaps */
uint32_t alloc_bitmap_dscr_size;
uint32_t unalloc_space, freed_space;
uint32_t meta_bitmap_dscr_size;
uint32_t meta_bitmap_space;
/* metadata partition */
uint32_t meta_file, meta_mirror, meta_bitmap;
uint32_t meta_part_start_lba, meta_part_size_lba;
/* main partition */
uint32_t part_start_lba, part_size_lba;
uint32_t fsd, rootdir, vat;
};
/* all info about discs and descriptors building */
struct udf_create_context {
/* descriptors */
int dscrver; /* 2 or 3 */
int min_udf; /* hex */
int max_udf; /* hex */
int serialnum; /* format serialno */
int gmtoff; /* in minutes */
/* XXX to layout? */
uint32_t sector_size;
/* identification */
char *logvol_name;
char *primary_name;
char *volset_name;
char *fileset_name;
char const *app_name;
char const *impl_name;
int app_version_main;
int app_version_sub;
/* building */
int vds_seq; /* for building functions */
int unique_id; /* only first few are used */
/* constructed structures */
struct anchor_vdp *anchors[UDF_ANCHORS]; /* anchors to VDS */
struct pri_vol_desc *primary_vol; /* identification */
struct logvol_desc *logical_vol; /* main mapping v->p */
struct unalloc_sp_desc *unallocated; /* free UDF space */
struct impvol_desc *implementation; /* likely reduntant */
struct logvol_int_desc *logvol_integrity; /* current integrity */
struct part_desc *partitions[UDF_PARTITIONS]; /* partitions */
/* XXX to layout? */
int data_part;
int metadata_part;
/* block numbers as offset in partition */
uint32_t metadata_alloc_pos;
uint32_t data_alloc_pos;
/* derived; points *into* other structures */
struct udf_logvol_info *logvol_info; /* inside integrity */
/* fileset and root directories */
struct fileset_desc *fileset_desc; /* normally one */
/* logical to physical translations */
int vtop[UDF_PMAPS+1]; /* vpartnr trans */
int vtop_tp[UDF_PMAPS+1]; /* type of trans */
uint64_t vtop_offset[UDF_PMAPS+1]; /* offset in lb */
/* sparable */
struct udf_sparing_table*sparing_table; /* replacements */
/* VAT file */
uint32_t vat_size; /* length */
uint32_t vat_allocated; /* allocated length */
uint32_t vat_start; /* offset 1st entry */
uint8_t *vat_contents; /* the VAT */
/* meta data partition */
struct extfile_entry *meta_file;
struct extfile_entry *meta_mirror;
struct extfile_entry *meta_bitmap;
/* lvint */
int num_files;
int num_directories;
uint32_t part_size[UDF_PARTITIONS];
uint32_t part_free[UDF_PARTITIONS];
struct space_bitmap_desc*part_unalloc_bits[UDF_PARTITIONS];
struct space_bitmap_desc*part_freed_bits [UDF_PARTITIONS];
};
/* globals */
extern struct udf_create_context context;
extern struct udf_disclayout layout;
/* prototypes */
void udf_init_create_context(void);
int a_udf_version(const char *s, const char *id_type);
int udf_calculate_disc_layout(int format_flags, int min_udf,
uint32_t wrtrack_skew,
uint32_t first_lba, uint32_t last_lba,
uint32_t sector_size, uint32_t blockingnr,
uint32_t sparable_blocks,
float meta_fract);
void udf_osta_charset(struct charspec *charspec);
void udf_encode_osta_id(char *osta_id, uint16_t len, char *text);
void udf_set_regid(struct regid *regid, char const *name);
void udf_add_domain_regid(struct regid *regid);
void udf_add_udf_regid(struct regid *regid);
void udf_add_impl_regid(struct regid *regid);
void udf_add_app_regid(struct regid *regid);
int udf_validate_tag_sum(union dscrptr *dscr);
int udf_validate_tag_and_crc_sums(union dscrptr *dscr);
void udf_set_timestamp_now(struct timestamp *timestamp);
void udf_inittag(struct desc_tag *tag, int tagid, uint32_t loc);
int udf_create_anchor(int num);
void udf_create_terminator(union dscrptr *dscr, uint32_t loc);
int udf_create_primaryd(void);
int udf_create_partitiond(int part_num, int part_accesstype);
int udf_create_unalloc_spaced(void);
int udf_create_sparing_tabled(void);
int udf_create_space_bitmap(uint32_t dscr_size, uint32_t part_size_lba,
struct space_bitmap_desc **sbdp);
int udf_create_logical_dscr(int format_flags);
int udf_create_impvold(char *field1, char *field2, char *field3);
int udf_create_fsd(void);
int udf_create_lvintd(int type);
void udf_update_lvintd(int type);
int udf_register_bad_block(uint32_t location);
void udf_mark_allocated(uint32_t start_lb, int partnr, uint32_t blocks);
int udf_create_new_fe(struct file_entry **fep, int file_type,
struct stat *st);
int udf_create_new_efe(struct extfile_entry **efep, int file_type,
struct stat *st);
int udf_encode_symlink(uint8_t **pathbufp, uint32_t *pathlenp, char *target);
void udf_advance_uniqueid(void);
int udf_fidsize(struct fileid_desc *fid);
void udf_create_fid(uint32_t diroff, struct fileid_desc *fid,
char *name, int namelen, struct long_ad *ref);
int udf_create_parentfid(struct fileid_desc *fid, struct long_ad *parent);
int udf_create_meta_files(void);
int udf_create_new_rootdir(union dscrptr **dscr);
int udf_create_VAT(union dscrptr **vat_dscr);
void udf_prepend_VAT_file(void);
void udf_vat_update(uint32_t virt, uint32_t phys);
int udf_append_VAT_file(void);
#endif /* _FS_UDF_UDF_CREATE_H_ */

906
sbin/newfs_udf/udf_write.c Normal file
View file

@ -0,0 +1,906 @@
/* $NetBSD: udf_write.c,v 1.8 2013/08/25 14:13:47 reinoud Exp $ */
/*
* Copyright (c) 2006, 2008, 2013 Reinoud Zandijk
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#if HAVE_NBTOOL_CONFIG_H
#include "nbtool_config.h"
#endif
#include <sys/cdefs.h>
__RCSID("$NetBSD: udf_write.c,v 1.8 2013/08/25 14:13:47 reinoud Exp $");
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#include <assert.h>
#include <err.h>
#include <sys/types.h>
#include <sys/param.h>
#if !HAVE_NBTOOL_CONFIG_H
#define _EXPOSE_MMC
#include <sys/cdio.h>
#else
#include "udf/cdio_mmc_structs.h"
#endif
#include "udf_create.h"
#include "udf_write.h"
#include "newfs_udf.h"
union dscrptr *terminator_dscr;
static int
udf_write_phys(void *blob, uint32_t location, uint32_t sects)
{
uint32_t phys, cnt;
uint8_t *bpos;
int error;
for (cnt = 0; cnt < sects; cnt++) {
bpos = (uint8_t *) blob;
bpos += context.sector_size * cnt;
phys = location + cnt;
error = udf_write_sector(bpos, phys);
if (error)
return error;
}
return 0;
}
static int
udf_write_dscr_phys(union dscrptr *dscr, uint32_t location,
uint32_t sects)
{
dscr->tag.tag_loc = udf_rw32(location);
(void) udf_validate_tag_and_crc_sums(dscr);
return udf_write_phys(dscr, location, sects);
}
int
udf_write_dscr_virt(union dscrptr *dscr, uint32_t location, uint32_t vpart,
uint32_t sects)
{
struct file_entry *fe;
struct extfile_entry *efe;
struct extattrhdr_desc *extattrhdr;
uint32_t phys;
extattrhdr = NULL;
if (udf_rw16(dscr->tag.id) == TAGID_FENTRY) {
fe = (struct file_entry *) dscr;
if (udf_rw32(fe->l_ea) > 0)
extattrhdr = (struct extattrhdr_desc *) fe->data;
}
if (udf_rw16(dscr->tag.id) == TAGID_EXTFENTRY) {
efe = (struct extfile_entry *) dscr;
if (udf_rw32(efe->l_ea) > 0)
extattrhdr = (struct extattrhdr_desc *) efe->data;
}
if (extattrhdr) {
extattrhdr->tag.tag_loc = udf_rw32(location);
udf_validate_tag_and_crc_sums((union dscrptr *) extattrhdr);
}
dscr->tag.tag_loc = udf_rw32(location);
udf_validate_tag_and_crc_sums(dscr);
/* determine physical location */
phys = context.vtop_offset[vpart];
if (context.vtop_tp[vpart] == UDF_VTOP_TYPE_VIRT) {
udf_vat_update(location, context.data_alloc_pos);
phys += context.data_alloc_pos++;
} else {
phys += location;
}
return udf_write_phys(dscr, phys, sects);
}
void
udf_metadata_alloc(int nblk, struct long_ad *pos)
{
memset(pos, 0, sizeof(*pos));
pos->len = udf_rw32(nblk * context.sector_size);
pos->loc.lb_num = udf_rw32(context.metadata_alloc_pos);
pos->loc.part_num = udf_rw16(context.metadata_part);
udf_mark_allocated(context.metadata_alloc_pos, context.metadata_part,
nblk);
context.metadata_alloc_pos += nblk;
if (context.metadata_part == context.data_part)
context.data_alloc_pos = context.metadata_alloc_pos;
}
void
udf_data_alloc(int nblk, struct long_ad *pos)
{
memset(pos, 0, sizeof(*pos));
pos->len = udf_rw32(nblk * context.sector_size);
pos->loc.lb_num = udf_rw32(context.data_alloc_pos);
pos->loc.part_num = udf_rw16(context.data_part);
udf_mark_allocated(context.data_alloc_pos, context.data_part, nblk);
context.data_alloc_pos += nblk;
if (context.metadata_part == context.data_part)
context.metadata_alloc_pos = context.data_alloc_pos;
}
/* --------------------------------------------------------------------- */
/*
* udf_derive_format derives the format_flags from the disc's mmc_discinfo.
* The resulting flags uniquely define a disc format. Note there are at least
* 7 distinct format types defined in UDF.
*/
#define UDF_VERSION(a) \
(((a) == 0x100) || ((a) == 0x102) || ((a) == 0x150) || ((a) == 0x200) || \
((a) == 0x201) || ((a) == 0x250) || ((a) == 0x260))
int
udf_derive_format(int req_enable, int req_disable, int force)
{
/* disc writability, formatted, appendable */
if ((mmc_discinfo.mmc_cur & MMC_CAP_RECORDABLE) == 0) {
(void)printf("Can't newfs readonly device\n");
return EROFS;
}
if (mmc_discinfo.mmc_cur & MMC_CAP_SEQUENTIAL) {
/* sequentials need sessions appended */
if (mmc_discinfo.disc_state == MMC_STATE_CLOSED) {
(void)printf("Can't append session to a closed disc\n");
return EROFS;
}
if ((mmc_discinfo.disc_state != MMC_STATE_EMPTY) && !force) {
(void)printf("Disc not empty! Use -F to force "
"initialisation\n");
return EROFS;
}
} else {
/* check if disc (being) formatted or has been started on */
if (mmc_discinfo.disc_state == MMC_STATE_EMPTY) {
(void)printf("Disc is not formatted\n");
return EROFS;
}
}
/* determine UDF format */
format_flags = 0;
if (mmc_discinfo.mmc_cur & MMC_CAP_REWRITABLE) {
/* all rewritable media */
format_flags |= FORMAT_REWRITABLE;
if (context.min_udf >= 0x0250) {
/* standard dictates meta as default */
format_flags |= FORMAT_META;
}
if ((mmc_discinfo.mmc_cur & MMC_CAP_HW_DEFECTFREE) == 0) {
/* sparables for defect management */
if (context.min_udf >= 0x150)
format_flags |= FORMAT_SPARABLE;
}
} else {
/* all once recordable media */
format_flags |= FORMAT_WRITEONCE;
if (mmc_discinfo.mmc_cur & MMC_CAP_SEQUENTIAL) {
format_flags |= FORMAT_SEQUENTIAL;
if (mmc_discinfo.mmc_cur & MMC_CAP_PSEUDOOVERWRITE) {
/* logical overwritable */
format_flags |= FORMAT_LOW;
} else {
/* have to use VAT for overwriting */
format_flags |= FORMAT_VAT;
}
} else {
/* rare WORM devices, but BluRay has one, strat4096 */
format_flags |= FORMAT_WORM;
}
}
/* enable/disable requests */
if (req_disable & FORMAT_META) {
format_flags &= ~(FORMAT_META | FORMAT_LOW);
req_disable &= ~FORMAT_META;
}
if ((format_flags & FORMAT_VAT) & UDF_512_TRACK)
format_flags |= FORMAT_TRACK512;
if (req_enable & FORMAT_READONLY) {
format_flags |= FORMAT_READONLY;
}
/* determine partition/media access type */
media_accesstype = UDF_ACCESSTYPE_NOT_SPECIFIED;
if (mmc_discinfo.mmc_cur & MMC_CAP_REWRITABLE) {
media_accesstype = UDF_ACCESSTYPE_OVERWRITABLE;
if (mmc_discinfo.mmc_cur & MMC_CAP_ERASABLE)
media_accesstype = UDF_ACCESSTYPE_REWRITEABLE;
} else {
/* all once recordable media */
media_accesstype = UDF_ACCESSTYPE_WRITE_ONCE;
}
if (mmc_discinfo.mmc_cur & MMC_CAP_PSEUDOOVERWRITE)
media_accesstype = UDF_ACCESSTYPE_PSEUDO_OVERWITE;
/* patch up media accesstype */
if (req_enable & FORMAT_READONLY) {
/* better now */
media_accesstype = UDF_ACCESSTYPE_READ_ONLY;
}
/* adjust minimum version limits */
if (format_flags & FORMAT_VAT)
context.min_udf = MAX(context.min_udf, 0x0150);
if (format_flags & FORMAT_SPARABLE)
context.min_udf = MAX(context.min_udf, 0x0150);
if (format_flags & FORMAT_META)
context.min_udf = MAX(context.min_udf, 0x0250);
if (format_flags & FORMAT_LOW)
context.min_udf = MAX(context.min_udf, 0x0260);
/* adjust maximum version limits not to tease or break things */
if (!(format_flags & (FORMAT_META | FORMAT_LOW)) &&
(context.max_udf > 0x200))
context.max_udf = 0x201;
if ((format_flags & (FORMAT_VAT | FORMAT_SPARABLE)) == 0)
if (context.max_udf <= 0x150)
context.min_udf = 0x102;
/* limit Ecma 167 descriptor if possible/needed */
context.dscrver = 3;
if ((context.min_udf < 0x200) || (context.max_udf < 0x200)) {
context.dscrver = 2;
context.max_udf = 0x150; /* last version < 0x200 */
}
/* is it possible ? */
if (context.min_udf > context.max_udf) {
(void)printf("Initialisation prohibited by specified maximum "
"UDF version 0x%04x. Minimum version required 0x%04x\n",
context.max_udf, context.min_udf);
return EPERM;
}
if (!UDF_VERSION(context.min_udf) || !UDF_VERSION(context.max_udf)) {
printf("Choose UDF version numbers from "
"0x102, 0x150, 0x200, 0x201, 0x250 and 0x260\n");
printf("Default version is 0x201\n");
return EPERM;
}
return 0;
}
#undef UDF_VERSION
/* --------------------------------------------------------------------- */
int
udf_proces_names(void)
{
uint32_t primary_nr;
uint64_t volset_nr;
if (context.logvol_name == NULL)
context.logvol_name = strdup("anonymous");
if (context.primary_name == NULL) {
if (mmc_discinfo.disc_flags & MMC_DFLAGS_DISCIDVALID) {
primary_nr = mmc_discinfo.disc_id;
} else {
primary_nr = (uint32_t) random();
}
context.primary_name = calloc(32, 1);
sprintf(context.primary_name, "%08"PRIx32, primary_nr);
}
if (context.volset_name == NULL) {
if (mmc_discinfo.disc_flags & MMC_DFLAGS_BARCODEVALID) {
volset_nr = mmc_discinfo.disc_barcode;
} else {
volset_nr = (uint32_t) random();
volset_nr |= ((uint64_t) random()) << 32;
}
context.volset_name = calloc(128,1);
sprintf(context.volset_name, "%016"PRIx64, volset_nr);
}
if (context.fileset_name == NULL)
context.fileset_name = strdup("anonymous");
/* check passed/created identifiers */
if (strlen(context.logvol_name) > 128) {
(void)printf("Logical volume name too long\n");
return EINVAL;
}
if (strlen(context.primary_name) > 32) {
(void)printf("Primary volume name too long\n");
return EINVAL;
}
if (strlen(context.volset_name) > 128) {
(void)printf("Volume set name too long\n");
return EINVAL;
}
if (strlen(context.fileset_name) > 32) {
(void)printf("Fileset name too long\n");
return EINVAL;
}
/* signal all OK */
return 0;
}
/* --------------------------------------------------------------------- */
static int
udf_write_iso9660_vrs(void)
{
struct vrs_desc *iso9660_vrs_desc;
uint32_t pos;
int error, cnt, dpos;
/* create ISO/Ecma-167 identification descriptors */
if ((iso9660_vrs_desc = calloc(1, context.sector_size)) == NULL)
return ENOMEM;
/*
* All UDF formats should have their ISO/Ecma-167 descriptors written
* except when not possible due to track reservation in the case of
* VAT
*/
if ((format_flags & FORMAT_TRACK512) == 0) {
dpos = (2048 + context.sector_size - 1) / context.sector_size;
/* wipe at least 6 times 2048 byte `sectors' */
for (cnt = 0; cnt < 6 *dpos; cnt++) {
pos = layout.iso9660_vrs + cnt;
if ((error = udf_write_sector(iso9660_vrs_desc, pos))) {
free(iso9660_vrs_desc);
return error;
}
}
/* common VRS fields in all written out ISO descriptors */
iso9660_vrs_desc->struct_type = 0;
iso9660_vrs_desc->version = 1;
pos = layout.iso9660_vrs;
/* BEA01, NSR[23], TEA01 */
memcpy(iso9660_vrs_desc->identifier, "BEA01", 5);
if ((error = udf_write_sector(iso9660_vrs_desc, pos))) {
free(iso9660_vrs_desc);
return error;
}
pos += dpos;
if (context.dscrver == 2)
memcpy(iso9660_vrs_desc->identifier, "NSR02", 5);
else
memcpy(iso9660_vrs_desc->identifier, "NSR03", 5);
;
if ((error = udf_write_sector(iso9660_vrs_desc, pos))) {
free(iso9660_vrs_desc);
return error;
}
pos += dpos;
memcpy(iso9660_vrs_desc->identifier, "TEA01", 5);
if ((error = udf_write_sector(iso9660_vrs_desc, pos))) {
free(iso9660_vrs_desc);
return error;
}
}
free(iso9660_vrs_desc);
/* return success */
return 0;
}
/* --------------------------------------------------------------------- */
/*
* Main function that creates and writes out disc contents based on the
* format_flags's that uniquely define the type of disc to create.
*/
int
udf_do_newfs_prefix(void)
{
union dscrptr *zero_dscr;
union dscrptr *dscr;
struct mmc_trackinfo ti;
uint32_t sparable_blocks;
uint32_t sector_size, blockingnr;
uint32_t cnt, loc, len;
int sectcopy;
int error, integrity_type;
int data_part, metadata_part;
/* init */
sector_size = mmc_discinfo.sector_size;
/* determine span/size */
ti.tracknr = mmc_discinfo.first_track_last_session;
error = udf_update_trackinfo(&mmc_discinfo, &ti);
if (error)
return error;
if (mmc_discinfo.sector_size < context.sector_size) {
fprintf(stderr, "Impossible to format: sectorsize too small\n");
return EIO;
}
context.sector_size = sector_size;
/* determine blockingnr */
blockingnr = ti.packet_size;
if (blockingnr <= 1) {
/* paranoia on blockingnr */
switch (mmc_discinfo.mmc_profile) {
case 0x08 : /* CDROM */
case 0x09 : /* CD-R */
case 0x0a : /* CD-RW */
blockingnr = 32; /* UDF requirement */
break;
case 0x10 : /* DVDROM */
case 0x11 : /* DVD-R (DL) */
case 0x12 : /* DVD-RAM */
case 0x1b : /* DVD+R */
case 0x2b : /* DVD+R Dual layer */
case 0x13 : /* DVD-RW restricted overwrite */
case 0x14 : /* DVD-RW sequential */
blockingnr = 16; /* SCSI definition */
break;
case 0x40 : /* BDROM */
case 0x41 : /* BD-R Sequential recording (SRM) */
case 0x42 : /* BD-R Random recording (RRM) */
case 0x43 : /* BD-RE */
case 0x51 : /* HD DVD-R */
case 0x52 : /* HD DVD-RW */
blockingnr = 32; /* SCSI definition */
break;
default:
break;
}
}
if (blockingnr <= 0) {
printf("Can't fixup blockingnumber for device "
"type %d\n", mmc_discinfo.mmc_profile);
printf("Device is not returning valid blocking"
" number and media type is unknown.\n");
return EINVAL;
}
wrtrack_skew = ti.track_start % blockingnr;
if (mmc_discinfo.mmc_class == MMC_CLASS_CD) {
/* not too much for CD-RW, still 20MiB */
sparable_blocks = 32;
} else {
/* take a value for DVD*RW mainly, BD is `defect free' */
sparable_blocks = 512;
}
/* get layout */
error = udf_calculate_disc_layout(format_flags, context.min_udf,
wrtrack_skew,
ti.track_start, mmc_discinfo.last_possible_lba,
context.sector_size, blockingnr, sparable_blocks,
meta_fract);
/* cache partition for we need it often */
data_part = context.data_part;
metadata_part = context.metadata_part;
/* Create sparing table descriptor if applicable */
if (format_flags & FORMAT_SPARABLE) {
if ((error = udf_create_sparing_tabled()))
return error;
if (check_surface) {
if ((error = udf_surface_check()))
return error;
}
}
/* Create a generic terminator descriptor (later reused) */
terminator_dscr = calloc(1, sector_size);
if (terminator_dscr == NULL)
return ENOMEM;
udf_create_terminator(terminator_dscr, 0);
/*
* Start with wipeout of VRS1 upto start of partition. This allows
* formatting for sequentials with the track reservation and it
* cleans old rubbish on rewritables. For sequentuals without the
* track reservation all is wiped from track start.
*/
if ((zero_dscr = calloc(1, context.sector_size)) == NULL)
return ENOMEM;
loc = (format_flags & FORMAT_TRACK512) ? layout.vds1 : ti.track_start;
for (; loc < layout.part_start_lba; loc++) {
if ((error = udf_write_sector(zero_dscr, loc))) {
free(zero_dscr);
return error;
}
}
free(zero_dscr);
/* Create anchors */
for (cnt = 0; cnt < 3; cnt++) {
if ((error = udf_create_anchor(cnt))) {
return error;
}
}
/*
* Create the two Volume Descriptor Sets (VDS) each containing the
* following descriptors : primary volume, partition space,
* unallocated space, logical volume, implementation use and the
* terminator
*/
/* start of volume recognision sequence building */
context.vds_seq = 0;
/* Create primary volume descriptor */
if ((error = udf_create_primaryd()))
return error;
/* Create partition descriptor */
if ((error = udf_create_partitiond(context.data_part, media_accesstype)))
return error;
/* Create unallocated space descriptor */
if ((error = udf_create_unalloc_spaced()))
return error;
/* Create logical volume descriptor */
if ((error = udf_create_logical_dscr(format_flags)))
return error;
/* Create implementation use descriptor */
/* TODO input of fields 1,2,3 and passing them */
if ((error = udf_create_impvold(NULL, NULL, NULL)))
return error;
/* write out what we've created so far */
/* writeout iso9660 vrs */
if ((error = udf_write_iso9660_vrs()))
return error;
/* Writeout anchors */
for (cnt = 0; cnt < 3; cnt++) {
dscr = (union dscrptr *) context.anchors[cnt];
loc = layout.anchors[cnt];
if ((error = udf_write_dscr_phys(dscr, loc, 1)))
return error;
/* sequential media has only one anchor */
if (format_flags & FORMAT_SEQUENTIAL)
break;
}
/* write out main and secondary VRS */
for (sectcopy = 1; sectcopy <= 2; sectcopy++) {
loc = (sectcopy == 1) ? layout.vds1 : layout.vds2;
/* primary volume descriptor */
dscr = (union dscrptr *) context.primary_vol;
error = udf_write_dscr_phys(dscr, loc, 1);
if (error)
return error;
loc++;
/* partition descriptor(s) */
for (cnt = 0; cnt < UDF_PARTITIONS; cnt++) {
dscr = (union dscrptr *) context.partitions[cnt];
if (dscr) {
error = udf_write_dscr_phys(dscr, loc, 1);
if (error)
return error;
loc++;
}
}
/* unallocated space descriptor */
dscr = (union dscrptr *) context.unallocated;
error = udf_write_dscr_phys(dscr, loc, 1);
if (error)
return error;
loc++;
/* logical volume descriptor */
dscr = (union dscrptr *) context.logical_vol;
error = udf_write_dscr_phys(dscr, loc, 1);
if (error)
return error;
loc++;
/* implementation use descriptor */
dscr = (union dscrptr *) context.implementation;
error = udf_write_dscr_phys(dscr, loc, 1);
if (error)
return error;
loc++;
/* terminator descriptor */
error = udf_write_dscr_phys(terminator_dscr, loc, 1);
if (error)
return error;
loc++;
}
/* writeout the two sparable table descriptors (if needed) */
if (format_flags & FORMAT_SPARABLE) {
for (sectcopy = 1; sectcopy <= 2; sectcopy++) {
loc = (sectcopy == 1) ? layout.spt_1 : layout.spt_2;
dscr = (union dscrptr *) context.sparing_table;
len = layout.sparing_table_dscr_lbas;
/* writeout */
error = udf_write_dscr_phys(dscr, loc, len);
if (error)
return error;
}
}
/*
* Create unallocated space bitmap descriptor. Sequential recorded
* media report their own free/used space; no free/used space tables
* should be recorded for these.
*/
if ((format_flags & (FORMAT_SEQUENTIAL | FORMAT_READONLY)) == 0) {
error = udf_create_space_bitmap(
layout.alloc_bitmap_dscr_size,
layout.part_size_lba,
&context.part_unalloc_bits[data_part]);
if (error)
return error;
/* TODO: freed space bitmap if applicable */
/* mark space allocated for the unallocated space bitmap */
udf_mark_allocated(layout.unalloc_space, data_part,
layout.alloc_bitmap_dscr_size);
}
/*
* Create metadata partition file entries and allocate and init their
* space and free space maps.
*/
if (format_flags & FORMAT_META) {
error = udf_create_space_bitmap(
layout.meta_bitmap_dscr_size,
layout.meta_part_size_lba,
&context.part_unalloc_bits[metadata_part]);
if (error)
return error;
error = udf_create_meta_files();
if (error)
return error;
/* mark space allocated for meta partition and its bitmap */
udf_mark_allocated(layout.meta_file, data_part, 1);
udf_mark_allocated(layout.meta_mirror, data_part, 1);
udf_mark_allocated(layout.meta_bitmap, data_part, 1);
udf_mark_allocated(layout.meta_part_start_lba, data_part,
layout.meta_part_size_lba);
/* mark space allocated for the unallocated space bitmap */
udf_mark_allocated(layout.meta_bitmap_space, data_part,
layout.meta_bitmap_dscr_size);
}
/* create logical volume integrity descriptor */
context.num_files = 0;
context.num_directories = 0;
integrity_type = UDF_INTEGRITY_OPEN;
if ((error = udf_create_lvintd(integrity_type)))
return error;
/* writeout initial open integrity sequence + terminator */
loc = layout.lvis;
dscr = (union dscrptr *) context.logvol_integrity;
error = udf_write_dscr_phys(dscr, loc, 1);
if (error)
return error;
loc++;
error = udf_write_dscr_phys(terminator_dscr, loc, 1);
if (error)
return error;
/* create VAT if needed */
if (format_flags & FORMAT_VAT) {
context.vat_allocated = context.sector_size;
context.vat_contents = malloc(context.vat_allocated);
assert(context.vat_contents);
udf_prepend_VAT_file();
}
/* create FSD and writeout */
if ((error = udf_create_fsd()))
return error;
udf_mark_allocated(layout.fsd, metadata_part, 1);
dscr = (union dscrptr *) context.fileset_desc;
error = udf_write_dscr_virt(dscr, layout.fsd, metadata_part, 1);
return error;
}
/* specific routine for newfs to create empty rootdirectory */
int
udf_do_rootdir(void) {
union dscrptr *root_dscr;
int error;
/* create root directory and write out */
assert(context.unique_id == 0x10);
context.unique_id = 0;
if ((error = udf_create_new_rootdir(&root_dscr)))
return error;
udf_mark_allocated(layout.rootdir, context.metadata_part, 1);
error = udf_write_dscr_virt(root_dscr,
layout.rootdir, context.metadata_part, 1);
free(root_dscr);
return error;
}
int
udf_do_newfs_postfix(void)
{
union dscrptr *vat_dscr;
union dscrptr *dscr;
struct long_ad vatdata_pos;
uint32_t loc, len, phys, sects;
int data_part, metadata_part;
int error;
/* cache partition for we need it often */
data_part = context.data_part;
metadata_part = context.metadata_part;
if ((format_flags & FORMAT_SEQUENTIAL) == 0) {
/* update lvint and mark it closed */
udf_update_lvintd(UDF_INTEGRITY_CLOSED);
/* overwrite initial terminator */
loc = layout.lvis+1;
dscr = (union dscrptr *) context.logvol_integrity;
error = udf_write_dscr_phys(dscr, loc, 1);
if (error)
return error;
loc++;
/* mark end of integrity desciptor sequence again */
error = udf_write_dscr_phys(terminator_dscr, loc, 1);
if (error)
return error;
}
/* write out unallocated space bitmap on non sequential media */
if ((format_flags & (FORMAT_SEQUENTIAL | FORMAT_READONLY)) == 0) {
/* writeout unallocated space bitmap */
loc = layout.unalloc_space;
dscr = (union dscrptr *) (context.part_unalloc_bits[data_part]);
len = layout.alloc_bitmap_dscr_size;
error = udf_write_dscr_virt(dscr, loc, data_part, len);
if (error)
return error;
}
if (format_flags & FORMAT_META) {
loc = layout.meta_file;
dscr = (union dscrptr *) context.meta_file;
error = udf_write_dscr_virt(dscr, loc, data_part, 1);
if (error)
return error;
loc = layout.meta_mirror;
dscr = (union dscrptr *) context.meta_mirror;
error = udf_write_dscr_virt(dscr, loc, data_part, 1);
if (error)
return error;
loc = layout.meta_bitmap;
dscr = (union dscrptr *) context.meta_bitmap;
error = udf_write_dscr_virt(dscr, loc, data_part, 1);
if (error)
return error;
/* writeout unallocated space bitmap */
loc = layout.meta_bitmap_space;
dscr = (union dscrptr *)
(context.part_unalloc_bits[metadata_part]);
len = layout.meta_bitmap_dscr_size;
error = udf_write_dscr_virt(dscr, loc, data_part, len);
if (error)
return error;
}
/* create a VAT and account for FSD+root */
vat_dscr = NULL;
if (format_flags & FORMAT_VAT) {
/* update lvint to reflect the newest values (no writeout) */
udf_update_lvintd(UDF_INTEGRITY_CLOSED);
error = udf_append_VAT_file();
if (error)
return error;
/* write out VAT data */
sects = UDF_ROUNDUP(context.vat_size, context.sector_size) /
context.sector_size;
layout.vat = context.data_alloc_pos;
udf_data_alloc(sects, &vatdata_pos);
loc = udf_rw32(vatdata_pos.loc.lb_num);
phys = context.vtop_offset[context.data_part] + loc;
error = udf_write_phys(context.vat_contents, phys, sects);
if (error)
return error;
loc += sects;
/* create new VAT descriptor */
error = udf_create_VAT(&vat_dscr);
if (error)
return error;
context.data_alloc_pos++;
loc++;
error = udf_write_dscr_virt(vat_dscr, loc, metadata_part, 1);
free(vat_dscr);
if (error)
return error;
}
/* done */
return 0;
}

View file

@ -0,0 +1,54 @@
/* $NetBSD: udf_write.h,v 1.4 2013/08/05 20:52:08 reinoud Exp $ */
/*
* Copyright (c) 2006, 2008, 2013 Reinoud Zandijk
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef _FS_UDF_UDF_WRITE_H_
#define _FS_UDF_UDF_WRITE_H_
#include "udf_create.h"
#if !HAVE_NBTOOL_CONFIG_H
#define _EXPOSE_MMC
#include <sys/cdio.h>
#else
#include "udf/cdio_mmc_structs.h"
#endif
/* prototypes */
int udf_write_dscr_virt(union dscrptr *dscr, uint32_t location, uint32_t vpart,
uint32_t sects);
void udf_metadata_alloc(int nblk, struct long_ad *pos);
void udf_data_alloc(int nblk, struct long_ad *pos);
int udf_derive_format(int req_enable, int req_disable, int force);
int udf_proces_names(void);
int udf_do_newfs_prefix(void);
int udf_do_rootdir(void);
int udf_do_newfs_postfix(void);
#endif /* _FS_UDF_UDF_WRITE_H_ */

161
sbin/newfs_udf/unicode.h Normal file
View file

@ -0,0 +1,161 @@
/* $NetBSD: unicode.h,v 1.1 2013/08/05 14:11:30 reinoud Exp $ */
/*-
* Copyright (c) 2001, 2004 The NetBSD Foundation, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*-
* Copyright (c) 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Paul Borman at Krystal Technologies.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Routines for handling Unicode encoded in UTF-8 form, code derived from
* src/lib/libc/locale/utf2.c.
*/
static u_int16_t wget_utf8(const char **, size_t *) __unused;
static int wput_utf8(char *, size_t, u_int16_t) __unused;
/*
* Read one UTF8-encoded character off the string, shift the string pointer
* and return the character.
*/
static u_int16_t
wget_utf8(const char **str, size_t *sz)
{
unsigned int c;
u_int16_t rune = 0;
const char *s = *str;
static const int _utf_count[16] = {
1, 1, 1, 1, 1, 1, 1, 1,
0, 0, 0, 0, 2, 2, 3, 0,
};
/* must be called with at least one byte remaining */
assert(*sz > 0);
c = _utf_count[(s[0] & 0xf0) >> 4];
if (c == 0 || c > *sz) {
decoding_error:
/*
* The first character is in range 128-255 and doesn't
* mark valid a valid UTF-8 sequence. There is not much
* we can do with this, so handle by returning
* the first character as if it would be a correctly
* encoded ISO-8859-1 character.
*/
c = 1;
}
switch (c) {
case 1:
rune = s[0] & 0xff;
break;
case 2:
if ((s[1] & 0xc0) != 0x80)
goto decoding_error;
rune = ((s[0] & 0x1F) << 6) | (s[1] & 0x3F);
break;
case 3:
if ((s[1] & 0xC0) != 0x80 || (s[2] & 0xC0) != 0x80)
goto decoding_error;
rune = ((s[0] & 0x0F) << 12) | ((s[1] & 0x3F) << 6)
| (s[2] & 0x3F);
break;
}
*str += c;
*sz -= c;
return rune;
}
/*
* Encode wide character and write it to the string. 'n' specifies
* how much buffer space remains in 's'. Returns number of bytes written
* to the target string 's'.
*/
static int
wput_utf8(char *s, size_t n, u_int16_t wc)
{
if (wc & 0xf800) {
if (n < 3) {
/* bound check failure */
return 0;
}
s[0] = 0xE0 | (wc >> 12);
s[1] = 0x80 | ((wc >> 6) & 0x3F);
s[2] = 0x80 | ((wc) & 0x3F);
return 3;
} else if (wc & 0x0780) {
if (n < 2) {
/* bound check failure */
return 0;
}
s[0] = 0xC0 | (wc >> 6);
s[1] = 0x80 | ((wc) & 0x3F);
return 2;
} else {
if (n < 1) {
/* bound check failure */
return 0;
}
s[0] = wc;
return 1;
}
}

21
sbin/newfs_v7fs/Makefile Normal file
View file

@ -0,0 +1,21 @@
# $NetBSD: Makefile,v 1.4 2012/09/05 23:01:42 riz Exp $
.include <bsd.own.mk>
V7FS = ${NETBSDSRCDIR}/sys/fs/v7fs
PROG= newfs_v7fs
MAN= newfs_v7fs.8
SRCS= newfs_v7fs.c main.c v7fs_endian.c v7fs_superblock.c v7fs_inode.c \
v7fs_datablock.c v7fs_dirent.c v7fs_io.c v7fs_io_user.c progress.c
# use progress meter.
FSCK= ${NETBSDSRCDIR}/sbin/fsck
DPADD+= ${LIBUTIL}
LDADD+= -lutil
CPPFLAGS+=-DV7FS_EI -I${V7FS} -I${FSCK}
.PATH: ${V7FS} ${FSCK}
COPTS.newfs_v7fs.c+= -Wno-pointer-sign
.include <bsd.prog.mk>

316
sbin/newfs_v7fs/main.c Normal file
View file

@ -0,0 +1,316 @@
/* $NetBSD: main.c,v 1.10 2011/08/10 11:31:49 uch Exp $ */
/*-
* Copyright (c) 2011 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by UCHIYAMA Yasushi.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#if HAVE_NBTOOL_CONFIG_H
#include "nbtool_config.h"
#endif
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: main.c,v 1.10 2011/08/10 11:31:49 uch Exp $");
#endif /* not lint */
#include <sys/param.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#include <err.h>
#include "v7fs.h"
#include "v7fs_impl.h"
#include "v7fs_endian.h"
#include "v7fs_superblock.h"
#include "v7fs_inode.h"
#include "v7fs_datablock.h" /*v7fs_datablock_expand/last */
#include "newfs_v7fs.h"
#include "progress.h" /*../sbin/fsck */
#define VPRINTF(lv, fmt, args...) { if (v7fs_newfs_verbose >= lv) \
printf(fmt, ##args); }
static v7fs_daddr_t
determine_ilist_size(v7fs_daddr_t volume_size, int32_t files)
{
v7fs_daddr_t ilist_size;
if (files)
ilist_size = howmany(files, V7FS_INODE_PER_BLOCK);
else
ilist_size = volume_size / 25; /* 4% */
if (ilist_size > (v7fs_daddr_t)V7FS_ILISTBLK_MAX)
ilist_size = V7FS_ILISTBLK_MAX;
return ilist_size;
}
static int
partition_check(struct v7fs_self *fs)
{
struct v7fs_superblock *sb = &fs->superblock;
int error;
if ((error = v7fs_superblock_load(fs))) {
if (error != EINVAL) {
/* Invalid superblock information is OK. */
warnx("Can't read superblock sector.");
}
}
sb->modified = 1;
if ((error = v7fs_superblock_writeback(fs))) {
if (errno == EROFS) {
warnx("Overwriting disk label? ");
}
warnx("Can't write superblock sector.");
}
return error;
}
static int
make_root(struct v7fs_self *fs)
{
struct v7fs_inode inode;
struct v7fs_dirent *dir;
int error;
/* INO 1 badblk (don't used) */
memset(&inode, 0, sizeof(inode));
inode.inode_number = 1;
inode.mode = V7FS_IFREG; /* V7 manner */
v7fs_inode_writeback(fs, &inode);
/* INO 2 root */
v7fs_ino_t ino;
if ((error = v7fs_inode_allocate(fs, &ino))) {
errno = error;
warn("Can't allocate / inode");
return error;
}
memset(&inode, 0, sizeof(inode));
inode.inode_number = ino;
inode.mode = 0777 | V7FS_IFDIR;
inode.uid = 0;
inode.gid = 0;
inode.nlink = 2; /* . + .. */
inode.atime = inode.mtime = inode.ctime = time(0);
/* root dirent. */
v7fs_datablock_expand(fs, &inode, sizeof(*dir) * 2);
v7fs_daddr_t blk = inode.addr[0];
void *buf;
if (!(buf = scratch_read(fs, blk))) {
v7fs_inode_deallocate(fs, ino);
errno = error = EIO;
warn("Can't read / dirent.");
return error;
}
dir = (struct v7fs_dirent *)buf; /*disk endian */
strcpy(dir[0].name, ".");
dir[0].inode_number = V7FS_VAL16(fs, ino);
strcpy(dir[1].name, "..");
dir[1].inode_number = V7FS_VAL16(fs, ino);
if (!fs->io.write(fs->io.cookie, buf, blk)) {/*writeback */
scratch_free(fs, buf);
errno = error = EIO;
warn("Can't write / dirent.");
return error;
}
scratch_free(fs, buf);
v7fs_inode_writeback(fs, &inode);
if ((error = v7fs_superblock_writeback(fs))) {
errno = error;
warnx("Can't write superblock.");
}
return error;
}
static v7fs_daddr_t
make_freeblocklist(struct v7fs_self *fs, v7fs_daddr_t listblk, uint8_t *buf)
{
uint32_t (*val32)(uint32_t) = fs->val.conv32;
uint16_t (*val16)(uint16_t) = fs->val.conv16;
struct v7fs_freeblock *fb = (struct v7fs_freeblock *)buf;
int i, j, k;
memset(buf, 0, V7FS_BSIZE);
for (i = V7FS_MAX_FREEBLOCK - 1, j = listblk + 1, k = 0; i >= 0;
i--, j++, k++) {
progress(0);
if (j == (int32_t)fs->superblock.volume_size)
{
VPRINTF(4, "\nlast freeblock #%d\n",
(*val32)(fb->freeblock[i + 1]));
memmove(fb->freeblock + 1, fb->freeblock + i + 1, k *
sizeof(v7fs_daddr_t));
fb->freeblock[0] = 0; /* Terminate link; */
fb->nfreeblock = (*val16)(k + 1);
VPRINTF(4, "last freeblock contains #%d\n",
(*val16)(fb->nfreeblock));
fs->io.write(fs->io.cookie, buf, listblk);
return 0;
}
fb->freeblock[i] = (*val32)(j);
}
fb->nfreeblock = (*val16)(k);
if (!fs->io.write(fs->io.cookie, buf, listblk)) {
errno = EIO;
warn("blk=%ld", (long)listblk);
return 0;
}
/* Return next link block */
return (*val32)(fb->freeblock[0]);
}
static int
make_filesystem(struct v7fs_self *fs, v7fs_daddr_t volume_size,
v7fs_daddr_t ilist_size)
{
struct v7fs_superblock *sb;
v7fs_daddr_t blk;
uint8_t buf[V7FS_BSIZE];
int error = 0;
int32_t i, j;
/* Setup ilist. (ilist must be zero filled. becuase of they are free) */
VPRINTF(4, "Zero clear ilist.\n");
progress(&(struct progress_arg){ .label = "zero ilist", .tick =
ilist_size / PROGRESS_BAR_GRANULE });
memset(buf, 0, sizeof buf);
for (i = V7FS_ILIST_SECTOR; i < (int32_t)ilist_size; i++) {
fs->io.write(fs->io.cookie, buf, i);
progress(0);
}
#ifndef HAVE_NBTOOL_CONFIG_H
progress_done();
#endif
VPRINTF(4, "\n");
/* Construct superblock */
sb = &fs->superblock;
sb->volume_size = volume_size;
sb->datablock_start_sector = ilist_size + V7FS_ILIST_SECTOR;
sb->update_time = time(NULL);
/* fill free inode cache. */
VPRINTF(4, "Setup inode cache.\n");
sb->nfreeinode = V7FS_MAX_FREEINODE;
for (i = V7FS_MAX_FREEINODE - 1, j = V7FS_ROOT_INODE; i >= 0; i--, j++)
sb->freeinode[i] = j;
sb->total_freeinode = ilist_size * V7FS_INODE_PER_BLOCK - 1;
/* fill free block cache. */
VPRINTF(4, "Setup free block cache.\n");
sb->nfreeblock = V7FS_MAX_FREEBLOCK;
for (i = V7FS_MAX_FREEBLOCK - 1, j = sb->datablock_start_sector; i >= 0;
i--, j++)
sb->freeblock[i] = j;
sb->total_freeblock = volume_size - sb->datablock_start_sector;
/* Write superblock. */
sb->modified = 1;
if ((error = v7fs_superblock_writeback(fs))) {
errno = error;
warn("Can't write back superblock.");
return error;
}
/* Construct freeblock list */
VPRINTF(4, "Setup whole freeblock list.\n");
progress(&(struct progress_arg){ .label = "freeblock list", .tick =
(volume_size - sb->datablock_start_sector) / PROGRESS_BAR_GRANULE});
blk = sb->freeblock[0];
while ((blk = make_freeblocklist(fs, blk, buf)))
continue;
#ifndef HAVE_NBTOOL_CONFIG_H
progress_done();
#endif
VPRINTF(4, "done.\n");
return 0;
}
int
v7fs_newfs(const struct v7fs_mount_device *mount, int32_t maxfile)
{
struct v7fs_self *fs;
v7fs_daddr_t ilist_size;
int error;
v7fs_daddr_t volume_size = mount->sectors;
/* Check and determine ilistblock, datablock size. */
if (volume_size > V7FS_DADDR_MAX + 1) {
warnx("volume size %d over v7fs limit %d. truncated.",
volume_size, V7FS_DADDR_MAX + 1);
volume_size = V7FS_DADDR_MAX + 1;
}
ilist_size = determine_ilist_size(volume_size, maxfile);
VPRINTF(1, "volume size=%d, ilist size=%d, endian=%d, NAME_MAX=%d\n",
volume_size, ilist_size, mount->endian, V7FS_NAME_MAX);
/* Setup I/O ops. */
if ((error = v7fs_io_init(&fs, mount, V7FS_BSIZE))) {
errno = error;
warn("I/O setup failed.");
return error;
}
fs->endian = mount->endian;
v7fs_endian_init(fs);
if ((error = partition_check(fs))) {
return error;
}
/* Construct filesystem. */
if ((error = make_filesystem(fs, volume_size, ilist_size))) {
return error;
}
/* Setup root. */
if ((error = make_root(fs))) {
return error;
}
v7fs_io_fini(fs);
return 0;
}

View file

@ -0,0 +1,130 @@
.\" $NetBSD: newfs_v7fs.8,v 1.3 2011/08/10 11:31:49 uch Exp $
.\"
.\" Copyright (c) 2011 The NetBSD Foundation, Inc.
.\" All rights reserved.
.\"
.\" This code is derived from software contributed to The NetBSD Foundation
.\" by UCHIYAMA Yasushi.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
.\" Copyright (c) 1993
.\" The Regents of the University of California. All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\" 3. Neither the name of the University nor the names of its contributors
.\" may be used to endorse or promote products derived from this software
.\" without specific prior written permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\" @(#)newlfs.8 8.1 (Berkeley) 6/19/93
.\"
.Dd April 29, 2011
.Dt NEWFS_V7FS 8
.Os
.Sh NAME
.Nm newfs_v7fs
.Nd construct a new 7th Edition(V7) File System
.Sh SYNOPSIS
.Nm
.Op Fl FZ
.Op Fl B Ar byte-order
.Op Fl n Ar inodes
.Op Fl s Ar sectors
.Op Fl V Ar verbose
.Ar special
.Sh DESCRIPTION
.Nm
builds a 7th Edition(V7) file system on the specified
.Ar special .
If it is a device, the size information will be taken from the disk label and
before running
.Nm
the disk must be labeled using
.Xr disklabel 8 ;
the proper fstype is
.Dq Version 7 .
Otherwise, the size must be specified on the command line.
V7 filesystem's block size and sector size are 512 byte.
Disk address limits are 24 bit.
.Pp
The following arguments are supported:
.Bl -tag -width XBXbyteXorderXX
.It Fl B Ar byte-order
Specify the metadata byte order of the file system to be created.
Valid byte orders are
.Sq be ,
.Sq le ,
and
.Sq pdp .
If no byte order is specified, the file system is created in host
byte order.
.It Fl F
Create file system to a regular file (needs the
.Fl s
option).
.It Fl n Ar inodes
This specifies the number of inodes for the filesystem.
If the number of inodes exceeds 65536, it is reduced to 65536.
.It Fl s Ar sectors
Create file system with specified number of disk sectors.
.It Fl V Ar verbose
This controls the amount of information written to stdout:
.Bl -tag -width 3n -offset indent -compact
.It 0
No output.
.It 1
Overall size, ilist size, endian and filename length.
.It 2
A progress bar.
.It 3
.It 4
More verbose message.
.El
The default is 3.
.It Fl Z
Fill file with zeroes instead of creating a sparse file.
.El
.Sh SEE ALSO
.Xr disklabel 5 ,
.Xr disktab 5 ,
.\" .Xr fs 5 ,
.Xr disklabel 8 ,
.Xr diskpart 8

View file

@ -0,0 +1,240 @@
/* $NetBSD: newfs_v7fs.c,v 1.3 2011/08/10 12:13:20 wiz Exp $ */
/*-
* Copyright (c) 2004, 2011 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by UCHIYAMA Yasushi.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: newfs_v7fs.c,v 1.3 2011/08/10 12:13:20 wiz Exp $");
#endif /* not lint */
#include <sys/types.h>
#include <sys/param.h>
#include <err.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/disklabel.h>
#include <fs/v7fs/v7fs.h>
#include "v7fs_impl.h"
#include "progress.h"
#include "newfs_v7fs.h"
static void usage(void) __dead;
static bool progress_bar_enable = false;
int v7fs_newfs_verbose = 3; /* newfs compatible */
int
main(int argc, char **argv)
{
const char *device;
struct disklabel d;
struct partition *p;
struct stat st;
uint32_t partsize;
int Fflag, Zflag;
int part;
int fd, ch;
int endian = _BYTE_ORDER;
int32_t maxfile = 0;
if (argc < 2)
usage();
Fflag = Zflag = partsize = 0;
while ((ch = getopt(argc, argv, "Fs:Zs:n:B:V:")) != -1) {
switch (ch) {
case 'V':
v7fs_newfs_verbose = atoi(optarg);
break;
case 'F':
Fflag = 1;
break;
case 's':
partsize = atoi(optarg);
break;
case 'n':
maxfile = atoi(optarg);
break;
case 'Z':
Zflag = 1;
break;
case 'B':
switch (optarg[0]) {
case 'l':
endian = _LITTLE_ENDIAN;
break;
case 'b':
endian = _BIG_ENDIAN;
break;
case 'p':
endian = _PDP_ENDIAN;
break;
}
break;
default:
usage();
/*NOTREACHED*/
}
}
argc -= optind;
argv += optind;
if (argc != 1)
usage();
device = argv[0];
progress_bar_enable = v7fs_newfs_verbose > 1;
if (progress_bar_enable) {
progress_switch(progress_bar_enable);
progress_init();
progress(&(struct progress_arg){ .cdev = device });
}
if (!Fflag) {
if ((fd = open(device, O_RDWR)) == -1) {
err(EXIT_FAILURE, "%s", device);
}
if (fstat(fd, &st) != 0) {
goto err_exit;
}
if (!S_ISCHR(st.st_mode)) {
warnx("not a raw device.\n");
}
part = DISKPART(st.st_rdev);
if (ioctl(fd, DIOCGDINFO, &d) == -1) {
goto err_exit;
}
p = &d.d_partitions[part];
if (v7fs_newfs_verbose) {
printf("partition=%d size=%d offset=%d fstype=%d"
" secsize=%d\n", part, p->p_size, p->p_offset,
p->p_fstype, d.d_secsize);
}
if (p->p_fstype != FS_V7) {
warnx("not a Version 7 partition.");
goto err_exit;
}
partsize = p->p_size;
} else {
off_t filesize;
uint8_t zbuf[8192] = {0, };
if (partsize == 0) {
errx(EXIT_FAILURE, "-F requires -s");
}
filesize = partsize << V7FS_BSHIFT;
fd = open(device, O_RDWR|O_CREAT|O_TRUNC, 0666);
if (fd == -1) {
err(EXIT_FAILURE, "%s", device);
}
if (Zflag) {
while (filesize > 0) {
size_t writenow = MIN(filesize,
(off_t)sizeof(zbuf));
if ((size_t)write(fd, zbuf, writenow) !=
writenow) {
err(EXIT_FAILURE, NULL);
}
filesize -= writenow;
}
} else {
if (lseek(fd, filesize - 1, SEEK_SET) == -1) {
goto err_exit;
}
if (write(fd, zbuf, 1) != 1) {
goto err_exit;
}
if (lseek(fd, 0, SEEK_SET) == -1) {
goto err_exit;
}
}
}
if (v7fs_newfs(&(struct v7fs_mount_device)
{ .device.fd = fd, .endian = endian, .sectors = partsize },
maxfile) != 0)
goto err_exit;
close(fd);
return EXIT_SUCCESS;
err_exit:
close(fd);
err(EXIT_FAILURE, NULL);
}
void
progress(const struct progress_arg *p)
{
static struct progress_arg Progress;
static char cdev[32];
static char label[32];
if (!progress_bar_enable)
return;
if (p) {
Progress = *p;
if (p->cdev)
strcpy(cdev, p->cdev);
if (p->label)
strcpy(label, p->label);
}
if (!Progress.tick)
return;
if (++Progress.cnt > Progress.tick) {
Progress.cnt = 0;
Progress.total++;
progress_bar(cdev, label, Progress.total, PROGRESS_BAR_GRANULE);
}
}
static void
usage(void)
{
(void)fprintf(stderr, "usage: \n%s [-FZ] [-B byte-order]"
" [-n inodes] [-s sectors] [-V verbose] special\n", getprogname());
exit(EXIT_FAILURE);
}

View file

@ -0,0 +1,48 @@
/* $NetBSD: newfs_v7fs.h,v 1.2 2011/08/10 11:31:49 uch Exp $ */
/*-
* Copyright (c) 2011 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by UCHIYAMA Yasushi.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _SBIN_NEWFS_V7FS_NEWFS_V7FS_H_
#define _SBIN_NEWFS_V7FS_NEWFS_V7FS_H_
#define PROGRESS_BAR_GRANULE 100
struct progress_arg {
const char *cdev;
const char *label;
off_t tick;
off_t cnt;
off_t total;
};
__BEGIN_DECLS
void progress(const struct progress_arg *);
int v7fs_newfs(const struct v7fs_mount_device *, int32_t);
extern int v7fs_newfs_verbose;
__END_DECLS
#endif /* !_SBIN_NEWFS_V7FS_NEWFS_V7FS_H_ */

View file

@ -1,6 +1,6 @@
# $NetBSD: Makefile,v 1.20 2011/06/27 11:52:24 uch Exp $ # $NetBSD: Makefile,v 1.20 2011/06/27 11:52:24 uch Exp $
SUBDIR= cd9660 msdosfs \ SUBDIR= cd9660 msdosfs \
puffs puffs udf v7fs
.include <bsd.kinc.mk> .include <bsd.kinc.mk>

7
sys/fs/udf/Makefile Normal file
View file

@ -0,0 +1,7 @@
# $NetBSD: Makefile,v 1.1 2006/02/02 15:19:15 reinoud Exp $
INCSDIR= /usr/include/fs/udf
INCS= ecma167-udf.h udf_mount.h
.include <bsd.kinc.mk>

835
sys/fs/udf/ecma167-udf.h Normal file
View file

@ -0,0 +1,835 @@
/* $NetBSD: ecma167-udf.h,v 1.14 2011/07/07 17:45:38 reinoud Exp $ */
/*-
* Copyright (c) 2003, 2004, 2005, 2006, 2008, 2009
* Reinoud Zandijk * <reinoud@NetBSD.org>
* Copyright (c) 2001, 2002 Scott Long <scottl@freebsd.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*
* Extended and adapted for UDFv2.50+ bij Reinoud Zandijk based on the
* original by Scott Long.
*
* 20030508 Made some small typo and explanatory comments
* 20030510 Added UDF 2.01 structures
* 20030519 Added/correct comments on multi-partitioned logical volume space
* 20050616 Added pseudo overwrite
* 20050624 Added the missing extended attribute types and `magic values'.
* 20051106 Reworked some implementation use parts
*
*/
#ifndef _FS_UDF_ECMA167_UDF_H_
#define _FS_UDF_ECMA167_UDF_H_
/*
* in case of an older gcc versions, define the __packed as explicit
* attribute
*/
/*
* You may specify the `aligned' and `transparent_union' attributes either in
* a `typedef' declaration or just past the closing curly brace of a complete
* enum, struct or union type _definition_ and the `packed' attribute only
* past the closing brace of a definition. You may also specify attributes
* between the enum, struct or union tag and the name of the type rather than
* after the closing brace.
*/
#ifndef __packed
#define __packed __attribute__((packed))
#endif
/* ecma167-udf.h */
/* Volume recognition sequence ECMA 167 rev. 3 16.1 */
struct vrs_desc {
uint8_t struct_type;
uint8_t identifier[5];
uint8_t version;
uint8_t data[2041];
} __packed;
#define VRS_NSR02 "NSR02"
#define VRS_NSR03 "NSR03"
#define VRS_BEA01 "BEA01"
#define VRS_TEA01 "TEA01"
#define VRS_CD001 "CD001"
#define VRS_CDW02 "CDW02"
/* Structure/definitions/constants a la ECMA 167 rev. 3 */
#define MAX_TAGID_VOLUMES 9
/* Tag identifiers */
enum {
TAGID_SPARING_TABLE = 0,
TAGID_PRI_VOL = 1,
TAGID_ANCHOR = 2,
TAGID_VOL = 3,
TAGID_IMP_VOL = 4,
TAGID_PARTITION = 5,
TAGID_LOGVOL = 6,
TAGID_UNALLOC_SPACE = 7,
TAGID_TERM = 8,
TAGID_LOGVOL_INTEGRITY= 9,
TAGID_FSD = 256,
TAGID_FID = 257,
TAGID_ALLOCEXTENT = 258,
TAGID_INDIRECTENTRY = 259,
TAGID_ICB_TERM = 260,
TAGID_FENTRY = 261,
TAGID_EXTATTR_HDR = 262,
TAGID_UNALL_SP_ENTRY = 263,
TAGID_SPACE_BITMAP = 264,
TAGID_PART_INTEGRITY = 265,
TAGID_EXTFENTRY = 266,
TAGID_MAX = 266
};
enum {
UDF_DOMAIN_FLAG_HARD_WRITE_PROTECT = 1,
UDF_DOMAIN_FLAG_SOFT_WRITE_PROTECT = 2
};
enum {
UDF_ACCESSTYPE_NOT_SPECIFIED = 0, /* unknown */
UDF_ACCESSTYPE_PSEUDO_OVERWITE = 0, /* pseudo overwritable, e.g. BD-R's LOW */
UDF_ACCESSTYPE_READ_ONLY = 1, /* really only readable */
UDF_ACCESSTYPE_WRITE_ONCE = 2, /* write once and you're done */
UDF_ACCESSTYPE_REWRITEABLE = 3, /* may need extra work to rewrite */
UDF_ACCESSTYPE_OVERWRITABLE = 4 /* no limits on rewriting; e.g. harddisc*/
};
/* Descriptor tag [3/7.2] */
struct desc_tag {
uint16_t id;
uint16_t descriptor_ver;
uint8_t cksum;
uint8_t reserved;
uint16_t serial_num;
uint16_t desc_crc;
uint16_t desc_crc_len;
uint32_t tag_loc;
} __packed;
#define UDF_DESC_TAG_LENGTH 16
/* Recorded Address [4/7.1] */
struct lb_addr { /* within partition space */
uint32_t lb_num;
uint16_t part_num;
} __packed;
/* Extent Descriptor [3/7.1] */
struct extent_ad {
uint32_t len;
uint32_t loc;
} __packed;
/* Short Allocation Descriptor [4/14.14.1] */
struct short_ad {
uint32_t len;
uint32_t lb_num;
} __packed;
/* Long Allocation Descriptor [4/14.14.2] */
struct UDF_ADImp_use {
uint16_t flags;
uint32_t unique_id;
} __packed;
#define UDF_ADIMP_FLAGS_EXTENT_ERASED 1
struct long_ad {
uint32_t len;
struct lb_addr loc; /* within a logical volume mapped partition space !! */
union {
uint8_t bytes[6];
struct UDF_ADImp_use im_used;
} impl;
} __packed;
#define longad_uniqueid impl.im_used.unique_id
/* Extended Allocation Descriptor [4/14.14.3] ; identifies an extent of allocation descriptors ; also in UDF ? */
struct ext_ad {
uint32_t ex_len;
uint32_t rec_len;
uint32_t inf_len;
struct lb_addr ex_loc;
uint8_t reserved[2];
} __packed;
/* ICB : Information Control Block; positioning */
union icb {
struct short_ad s_ad;
struct long_ad l_ad;
struct ext_ad e_ad;
};
/* short/long/ext extent have flags encoded in length */
#define UDF_EXT_ALLOCATED (0<<30)
#define UDF_EXT_FREED (1<<30)
#define UDF_EXT_ALLOCATED_BUT_NOT_USED (1<<30)
#define UDF_EXT_FREE (2<<30)
#define UDF_EXT_REDIRECT (3<<30)
#define UDF_EXT_FLAGS(len) ((len) & (3<<30))
#define UDF_EXT_LEN(len) ((len) & ((1<<30)-1))
#define UDF_EXT_MAXLEN ((1<<30)-1)
/* Character set spec [1/7.2.1] */
struct charspec {
uint8_t type;
uint8_t inf[63];
} __packed;
struct pathcomp {
uint8_t type;
uint8_t l_ci;
uint16_t comp_filever;
uint8_t ident[256];
} __packed;
#define UDF_PATH_COMP_SIZE 4
#define UDF_PATH_COMP_RESERVED 0
#define UDF_PATH_COMP_ROOT 1
#define UDF_PATH_COMP_MOUNTROOT 2
#define UDF_PATH_COMP_PARENTDIR 3
#define UDF_PATH_COMP_CURDIR 4
#define UDF_PATH_COMP_NAME 5
/* Timestamp [1/7.3] */
struct timestamp {
uint16_t type_tz;
uint16_t year;
uint8_t month;
uint8_t day;
uint8_t hour;
uint8_t minute;
uint8_t second;
uint8_t centisec;
uint8_t hund_usec;
uint8_t usec;
} __packed;
#define UDF_TIMESTAMP_SIZE 12
/* Entity Identifier [1/7.4] */
#define UDF_REGID_ID_SIZE 23
struct regid {
uint8_t flags;
uint8_t id[UDF_REGID_ID_SIZE];
uint8_t id_suffix[8];
} __packed;
/* ICB Tag [4/14.6] */
struct icb_tag {
uint32_t prev_num_dirs;
uint16_t strat_type;
uint8_t strat_param[2];
uint16_t max_num_entries;
uint8_t reserved;
uint8_t file_type;
struct lb_addr parent_icb;
uint16_t flags;
} __packed;
#define UDF_ICB_TAG_FLAGS_ALLOC_MASK 0x03
#define UDF_ICB_SHORT_ALLOC 0x00
#define UDF_ICB_LONG_ALLOC 0x01
#define UDF_ICB_EXT_ALLOC 0x02
#define UDF_ICB_INTERN_ALLOC 0x03
#define UDF_ICB_TAG_FLAGS_DIRORDERED (1<< 3)
#define UDF_ICB_TAG_FLAGS_NONRELOC (1<< 4)
#define UDF_ICB_TAG_FLAGS_CONTIGUES (1<< 9)
#define UDF_ICB_TAG_FLAGS_MULTIPLEVERS (1<<12)
#define UDF_ICB_TAG_FLAGS_SETUID (1<< 6)
#define UDF_ICB_TAG_FLAGS_SETGID (1<< 7)
#define UDF_ICB_TAG_FLAGS_STICKY (1<< 8)
#define UDF_ICB_FILETYPE_UNKNOWN 0
#define UDF_ICB_FILETYPE_UNALLOCSPACE 1
#define UDF_ICB_FILETYPE_PARTINTEGRITY 2
#define UDF_ICB_FILETYPE_INDIRECTENTRY 3
#define UDF_ICB_FILETYPE_DIRECTORY 4
#define UDF_ICB_FILETYPE_RANDOMACCESS 5
#define UDF_ICB_FILETYPE_BLOCKDEVICE 6
#define UDF_ICB_FILETYPE_CHARDEVICE 7
#define UDF_ICB_FILETYPE_EXTATTRREC 8
#define UDF_ICB_FILETYPE_FIFO 9
#define UDF_ICB_FILETYPE_SOCKET 10
#define UDF_ICB_FILETYPE_TERM 11
#define UDF_ICB_FILETYPE_SYMLINK 12
#define UDF_ICB_FILETYPE_STREAMDIR 13
#define UDF_ICB_FILETYPE_VAT 248
#define UDF_ICB_FILETYPE_REALTIME 249
#define UDF_ICB_FILETYPE_META_MAIN 250
#define UDF_ICB_FILETYPE_META_MIRROR 251
#define UDF_ICB_FILETYPE_META_BITMAP 252
/* Anchor Volume Descriptor Pointer [3/10.2] */
struct anchor_vdp {
struct desc_tag tag;
struct extent_ad main_vds_ex; /* to main volume descriptor set ; 16 sectors min */
struct extent_ad reserve_vds_ex; /* copy of main volume descriptor set ; 16 sectors min */
} __packed;
/* Volume Descriptor Pointer [3/10.3] */
struct vol_desc_ptr {
struct desc_tag tag; /* use for extending the volume descriptor space */
uint32_t vds_number;
struct extent_ad next_vds_ex; /* points to the next block for volume descriptor space */
} __packed;
/* Primary Volume Descriptor [3/10.1] */
struct pri_vol_desc {
struct desc_tag tag;
uint32_t seq_num; /* MAX prevail */
uint32_t pvd_num; /* assigned by author; 0 is special as in it may only occur once */
char vol_id[32]; /* KEY ; main identifier of this disc */
uint16_t vds_num; /* volume descriptor number; i.e. what volume number is it */
uint16_t max_vol_seq; /* maximum volume descriptor number known */
uint16_t ichg_lvl;
uint16_t max_ichg_lvl;
uint32_t charset_list;
uint32_t max_charset_list;
char volset_id[128]; /* KEY ; if part of a multi-disc set or a band of volumes */
struct charspec desc_charset; /* KEY according to ECMA 167 */
struct charspec explanatory_charset;
struct extent_ad vol_abstract;
struct extent_ad vol_copyright;
struct regid app_id;
struct timestamp time;
struct regid imp_id;
uint8_t imp_use[64];
uint32_t prev_vds_loc; /* location of predecessor _lov ? */
uint16_t flags; /* bit 0 : if set indicates volume set name is meaningful */
uint8_t reserved[22];
} __packed;
/* UDF specific implementation use part of the implementation use volume descriptor */
struct udf_lv_info {
struct charspec lvi_charset;
char logvol_id[128];
char lvinfo1[36];
char lvinfo2[36];
char lvinfo3[36];
struct regid impl_id;
uint8_t impl_use[128];
} __packed;
/* Implementation use Volume Descriptor */
struct impvol_desc {
struct desc_tag tag;
uint32_t seq_num;
struct regid impl_id;
union {
struct udf_lv_info lv_info;
char impl_use[460];
} _impl_use;
} __packed;
/* Logical Volume Descriptor [3/10.6] */
struct logvol_desc {
struct desc_tag tag;
uint32_t seq_num; /* MAX prevail */
struct charspec desc_charset; /* KEY */
char logvol_id[128]; /* KEY */
uint32_t lb_size;
struct regid domain_id;
union {
struct long_ad fsd_loc; /* to fileset descriptor SEQUENCE */
uint8_t logvol_content_use[16];
} _lvd_use;
uint32_t mt_l; /* Partition map length */
uint32_t n_pm; /* Number of partition maps */
struct regid imp_id;
uint8_t imp_use[128];
struct extent_ad integrity_seq_loc;
uint8_t maps[1];
} __packed;
#define lv_fsd_loc _lvd_use.fsd_loc
#define UDF_INTEGRITY_OPEN 0
#define UDF_INTEGRITY_CLOSED 1
#define UDF_PMAP_SIZE 64
/* Type 1 Partition Map [3/10.7.2] */
struct part_map_1 {
uint8_t type;
uint8_t len;
uint16_t vol_seq_num;
uint16_t part_num;
} __packed;
/* Type 2 Partition Map [3/10.7.3] */
struct part_map_2 {
uint8_t type;
uint8_t len;
uint8_t reserved[2];
struct regid part_id;
uint16_t vol_seq_num;
uint16_t part_num;
uint8_t reserved2[24];
} __packed;
/* Virtual Partition Map [UDF 2.01/2.2.8] */
struct part_map_virt {
uint8_t type;
uint8_t len;
uint8_t reserved[2];
struct regid id;
uint16_t vol_seq_num;
uint16_t part_num;
uint8_t reserved1[24];
} __packed;
/* Sparable Partition Map [UDF 2.01/2.2.9] */
struct part_map_spare {
uint8_t type;
uint8_t len;
uint8_t reserved[2];
struct regid id;
uint16_t vol_seq_num;
uint16_t part_num;
uint16_t packet_len;
uint8_t n_st; /* Number of redundant sparing tables range 1-4 */
uint8_t reserved1;
uint32_t st_size; /* size of EACH sparing table */
uint32_t st_loc[1]; /* locations of sparing tables */
} __packed;
/* Metadata Partition Map [UDF 2.50/2.2.10] */
struct part_map_meta {
uint8_t type;
uint8_t len;
uint8_t reserved[2];
struct regid id;
uint16_t vol_seq_num;
uint16_t part_num;
uint32_t meta_file_lbn; /* logical block number for file entry within part_num */
uint32_t meta_mirror_file_lbn;
uint32_t meta_bitmap_file_lbn;
uint32_t alloc_unit_size; /* allocation unit size in blocks */
uint16_t alignment_unit_size; /* alignment necessary in blocks */
uint8_t flags;
uint8_t reserved1[5];
} __packed;
#define METADATA_DUPLICATED 1
union udf_pmap {
uint8_t data[UDF_PMAP_SIZE];
struct part_map_1 pm1;
struct part_map_2 pm2;
struct part_map_virt pmv;
struct part_map_spare pms;
struct part_map_meta pmm;
};
/* Sparing Map Entry [UDF 2.01/2.2.11] */
struct spare_map_entry {
uint32_t org; /* partition relative address */
uint32_t map; /* absolute disc address (!) can be in partition, but doesn't have to be */
} __packed;
/* Sparing Table [UDF 2.01/2.2.11] */
struct udf_sparing_table {
struct desc_tag tag;
struct regid id;
uint16_t rt_l; /* Relocation Table len */
uint8_t reserved[2];
uint32_t seq_num;
struct spare_map_entry entries[1];
} __packed;
#define UDF_NO_PREV_VAT 0xffffffff
/* UDF 1.50 VAT suffix [UDF 2.2.10 (UDF 1.50 spec)] */
struct udf_oldvat_tail {
struct regid id; /* "*UDF Virtual Alloc Tbl" */
uint32_t prev_vat;
} __packed;
/* VAT table [UDF 2.0.1/2.2.10] */
struct udf_vat {
uint16_t header_len;
uint16_t impl_use_len;
char logvol_id[128]; /* newer version of the LVD one */
uint32_t prev_vat;
uint32_t num_files;
uint32_t num_directories;
uint16_t min_udf_readver;
uint16_t min_udf_writever;
uint16_t max_udf_writever;
uint16_t reserved;
uint8_t data[1]; /* impl.use followed by VAT entries (uint32_t) */
} __packed;
/* Space bitmap descriptor as found in the partition header descriptor */
struct space_bitmap_desc {
struct desc_tag tag; /* TagId 264 */
uint32_t num_bits; /* number of bits */
uint32_t num_bytes; /* bytes that contain it */
uint8_t data[1];
} __packed;
/* Unalloc space entry as found in the partition header descriptor */
struct space_entry_desc {
struct desc_tag tag; /* TagId 263 */
struct icb_tag icbtag; /* type 1 */
uint32_t l_ad; /* in bytes */
uint8_t entry[1];
} __packed;
/* Partition header descriptor; in the contents_use of part_desc */
struct part_hdr_desc {
struct short_ad unalloc_space_table;
struct short_ad unalloc_space_bitmap;
struct short_ad part_integrity_table; /* has to be ZERO for UDF */
struct short_ad freed_space_table;
struct short_ad freed_space_bitmap;
uint8_t reserved[88];
} __packed;
/* Partition Descriptor [3/10.5] */
struct part_desc {
struct desc_tag tag;
uint32_t seq_num; /* MAX prevailing */
uint16_t flags; /* bit 0 : if set the space is allocated */
uint16_t part_num; /* KEY */
struct regid contents;
union {
struct part_hdr_desc part_hdr;
uint8_t contents_use[128];
} _impl_use;
uint32_t access_type; /* R/W, WORM etc. */
uint32_t start_loc; /* start of partition with given length */
uint32_t part_len;
struct regid imp_id;
uint8_t imp_use[128];
uint8_t reserved[156];
} __packed;
#define pd_part_hdr _impl_use.part_hdr
#define UDF_PART_FLAG_ALLOCATED 1
/* Unallocated Space Descriptor (UDF 2.01/2.2.5) */
struct unalloc_sp_desc {
struct desc_tag tag;
uint32_t seq_num; /* MAX prevailing */
uint32_t alloc_desc_num;
struct extent_ad alloc_desc[1];
} __packed;
/* Logical Volume Integrity Descriptor [3/30.10] */
struct logvolhdr {
uint64_t next_unique_id;
/* rest reserved */
} __packed;
struct udf_logvol_info {
struct regid impl_id;
uint32_t num_files;
uint32_t num_directories;
uint16_t min_udf_readver;
uint16_t min_udf_writever;
uint16_t max_udf_writever;
} __packed;
struct logvol_int_desc {
struct desc_tag tag;
struct timestamp time;
uint32_t integrity_type;
struct extent_ad next_extent;
union {
struct logvolhdr logvolhdr;
int8_t reserved[32];
} _impl_use;
uint32_t num_part;
uint32_t l_iu;
uint32_t tables[1]; /* Freespace table, Sizetable, Implementation use */
} __packed;
#define lvint_next_unique_id _impl_use.logvolhdr.next_unique_id
/* File Set Descriptor [4/14.1] */
struct fileset_desc {
struct desc_tag tag;
struct timestamp time;
uint16_t ichg_lvl;
uint16_t max_ichg_lvl;
uint32_t charset_list;
uint32_t max_charset_list;
uint32_t fileset_num; /* key! */
uint32_t fileset_desc_num;
struct charspec logvol_id_charset;
char logvol_id[128]; /* for recovery */
struct charspec fileset_charset;
char fileset_id[32]; /* Mountpoint !! */
char copyright_file_id[32];
char abstract_file_id[32];
struct long_ad rootdir_icb; /* to rootdir; icb->virtual ? */
struct regid domain_id;
struct long_ad next_ex; /* to the next fileset_desc extent */
struct long_ad streamdir_icb; /* streamdir; needed? */
uint8_t reserved[32];
} __packed;
/* File Identifier Descriptor [4/14.4] */
struct fileid_desc {
struct desc_tag tag;
uint16_t file_version_num;
uint8_t file_char;
uint8_t l_fi; /* Length of file identifier area */
struct long_ad icb;
uint16_t l_iu; /* Length of implementation use area */
uint8_t data[0];
} __packed;
#define UDF_FID_SIZE 38
#define UDF_FILE_CHAR_VIS (1 << 0) /* Invisible */
#define UDF_FILE_CHAR_DIR (1 << 1) /* Directory */
#define UDF_FILE_CHAR_DEL (1 << 2) /* Deleted */
#define UDF_FILE_CHAR_PAR (1 << 3) /* Parent Directory */
#define UDF_FILE_CHAR_META (1 << 4) /* Stream metadata */
/* Extended attributes [4/14.10.1] */
struct extattrhdr_desc {
struct desc_tag tag;
uint32_t impl_attr_loc; /* offsets within this descriptor */
uint32_t appl_attr_loc; /* ditto */
} __packed;
#define UDF_IMPL_ATTR_LOC_NOT_PRESENT 0xffffffff
#define UDF_APPL_ATTR_LOC_NOT_PRESENT 0xffffffff
/* Extended attribute entry [4/48.10.2] */
struct extattr_entry {
uint32_t type;
uint8_t subtype;
uint8_t reserved[3];
uint32_t a_l;
} __packed;
/* Extended attribute entry; type 2048 [4/48.10.8] */
struct impl_extattr_entry {
struct extattr_entry hdr;
uint32_t iu_l;
struct regid imp_id;
uint8_t data[1];
} __packed;
/* Extended attribute entry; type 65 536 [4/48.10.9] */
struct appl_extattr_entry {
struct extattr_entry hdr;
uint32_t au_l;
struct regid appl_id;
uint8_t data[1];
} __packed;
/* File Times attribute entry; type 5 or type 6 [4/48.10.5], [4/48.10.6] */
struct filetimes_extattr_entry {
struct extattr_entry hdr;
uint32_t d_l; /* length of times[] data following */
uint32_t existence; /* bitmask */
struct timestamp times[1]; /* in order of ascending bits */
} __packed;
#define UDF_FILETIMES_ATTR_NO 5
#define UDF_FILETIMES_FILE_CREATION 1
#define UDF_FILETIMES_FILE_DELETION 4
#define UDF_FILETIMES_FILE_EFFECTIVE 8
#define UDF_FILETIMES_FILE_BACKUPED 16
#define UDF_FILETIMES_ATTR_SIZE(no) (20 + (no)*sizeof(struct timestamp))
/* Device Specification Extended Attribute [4/4.10.7] */
struct device_extattr_entry {
struct extattr_entry hdr;
uint32_t iu_l; /* length of implementation use */
uint32_t major;
uint32_t minor;
uint8_t data[1]; /* UDF: if nonzero length, contain developer ID regid */
} __packed;
#define UDF_DEVICESPEC_ATTR_NO 12
/* VAT LV extension Extended Attribute [UDF 3.3.4.5.1.3] 1.50 errata */
struct vatlvext_extattr_entry {
uint64_t unique_id_chk; /* needs to be copy of ICB's */
uint32_t num_files;
uint32_t num_directories;
char logvol_id[128]; /* replaces logvol name */
} __packed;
/* File Entry [4/14.9] */
struct file_entry {
struct desc_tag tag;
struct icb_tag icbtag;
uint32_t uid;
uint32_t gid;
uint32_t perm;
uint16_t link_cnt;
uint8_t rec_format;
uint8_t rec_disp_attr;
uint32_t rec_len;
uint64_t inf_len;
uint64_t logblks_rec;
struct timestamp atime;
struct timestamp mtime;
struct timestamp attrtime;
uint32_t ckpoint;
struct long_ad ex_attr_icb;
struct regid imp_id;
uint64_t unique_id;
uint32_t l_ea; /* Length of extended attribute area */
uint32_t l_ad; /* Length of allocation descriptors */
uint8_t data[1];
} __packed;
#define UDF_FENTRY_SIZE 176
#define UDF_FENTRY_PERM_USER_MASK 0x07
#define UDF_FENTRY_PERM_GRP_MASK 0xE0
#define UDF_FENTRY_PERM_OWNER_MASK 0x1C00
/* Extended File Entry [4/48.17] */
struct extfile_entry {
struct desc_tag tag;
struct icb_tag icbtag;
uint32_t uid;
uint32_t gid;
uint32_t perm;
uint16_t link_cnt;
uint8_t rec_format;
uint8_t rec_disp_attr;
uint32_t rec_len;
uint64_t inf_len;
uint64_t obj_size;
uint64_t logblks_rec;
struct timestamp atime;
struct timestamp mtime;
struct timestamp ctime;
struct timestamp attrtime;
uint32_t ckpoint;
uint32_t reserved1;
struct long_ad ex_attr_icb;
struct long_ad streamdir_icb;
struct regid imp_id;
uint64_t unique_id;
uint32_t l_ea; /* Length of extended attribute area */
uint32_t l_ad; /* Length of allocation descriptors */
uint8_t data[1];
} __packed;
#define UDF_EXTFENTRY_SIZE 216
/* Indirect entry [ecma 48.7] */
struct indirect_entry {
struct desc_tag tag;
struct icb_tag icbtag;
struct long_ad indirect_icb;
} __packed;
/* Allocation extent descriptor [ecma 48.5] */
struct alloc_ext_entry {
struct desc_tag tag;
uint32_t prev_entry;
uint32_t l_ad;
uint8_t data[1];
} __packed;
union dscrptr {
struct desc_tag tag;
struct anchor_vdp avdp;
struct vol_desc_ptr vdp;
struct pri_vol_desc pvd;
struct logvol_desc lvd;
struct unalloc_sp_desc usd;
struct logvol_int_desc lvid;
struct impvol_desc ivd;
struct part_desc pd;
struct fileset_desc fsd;
struct fileid_desc fid;
struct file_entry fe;
struct extfile_entry efe;
struct extattrhdr_desc eahd;
struct indirect_entry inde;
struct alloc_ext_entry aee;
struct udf_sparing_table spt;
struct space_bitmap_desc sbd;
struct space_entry_desc sed;
};
#endif /* !_FS_UDF_ECMA167_UDF_H_ */

16
sys/fs/udf/files.udf Normal file
View file

@ -0,0 +1,16 @@
# $NetBSD: files.udf,v 1.5 2013/07/10 15:10:56 reinoud Exp $
deffs UDF
file fs/udf/udf_osta.c udf
file fs/udf/udf_vfsops.c udf
file fs/udf/udf_vnops.c udf
file fs/udf/udf_subr.c udf
file fs/udf/udf_readwrite.c udf
file fs/udf/udf_strat_bootstrap.c udf
file fs/udf/udf_strat_sequential.c udf
file fs/udf/udf_strat_direct.c udf
file fs/udf/udf_strat_rmw.c udf
file fs/udf/udf_allocation.c udf
file fs/udf/udf_rename.c udf

426
sys/fs/udf/udf.h Normal file
View file

@ -0,0 +1,426 @@
/* $NetBSD: udf.h,v 1.46 2013/10/18 19:56:55 christos Exp $ */
/*
* Copyright (c) 2006, 2008 Reinoud Zandijk
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef _FS_UDF_UDF_H_
#define _FS_UDF_UDF_H_
#include <sys/queue.h>
#include <sys/rbtree.h>
#include <sys/uio.h>
#include <sys/mutex.h>
#include "udf_osta.h"
#include "ecma167-udf.h"
#include <sys/cdio.h>
#include <sys/bufq.h>
#include <sys/disk.h>
#include <sys/kthread.h>
#include <miscfs/genfs/genfs_node.h>
/* debug section */
extern int udf_verbose;
/* undefine UDF_COMPLETE_DELETE to need `purge'; but purge is not implemented */
#define UDF_COMPLETE_DELETE
/* debug categories */
#define UDF_DEBUG_VOLUMES 0x0000001
#define UDF_DEBUG_LOCKING 0x0000002
#define UDF_DEBUG_NODE 0x0000004
#define UDF_DEBUG_LOOKUP 0x0000008
#define UDF_DEBUG_READDIR 0x0000010
#define UDF_DEBUG_FIDS 0x0000020
#define UDF_DEBUG_DESCRIPTOR 0x0000040
#define UDF_DEBUG_TRANSLATE 0x0000080
#define UDF_DEBUG_STRATEGY 0x0000100
#define UDF_DEBUG_READ 0x0000200
#define UDF_DEBUG_WRITE 0x0000400
#define UDF_DEBUG_CALL 0x0000800
#define UDF_DEBUG_ATTR 0x0001000
#define UDF_DEBUG_EXTATTR 0x0002000
#define UDF_DEBUG_ALLOC 0x0004000
#define UDF_DEBUG_ADWLK 0x0008000
#define UDF_DEBUG_DIRHASH 0x0010000
#define UDF_DEBUG_NOTIMPL 0x0020000
#define UDF_DEBUG_SHEDULE 0x0040000
#define UDF_DEBUG_ECCLINE 0x0080000
#define UDF_DEBUG_SYNC 0x0100000
#define UDF_DEBUG_PARANOIA 0x0200000
#define UDF_DEBUG_PARANOIDADWLK 0x0400000
#define UDF_DEBUG_NODEDUMP 0x0800000
#define UDF_DEBUG_RESERVE 0x1000000
/* initial value of udf_verbose */
#define UDF_DEBUGGING 0
#ifdef UDF_DEBUG
#define DPRINTF(name, arg) { \
if (udf_verbose & UDF_DEBUG_##name) {\
printf arg;\
};\
}
#define DPRINTFIF(name, cond, arg) { \
if (udf_verbose & UDF_DEBUG_##name) { \
if (cond) printf arg;\
};\
}
#else
#define DPRINTF(name, arg) {}
#define DPRINTFIF(name, cond, arg) {}
#endif
/* constants to identify what kind of identifier we are dealing with */
#define UDF_REGID_DOMAIN 1
#define UDF_REGID_UDF 2
#define UDF_REGID_IMPLEMENTATION 3
#define UDF_REGID_APPLICATION 4
#define UDF_REGID_NAME 99
/* DON'T change these: they identify 13thmonkey's UDF implementation */
#define APP_NAME "*NetBSD UDF"
#define APP_VERSION_MAIN 0
#define APP_VERSION_SUB 5
#define IMPL_NAME "*NetBSD kernel UDF"
/* Configuration values */
#define UDF_INODE_HASHBITS 10
#define UDF_INODE_HASHSIZE (1<<UDF_INODE_HASHBITS)
#define UDF_INODE_HASHMASK (UDF_INODE_HASHSIZE - 1)
#define UDF_ECCBUF_HASHBITS 10
#define UDF_ECCBUF_HASHSIZE (1<<UDF_ECCBUF_HASHBITS)
#define UDF_ECCBUF_HASHMASK (UDF_ECCBUF_HASHSIZE -1)
#define UDF_ECCLINE_MAXFREE 5 /* picked, needs calculation */
#define UDF_ECCLINE_MAXBUSY 100 /* picked, needs calculation */
#define UDF_MAX_MAPPINGS (MAXPHYS/DEV_BSIZE) /* 128 */
#define UDF_VAT_CHUNKSIZE (64*1024) /* picked */
#define UDF_SYMLINKBUFLEN (64*1024) /* picked */
#define UDF_DISC_SLACK (128) /* picked, at least 64 kb or 128 */
#define UDF_ISO_VRS_SIZE (32*2048) /* 32 ISO `sectors' */
/* structure space */
#define UDF_ANCHORS 4 /* 256, 512, N-256, N */
#define UDF_PARTITIONS 4 /* overkill */
#define UDF_PMAPS 5 /* overkill */
#define UDF_LVDINT_SEGMENTS 100 /* big overkill */
#define UDF_LVINT_LOSSAGE 4 /* lose 2 openings */
#define UDF_MAX_ALLOC_EXTENTS 50 /* overkill */
/* constants */
#define UDF_MAXNAMLEN 255 /* as per SPEC */
#define UDF_TRANS_ZERO ((uint64_t) -1)
#define UDF_TRANS_UNMAPPED ((uint64_t) -2)
#define UDF_TRANS_INTERN ((uint64_t) -3)
#define UDF_MAX_SECTOR ((uint64_t) -10) /* high water mark */
/* RW content hint for allocation and other purposes */
#define UDF_C_ABSOLUTE 0 /* blob to write at absolute */
#define UDF_C_PROCESSED 0 /* not relevant */
#define UDF_C_USERDATA 1 /* all but userdata is metadata */
#define UDF_C_DSCR 2 /* update sectornr and CRC */
#define UDF_C_FLOAT_DSCR 3 /* update sectornr and CRC; sequential */
#define UDF_C_NODE 4 /* file/dir node, update sectornr and CRC */
#define UDF_C_FIDS 5 /* update all contained fids */
#define UDF_C_METADATA_SBM 6 /* space bitmap, update sectornr and CRC */
#define UDF_C_EXTATTRS 7 /* dunno what to do yet */
/* use unused b_freelistindex for our UDF_C_TYPE */
#define b_udf_c_type b_freelistindex
/* virtual to physical mapping types */
#define UDF_VTOP_RAWPART UDF_PMAPS /* [0..UDF_PMAPS> are normal */
#define UDF_VTOP_TYPE_RAW 0
#define UDF_VTOP_TYPE_UNKNOWN 0
#define UDF_VTOP_TYPE_PHYS 1
#define UDF_VTOP_TYPE_VIRT 2
#define UDF_VTOP_TYPE_SPARABLE 3
#define UDF_VTOP_TYPE_META 4
/* allocation strategies */
#define UDF_ALLOC_INVALID 0
#define UDF_ALLOC_SEQUENTIAL 1 /* linear on NWA */
#define UDF_ALLOC_VAT 2 /* VAT handling */
#define UDF_ALLOC_SPACEMAP 3 /* spacemaps */
#define UDF_ALLOC_METABITMAP 4 /* metadata bitmap */
#define UDF_ALLOC_METASEQUENTIAL 5 /* in chunks seq., nodes not seq */
#define UDF_ALLOC_RELAXEDSEQUENTIAL 6 /* only nodes not seq. */
/* logical volume open/close actions */
#define UDF_OPEN_SESSION 0x01 /* if needed writeout VRS + VDS */
#define UDF_CLOSE_SESSION 0x02 /* close session after writing VAT */
#define UDF_FINALISE_DISC 0x04 /* close session after writing VAT */
#define UDF_WRITE_VAT 0x08 /* sequential VAT filesystem */
#define UDF_WRITE_LVINT 0x10 /* write out open lvint */
#define UDF_WRITE_PART_BITMAPS 0x20 /* write out partition space bitmaps */
#define UDF_APPENDONLY_LVINT 0x40 /* no shifting, only appending */
#define UDF_WRITE_METAPART_NODES 0x80 /* write out metadata partition nodes*/
#define UDFLOGVOL_BITS "\20\1OPEN_SESSION\2CLOSE_SESSION\3FINALISE_DISC" \
"\4WRITE_VAT\5WRITE_LVINT\6WRITE_PART_BITMAPS" \
"\7APPENDONLY_LVINT\10WRITE_METAPART_NODES"
/* logical volume error handling actions */
#define UDF_UPDATE_TRACKINFO 0x01 /* update trackinfo and re-shedule */
#define UDF_REMAP_BLOCK 0x02 /* remap the failing block length */
#define UDFONERROR_BITS "\20\1UPDATE_TRACKINFO\2REMAP_BLOCK"
/* readdir cookies */
#define UDF_DIRCOOKIE_DOT 1
/* malloc pools */
MALLOC_DECLARE(M_UDFMNT);
MALLOC_DECLARE(M_UDFVOLD);
MALLOC_DECLARE(M_UDFTEMP);
extern struct pool udf_node_pool;
struct udf_node;
struct udf_strategy;
struct udf_lvintq {
uint32_t start;
uint32_t end;
uint32_t pos;
uint32_t wpos;
};
struct udf_bitmap {
uint8_t *blob; /* allocated */
uint8_t *bits; /* bits themselves */
uint8_t *pages; /* dirty pages */
uint32_t max_offset; /* in bits */
uint32_t data_pos; /* position in data */
uint32_t metadata_pos; /* .. in metadata */
};
struct udf_strat_args {
struct udf_mount *ump;
struct udf_node *udf_node;
struct long_ad *icb;
union dscrptr *dscr;
struct buf *nestbuf;
kauth_cred_t cred;
int waitfor;
};
struct udf_strategy {
int (*create_logvol_dscr) (struct udf_strat_args *args);
void (*free_logvol_dscr) (struct udf_strat_args *args);
int (*read_logvol_dscr) (struct udf_strat_args *args);
int (*write_logvol_dscr) (struct udf_strat_args *args);
void (*queuebuf) (struct udf_strat_args *args);
void (*discstrat_init) (struct udf_strat_args *args);
void (*discstrat_finish) (struct udf_strat_args *args);
};
extern struct udf_strategy udf_strat_bootstrap;
extern struct udf_strategy udf_strat_sequential;
extern struct udf_strategy udf_strat_direct;
extern struct udf_strategy udf_strat_rmw;
/* pre cleanup */
struct udf_mount {
struct mount *vfs_mountp;
struct vnode *devvp;
struct mmc_discinfo discinfo;
struct udf_args mount_args;
/* format descriptors */
kmutex_t logvol_mutex;
struct anchor_vdp *anchors[UDF_ANCHORS]; /* anchors to VDS */
struct pri_vol_desc *primary_vol; /* identification */
struct logvol_desc *logical_vol; /* main mapping v->p */
struct unalloc_sp_desc *unallocated; /* free UDF space */
struct impvol_desc *implementation; /* likely reduntant */
struct logvol_int_desc *logvol_integrity; /* current integrity */
struct part_desc *partitions[UDF_PARTITIONS]; /* partitions */
/* logvol_info is derived; points *into* other structures */
struct udf_logvol_info *logvol_info; /* integrity descr. */
/* fileset and root directories */
struct fileset_desc *fileset_desc; /* normally one */
/* tracing logvol integrity history */
struct udf_lvintq lvint_trace[UDF_LVDINT_SEGMENTS];
int lvopen; /* logvol actions */
int lvclose; /* logvol actions */
/* logical to physical translations */
int vtop[UDF_PMAPS+1]; /* vpartnr trans */
int vtop_tp[UDF_PMAPS+1]; /* type of trans */
/* disc allocation / writing method */
kmutex_t allocate_mutex;
int lvreadwrite; /* error handling */
int vtop_alloc[UDF_PMAPS+1]; /* alloc scheme */
int data_part;
int node_part;
int fids_part;
/* sequential track info */
struct mmc_trackinfo data_track;
struct mmc_trackinfo metadata_track;
/* VAT */
uint32_t first_possible_vat_location;
uint32_t last_possible_vat_location;
uint32_t vat_entries;
uint32_t vat_offset; /* offset in table */
uint32_t vat_last_free_lb; /* last free lb_num */
uint32_t vat_table_len;
uint32_t vat_table_alloc_len;
uint8_t *vat_table;
uint8_t *vat_pages; /* TODO */
struct udf_node *vat_node; /* system node */
/* space bitmaps for physical partitions */
struct space_bitmap_desc*part_unalloc_dscr[UDF_PARTITIONS];
struct space_bitmap_desc*part_freed_dscr [UDF_PARTITIONS];
struct udf_bitmap part_unalloc_bits[UDF_PARTITIONS];
struct udf_bitmap part_freed_bits [UDF_PARTITIONS];
/* sparable */
uint32_t sparable_packet_size;
uint32_t packet_size;
struct udf_sparing_table*sparing_table;
/* meta */
struct udf_node *metadata_node; /* system node */
struct udf_node *metadatamirror_node; /* system node */
struct udf_node *metadatabitmap_node; /* system node */
struct space_bitmap_desc*metadata_unalloc_dscr;
struct udf_bitmap metadata_unalloc_bits;
uint32_t metadata_alloc_unit_size;
uint16_t metadata_alignment_unit_size;
uint8_t metadata_flags;
/* rb tree for lookup icb to udf_node and sorted list for sync */
kmutex_t ihash_lock;
kmutex_t get_node_lock;
struct rb_tree udf_node_tree;
/* syncing */
int syncing; /* are we syncing? */
kcondvar_t dirtynodes_cv; /* sleeping on sync */
/* late allocation */
int32_t uncommitted_lbs[UDF_PARTITIONS];
struct long_ad *la_node_ad_cpy; /* issue buf */
uint64_t *la_lmapping, *la_pmapping; /* issue buf */
/* lists */
STAILQ_HEAD(udfmntpts, udf_mount) all_udf_mntpnts;
/* device strategy */
struct udf_strategy *strategy;
void *strategy_private;
};
/*
* UDF node describing a file/directory.
*
* BUGALERT claim node_mutex before reading/writing to prevent inconsistencies !
*/
struct udf_node {
struct genfs_node i_gnode; /* has to be first */
struct vnode *vnode; /* vnode associated */
struct udf_mount *ump;
kmutex_t node_mutex;
kcondvar_t node_lock; /* sleeping lock */
char const *lock_fname;
int lock_lineno;
/* rb_node for fast lookup and fast sequential visiting */
struct rb_node rbnode;
/* one of `fe' or `efe' can be set, not both (UDF file entry dscr.) */
struct file_entry *fe;
struct extfile_entry *efe;
struct alloc_ext_entry *ext[UDF_MAX_ALLOC_EXTENTS];
int num_extensions;
/* location found, recording location & hints */
struct long_ad loc; /* FID/hash loc. */
struct long_ad write_loc; /* strat 4096 loc */
int needs_indirect; /* has missing indr. */
struct long_ad ext_loc[UDF_MAX_ALLOC_EXTENTS];
struct dirhash *dir_hash;
/* misc */
uint32_t i_flags; /* associated flags */
struct lockf *lockf; /* lock list */
uint32_t outstanding_bufs; /* file data */
uint32_t outstanding_nodedscr; /* node dscr */
int32_t uncommitted_lbs; /* in UBC */
/* references to associated nodes */
struct udf_node *extattr;
struct udf_node *streamdir;
struct udf_node *my_parent; /* if extended attr. */
};
/* misc. flags stored in i_flags (XXX needs cleaning up) */
#define IN_ACCESS 0x0001 /* Inode access time update request */
#define IN_CHANGE 0x0002 /* Inode change time update request */
#define IN_UPDATE 0x0004 /* Inode was written to; update mtime*/
#define IN_MODIFY 0x0008 /* Modification time update request */
#define IN_MODIFIED 0x0010 /* node has been modified */
#define IN_ACCESSED 0x0020 /* node has been accessed */
#define IN_RENAME 0x0040 /* node is being renamed. XXX ?? */
#define IN_DELETED 0x0080 /* node is unlinked, no FID reference*/
#define IN_LOCKED 0x0100 /* node is locked by condvar */
#define IN_SYNCED 0x0200 /* node is being used by sync */
#define IN_CALLBACK_ULK 0x0400 /* node will be unlocked by callback */
#define IN_NODE_REBUILD 0x0800 /* node is rebuild */
#define IN_FLAGBITS \
"\10\1IN_ACCESS\2IN_CHANGE\3IN_UPDATE\4IN_MODIFY\5IN_MODIFIED" \
"\6IN_ACCESSED\7IN_RENAME\10IN_DELETED\11IN_LOCKED\12IN_SYNCED" \
"\13IN_CALLBACK_ULK\14IN_NODE_REBUILD"
#endif /* !_FS_UDF_UDF_H_ */

3215
sys/fs/udf/udf_allocation.c Normal file

File diff suppressed because it is too large Load diff

76
sys/fs/udf/udf_bswap.h Normal file
View file

@ -0,0 +1,76 @@
/* $NetBSD: udf_bswap.h,v 1.8 2009/10/22 21:50:01 bouyer Exp $ */
/*
* Copyright (c) 1998 Manuel Bouyer.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* adapted for UDF by Reinoud Zandijk <reinoud@netbsd.org>
*
*/
#ifndef _FS_UDF_UDF_BSWAP_H_
#define _FS_UDF_UDF_BSWAP_H_
#include <sys/endian.h>
#include <machine/bswap.h>
#include <sys/bswap.h>
/* rest only relevant for big endian machines */
#if (BYTE_ORDER == BIG_ENDIAN)
/* inlines for access to swapped data */
static __inline uint16_t udf_rw16(uint16_t);
static __inline uint32_t udf_rw32(uint32_t);
static __inline uint64_t udf_rw64(uint64_t);
static __inline uint16_t
udf_rw16(uint16_t a)
{
return bswap16(a);
}
static __inline uint32_t
udf_rw32(uint32_t a)
{
return bswap32(a);
}
static __inline uint64_t
udf_rw64(uint64_t a)
{
return bswap64(a);
}
#else
#define udf_rw16(a) ((uint16_t)(a))
#define udf_rw32(a) ((uint32_t)(a))
#define udf_rw64(a) ((uint64_t)(a))
#endif
#endif /* !_FS_UDF_UDF_BSWAP_H_ */

70
sys/fs/udf/udf_mount.h Normal file
View file

@ -0,0 +1,70 @@
/* $NetBSD: udf_mount.h,v 1.3 2006/02/02 15:52:23 reinoud Exp $ */
/*
* Copyright (c) 2006 Reinoud Zandijk
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed for the
* NetBSD Project. See http://www.NetBSD.org/ for
* information about NetBSD.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef _FS_UDF_UDF_MOUNT_H_
#define _FS_UDF_UDF_MOUNT_H_
/*
* Arguments to mount UDF filingsystem.
*/
#define UDFMNT_VERSION 1
struct udf_args {
uint32_t version; /* version of this structure */
char *fspec; /* mount specifier */
int32_t sessionnr; /* session specifier, rel of abs */
uint32_t udfmflags; /* mount options */
int32_t gmtoff; /* offset from UTC in seconds */
uid_t anon_uid; /* mapping of anonymous files uid */
gid_t anon_gid; /* mapping of anonymous files gid */
uid_t nobody_uid; /* nobody:nobody will map to -1:-1 */
gid_t nobody_gid; /* nobody:nobody will map to -1:-1 */
uint32_t sector_size; /* for mounting dumps/files */
/* extendable */
uint8_t reserved[32];
};
/* udf mount options */
#define UDFMNT_CLOSESESSION 0x00000001 /* close session on dismount */
#define UDFMNT_BITS "\20\1CLOSESESSION"
#endif /* !_FS_UDF_UDF_MOUNT_H_ */

514
sys/fs/udf/udf_osta.c Normal file
View file

@ -0,0 +1,514 @@
/* $NetBSD: udf_osta.c,v 1.10 2013/08/05 17:02:54 joerg Exp $ */
#if HAVE_NBTOOL_CONFIG_H
#include "nbtool_config.h"
#endif
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: udf_osta.c,v 1.10 2013/08/05 17:02:54 joerg Exp $");
/*
* Various routines from the OSTA 2.01 specs. Copyrights are included with
* each code segment. Slight whitespace modifications have been made for
* formatting purposes. Typos/bugs have been fixed.
*
*/
#include "udf_osta.h"
#ifndef _KERNEL
#include <ctype.h>
#endif
/*****************************************************************************/
/***********************************************************************
* OSTA compliant Unicode compression, uncompression routines.
* Copyright 1995 Micro Design International, Inc.
* Written by Jason M. Rinn.
* Micro Design International gives permission for the free use of the
* following source code.
*/
/***********************************************************************
* Takes an OSTA CS0 compressed unicode name, and converts
* it to Unicode.
* The Unicode output will be in the byte order
* that the local compiler uses for 16-bit values.
* NOTE: This routine only performs error checking on the compID.
* It is up to the user to ensure that the unicode buffer is large
* enough, and that the compressed unicode name is correct.
*
* RETURN VALUE
*
* The number of unicode characters which were uncompressed.
* A -1 is returned if the compression ID is invalid.
*/
int
udf_UncompressUnicode(
int numberOfBytes, /* (Input) number of bytes read from media. */
byte *UDFCompressed, /* (Input) bytes read from media. */
unicode_t *unicode) /* (Output) uncompressed unicode characters. */
{
unsigned int compID;
int returnValue, unicodeIndex, byteIndex;
/* Use UDFCompressed to store current byte being read. */
compID = UDFCompressed[0];
/* First check for valid compID. */
if (compID != 8 && compID != 16) {
returnValue = -1;
} else {
unicodeIndex = 0;
byteIndex = 1;
/* Loop through all the bytes. */
while (byteIndex < numberOfBytes) {
if (compID == 16) {
/* Move the first byte to the high bits of the
* unicode char.
*/
unicode[unicodeIndex] =
UDFCompressed[byteIndex++] << 8;
} else {
unicode[unicodeIndex] = 0;
}
if (byteIndex < numberOfBytes) {
/*Then the next byte to the low bits. */
unicode[unicodeIndex] |=
UDFCompressed[byteIndex++];
}
unicodeIndex++;
}
returnValue = unicodeIndex;
}
return(returnValue);
}
/***********************************************************************
* DESCRIPTION:
* Takes a string of unicode wide characters and returns an OSTA CS0
* compressed unicode string. The unicode MUST be in the byte order of
* the compiler in order to obtain correct results. Returns an error
* if the compression ID is invalid.
*
* NOTE: This routine assumes the implementation already knows, by
* the local environment, how many bits are appropriate and
* therefore does no checking to test if the input characters fit
* into that number of bits or not.
*
* RETURN VALUE
*
* The total number of bytes in the compressed OSTA CS0 string,
* including the compression ID.
* A -1 is returned if the compression ID is invalid.
*/
int
udf_CompressUnicode(
int numberOfChars, /* (Input) number of unicode characters. */
int compID, /* (Input) compression ID to be used. */
unicode_t *unicode, /* (Input) unicode characters to compress. */
byte *UDFCompressed) /* (Output) compressed string, as bytes. */
{
int byteIndex, unicodeIndex;
if (compID != 8 && compID != 16) {
byteIndex = -1; /* Unsupported compression ID ! */
} else {
/* Place compression code in first byte. */
UDFCompressed[0] = compID;
byteIndex = 1;
unicodeIndex = 0;
while (unicodeIndex < numberOfChars) {
if (compID == 16) {
/* First, place the high bits of the char
* into the byte stream.
*/
UDFCompressed[byteIndex++] =
(unicode[unicodeIndex] & 0xFF00) >> 8;
}
/*Then place the low bits into the stream. */
UDFCompressed[byteIndex++] =
unicode[unicodeIndex] & 0x00FF;
unicodeIndex++;
}
}
return(byteIndex);
}
/*****************************************************************************/
/*
* CRC 010041
*/
static unsigned short crc_table[256] = {
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,
0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6,
0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE,
0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485,
0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D,
0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4,
0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC,
0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B,
0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12,
0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A,
0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41,
0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49,
0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70,
0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78,
0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F,
0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E,
0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256,
0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D,
0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C,
0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634,
0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB,
0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3,
0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92,
0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9,
0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1,
0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8,
0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
};
unsigned short
udf_cksum(unsigned char *s, int n)
{
unsigned short crc=0;
while (n-- > 0)
crc = crc_table[(crc>>8 ^ *s++) & 0xff] ^ (crc<<8);
return crc;
}
/* UNICODE Checksum */
unsigned short
udf_unicode_cksum(unsigned short *s, int n)
{
unsigned short crc=0;
while (n-- > 0) {
/* Take high order byte first--corresponds to a big endian
* byte stream.
*/
crc = crc_table[(crc>>8 ^ (*s>>8)) & 0xff] ^ (crc<<8);
crc = crc_table[(crc>>8 ^ (*s++ & 0xff)) & 0xff] ^ (crc<<8);
}
return crc;
}
/*
* Calculates a 16-bit checksum of the Implementation Use
* Extended Attribute header or Application Use Extended Attribute
* header. The fields AttributeType through ImplementationIdentifier
* (or ApplicationIdentifier) inclusively represent the
* data covered by the checksum (48 bytes).
*
*/
uint16_t udf_ea_cksum(uint8_t *data) {
uint16_t checksum = 0;
int count;
for (count = 0; count < 48; count++) {
checksum += *data++;
}
return checksum;
}
#ifdef MAIN
unsigned char bytes[] = { 0x70, 0x6A, 0x77 };
main(void)
{
unsigned short x;
x = cksum(bytes, sizeof bytes);
printf("checksum: calculated=%4.4x, correct=%4.4x\en", x, 0x3299);
exit(0);
}
#endif
/*****************************************************************************/
/* #ifdef NEEDS_ISPRINT */
/***********************************************************************
* OSTA UDF compliant file name translation routine for OS/2,
* Windows 95, Windows NT, Macintosh and UNIX.
* Copyright 1995 Micro Design International, Inc.
* Written by Jason M. Rinn.
* Micro Design International gives permission for the free use of the
* following source code.
*/
/***********************************************************************
* To use these routines with different operating systems.
*
* OS/2
* Define OS2
* Define MAXLEN = 254
*
* Windows 95
* Define WIN_95
* Define MAXLEN = 255
*
* Windows NT
* Define WIN_NT
* Define MAXLEN = 255
*
* Macintosh:
* Define MAC.
* Define MAXLEN = 31.
*
* UNIX
* Define UNIX.
* Define MAXLEN as specified by unix version.
*/
#define ILLEGAL_CHAR_MARK 0x005F
#define CRC_MARK 0x0023
#define EXT_SIZE 5
#define PERIOD 0x002E
#define SPACE 0x0020
/*** PROTOTYPES ***/
int IsIllegal(unicode_t ch);
/* Define a function or macro which determines if a Unicode character is
* printable under your implementation.
*/
/* #include <stdio.h> */
static int UnicodeIsPrint(unicode_t ch) {
return (ch >=' ') && (ch != 127);
}
int UnicodeLength(unicode_t *string) {
int length;
length = 0;
while (*string++) length++;
return length;
}
#ifdef _KERNEL
static int isprint(int c) {
return (c >= ' ') && (c != 127);
}
#endif
/***********************************************************************
* Translates a long file name to one using a MAXLEN and an illegal
* char set in accord with the OSTA requirements. Assumes the name has
* already been translated to Unicode.
*
* RETURN VALUE
*
* Number of unicode characters in translated name.
*/
int UDFTransName(
unicode_t *newName, /* (Output)Translated name. Must be of length
* MAXLEN */
unicode_t *udfName, /* (Input) Name from UDF volume.*/
int udfLen) /* (Input) Length of UDF Name. */
{
int Index, newIndex = 0, needsCRC = false; /* index is shadowed */
int extIndex = 0, newExtIndex = 0, hasExt = false;
#if defined OS2 || defined WIN_95 || defined WIN_NT
int trailIndex = 0;
#endif
unsigned short valueCRC;
unicode_t current;
const char hexChar[] = "0123456789ABCDEF";
for (Index = 0; Index < udfLen; Index++) {
current = udfName[Index];
if (IsIllegal(current) || !UnicodeIsPrint(current)) {
needsCRC = true;
/* Replace Illegal and non-displayable chars with
* underscore.
*/
current = ILLEGAL_CHAR_MARK;
/* Skip any other illegal or non-displayable
* characters.
*/
while(Index+1 < udfLen && (IsIllegal(udfName[Index+1])
|| !UnicodeIsPrint(udfName[Index+1]))) {
Index++;
}
}
/* Record position of extension, if one is found. */
if (current == PERIOD && (udfLen - Index -1) <= EXT_SIZE) {
if (udfLen == Index + 1) {
/* A trailing period is NOT an extension. */
hasExt = false;
} else {
hasExt = true;
extIndex = Index;
newExtIndex = newIndex;
}
}
#if defined OS2 || defined WIN_95 || defined WIN_NT
/* Record position of last char which is NOT period or space. */
else if (current != PERIOD && current != SPACE) {
trailIndex = newIndex;
}
#endif
if (newIndex < MAXLEN) {
newName[newIndex++] = current;
} else {
needsCRC = true;
}
}
#if defined OS2 || defined WIN_95 || defined WIN_NT
/* For OS2, 95 & NT, truncate any trailing periods and\or spaces. */
if (trailIndex != newIndex - 1) {
newIndex = trailIndex + 1;
needsCRC = true;
hasExt = false; /* Trailing period does not make an
* extension. */
}
#endif
if (needsCRC) {
unicode_t ext[EXT_SIZE];
int localExtIndex = 0;
if (hasExt) {
int maxFilenameLen;
/* Translate extension, and store it in ext. */
for(Index = 0; Index<EXT_SIZE &&
extIndex + Index +1 < udfLen; Index++ ) {
current = udfName[extIndex + Index + 1];
if (IsIllegal(current) ||
!UnicodeIsPrint(current)) {
needsCRC = 1;
/* Replace Illegal and non-displayable
* chars with underscore.
*/
current = ILLEGAL_CHAR_MARK;
/* Skip any other illegal or
* non-displayable characters.
*/
while(Index + 1 < EXT_SIZE
&& (IsIllegal(udfName[extIndex +
Index + 2]) ||
!isprint(udfName[extIndex +
Index + 2]))) {
Index++;
}
}
ext[localExtIndex++] = current;
}
/* Truncate filename to leave room for extension and
* CRC.
*/
maxFilenameLen = ((MAXLEN - 5) - localExtIndex - 1);
if (newIndex > maxFilenameLen) {
newIndex = maxFilenameLen;
} else {
newIndex = newExtIndex;
}
} else if (newIndex > MAXLEN - 5) {
/*If no extension, make sure to leave room for CRC. */
newIndex = MAXLEN - 5;
}
newName[newIndex++] = CRC_MARK; /* Add mark for CRC. */
/*Calculate CRC from original filename from FileIdentifier. */
valueCRC = udf_unicode_cksum(udfName, udfLen);
/* Convert 16-bits of CRC to hex characters. */
newName[newIndex++] = hexChar[(valueCRC & 0xf000) >> 12];
newName[newIndex++] = hexChar[(valueCRC & 0x0f00) >> 8];
newName[newIndex++] = hexChar[(valueCRC & 0x00f0) >> 4];
newName[newIndex++] = hexChar[(valueCRC & 0x000f)];
/* Place a translated extension at end, if found. */
if (hasExt) {
newName[newIndex++] = PERIOD;
for (Index = 0;Index < localExtIndex ;Index++ ) {
newName[newIndex++] = ext[Index];
}
}
}
return(newIndex);
}
#if defined OS2 || defined WIN_95 || defined WIN_NT
/***********************************************************************
* Decides if a Unicode character matches one of a list
* of ASCII characters.
* Used by OS2 version of IsIllegal for readability, since all of the
* illegal characters above 0x0020 are in the ASCII subset of Unicode.
* Works very similarly to the standard C function strchr().
*
* RETURN VALUE
*
* Non-zero if the Unicode character is in the given ASCII string.
*/
int UnicodeInString(
unsigned char *string, /* (Input) String to search through. */
unicode_t ch) /* (Input) Unicode char to search for. */
{
int found = false;
while (*string != '\0' && found == false) {
/* These types should compare, since both are unsigned
* numbers. */
if (*string == ch) {
found = true;
}
string++;
}
return(found);
}
#endif /* OS2 */
/***********************************************************************
* Decides whether the given character is illegal for a given OS.
*
* RETURN VALUE
*
* Non-zero if char is illegal.
*/
int IsIllegal(unicode_t ch)
{
#ifdef MAC
/* Only illegal character on the MAC is the colon. */
if (ch == 0x003A) {
return(1);
} else {
return(0);
}
#elif defined UNIX
/* Illegal UNIX characters are NULL and slash. */
if (ch == 0x0000 || ch == 0x002F) {
return(1);
} else {
return(0);
}
#elif defined OS2 || defined WIN_95 || defined WIN_NT
/* Illegal char's for OS/2 according to WARP toolkit. */
if (ch < 0x0020 || UnicodeInString("\\/:*?\"<>|", ch)) {
return(1);
} else {
return(0);
}
#endif
}
/* #endif*/ /* NEEDS_ISPRINT */

44
sys/fs/udf/udf_osta.h Normal file
View file

@ -0,0 +1,44 @@
/* $NetBSD: udf_osta.h,v 1.4 2008/05/14 16:49:48 reinoud Exp $ */
/*
* Prototypes for the OSTA functions
*/
#ifndef _FS_UDF_OSTA_H_
#define _FS_UDF_OSTA_H_
#include <sys/types.h>
#ifndef _KERNEL
#include <stdbool.h>
#endif
#ifndef UNIX
#define UNIX
#endif
#ifndef MAXLEN
#define MAXLEN 255
#endif
/***********************************************************************
* The following two typedef's are to remove compiler dependancies.
* byte needs to be unsigned 8-bit, and unicode_t needs to be
* unsigned 16-bit.
*/
typedef uint16_t unicode_t;
typedef uint8_t byte;
int udf_UncompressUnicode(int, byte *, unicode_t *);
int udf_CompressUnicode(int, int, unicode_t *, byte *);
unsigned short udf_cksum(unsigned char *, int);
unsigned short udf_unicode_cksum(unsigned short *, int);
uint16_t udf_ea_cksum(uint8_t *data);
int UDFTransName(unicode_t *, unicode_t *, int);
int UnicodeLength(unicode_t *string);
#endif /* _FS_UDF_OSTA_H_ */

723
sys/fs/udf/udf_readwrite.c Normal file
View file

@ -0,0 +1,723 @@
/* $NetBSD: udf_readwrite.c,v 1.11 2011/06/12 03:35:55 rmind Exp $ */
/*
* Copyright (c) 2007, 2008 Reinoud Zandijk
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include <sys/cdefs.h>
#ifndef lint
__KERNEL_RCSID(0, "$NetBSD: udf_readwrite.c,v 1.11 2011/06/12 03:35:55 rmind Exp $");
#endif /* not lint */
#if defined(_KERNEL_OPT)
#include "opt_compat_netbsd.h"
#endif
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/sysctl.h>
#include <sys/namei.h>
#include <sys/proc.h>
#include <sys/kernel.h>
#include <sys/vnode.h>
#include <miscfs/genfs/genfs_node.h>
#include <sys/mount.h>
#include <sys/buf.h>
#include <sys/file.h>
#include <sys/device.h>
#include <sys/disklabel.h>
#include <sys/ioctl.h>
#include <sys/malloc.h>
#include <sys/dirent.h>
#include <sys/stat.h>
#include <sys/conf.h>
#include <sys/kauth.h>
#include <sys/kthread.h>
#include <dev/clock_subr.h>
#include <fs/udf/ecma167-udf.h>
#include <fs/udf/udf_mount.h>
#include "udf.h"
#include "udf_subr.h"
#include "udf_bswap.h"
#define VTOI(vnode) ((struct udf_node *) vnode->v_data)
/* --------------------------------------------------------------------- */
void
udf_fixup_fid_block(uint8_t *blob, int lb_size,
int rfix_pos, int max_rfix_pos, uint32_t lb_num)
{
struct fileid_desc *fid;
uint8_t *fid_pos;
int fid_len, found;
/* needs to be word aligned */
KASSERT(rfix_pos % 4 == 0);
/* first resync with the FID stream !!! */
found = 0;
while (rfix_pos + sizeof(struct desc_tag) <= max_rfix_pos) {
fid_pos = blob + rfix_pos;
fid = (struct fileid_desc *) fid_pos;
if (udf_rw16(fid->tag.id) == TAGID_FID) {
if (udf_check_tag((union dscrptr *) fid) == 0)
found = 1;
}
if (found)
break;
/* try next location; can only be 4 bytes aligned */
rfix_pos += 4;
}
/* walk over the fids */
fid_pos = blob + rfix_pos;
while (rfix_pos + sizeof(struct desc_tag) <= max_rfix_pos) {
fid = (struct fileid_desc *) fid_pos;
if (udf_rw16(fid->tag.id) != TAGID_FID) {
/* end of FID stream; end of directory or currupted */
break;
}
/* update sector number and recalculate checkum */
fid->tag.tag_loc = udf_rw32(lb_num);
udf_validate_tag_sum((union dscrptr *) fid);
/* if the FID crosses the memory, we're done! */
if (rfix_pos + UDF_FID_SIZE >= max_rfix_pos)
break;
fid_len = udf_fidsize(fid);
fid_pos += fid_len;
rfix_pos += fid_len;
}
}
void
udf_fixup_internal_extattr(uint8_t *blob, uint32_t lb_num)
{
struct desc_tag *tag;
struct file_entry *fe;
struct extfile_entry *efe;
struct extattrhdr_desc *eahdr;
int l_ea;
/* get information from fe/efe */
tag = (struct desc_tag *) blob;
switch (udf_rw16(tag->id)) {
case TAGID_FENTRY :
fe = (struct file_entry *) blob;
l_ea = udf_rw32(fe->l_ea);
eahdr = (struct extattrhdr_desc *) fe->data;
break;
case TAGID_EXTFENTRY :
efe = (struct extfile_entry *) blob;
l_ea = udf_rw32(efe->l_ea);
eahdr = (struct extattrhdr_desc *) efe->data;
break;
case TAGID_INDIRECTENTRY :
case TAGID_ALLOCEXTENT :
case TAGID_EXTATTR_HDR :
return;
default:
panic("%s: passed bad tag\n", __func__);
}
/* something recorded here? (why am i called?) */
if (l_ea == 0)
return;
#if 0
/* check extended attribute tag */
/* TODO XXX what to do when we encounter an error here? */
error = udf_check_tag(eahdr);
if (error)
return; /* for now */
if (udf_rw16(eahdr->tag.id) != TAGID_EXTATTR_HDR)
return; /* for now */
error = udf_check_tag_payload(eahdr, sizeof(struct extattrhdr_desc));
if (error)
return; /* for now */
#endif
DPRINTF(EXTATTR, ("node fixup: found %d bytes of extended attributes\n",
l_ea));
/* fixup eahdr tag */
eahdr->tag.tag_loc = udf_rw32(lb_num);
udf_validate_tag_and_crc_sums((union dscrptr *) eahdr);
}
void
udf_fixup_node_internals(struct udf_mount *ump, uint8_t *blob, int udf_c_type)
{
struct desc_tag *tag, *sbm_tag;
struct file_entry *fe;
struct extfile_entry *efe;
struct alloc_ext_entry *ext;
uint32_t lb_size, lb_num;
uint32_t intern_pos, max_intern_pos;
int icbflags, addr_type, file_type, intern, has_fids, has_sbm, l_ea;
lb_size = udf_rw32(ump->logical_vol->lb_size);
/* if its not a node we're done */
if (udf_c_type != UDF_C_NODE)
return;
/* NOTE this could also be done in write_internal */
/* start of a descriptor */
l_ea = 0;
has_fids = 0;
has_sbm = 0;
intern = 0;
file_type = 0;
max_intern_pos = intern_pos = lb_num = 0; /* shut up gcc! */
tag = (struct desc_tag *) blob;
switch (udf_rw16(tag->id)) {
case TAGID_FENTRY :
fe = (struct file_entry *) tag;
l_ea = udf_rw32(fe->l_ea);
icbflags = udf_rw16(fe->icbtag.flags);
addr_type = (icbflags & UDF_ICB_TAG_FLAGS_ALLOC_MASK);
file_type = fe->icbtag.file_type;
intern = (addr_type == UDF_ICB_INTERN_ALLOC);
intern_pos = UDF_FENTRY_SIZE + l_ea;
max_intern_pos = intern_pos + udf_rw64(fe->inf_len);
lb_num = udf_rw32(fe->tag.tag_loc);
break;
case TAGID_EXTFENTRY :
efe = (struct extfile_entry *) tag;
l_ea = udf_rw32(efe->l_ea);
icbflags = udf_rw16(efe->icbtag.flags);
addr_type = (icbflags & UDF_ICB_TAG_FLAGS_ALLOC_MASK);
file_type = efe->icbtag.file_type;
intern = (addr_type == UDF_ICB_INTERN_ALLOC);
intern_pos = UDF_EXTFENTRY_SIZE + l_ea;
max_intern_pos = intern_pos + udf_rw64(efe->inf_len);
lb_num = udf_rw32(efe->tag.tag_loc);
break;
case TAGID_INDIRECTENTRY :
case TAGID_EXTATTR_HDR :
break;
case TAGID_ALLOCEXTENT :
/* force crclen to 8 for UDF version < 2.01 */
ext = (struct alloc_ext_entry *) tag;
if (udf_rw16(ump->logvol_info->min_udf_readver) <= 0x200)
ext->tag.desc_crc_len = udf_rw16(8);
break;
default:
panic("%s: passed bad tag\n", __func__);
break;
}
/* determine what to fix if its internally recorded */
if (intern) {
has_fids = (file_type == UDF_ICB_FILETYPE_DIRECTORY) ||
(file_type == UDF_ICB_FILETYPE_STREAMDIR);
has_sbm = (file_type == UDF_ICB_FILETYPE_META_BITMAP);
}
/* fixup internal extended attributes if present */
if (l_ea)
udf_fixup_internal_extattr(blob, lb_num);
/* fixup fids lb numbers */
if (has_fids)
udf_fixup_fid_block(blob, lb_size, intern_pos,
max_intern_pos, lb_num);
/* fixup space bitmap descriptor */
if (has_sbm) {
sbm_tag = (struct desc_tag *) (blob + intern_pos);
sbm_tag->tag_loc = tag->tag_loc;
udf_validate_tag_and_crc_sums((uint8_t *) sbm_tag);
}
udf_validate_tag_and_crc_sums(blob);
}
/* --------------------------------------------------------------------- */
/*
* Set of generic descriptor readers and writers and their helper functions.
* Descriptors inside `logical space' i.e. inside logically mapped partitions
* can never be longer than one logical sector.
*
* NOTE that these functions *can* be used by the sheduler backends to read
* node descriptors too.
*
* For reading, the size of allocated piece is returned in multiple of sector
* size due to udf_calc_udf_malloc_size().
*/
/* SYNC reading of n blocks from specified sector */
int
udf_read_phys_sectors(struct udf_mount *ump, int what, void *blob,
uint32_t start, uint32_t sectors)
{
struct buf *buf, *nestbuf;
uint32_t buf_offset;
off_t lblkno, rblkno;
int sector_size = ump->discinfo.sector_size;
int blks = sector_size / DEV_BSIZE;
int piece;
int error;
DPRINTF(READ, ("udf_intbreadn() : sectors = %d, sector_size = %d\n",
sectors, sector_size));
buf = getiobuf(ump->devvp, true);
buf->b_flags = B_READ;
buf->b_cflags = BC_BUSY; /* needed? */
buf->b_iodone = NULL;
buf->b_data = blob;
buf->b_bcount = sectors * sector_size;
buf->b_resid = buf->b_bcount;
buf->b_bufsize = buf->b_bcount;
buf->b_private = NULL; /* not needed yet */
BIO_SETPRIO(buf, BPRIO_DEFAULT);
buf->b_lblkno = buf->b_blkno = buf->b_rawblkno = start * blks;
buf->b_proc = NULL;
error = 0;
buf_offset = 0;
rblkno = start;
lblkno = 0;
while ((sectors > 0) && (error == 0)) {
piece = MIN(MAXPHYS/sector_size, sectors);
DPRINTF(READ, ("read in %d + %d\n", (uint32_t) rblkno, piece));
nestbuf = getiobuf(NULL, true);
nestiobuf_setup(buf, nestbuf, buf_offset, piece * sector_size);
/* nestbuf is B_ASYNC */
/* identify this nestbuf */
nestbuf->b_lblkno = lblkno;
/* CD shedules on raw blkno */
nestbuf->b_blkno = rblkno * blks;
nestbuf->b_proc = NULL;
nestbuf->b_rawblkno = rblkno * blks;
nestbuf->b_udf_c_type = what;
udf_discstrat_queuebuf(ump, nestbuf);
lblkno += piece;
rblkno += piece;
buf_offset += piece * sector_size;
sectors -= piece;
}
error = biowait(buf);
putiobuf(buf);
return error;
}
/* synchronous generic descriptor read */
int
udf_read_phys_dscr(struct udf_mount *ump, uint32_t sector,
struct malloc_type *mtype, union dscrptr **dstp)
{
union dscrptr *dst, *new_dst;
uint8_t *pos;
int sectors, dscrlen;
int i, error, sector_size;
sector_size = ump->discinfo.sector_size;
*dstp = dst = NULL;
dscrlen = sector_size;
/* read initial piece */
dst = malloc(sector_size, mtype, M_WAITOK);
error = udf_read_phys_sectors(ump, UDF_C_DSCR, dst, sector, 1);
DPRINTFIF(DESCRIPTOR, error, ("read error (%d)\n", error));
if (!error) {
/* check if its a valid tag */
error = udf_check_tag(dst);
if (error) {
/* check if its an empty block */
pos = (uint8_t *) dst;
for (i = 0; i < sector_size; i++, pos++) {
if (*pos) break;
}
if (i == sector_size) {
/* return no error but with no dscrptr */
/* dispose first block */
free(dst, mtype);
return 0;
}
}
/* calculate descriptor size */
dscrlen = udf_tagsize(dst, sector_size);
}
DPRINTFIF(DESCRIPTOR, error, ("bad tag checksum\n"));
if (!error && (dscrlen > sector_size)) {
DPRINTF(DESCRIPTOR, ("multi block descriptor read\n"));
/*
* Read the rest of descriptor. Since it is only used at mount
* time its overdone to define and use a specific udf_intbreadn
* for this alone.
*/
new_dst = realloc(dst, dscrlen, mtype, M_WAITOK);
if (new_dst == NULL) {
free(dst, mtype);
return ENOMEM;
}
dst = new_dst;
sectors = (dscrlen + sector_size -1) / sector_size;
DPRINTF(DESCRIPTOR, ("dscrlen = %d (%d blk)\n", dscrlen, sectors));
pos = (uint8_t *) dst + sector_size;
error = udf_read_phys_sectors(ump, UDF_C_DSCR, pos,
sector + 1, sectors-1);
DPRINTFIF(DESCRIPTOR, error, ("read error on multi (%d)\n",
error));
}
if (!error) {
error = udf_check_tag_payload(dst, dscrlen);
DPRINTFIF(DESCRIPTOR, error, ("bad payload check sum\n"));
}
if (error && dst) {
free(dst, mtype);
dst = NULL;
}
*dstp = dst;
return error;
}
static void
udf_write_phys_buf(struct udf_mount *ump, int what, struct buf *buf)
{
struct buf *nestbuf;
uint32_t buf_offset;
off_t lblkno, rblkno;
int sector_size = ump->discinfo.sector_size;
int blks = sector_size / DEV_BSIZE;
uint32_t sectors;
int piece;
int error;
sectors = buf->b_bcount / sector_size;
DPRINTF(WRITE, ("udf_intbwriten() : sectors = %d, sector_size = %d\n",
sectors, sector_size));
/* don't forget to increase pending count for the bwrite itself */
/* panic("NO WRITING\n"); */
if (buf->b_vp) {
mutex_enter(buf->b_vp->v_interlock);
buf->b_vp->v_numoutput++;
mutex_exit(buf->b_vp->v_interlock);
}
error = 0;
buf_offset = 0;
rblkno = buf->b_blkno / blks;
lblkno = 0;
while ((sectors > 0) && (error == 0)) {
piece = MIN(MAXPHYS/sector_size, sectors);
DPRINTF(WRITE, ("write out %d + %d\n",
(uint32_t) rblkno, piece));
nestbuf = getiobuf(NULL, true);
nestiobuf_setup(buf, nestbuf, buf_offset, piece * sector_size);
/* nestbuf is B_ASYNC */
/* identify this nestbuf */
nestbuf->b_lblkno = lblkno;
/* CD shedules on raw blkno */
nestbuf->b_blkno = rblkno * blks;
nestbuf->b_proc = NULL;
nestbuf->b_rawblkno = rblkno * blks;
nestbuf->b_udf_c_type = what;
udf_discstrat_queuebuf(ump, nestbuf);
lblkno += piece;
rblkno += piece;
buf_offset += piece * sector_size;
sectors -= piece;
}
}
/* SYNC writing of n blocks from specified sector */
int
udf_write_phys_sectors(struct udf_mount *ump, int what, void *blob,
uint32_t start, uint32_t sectors)
{
struct vnode *vp;
struct buf *buf;
int sector_size = ump->discinfo.sector_size;
int blks = sector_size / DEV_BSIZE;
int error;
/* get transfer buffer */
vp = ump->devvp;
buf = getiobuf(vp, true);
buf->b_flags = B_WRITE;
buf->b_cflags = BC_BUSY; /* needed? */
buf->b_iodone = NULL;
buf->b_data = blob;
buf->b_bcount = sectors * sector_size;
buf->b_resid = buf->b_bcount;
buf->b_bufsize = buf->b_bcount;
buf->b_private = NULL; /* not needed yet */
BIO_SETPRIO(buf, BPRIO_DEFAULT);
buf->b_lblkno = buf->b_blkno = buf->b_rawblkno = start * blks;
buf->b_proc = NULL;
/* do the write, wait and return error */
udf_write_phys_buf(ump, what, buf);
error = biowait(buf);
putiobuf(buf);
return error;
}
/* synchronous generic descriptor write */
int
udf_write_phys_dscr_sync(struct udf_mount *ump, struct udf_node *udf_node, int what,
union dscrptr *dscr, uint32_t sector, uint32_t logsector)
{
struct vnode *vp;
struct buf *buf;
int sector_size = ump->discinfo.sector_size;
int blks = sector_size / DEV_BSIZE;
int dscrlen;
int error;
/* set sector number in the descriptor and validate */
dscr->tag.tag_loc = udf_rw32(logsector);
udf_validate_tag_and_crc_sums(dscr);
/* calculate descriptor size */
dscrlen = udf_tagsize(dscr, sector_size);
/* get transfer buffer */
vp = udf_node ? udf_node->vnode : ump->devvp;
buf = getiobuf(vp, true);
buf->b_flags = B_WRITE;
buf->b_cflags = BC_BUSY; /* needed? */
buf->b_iodone = NULL;
buf->b_data = (void *) dscr;
buf->b_bcount = dscrlen;
buf->b_resid = buf->b_bcount;
buf->b_bufsize = buf->b_bcount;
buf->b_private = NULL; /* not needed yet */
BIO_SETPRIO(buf, BPRIO_DEFAULT);
buf->b_lblkno = buf->b_blkno = buf->b_rawblkno = sector * blks;
buf->b_proc = NULL;
/* do the write, wait and return error */
udf_write_phys_buf(ump, what, buf);
error = biowait(buf);
putiobuf(buf);
return error;
}
/* asynchronous generic descriptor write */
int
udf_write_phys_dscr_async(struct udf_mount *ump, struct udf_node *udf_node,
int what, union dscrptr *dscr,
uint32_t sector, uint32_t logsector,
void (*dscrwr_callback)(struct buf *))
{
struct vnode *vp;
struct buf *buf;
int dscrlen;
int sector_size = ump->discinfo.sector_size;
int blks = sector_size / DEV_BSIZE;
KASSERT(dscrwr_callback);
DPRINTF(NODE, ("udf_write_phys_dscr_async() called\n"));
/* set sector number in the descriptor and validate */
dscr->tag.tag_loc = udf_rw32(logsector);
udf_validate_tag_and_crc_sums(dscr);
/* calculate descriptor size */
dscrlen = udf_tagsize(dscr, sector_size);
/* get transfer buffer */
vp = udf_node ? udf_node->vnode : ump->devvp;
buf = getiobuf(vp, true);
buf->b_flags = B_WRITE; // | B_ASYNC;
buf->b_cflags = BC_BUSY;
buf->b_iodone = dscrwr_callback;
buf->b_data = dscr;
buf->b_bcount = dscrlen;
buf->b_resid = buf->b_bcount;
buf->b_bufsize = buf->b_bcount;
buf->b_private = NULL; /* not needed yet */
BIO_SETPRIO(buf, BPRIO_DEFAULT);
buf->b_lblkno = buf->b_blkno = buf->b_rawblkno = sector * blks;
buf->b_proc = NULL;
/* do the write and return no error */
udf_write_phys_buf(ump, what, buf);
return 0;
}
/* --------------------------------------------------------------------- */
/* disc strategy dispatchers */
int
udf_create_logvol_dscr(struct udf_mount *ump, struct udf_node *udf_node, struct long_ad *icb,
union dscrptr **dscrptr)
{
struct udf_strategy *strategy = ump->strategy;
struct udf_strat_args args;
int error;
KASSERT(strategy);
args.ump = ump;
args.udf_node = udf_node;
args.icb = icb;
args.dscr = NULL;
error = (strategy->create_logvol_dscr)(&args);
*dscrptr = args.dscr;
return error;
}
void
udf_free_logvol_dscr(struct udf_mount *ump, struct long_ad *icb,
void *dscr)
{
struct udf_strategy *strategy = ump->strategy;
struct udf_strat_args args;
KASSERT(strategy);
args.ump = ump;
args.icb = icb;
args.dscr = dscr;
(strategy->free_logvol_dscr)(&args);
}
int
udf_read_logvol_dscr(struct udf_mount *ump, struct long_ad *icb,
union dscrptr **dscrptr)
{
struct udf_strategy *strategy = ump->strategy;
struct udf_strat_args args;
int error;
KASSERT(strategy);
args.ump = ump;
args.icb = icb;
args.dscr = NULL;
error = (strategy->read_logvol_dscr)(&args);
*dscrptr = args.dscr;
return error;
}
int
udf_write_logvol_dscr(struct udf_node *udf_node, union dscrptr *dscr,
struct long_ad *icb, int waitfor)
{
struct udf_strategy *strategy = udf_node->ump->strategy;
struct udf_strat_args args;
int error;
KASSERT(strategy);
args.ump = udf_node->ump;
args.udf_node = udf_node;
args.icb = icb;
args.dscr = dscr;
args.waitfor = waitfor;
error = (strategy->write_logvol_dscr)(&args);
return error;
}
void
udf_discstrat_queuebuf(struct udf_mount *ump, struct buf *nestbuf)
{
struct udf_strategy *strategy = ump->strategy;
struct udf_strat_args args;
KASSERT(strategy);
args.ump = ump;
args.nestbuf = nestbuf;
(strategy->queuebuf)(&args);
}
void
udf_discstrat_init(struct udf_mount *ump)
{
struct udf_strategy *strategy = ump->strategy;
struct udf_strat_args args;
KASSERT(strategy);
args.ump = ump;
(strategy->discstrat_init)(&args);
}
void udf_discstrat_finish(struct udf_mount *ump)
{
struct udf_strategy *strategy = ump->strategy;
struct udf_strat_args args;
/* strategy might not have been set, so ignore if not set */
if (strategy) {
args.ump = ump;
(strategy->discstrat_finish)(&args);
}
}
/* --------------------------------------------------------------------- */

669
sys/fs/udf/udf_rename.c Normal file
View file

@ -0,0 +1,669 @@
/* $NetBSD: udf_rename.c,v 1.10 2013/07/16 10:49:36 reinoud Exp $ */
/*
* Copyright (c) 2013 Reinoud Zandijk
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Comments and trivial code from the reference implementation in tmpfs.
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: udf_rename.c,v 1.10 2013/07/16 10:49:36 reinoud Exp $");
#include <sys/param.h>
#include <sys/errno.h>
#include <sys/kauth.h>
#include <sys/mount.h>
#include <sys/namei.h>
#include <sys/stat.h>
#include <sys/malloc.h>
#include <sys/dirent.h>
#include <sys/vnode.h>
#include <sys/vnode_if.h>
#include <miscfs/genfs/genfs.h>
#include <fs/udf/ecma167-udf.h>
#include <fs/udf/udf_mount.h>
#include <sys/dirhash.h>
#include "udf.h"
#include "udf_subr.h"
#include "udf_bswap.h"
/* forwards */
static int udf_sane_rename( struct vnode *, struct componentname *,
struct vnode *, struct componentname *,
kauth_cred_t, bool);
static bool udf_rmdired_p(struct vnode *);
static int udf_gro_lock_directory(struct mount *, struct vnode *);
static const struct genfs_rename_ops udf_genfs_rename_ops;
#define VTOI(vnode) ((struct udf_node *) (vnode)->v_data)
/*
* udf_sane_rename: The hairiest vop, with the saner API.
*
* Arguments:
*
* . fdvp (from directory vnode),
* . fcnp (from component name),
* . tdvp (to directory vnode),
* . tcnp (to component name),
* . cred (credentials structure), and
* . posixly_correct (flag for behaviour if target & source link same file).
*
* fdvp and tdvp may be the same, and must be referenced and unlocked.
*/
static int
udf_sane_rename( struct vnode *fdvp, struct componentname *fcnp,
struct vnode *tdvp, struct componentname *tcnp,
kauth_cred_t cred, bool posixly_correct)
{
DPRINTF(CALL, ("udf_sane_rename '%s' -> '%s'\n",
fcnp->cn_nameptr, tcnp->cn_nameptr));
return genfs_sane_rename(&udf_genfs_rename_ops,
fdvp, fcnp, NULL, tdvp, tcnp, NULL,
cred, posixly_correct);
}
/*
* udf_rename: the hairiest vop, with the insanest API. Pass to
* genfs_insane_rename immediately.
*/
int
udf_rename(void *v)
{
struct vop_rename_args /* {
struct vnode *a_fdvp;
struct vnode *a_fvp;
struct componentname *a_fcnp;
struct vnode *a_tdvp;
struct vnode *a_tvp;
struct componentname *a_tcnp;
} */ *ap = v;
DPRINTF(CALL, ("udf_rename called\n"));
return genfs_insane_rename(ap, &udf_sane_rename);
}
/*
* udf_gro_directory_empty_p: return true if the directory vp is empty. dvp is
* its parent.
*
* vp and dvp must be locked and referenced.
*/
static bool
udf_gro_directory_empty_p(struct mount *mp, kauth_cred_t cred,
struct vnode *vp, struct vnode *dvp)
{
struct udf_node *udf_node = VTOI(vp);
int error, isempty;
KASSERT(mp != NULL);
KASSERT(vp != NULL);
KASSERT(dvp != NULL);
KASSERT(vp != dvp);
KASSERT(vp->v_mount == mp);
KASSERT(dvp->v_mount == mp);
KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE);
KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE);
DPRINTF(CALL, ("udf_gro_directory_empty_p called\n"));
/* make sure our `leaf' node's hash is populated */
dirhash_get(&udf_node->dir_hash);
error = udf_dirhash_fill(udf_node);
if (error) {
dirhash_put(udf_node->dir_hash);
/* VERY unlikely, answer its not empty */
return 0;
}
/* check to see if the directory is empty */
isempty = dirhash_dir_isempty(udf_node->dir_hash);
dirhash_put(udf_node->dir_hash);
return isempty;
}
/*
* udf_gro_rename_check_possible: check whether a rename is possible
* independent of credentials.
*/
static int
udf_gro_rename_check_possible(struct mount *mp,
struct vnode *fdvp, struct vnode *fvp,
struct vnode *tdvp, struct vnode *tvp)
{
(void)mp;
KASSERT(mp != NULL);
KASSERT(fdvp != NULL);
KASSERT(fvp != NULL);
KASSERT(tdvp != NULL);
KASSERT(fdvp != fvp);
KASSERT(fdvp != tvp);
KASSERT(tdvp != fvp);
KASSERT(tdvp != tvp);
KASSERT(fvp != tvp);
KASSERT(fdvp->v_type == VDIR);
KASSERT(tdvp->v_type == VDIR);
KASSERT(fdvp->v_mount == mp);
KASSERT(fvp->v_mount == mp);
KASSERT(tdvp->v_mount == mp);
KASSERT((tvp == NULL) || (tvp->v_mount == mp));
KASSERT(VOP_ISLOCKED(fdvp) == LK_EXCLUSIVE);
KASSERT(VOP_ISLOCKED(fvp) == LK_EXCLUSIVE);
KASSERT(VOP_ISLOCKED(tdvp) == LK_EXCLUSIVE);
KASSERT((tvp == NULL) || (VOP_ISLOCKED(tvp) == LK_EXCLUSIVE));
DPRINTF(CALL, ("udf_gro_rename_check_possible called\n"));
/* flags not implemented since they are not defined (yet) in UDF */
return 0;
}
/*
* udf_gro_rename_check_permitted: check whether a rename is permitted given
* our credentials.
*/
static int
udf_gro_rename_check_permitted(struct mount *mp, kauth_cred_t cred,
struct vnode *fdvp, struct vnode *fvp,
struct vnode *tdvp, struct vnode *tvp)
{
struct udf_node *fdir_node = VTOI(fdvp);
struct udf_node *tdir_node = VTOI(tdvp);
struct udf_node *f_node = VTOI(fvp);
struct udf_node *t_node = (tvp? VTOI(tvp): NULL);
mode_t fdmode, tdmode;
uid_t fduid, tduid, fuid, tuid;
gid_t gdummy;
(void)mp;
KASSERT(mp != NULL);
KASSERT(fdvp != NULL);
KASSERT(fvp != NULL);
KASSERT(tdvp != NULL);
KASSERT(fdvp != fvp);
KASSERT(fdvp != tvp);
KASSERT(tdvp != fvp);
KASSERT(tdvp != tvp);
KASSERT(fvp != tvp);
KASSERT(fdvp->v_type == VDIR);
KASSERT(tdvp->v_type == VDIR);
KASSERT(fdvp->v_mount == mp);
KASSERT(fvp->v_mount == mp);
KASSERT(tdvp->v_mount == mp);
KASSERT((tvp == NULL) || (tvp->v_mount == mp));
KASSERT(VOP_ISLOCKED(fdvp) == LK_EXCLUSIVE);
KASSERT(VOP_ISLOCKED(fvp) == LK_EXCLUSIVE);
KASSERT(VOP_ISLOCKED(tdvp) == LK_EXCLUSIVE);
KASSERT((tvp == NULL) || (VOP_ISLOCKED(tvp) == LK_EXCLUSIVE));
DPRINTF(CALL, ("udf_gro_rename_check_permitted called\n"));
fdmode = udf_getaccessmode(fdir_node);
tdmode = udf_getaccessmode(tdir_node);
udf_getownership(fdir_node, &fduid, &gdummy);
udf_getownership(tdir_node, &tduid, &gdummy);
udf_getownership(f_node, &fuid, &gdummy);
tuid = 0;
if (t_node)
udf_getownership(t_node, &tuid, &gdummy);
return genfs_ufslike_rename_check_permitted(cred,
fdvp, fdmode, fduid,
fvp, fuid,
tdvp, tdmode, tduid,
tvp, tuid);
}
/*
* udf_gro_remove_check_possible: check whether a remove is possible
* independent of credentials.
*
* XXX could check for special attributes?
*/
static int
udf_gro_remove_check_possible(struct mount *mp,
struct vnode *dvp, struct vnode *vp)
{
(void)mp;
KASSERT(mp != NULL);
KASSERT(dvp != NULL);
KASSERT(vp != NULL);
KASSERT(dvp != vp);
KASSERT(dvp->v_type == VDIR);
KASSERT(vp->v_type != VDIR);
KASSERT(dvp->v_mount == mp);
KASSERT(vp->v_mount == mp);
KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE);
KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE);
DPRINTF(CALL, ("udf_gro_remove_check_possible called\n"));
/* flags not implemented since they are not defined (yet) in UDF */
return 0;
}
/*
* udf_gro_remove_check_permitted: check whether a remove is permitted given
* our credentials.
*/
static int
udf_gro_remove_check_permitted(struct mount *mp, kauth_cred_t cred,
struct vnode *dvp, struct vnode *vp)
{
struct udf_node *dir_node = VTOI(dvp);
struct udf_node *udf_node = VTOI(vp);
mode_t dmode;
uid_t duid, uid;
gid_t gdummy;
(void)mp;
KASSERT(mp != NULL);
KASSERT(dvp != NULL);
KASSERT(vp != NULL);
KASSERT(dvp != vp);
KASSERT(dvp->v_type == VDIR);
KASSERT(vp->v_type != VDIR);
KASSERT(dvp->v_mount == mp);
KASSERT(vp->v_mount == mp);
KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE);
KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE);
DPRINTF(CALL, ("udf_gro_remove_check_permitted called\n"));
dmode = udf_getaccessmode(dir_node);
udf_getownership(dir_node, &duid, &gdummy);
udf_getownership(udf_node, &uid, &gdummy);
return genfs_ufslike_remove_check_permitted(cred,
dvp, dmode, duid,
vp, uid);
}
/*
* udf_gro_rename: actually perform the rename operation.
*/
static int
udf_gro_rename(struct mount *mp, kauth_cred_t cred,
struct vnode *fdvp, struct componentname *fcnp,
void *fde, struct vnode *fvp,
struct vnode *tdvp, struct componentname *tcnp,
void *tde, struct vnode *tvp)
{
struct udf_node *fnode, *fdnode, *tnode, *tdnode;
struct vattr fvap;
int error;
(void)cred;
KASSERT(mp != NULL);
KASSERT(fdvp != NULL);
KASSERT(fcnp != NULL);
KASSERT(fvp != NULL);
KASSERT(tdvp != NULL);
KASSERT(tcnp != NULL);
KASSERT(fdvp != fvp);
KASSERT(fdvp != tvp);
KASSERT(tdvp != fvp);
KASSERT(tdvp != tvp);
KASSERT(fvp != tvp);
KASSERT(fdvp->v_mount == mp);
KASSERT(fvp->v_mount == mp);
KASSERT(tdvp->v_mount == mp);
KASSERT((tvp == NULL) || (tvp->v_mount == mp));
KASSERT(VOP_ISLOCKED(fdvp) == LK_EXCLUSIVE);
KASSERT(VOP_ISLOCKED(fvp) == LK_EXCLUSIVE);
KASSERT(VOP_ISLOCKED(tdvp) == LK_EXCLUSIVE);
KASSERT((tvp == NULL) || (VOP_ISLOCKED(tvp) == LK_EXCLUSIVE));
DPRINTF(CALL, ("udf_gro_rename called\n"));
DPRINTF(NODE, ("udf_gro_rename called : %s -> %s\n",
fcnp->cn_nameptr, tcnp->cn_nameptr));
fnode = VTOI(fvp);
fdnode = VTOI(fdvp);
tnode = (tvp == NULL) ? NULL : VTOI(tvp);
tdnode = VTOI(tdvp);
/* get attribute information */
error = VOP_GETATTR(fvp, &fvap, NULL);
if (error)
return error;
/* remove existing entry if present */
if (tvp)
udf_dir_detach(tdnode->ump, tdnode, tnode, tcnp);
/* create new directory entry for the node */
error = udf_dir_attach(tdnode->ump, tdnode, fnode, &fvap, tcnp);
if (error)
return error;
/* unlink old directory entry for the node, if failing, unattach new */
error = udf_dir_detach(tdnode->ump, fdnode, fnode, fcnp);
if (error)
goto rollback_attach;
if ((fdnode != tdnode) && (fvp->v_type == VDIR)) {
/* update fnode's '..' entry */
error = udf_dir_update_rootentry(fnode->ump, fnode, tdnode);
if (error)
goto rollback;
}
VN_KNOTE(fvp, NOTE_RENAME);
genfs_rename_cache_purge(fdvp, fvp, tdvp, tvp);
return 0;
rollback:
/* 'try' to recover from this situation */
udf_dir_attach(tdnode->ump, fdnode, fnode, &fvap, fcnp);
rollback_attach:
udf_dir_detach(tdnode->ump, tdnode, fnode, tcnp);
return error;
}
/*
* udf_gro_remove: rename an object over another link to itself, effectively
* removing just the original link.
*/
static int
udf_gro_remove(struct mount *mp, kauth_cred_t cred,
struct vnode *dvp, struct componentname *cnp, void *de, struct vnode *vp)
{
struct udf_node *dir_node, *udf_node;
KASSERT(mp != NULL);
KASSERT(dvp != NULL);
KASSERT(cnp != NULL);
KASSERT(vp != NULL);
KASSERT(dvp != vp);
KASSERT(dvp->v_mount == mp);
KASSERT(vp->v_mount == mp);
KASSERT(dvp->v_type == VDIR);
KASSERT(vp->v_type != VDIR);
KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE);
KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE);
DPRINTF(CALL, ("udf_gro_remove called\n"));
dir_node = VTOI(dvp);
udf_node = VTOI(vp);
udf_dir_detach(dir_node->ump, dir_node, udf_node, cnp);
return 0;
}
/*
* udf_gro_lookup: look up and save the lookup results.
*/
static int
udf_gro_lookup(struct mount *mp, struct vnode *dvp,
struct componentname *cnp, void *de_ret, struct vnode **vp_ret)
{
struct udf_node *dir_node, *res_node;
struct long_ad icb_loc;
const char *name;
int namelen, error;
int found;
(void)mp;
KASSERT(mp != NULL);
KASSERT(dvp != NULL);
KASSERT(cnp != NULL);
KASSERT(vp_ret != NULL);
KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE);
dir_node = VTOI(dvp);
DPRINTF(CALL, ("udf_gro_lookup called\n"));
/* lookup filename in the directory; location icb_loc */
name = cnp->cn_nameptr;
namelen = cnp->cn_namelen;
error = udf_lookup_name_in_dir(dvp, name, namelen,
&icb_loc, &found);
if (error)
return error;
if (!found)
return ENOENT;
DPRINTF(LOOKUP, ("udf_gro_lookup found '%s'\n", name));
error = udf_get_node(dir_node->ump, &icb_loc, &res_node);
if (error)
return error;
*vp_ret = res_node->vnode;
VOP_UNLOCK(res_node->vnode);
return 0;
}
/*
* udf_rmdired_p: check whether the directory vp has been rmdired.
*
* vp must be locked and referenced.
*/
static bool
udf_rmdired_p(struct vnode *vp)
{
DPRINTF(CALL, ("udf_rmdired_p called\n"));
KASSERT(vp != NULL);
KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE);
KASSERT(vp->v_type == VDIR);
return (VTOI(vp)->i_flags & IN_DELETED);
}
/*
* udf_gro_genealogy: analyze the genealogy of the source and target
* directories.
*/
static int
udf_gro_genealogy(struct mount *mp, kauth_cred_t cred,
struct vnode *fdvp, struct vnode *tdvp,
struct vnode **intermediate_node_ret)
{
struct udf_mount *ump;
struct udf_node *parent_node;
struct vnode *vp, *dvp;
struct long_ad parent_loc;
const char *name;
int namelen;
int error, found;
(void)cred;
KASSERT(mp != NULL);
KASSERT(fdvp != NULL);
KASSERT(tdvp != NULL);
KASSERT(fdvp != tdvp);
KASSERT(intermediate_node_ret != NULL);
KASSERT(fdvp->v_mount == mp);
KASSERT(tdvp->v_mount == mp);
KASSERT(fdvp->v_type == VDIR);
KASSERT(tdvp->v_type == VDIR);
DPRINTF(CALL, ("udf_gro_genealogy called\n"));
/*
* We need to provisionally lock tdvp to keep rmdir from deleting it
* -- or any ancestor -- at an inopportune moment.
*
* XXX WHY is this not in genfs's rename? XXX
*/
error = udf_gro_lock_directory(mp, tdvp);
if (error)
return error;
name = "..";
namelen = 2;
error = 0;
ump = VTOI(tdvp)->ump;
/* if nodes are equal, it is no use looking */
KASSERT(udf_compare_icb(&VTOI(fdvp)->loc, &VTOI(tdvp)->loc) != 0);
/* start at destination vnode and walk up the tree */
vp = tdvp;
vref(vp);
for (;;) {
KASSERT(vp != NULL);
KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE);
KASSERT(vp->v_mount == mp);
KASSERT(vp->v_type == VDIR);
KASSERT(!udf_rmdired_p(vp));
DPRINTF(NODE, ("udf_gro_genealogy : "
"fdvp %p, looking at vp %p\n",
fdvp, vp));
/* sanity check */
if (vp->v_type != VDIR) {
vput(vp);
return ENOTDIR;
}
/* go down one level */
error = udf_lookup_name_in_dir(vp, name, namelen,
&parent_loc, &found);
DPRINTF(NODE, ("\tlookup of parent '..' resulted in error %d, "
"found %d\n", error, found));
if (!found)
error = ENOENT;
if (error) {
vput(vp);
return error;
}
/* did we encounter the root node? i.e. loop back */
if (udf_compare_icb(&parent_loc, &VTOI(vp)->loc) == 0) {
DPRINTF(NODE, ("ROOT found!\n"));
vput(vp);
*intermediate_node_ret = NULL;
return 0;
}
/* Did we find that fdvp is an ancestor of tdvp? */
if (udf_compare_icb(&parent_loc, &VTOI(fdvp)->loc) == 0) {
DPRINTF(NODE, ("fdvp is ancestor of tdvp\n"));
*intermediate_node_ret = vp;
VOP_UNLOCK(vp);
return 0;
}
/*
* Unlock vp so that we can lock the parent, but keep child vp
* referenced until after we have found the parent, so that
* parent_node will not be recycled.
*/
DPRINTF(NODE, ("\tgetting the parent node\n"));
VOP_UNLOCK(vp);
error = udf_get_node(ump, &parent_loc, &parent_node);
vrele(vp);
if (error)
return error;
dvp = parent_node->vnode;
/* switch */
KASSERT(dvp != NULL);
KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE);
vp = dvp;
/* sanity check */
if (vp->v_type != VDIR) {
/*
* Odd, but can happen if we loose the race and the
* '..' node has been recycled.
*/
vput(vp);
return ENOTDIR;
}
if (udf_rmdired_p(vp)) {
vput(vp);
return ENOENT;
}
}
}
/*
* udf_gro_lock_directory: lock the directory vp, but fail if it has been
* rmdir'd.
*/
static int
udf_gro_lock_directory(struct mount *mp, struct vnode *vp)
{
(void)mp;
KASSERT(mp != NULL);
KASSERT(vp != NULL);
KASSERT(vp->v_mount == mp);
DPRINTF(CALL, ("udf_gro_lock_directory called\n"));
DPRINTF(LOCKING, ("udf_gro_lock_directory called\n"));
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
if (udf_rmdired_p(vp)) {
VOP_UNLOCK(vp);
return ENOENT;
}
return 0;
}
static const struct genfs_rename_ops udf_genfs_rename_ops = {
.gro_directory_empty_p = udf_gro_directory_empty_p,
.gro_rename_check_possible = udf_gro_rename_check_possible,
.gro_rename_check_permitted = udf_gro_rename_check_permitted,
.gro_remove_check_possible = udf_gro_remove_check_possible,
.gro_remove_check_permitted = udf_gro_remove_check_permitted,
.gro_rename = udf_gro_rename,
.gro_remove = udf_gro_remove,
.gro_lookup = udf_gro_lookup,
.gro_genealogy = udf_gro_genealogy,
.gro_lock_directory = udf_gro_lock_directory,
};

View file

@ -0,0 +1,145 @@
/* $NetBSD: udf_strat_bootstrap.c,v 1.3 2008/12/16 16:18:25 pooka Exp $ */
/*
* Copyright (c) 2006, 2008 Reinoud Zandijk
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include <sys/cdefs.h>
#ifndef lint
__KERNEL_RCSID(0, "$NetBSD: udf_strat_bootstrap.c,v 1.3 2008/12/16 16:18:25 pooka Exp $");
#endif /* not lint */
#if defined(_KERNEL_OPT)
#include "opt_compat_netbsd.h"
#endif
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/sysctl.h>
#include <sys/namei.h>
#include <sys/proc.h>
#include <sys/kernel.h>
#include <sys/vnode.h>
#include <miscfs/genfs/genfs_node.h>
#include <sys/mount.h>
#include <sys/buf.h>
#include <sys/file.h>
#include <sys/device.h>
#include <sys/disklabel.h>
#include <sys/ioctl.h>
#include <sys/malloc.h>
#include <sys/dirent.h>
#include <sys/stat.h>
#include <sys/conf.h>
#include <sys/kauth.h>
#include <sys/kthread.h>
#include <dev/clock_subr.h>
#include <fs/udf/ecma167-udf.h>
#include <fs/udf/udf_mount.h>
#include "udf.h"
#include "udf_subr.h"
#include "udf_bswap.h"
#define VTOI(vnode) ((struct udf_node *) vnode->v_data)
#define PRIV(ump) ((struct strat_private *) ump->strategy_private)
/* --------------------------------------------------------------------- */
static int
udf_create_logvol_dscr_bootstrap(struct udf_strat_args *args)
{
panic("udf_create_logvol_dscr_bootstrap: not possible\n");
return 0;
}
static void
udf_free_logvol_dscr_bootstrap(struct udf_strat_args *args)
{
panic("udf_free_logvol_dscr_bootstrap: no node descriptor reading\n");
}
static int
udf_read_logvol_dscr_bootstrap(struct udf_strat_args *args)
{
panic("udf_read_logvol_dscr_bootstrap: no node descriptor reading\n");
return 0;
}
static int
udf_write_logvol_dscr_bootstrap(struct udf_strat_args *args)
{
panic("udf_write_logvol_dscr_bootstrap: no writing\n");
}
/* --------------------------------------------------------------------- */
static void
udf_queuebuf_bootstrap(struct udf_strat_args *args)
{
struct udf_mount *ump = args->ump;
struct buf *buf = args->nestbuf;
KASSERT(ump);
KASSERT(buf);
KASSERT(buf->b_iodone == nestiobuf_iodone);
KASSERT(buf->b_flags & B_READ);
VOP_STRATEGY(ump->devvp, buf);
}
static void
udf_discstrat_init_bootstrap(struct udf_strat_args *args)
{
/* empty */
}
static void
udf_discstrat_finish_bootstrap(struct udf_strat_args *args)
{
/* empty */
}
/* --------------------------------------------------------------------- */
struct udf_strategy udf_strat_bootstrap =
{
udf_create_logvol_dscr_bootstrap,
udf_free_logvol_dscr_bootstrap,
udf_read_logvol_dscr_bootstrap,
udf_write_logvol_dscr_bootstrap,
udf_queuebuf_bootstrap,
udf_discstrat_init_bootstrap,
udf_discstrat_finish_bootstrap
};

View file

@ -0,0 +1,454 @@
/* $NetBSD: udf_strat_direct.c,v 1.12 2013/10/30 08:41:38 mrg Exp $ */
/*
* Copyright (c) 2006, 2008 Reinoud Zandijk
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include <sys/cdefs.h>
#ifndef lint
__KERNEL_RCSID(0, "$NetBSD: udf_strat_direct.c,v 1.12 2013/10/30 08:41:38 mrg Exp $");
#endif /* not lint */
#if defined(_KERNEL_OPT)
#include "opt_compat_netbsd.h"
#endif
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/sysctl.h>
#include <sys/namei.h>
#include <sys/proc.h>
#include <sys/kernel.h>
#include <sys/vnode.h>
#include <miscfs/genfs/genfs_node.h>
#include <sys/mount.h>
#include <sys/buf.h>
#include <sys/file.h>
#include <sys/device.h>
#include <sys/disklabel.h>
#include <sys/ioctl.h>
#include <sys/malloc.h>
#include <sys/dirent.h>
#include <sys/stat.h>
#include <sys/conf.h>
#include <sys/kauth.h>
#include <sys/kthread.h>
#include <dev/clock_subr.h>
#include <fs/udf/ecma167-udf.h>
#include <fs/udf/udf_mount.h>
#include "udf.h"
#include "udf_subr.h"
#include "udf_bswap.h"
#define VTOI(vnode) ((struct udf_node *) vnode->v_data)
#define PRIV(ump) ((struct strat_private *) ump->strategy_private)
/* --------------------------------------------------------------------- */
/* BUFQ's */
#define UDF_SHED_MAX 3
#define UDF_SHED_READING 0
#define UDF_SHED_WRITING 1
#define UDF_SHED_SEQWRITING 2
struct strat_private {
struct pool desc_pool; /* node descriptors */
};
/* --------------------------------------------------------------------- */
static void
udf_wr_nodedscr_callback(struct buf *buf)
{
struct udf_node *udf_node;
KASSERT(buf);
KASSERT(buf->b_data);
/* called when write action is done */
DPRINTF(WRITE, ("udf_wr_nodedscr_callback(): node written out\n"));
udf_node = VTOI(buf->b_vp);
if (udf_node == NULL) {
putiobuf(buf);
printf("udf_wr_node_callback: NULL node?\n");
return;
}
/* XXX right flags to mark dirty again on error? */
if (buf->b_error) {
/* write error on `defect free' media??? how to solve? */
/* XXX lookup UDF standard for unallocatable space */
udf_node->i_flags |= IN_MODIFIED | IN_ACCESSED;
}
/* decrement outstanding_nodedscr */
KASSERT(udf_node->outstanding_nodedscr >= 1);
udf_node->outstanding_nodedscr--;
if (udf_node->outstanding_nodedscr == 0) {
/* unlock the node */
UDF_UNLOCK_NODE(udf_node, 0);
wakeup(&udf_node->outstanding_nodedscr);
}
/* unreference the vnode so it can be recycled */
holdrele(udf_node->vnode);
putiobuf(buf);
}
/* --------------------------------------------------------------------- */
static int
udf_getblank_nodedscr_direct(struct udf_strat_args *args)
{
union dscrptr **dscrptr = &args->dscr;
struct udf_mount *ump = args->ump;
struct strat_private *priv = PRIV(ump);
uint32_t lb_size;
lb_size = udf_rw32(ump->logical_vol->lb_size);
*dscrptr = pool_get(&priv->desc_pool, PR_WAITOK);
memset(*dscrptr, 0, lb_size);
return 0;
}
static void
udf_free_nodedscr_direct(struct udf_strat_args *args)
{
union dscrptr *dscr = args->dscr;
struct udf_mount *ump = args->ump;
struct strat_private *priv = PRIV(ump);
pool_put(&priv->desc_pool, dscr);
}
static int
udf_read_nodedscr_direct(struct udf_strat_args *args)
{
union dscrptr **dscrptr = &args->dscr;
union dscrptr *tmpdscr;
struct udf_mount *ump = args->ump;
struct long_ad *icb = args->icb;
struct strat_private *priv = PRIV(ump);
uint32_t lb_size;
uint32_t sector, dummy;
int error;
lb_size = udf_rw32(ump->logical_vol->lb_size);
error = udf_translate_vtop(ump, icb, &sector, &dummy);
if (error)
return error;
/* try to read in fe/efe */
error = udf_read_phys_dscr(ump, sector, M_UDFTEMP, &tmpdscr);
if (error)
return error;
*dscrptr = pool_get(&priv->desc_pool, PR_WAITOK);
memcpy(*dscrptr, tmpdscr, lb_size);
free(tmpdscr, M_UDFTEMP);
return 0;
}
static int
udf_write_nodedscr_direct(struct udf_strat_args *args)
{
struct udf_mount *ump = args->ump;
struct udf_node *udf_node = args->udf_node;
union dscrptr *dscr = args->dscr;
struct long_ad *icb = args->icb;
int waitfor = args->waitfor;
uint32_t logsector, sector, dummy;
int error, vpart __diagused;
/*
* we have to decide if we write it out sequential or at its fixed
* position by examining the partition its (to be) written on.
*/
vpart = udf_rw16(udf_node->loc.loc.part_num);
logsector = udf_rw32(icb->loc.lb_num);
KASSERT(ump->vtop_tp[vpart] != UDF_VTOP_TYPE_VIRT);
sector = 0;
error = udf_translate_vtop(ump, icb, &sector, &dummy);
if (error)
goto out;
/* add reference to the vnode to prevent recycling */
vhold(udf_node->vnode);
if (waitfor) {
DPRINTF(WRITE, ("udf_write_nodedscr: sync write\n"));
error = udf_write_phys_dscr_sync(ump, udf_node, UDF_C_NODE,
dscr, sector, logsector);
} else {
DPRINTF(WRITE, ("udf_write_nodedscr: no wait, async write\n"));
error = udf_write_phys_dscr_async(ump, udf_node, UDF_C_NODE,
dscr, sector, logsector, udf_wr_nodedscr_callback);
/* will be UNLOCKED in call back */
return error;
}
holdrele(udf_node->vnode);
out:
udf_node->outstanding_nodedscr--;
if (udf_node->outstanding_nodedscr == 0) {
UDF_UNLOCK_NODE(udf_node, 0);
wakeup(&udf_node->outstanding_nodedscr);
}
return error;
}
/* --------------------------------------------------------------------- */
static void
udf_queue_buf_direct(struct udf_strat_args *args)
{
struct udf_mount *ump = args->ump;
struct buf *buf = args->nestbuf;
struct buf *nestbuf;
struct desc_tag *tag;
struct long_ad *node_ad_cpy;
uint64_t *lmapping, *pmapping, *lmappos, run_start;
uint32_t sectornr;
uint32_t buf_offset, rbuflen, bpos;
uint16_t vpart_num;
uint8_t *fidblk;
off_t rblk;
int sector_size = ump->discinfo.sector_size;
int len, buf_len, sector, sectors, run_length;
int blks = sector_size / DEV_BSIZE;
int what, class __diagused, queue;
KASSERT(ump);
KASSERT(buf);
KASSERT(buf->b_iodone == nestiobuf_iodone);
what = buf->b_udf_c_type;
queue = UDF_SHED_READING;
if ((buf->b_flags & B_READ) == 0) {
/* writing */
queue = UDF_SHED_SEQWRITING;
if (what == UDF_C_ABSOLUTE)
queue = UDF_SHED_WRITING;
if (what == UDF_C_DSCR)
queue = UDF_SHED_WRITING;
if (what == UDF_C_NODE)
queue = UDF_SHED_WRITING;
}
/* use disc sheduler */
class = ump->discinfo.mmc_class;
KASSERT((class == MMC_CLASS_UNKN) || (class == MMC_CLASS_DISC) ||
(ump->discinfo.mmc_cur & MMC_CAP_HW_DEFECTFREE) ||
(ump->vfs_mountp->mnt_flag & MNT_RDONLY));
#ifndef UDF_DEBUG
__USE(blks);
#endif
if (queue == UDF_SHED_READING) {
DPRINTF(SHEDULE, ("\nudf_issue_buf READ %p : sector %d type %d,"
"b_resid %d, b_bcount %d, b_bufsize %d\n",
buf, (uint32_t) buf->b_blkno / blks, buf->b_udf_c_type,
buf->b_resid, buf->b_bcount, buf->b_bufsize));
VOP_STRATEGY(ump->devvp, buf);
return;
}
if (queue == UDF_SHED_WRITING) {
DPRINTF(SHEDULE, ("\nudf_issue_buf WRITE %p : sector %d "
"type %d, b_resid %d, b_bcount %d, b_bufsize %d\n",
buf, (uint32_t) buf->b_blkno / blks, buf->b_udf_c_type,
buf->b_resid, buf->b_bcount, buf->b_bufsize));
KASSERT(buf->b_udf_c_type == UDF_C_DSCR ||
buf->b_udf_c_type == UDF_C_ABSOLUTE ||
buf->b_udf_c_type == UDF_C_NODE);
udf_fixup_node_internals(ump, buf->b_data, buf->b_udf_c_type);
VOP_STRATEGY(ump->devvp, buf);
return;
}
/* UDF_SHED_SEQWRITING */
KASSERT(queue == UDF_SHED_SEQWRITING);
DPRINTF(SHEDULE, ("\nudf_issue_buf SEQWRITE %p : sector XXXX "
"type %d, b_resid %d, b_bcount %d, b_bufsize %d\n",
buf, buf->b_udf_c_type, buf->b_resid, buf->b_bcount,
buf->b_bufsize));
/*
* Buffers should not have been allocated to disc addresses yet on
* this queue. Note that a buffer can get multiple extents allocated.
*
* lmapping contains lb_num relative to base partition.
*/
lmapping = ump->la_lmapping;
node_ad_cpy = ump->la_node_ad_cpy;
/* logically allocate buf and map it in the file */
udf_late_allocate_buf(ump, buf, lmapping, node_ad_cpy, &vpart_num);
/* if we have FIDs, fixup using the new allocation table */
if (buf->b_udf_c_type == UDF_C_FIDS) {
buf_len = buf->b_bcount;
bpos = 0;
lmappos = lmapping;
while (buf_len) {
sectornr = *lmappos++;
len = MIN(buf_len, sector_size);
fidblk = (uint8_t *) buf->b_data + bpos;
udf_fixup_fid_block(fidblk, sector_size,
0, len, sectornr);
bpos += len;
buf_len -= len;
}
}
if (buf->b_udf_c_type == UDF_C_METADATA_SBM) {
if (buf->b_lblkno == 0) {
/* update the tag location inside */
tag = (struct desc_tag *) buf->b_data;
tag->tag_loc = udf_rw32(*lmapping);
udf_validate_tag_and_crc_sums(buf->b_data);
}
}
udf_fixup_node_internals(ump, buf->b_data, buf->b_udf_c_type);
/*
* Translate new mappings in lmapping to pmappings and try to
* conglomerate extents to reduce the number of writes.
*
* pmapping to contain lb_nums as used for disc adressing.
*/
pmapping = ump->la_pmapping;
sectors = (buf->b_bcount + sector_size -1) / sector_size;
udf_translate_vtop_list(ump, sectors, vpart_num, lmapping, pmapping);
for (sector = 0; sector < sectors; sector++) {
buf_offset = sector * sector_size;
DPRINTF(WRITE, ("\tprocessing rel sector %d\n", sector));
DPRINTF(WRITE, ("\tissue write sector %"PRIu64"\n",
pmapping[sector]));
run_start = pmapping[sector];
run_length = 1;
while (sector < sectors-1) {
if (pmapping[sector+1] != pmapping[sector]+1)
break;
run_length++;
sector++;
}
/* nest an iobuf for the extent */
rbuflen = run_length * sector_size;
rblk = run_start * (sector_size/DEV_BSIZE);
nestbuf = getiobuf(NULL, true);
nestiobuf_setup(buf, nestbuf, buf_offset, rbuflen);
/* nestbuf is B_ASYNC */
/* identify this nestbuf */
nestbuf->b_lblkno = sector;
assert(nestbuf->b_vp == buf->b_vp);
/* CD shedules on raw blkno */
nestbuf->b_blkno = rblk;
nestbuf->b_proc = NULL;
nestbuf->b_rawblkno = rblk;
nestbuf->b_udf_c_type = UDF_C_PROCESSED;
VOP_STRATEGY(ump->devvp, nestbuf);
}
}
static void
udf_discstrat_init_direct(struct udf_strat_args *args)
{
struct udf_mount *ump = args->ump;
struct strat_private *priv = PRIV(ump);
uint32_t lb_size;
KASSERT(priv == NULL);
ump->strategy_private = malloc(sizeof(struct strat_private),
M_UDFTEMP, M_WAITOK);
priv = ump->strategy_private;
memset(priv, 0 , sizeof(struct strat_private));
/*
* Initialise pool for descriptors associated with nodes. This is done
* in lb_size units though currently lb_size is dictated to be
* sector_size.
*/
memset(&priv->desc_pool, 0, sizeof(struct pool));
lb_size = udf_rw32(ump->logical_vol->lb_size);
pool_init(&priv->desc_pool, lb_size, 0, 0, 0, "udf_desc_pool", NULL,
IPL_NONE);
}
static void
udf_discstrat_finish_direct(struct udf_strat_args *args)
{
struct udf_mount *ump = args->ump;
struct strat_private *priv = PRIV(ump);
/* destroy our pool */
pool_destroy(&priv->desc_pool);
/* free our private space */
free(ump->strategy_private, M_UDFTEMP);
ump->strategy_private = NULL;
}
/* --------------------------------------------------------------------- */
struct udf_strategy udf_strat_direct =
{
udf_getblank_nodedscr_direct,
udf_free_nodedscr_direct,
udf_read_nodedscr_direct,
udf_write_nodedscr_direct,
udf_queue_buf_direct,
udf_discstrat_init_direct,
udf_discstrat_finish_direct
};

1507
sys/fs/udf/udf_strat_rmw.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,687 @@
/* $NetBSD: udf_strat_sequential.c,v 1.12 2013/10/18 19:56:55 christos Exp $ */
/*
* Copyright (c) 2006, 2008 Reinoud Zandijk
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include <sys/cdefs.h>
#ifndef lint
__KERNEL_RCSID(0, "$NetBSD: udf_strat_sequential.c,v 1.12 2013/10/18 19:56:55 christos Exp $");
#endif /* not lint */
#if defined(_KERNEL_OPT)
#include "opt_compat_netbsd.h"
#endif
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/sysctl.h>
#include <sys/namei.h>
#include <sys/proc.h>
#include <sys/kernel.h>
#include <sys/vnode.h>
#include <miscfs/genfs/genfs_node.h>
#include <sys/mount.h>
#include <sys/buf.h>
#include <sys/file.h>
#include <sys/device.h>
#include <sys/disklabel.h>
#include <sys/ioctl.h>
#include <sys/malloc.h>
#include <sys/dirent.h>
#include <sys/stat.h>
#include <sys/conf.h>
#include <sys/kauth.h>
#include <sys/kthread.h>
#include <dev/clock_subr.h>
#include <fs/udf/ecma167-udf.h>
#include <fs/udf/udf_mount.h>
#include "udf.h"
#include "udf_subr.h"
#include "udf_bswap.h"
#define VTOI(vnode) ((struct udf_node *) vnode->v_data)
#define PRIV(ump) ((struct strat_private *) ump->strategy_private)
/* --------------------------------------------------------------------- */
/* BUFQ's */
#define UDF_SHED_MAX 3
#define UDF_SHED_READING 0
#define UDF_SHED_WRITING 1
#define UDF_SHED_SEQWRITING 2
struct strat_private {
struct pool desc_pool; /* node descriptors */
lwp_t *queue_lwp;
kcondvar_t discstrat_cv; /* to wait on */
kmutex_t discstrat_mutex; /* disc strategy */
int run_thread; /* thread control */
int cur_queue;
struct disk_strategy old_strategy_setting;
struct bufq_state *queues[UDF_SHED_MAX];
struct timespec last_queued[UDF_SHED_MAX];
};
/* --------------------------------------------------------------------- */
static void
udf_wr_nodedscr_callback(struct buf *buf)
{
struct udf_node *udf_node;
KASSERT(buf);
KASSERT(buf->b_data);
/* called when write action is done */
DPRINTF(WRITE, ("udf_wr_nodedscr_callback(): node written out\n"));
udf_node = VTOI(buf->b_vp);
if (udf_node == NULL) {
putiobuf(buf);
printf("udf_wr_node_callback: NULL node?\n");
return;
}
/* XXX right flags to mark dirty again on error? */
if (buf->b_error) {
udf_node->i_flags |= IN_MODIFIED | IN_ACCESSED;
/* XXX TODO reshedule on error */
}
/* decrement outstanding_nodedscr */
KASSERT(udf_node->outstanding_nodedscr >= 1);
udf_node->outstanding_nodedscr--;
if (udf_node->outstanding_nodedscr == 0) {
/* first unlock the node */
UDF_UNLOCK_NODE(udf_node, 0);
wakeup(&udf_node->outstanding_nodedscr);
}
/* unreference the vnode so it can be recycled */
holdrele(udf_node->vnode);
putiobuf(buf);
}
/* --------------------------------------------------------------------- */
static int
udf_create_logvol_dscr_seq(struct udf_strat_args *args)
{
union dscrptr **dscrptr = &args->dscr;
struct udf_mount *ump = args->ump;
struct strat_private *priv = PRIV(ump);
uint32_t lb_size;
lb_size = udf_rw32(ump->logical_vol->lb_size);
*dscrptr = pool_get(&priv->desc_pool, PR_WAITOK);
memset(*dscrptr, 0, lb_size);
return 0;
}
static void
udf_free_logvol_dscr_seq(struct udf_strat_args *args)
{
union dscrptr *dscr = args->dscr;
struct udf_mount *ump = args->ump;
struct strat_private *priv = PRIV(ump);
pool_put(&priv->desc_pool, dscr);
}
static int
udf_read_logvol_dscr_seq(struct udf_strat_args *args)
{
union dscrptr **dscrptr = &args->dscr;
union dscrptr *tmpdscr;
struct udf_mount *ump = args->ump;
struct long_ad *icb = args->icb;
struct strat_private *priv = PRIV(ump);
uint32_t lb_size;
uint32_t sector, dummy;
int error;
lb_size = udf_rw32(ump->logical_vol->lb_size);
error = udf_translate_vtop(ump, icb, &sector, &dummy);
if (error)
return error;
/* try to read in fe/efe */
error = udf_read_phys_dscr(ump, sector, M_UDFTEMP, &tmpdscr);
if (error)
return error;
*dscrptr = pool_get(&priv->desc_pool, PR_WAITOK);
memcpy(*dscrptr, tmpdscr, lb_size);
free(tmpdscr, M_UDFTEMP);
return 0;
}
static int
udf_write_logvol_dscr_seq(struct udf_strat_args *args)
{
union dscrptr *dscr = args->dscr;
struct udf_mount *ump = args->ump;
struct udf_node *udf_node = args->udf_node;
struct long_ad *icb = args->icb;
int waitfor = args->waitfor;
uint32_t logsectornr, sectornr, dummy;
int error, vpart;
/*
* we have to decide if we write it out sequential or at its fixed
* position by examining the partition its (to be) written on.
*/
vpart = udf_rw16(udf_node->loc.loc.part_num);
logsectornr = udf_rw32(icb->loc.lb_num);
sectornr = 0;
if (ump->vtop_tp[vpart] != UDF_VTOP_TYPE_VIRT) {
error = udf_translate_vtop(ump, icb, &sectornr, &dummy);
if (error)
goto out;
}
/* add reference to the vnode to prevent recycling */
vhold(udf_node->vnode);
if (waitfor) {
DPRINTF(WRITE, ("udf_write_logvol_dscr: sync write\n"));
error = udf_write_phys_dscr_sync(ump, udf_node, UDF_C_NODE,
dscr, sectornr, logsectornr);
} else {
DPRINTF(WRITE, ("udf_write_logvol_dscr: no wait, async write\n"));
error = udf_write_phys_dscr_async(ump, udf_node, UDF_C_NODE,
dscr, sectornr, logsectornr, udf_wr_nodedscr_callback);
/* will be UNLOCKED in call back */
return error;
}
holdrele(udf_node->vnode);
out:
udf_node->outstanding_nodedscr--;
if (udf_node->outstanding_nodedscr == 0) {
UDF_UNLOCK_NODE(udf_node, 0);
wakeup(&udf_node->outstanding_nodedscr);
}
return error;
}
/* --------------------------------------------------------------------- */
/*
* Main file-system specific sheduler. Due to the nature of optical media
* sheduling can't be performed in the traditional way. Most OS
* implementations i've seen thus read or write a file atomically giving all
* kinds of side effects.
*
* This implementation uses a kernel thread to shedule the queued requests in
* such a way that is semi-optimal for optical media; this means aproximately
* (R*|(Wr*|Ws*))* since switching between reading and writing is expensive in
* time.
*/
static void
udf_queuebuf_seq(struct udf_strat_args *args)
{
struct udf_mount *ump = args->ump;
struct buf *nestbuf = args->nestbuf;
struct strat_private *priv = PRIV(ump);
int queue;
int what;
KASSERT(ump);
KASSERT(nestbuf);
KASSERT(nestbuf->b_iodone == nestiobuf_iodone);
what = nestbuf->b_udf_c_type;
queue = UDF_SHED_READING;
if ((nestbuf->b_flags & B_READ) == 0) {
/* writing */
queue = UDF_SHED_SEQWRITING;
if (what == UDF_C_ABSOLUTE)
queue = UDF_SHED_WRITING;
}
/* use our own sheduler lists for more complex sheduling */
mutex_enter(&priv->discstrat_mutex);
bufq_put(priv->queues[queue], nestbuf);
vfs_timestamp(&priv->last_queued[queue]);
mutex_exit(&priv->discstrat_mutex);
/* signal our thread that there might be something to do */
cv_signal(&priv->discstrat_cv);
}
/* --------------------------------------------------------------------- */
/* TODO convert to lb_size */
static void
udf_VAT_mapping_update(struct udf_mount *ump, struct buf *buf, uint32_t lb_map)
{
union dscrptr *fdscr = (union dscrptr *) buf->b_data;
struct vnode *vp = buf->b_vp;
struct udf_node *udf_node = VTOI(vp);
uint32_t lb_num;
uint32_t udf_rw32_lbmap;
int c_type = buf->b_udf_c_type;
int error;
/* only interested when we're using a VAT */
KASSERT(ump->vat_node);
KASSERT(ump->vtop_alloc[ump->node_part] == UDF_ALLOC_VAT);
/* only nodes are recorded in the VAT */
/* NOTE: and the fileset descriptor (FIXME ?) */
if (c_type != UDF_C_NODE)
return;
udf_rw32_lbmap = udf_rw32(lb_map);
/* if we're the VAT itself, only update our assigned sector number */
if (udf_node == ump->vat_node) {
fdscr->tag.tag_loc = udf_rw32_lbmap;
udf_validate_tag_sum(fdscr);
DPRINTF(TRANSLATE, ("VAT assigned to sector %u\n",
udf_rw32(udf_rw32_lbmap)));
/* no use mapping the VAT node in the VAT */
return;
}
/* record new position in VAT file */
lb_num = udf_rw32(fdscr->tag.tag_loc);
/* lb_num = udf_rw32(udf_node->write_loc.loc.lb_num); */
DPRINTF(TRANSLATE, ("VAT entry change (log %u -> phys %u)\n",
lb_num, lb_map));
/* VAT should be the longer than this write, can't go wrong */
KASSERT(lb_num <= ump->vat_entries);
mutex_enter(&ump->allocate_mutex);
error = udf_vat_write(ump->vat_node,
(uint8_t *) &udf_rw32_lbmap, 4,
ump->vat_offset + lb_num * 4);
mutex_exit(&ump->allocate_mutex);
if (error)
panic( "udf_VAT_mapping_update: HELP! i couldn't "
"write in the VAT file ?\n");
}
static void
udf_issue_buf(struct udf_mount *ump, int queue, struct buf *buf)
{
union dscrptr *dscr;
struct long_ad *node_ad_cpy;
struct part_desc *pdesc;
uint64_t *lmapping, *lmappos;
uint32_t sectornr, bpos;
uint32_t ptov;
uint16_t vpart_num;
uint8_t *fidblk;
int sector_size = ump->discinfo.sector_size;
int blks = sector_size / DEV_BSIZE;
int len, buf_len;
/* if reading, just pass to the device's STRATEGY */
if (queue == UDF_SHED_READING) {
DPRINTF(SHEDULE, ("\nudf_issue_buf READ %p : sector %d type %d,"
"b_resid %d, b_bcount %d, b_bufsize %d\n",
buf, (uint32_t) buf->b_blkno / blks, buf->b_udf_c_type,
buf->b_resid, buf->b_bcount, buf->b_bufsize));
VOP_STRATEGY(ump->devvp, buf);
return;
}
if (queue == UDF_SHED_WRITING) {
DPRINTF(SHEDULE, ("\nudf_issue_buf WRITE %p : sector %d "
"type %d, b_resid %d, b_bcount %d, b_bufsize %d\n",
buf, (uint32_t) buf->b_blkno / blks, buf->b_udf_c_type,
buf->b_resid, buf->b_bcount, buf->b_bufsize));
KASSERT(buf->b_udf_c_type == UDF_C_ABSOLUTE);
// udf_fixup_node_internals(ump, buf->b_data, buf->b_udf_c_type);
VOP_STRATEGY(ump->devvp, buf);
return;
}
KASSERT(queue == UDF_SHED_SEQWRITING);
DPRINTF(SHEDULE, ("\nudf_issue_buf SEQWRITE %p : sector XXXX "
"type %d, b_resid %d, b_bcount %d, b_bufsize %d\n",
buf, buf->b_udf_c_type, buf->b_resid, buf->b_bcount,
buf->b_bufsize));
/*
* Buffers should not have been allocated to disc addresses yet on
* this queue. Note that a buffer can get multiple extents allocated.
*
* lmapping contains lb_num relative to base partition.
*/
lmapping = ump->la_lmapping;
node_ad_cpy = ump->la_node_ad_cpy;
/* logically allocate buf and map it in the file */
udf_late_allocate_buf(ump, buf, lmapping, node_ad_cpy, &vpart_num);
/*
* NOTE We are using the knowledge here that sequential media will
* always be mapped linearly. Thus no use to explicitly translate the
* lmapping list.
*/
/* calculate offset from physical base partition */
pdesc = ump->partitions[ump->vtop[vpart_num]];
ptov = udf_rw32(pdesc->start_loc);
/* set buffers blkno to the physical block number */
buf->b_blkno = (*lmapping + ptov) * blks;
/* fixate floating descriptors */
if (buf->b_udf_c_type == UDF_C_FLOAT_DSCR) {
/* set our tag location to the absolute position */
dscr = (union dscrptr *) buf->b_data;
dscr->tag.tag_loc = udf_rw32(*lmapping + ptov);
udf_validate_tag_and_crc_sums(dscr);
}
/* update mapping in the VAT */
if (buf->b_udf_c_type == UDF_C_NODE) {
udf_VAT_mapping_update(ump, buf, *lmapping);
udf_fixup_node_internals(ump, buf->b_data, buf->b_udf_c_type);
}
/* if we have FIDs, fixup using the new allocation table */
if (buf->b_udf_c_type == UDF_C_FIDS) {
buf_len = buf->b_bcount;
bpos = 0;
lmappos = lmapping;
while (buf_len) {
sectornr = *lmappos++;
len = MIN(buf_len, sector_size);
fidblk = (uint8_t *) buf->b_data + bpos;
udf_fixup_fid_block(fidblk, sector_size,
0, len, sectornr);
bpos += len;
buf_len -= len;
}
}
VOP_STRATEGY(ump->devvp, buf);
}
static void
udf_doshedule(struct udf_mount *ump)
{
struct buf *buf;
struct timespec now, *last;
struct strat_private *priv = PRIV(ump);
void (*b_callback)(struct buf *);
int new_queue;
int error;
buf = bufq_get(priv->queues[priv->cur_queue]);
if (buf) {
/* transfer from the current queue to the device queue */
mutex_exit(&priv->discstrat_mutex);
/* transform buffer to synchronous; XXX needed? */
b_callback = buf->b_iodone;
buf->b_iodone = NULL;
CLR(buf->b_flags, B_ASYNC);
/* issue and wait on completion */
udf_issue_buf(ump, priv->cur_queue, buf);
biowait(buf);
mutex_enter(&priv->discstrat_mutex);
/* if there is an error, repair this error, otherwise propagate */
if (buf->b_error && ((buf->b_flags & B_READ) == 0)) {
/* check what we need to do */
panic("UDF write error, can't handle yet!\n");
}
/* propagate result to higher layers */
if (b_callback) {
buf->b_iodone = b_callback;
(*buf->b_iodone)(buf);
}
return;
}
/* Check if we're idling in this state */
vfs_timestamp(&now);
last = &priv->last_queued[priv->cur_queue];
if (ump->discinfo.mmc_class == MMC_CLASS_CD) {
/* dont switch too fast for CD media; its expensive in time */
if (now.tv_sec - last->tv_sec < 3)
return;
}
/* check if we can/should switch */
new_queue = priv->cur_queue;
if (bufq_peek(priv->queues[UDF_SHED_READING]))
new_queue = UDF_SHED_READING;
if (bufq_peek(priv->queues[UDF_SHED_WRITING])) /* only for unmount */
new_queue = UDF_SHED_WRITING;
if (bufq_peek(priv->queues[UDF_SHED_SEQWRITING]))
new_queue = UDF_SHED_SEQWRITING;
if (priv->cur_queue == UDF_SHED_READING) {
if (new_queue == UDF_SHED_SEQWRITING) {
/* TODO use flag to signal if this is needed */
mutex_exit(&priv->discstrat_mutex);
/* update trackinfo for data and metadata */
error = udf_update_trackinfo(ump,
&ump->data_track);
assert(error == 0);
error = udf_update_trackinfo(ump,
&ump->metadata_track);
assert(error == 0);
mutex_enter(&priv->discstrat_mutex);
}
}
if (new_queue != priv->cur_queue) {
DPRINTF(SHEDULE, ("switching from %d to %d\n",
priv->cur_queue, new_queue));
}
priv->cur_queue = new_queue;
}
static void
udf_discstrat_thread(void *arg)
{
struct udf_mount *ump = (struct udf_mount *) arg;
struct strat_private *priv = PRIV(ump);
int empty;
empty = 1;
mutex_enter(&priv->discstrat_mutex);
while (priv->run_thread || !empty) {
/* process the current selected queue */
udf_doshedule(ump);
empty = (bufq_peek(priv->queues[UDF_SHED_READING]) == NULL);
empty &= (bufq_peek(priv->queues[UDF_SHED_WRITING]) == NULL);
empty &= (bufq_peek(priv->queues[UDF_SHED_SEQWRITING]) == NULL);
/* wait for more if needed */
if (empty)
cv_timedwait(&priv->discstrat_cv,
&priv->discstrat_mutex, hz/8);
}
mutex_exit(&priv->discstrat_mutex);
wakeup(&priv->run_thread);
kthread_exit(0);
/* not reached */
}
/* --------------------------------------------------------------------- */
static void
udf_discstrat_init_seq(struct udf_strat_args *args)
{
struct udf_mount *ump = args->ump;
struct strat_private *priv = PRIV(ump);
struct disk_strategy dkstrat;
uint32_t lb_size;
KASSERT(ump);
KASSERT(ump->logical_vol);
KASSERT(priv == NULL);
lb_size = udf_rw32(ump->logical_vol->lb_size);
KASSERT(lb_size > 0);
/* initialise our memory space */
ump->strategy_private = malloc(sizeof(struct strat_private),
M_UDFTEMP, M_WAITOK);
priv = ump->strategy_private;
memset(priv, 0 , sizeof(struct strat_private));
/* initialise locks */
cv_init(&priv->discstrat_cv, "udfstrat");
mutex_init(&priv->discstrat_mutex, MUTEX_DEFAULT, IPL_NONE);
/*
* Initialise pool for descriptors associated with nodes. This is done
* in lb_size units though currently lb_size is dictated to be
* sector_size.
*/
pool_init(&priv->desc_pool, lb_size, 0, 0, 0, "udf_desc_pool", NULL,
IPL_NONE);
/*
* remember old device strategy method and explicit set method
* `discsort' since we have our own more complex strategy that is not
* implementable on the CD device and other strategies will get in the
* way.
*/
memset(&priv->old_strategy_setting, 0,
sizeof(struct disk_strategy));
VOP_IOCTL(ump->devvp, DIOCGSTRATEGY, &priv->old_strategy_setting,
FREAD | FKIOCTL, NOCRED);
memset(&dkstrat, 0, sizeof(struct disk_strategy));
strcpy(dkstrat.dks_name, "discsort");
VOP_IOCTL(ump->devvp, DIOCSSTRATEGY, &dkstrat, FWRITE | FKIOCTL,
NOCRED);
/* initialise our internal sheduler */
priv->cur_queue = UDF_SHED_READING;
bufq_alloc(&priv->queues[UDF_SHED_READING], "disksort",
BUFQ_SORT_RAWBLOCK);
bufq_alloc(&priv->queues[UDF_SHED_WRITING], "disksort",
BUFQ_SORT_RAWBLOCK);
bufq_alloc(&priv->queues[UDF_SHED_SEQWRITING], "fcfs", 0);
vfs_timestamp(&priv->last_queued[UDF_SHED_READING]);
vfs_timestamp(&priv->last_queued[UDF_SHED_WRITING]);
vfs_timestamp(&priv->last_queued[UDF_SHED_SEQWRITING]);
/* create our disk strategy thread */
priv->run_thread = 1;
if (kthread_create(PRI_NONE, 0 /* KTHREAD_MPSAFE*/, NULL /* cpu_info*/,
udf_discstrat_thread, ump, &priv->queue_lwp,
"%s", "udf_rw")) {
panic("fork udf_rw");
}
}
static void
udf_discstrat_finish_seq(struct udf_strat_args *args)
{
struct udf_mount *ump = args->ump;
struct strat_private *priv = PRIV(ump);
int error;
if (ump == NULL)
return;
/* stop our sheduling thread */
KASSERT(priv->run_thread == 1);
priv->run_thread = 0;
wakeup(priv->queue_lwp);
do {
error = tsleep(&priv->run_thread, PRIBIO+1,
"udfshedfin", hz);
} while (error);
/* kthread should be finished now */
/* set back old device strategy method */
VOP_IOCTL(ump->devvp, DIOCSSTRATEGY, &priv->old_strategy_setting,
FWRITE, NOCRED);
/* destroy our pool */
pool_destroy(&priv->desc_pool);
mutex_destroy(&priv->discstrat_mutex);
cv_destroy(&priv->discstrat_cv);
/* free our private space */
free(ump->strategy_private, M_UDFTEMP);
ump->strategy_private = NULL;
}
/* --------------------------------------------------------------------- */
struct udf_strategy udf_strat_sequential =
{
udf_create_logvol_dscr_seq,
udf_free_logvol_dscr_seq,
udf_read_logvol_dscr_seq,
udf_write_logvol_dscr_seq,
udf_queuebuf_seq,
udf_discstrat_init_seq,
udf_discstrat_finish_seq
};

6817
sys/fs/udf/udf_subr.c Normal file

File diff suppressed because it is too large Load diff

229
sys/fs/udf/udf_subr.h Normal file
View file

@ -0,0 +1,229 @@
/* $NetBSD: udf_subr.h,v 1.19 2013/07/07 19:49:44 reinoud Exp $ */
/*
* Copyright (c) 2006, 2008 Reinoud Zandijk
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef _FS_UDF_UDF_SUBR_H_
#define _FS_UDF_UDF_SUBR_H_
/* handies */
#define VFSTOUDF(mp) ((struct udf_mount *)mp->mnt_data)
/* device information updating */
int udf_update_trackinfo(struct udf_mount *ump, struct mmc_trackinfo *trackinfo);
int udf_update_discinfo(struct udf_mount *ump);
int udf_search_tracks(struct udf_mount *ump, struct udf_args *args,
int *first_tracknr, int *last_tracknr);
int udf_search_writing_tracks(struct udf_mount *ump);
int udf_setup_writeparams(struct udf_mount *ump);
int udf_synchronise_caches(struct udf_mount *ump);
/* tags operations */
int udf_fidsize(struct fileid_desc *fid);
int udf_check_tag(void *blob);
int udf_check_tag_payload(void *blob, uint32_t max_length);
void udf_validate_tag_sum(void *blob);
void udf_validate_tag_and_crc_sums(void *blob);
int udf_tagsize(union dscrptr *dscr, uint32_t udf_sector_size);
/* read/write descriptors */
int udf_read_phys_sectors(struct udf_mount *ump, int what, void *blob,
uint32_t start, uint32_t sectors);
int udf_write_phys_sectors(struct udf_mount *ump, int what, void *blob,
uint32_t start, uint32_t sectors);
int udf_read_phys_dscr(
struct udf_mount *ump,
uint32_t sector,
struct malloc_type *mtype, /* where to allocate */
union dscrptr **dstp); /* out */
int udf_write_phys_dscr_sync(struct udf_mount *ump, struct udf_node *udf_node,
int what, union dscrptr *dscr,
uint32_t sector, uint32_t logsector);
int udf_write_phys_dscr_async(struct udf_mount *ump, struct udf_node *udf_node,
int what, union dscrptr *dscr,
uint32_t sector, uint32_t logsector,
void (*dscrwr_callback)(struct buf *));
/* read/write node descriptors */
int udf_create_logvol_dscr(struct udf_mount *ump, struct udf_node *udf_node,
struct long_ad *icb, union dscrptr **dscrptr);
void udf_free_logvol_dscr(struct udf_mount *ump, struct long_ad *icb_loc,
void *dscr);
int udf_read_logvol_dscr(struct udf_mount *ump, struct long_ad *icb,
union dscrptr **dscrptr);
int udf_write_logvol_dscr(struct udf_node *udf_node, union dscrptr *dscr,
struct long_ad *icb, int waitfor);
/* volume descriptors readers and checkers */
int udf_read_anchors(struct udf_mount *ump);
int udf_read_vds_space(struct udf_mount *ump);
int udf_process_vds(struct udf_mount *ump);
int udf_read_vds_tables(struct udf_mount *ump);
int udf_read_rootdirs(struct udf_mount *ump);
/* open/close and sync volumes */
int udf_open_logvol(struct udf_mount *ump);
int udf_close_logvol(struct udf_mount *ump, int mntflags);
int udf_writeout_vat(struct udf_mount *ump);
int udf_write_physical_partition_spacetables(struct udf_mount *ump, int waitfor);
int udf_write_metadata_partition_spacetable(struct udf_mount *ump, int waitfor);
void udf_do_sync(struct udf_mount *ump, kauth_cred_t cred, int waitfor);
void udf_synchronise_metadatamirror_node(struct udf_mount *ump);
/* translation services */
int udf_translate_vtop(struct udf_mount *ump, struct long_ad *icb_loc,
uint32_t *lb_numres, uint32_t *extres);
void udf_translate_vtop_list(struct udf_mount *ump, uint32_t sectors,
uint16_t vpart_num, uint64_t *lmapping, uint64_t *pmapping);
int udf_translate_file_extent(struct udf_node *node,
uint32_t from, uint32_t num_lb, uint64_t *map);
void udf_get_adslot(struct udf_node *udf_node, int slot, struct long_ad *icb, int *eof);
int udf_append_adslot(struct udf_node *udf_node, int *slot, struct long_ad *icb);
int udf_vat_read(struct udf_node *vat_node, uint8_t *blob, int size, uint32_t offset);
int udf_vat_write(struct udf_node *vat_node, uint8_t *blob, int size, uint32_t offset);
/* disc allocation */
int udf_get_c_type(struct udf_node *udf_node);
int udf_get_record_vpart(struct udf_mount *ump, int udf_c_type);
void udf_do_reserve_space(struct udf_mount *ump, struct udf_node *udf_node, uint16_t vpart_num, uint32_t num_lb);
void udf_do_unreserve_space(struct udf_mount *ump, struct udf_node *udf_node, uint16_t vpart_num, uint32_t num_lb);
int udf_reserve_space(struct udf_mount *ump, struct udf_node *udf_node, int udf_c_type, uint16_t vpart_num, uint32_t num_lb, int can_fail);
void udf_cleanup_reservation(struct udf_node *udf_node);
int udf_allocate_space(struct udf_mount *ump, struct udf_node *udf_node, int udf_c_type, uint16_t vpart_num, uint32_t num_lb, uint64_t *lmapping);
void udf_free_allocated_space(struct udf_mount *ump, uint32_t lb_num, uint16_t vpart_num, uint32_t num_lb);
void udf_late_allocate_buf(struct udf_mount *ump, struct buf *buf, uint64_t *lmapping, struct long_ad *node_ad_cpy, uint16_t *vpart_num);
int udf_grow_node(struct udf_node *node, uint64_t new_size);
int udf_shrink_node(struct udf_node *node, uint64_t new_size);
void udf_calc_freespace(struct udf_mount *ump, uint64_t *sizeblks, uint64_t *freeblks);
/* node readers and writers */
uint64_t udf_advance_uniqueid(struct udf_mount *ump);
#define UDF_LOCK_NODE(udf_node, flag) udf_lock_node(udf_node, (flag), __FILE__, __LINE__)
#define UDF_UNLOCK_NODE(udf_node, flag) udf_unlock_node(udf_node, (flag))
void udf_lock_node(struct udf_node *udf_node, int flag, char const *fname, const int lineno);
void udf_unlock_node(struct udf_node *udf_node, int flag);
int udf_get_node(struct udf_mount *ump, struct long_ad *icbloc, struct udf_node **noderes);
int udf_writeout_node(struct udf_node *udf_node, int waitfor);
int udf_dispose_node(struct udf_node *node);
/* node ops */
int udf_resize_node(struct udf_node *node, uint64_t new_size, int *extended);
int udf_extattr_search_intern(struct udf_node *node, uint32_t sattr, char const *sattrname, uint32_t *offsetp, uint32_t *lengthp);
/* node data buffer read/write */
void udf_read_filebuf(struct udf_node *node, struct buf *buf);
void udf_write_filebuf(struct udf_node *node, struct buf *buf);
void udf_fixup_fid_block(uint8_t *blob, int lb_size, int rfix_pos, int max_rfix_pos, uint32_t lb_num);
void udf_fixup_internal_extattr(uint8_t *blob, uint32_t lb_num);
void udf_fixup_node_internals(struct udf_mount *ump, uint8_t *blob, int udf_c_type);
/* device strategy */
void udf_discstrat_init(struct udf_mount *ump);
void udf_discstrat_finish(struct udf_mount *ump);
void udf_discstrat_queuebuf(struct udf_mount *ump, struct buf *nestbuf);
/* structure writers */
int udf_write_terminator(struct udf_mount *ump, uint32_t sector);
/* structure creators */
void udf_inittag(struct udf_mount *ump, struct desc_tag *tag, int tagid, uint32_t sector);
void udf_set_regid(struct regid *regid, char const *name);
void udf_add_domain_regid(struct udf_mount *ump, struct regid *regid);
void udf_add_udf_regid(struct udf_mount *ump, struct regid *regid);
void udf_add_impl_regid(struct udf_mount *ump, struct regid *regid);
void udf_add_app_regid(struct udf_mount *ump, struct regid *regid);
/* directory operations and helpers */
void udf_osta_charset(struct charspec *charspec);
int udf_read_fid_stream(struct vnode *vp, uint64_t *offset, struct fileid_desc *fid, struct dirent *dirent);
int udf_lookup_name_in_dir(struct vnode *vp, const char *name, int namelen, struct long_ad *icb_loc, int *found);
int udf_create_node(struct vnode *dvp, struct vnode **vpp, struct vattr *vap, struct componentname *cnp);
void udf_delete_node(struct udf_node *udf_node);
int udf_chsize(struct vnode *vp, u_quad_t newsize, kauth_cred_t cred);
int udf_dir_detach(struct udf_mount *ump, struct udf_node *dir_node, struct udf_node *udf_node, struct componentname *cnp);
int udf_dir_attach(struct udf_mount *ump, struct udf_node *dir_node, struct udf_node *udf_node, struct vattr *vap, struct componentname *cnp);
int udf_dir_update_rootentry(struct udf_mount *ump, struct udf_node *dir_node, struct udf_node *new_parent_node);
int udf_dirhash_fill(struct udf_node *dir_node);
/* update and times */
void udf_add_to_dirtylist(struct udf_node *udf_node);
void udf_remove_from_dirtylist(struct udf_node *udf_node);
void udf_itimes(struct udf_node *udf_node, struct timespec *acc,
struct timespec *mod, struct timespec *birth);
int udf_update(struct vnode *node, struct timespec *acc,
struct timespec *mod, struct timespec *birth, int updflags);
/* helpers and converters */
void udf_init_nodes_tree(struct udf_mount *ump);
long udf_get_node_id(const struct long_ad *icbptr); /* for `inode' numbering */
int udf_compare_icb(const struct long_ad *a, const struct long_ad *b);
uint32_t udf_getaccessmode(struct udf_node *node);
void udf_setaccessmode(struct udf_node *udf_node, mode_t mode);
void udf_getownership(struct udf_node *udf_node, uid_t *uidp, gid_t *gidp);
void udf_setownership(struct udf_node *udf_node, uid_t uid, gid_t gid);
void udf_to_unix_name(char *result, int result_len, char *id, int len, struct charspec *chsp);
void unix_to_udf_name(char *result, uint8_t *result_len, char const *name, int name_len, struct charspec *chsp);
void udf_timestamp_to_timespec(struct udf_mount *ump, struct timestamp *timestamp, struct timespec *timespec);
void udf_timespec_to_timestamp(struct timespec *timespec, struct timestamp *timestamp);
/* vnode operations */
int udf_inactive(void *v);
int udf_reclaim(void *v);
int udf_readdir(void *v);
int udf_getattr(void *v);
int udf_setattr(void *v);
int udf_pathconf(void *v);
int udf_open(void *v);
int udf_close(void *v);
int udf_access(void *v);
int udf_read(void *v);
int udf_write(void *v);
int udf_trivial_bmap(void *v);
int udf_vfsstrategy(void *v);
int udf_lookup(void *v);
int udf_create(void *v);
int udf_mknod(void *v);
int udf_link(void *);
int udf_symlink(void *v);
int udf_readlink(void *v);
int udf_rename(void *v);
int udf_remove(void *v);
int udf_mkdir(void *v);
int udf_rmdir(void *v);
int udf_fsync(void *v);
int udf_advlock(void *v);
#endif /* !_FS_UDF_UDF_SUBR_H_ */

949
sys/fs/udf/udf_vfsops.c Normal file
View file

@ -0,0 +1,949 @@
/* $NetBSD: udf_vfsops.c,v 1.64 2013/09/30 18:58:00 hannken Exp $ */
/*
* Copyright (c) 2006, 2008 Reinoud Zandijk
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include <sys/cdefs.h>
#ifndef lint
__KERNEL_RCSID(0, "$NetBSD: udf_vfsops.c,v 1.64 2013/09/30 18:58:00 hannken Exp $");
#endif /* not lint */
#if defined(_KERNEL_OPT)
#include "opt_compat_netbsd.h"
#endif
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/sysctl.h>
#include <sys/namei.h>
#include <sys/proc.h>
#include <sys/kernel.h>
#include <sys/vnode.h>
#include <miscfs/genfs/genfs.h>
#include <miscfs/specfs/specdev.h>
#include <sys/mount.h>
#include <sys/buf.h>
#include <sys/file.h>
#include <sys/device.h>
#include <sys/disklabel.h>
#include <sys/ioctl.h>
#include <sys/malloc.h>
#include <sys/dirent.h>
#include <sys/stat.h>
#include <sys/conf.h>
#include <sys/kauth.h>
#include <sys/module.h>
#include <fs/udf/ecma167-udf.h>
#include <fs/udf/udf_mount.h>
#include <sys/dirhash.h>
#include "udf.h"
#include "udf_subr.h"
#include "udf_bswap.h"
MODULE(MODULE_CLASS_VFS, udf, NULL);
#define VTOI(vnode) ((struct udf_node *) vnode->v_data)
/* verbose levels of the udf filingsystem */
int udf_verbose = UDF_DEBUGGING;
/* malloc regions */
MALLOC_JUSTDEFINE(M_UDFMNT, "UDF mount", "UDF mount structures");
MALLOC_JUSTDEFINE(M_UDFVOLD, "UDF volspace", "UDF volume space descriptors");
MALLOC_JUSTDEFINE(M_UDFTEMP, "UDF temp", "UDF scrap space");
struct pool udf_node_pool;
/* supported functions predefined */
VFS_PROTOS(udf);
static struct sysctllog *udf_sysctl_log;
/* internal functions */
static int udf_mountfs(struct vnode *, struct mount *, struct lwp *, struct udf_args *);
/* --------------------------------------------------------------------- */
/* predefine vnode-op list descriptor */
extern const struct vnodeopv_desc udf_vnodeop_opv_desc;
const struct vnodeopv_desc * const udf_vnodeopv_descs[] = {
&udf_vnodeop_opv_desc,
NULL,
};
/* vfsops descriptor linked in as anchor point for the filingsystem */
struct vfsops udf_vfsops = {
MOUNT_UDF, /* vfs_name */
sizeof (struct udf_args),
udf_mount,
udf_start,
udf_unmount,
udf_root,
(void *)eopnotsupp, /* vfs_quotactl */
udf_statvfs,
udf_sync,
udf_vget,
udf_fhtovp,
udf_vptofh,
udf_init,
udf_reinit,
udf_done,
udf_mountroot,
udf_snapshot,
vfs_stdextattrctl,
(void *)eopnotsupp, /* vfs_suspendctl */
genfs_renamelock_enter,
genfs_renamelock_exit,
(void *)eopnotsupp,
udf_vnodeopv_descs,
0, /* int vfs_refcount */
{ NULL, NULL, }, /* LIST_ENTRY(vfsops) */
};
/* --------------------------------------------------------------------- */
/* file system starts here */
void
udf_init(void)
{
size_t size;
/* setup memory types */
malloc_type_attach(M_UDFMNT);
malloc_type_attach(M_UDFVOLD);
malloc_type_attach(M_UDFTEMP);
/* init node pools */
size = sizeof(struct udf_node);
pool_init(&udf_node_pool, size, 0, 0, 0,
"udf_node_pool", NULL, IPL_NONE);
}
void
udf_reinit(void)
{
/* nothing to do */
}
void
udf_done(void)
{
/* remove pools */
pool_destroy(&udf_node_pool);
malloc_type_detach(M_UDFMNT);
malloc_type_detach(M_UDFVOLD);
malloc_type_detach(M_UDFTEMP);
}
/*
* If running a DEBUG kernel, provide an easy way to set the debug flags when
* running into a problem.
*/
#define UDF_VERBOSE_SYSCTLOPT 1
static int
udf_modcmd(modcmd_t cmd, void *arg)
{
const struct sysctlnode *node;
int error;
switch (cmd) {
case MODULE_CMD_INIT:
error = vfs_attach(&udf_vfsops);
if (error != 0)
break;
/*
* XXX the "24" below could be dynamic, thereby eliminating one
* more instance of the "number to vfs" mapping problem, but
* "24" is the order as taken from sys/mount.h
*/
sysctl_createv(&udf_sysctl_log, 0, NULL, NULL,
CTLFLAG_PERMANENT,
CTLTYPE_NODE, "vfs", NULL,
NULL, 0, NULL, 0,
CTL_VFS, CTL_EOL);
sysctl_createv(&udf_sysctl_log, 0, NULL, &node,
CTLFLAG_PERMANENT,
CTLTYPE_NODE, "udf",
SYSCTL_DESCR("OSTA Universal File System"),
NULL, 0, NULL, 0,
CTL_VFS, 24, CTL_EOL);
#ifdef DEBUG
sysctl_createv(&udf_sysctl_log, 0, NULL, &node,
CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
CTLTYPE_INT, "verbose",
SYSCTL_DESCR("Bitmask for filesystem debugging"),
NULL, 0, &udf_verbose, 0,
CTL_VFS, 24, UDF_VERBOSE_SYSCTLOPT, CTL_EOL);
#endif
break;
case MODULE_CMD_FINI:
error = vfs_detach(&udf_vfsops);
if (error != 0)
break;
sysctl_teardown(&udf_sysctl_log);
break;
default:
error = ENOTTY;
break;
}
return (error);
}
/* --------------------------------------------------------------------- */
int
udf_mountroot(void)
{
return EOPNOTSUPP;
}
/* --------------------------------------------------------------------- */
#define MPFREE(a, lst) \
if ((a)) free((a), lst);
static void
free_udf_mountinfo(struct mount *mp)
{
struct udf_mount *ump;
int i;
if (!mp)
return;
ump = VFSTOUDF(mp);
if (ump) {
/* clear our data */
for (i = 0; i < UDF_ANCHORS; i++)
MPFREE(ump->anchors[i], M_UDFVOLD);
MPFREE(ump->primary_vol, M_UDFVOLD);
MPFREE(ump->logical_vol, M_UDFVOLD);
MPFREE(ump->unallocated, M_UDFVOLD);
MPFREE(ump->implementation, M_UDFVOLD);
MPFREE(ump->logvol_integrity, M_UDFVOLD);
for (i = 0; i < UDF_PARTITIONS; i++) {
MPFREE(ump->partitions[i], M_UDFVOLD);
MPFREE(ump->part_unalloc_dscr[i], M_UDFVOLD);
MPFREE(ump->part_freed_dscr[i], M_UDFVOLD);
}
MPFREE(ump->metadata_unalloc_dscr, M_UDFVOLD);
MPFREE(ump->fileset_desc, M_UDFVOLD);
MPFREE(ump->sparing_table, M_UDFVOLD);
MPFREE(ump->la_node_ad_cpy, M_UDFMNT);
MPFREE(ump->la_pmapping, M_TEMP);
MPFREE(ump->la_lmapping, M_TEMP);
mutex_destroy(&ump->ihash_lock);
mutex_destroy(&ump->get_node_lock);
mutex_destroy(&ump->logvol_mutex);
mutex_destroy(&ump->allocate_mutex);
cv_destroy(&ump->dirtynodes_cv);
MPFREE(ump->vat_table, M_UDFVOLD);
free(ump, M_UDFMNT);
}
}
#undef MPFREE
/* --------------------------------------------------------------------- */
/* if the system nodes exist, release them */
static void
udf_release_system_nodes(struct mount *mp)
{
struct udf_mount *ump = VFSTOUDF(mp);
int error;
/* if we haven't even got an ump, dont bother */
if (!ump)
return;
/* VAT partition support */
if (ump->vat_node)
vrele(ump->vat_node->vnode);
/* Metadata partition support */
if (ump->metadata_node)
vrele(ump->metadata_node->vnode);
if (ump->metadatamirror_node)
vrele(ump->metadatamirror_node->vnode);
if (ump->metadatabitmap_node)
vrele(ump->metadatabitmap_node->vnode);
/* This flush should NOT write anything nor allow any node to remain */
if ((error = vflush(ump->vfs_mountp, NULLVP, 0)) != 0)
panic("Failure to flush UDF system vnodes\n");
}
int
udf_mount(struct mount *mp, const char *path,
void *data, size_t *data_len)
{
struct lwp *l = curlwp;
struct udf_args *args = data;
struct udf_mount *ump;
struct vnode *devvp;
int openflags, accessmode, error;
DPRINTF(CALL, ("udf_mount called\n"));
if (*data_len < sizeof *args)
return EINVAL;
if (mp->mnt_flag & MNT_GETARGS) {
/* request for the mount arguments */
ump = VFSTOUDF(mp);
if (ump == NULL)
return EINVAL;
*args = ump->mount_args;
*data_len = sizeof *args;
return 0;
}
/* handle request for updating mount parameters */
/* TODO can't update my mountpoint yet */
if (mp->mnt_flag & MNT_UPDATE) {
return EOPNOTSUPP;
}
/* OK, so we are asked to mount the device */
/* check/translate struct version */
/* TODO sanity checking other mount arguments */
if (args->version != 1) {
printf("mount_udf: unrecognized argument structure version\n");
return EINVAL;
}
/* lookup name to get its vnode */
error = namei_simple_user(args->fspec,
NSM_FOLLOW_NOEMULROOT, &devvp);
if (error)
return error;
#ifdef DEBUG
if (udf_verbose & UDF_DEBUG_VOLUMES)
vprint("UDF mount, trying to mount \n", devvp);
#endif
/* check if its a block device specified */
if (devvp->v_type != VBLK) {
vrele(devvp);
return ENOTBLK;
}
if (bdevsw_lookup(devvp->v_rdev) == NULL) {
vrele(devvp);
return ENXIO;
}
/*
* If mount by non-root, then verify that user has necessary
* permissions on the device.
*/
accessmode = VREAD;
if ((mp->mnt_flag & MNT_RDONLY) == 0)
accessmode |= VWRITE;
vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_MOUNT,
KAUTH_REQ_SYSTEM_MOUNT_DEVICE, mp, devvp, KAUTH_ARG(accessmode));
VOP_UNLOCK(devvp);
if (error) {
vrele(devvp);
return error;
}
/*
* Open device and try to mount it!
*/
if (mp->mnt_flag & MNT_RDONLY) {
openflags = FREAD;
} else {
openflags = FREAD | FWRITE;
}
vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
error = VOP_OPEN(devvp, openflags, FSCRED);
VOP_UNLOCK(devvp);
if (error == 0) {
/* opened ok, try mounting */
error = udf_mountfs(devvp, mp, l, args);
if (error) {
udf_release_system_nodes(mp);
/* cleanup */
udf_discstrat_finish(VFSTOUDF(mp));
free_udf_mountinfo(mp);
vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
(void) VOP_CLOSE(devvp, openflags, NOCRED);
VOP_UNLOCK(devvp);
}
}
if (error) {
/* devvp is still locked */
vrele(devvp);
return error;
}
/* register our mountpoint being on this device */
spec_node_setmountedfs(devvp, mp);
/* successfully mounted */
DPRINTF(VOLUMES, ("udf_mount() successfull\n"));
error = set_statvfs_info(path, UIO_USERSPACE, args->fspec, UIO_USERSPACE,
mp->mnt_op->vfs_name, mp, l);
if (error)
return error;
/* If we're not opened read-only, open its logical volume */
if ((mp->mnt_flag & MNT_RDONLY) == 0) {
if ((error = udf_open_logvol(VFSTOUDF(mp))) != 0) {
printf( "mount_udf: can't open logical volume for "
"writing, downgrading access to read-only\n");
mp->mnt_flag |= MNT_RDONLY;
/* FIXME we can't return error now on open failure */
return 0;
}
}
return 0;
}
/* --------------------------------------------------------------------- */
#ifdef DEBUG
static void
udf_unmount_sanity_check(struct mount *mp)
{
struct vnode *vp;
printf("On unmount, i found the following nodes:\n");
TAILQ_FOREACH(vp, &mp->mnt_vnodelist, v_mntvnodes) {
vprint("", vp);
if (VOP_ISLOCKED(vp) == LK_EXCLUSIVE) {
printf(" is locked\n");
}
if (vp->v_usecount > 1)
printf(" more than one usecount %d\n", vp->v_usecount);
}
}
#endif
int
udf_unmount(struct mount *mp, int mntflags)
{
struct udf_mount *ump;
int error, flags, closeflags;
DPRINTF(CALL, ("udf_umount called\n"));
ump = VFSTOUDF(mp);
if (!ump)
panic("UDF unmount: empty ump\n");
flags = (mntflags & MNT_FORCE) ? FORCECLOSE : 0;
/* TODO remove these paranoid functions */
#ifdef DEBUG
if (udf_verbose & UDF_DEBUG_LOCKING)
udf_unmount_sanity_check(mp);
#endif
/*
* By specifying SKIPSYSTEM we can skip vnodes marked with VV_SYSTEM.
* This hardly documented feature allows us to exempt certain files
* from being flushed.
*/
if ((error = vflush(mp, NULLVP, flags | SKIPSYSTEM)) != 0)
return error;
/* update nodes and wait for completion of writeout of system nodes */
udf_sync(mp, FSYNC_WAIT, NOCRED);
#ifdef DEBUG
if (udf_verbose & UDF_DEBUG_LOCKING)
udf_unmount_sanity_check(mp);
#endif
/* flush again, to check if we are still busy for something else */
if ((error = vflush(ump->vfs_mountp, NULLVP, flags | SKIPSYSTEM)) != 0)
return error;
DPRINTF(VOLUMES, ("flush OK on unmount\n"));
/* close logical volume and close session if requested */
if ((error = udf_close_logvol(ump, mntflags)) != 0)
return error;
#ifdef DEBUG
DPRINTF(VOLUMES, ("FINAL sanity check\n"));
if (udf_verbose & UDF_DEBUG_LOCKING)
udf_unmount_sanity_check(mp);
#endif
/* NOTE release system nodes should NOT write anything */
udf_release_system_nodes(mp);
/* finalise disc strategy */
udf_discstrat_finish(ump);
/* synchronise device caches */
(void) udf_synchronise_caches(ump);
/* close device */
DPRINTF(VOLUMES, ("closing device\n"));
if (mp->mnt_flag & MNT_RDONLY) {
closeflags = FREAD;
} else {
closeflags = FREAD | FWRITE;
}
/* devvp is still locked by us */
vn_lock(ump->devvp, LK_EXCLUSIVE | LK_RETRY);
error = VOP_CLOSE(ump->devvp, closeflags, NOCRED);
if (error)
printf("Error during closure of device! error %d, "
"device might stay locked\n", error);
DPRINTF(VOLUMES, ("device close ok\n"));
/* clear our mount reference and release device node */
spec_node_setmountedfs(ump->devvp, NULL);
vput(ump->devvp);
/* free our ump */
free_udf_mountinfo(mp);
/* free ump struct references */
mp->mnt_data = NULL;
mp->mnt_flag &= ~MNT_LOCAL;
DPRINTF(VOLUMES, ("Fin unmount\n"));
return error;
}
/* --------------------------------------------------------------------- */
/*
* Helper function of udf_mount() that actually mounts the disc.
*/
static int
udf_mountfs(struct vnode *devvp, struct mount *mp,
struct lwp *l, struct udf_args *args)
{
struct udf_mount *ump;
uint32_t sector_size, lb_size, bshift;
uint32_t logvol_integrity;
int num_anchors, error;
/* flush out any old buffers remaining from a previous use. */
if ((error = vinvalbuf(devvp, V_SAVE, l->l_cred, l, 0, 0)))
return error;
/* setup basic mount information */
mp->mnt_data = NULL;
mp->mnt_stat.f_fsidx.__fsid_val[0] = (uint32_t) devvp->v_rdev;
mp->mnt_stat.f_fsidx.__fsid_val[1] = makefstype(MOUNT_UDF);
mp->mnt_stat.f_fsid = mp->mnt_stat.f_fsidx.__fsid_val[0];
mp->mnt_stat.f_namemax = UDF_MAXNAMLEN;
mp->mnt_flag |= MNT_LOCAL;
// mp->mnt_iflag |= IMNT_MPSAFE;
/* allocate udf part of mount structure; malloc always succeeds */
ump = malloc(sizeof(struct udf_mount), M_UDFMNT, M_WAITOK | M_ZERO);
/* init locks */
mutex_init(&ump->logvol_mutex, MUTEX_DEFAULT, IPL_NONE);
mutex_init(&ump->ihash_lock, MUTEX_DEFAULT, IPL_NONE);
mutex_init(&ump->get_node_lock, MUTEX_DEFAULT, IPL_NONE);
mutex_init(&ump->allocate_mutex, MUTEX_DEFAULT, IPL_NONE);
cv_init(&ump->dirtynodes_cv, "udfsync2");
/* init rbtree for nodes, ordered by their icb address (long_ad) */
udf_init_nodes_tree(ump);
/* set up linkage */
mp->mnt_data = ump;
ump->vfs_mountp = mp;
/* set up arguments and device */
ump->mount_args = *args;
ump->devvp = devvp;
if ((error = udf_update_discinfo(ump))) {
printf("UDF mount: error inspecting fs node\n");
return error;
}
/* inspect sector size */
sector_size = ump->discinfo.sector_size;
bshift = 1;
while ((1 << bshift) < sector_size)
bshift++;
if ((1 << bshift) != sector_size) {
printf("UDF mount: "
"hit NetBSD implementation fence on sector size\n");
return EIO;
}
/* temporary check to overcome sectorsize >= 8192 bytes panic */
if (sector_size >= 8192) {
printf("UDF mount: "
"hit implementation limit, sectorsize to big\n");
return EIO;
}
/*
* Inspect if we're asked to mount read-write on a non recordable or
* closed sequential disc.
*/
if ((mp->mnt_flag & MNT_RDONLY) == 0) {
if ((ump->discinfo.mmc_cur & MMC_CAP_RECORDABLE) == 0) {
printf("UDF mount: disc is not recordable\n");
return EROFS;
}
if (ump->discinfo.mmc_cur & MMC_CAP_SEQUENTIAL) {
if (ump->discinfo.disc_state == MMC_STATE_FULL) {
printf("UDF mount: disc is not appendable\n");
return EROFS;
}
/*
* TODO if the last session is closed check if there
* is enough space to open/close new session
*/
}
/* double check if we're not mounting a pervious session RW */
if (args->sessionnr != 0) {
printf("UDF mount: updating a previous session "
"not yet allowed\n");
return EROFS;
}
}
/* initialise bootstrap disc strategy */
ump->strategy = &udf_strat_bootstrap;
udf_discstrat_init(ump);
/* read all anchors to get volume descriptor sequence */
num_anchors = udf_read_anchors(ump);
if (num_anchors == 0)
return EINVAL;
DPRINTF(VOLUMES, ("Read %d anchors on this disc, session %d\n",
num_anchors, args->sessionnr));
/* read in volume descriptor sequence */
if ((error = udf_read_vds_space(ump))) {
printf("UDF mount: error reading volume space\n");
return error;
}
/* close down bootstrap disc strategy */
udf_discstrat_finish(ump);
/* check consistency and completeness */
if ((error = udf_process_vds(ump))) {
printf( "UDF mount: disc not properly formatted"
"(bad VDS)\n");
return error;
}
/* switch to new disc strategy */
KASSERT(ump->strategy != &udf_strat_bootstrap);
udf_discstrat_init(ump);
/* initialise late allocation administration space */
ump->la_lmapping = malloc(sizeof(uint64_t) * UDF_MAX_MAPPINGS,
M_TEMP, M_WAITOK);
ump->la_pmapping = malloc(sizeof(uint64_t) * UDF_MAX_MAPPINGS,
M_TEMP, M_WAITOK);
/* setup node cleanup extents copy space */
lb_size = udf_rw32(ump->logical_vol->lb_size);
ump->la_node_ad_cpy = malloc(lb_size * UDF_MAX_ALLOC_EXTENTS,
M_UDFMNT, M_WAITOK);
memset(ump->la_node_ad_cpy, 0, lb_size * UDF_MAX_ALLOC_EXTENTS);
/* setup rest of mount information */
mp->mnt_data = ump;
/* bshift is allways equal to disc sector size */
mp->mnt_dev_bshift = bshift;
mp->mnt_fs_bshift = bshift;
/* note that the mp info needs to be initialised for reading! */
/* read vds support tables like VAT, sparable etc. */
if ((error = udf_read_vds_tables(ump))) {
printf( "UDF mount: error in format or damaged disc "
"(VDS tables failing)\n");
return error;
}
/* check if volume integrity is closed otherwise its dirty */
logvol_integrity = udf_rw32(ump->logvol_integrity->integrity_type);
if (logvol_integrity != UDF_INTEGRITY_CLOSED) {
printf("UDF mount: file system is not clean; ");
printf("please fsck(8)\n");
return EPERM;
}
/* read root directory */
if ((error = udf_read_rootdirs(ump))) {
printf( "UDF mount: "
"disc not properly formatted or damaged disc "
"(rootdirs failing)\n");
return error;
}
/* success! */
return 0;
}
/* --------------------------------------------------------------------- */
int
udf_start(struct mount *mp, int flags)
{
/* do we have to do something here? */
return 0;
}
/* --------------------------------------------------------------------- */
int
udf_root(struct mount *mp, struct vnode **vpp)
{
struct vnode *vp;
struct long_ad *dir_loc;
struct udf_mount *ump = VFSTOUDF(mp);
struct udf_node *root_dir;
int error;
DPRINTF(CALL, ("udf_root called\n"));
dir_loc = &ump->fileset_desc->rootdir_icb;
error = udf_get_node(ump, dir_loc, &root_dir);
if (!root_dir)
error = ENOENT;
if (error)
return error;
vp = root_dir->vnode;
KASSERT(vp->v_vflag & VV_ROOT);
*vpp = vp;
return 0;
}
/* --------------------------------------------------------------------- */
int
udf_statvfs(struct mount *mp, struct statvfs *sbp)
{
struct udf_mount *ump = VFSTOUDF(mp);
struct logvol_int_desc *lvid;
struct udf_logvol_info *impl;
uint64_t freeblks, sizeblks;
int num_part;
DPRINTF(CALL, ("udf_statvfs called\n"));
sbp->f_flag = mp->mnt_flag;
sbp->f_bsize = ump->discinfo.sector_size;
sbp->f_frsize = ump->discinfo.sector_size;
sbp->f_iosize = ump->discinfo.sector_size;
mutex_enter(&ump->allocate_mutex);
udf_calc_freespace(ump, &sizeblks, &freeblks);
sbp->f_blocks = sizeblks;
sbp->f_bfree = freeblks;
sbp->f_files = 0;
lvid = ump->logvol_integrity;
num_part = udf_rw32(lvid->num_part);
impl = (struct udf_logvol_info *) (lvid->tables + 2*num_part);
if (impl) {
sbp->f_files = udf_rw32(impl->num_files);
sbp->f_files += udf_rw32(impl->num_directories);
}
/* XXX read only for now XXX */
sbp->f_bavail = 0;
sbp->f_bresvd = 0;
/* tricky, next only aplies to ffs i think, so set to zero */
sbp->f_ffree = 0;
sbp->f_favail = 0;
sbp->f_fresvd = 0;
mutex_exit(&ump->allocate_mutex);
copy_statvfs_info(sbp, mp);
return 0;
}
/* --------------------------------------------------------------------- */
/*
* TODO what about writing out free space maps, lvid etc? only on `waitfor'
* i.e. explicit syncing by the user?
*/
static int
udf_sync_writeout_system_files(struct udf_mount *ump, int clearflags)
{
int error;
/* XXX lock for VAT en bitmaps? */
/* metadata nodes are written synchronous */
DPRINTF(CALL, ("udf_sync: syncing metadata\n"));
if (ump->lvclose & UDF_WRITE_VAT)
udf_writeout_vat(ump);
error = 0;
if (ump->lvclose & UDF_WRITE_PART_BITMAPS) {
/* writeout metadata spacetable if existing */
error = udf_write_metadata_partition_spacetable(ump, MNT_WAIT);
if (error)
printf( "udf_writeout_system_files : "
" writeout of metadata space bitmap failed\n");
/* writeout partition spacetables */
error = udf_write_physical_partition_spacetables(ump, MNT_WAIT);
if (error)
printf( "udf_writeout_system_files : "
"writeout of space tables failed\n");
if (!error && clearflags)
ump->lvclose &= ~UDF_WRITE_PART_BITMAPS;
}
return error;
}
int
udf_sync(struct mount *mp, int waitfor, kauth_cred_t cred)
{
struct udf_mount *ump = VFSTOUDF(mp);
DPRINTF(CALL, ("udf_sync called\n"));
/* if called when mounted readonly, just ignore */
if (mp->mnt_flag & MNT_RDONLY)
return 0;
if (ump->syncing && !waitfor) {
printf("UDF: skipping autosync\n");
return 0;
}
/* get sync lock */
ump->syncing = 1;
/* pre-sync */
udf_do_sync(ump, cred, waitfor);
if (waitfor == MNT_WAIT)
udf_sync_writeout_system_files(ump, true);
DPRINTF(CALL, ("end of udf_sync()\n"));
ump->syncing = 0;
return 0;
}
/* --------------------------------------------------------------------- */
/*
* Get vnode for the file system type specific file id ino for the fs. Its
* used for reference to files by unique ID and for NFSv3.
* (optional) TODO lookup why some sources state NFSv3
*/
int
udf_vget(struct mount *mp, ino_t ino,
struct vnode **vpp)
{
DPRINTF(NOTIMPL, ("udf_vget called\n"));
return EOPNOTSUPP;
}
/* --------------------------------------------------------------------- */
/*
* Lookup vnode for file handle specified
*/
int
udf_fhtovp(struct mount *mp, struct fid *fhp,
struct vnode **vpp)
{
DPRINTF(NOTIMPL, ("udf_fhtovp called\n"));
return EOPNOTSUPP;
}
/* --------------------------------------------------------------------- */
/*
* Create an unique file handle. Its structure is opaque and won't be used by
* other subsystems. It should uniquely identify the file in the filingsystem
* and enough information to know if a file has been removed and/or resources
* have been recycled.
*/
int
udf_vptofh(struct vnode *vp, struct fid *fid,
size_t *fh_size)
{
DPRINTF(NOTIMPL, ("udf_vptofh called\n"));
return EOPNOTSUPP;
}
/* --------------------------------------------------------------------- */
/*
* Create a filingsystem snapshot at the specified timestamp. Could be
* implemented by explicitly creating a new session or with spare room in the
* integrity descriptor space
*/
int
udf_snapshot(struct mount *mp, struct vnode *vp,
struct timespec *tm)
{
DPRINTF(NOTIMPL, ("udf_snapshot called\n"));
return EOPNOTSUPP;
}
/* --------------------------------------------------------------------- */

2183
sys/fs/udf/udf_vnops.c Normal file

File diff suppressed because it is too large Load diff

7
sys/fs/v7fs/Makefile Normal file
View file

@ -0,0 +1,7 @@
# $NetBSD: Makefile,v 1.1 2011/06/27 11:52:24 uch Exp $
INCSDIR= /usr/include/fs/v7fs
INCS= v7fs.h v7fs_args.h
.include <bsd.kinc.mk>

22
sys/fs/v7fs/files.v7fs Normal file
View file

@ -0,0 +1,22 @@
# $NetBSD: files.v7fs,v 1.1 2011/06/27 11:52:24 uch Exp $
deffs V7FS
defflag opt_v7fs.h V7FS_EI
# Core. OS independent. These files are used by userland program.(fsck,newfs)
file fs/v7fs/v7fs_endian.c v7fs
file fs/v7fs/v7fs_superblock.c v7fs
file fs/v7fs/v7fs_inode.c v7fs
file fs/v7fs/v7fs_dirent.c v7fs
file fs/v7fs/v7fs_datablock.c v7fs
file fs/v7fs/v7fs_file.c v7fs
file fs/v7fs/v7fs_io.c v7fs
# util.
file fs/v7fs/v7fs_file_util.c v7fs
file fs/v7fs/v7fs_inode_util.c v7fs
file fs/v7fs/v7fs_superblock_util.c v7fs
# OS glue
file fs/v7fs/v7fs_io_kern.c v7fs
file fs/v7fs/v7fs_extern.c v7fs
file fs/v7fs/v7fs_vnops.c v7fs
file fs/v7fs/v7fs_vfsops.c v7fs

180
sys/fs/v7fs/v7fs.h Normal file
View file

@ -0,0 +1,180 @@
/* $NetBSD: v7fs.h,v 1.2 2011/07/16 12:35:40 uch Exp $ */
/*-
* Copyright (c) 2011 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by UCHIYAMA Yasushi.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _V7FS_H_
/* 7th Edition of Unix(PDP-11) Filesystem definition. */
#define _V7FS_H_
#include <sys/types.h>
#ifndef _KERNEL
#include <inttypes.h>
#endif
/*
* V7 File System
*
* +------------------
* |Boot block (512byte) sector [0]
* |
* +------------------
* |Super block (512byte) sector [1]
* |
* +------------------
* |v7fs_inode(64byte sector [2]
* .
* .
* |
* +------------------
* |data block sector [datablock_start_sector]
* |
* .
* .
* |
* +------------------
* <- [sector volume_size]
*
* |
* +------------------ volume size.
*
* Max volume size is 8GB (24bit daddr_t)
* Max file size is ~1GB
*
*/
/* V7 type. */
typedef uint16_t v7fs_ino_t;
typedef uint32_t v7fs_daddr_t;
typedef int32_t v7fs_time_t;
typedef uint32_t v7fs_off_t;
typedef uint16_t v7fs_dev_t;
typedef uint16_t v7fs_mode_t;
#define V7FS_DADDR_MAX 0x00ffffff
#define V7FS_INODE_MAX 0xffff
#define V7FS_BSIZE 512
#define V7FS_BSHIFT 9
#define V7FS_ROUND_BSIZE(x) \
((((x) + (V7FS_BSIZE - 1)) & ~(V7FS_BSIZE - 1)))
#define V7FS_TRUNC_BSIZE(x) ((x) & ~(V7FS_BSIZE - 1))
#define V7FS_RESIDUE_BSIZE(x) \
((x) - ((((x) - 1) >> V7FS_BSHIFT) << V7FS_BSHIFT))
/* Disk location. */
#define V7FS_BOOTBLOCK_SECTOR 0
#define V7FS_SUPERBLOCK_SECTOR 1
#define V7FS_ILIST_SECTOR 2
/* Superblock */
/* cache. */
#define V7FS_MAX_FREEBLOCK 50
#define V7FS_MAX_FREEINODE 100
struct v7fs_superblock {
/* [3 ... (datablock_start_sector-1)]are ilist */
uint16_t datablock_start_sector;
v7fs_daddr_t volume_size;
int16_t nfreeblock; /* # of freeblock in superblock cache. */
v7fs_daddr_t freeblock[V7FS_MAX_FREEBLOCK]; /* cache. */
int16_t nfreeinode; /* # of free inode in superblock cache. */
v7fs_ino_t freeinode[V7FS_MAX_FREEINODE]; /* cache. */
int8_t lock_freeblock;
int8_t lock_freeinode;
int8_t modified;
int8_t readonly;
v7fs_time_t update_time;
v7fs_daddr_t total_freeblock;
v7fs_ino_t total_freeinode;
} __packed;
/* Datablock */
#define V7FS_NADDR 13
#define V7FS_NADDR_DIRECT 10
#define V7FS_NADDR_INDEX1 10
#define V7FS_NADDR_INDEX2 11
#define V7FS_NADDR_INDEX3 12
/* daddr index. */
#define V7FS_DADDR_PER_BLOCK (V7FS_BSIZE / sizeof(v7fs_daddr_t))
struct v7fs_freeblock {
int16_t nfreeblock;
v7fs_daddr_t freeblock[V7FS_MAX_FREEBLOCK];
} __packed;
/* Dirent */
#define V7FS_NAME_MAX 14
#define V7FS_PATH_MAX PATH_MAX /* No V7 limit. */
#define V7FS_LINK_MAX LINK_MAX /* No V7 limit. */
struct v7fs_dirent {
v7fs_ino_t inode_number;
char name[V7FS_NAME_MAX];
} __packed; /*16byte */
/* Inode */
#define V7FS_BALBLK_INODE 1 /* monument */
#define V7FS_ROOT_INODE 2
#define V7FS_MAX_INODE(s) \
(((s)->datablock_start_sector - V7FS_ILIST_SECTOR) * \
V7FS_BSIZE / sizeof(struct v7fs_inode_diskimage))
#define V7FS_INODE_PER_BLOCK \
(V7FS_BSIZE / sizeof(struct v7fs_inode_diskimage))
#define V7FS_ILISTBLK_MAX (V7FS_INODE_MAX / V7FS_INODE_PER_BLOCK)
struct v7fs_inode_diskimage {
int16_t mode;
int16_t nlink; /* [DIR] # of child directories. [REG] link count. */
int16_t uid;
int16_t gid;
v7fs_off_t filesize; /* byte */
#define V7FS_DINODE_ADDR_LEN 40
/* 39 used; 13 addresses of 3 byte each. */
uint8_t addr[V7FS_DINODE_ADDR_LEN];
/*for device node: addr[0] is major << 8 | minor. */
v7fs_time_t atime;
v7fs_time_t mtime;
v7fs_time_t ctime;
} __packed; /*64byte */
/* File type */
#define V7FS_IFMT 0170000 /* File type mask */
#define V7FS_IFCHR 0020000 /* charcter device */
#define V7FS_IFDIR 0040000 /* directory */
#define V7FS_IFBLK 0060000 /* block device */
#define V7FS_IFREG 0100000 /* file. */
/* Obsoleted file type. */
#define V7FS_IFMPC 0030000 /* multiplexed char special */
#define V7FS_IFMPB 0070000 /* multiplexed block special */
/* Don't apear original V7 filesystem. Found at 2.10BSD. */
#define V7FSBSD_IFLNK 0120000 /* symbolic link */
#define V7FSBSD_IFSOCK 0140000 /* socket */
/* Don't apear original V7 filesystem. NetBSD. */
#define V7FSBSD_IFFIFO 0010000 /* Named pipe. */
#define V7FSBSD_MAXSYMLINKLEN V7FS_BSIZE
#endif /*!_V7FS_H_ */

40
sys/fs/v7fs/v7fs_args.h Normal file
View file

@ -0,0 +1,40 @@
/* $NetBSD: v7fs_args.h,v 1.1 2011/06/27 11:52:24 uch Exp $ */
/*-
* Copyright (c) 2004, 2011 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by UCHIYAMA Yasushi.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _FS_V7FS_V7FS_ARGS_H_
#define _FS_V7FS_V7FS_ARGS_H_
struct v7fs_args {
char *fspec; /* blocks special holding the fs to mount */
int endian; /* target filesystem endian */
};
#endif /* _FS_V7FS_V7FS_ARGS_H_ */

View file

@ -0,0 +1,729 @@
/* $NetBSD: v7fs_datablock.c,v 1.5 2011/08/14 09:02:07 apb Exp $ */
/*-
* Copyright (c) 2011 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by UCHIYAMA Yasushi.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#if HAVE_NBTOOL_CONFIG_H
#include "nbtool_config.h"
#endif
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: v7fs_datablock.c,v 1.5 2011/08/14 09:02:07 apb Exp $");
#if defined _KERNEL_OPT
#include "opt_v7fs.h"
#endif
#include <sys/types.h>
#ifdef _KERNEL
#include <sys/systm.h>
#include <sys/param.h>
#else
#include <stdio.h>
#include <string.h>
#include <errno.h>
#endif
#include "v7fs.h"
#include "v7fs_impl.h"
#include "v7fs_endian.h"
#include "v7fs_inode.h"
#include "v7fs_datablock.h"
#include "v7fs_superblock.h"
#ifdef V7FS_DATABLOCK_DEBUG
#define DPRINTF(fmt, args...) printf("%s: " fmt, __func__, ##args)
#else
#define DPRINTF(fmt, args...) ((void)0)
#endif
static int v7fs_datablock_deallocate(struct v7fs_self *, v7fs_daddr_t);
static int v7fs_loop1(struct v7fs_self *, v7fs_daddr_t, size_t *,
int (*)(struct v7fs_self *, void *, v7fs_daddr_t, size_t), void *);
static int v7fs_loop2(struct v7fs_self *, v7fs_daddr_t, size_t *,
int (*)(struct v7fs_self *, void *, v7fs_daddr_t, size_t), void *);
static v7fs_daddr_t v7fs_link(struct v7fs_self *, v7fs_daddr_t, int);
static v7fs_daddr_t v7fs_add_leaf(struct v7fs_self *, v7fs_daddr_t, int);
static v7fs_daddr_t v7fs_unlink(struct v7fs_self *, v7fs_daddr_t, int);
static v7fs_daddr_t v7fs_remove_leaf(struct v7fs_self *, v7fs_daddr_t, int);
static v7fs_daddr_t v7fs_remove_self(struct v7fs_self *, v7fs_daddr_t);
#ifdef V7FS_DATABLOCK_DEBUG
void daddr_map_dump(const struct v7fs_daddr_map *);
#else
#define daddr_map_dump(x) ((void)0)
#endif
bool
datablock_number_sanity(const struct v7fs_self *fs, v7fs_daddr_t blk)
{
const struct v7fs_superblock *sb = &fs->superblock;
bool ok = (blk >= sb->datablock_start_sector) &&
(blk < sb->volume_size);
#ifdef V7FS_DATABLOCK_DEBUG
if (!ok) {
DPRINTF("Bad data block #%d\n", blk);
}
#endif
return ok;
}
int
v7fs_datablock_allocate(struct v7fs_self *fs, v7fs_daddr_t *block_number)
{
struct v7fs_superblock *sb = &fs->superblock;
v7fs_daddr_t blk;
int error = 0;
*block_number = 0;
SUPERB_LOCK(fs);
do {
if (!sb->total_freeblock) {
DPRINTF("free block exhausted!!!\n");
SUPERB_UNLOCK(fs);
return ENOSPC;
}
/* Get free block from superblock cache. */
blk = sb->freeblock[--sb->nfreeblock];
sb->total_freeblock--;
sb->modified = 1;
/* If nfreeblock is zero, it block is next freeblock link. */
if (sb->nfreeblock == 0) {
if ((error = v7fs_freeblock_update(fs, blk))) {
DPRINTF("no freeblock!!!\n");
SUPERB_UNLOCK(fs);
return error;
}
/* This freeblock link is no longer required. */
/* use as data block. */
}
} while (!datablock_number_sanity(fs, blk)); /* skip bogus block. */
SUPERB_UNLOCK(fs);
DPRINTF("Get freeblock %d\n", blk);
/* Zero clear datablock. */
void *buf;
if (!(buf = scratch_read(fs, blk)))
return EIO;
memset(buf, 0, V7FS_BSIZE);
if (!fs->io.write(fs->io.cookie, buf, blk))
error = EIO;
scratch_free(fs, buf);
if (error == 0)
*block_number = blk;
return error;
}
static int
v7fs_datablock_deallocate(struct v7fs_self *fs, v7fs_daddr_t blk)
{
struct v7fs_superblock *sb = &fs->superblock;
void *buf;
int error = 0;
if (!datablock_number_sanity(fs, blk))
return EIO;
/* Add to in-core freelist. */
SUPERB_LOCK(fs);
if (sb->nfreeblock < V7FS_MAX_FREEBLOCK) {
sb->freeblock[sb->nfreeblock++] = blk;
sb->total_freeblock++;
sb->modified = 1;
DPRINTF("n_freeblock=%d\n", sb->total_freeblock);
SUPERB_UNLOCK(fs);
return 0;
}
/* No space to push. */
/* Make this block to freeblock list.and current cache moved to this. */
if (!(buf = scratch_read(fs, blk))) {
SUPERB_UNLOCK(fs);
return EIO; /* Fatal */
}
struct v7fs_freeblock *fb = (struct v7fs_freeblock *)buf;
fb->nfreeblock = V7FS_MAX_FREEBLOCK;
int i;
for (i = 0; i < V7FS_MAX_FREEBLOCK; i++)
fb->freeblock[i] = V7FS_VAL32(fs, sb->freeblock[i]);
if (!fs->io.write(fs->io.cookie, (uint8_t *)fb, blk)) {
error = EIO; /* Fatal */
} else {
/* Link. on next allocate, this block is used as datablock, */
/* and swap outed freeblock list is restored. */
sb->freeblock[0] = blk;
sb->nfreeblock = 1;
sb->total_freeblock++;
sb->modified = 1;
DPRINTF("n_freeblock=%d\n", sb->total_freeblock);
}
SUPERB_UNLOCK(fs);
scratch_free(fs, buf);
return error;
}
int
v7fs_datablock_addr(size_t sz, struct v7fs_daddr_map *map)
{
#define NIDX V7FS_DADDR_PER_BLOCK
#define DIRECT_SZ (V7FS_NADDR_DIRECT * V7FS_BSIZE)
#define IDX1_SZ (NIDX * V7FS_BSIZE)
#define IDX2_SZ (NIDX * NIDX * V7FS_BSIZE)
#define ROUND(x, a) ((((x) + ((a) - 1)) & ~((a) - 1)))
if (!sz) {
map->level = 0;
map->index[0] = 0;
return 0;
}
sz = V7FS_ROUND_BSIZE(sz);
/* Direct */
if (sz <= DIRECT_SZ) {
map->level = 0;
map->index[0] = (sz >> V7FS_BSHIFT) - 1;
return 0;
}
/* Index 1 */
sz -= DIRECT_SZ;
if (sz <= IDX1_SZ) {
map->level = 1;
map->index[0] = (sz >> V7FS_BSHIFT) - 1;
return 0;
}
sz -= IDX1_SZ;
/* Index 2 */
if (sz <= IDX2_SZ) {
map->level = 2;
map->index[0] = ROUND(sz, IDX1_SZ) / IDX1_SZ - 1;
map->index[1] = ((sz - (map->index[0] * IDX1_SZ)) >>
V7FS_BSHIFT) - 1;
return 0;
}
sz -= IDX2_SZ;
/* Index 3 */
map->level = 3;
map->index[0] = ROUND(sz, IDX2_SZ) / IDX2_SZ - 1;
sz -= map->index[0] * IDX2_SZ;
map->index[1] = ROUND(sz, IDX1_SZ) / IDX1_SZ - 1;
sz -= map->index[1] * IDX1_SZ;
map->index[2] = (sz >> V7FS_BSHIFT) - 1;
return map->index[2] >= NIDX ? ENOSPC : 0;
}
int
v7fs_datablock_foreach(struct v7fs_self *fs, struct v7fs_inode *p,
int (*func)(struct v7fs_self *, void *, v7fs_daddr_t, size_t), void *ctx)
{
size_t i;
v7fs_daddr_t blk, blk2;
size_t filesize;
bool last;
int ret;
if (!(filesize = v7fs_inode_filesize(p)))
return V7FS_ITERATOR_END;
#ifdef V7FS_DATABLOCK_DEBUG
size_t sz = filesize;
#endif
/* Direct */
for (i = 0; i < V7FS_NADDR_DIRECT; i++, filesize -= V7FS_BSIZE) {
blk = p->addr[i];
if (!datablock_number_sanity(fs, blk)) {
DPRINTF("inode#%d direct=%zu filesize=%zu\n",
p->inode_number, i, sz);
return EIO;
}
last = filesize <= V7FS_BSIZE;
if ((ret = func(fs, ctx, blk, last ? filesize : V7FS_BSIZE)))
return ret;
if (last)
return V7FS_ITERATOR_END;
}
/* Index 1 */
blk = p->addr[V7FS_NADDR_INDEX1];
if (!datablock_number_sanity(fs, blk))
return EIO;
if ((ret = v7fs_loop1(fs, blk, &filesize, func, ctx)))
return ret;
/* Index 2 */
blk = p->addr[V7FS_NADDR_INDEX2];
if (!datablock_number_sanity(fs, blk))
return EIO;
if ((ret = v7fs_loop2(fs, blk, &filesize, func, ctx)))
return ret;
/* Index 3 */
blk = p->addr[V7FS_NADDR_INDEX3];
if (!datablock_number_sanity(fs, blk))
return EIO;
for (i = 0; i < V7FS_DADDR_PER_BLOCK; i++) {
blk2 = v7fs_link(fs, blk, i);
if (!datablock_number_sanity(fs, blk))
return EIO;
if ((ret = v7fs_loop2(fs, blk2, &filesize, func, ctx)))
return ret;
}
return EFBIG;
}
static int
v7fs_loop2(struct v7fs_self *fs, v7fs_daddr_t listblk, size_t *filesize,
int (*func)(struct v7fs_self *, void *, v7fs_daddr_t, size_t), void *ctx)
{
v7fs_daddr_t blk;
int ret;
size_t j;
for (j = 0; j < V7FS_DADDR_PER_BLOCK; j++) {
blk = v7fs_link(fs, listblk, j);
if (!datablock_number_sanity(fs, blk))
return EIO;
if ((ret = v7fs_loop1(fs, blk, filesize, func, ctx)))
return ret;
}
return 0;
}
static int
v7fs_loop1(struct v7fs_self *fs, v7fs_daddr_t listblk, size_t *filesize,
int (*func)(struct v7fs_self *, void *, v7fs_daddr_t, size_t), void *ctx)
{
v7fs_daddr_t blk;
bool last;
int ret;
size_t k;
for (k = 0; k < V7FS_DADDR_PER_BLOCK; k++, *filesize -= V7FS_BSIZE) {
blk = v7fs_link(fs, listblk, k);
if (!datablock_number_sanity(fs, blk))
return EIO;
last = *filesize <= V7FS_BSIZE;
if ((ret = func(fs, ctx, blk, last ? *filesize : V7FS_BSIZE)))
return ret;
if (last)
return V7FS_ITERATOR_END;
}
return 0;
}
v7fs_daddr_t
v7fs_datablock_last(struct v7fs_self *fs, struct v7fs_inode *inode,
v7fs_off_t ofs)
{
struct v7fs_daddr_map map;
v7fs_daddr_t blk = 0;
v7fs_daddr_t *addr = inode->addr;
/* Inquire last data block location. */
if (v7fs_datablock_addr(ofs, &map) != 0)
return 0;
switch (map.level)
{
case 0: /*Direct */
blk = inode->addr[map.index[0]];
break;
case 1: /*Index1 */
blk = v7fs_link(fs, addr[V7FS_NADDR_INDEX1], map.index[0]);
break;
case 2: /*Index2 */
blk = v7fs_link(fs, v7fs_link(fs,
addr[V7FS_NADDR_INDEX2], map.index[0]), map.index[1]);
break;
case 3: /*Index3 */
blk = v7fs_link(fs, v7fs_link(fs, v7fs_link(fs,
addr[V7FS_NADDR_INDEX3], map.index[0]), map.index[1]),
map.index[2]);
break;
}
return blk;
}
int
v7fs_datablock_expand(struct v7fs_self *fs, struct v7fs_inode *inode, size_t sz)
{
size_t old_filesize = inode->filesize;
size_t new_filesize = old_filesize + sz;
struct v7fs_daddr_map oldmap, newmap;
v7fs_daddr_t blk, idxblk;
int error;
v7fs_daddr_t old_nblk = V7FS_ROUND_BSIZE(old_filesize) >> V7FS_BSHIFT;
v7fs_daddr_t new_nblk = V7FS_ROUND_BSIZE(new_filesize) >> V7FS_BSHIFT;
if (old_nblk == new_nblk) {
inode->filesize += sz;
v7fs_inode_writeback(fs, inode);
return 0; /* no need to expand. */
}
struct v7fs_inode backup = *inode;
v7fs_daddr_t required_blk = new_nblk - old_nblk;
DPRINTF("%zu->%zu, required block=%d\n", old_filesize, new_filesize,
required_blk);
v7fs_datablock_addr(old_filesize, &oldmap);
v7fs_daddr_t i;
for (i = 0; i < required_blk; i++) {
v7fs_datablock_addr(old_filesize + (i+1) * V7FS_BSIZE, &newmap);
daddr_map_dump(&oldmap);
daddr_map_dump(&newmap);
if (oldmap.level != newmap.level) {
/* Allocate index area */
if ((error = v7fs_datablock_allocate(fs, &idxblk)))
return error;
switch (newmap.level) {
case 1:
DPRINTF("0->1\n");
inode->addr[V7FS_NADDR_INDEX1] = idxblk;
blk = v7fs_add_leaf(fs, idxblk, 0);
break;
case 2:
DPRINTF("1->2\n");
inode->addr[V7FS_NADDR_INDEX2] = idxblk;
blk = v7fs_add_leaf(fs, v7fs_add_leaf(fs,
idxblk, 0), 0);
break;
case 3:
DPRINTF("2->3\n");
inode->addr[V7FS_NADDR_INDEX3] = idxblk;
blk = v7fs_add_leaf(fs, v7fs_add_leaf(fs,
v7fs_add_leaf(fs, idxblk, 0), 0), 0);
break;
}
} else {
switch (newmap.level) {
case 0:
if ((error = v7fs_datablock_allocate(fs, &blk)))
return error;
inode->addr[newmap.index[0]] = blk;
DPRINTF("direct index %d = blk%d\n",
newmap.index[0], blk);
break;
case 1:
idxblk = inode->addr[V7FS_NADDR_INDEX1];
blk = v7fs_add_leaf(fs, idxblk,
newmap.index[0]);
break;
case 2:
idxblk = inode->addr[V7FS_NADDR_INDEX2];
if (oldmap.index[0] != newmap.index[0]) {
v7fs_add_leaf(fs, idxblk,
newmap.index[0]);
}
blk = v7fs_add_leaf(fs, v7fs_link(fs,idxblk,
newmap.index[0]), newmap.index[1]);
break;
case 3:
idxblk = inode->addr[V7FS_NADDR_INDEX3];
if (oldmap.index[0] != newmap.index[0]) {
v7fs_add_leaf(fs, idxblk,
newmap.index[0]);
}
if (oldmap.index[1] != newmap.index[1]) {
v7fs_add_leaf(fs, v7fs_link(fs, idxblk,
newmap.index[0]), newmap.index[1]);
}
blk = v7fs_add_leaf(fs, v7fs_link(fs,
v7fs_link(fs, idxblk, newmap.index[0]),
newmap.index[1]), newmap.index[2]);
break;
}
}
if (!blk) {
*inode = backup; /* structure copy; */
return ENOSPC;
}
oldmap = newmap;
}
inode->filesize += sz;
v7fs_inode_writeback(fs, inode);
return 0;
}
static v7fs_daddr_t
v7fs_link(struct v7fs_self *fs, v7fs_daddr_t listblk, int n)
{
v7fs_daddr_t *list;
v7fs_daddr_t blk;
void *buf;
if (!datablock_number_sanity(fs, listblk))
return 0;
if (!(buf = scratch_read(fs, listblk)))
return 0;
list = (v7fs_daddr_t *)buf;
blk = V7FS_VAL32(fs, list[n]);
scratch_free(fs, buf);
if (!datablock_number_sanity(fs, blk))
return 0;
return blk;
}
static v7fs_daddr_t
v7fs_add_leaf(struct v7fs_self *fs, v7fs_daddr_t up, int idx)
{
v7fs_daddr_t newblk;
v7fs_daddr_t *daddr_list;
int error = 0;
void *buf;
if (!up)
return 0;
if (!datablock_number_sanity(fs, up))
return 0;
if ((error = v7fs_datablock_allocate(fs, &newblk)))
return 0;
if (!(buf = scratch_read(fs, up)))
return 0;
daddr_list = (v7fs_daddr_t *)buf;
daddr_list[idx] = V7FS_VAL32(fs, newblk);
if (!fs->io.write(fs->io.cookie, buf, up))
newblk = 0;
scratch_free(fs, buf);
return newblk;
}
int
v7fs_datablock_contract(struct v7fs_self *fs, struct v7fs_inode *inode,
size_t sz)
{
size_t old_filesize = inode->filesize;
size_t new_filesize = old_filesize - sz;
struct v7fs_daddr_map oldmap, newmap;
v7fs_daddr_t blk, idxblk;
int error = 0;
v7fs_daddr_t old_nblk = V7FS_ROUND_BSIZE(old_filesize) >> V7FS_BSHIFT;
v7fs_daddr_t new_nblk = V7FS_ROUND_BSIZE(new_filesize) >> V7FS_BSHIFT;
if (old_nblk == new_nblk) {
inode->filesize -= sz;
v7fs_inode_writeback(fs, inode);
return 0; /* no need to contract; */
}
v7fs_daddr_t erase_blk = old_nblk - new_nblk;
DPRINTF("%zu->%zu # of erased block=%d\n", old_filesize, new_filesize,
erase_blk);
v7fs_datablock_addr(old_filesize, &oldmap);
v7fs_daddr_t i;
for (i = 0; i < erase_blk; i++) {
v7fs_datablock_addr(old_filesize - (i+1) * V7FS_BSIZE, &newmap);
if (oldmap.level != newmap.level) {
switch (newmap.level) {
case 0: /*1->0 */
DPRINTF("1->0\n");
idxblk = inode->addr[V7FS_NADDR_INDEX1];
inode->addr[V7FS_NADDR_INDEX1] = 0;
error = v7fs_datablock_deallocate(fs,
v7fs_remove_self(fs, idxblk));
break;
case 1: /*2->1 */
DPRINTF("2->1\n");
idxblk = inode->addr[V7FS_NADDR_INDEX2];
inode->addr[V7FS_NADDR_INDEX2] = 0;
error = v7fs_datablock_deallocate(fs,
v7fs_remove_self(fs, v7fs_remove_self(fs,
idxblk)));
break;
case 2:/*3->2 */
DPRINTF("3->2\n");
idxblk = inode->addr[V7FS_NADDR_INDEX3];
inode->addr[V7FS_NADDR_INDEX3] = 0;
error = v7fs_datablock_deallocate(fs,
v7fs_remove_self(fs, v7fs_remove_self(fs,
v7fs_remove_self(fs, idxblk))));
break;
}
} else {
switch (newmap.level) {
case 0:
DPRINTF("[0] %d\n", oldmap.index[0]);
blk = inode->addr[oldmap.index[0]];
error = v7fs_datablock_deallocate(fs, blk);
break;
case 1:
DPRINTF("[1] %d\n", oldmap.index[0]);
idxblk = inode->addr[V7FS_NADDR_INDEX1];
v7fs_remove_leaf(fs, idxblk, oldmap.index[0]);
break;
case 2:
DPRINTF("[2] %d %d\n", oldmap.index[0],
oldmap.index[1]);
idxblk = inode->addr[V7FS_NADDR_INDEX2];
v7fs_remove_leaf(fs, v7fs_link(fs, idxblk,
oldmap.index[0]), oldmap.index[1]);
if (oldmap.index[0] != newmap.index[0]) {
v7fs_remove_leaf(fs, idxblk,
oldmap.index[0]);
}
break;
case 3:
DPRINTF("[2] %d %d %d\n", oldmap.index[0],
oldmap.index[1], oldmap.index[2]);
idxblk = inode->addr[V7FS_NADDR_INDEX3];
v7fs_remove_leaf(fs, v7fs_link(fs,
v7fs_link(fs, idxblk, oldmap.index[0]),
oldmap.index[1]), oldmap.index[2]);
if (oldmap.index[1] != newmap.index[1]) {
v7fs_remove_leaf(fs, v7fs_link(fs,
idxblk, oldmap.index[0]),
oldmap.index[1]);
}
if (oldmap.index[0] != newmap.index[0]) {
v7fs_remove_leaf(fs, idxblk,
oldmap.index[0]);
}
break;
}
}
oldmap = newmap;
}
inode->filesize -= sz;
v7fs_inode_writeback(fs, inode);
return error;
}
static v7fs_daddr_t
v7fs_unlink(struct v7fs_self *fs, v7fs_daddr_t idxblk, int n)
{
v7fs_daddr_t *daddr_list;
v7fs_daddr_t blk;
void *buf;
if (!(buf = scratch_read(fs, idxblk)))
return 0;
daddr_list = (v7fs_daddr_t *)buf;
blk = V7FS_VAL32(fs, daddr_list[n]);
daddr_list[n] = 0;
fs->io.write(fs->io.cookie, buf, idxblk);
scratch_free(fs, buf);
return blk; /* unlinked block. */
}
static v7fs_daddr_t
v7fs_remove_self(struct v7fs_self *fs, v7fs_daddr_t up)
{
v7fs_daddr_t down;
if (!datablock_number_sanity(fs, up))
return 0;
/* At 1st, remove from datablock list. */
down = v7fs_unlink(fs, up, 0);
/* link self to freelist. */
v7fs_datablock_deallocate(fs, up);
return down;
}
static v7fs_daddr_t
v7fs_remove_leaf(struct v7fs_self *fs, v7fs_daddr_t up, int n)
{
v7fs_daddr_t down;
if (!datablock_number_sanity(fs, up))
return 0;
/* At 1st, remove from datablock list. */
down = v7fs_unlink(fs, up, n);
/* link leaf to freelist. */
v7fs_datablock_deallocate(fs, down);
return down;
}
int
v7fs_datablock_size_change(struct v7fs_self *fs, size_t newsz,
struct v7fs_inode *inode)
{
ssize_t diff = newsz - v7fs_inode_filesize(inode);
int error = 0;
if (diff > 0)
error = v7fs_datablock_expand(fs, inode, diff);
else if (diff < 0)
error = v7fs_datablock_contract(fs, inode, -diff);
return error;
}
#ifdef V7FS_DATABLOCK_DEBUG
void
daddr_map_dump(const struct v7fs_daddr_map *map)
{
DPRINTF("level %d ", map->level);
int m, n = !map->level ? 1 : map->level;
for (m = 0; m < n; m++)
printf("[%d]", map->index[m]);
printf("\n");
}
#endif

View file

@ -0,0 +1,52 @@
/* $NetBSD: v7fs_datablock.h,v 1.2 2011/07/16 12:35:32 uch Exp $ */
/*-
* Copyright (c) 2011 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by UCHIYAMA Yasushi.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _V7FS_DATABLOCK_H_
#define _V7FS_DATABLOCK_H_
__BEGIN_DECLS
bool datablock_number_sanity(const struct v7fs_self *, v7fs_daddr_t);
int v7fs_datablock_allocate(struct v7fs_self *, v7fs_daddr_t *);
int v7fs_datablock_foreach(struct v7fs_self *, struct v7fs_inode *,
int (*)(struct v7fs_self *, void *, v7fs_daddr_t, size_t), void *);
v7fs_daddr_t v7fs_datablock_last(struct v7fs_self *, struct v7fs_inode *,
v7fs_off_t);
int v7fs_datablock_expand(struct v7fs_self *, struct v7fs_inode *, size_t);
int v7fs_datablock_contract(struct v7fs_self *, struct v7fs_inode *, size_t);
int v7fs_datablock_size_change(struct v7fs_self *, size_t, struct v7fs_inode *);
struct v7fs_daddr_map {
int level; /* direct, index1, index2, index3 */
v7fs_daddr_t index[3];
};
int v7fs_datablock_addr(size_t, struct v7fs_daddr_map *);
__END_DECLS
#endif /*!_V7FS_INODE_H_ */

89
sys/fs/v7fs/v7fs_dirent.c Normal file
View file

@ -0,0 +1,89 @@
/* $NetBSD: v7fs_dirent.c,v 1.2 2011/07/18 21:51:49 apb Exp $ */
/*-
* Copyright (c) 2011 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by UCHIYAMA Yasushi.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#if HAVE_NBTOOL_CONFIG_H
#include "nbtool_config.h"
#endif
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: v7fs_dirent.c,v 1.2 2011/07/18 21:51:49 apb Exp $");
#if defined _KERNEL_OPT
#include "opt_v7fs.h"
#endif
#ifdef _KERNEL
#include <sys/systm.h>
#include <sys/param.h>
#else
#include <stdio.h>
#include <string.h>
#endif
#include "v7fs.h"
#include "v7fs_impl.h"
#include "v7fs_endian.h"
#include "v7fs_inode.h"
#include "v7fs_dirent.h"
#ifdef V7FS_DIRENT_DEBUG
#define DPRINTF(fmt, args...) printf("%s: " fmt, __func__, ##args)
#else
#define DPRINTF(fmt, args...) ((void)0)
#endif
bool
v7fs_dirent_endian_convert(struct v7fs_self *fs, struct v7fs_dirent *dir, int n)
{
struct v7fs_superblock *sb = &fs->superblock;
int i;
v7fs_ino_t ino;
bool ok = true;
for (i = 0; i < n; i++, dir++) {
ino = V7FS_VAL16(fs, dir->inode_number);
if (v7fs_inode_number_sanity(sb, ino)) {
DPRINTF("Invalid inode# %d %s\n", ino, dir->name);
ok = false;
}
dir->inode_number = ino;
}
return ok;
}
void
v7fs_dirent_filename(char *dst/* size must be V7FS_NAME_MAX + 1 */,
const char *src)
{
strncpy(dst, src, V7FS_NAME_MAX);
dst[V7FS_NAME_MAX] = '\0';
}

38
sys/fs/v7fs/v7fs_dirent.h Normal file
View file

@ -0,0 +1,38 @@
/* $NetBSD: v7fs_dirent.h,v 1.1 2011/06/27 11:52:24 uch Exp $ */
/*-
* Copyright (c) 2011 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by UCHIYAMA Yasushi.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _V7FS_DIRENT_H_
#define _V7FS_DIRENT_H_
__BEGIN_DECLS
bool v7fs_dirent_endian_convert(struct v7fs_self *, struct v7fs_dirent *, int);
void v7fs_dirent_filename(char *, const char *);
__END_DECLS
#endif /*!_V7FS_DIRENT_H_ */

231
sys/fs/v7fs/v7fs_endian.c Normal file
View file

@ -0,0 +1,231 @@
/* $NetBSD: v7fs_endian.c,v 1.2 2011/07/18 21:51:49 apb Exp $ */
/*-
* Copyright (c) 2011 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by UCHIYAMA Yasushi.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#if HAVE_NBTOOL_CONFIG_H
#include "nbtool_config.h"
#endif
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: v7fs_endian.c,v 1.2 2011/07/18 21:51:49 apb Exp $");
#if defined _KERNEL_OPT
#include "opt_v7fs.h"
#endif
#include "v7fs.h"
#include "v7fs_endian.h"
#include "v7fs_impl.h"
#ifndef BYTE_ORDER
#error
#endif
/* PDP to Little */
#define bswap32pdp_le(x) \
((uint32_t) \
((((x) & 0xffff0000) >> 16) | \
(((x) & 0x0000ffff) << 16)))
/* PDP to Big */
#define bswap32pdp_be(x) \
((uint32_t) \
((((x) & 0xff00ff00) >> 8) | \
(((x) & 0x00ff00ff) << 8)))
#ifdef V7FS_EI
static uint32_t val32_normal_order(uint32_t);
static uint32_t val32_reverse_order(uint32_t);
#if BYTE_ORDER == LITTLE_ENDIAN
static uint32_t val32_pdp_to_little(uint32_t);
#else
static uint32_t val32_pdp_to_big(uint32_t);
#endif
static uint16_t val16_normal_order(uint16_t);
static uint16_t val16_reverse_order(uint16_t);
static v7fs_daddr_t val24_reverse_order_read(uint8_t *);
static void val24_reverse_order_write(v7fs_daddr_t, uint8_t *);
static v7fs_daddr_t val24_pdp_read(uint8_t *);
static void val24_pdp_write(v7fs_daddr_t, uint8_t *);
static uint32_t
val32_normal_order(uint32_t v)
{
return v;
}
static uint32_t
val32_reverse_order(uint32_t v)
{
return bswap32(v);
}
#if BYTE_ORDER == LITTLE_ENDIAN
static uint32_t
val32_pdp_to_little(uint32_t v)
{
return bswap32pdp_le(v);
}
#else
static uint32_t
val32_pdp_to_big(uint32_t v)
{
return bswap32pdp_be(v);
}
#endif
static uint16_t
val16_normal_order(uint16_t v)
{
return v;
}
static uint16_t
val16_reverse_order(uint16_t v)
{
return bswap16(v);
}
static v7fs_daddr_t
val24_reverse_order_read(uint8_t *a)
{
#if BYTE_ORDER == LITTLE_ENDIAN
return (a[0] << 16) | (a[1] << 8) | a[2];
#else
return (a[2] << 16) | (a[1] << 8) | a[0];
#endif
}
static void
val24_reverse_order_write(v7fs_daddr_t addr, uint8_t *a)
{
#if BYTE_ORDER == LITTLE_ENDIAN
a[0] = (addr >> 16) & 0xff;
a[1] = (addr >> 8) & 0xff;
a[2] = addr & 0xff;
#else
a[0] = addr & 0xff;
a[1] = (addr >> 8) & 0xff;
a[2] = (addr >> 16) & 0xff;
#endif
}
static v7fs_daddr_t
val24_pdp_read(uint8_t *a)
{
return (a[0] << 16) | a[1] | (a[2] << 8);
}
static void
val24_pdp_write(v7fs_daddr_t addr, uint8_t *a)
{
a[0] = (addr >> 16) & 0xff;
a[1] = addr & 0xff;
a[2] = (addr >> 8) & 0xff;
}
void
v7fs_endian_init(struct v7fs_self *fs)
{
struct endian_conversion_ops *ops = &fs->val;
switch (fs->endian)
{
#if BYTE_ORDER == LITTLE_ENDIAN
case LITTLE_ENDIAN:
ops->conv32 = val32_normal_order;
ops->conv16 = val16_normal_order;
ops->conv24read = val24_normal_order_read;
ops->conv24write = val24_normal_order_write;
break;
case BIG_ENDIAN:
ops->conv32 = val32_reverse_order;
ops->conv16 = val16_reverse_order;
ops->conv24read = val24_reverse_order_read;
ops->conv24write = val24_reverse_order_write;
break;
case PDP_ENDIAN:
ops->conv32 = val32_pdp_to_little;
ops->conv16 = val16_normal_order;
ops->conv24read = val24_pdp_read;
ops->conv24write = val24_pdp_write;
break;
#else /* BIG_ENDIAN */
case LITTLE_ENDIAN:
ops->conv32 = val32_reverse_order;
ops->conv16 = val16_reverse_order;
ops->conv24read = val24_reverse_order_read;
ops->conv24write = val24_reverse_order_write;
break;
case BIG_ENDIAN:
ops->conv32 = val32_normal_order;
ops->conv16 = val16_normal_order;
ops->conv24read = val24_normal_order_read;
ops->conv24write = val24_normal_order_write;
break;
case PDP_ENDIAN:
ops->conv32 = val32_pdp_to_big;
ops->conv16 = val16_reverse_order;
ops->conv24read = val24_pdp_read;
ops->conv24write = val24_pdp_write;
break;
#endif
}
}
#endif /* V7FS_EI */
v7fs_daddr_t
val24_normal_order_read(uint8_t *a)
{
/*(v7fs_daddr_t)cast is required for int 16bit system. */
#if BYTE_ORDER == LITTLE_ENDIAN
return ((v7fs_daddr_t)a[2] << 16) | ((v7fs_daddr_t)a[1] << 8) |
(v7fs_daddr_t)a[0];
#else
return ((v7fs_daddr_t)a[0] << 16) | ((v7fs_daddr_t)a[1] << 8) |
(v7fs_daddr_t)a[2];
#endif
}
void
val24_normal_order_write(v7fs_daddr_t addr, uint8_t *a)
{
#if BYTE_ORDER == LITTLE_ENDIAN
a[0] = addr & 0xff;
a[1] = (addr >> 8) & 0xff;
a[2] = (addr >> 16) & 0xff;
#else
a[0] = (addr >> 16) & 0xff;
a[1] = (addr >> 8) & 0xff;
a[2] = addr & 0xff;
#endif
}

52
sys/fs/v7fs/v7fs_endian.h Normal file
View file

@ -0,0 +1,52 @@
/* $NetBSD: v7fs_endian.h,v 1.1 2011/06/27 11:52:24 uch Exp $ */
/*-
* Copyright (c) 2011 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by UCHIYAMA Yasushi.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _V7FS_ENDIAN_H_
#define _V7FS_ENDIAN_H_
struct v7fs_self;
__BEGIN_DECLS;
v7fs_daddr_t val24_normal_order_read(uint8_t *);
void val24_normal_order_write(v7fs_daddr_t, uint8_t *);
__END_DECLS
#ifdef V7FS_EI
#define V7FS_VAL32(x, v) ((*(x)->val.conv32)(v))
#define V7FS_VAL16(x, v) ((*(x)->val.conv16)(v))
#define V7FS_VAL24_READ(x, a) ((*(x)->val.conv24read)(a))
#define V7FS_VAL24_WRITE(x, v, a) ((*(x)->val.conv24write)(v, a))
void v7fs_endian_init(struct v7fs_self *);
#else
#define V7FS_VAL32(x, v) (v)
#define V7FS_VAL16(x, v) (v)
#define V7FS_VAL24_READ(x, a) (val24_normal_order_read(a))
#define V7FS_VAL24_WRITE(x, v, a) (val24_normal_order_write(v, a))
#endif /*V7FS_EI */
#endif /*!_V7FS_ENDIAN_H_ */

262
sys/fs/v7fs/v7fs_extern.c Normal file
View file

@ -0,0 +1,262 @@
/* $NetBSD: v7fs_extern.c,v 1.1 2011/06/27 11:52:24 uch Exp $ */
/*-
* Copyright (c) 2004, 2011 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by UCHIYAMA Yasushi.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: v7fs_extern.c,v 1.1 2011/06/27 11:52:24 uch Exp $");
#if defined _KERNEL_OPT
#include "opt_v7fs.h"
#endif
#include <sys/resource.h>
#include <sys/param.h>
#include <sys/vnode.h>
#include <sys/mount.h>
#include <sys/module.h>
#include <miscfs/fifofs/fifo.h>
#include <miscfs/genfs/genfs.h>
#include <miscfs/genfs/genfs_node.h>
#include <fs/v7fs/v7fs_extern.h>
MODULE(MODULE_CLASS_VFS, v7fs, NULL);
/* External interfaces */
int (**v7fs_vnodeop_p)(void *); /* filled by getnewvnode (vnode.h) */
const struct vnodeopv_entry_desc v7fs_vnodeop_entries[] = {
{ &vop_default_desc, vn_default_error },
{ &vop_lookup_desc, v7fs_lookup }, /* lookup */
{ &vop_create_desc, v7fs_create }, /* create */
{ &vop_mknod_desc, v7fs_mknod }, /* mknod */
{ &vop_open_desc, v7fs_open }, /* open */
{ &vop_close_desc, v7fs_close }, /* close */
{ &vop_access_desc, v7fs_access }, /* access */
{ &vop_getattr_desc, v7fs_getattr }, /* getattr */
{ &vop_setattr_desc, v7fs_setattr }, /* setattr */
{ &vop_read_desc, v7fs_read }, /* read */
{ &vop_write_desc, v7fs_write }, /* write */
{ &vop_fcntl_desc, genfs_fcntl }, /* fcntl */
{ &vop_ioctl_desc, genfs_enoioctl }, /* ioctl */
{ &vop_poll_desc, genfs_poll }, /* poll */
{ &vop_kqfilter_desc, genfs_kqfilter }, /* kqfilter */
{ &vop_revoke_desc, genfs_revoke }, /* revoke */
{ &vop_mmap_desc, genfs_mmap }, /* mmap */
{ &vop_fsync_desc, v7fs_fsync }, /* fsync */
{ &vop_seek_desc, genfs_seek }, /* seek */
{ &vop_remove_desc, v7fs_remove }, /* remove */
{ &vop_link_desc, v7fs_link }, /* link */
{ &vop_rename_desc, v7fs_rename }, /* rename */
{ &vop_mkdir_desc, v7fs_mkdir }, /* mkdir */
{ &vop_rmdir_desc, v7fs_rmdir }, /* rmdir */
{ &vop_symlink_desc, v7fs_symlink }, /* symlink */
{ &vop_readdir_desc, v7fs_readdir }, /* readdir */
{ &vop_readlink_desc, v7fs_readlink }, /* readlink */
{ &vop_abortop_desc, genfs_abortop }, /* abortop */
{ &vop_inactive_desc, v7fs_inactive }, /* inactive */
{ &vop_reclaim_desc, v7fs_reclaim }, /* reclaim */
{ &vop_lock_desc, genfs_lock }, /* lock */
{ &vop_unlock_desc, genfs_unlock }, /* unlock */
{ &vop_bmap_desc, v7fs_bmap }, /* bmap */
{ &vop_strategy_desc, v7fs_strategy }, /* strategy */
{ &vop_print_desc, v7fs_print }, /* print */
{ &vop_islocked_desc, genfs_islocked }, /* islocked */
{ &vop_pathconf_desc, v7fs_pathconf }, /* pathconf */
{ &vop_advlock_desc, v7fs_advlock }, /* advlock */
{ &vop_bwrite_desc, vn_bwrite }, /* bwrite */
{ &vop_getpages_desc, genfs_getpages }, /* getpages */
{ &vop_putpages_desc, genfs_putpages }, /* putpages */
{ NULL, NULL }
};
int (**v7fs_specop_p)(void *);
const struct vnodeopv_entry_desc v7fs_specop_entries[] = {
{ &vop_default_desc, vn_default_error },
{ &vop_lookup_desc, spec_lookup }, /* lookup */
{ &vop_create_desc, spec_create }, /* create xxx*/
{ &vop_mknod_desc, spec_mknod }, /* mknod xxx*/
{ &vop_open_desc, spec_open }, /* open */
{ &vop_close_desc, spec_close }, /* close */
{ &vop_access_desc, v7fs_access }, /* access */
{ &vop_getattr_desc, v7fs_getattr }, /* getattr */
{ &vop_setattr_desc, v7fs_setattr }, /* setattr */
{ &vop_read_desc, spec_read }, /* read */
{ &vop_write_desc, spec_write }, /* write */
{ &vop_ioctl_desc, spec_ioctl }, /* ioctl */
{ &vop_fcntl_desc, genfs_fcntl }, /* fcntl */
{ &vop_poll_desc, spec_poll }, /* poll */
{ &vop_kqfilter_desc, spec_kqfilter }, /* kqfilter */
{ &vop_revoke_desc, spec_revoke }, /* revoke */
{ &vop_mmap_desc, spec_mmap }, /* mmap */
{ &vop_fsync_desc, spec_fsync }, /* fsync */
{ &vop_seek_desc, spec_seek }, /* seek */
{ &vop_remove_desc, spec_remove }, /* remove */
{ &vop_link_desc, spec_link }, /* link */
{ &vop_rename_desc, spec_rename }, /* rename */
{ &vop_mkdir_desc, spec_mkdir }, /* mkdir */
{ &vop_rmdir_desc, spec_rmdir }, /* rmdir */
{ &vop_symlink_desc, spec_symlink }, /* symlink */
{ &vop_readdir_desc, spec_readdir }, /* readdir */
{ &vop_readlink_desc, spec_readlink }, /* readlink */
{ &vop_abortop_desc, spec_abortop }, /* abortop */
{ &vop_inactive_desc, v7fs_inactive }, /* inactive */
{ &vop_reclaim_desc, v7fs_reclaim }, /* reclaim */
{ &vop_lock_desc, genfs_lock }, /* lock */
{ &vop_unlock_desc, genfs_unlock }, /* unlock */
{ &vop_bmap_desc, spec_bmap }, /* bmap */
{ &vop_strategy_desc, spec_strategy }, /* strategy */
{ &vop_print_desc, spec_print }, /* print */
{ &vop_islocked_desc, genfs_islocked }, /* islocked */
{ &vop_pathconf_desc, spec_pathconf }, /* pathconf */
{ &vop_advlock_desc, spec_advlock }, /* advlock */
{ &vop_bwrite_desc, vn_bwrite }, /* bwrite */
{ &vop_getpages_desc, spec_getpages }, /* getpages */
{ &vop_putpages_desc, spec_putpages }, /* putpages */
{ NULL, NULL }
};
int (**v7fs_fifoop_p)(void *);
const struct vnodeopv_entry_desc v7fs_fifoop_entries[] = {
{ &vop_default_desc, vn_default_error },
{ &vop_lookup_desc, vn_fifo_bypass }, /* lookup */
{ &vop_create_desc, vn_fifo_bypass }, /* create */
{ &vop_mknod_desc, vn_fifo_bypass }, /* mknod */
{ &vop_open_desc, vn_fifo_bypass }, /* open */
{ &vop_close_desc, vn_fifo_bypass }, /* close */
{ &vop_access_desc, v7fs_access }, /* access */
{ &vop_getattr_desc, v7fs_getattr }, /* getattr */
{ &vop_setattr_desc, v7fs_setattr }, /* setattr */
{ &vop_read_desc, vn_fifo_bypass }, /* read */
{ &vop_write_desc, vn_fifo_bypass }, /* write */
{ &vop_ioctl_desc, vn_fifo_bypass }, /* ioctl */
{ &vop_fcntl_desc, genfs_fcntl }, /* fcntl */
{ &vop_poll_desc, vn_fifo_bypass }, /* poll */
{ &vop_kqfilter_desc, vn_fifo_bypass }, /* kqfilter */
{ &vop_revoke_desc, vn_fifo_bypass }, /* revoke */
{ &vop_mmap_desc, vn_fifo_bypass }, /* mmap */
{ &vop_fsync_desc, vn_fifo_bypass }, /* fsync */
{ &vop_seek_desc, vn_fifo_bypass }, /* seek */
{ &vop_remove_desc, vn_fifo_bypass }, /* remove */
{ &vop_link_desc, vn_fifo_bypass }, /* link */
{ &vop_rename_desc, vn_fifo_bypass }, /* rename */
{ &vop_mkdir_desc, vn_fifo_bypass }, /* mkdir */
{ &vop_rmdir_desc, vn_fifo_bypass }, /* rmdir */
{ &vop_symlink_desc, vn_fifo_bypass }, /* symlink */
{ &vop_readdir_desc, vn_fifo_bypass }, /* readdir */
{ &vop_readlink_desc, vn_fifo_bypass }, /* readlink */
{ &vop_abortop_desc, vn_fifo_bypass }, /* abortop */
{ &vop_inactive_desc, v7fs_inactive }, /* inactive */
{ &vop_reclaim_desc, v7fs_reclaim }, /* reclaim */
{ &vop_lock_desc, vn_fifo_bypass }, /* lock */
{ &vop_unlock_desc, vn_fifo_bypass }, /* unlock */
{ &vop_bmap_desc, vn_fifo_bypass }, /* bmap */
{ &vop_strategy_desc, vn_fifo_bypass }, /* strategy */
{ &vop_print_desc, vn_fifo_bypass }, /* print */
{ &vop_islocked_desc, vn_fifo_bypass }, /* islocked */
{ &vop_pathconf_desc, vn_fifo_bypass }, /* pathconf */
{ &vop_advlock_desc, vn_fifo_bypass }, /* advlock */
{ &vop_bwrite_desc, vn_bwrite }, /* bwrite */
{ &vop_putpages_desc, vn_fifo_bypass }, /* putpages */
{ NULL, NULL }
};
const struct vnodeopv_desc v7fs_fifoop_opv_desc = {
&v7fs_fifoop_p,
v7fs_fifoop_entries
};
const struct vnodeopv_desc v7fs_vnodeop_opv_desc = {
&v7fs_vnodeop_p,
v7fs_vnodeop_entries
};
const struct vnodeopv_desc v7fs_specop_opv_desc = {
&v7fs_specop_p,
v7fs_specop_entries
};
const struct vnodeopv_desc *v7fs_vnodeopv_descs[] = {
&v7fs_vnodeop_opv_desc,
&v7fs_specop_opv_desc,
&v7fs_fifoop_opv_desc,
NULL,
};
const struct genfs_ops v7fs_genfsops = {
.gop_size = genfs_size,
.gop_alloc = v7fs_gop_alloc,
.gop_write = genfs_gop_write,
};
struct vfsops v7fs_vfsops = {
MOUNT_V7FS,
sizeof(struct v7fs_args),
v7fs_mount,
v7fs_start,
v7fs_unmount,
v7fs_root,
(void *)eopnotsupp, /* vfs_quotactl */
v7fs_statvfs,
v7fs_sync,
v7fs_vget,
v7fs_fhtovp,
v7fs_vptofh,
v7fs_init,
v7fs_reinit,
v7fs_done,
v7fs_mountroot,
(int (*)(struct mount *, struct vnode *, struct timespec *))
eopnotsupp, /* snapshot */
vfs_stdextattrctl,
(void *)eopnotsupp, /* vfs_suspendctl */
genfs_renamelock_enter,
genfs_renamelock_exit,
(void *)eopnotsupp,
v7fs_vnodeopv_descs,
0,
{ NULL, NULL }
};
static int
v7fs_modcmd(modcmd_t cmd, void *arg)
{
switch (cmd) {
case MODULE_CMD_INIT:
return vfs_attach(&v7fs_vfsops);
case MODULE_CMD_FINI:
return vfs_detach(&v7fs_vfsops);
default:
return ENOTTY;
}
}

116
sys/fs/v7fs/v7fs_extern.h Normal file
View file

@ -0,0 +1,116 @@
/* $NetBSD: v7fs_extern.h,v 1.1 2011/06/27 11:52:24 uch Exp $ */
/*-
* Copyright (c) 2004, 2011 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by UCHIYAMA Yasushi.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _FS_V7FS_EXTERN_H_
#define _FS_V7FS_EXTERN_H_
#include <fs/v7fs/v7fs_args.h>
#include <miscfs/genfs/genfs.h>
#include <miscfs/genfs/genfs_node.h>
#include <miscfs/specfs/specdev.h>
#include "v7fs.h"
#include "v7fs_impl.h"
#include "v7fs_inode.h"
struct v7fs_mount {
struct mount *mountp;
struct vnode *devvp; /* block device mounted vnode */
struct v7fs_self *core; /* filesystem dependent implementation*/
LIST_HEAD(, v7fs_node) v7fs_node_head;
};
struct v7fs_node {
struct genfs_node gnode;
struct v7fs_inode inode; /* filesystem dependent implementation */
struct vnode *vnode; /* back-link */
struct v7fs_mount *v7fsmount; /* our filesystem */
struct lockf *lockf; /* advlock */
int update_ctime;
int update_atime;
int update_mtime;
LIST_ENTRY(v7fs_node) link;
};
#define VFSTOV7FS(mp) ((struct v7fs_mount *)((mp)->mnt_data))
__BEGIN_DECLS
/* v-node ops. */
int v7fs_lookup(void *);
int v7fs_create(void *);
int v7fs_open(void *);
int v7fs_close(void *);
int v7fs_access(void *);
int v7fs_getattr(void *);
int v7fs_setattr(void *);
int v7fs_read(void *);
int v7fs_write(void *);
int v7fs_fsync(void *);
int v7fs_remove(void *);
int v7fs_rename(void *);
int v7fs_readdir(void *);
int v7fs_inactive(void *);
int v7fs_reclaim(void *);
int v7fs_bmap(void *);
int v7fs_strategy(void *);
int v7fs_print(void *);
int v7fs_advlock(void *);
int v7fs_pathconf(void *);
int v7fs_link(void *);
int v7fs_symlink(void *);
int v7fs_readlink(void *);
int v7fs_mkdir(void *);
int v7fs_rmdir(void *);
int v7fs_mknod(void *);
/* vfs ops. */
VFS_PROTOS(v7fs);
int v7fs_mountroot(void);
extern int (**v7fs_vnodeop_p)(void *);
extern int (**v7fs_specop_p)(void *);
extern int (**v7fs_fifoop_p)(void *);
/* genfs ops */
int v7fs_gop_alloc(struct vnode *, off_t, off_t, int, kauth_cred_t);
extern const struct genfs_ops v7fs_genfsops;
/* internal service */
int v7fs_update(struct vnode *, const struct timespec *,
const struct timespec *, int);
__END_DECLS
#endif /* _FS_V7FS_EXTERN_H_ */

422
sys/fs/v7fs/v7fs_file.c Normal file
View file

@ -0,0 +1,422 @@
/* $NetBSD: v7fs_file.c,v 1.5 2012/12/07 06:50:15 msaitoh Exp $ */
/*-
* Copyright (c) 2011 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by UCHIYAMA Yasushi.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#if HAVE_NBTOOL_CONFIG_H
#include "nbtool_config.h"
#endif
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: v7fs_file.c,v 1.5 2012/12/07 06:50:15 msaitoh Exp $");
#if defined _KERNEL_OPT
#include "opt_v7fs.h"
#endif
#include <sys/param.h>
#ifdef _KERNEL
#include <sys/systm.h>
#else
#include <stdio.h>
#include <string.h>
#include <errno.h>
#endif
#include "v7fs.h"
#include "v7fs_impl.h"
#include "v7fs_endian.h"
#include "v7fs_inode.h"
#include "v7fs_dirent.h"
#include "v7fs_file.h"
#include "v7fs_datablock.h"
#ifdef V7FS_FILE_DEBUG
#define DPRINTF(fmt, args...) printf("%s: " fmt, __func__, ##args)
#else
#define DPRINTF(fmt, args...) ((void)0)
#endif
static int lookup_subr(struct v7fs_self *, void *, v7fs_daddr_t, size_t);
static int remove_subr(struct v7fs_self *, void *, v7fs_daddr_t, size_t);
int
v7fs_file_lookup_by_name(struct v7fs_self *fs, struct v7fs_inode *parent_dir,
const char *name, v7fs_ino_t *ino)
{
char filename[V7FS_NAME_MAX + 1];
char *q;
int error;
size_t len;
if ((q = strchr(name, '/'))) {
/* Zap following path. */
len = MIN(V7FS_NAME_MAX, q - name);
memcpy(filename, name, len);
filename[len] = '\0'; /* '/' -> '\0' */
} else {
v7fs_dirent_filename(filename, name);
}
DPRINTF("%s(%s) dir=%d\n", filename, name, parent_dir->inode_number);
struct v7fs_lookup_arg lookup_arg = { .name = filename,
.inode_number = 0 };
if ((error = v7fs_datablock_foreach(fs, parent_dir, lookup_subr,
&lookup_arg)) != V7FS_ITERATOR_BREAK) {
DPRINTF("not found.\n");
return ENOENT;
}
*ino = lookup_arg.inode_number;
DPRINTF("done. ino=%d\n", *ino);
return 0;
}
static int
lookup_subr(struct v7fs_self *fs, void *ctx, v7fs_daddr_t blk, size_t sz)
{
struct v7fs_lookup_arg *p = (struct v7fs_lookup_arg *)ctx;
struct v7fs_dirent *dir;
const char *name = p->name;
void *buf;
size_t i, n;
int ret = 0;
if (!(buf = scratch_read(fs, blk)))
return EIO;
dir = (struct v7fs_dirent *)buf;
n = sz / sizeof(*dir);
v7fs_dirent_endian_convert(fs, dir, n);
for (i = 0; i < n; i++, dir++) {
if (dir->inode_number < 1) {
DPRINTF("*** bad inode #%d ***\n", dir->inode_number);
continue;
}
if (strncmp((const char *)dir->name, name, V7FS_NAME_MAX) == 0)
{
p->inode_number = dir->inode_number;
ret = V7FS_ITERATOR_BREAK; /* found */
break;
}
}
scratch_free(fs, buf);
return ret;
}
int
v7fs_file_allocate(struct v7fs_self *fs, struct v7fs_inode *parent_dir,
const char *srcname, struct v7fs_fileattr *attr, v7fs_ino_t *ino)
{
struct v7fs_inode inode;
char filename[V7FS_NAME_MAX + 1];
struct v7fs_dirent *dir;
int error;
/* Truncate filename. */
v7fs_dirent_filename(filename, srcname);
DPRINTF("%s(%s)\n", filename, srcname);
/* Check filename. */
if (v7fs_file_lookup_by_name(fs, parent_dir, filename, ino) == 0) {
DPRINTF("%s exists\n", filename);
return EEXIST;
}
/* Get new inode. */
if ((error = v7fs_inode_allocate(fs, ino)))
return error;
/* Set initial attribute. */
memset(&inode, 0, sizeof(inode));
inode.inode_number = *ino;
inode.mode = attr->mode;
inode.uid = attr->uid;
inode.gid = attr->gid;
if (attr->ctime)
inode.ctime = attr->ctime;
if (attr->mtime)
inode.mtime = attr->mtime;
if (attr->atime)
inode.atime = attr->atime;
switch (inode.mode & V7FS_IFMT) {
default:
DPRINTF("Can't allocate %o type.\n", inode.mode);
v7fs_inode_deallocate(fs, *ino);
return EINVAL;
case V7FS_IFCHR:
/* FALLTHROUGH */
case V7FS_IFBLK:
inode.nlink = 1;
inode.device = attr->device;
inode.addr[0] = inode.device;
break;
case V7FSBSD_IFFIFO:
/* FALLTHROUGH */
case V7FSBSD_IFSOCK:
/* FALLTHROUGH */
case V7FSBSD_IFLNK:
/* FALLTHROUGH */
case V7FS_IFREG:
inode.nlink = 1;
break;
case V7FS_IFDIR:
inode.nlink = 2; /* . + .. */
if ((error = v7fs_datablock_expand(fs, &inode, sizeof(*dir) * 2
))) {
v7fs_inode_deallocate(fs, *ino);
return error;
}
v7fs_daddr_t blk = inode.addr[0];
void *buf;
if (!(buf = scratch_read(fs, blk))) {
v7fs_inode_deallocate(fs, *ino);
return EIO;
}
dir = (struct v7fs_dirent *)buf;
strcpy(dir[0].name, ".");
dir[0].inode_number = V7FS_VAL16(fs, *ino);
strcpy(dir[1].name, "..");
dir[1].inode_number = V7FS_VAL16(fs, parent_dir->inode_number);
if (!fs->io.write(fs->io.cookie, buf, blk)) {
scratch_free(fs, buf);
return EIO;
}
scratch_free(fs, buf);
break;
}
v7fs_inode_writeback(fs, &inode);
/* Link this inode to parent directory. */
if ((error = v7fs_directory_add_entry(fs, parent_dir, *ino, filename)))
{
DPRINTF("can't add dirent.\n");
return error;
}
return 0;
}
int
v7fs_file_deallocate(struct v7fs_self *fs, struct v7fs_inode *parent_dir,
const char *name)
{
v7fs_ino_t ino;
struct v7fs_inode inode;
int error;
DPRINTF("%s\n", name);
if ((error = v7fs_file_lookup_by_name(fs, parent_dir, name, &ino))) {
DPRINTF("no such a file: %s\n", name);
return error;
}
DPRINTF("%s->#%d\n", name, ino);
if ((error = v7fs_inode_load(fs, &inode, ino)))
return error;
if (v7fs_inode_isdir(&inode)) {
char filename[V7FS_NAME_MAX + 1];
v7fs_dirent_filename(filename, name);
/* Check parent */
if (strncmp(filename, "..", V7FS_NAME_MAX) == 0) {
DPRINTF("can not remove '..'\n");
return EINVAL; /* t_vnops rename_dotdot */
}
/* Check empty */
if (v7fs_inode_filesize(&inode) !=
sizeof(struct v7fs_dirent) * 2 /*"." + ".."*/) {
DPRINTF("directory not empty.\n");
return ENOTEMPTY;/* t_vnops dir_noempty, rename_dir(6)*/
}
inode.nlink = 0; /* remove this. */
} else {
/* Decrement reference count. */
--inode.nlink; /* regular file. */
DPRINTF("%s nlink=%d\n", name, inode.nlink);
}
if ((error = v7fs_directory_remove_entry(fs, parent_dir, name)))
return error;
DPRINTF("remove dirent\n");
if (inode.nlink == 0) {
v7fs_datablock_contract(fs, &inode, inode.filesize);
DPRINTF("remove datablock\n");
v7fs_inode_deallocate(fs, ino);
DPRINTF("remove inode\n");
} else {
v7fs_inode_writeback(fs, &inode);
}
return 0;
}
int
v7fs_directory_add_entry(struct v7fs_self *fs, struct v7fs_inode *parent_dir,
v7fs_ino_t ino, const char *srcname)
{
struct v7fs_inode inode;
struct v7fs_dirent *dir;
int error = 0;
v7fs_daddr_t blk;
void *buf;
char filename[V7FS_NAME_MAX + 1];
/* Truncate filename. */
v7fs_dirent_filename(filename, srcname);
DPRINTF("%s(%s) %d\n", filename, srcname, ino);
/* Target inode */
if ((error = v7fs_inode_load(fs, &inode, ino)))
return error;
/* Expand datablock. */
if ((error = v7fs_datablock_expand(fs, parent_dir, sizeof(*dir))))
return error;
/* Read last entry. */
if (!(blk = v7fs_datablock_last(fs, parent_dir,
v7fs_inode_filesize(parent_dir))))
return EIO;
/* Load dirent block. This vnode(parent dir) is locked by VFS layer. */
if (!(buf = scratch_read(fs, blk)))
return EIO;
size_t sz = v7fs_inode_filesize(parent_dir);
sz = V7FS_RESIDUE_BSIZE(sz); /* last block payload. */
int n = sz / sizeof(*dir) - 1;
/* Add dirent. */
dir = (struct v7fs_dirent *)buf;
dir[n].inode_number = V7FS_VAL16(fs, ino);
memcpy((char *)dir[n].name, filename, V7FS_NAME_MAX);
/* Write back datablock */
if (!fs->io.write(fs->io.cookie, buf, blk))
error = EIO;
scratch_free(fs, buf);
if (v7fs_inode_isdir(&inode)) {
parent_dir->nlink++;
v7fs_inode_writeback(fs, parent_dir);
}
DPRINTF("done. (dirent size=%dbyte)\n", parent_dir->filesize);
return error;
}
int
v7fs_directory_remove_entry(struct v7fs_self *fs, struct v7fs_inode *parent_dir,
const char *name)
{
struct v7fs_inode inode;
int error;
struct v7fs_dirent lastdirent;
v7fs_daddr_t lastblk;
size_t sz, lastsz;
v7fs_off_t pos;
void *buf;
/* Setup replaced entry. */
sz = parent_dir->filesize;
lastblk = v7fs_datablock_last(fs, parent_dir,
v7fs_inode_filesize(parent_dir));
lastsz = V7FS_RESIDUE_BSIZE(sz);
pos = lastsz - sizeof(lastdirent);
if (!(buf = scratch_read(fs, lastblk)))
return EIO;
lastdirent = *((struct v7fs_dirent *)((uint8_t *)buf + pos));
scratch_free(fs, buf);
DPRINTF("last dirent=%d %s pos=%d\n",
V7FS_VAL16(fs, lastdirent.inode_number), lastdirent.name, pos);
struct v7fs_lookup_arg lookup_arg =
{ .name = name, .replace = &lastdirent/*disk endian */ };
/* Search entry that removed. replace it to last dirent. */
if ((error = v7fs_datablock_foreach(fs, parent_dir, remove_subr,
&lookup_arg)) != V7FS_ITERATOR_BREAK)
return ENOENT;
/* Contract dirent entries. */
v7fs_datablock_contract(fs, parent_dir, sizeof(lastdirent));
DPRINTF("done. (dirent size=%dbyte)\n", parent_dir->filesize);
/* Target inode */
if ((error = v7fs_inode_load(fs, &inode, lookup_arg.inode_number)))
return error;
if (v7fs_inode_isdir(&inode)) {
parent_dir->nlink--;
v7fs_inode_writeback(fs, parent_dir);
}
return 0;
}
static int
remove_subr(struct v7fs_self *fs, void *ctx, v7fs_daddr_t blk, size_t sz)
{
struct v7fs_lookup_arg *p = (struct v7fs_lookup_arg *)ctx;
struct v7fs_dirent *dir;
void *buf;
size_t i;
int ret = 0;
DPRINTF("match start blk=%x\n", blk);
if (!(buf = scratch_read(fs, blk)))
return EIO;
dir = (struct v7fs_dirent *)buf;
for (i = 0; i < sz / sizeof(*dir); i++, dir++) {
DPRINTF("%d\n", V7FS_VAL16(fs, dir->inode_number));
if (strncmp(p->name,
(const char *)dir->name, V7FS_NAME_MAX) == 0) {
p->inode_number = V7FS_VAL16(fs, dir->inode_number);
/* Replace to last dirent. */
*dir = *(p->replace); /* disk endian */
/* Write back. */
if (!fs->io.write(fs->io.cookie, buf, blk))
ret = EIO;
else
ret = V7FS_ITERATOR_BREAK;
break;
}
}
scratch_free(fs, buf);
return ret;
}

65
sys/fs/v7fs/v7fs_file.h Normal file
View file

@ -0,0 +1,65 @@
/* $NetBSD: v7fs_file.h,v 1.2 2011/07/16 12:35:40 uch Exp $ */
/*-
* Copyright (c) 2011 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by UCHIYAMA Yasushi.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _V7FS_FILE_H_
#define _V7FS_FILE_H_
struct v7fs_lookup_arg {
const char *name;
char *buf;
v7fs_ino_t inode_number;
struct v7fs_dirent *replace;
};
__BEGIN_DECLS
/* core */
int v7fs_file_lookup_by_name(struct v7fs_self *, struct v7fs_inode *,
const char*, v7fs_ino_t *);
int v7fs_file_allocate(struct v7fs_self *, struct v7fs_inode *, const char *,
struct v7fs_fileattr *, v7fs_ino_t *);
int v7fs_file_deallocate(struct v7fs_self *, struct v7fs_inode *, const char *);
int v7fs_directory_add_entry(struct v7fs_self *,struct v7fs_inode *, v7fs_ino_t,
const char *);
int v7fs_directory_remove_entry(struct v7fs_self *,struct v7fs_inode *,
const char *);
/* util */
int v7fs_file_rename(struct v7fs_self *, struct v7fs_inode *, const char *,
struct v7fs_inode *, const char *);
int v7fs_directory_replace_entry(struct v7fs_self *, struct v7fs_inode *,
const char *, v7fs_ino_t);
int v7fs_file_link(struct v7fs_self *, struct v7fs_inode *, struct v7fs_inode *,
const char *);
bool v7fs_file_lookup_by_number(struct v7fs_self *, struct v7fs_inode *,
v7fs_ino_t, char *);
int v7fs_file_symlink(struct v7fs_self *, struct v7fs_inode *, const char *);
__END_DECLS
#endif /*!_V7FS_INODE_H_ */

View file

@ -0,0 +1,344 @@
/* $NetBSD: v7fs_file_util.c,v 1.4 2011/07/30 03:52:04 uch Exp $ */
/*-
* Copyright (c) 2011 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by UCHIYAMA Yasushi.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#if HAVE_NBTOOL_CONFIG_H
#include "nbtool_config.h"
#endif
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: v7fs_file_util.c,v 1.4 2011/07/30 03:52:04 uch Exp $");
#ifdef _KERNEL
#include <sys/systm.h>
#include <sys/param.h>
#else
#include <stdio.h>
#include <string.h>
#include <errno.h>
#endif
#include "v7fs.h"
#include "v7fs_impl.h"
#include "v7fs_endian.h"
#include "v7fs_inode.h"
#include "v7fs_dirent.h"
#include "v7fs_file.h"
#include "v7fs_datablock.h"
#ifdef V7FS_FILE_DEBUG
#define DPRINTF(fmt, args...) printf("%s: " fmt, __func__, ##args)
#else
#define DPRINTF(fmt, args...) ((void)0)
#endif
static int replace_subr(struct v7fs_self *, void *, v7fs_daddr_t, size_t);
static int lookup_by_number_subr(struct v7fs_self *, void *, v7fs_daddr_t,
size_t);
static int can_dirmove(struct v7fs_self *, v7fs_ino_t, v7fs_ino_t);
static int lookup_parent_from_dir_subr(struct v7fs_self *, void *,
v7fs_daddr_t, size_t);
int
v7fs_file_link(struct v7fs_self *fs, struct v7fs_inode *parent_dir,
struct v7fs_inode *p, const char *name)
{
int error = 0;
DPRINTF("%d %d %s\n", parent_dir->inode_number, p->inode_number, name);
if ((error = v7fs_directory_add_entry(fs, parent_dir, p->inode_number,
name))) {
DPRINTF("can't add entry");
return error;
}
p->nlink++;
v7fs_inode_writeback(fs, p);
return 0;
}
int
v7fs_file_symlink(struct v7fs_self *fs, struct v7fs_inode *p,
const char *target)
{
int error;
size_t len = strlen(target) + 1;
if (len > V7FSBSD_MAXSYMLINKLEN) {/* limited target 512byte pathname */
DPRINTF("too long pathname.");
return ENAMETOOLONG;
}
if ((error = v7fs_datablock_expand(fs, p, len))) {
return error;
}
v7fs_daddr_t blk = p->addr[0]; /* 1block only. */
void *buf;
if (!(buf = scratch_read(fs, blk))) {
return EIO;
}
strncpy(buf, target, V7FS_BSIZE);
if (!fs->io.write(fs->io.cookie, buf, blk)) {
scratch_free(fs, buf);
return EIO;
}
scratch_free(fs, buf);
v7fs_inode_writeback(fs, p);
return 0;
}
int
v7fs_file_rename(struct v7fs_self *fs, struct v7fs_inode *parent_from,
const char *from, struct v7fs_inode *parent_to, const char *to)
{
v7fs_ino_t from_ino, to_ino;
struct v7fs_inode inode;
int error;
bool dir_move;
/* Check source file */
if ((error = v7fs_file_lookup_by_name(fs, parent_from, from,
&from_ino))) {
DPRINTF("%s don't exists\n", from);
return error;
}
v7fs_inode_load(fs, &inode, from_ino);
dir_move = v7fs_inode_isdir(&inode);
/* Check target file */
error = v7fs_file_lookup_by_name(fs, parent_to, to, &to_ino);
if (error == 0) { /* found */
DPRINTF("%s already exists\n", to);
if ((error = v7fs_file_deallocate(fs, parent_to, to))) {
DPRINTF("%s can't remove %d\n", to, error);
return error;
}
} else if (error != ENOENT) {
DPRINTF("error=%d\n", error);
return error;
}
/* Check directory hierarchy. t_vnops rename_dir(5) */
if (dir_move && (error = can_dirmove(fs, from_ino,
parent_to->inode_number))) {
DPRINTF("dst '%s' is child dir of '%s'. error=%d\n", to, from,
error);
return error;
}
if ((error = v7fs_directory_add_entry(fs, parent_to, from_ino, to))) {
DPRINTF("can't add entry");
return error;
}
if ((error = v7fs_directory_remove_entry(fs, parent_from, from))) {
DPRINTF("can't remove entry");
return error;
}
if (dir_move && (parent_from != parent_to)) {
/* If directory move, update ".." */
if ((error = v7fs_directory_replace_entry(fs, &inode, "..",
parent_to->inode_number))) {
DPRINTF("can't replace parent dir");
return error;
}
v7fs_inode_writeback(fs, &inode);
}
return 0;
}
int
v7fs_directory_replace_entry(struct v7fs_self *fs, struct v7fs_inode *self_dir,
const char *name, v7fs_ino_t ino)
{
int error;
/* Search entry that replaced. replace it to new inode number. */
struct v7fs_lookup_arg lookup_arg = { .name = name,
.inode_number = ino };
if ((error = v7fs_datablock_foreach(fs, self_dir, replace_subr,
&lookup_arg)) != V7FS_ITERATOR_BREAK)
return ENOENT;
return 0;
}
static int
replace_subr(struct v7fs_self *fs, void *ctx, v7fs_daddr_t blk, size_t sz)
{
struct v7fs_lookup_arg *p = (struct v7fs_lookup_arg *)ctx;
struct v7fs_dirent *dir;
void *buf;
size_t i, n;
int ret = 0;
DPRINTF("match start blk=%x\n", blk);
if (!(buf = scratch_read(fs, blk)))
return EIO;
dir = (struct v7fs_dirent *)buf;
n = sz / sizeof(*dir);
for (i = 0; i < n; i++, dir++) { /*disk endian */
if (strncmp(p->name, (const char *)dir->name, V7FS_NAME_MAX)
== 0) {
/* Replace inode# */
dir->inode_number = V7FS_VAL16(fs, p->inode_number);
/* Write back. */
if (!fs->io.write(fs->io.cookie, buf, blk))
ret = EIO;
else
ret = V7FS_ITERATOR_BREAK;
break;
}
}
scratch_free(fs, buf);
return ret;
}
bool
v7fs_file_lookup_by_number(struct v7fs_self *fs, struct v7fs_inode *parent_dir,
v7fs_ino_t ino, char *buf)
{
int ret;
ret = v7fs_datablock_foreach(fs, parent_dir, lookup_by_number_subr,
&(struct v7fs_lookup_arg){ .inode_number = ino, .buf = buf });
return ret == V7FS_ITERATOR_BREAK;
}
static int
lookup_by_number_subr(struct v7fs_self *fs, void *ctx, v7fs_daddr_t blk,
size_t sz)
{
struct v7fs_lookup_arg *p = (struct v7fs_lookup_arg *)ctx;
struct v7fs_dirent *dir;
void *buf;
size_t i, n;
int ret = 0;
if (!(buf = scratch_read(fs, blk)))
return EIO;
dir = (struct v7fs_dirent *)buf;
n = sz / sizeof(*dir);
v7fs_dirent_endian_convert(fs, dir, n);
for (i = 0; i < n; i++, dir++) {
if (dir->inode_number == p->inode_number) {
if (p->buf)
v7fs_dirent_filename(p->buf, dir->name);
ret = V7FS_ITERATOR_BREAK;
break;
}
}
scratch_free(fs, buf);
return ret;
}
struct lookup_parent_arg {
v7fs_ino_t parent_ino;
};
static int
can_dirmove(struct v7fs_self *fs, v7fs_ino_t from_ino, v7fs_ino_t to_ino)
{
struct v7fs_inode inode;
v7fs_ino_t parent;
int error;
/* Start dir. */
if ((error = v7fs_inode_load(fs, &inode, to_ino)))
return error;
if (!v7fs_inode_isdir(&inode))
return ENOTDIR;
/* Lookup the parent. */
do {
struct lookup_parent_arg arg;
/* Search parent dir */
arg.parent_ino = 0;
v7fs_datablock_foreach(fs, &inode, lookup_parent_from_dir_subr,
&arg);
if ((parent = arg.parent_ino) == 0) {
DPRINTF("***parent missing\n");
return ENOENT;
}
/* Load parent dir */
if ((error = v7fs_inode_load(fs, &inode, parent)))
return error;
if (parent == from_ino) {
DPRINTF("#%d is child dir of #%d\n", to_ino, from_ino);
return EINVAL;
}
} while (parent != V7FS_ROOT_INODE);
return 0;
}
static int
lookup_parent_from_dir_subr(struct v7fs_self *fs, void *ctx, v7fs_daddr_t blk,
size_t sz)
{
struct lookup_parent_arg *arg = (struct lookup_parent_arg *)ctx;
char name[V7FS_NAME_MAX + 1];
void *buf;
int ret = 0;
if (!(buf = scratch_read(fs, blk)))
return 0;
struct v7fs_dirent *dir = (struct v7fs_dirent *)buf;
size_t i, n = sz / sizeof(*dir);
if (!v7fs_dirent_endian_convert(fs, dir, n)) {
scratch_free(fs, buf);
return V7FS_ITERATOR_ERROR;
}
for (i = 0; i < n; i++, dir++) {
v7fs_dirent_filename(name, dir->name);
if (strncmp(dir->name, "..", V7FS_NAME_MAX) != 0)
continue;
arg->parent_ino = dir->inode_number;
ret = V7FS_ITERATOR_BREAK;
break;
}
scratch_free(fs, buf);
return ret;
}

154
sys/fs/v7fs/v7fs_impl.h Normal file
View file

@ -0,0 +1,154 @@
/* $NetBSD: v7fs_impl.h,v 1.1 2011/06/27 11:52:25 uch Exp $ */
/*-
* Copyright (c) 2011 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by UCHIYAMA Yasushi.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/* V7FS implementation. */
#ifndef _V7FS_IMPL_H_
#define _V7FS_IMPL_H_
#ifndef _KERNEL
#include <stdbool.h>
#include <assert.h>
#define KDASSERT(x) assert(x)
#endif
struct block_io_ops {
void *cookie;
bool (*drive)(void *, uint8_t);
bool (*read)(void *, uint8_t *, daddr_t);
bool (*read_n)(void *, uint8_t *, daddr_t, int);
bool (*write)(void *, uint8_t *, daddr_t);
bool (*write_n)(void *, uint8_t *, daddr_t, int);
};
#ifdef V7FS_EI
struct endian_conversion_ops {
uint32_t (*conv32)(uint32_t);
uint16_t (*conv16)(uint16_t);
/* For daddr packing */
v7fs_daddr_t (*conv24read)(uint8_t *);
void (*conv24write)(v7fs_daddr_t, uint8_t *);
};
#endif
#ifdef _KERNEL
#define V7FS_LOCK
#endif
#ifdef V7FS_LOCK
struct lock_ops {
void *cookie;
void (*lock)(void*);
void (*unlock)(void *);
};
#define SUPERB_LOCK(x) ((x)->sb_lock.lock((x)->sb_lock.cookie))
#define SUPERB_UNLOCK(x) ((x)->sb_lock.unlock((x)->sb_lock.cookie))
#define ILIST_LOCK(x) ((x)->ilist_lock.lock((x)->ilist_lock.cookie))
#define ILIST_UNLOCK(x) ((x)->ilist_lock.unlock((x)->ilist_lock.cookie))
#define MEM_LOCK(x) ((x)->mem_lock.lock((x)->mem_lock.cookie))
#define MEM_UNLOCK(x) ((x)->mem_lock.unlock((x)->mem_lock.cookie))
#else /*V7FS_LOCK */
#define SUPERB_LOCK(x) ((void)0)
#define SUPERB_UNLOCK(x) ((void)0)
#define ILIST_LOCK(x) ((void)0)
#define ILIST_UNLOCK(x) ((void)0)
#define MEM_LOCK(x) ((void)0)
#define MEM_UNLOCK(x) ((void)0)
#endif /*V7FS_LOCK */
struct v7fs_stat {
int32_t total_blocks;
int32_t free_blocks;
int32_t total_inode;
int32_t free_inode;
int32_t total_files;
};
struct v7fs_fileattr {
int16_t uid;
int16_t gid;
v7fs_mode_t mode;
v7fs_dev_t device;
v7fs_time_t ctime;
v7fs_time_t mtime;
v7fs_time_t atime;
};
struct v7fs_self {
#define V7FS_SELF_NSCRATCH 3
uint8_t scratch[V7FS_SELF_NSCRATCH][V7FS_BSIZE];
int scratch_free; /* free block bitmap. */
int scratch_remain; /* for statistic */
struct block_io_ops io;
#ifdef V7FS_EI
struct endian_conversion_ops val;
#endif
#ifdef V7FS_LOCK
/* in-core superblock access. (freeblock/freeinode) split? -uch */
struct lock_ops sb_lock;
struct lock_ops ilist_lock; /* disk ilist access. */
struct lock_ops mem_lock; /* work memory allocation lock. */
#endif
struct v7fs_superblock superblock;
struct v7fs_stat stat;
int endian;
};
struct v7fs_mount_device {
union {
void *vnode; /* NetBSD kernel */
int fd; /* NetBSD newfs,fsck */
const char *filename;/* misc test */
} device;
daddr_t sectors; /*total size in sector. */
int endian;
};
#define V7FS_ITERATOR_BREAK (-1)
#define V7FS_ITERATOR_END (-2)
#define V7FS_ITERATOR_ERROR (-3)
__BEGIN_DECLS
int v7fs_io_init(struct v7fs_self **, const struct v7fs_mount_device *, size_t);
void v7fs_io_fini(struct v7fs_self *);
void *scratch_read(struct v7fs_self *, daddr_t);
void scratch_free(struct v7fs_self *, void *);
int scratch_remain(const struct v7fs_self *);
__END_DECLS
#if 0
#define V7FS_IO_DEBUG
#define V7FS_SUPERBLOCK_DEBUG
#define V7FS_DATABLOCK_DEBUG
#define V7FS_INODE_DEBUG
#define V7FS_DIRENT_DEBUG
#define V7FS_FILE_DEBUG
#define V7FS_VFSOPS_DEBUG
#define V7FS_VNOPS_DEBUG
#endif
#endif /*!_V7FS_IMPL_H_ */

301
sys/fs/v7fs/v7fs_inode.c Normal file
View file

@ -0,0 +1,301 @@
/* $NetBSD: v7fs_inode.c,v 1.2 2011/07/18 21:51:49 apb Exp $ */
/*-
* Copyright (c) 2011 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by UCHIYAMA Yasushi.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#if HAVE_NBTOOL_CONFIG_H
#include "nbtool_config.h"
#endif
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: v7fs_inode.c,v 1.2 2011/07/18 21:51:49 apb Exp $");
#if defined _KERNEL_OPT
#include "opt_v7fs.h"
#endif
#ifdef _KERNEL
#include <sys/systm.h>
#include <sys/param.h>
#else
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#endif
#include "v7fs.h"
#include "v7fs_impl.h"
#include "v7fs_endian.h"
#include "v7fs_inode.h"
#include "v7fs_superblock.h"
#ifdef V7FS_INODE_DEBUG
#define DPRINTF(fmt, args...) printf("%s: " fmt, __func__, ##args)
#else
#define DPRINTF(fmt, args...) ((void)0)
#endif
static void v7fs_inode_setup_disk_image(const struct v7fs_self *,
struct v7fs_inode *, struct v7fs_inode_diskimage *);
static int v7fs_inode_inquire_disk_location(const struct v7fs_self *,
v7fs_ino_t, v7fs_daddr_t *, v7fs_daddr_t *);
#ifdef V7FS_INODE_DEBUG
static int v7fs_inode_block_sanity(const struct v7fs_superblock *,
v7fs_daddr_t);
static int
v7fs_inode_block_sanity(const struct v7fs_superblock *sb, v7fs_daddr_t blk)
{
if ((blk < V7FS_ILIST_SECTOR) || (blk >= sb->datablock_start_sector)) {
DPRINTF("invalid inode block#%d (%d-%d)\n", blk,
V7FS_ILIST_SECTOR, sb->datablock_start_sector);
return ENOSPC;
}
return 0;
}
#endif /* V7FS_INODE_DEBUG */
int
v7fs_inode_number_sanity(const struct v7fs_superblock *sb, v7fs_ino_t ino)
{
if (ino < V7FS_ROOT_INODE || ((size_t)ino >= V7FS_MAX_INODE(sb))) {
DPRINTF("invalid inode#%d (%d-%zu)\n", ino,
V7FS_ROOT_INODE, V7FS_MAX_INODE(sb));
return ENOSPC;
}
return 0;
}
int
v7fs_inode_allocate(struct v7fs_self *fs, v7fs_ino_t *ino)
{
struct v7fs_superblock *sb = &fs->superblock;
v7fs_ino_t inode_number;
int error = ENOSPC;
*ino = 0;
SUPERB_LOCK(fs);
if (sb->total_freeinode == 0) {
DPRINTF("inode exhausted!(1)\n");
goto errexit;
}
/* If there is no free inode cache, update it. */
if (sb->nfreeinode <= 0 && (error = v7fs_freeinode_update(fs))) {
DPRINTF("inode exhausted!(2)\n");
goto errexit;
}
/* Get inode from superblock cache. */
KDASSERT(sb->nfreeinode <= V7FS_MAX_FREEINODE);
inode_number = sb->freeinode[--sb->nfreeinode];
sb->total_freeinode--;
sb->modified = 1;
if ((error = v7fs_inode_number_sanity(sb, inode_number))) {
DPRINTF("new inode#%d %d %d\n", inode_number, sb->nfreeinode,
sb->total_freeinode);
DPRINTF("free inode list corupt\n");
goto errexit;
}
*ino = inode_number;
errexit:
SUPERB_UNLOCK(fs);
return error;
}
void
v7fs_inode_deallocate(struct v7fs_self *fs, v7fs_ino_t ino)
{
struct v7fs_superblock *sb = &fs->superblock;
struct v7fs_inode inode;
memset(&inode, 0, sizeof(inode));
inode.inode_number = ino;
v7fs_inode_writeback(fs, &inode);
SUPERB_LOCK(fs);
if (sb->nfreeinode < V7FS_MAX_FREEINODE) {
/* link to freeinode list. */
sb->freeinode[sb->nfreeinode++] = ino;
}
/* If superblock inode cache is full, this inode charged by
v7fs_freeinode_update() later. */
sb->total_freeinode++;
sb->modified = true;
SUPERB_UNLOCK(fs);
}
void
v7fs_inode_setup_memory_image(const struct v7fs_self *fs __unused,
struct v7fs_inode *mem, struct v7fs_inode_diskimage *disk)
{
#define conv16(m) (mem->m = V7FS_VAL16(fs, (disk->m)))
#define conv32(m) (mem->m = V7FS_VAL32(fs, (disk->m)))
uint32_t addr;
int i;
memset(mem, 0, sizeof(*mem));
conv16(mode);
conv16(nlink);
conv16(uid);
conv16(gid);
conv32(filesize);
conv32(atime);
conv32(mtime);
conv32(ctime);
for (i = 0; i < V7FS_NADDR; i++) {
int j = i * 3; /* 3 byte each. (v7fs_daddr is 24bit) */
/* expand to 4byte with endian conversion. */
addr = V7FS_VAL24_READ(fs, &disk->addr[j]);
mem->addr[i] = addr;
}
mem->device = 0;
if (v7fs_inode_iscdev(mem) || v7fs_inode_isbdev(mem)) {
mem->device = mem->addr[0];
}
#undef conv16
#undef conv32
}
static void
v7fs_inode_setup_disk_image(const struct v7fs_self *fs __unused,
struct v7fs_inode *mem, struct v7fs_inode_diskimage *disk)
{
#define conv16(m) (disk->m = V7FS_VAL16(fs, (mem->m)))
#define conv32(m) (disk->m = V7FS_VAL32(fs, (mem->m)))
conv16(mode);
conv16(nlink);
conv16(uid);
conv16(gid);
conv32(filesize);
conv32(atime);
conv32(mtime);
conv32(ctime);
int i;
for (i = 0; i < V7FS_NADDR; i++) {
int j = i * 3; /* 3 byte each. */
V7FS_VAL24_WRITE(fs, mem->addr[i], disk->addr + j);
}
#undef conv16
#undef conv32
}
/* Load inode from disk. */
int
v7fs_inode_load(struct v7fs_self *fs, struct v7fs_inode *p, v7fs_ino_t n)
{
v7fs_daddr_t blk, ofs;
struct v7fs_inode_diskimage *di;
void *buf;
if (v7fs_inode_inquire_disk_location(fs, n, &blk, &ofs) != 0)
return ENOENT;
ILIST_LOCK(fs);
if (!(buf = scratch_read(fs, blk))) {
ILIST_UNLOCK(fs);
return EIO;
}
ILIST_UNLOCK(fs);
di = (struct v7fs_inode_diskimage *)buf;
/* Decode disk address, convert endian. */
v7fs_inode_setup_memory_image(fs, p, di + ofs);
p->inode_number = n;
scratch_free(fs, buf);
return 0;
}
/* Write back inode to disk. */
int
v7fs_inode_writeback(struct v7fs_self *fs, struct v7fs_inode *mem)
{
struct v7fs_inode_diskimage disk;
v7fs_ino_t ino = mem->inode_number;
v7fs_daddr_t blk;
v7fs_daddr_t ofs;
void *buf;
int error = 0;
if (v7fs_inode_inquire_disk_location(fs, ino, &blk, &ofs) != 0)
return ENOENT;
v7fs_inode_setup_disk_image(fs, mem, &disk);
ILIST_LOCK(fs);
if (!(buf = scratch_read(fs, blk))) {
ILIST_UNLOCK(fs);
return EIO;
}
struct v7fs_inode_diskimage *di = (struct v7fs_inode_diskimage *)buf;
di[ofs] = disk; /* structure copy; */
if (!fs->io.write(fs->io.cookie, buf, blk))
error = EIO;
ILIST_UNLOCK(fs);
scratch_free(fs, buf);
return error;
}
static int
v7fs_inode_inquire_disk_location(const struct v7fs_self *fs
__unused, v7fs_ino_t n, v7fs_daddr_t *block,
v7fs_daddr_t *offset)
{
v7fs_daddr_t ofs, blk;
#ifdef V7FS_INODE_DEBUG
v7fs_inode_number_sanity(&fs->superblock, n);
#endif
ofs = (n - 1/*inode start from 1*/) *
sizeof(struct v7fs_inode_diskimage);
blk = ofs >> V7FS_BSHIFT;
*block = blk + V7FS_ILIST_SECTOR;
*offset = (ofs - blk * V7FS_BSIZE) /
sizeof(struct v7fs_inode_diskimage);
#ifdef V7FS_INODE_DEBUG
return v7fs_inode_block_sanity(&fs->superblock, *block);
#else
return 0;
#endif
}

91
sys/fs/v7fs/v7fs_inode.h Normal file
View file

@ -0,0 +1,91 @@
/* $NetBSD: v7fs_inode.h,v 1.1 2011/06/27 11:52:25 uch Exp $ */
/*-
* Copyright (c) 2011 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by UCHIYAMA Yasushi.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _V7FS_INODE_H_
#define _V7FS_INODE_H_
/* Software implementation of inode. (memory image) */
struct v7fs_inode {
v7fs_ino_t inode_number; /* inode location */
/* attr */
uint16_t mode;
int16_t nlink;
int16_t uid;
int16_t gid;
v7fs_time_t atime;
v7fs_time_t mtime;
v7fs_time_t ctime;
/* open mode */
bool append_mode;
v7fs_dev_t device; /* for special file.(cdev, bdev) */
/* payload. */
v7fs_off_t filesize; /* size of file (byte) */
v7fs_daddr_t addr[V7FS_NADDR]; /* data block address list */
};
#define v7fs_inode_filesize(i) ((i)->filesize)
#define v7fs_inode_allocated(i) ((i)->mode)
#define v7fs_inode_nlink(i) ((i)->nlink)
/* V7 original */
#define v7fs_inode_isdir(i) (((i)->mode & V7FS_IFMT) == V7FS_IFDIR)
#define v7fs_inode_isfile(i) (((i)->mode & V7FS_IFMT) == V7FS_IFREG)
#define v7fs_inode_iscdev(i) (((i)->mode & V7FS_IFMT) == V7FS_IFCHR)
#define v7fs_inode_isbdev(i) (((i)->mode & V7FS_IFMT) == V7FS_IFBLK)
/* 2BSD extension (implementation is different) */
#define v7fs_inode_islnk(i) (((i)->mode & V7FS_IFMT) == V7FSBSD_IFLNK)
#define v7fs_inode_issock(i) (((i)->mode & V7FS_IFMT) == V7FSBSD_IFSOCK)
/* NetBSD Extension */
#define v7fs_inode_isfifo(i) (((i)->mode & V7FS_IFMT) == V7FSBSD_IFFIFO)
__BEGIN_DECLS
/* Free inode access ops. */
int v7fs_inode_allocate(struct v7fs_self *, v7fs_ino_t *);
void v7fs_inode_deallocate(struct v7fs_self *, v7fs_ino_t);
/* Disk I/O ops. */
int v7fs_inode_load(struct v7fs_self *, struct v7fs_inode *, v7fs_ino_t);
int v7fs_inode_writeback(struct v7fs_self *, struct v7fs_inode *);
void v7fs_inode_setup_memory_image(const struct v7fs_self *,
struct v7fs_inode *, struct v7fs_inode_diskimage *);
/* Check. */
int v7fs_inode_number_sanity(const struct v7fs_superblock *, v7fs_ino_t);
/* Util. */
void v7fs_inode_chmod(struct v7fs_inode *, v7fs_mode_t);
void v7fs_inode_dump(const struct v7fs_inode *);
/* Loop over all inode in ilist. */
int v7fs_ilist_foreach(struct v7fs_self *, int (*)(struct v7fs_self *, void *,
struct v7fs_inode *, v7fs_ino_t), void *);
__END_DECLS
#endif /*!_V7FS_INODE_H_ */

View file

@ -0,0 +1,128 @@
/* $NetBSD: v7fs_inode_util.c,v 1.2 2011/07/18 21:51:49 apb Exp $ */
/*-
* Copyright (c) 2011 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by UCHIYAMA Yasushi.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#if HAVE_NBTOOL_CONFIG_H
#include "nbtool_config.h"
#endif
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: v7fs_inode_util.c,v 1.2 2011/07/18 21:51:49 apb Exp $");
#if defined _KERNEL_OPT
#include "opt_v7fs.h"
#endif
#ifdef _KERNEL
#include <sys/systm.h>
#include <sys/param.h>
#else
#include <stdio.h>
#include <time.h>
#endif
#include "v7fs.h"
#include "v7fs_impl.h"
#include "v7fs_inode.h"
#ifdef V7FS_INODE_DEBUG
#define DPRINTF(fmt, args...) printf("%s: " fmt, __func__, ##args)
#else
#define DPRINTF(fmt, args...) ((void)0)
#endif
void
v7fs_inode_chmod(struct v7fs_inode *inode, v7fs_mode_t mode)
{
#define V7FS_MODE_MASK 0xfff
DPRINTF("setattr %08o -> %08o\n", inode->mode, mode);
inode->mode &= ~V7FS_MODE_MASK;
inode->mode |= (mode & V7FS_MODE_MASK);
DPRINTF("setattr %08o -> %08o\n", inode->mode, mode);
}
void
v7fs_inode_dump(const struct v7fs_inode *p)
{
printf("nlink %d mode %06o %d/%d %d bytes\n",
p->nlink, p->mode,
p->uid, p->gid, p->filesize);
printf("atime %d mtime %d ctime %d\n",
p->atime, p->mtime, p->ctime);
#ifndef _KERNEL
time_t at = p->atime;
time_t mt = p->mtime;
time_t ct = p->ctime;
printf(" atime %s mtime %s ctime %s", ctime(&at), ctime(&mt),
ctime(&ct));
#endif
if (v7fs_inode_iscdev(p) || v7fs_inode_isbdev(p)) {
printf("device:%d/%d\n", (p->device >> 8), p->device & 0xff);
}
printf("\n");
}
int
v7fs_ilist_foreach
(struct v7fs_self *fs,
int (*func)(struct v7fs_self *, void *, struct v7fs_inode *, v7fs_ino_t),
void *ctx)
{
struct v7fs_superblock *sb = &fs->superblock;
size_t i, j, k;
int ret;
/* Loop over ilist. */
for (k = 1, i = V7FS_ILIST_SECTOR; i < sb->datablock_start_sector;
i++) {
struct v7fs_inode_diskimage *di;
struct v7fs_inode inode;
void *buf;
if (!(buf = scratch_read(fs, i))) {
DPRINTF("block %zu I/O error.\n", i);
k += V7FS_INODE_PER_BLOCK;
continue;
}
di = (struct v7fs_inode_diskimage *)buf;
for (j = 0; j < V7FS_INODE_PER_BLOCK; j++, k++) {
v7fs_inode_setup_memory_image(fs, &inode, di + j);
inode.inode_number = k;
if ((ret = func(fs, ctx, &inode, k))) {
scratch_free(fs, buf);
return ret;
}
}
scratch_free(fs, buf);
}
return 0;
}

141
sys/fs/v7fs/v7fs_io.c Normal file
View file

@ -0,0 +1,141 @@
/* $NetBSD: v7fs_io.c,v 1.3 2013/06/28 14:49:14 christos Exp $ */
/*-
* Copyright (c) 2011 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by UCHIYAMA Yasushi.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#if HAVE_NBTOOL_CONFIG_H
#include "nbtool_config.h"
#endif
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: v7fs_io.c,v 1.3 2013/06/28 14:49:14 christos Exp $");
#if defined _KERNEL_OPT
#include "opt_v7fs.h"
#endif
#ifdef _KERNEL
#include <sys/param.h>
#else
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#endif
#include "v7fs.h"
#include "v7fs_impl.h"
#if defined _KERNEL
#define STATIC_BUFFER
#endif
#ifdef V7FS_IO_DEBUG
#define DPRINTF(fmt, args...) printf("%s: " fmt, __func__, ##args)
#else
#define DPRINTF(fmt, args...) ((void)0)
#endif
void *
scratch_read(struct v7fs_self *fs, daddr_t blk)
{
#ifdef STATIC_BUFFER
int i;
MEM_LOCK(fs);
for (i = 0; i < V7FS_SELF_NSCRATCH; i++) {
if (fs->scratch_free & (1 << i)) {
fs->scratch_free &= ~(1 << i);
break;
}
}
if (i == V7FS_SELF_NSCRATCH) {
DPRINTF("No scratch area. increase V7FS_SELF_NSCRATCH\n");
assert(0);
MEM_UNLOCK(fs);
return NULL;
}
if (!fs->io.read(fs->io.cookie, fs->scratch[i], blk)) {
DPRINTF("*** I/O error block %ld\n", (long)blk);
fs->scratch_free |= (1 << i);
MEM_UNLOCK(fs);
return NULL;
}
MEM_UNLOCK(fs);
/* Statistic */
int n;
if ((n = scratch_remain(fs)) < fs->scratch_remain)
fs->scratch_remain = n;
return fs->scratch[i];
#else
uint8_t *buf = malloc(V7FS_BSIZE);
if (!fs->io.read(fs->io.cookie, buf, blk)) {
DPRINTF("*** I/O error block %ld\n",(long)blk);
free(buf);
return NULL;
}
return buf;
#endif
}
int
scratch_remain(const struct v7fs_self *fs)
{
#ifdef STATIC_BUFFER
int nfree;
int i;
MEM_LOCK(fs);
for (i = 0, nfree = 0; i < V7FS_SELF_NSCRATCH; i++) {
if (fs->scratch_free & (1 << i)) {
nfree++;
}
}
MEM_UNLOCK(fs);
return nfree;
#else
return -1;
#endif
}
void
scratch_free(struct v7fs_self *fs __unused, void *p)
{
#ifdef STATIC_BUFFER
int i;
MEM_LOCK(fs);
for (i = 0; i < V7FS_SELF_NSCRATCH; i++)
if (fs->scratch[i] == p) {
fs->scratch_free |= (1 << i);
break;
}
MEM_UNLOCK(fs);
assert(i != V7FS_SELF_NSCRATCH);
#else
free(p);
#endif
}

241
sys/fs/v7fs/v7fs_io_kern.c Normal file
View file

@ -0,0 +1,241 @@
/* $NetBSD: v7fs_io_kern.c,v 1.2 2013/11/20 23:44:23 rmind Exp $ */
/*-
* Copyright (c) 2004, 2011 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by UCHIYAMA Yasushi.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: v7fs_io_kern.c,v 1.2 2013/11/20 23:44:23 rmind Exp $");
#if defined _KERNEL_OPT
#include "opt_v7fs.h"
#endif
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: v7fs_io_kern.c,v 1.2 2013/11/20 23:44:23 rmind Exp $");
#include <sys/param.h>
#include <sys/types.h>
#include <sys/systm.h>
#include <sys/buf.h>
#include <sys/kmem.h>
#include <sys/kauth.h>
#include <sys/mutex.h>
#include <fs/v7fs/v7fs.h>
#include "v7fs_endian.h"
#include "v7fs_impl.h"
#ifdef V7FS_IO_DEBUG
#define DPRINTF(fmt, args...) printf("%s: " fmt, __func__, ##args)
#else
#define DPRINTF(fmt, args...) ((void)0)
#endif
struct local_io {
struct vnode *vp;
kauth_cred_t cred;
};
static bool v7fs_os_read_n(void *, uint8_t *, daddr_t, int);
static bool v7fs_os_read(void *, uint8_t *, daddr_t);
static bool v7fs_os_write_n(void *, uint8_t *, daddr_t, int);
static bool v7fs_os_write(void *, uint8_t *, daddr_t);
static void v7fs_os_lock(void *);
static void v7fs_os_unlock(void *);
static bool lock_init(struct lock_ops *);
int
v7fs_io_init(struct v7fs_self **fs,
const struct v7fs_mount_device *mount_device, size_t block_size)
{
struct vnode *vp = mount_device->device.vnode;
struct v7fs_self *p;
struct local_io *local;
int error = 0;
if ((p = kmem_zalloc(sizeof(*p), KM_SLEEP)) == NULL)
return ENOMEM;
p->scratch_free = -1;
p->scratch_remain = V7FS_SELF_NSCRATCH;
/* Endian */
p->endian = mount_device->endian;
#ifdef V7FS_EI
v7fs_endian_init(p);
#endif
/* IO */
if ((local = kmem_zalloc(sizeof(*local), KM_SLEEP)) == NULL) {
error = ENOMEM;
goto errexit;
}
p->io.read = v7fs_os_read;
p->io.read_n = v7fs_os_read_n;
p->io.write = v7fs_os_write;
p->io.write_n = v7fs_os_write_n;
p->scratch_free = -1; /* free all scratch buffer */
p->io.cookie = local;
local->vp = vp;
local->cred = NOCRED; /* upper layer check cred. */
/*LOCK */
error = ENOMEM;
if (!lock_init(&p->sb_lock))
goto errexit;
if (!lock_init(&p->ilist_lock))
goto errexit;
if (!lock_init(&p->mem_lock))
goto errexit;
error = 0;
*fs = p;
return 0;
errexit:
v7fs_io_fini(p);
return error;
}
static bool
lock_init(struct lock_ops *ops)
{
if ((ops->cookie = kmem_zalloc(sizeof(kmutex_t), KM_SLEEP)) == NULL) {
return false;
}
mutex_init(ops->cookie, MUTEX_DEFAULT, IPL_NONE);
ops->lock = v7fs_os_lock;
ops->unlock = v7fs_os_unlock;
return true;
}
void
v7fs_io_fini(struct v7fs_self *fs)
{
if (fs->io.cookie) {
kmem_free(fs->io.cookie, sizeof(struct local_io));
}
if (fs->sb_lock.cookie) {
mutex_destroy(fs->sb_lock.cookie);
kmem_free(fs->sb_lock.cookie, sizeof(kmutex_t));
}
if (fs->ilist_lock.cookie) {
mutex_destroy(fs->ilist_lock.cookie);
kmem_free(fs->ilist_lock.cookie, sizeof(kmutex_t));
}
if (fs->mem_lock.cookie) {
mutex_destroy(fs->mem_lock.cookie);
kmem_free(fs->mem_lock.cookie, sizeof(kmutex_t));
}
kmem_free(fs, sizeof(*fs));
}
static bool
v7fs_os_read_n(void *self, uint8_t *buf, daddr_t block, int count)
{
int i;
for (i = 0; i < count; i++) {
if (!v7fs_os_read(self, buf, block))
return false;
buf += DEV_BSIZE;
block++;
}
return true;
}
static bool
v7fs_os_read(void *self, uint8_t *buf, daddr_t block)
{
struct local_io *bio = (struct local_io *)self;
struct buf *bp = NULL;
if (bread(bio->vp, block, DEV_BSIZE, bio->cred, 0, &bp) != 0)
goto error_exit;
memcpy(buf, bp->b_data, DEV_BSIZE);
brelse(bp, 0);
return true;
error_exit:
DPRINTF("block %ld read failed.\n", (long)block);
if (bp != NULL)
brelse(bp, 0);
return false;
}
static bool
v7fs_os_write_n(void *self, uint8_t *buf, daddr_t block, int count)
{
int i;
for (i = 0; i < count; i++) {
if (!v7fs_os_write(self, buf, block))
return false;
buf += DEV_BSIZE;
block++;
}
return true;
}
static bool
v7fs_os_write(void *self, uint8_t *buf, daddr_t block)
{
struct local_io *bio = (struct local_io *)self;
struct buf *bp;
if ((bp = getblk(bio->vp, block, DEV_BSIZE, 0, 0)) == 0) {
DPRINTF("getblk failed. block=%ld\n", (long)block);
return false;
}
memcpy(bp->b_data, buf, DEV_BSIZE);
if (bwrite(bp) != 0) {
DPRINTF("bwrite failed. block=%ld\n", (long)block);
return false;
}
return true;
}
static void
v7fs_os_lock(void *self)
{
mutex_enter((kmutex_t *)self);
}
static void
v7fs_os_unlock(void *self)
{
mutex_exit((kmutex_t *)self);
}

172
sys/fs/v7fs/v7fs_io_user.c Normal file
View file

@ -0,0 +1,172 @@
/* $NetBSD: v7fs_io_user.c,v 1.4 2011/08/08 11:42:30 uch Exp $ */
/*-
* Copyright (c) 2011 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by UCHIYAMA Yasushi.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#if HAVE_NBTOOL_CONFIG_H
#include "nbtool_config.h"
#endif
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: v7fs_io_user.c,v 1.4 2011/08/08 11:42:30 uch Exp $");
#endif /* not lint */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <err.h>
#include <sys/mman.h>
#include "v7fs.h"
#include "v7fs_endian.h"
#include "v7fs_impl.h"
#ifdef V7FS_IO_DEBUG
#define DPRINTF(fmt, args...) printf("%s: " fmt, __func__, ##args)
#else
#define DPRINTF(fmt, args...) ((void)0)
#endif
struct local_io {
int fd;
size_t size;
size_t blksz;
uint8_t *addr;
} local;
static bool read_sector(void *, uint8_t *, daddr_t);
static bool write_sector(void *, uint8_t *, daddr_t);
static bool read_mmap(void *, uint8_t *, daddr_t);
static bool write_mmap(void *, uint8_t *, daddr_t);
int
v7fs_io_init(struct v7fs_self **fs, const struct v7fs_mount_device *mount,
size_t block_size)
{
struct v7fs_self *p;
if (!(p = (struct v7fs_self *)malloc(sizeof(*p))))
return ENOMEM;
memset(p, 0, sizeof(*p));
/* Endian */
p->endian = mount->endian;
#ifdef V7FS_EI
v7fs_endian_init(p);
#endif
local.blksz = block_size;
local.fd = mount->device.fd;
local.size = mount->sectors * block_size;
local.addr = mmap(NULL, local.size, PROT_READ | PROT_WRITE | PROT_NONE,
MAP_FILE | MAP_SHARED/*writeback*/, local.fd, 0);
if (local.addr == MAP_FAILED) {
local.addr = 0;
p->io.read = read_sector;
p->io.write = write_sector;
} else {
DPRINTF("mmaped addr=%p\n", local.addr);
p->io.read = read_mmap;
p->io.write = write_mmap;
}
p->io.cookie = &local;
*fs = p;
return 0;
}
void
v7fs_io_fini(struct v7fs_self *fs)
{
struct local_io *lio = (struct local_io *)fs->io.cookie;
if (lio->addr) {
if (munmap(lio->addr, lio->size) != 0)
warn(0);
}
fsync(lio->fd);
free(fs);
}
static bool
read_sector(void *ctx, uint8_t *buf, daddr_t sector)
{
struct local_io *lio = (struct local_io *)ctx;
size_t blksz = lio->blksz;
int fd = lio->fd;
if ((lseek(fd, (off_t)sector * blksz, SEEK_SET) < 0) ||
(read(fd, buf, blksz) < (ssize_t)blksz)) {
warn("sector=%ld\n", (long)sector);
return false;
}
return true;
}
static bool
write_sector(void *ctx, uint8_t *buf, daddr_t sector)
{
struct local_io *lio = (struct local_io *)ctx;
size_t blksz = lio->blksz;
int fd = lio->fd;
if ((lseek(fd, (off_t)sector * blksz, SEEK_SET) < 0) ||
(write(fd, buf, blksz) < (ssize_t)blksz)) {
warn("sector=%ld\n", (long)sector);
return false;
}
return true;
}
static bool
read_mmap(void *ctx, uint8_t *buf, daddr_t sector)
{
struct local_io *lio = (struct local_io *)ctx;
size_t blksz = lio->blksz;
memcpy(buf, lio->addr + sector * blksz, blksz);
return true;
}
static bool
write_mmap(void *ctx, uint8_t *buf, daddr_t sector)
{
struct local_io *lio = (struct local_io *)ctx;
size_t blksz = lio->blksz;
memcpy(lio->addr + sector * blksz, buf, blksz);
return true;
}

View file

@ -0,0 +1,263 @@
/* $NetBSD: v7fs_superblock.c,v 1.2 2011/07/18 21:51:49 apb Exp $ */
/*-
* Copyright (c) 2011 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by UCHIYAMA Yasushi.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#if HAVE_NBTOOL_CONFIG_H
#include "nbtool_config.h"
#endif
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: v7fs_superblock.c,v 1.2 2011/07/18 21:51:49 apb Exp $");
#if defined _KERNEL_OPT
#include "opt_v7fs.h"
#endif
#ifdef _KERNEL
#include <sys/systm.h>
#include <sys/param.h> /* errno */
#else
#include <stdio.h>
#include <string.h>
#include <errno.h>
#endif
#include "v7fs.h"
#include "v7fs_impl.h"
#include "v7fs_endian.h"
#include "v7fs_superblock.h"
#include "v7fs_inode.h"
#include "v7fs_datablock.h"
#ifdef V7FS_SUPERBLOCK_DEBUG
#define DPRINTF(fmt, args...) printf("%s: " fmt, __func__, ##args)
#define DPRINTF_(fmt, args...) printf(fmt, ##args)
#else
#define DPRINTF(fmt, args...) ((void)0)
#define DPRINTF_(fmt, args...) ((void)0)
#endif
static void v7fs_superblock_endian_convert(struct v7fs_self *,
struct v7fs_superblock *, struct v7fs_superblock *);
static int v7fs_superblock_sanity(struct v7fs_self *);
/* Load superblock from disk. */
int
v7fs_superblock_load(struct v7fs_self *fs)
{
struct v7fs_superblock *disksb;
void *buf;
int error;
if (!(buf = scratch_read(fs, V7FS_SUPERBLOCK_SECTOR)))
return EIO;
disksb = (struct v7fs_superblock *)buf;
v7fs_superblock_endian_convert(fs, &fs->superblock, disksb);
scratch_free(fs, buf);
if ((error = v7fs_superblock_sanity(fs)))
return error;
return 0;
}
/* Writeback superblock to disk. */
int
v7fs_superblock_writeback(struct v7fs_self *fs)
{
struct v7fs_superblock *memsb = &fs->superblock;
struct v7fs_superblock *disksb;
void *buf;
int error = 0;
if (!memsb->modified)
return 0;
if (!(buf = scratch_read(fs, V7FS_SUPERBLOCK_SECTOR)))
return EIO;
disksb = (struct v7fs_superblock *)buf;
v7fs_superblock_endian_convert(fs, disksb, memsb);
if (!fs->io.write(fs->io.cookie, buf, V7FS_SUPERBLOCK_SECTOR))
error = EIO;
scratch_free(fs, buf);
memsb->modified = 0;
DPRINTF("done. %d\n", error);
return error;
}
/* Check endian mismatch. */
static int
v7fs_superblock_sanity(struct v7fs_self *fs)
{
const struct v7fs_superblock *sb = &fs->superblock;
void *buf = 0;
if ((sb->volume_size < 128) || /* smaller than 64KB. */
(sb->datablock_start_sector > sb->volume_size) ||
(sb->nfreeinode > V7FS_MAX_FREEINODE) ||
(sb->nfreeblock > V7FS_MAX_FREEBLOCK) ||
(sb->update_time < 0) ||
(sb->total_freeblock > sb->volume_size) ||
((sb->nfreeinode == 0) && (sb->nfreeblock == 0) &&
(sb->total_freeblock == 0) && (sb->total_freeinode == 0)) ||
(!(buf = scratch_read(fs, sb->volume_size - 1)))) {
DPRINTF("invalid super block.\n");
return EINVAL;
}
if (buf)
scratch_free(fs, buf);
return 0;
}
/* Fill free block to superblock cache. */
int
v7fs_freeblock_update(struct v7fs_self *fs, v7fs_daddr_t blk)
{
/* Assume superblock is locked by caller. */
struct v7fs_superblock *sb = &fs->superblock;
struct v7fs_freeblock *fb;
void *buf;
int error;
/* Read next freeblock table from disk. */
if (!datablock_number_sanity(fs, blk) || !(buf = scratch_read(fs, blk)))
return EIO;
/* Update in-core superblock freelist. */
fb = (struct v7fs_freeblock *)buf;
if ((error = v7fs_freeblock_endian_convert(fs, fb))) {
scratch_free(fs, buf);
return error;
}
DPRINTF("freeblock table#%d, nfree=%d\n", blk, fb->nfreeblock);
memcpy(sb->freeblock, fb->freeblock, sizeof(blk) * fb->nfreeblock);
sb->nfreeblock = fb->nfreeblock;
sb->modified = true;
scratch_free(fs, buf);
return 0;
}
int
v7fs_freeblock_endian_convert(struct v7fs_self *fs __unused,
struct v7fs_freeblock *fb __unused)
{
#ifdef V7FS_EI
int i;
int16_t nfree;
nfree = V7FS_VAL16(fs, fb->nfreeblock);
if (nfree <= 0 || nfree > V7FS_MAX_FREEBLOCK) {
DPRINTF("invalid freeblock list. %d (max=%d)\n", nfree,
V7FS_MAX_FREEBLOCK);
return ENOSPC;
}
fb->nfreeblock = nfree;
for (i = 0; i < nfree; i++) {
fb->freeblock[i] = V7FS_VAL32(fs, fb->freeblock[i]);
}
#endif /* V7FS_EI */
return 0;
}
/* Fill free inode to superblock cache. */
int
v7fs_freeinode_update(struct v7fs_self *fs)
{
/* Assume superblock is locked by caller. */
struct v7fs_superblock *sb = &fs->superblock;
v7fs_ino_t *freeinode = sb->freeinode;
size_t i, j, k;
v7fs_ino_t ino;
/* Loop over all inode list. */
for (i = V7FS_ILIST_SECTOR, ino = 1/* inode start from 1*/, k = 0;
i < sb->datablock_start_sector; i++) {
struct v7fs_inode_diskimage *di;
void *buf;
if (!(buf = scratch_read(fs, i))) {
DPRINTF("block %zu I/O error.\n", i);
ino += V7FS_INODE_PER_BLOCK;
continue;
}
di = (struct v7fs_inode_diskimage *)buf;
for (j = 0;
(j < V7FS_INODE_PER_BLOCK) && (k < V7FS_MAX_FREEINODE);
j++, di++, ino++) {
if (v7fs_inode_allocated(di))
continue;
DPRINTF("free inode%d\n", ino);
freeinode[k++] = ino;
}
scratch_free(fs, buf);
}
sb->nfreeinode = k;
return 0;
}
static void
v7fs_superblock_endian_convert(struct v7fs_self *fs __unused,
struct v7fs_superblock *to, struct v7fs_superblock *from)
{
#ifdef V7FS_EI
#define conv16(m) (to->m = V7FS_VAL16(fs, from->m))
#define conv32(m) (to->m = V7FS_VAL32(fs, from->m))
int i;
conv16(datablock_start_sector);
conv32(volume_size);
conv16(nfreeblock);
v7fs_daddr_t *dfrom = from->freeblock;
v7fs_daddr_t *dto = to->freeblock;
for (i = 0; i < V7FS_MAX_FREEBLOCK; i++, dfrom++, dto++)
*dto = V7FS_VAL32(fs, *dfrom);
conv16(nfreeinode);
v7fs_ino_t *ifrom = from->freeinode;
v7fs_ino_t *ito = to->freeinode;
for (i = 0; i < V7FS_MAX_FREEINODE; i++, ifrom++, ito++)
*ito = V7FS_VAL16(fs, *ifrom);
conv32(update_time);
conv32(total_freeblock);
conv16(total_freeinode);
#undef conv16
#undef conv32
#else /* V7FS_EI */
memcpy(to, from , sizeof(*to));
#endif /* V7FS_EI */
}

View file

@ -0,0 +1,48 @@
/* $NetBSD: v7fs_superblock.h,v 1.1 2011/06/27 11:52:25 uch Exp $ */
/*-
* Copyright (c) 2011 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by UCHIYAMA Yasushi.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _V7FS_SUPERBLOCK_H_
#define _V7FS_SUPERBLOCK_H_
struct v7fs_self;
__BEGIN_DECLS
/* core */
int v7fs_superblock_load(struct v7fs_self *);
int v7fs_superblock_writeback(struct v7fs_self *);
int v7fs_freeblock_update(struct v7fs_self *, v7fs_daddr_t);
int v7fs_freeblock_endian_convert(struct v7fs_self *, struct v7fs_freeblock *);
int v7fs_freeinode_update(struct v7fs_self *);
/* util. */
void v7fs_superblock_status(struct v7fs_self *);
void v7fs_superblock_dump(const struct v7fs_self *);
__END_DECLS
#endif /*!_V7FS_SUPERBLOCK_H_ */

View file

@ -0,0 +1,101 @@
/* $NetBSD: v7fs_superblock_util.c,v 1.2 2011/07/18 21:51:49 apb Exp $ */
/*-
* Copyright (c) 2011 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by UCHIYAMA Yasushi.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#if HAVE_NBTOOL_CONFIG_H
#include "nbtool_config.h"
#endif
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: v7fs_superblock_util.c,v 1.2 2011/07/18 21:51:49 apb Exp $");
#if defined _KERNEL_OPT
#include "opt_v7fs.h"
#endif
#ifdef _KERNEL
#include <sys/systm.h>
#include <sys/param.h> /* errno */
#else
#include <stdio.h>
#include <time.h>
#endif
#include "v7fs.h"
#include "v7fs_impl.h"
#include "v7fs_superblock.h"
#include "v7fs_inode.h"
#ifdef V7FS_SUPERBLOCK_DEBUG
#define DPRINTF(fmt, args...) printf("%s: " fmt, __func__, ##args)
#define DPRINTF_(fmt, args...) printf(fmt, ##args)
#else
#define DPRINTF(fmt, args...) ((void)0)
#define DPRINTF_(fmt, args...) ((void)0)
#endif
void
v7fs_superblock_status(struct v7fs_self *fs)
{
struct v7fs_superblock *sb = &fs->superblock;
struct v7fs_stat *stat = &fs->stat;
stat->total_blocks = sb->volume_size - sb->datablock_start_sector;
stat->total_inode = V7FS_MAX_INODE(sb);
stat->free_inode = sb->total_freeinode;
stat->free_blocks = sb->total_freeblock;
stat->total_files = stat->total_inode - sb->total_freeinode - 1;
DPRINTF("block %d/%d, inode %d/%d\n", stat->free_blocks,
stat->total_blocks, stat->free_inode, stat->total_inode);
}
void
v7fs_superblock_dump(const struct v7fs_self *fs)
{
const struct v7fs_superblock *sb = &fs->superblock;
#define print(x) printf("%s: %d\n", #x, sb->x)
print(datablock_start_sector);
print(volume_size);
print(nfreeblock);
print(nfreeinode);
print(update_time);
print(lock_freeblock);
print(lock_freeinode);
print(modified);
print(readonly);
#if !defined _KERNEL
time_t t = sb->update_time;
printf("%s", ctime(&t));
#endif
print(total_freeblock);
print(total_freeinode);
#undef print
}

617
sys/fs/v7fs/v7fs_vfsops.c Normal file
View file

@ -0,0 +1,617 @@
/* $NetBSD: v7fs_vfsops.c,v 1.9 2013/11/23 13:35:36 christos Exp $ */
/*-
* Copyright (c) 2004, 2011 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by UCHIYAMA Yasushi.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: v7fs_vfsops.c,v 1.9 2013/11/23 13:35:36 christos Exp $");
#if defined _KERNEL_OPT
#include "opt_v7fs.h"
#endif
#include <sys/types.h>
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/pool.h>
#include <sys/time.h>
#include <sys/ucred.h>
#include <sys/mount.h>
#include <sys/disk.h>
#include <sys/device.h>
#include <sys/fcntl.h>
#include <sys/kmem.h>
#include <sys/kauth.h>
#include <sys/proc.h>
/* v-node */
#include <sys/namei.h>
#include <sys/vnode.h>
/* devsw */
#include <sys/conf.h>
#include "v7fs_extern.h"
#include "v7fs.h"
#include "v7fs_impl.h"
#include "v7fs_inode.h"
#include "v7fs_superblock.h"
#ifdef V7FS_VFSOPS_DEBUG
#define DPRINTF(fmt, args...) printf("%s: " fmt, __func__, ##args)
#else
#define DPRINTF(arg...) ((void)0)
#endif
struct pool v7fs_node_pool;
static int v7fs_mountfs(struct vnode *, struct mount *, int);
static int v7fs_openfs(struct vnode *, struct mount *, struct lwp *);
static void v7fs_closefs(struct vnode *, struct mount *);
static int is_v7fs_partition(struct vnode *);
static enum vtype v7fs_mode_to_vtype(v7fs_mode_t mode);
int v7fs_vnode_reload(struct mount *, struct vnode *);
int
v7fs_mount(struct mount *mp, const char *path, void *data, size_t *data_len)
{
struct lwp *l = curlwp;
struct v7fs_args *args = data;
struct v7fs_mount *v7fsmount = (void *)mp->mnt_data;
struct vnode *devvp = NULL;
int error = 0;
bool update = mp->mnt_flag & MNT_UPDATE;
DPRINTF("mnt_flag=%x %s\n", mp->mnt_flag, update ? "update" : "");
if (*data_len < sizeof(*args))
return EINVAL;
if (mp->mnt_flag & MNT_GETARGS) {
if (!v7fsmount)
return EIO;
args->fspec = NULL;
args->endian = v7fsmount->core->endian;
*data_len = sizeof(*args);
return 0;
}
DPRINTF("args->fspec=%s endian=%d\n", args->fspec, args->endian);
if (args->fspec == NULL) {
/* nothing to do. */
return EINVAL;
}
if (args->fspec != NULL) {
/* Look up the name and verify that it's sane. */
error = namei_simple_user(args->fspec,
NSM_FOLLOW_NOEMULROOT, &devvp);
if (error != 0)
return (error);
DPRINTF("mount device=%lx\n", (long)devvp->v_rdev);
if (!update) {
/*
* Be sure this is a valid block device
*/
if (devvp->v_type != VBLK)
error = ENOTBLK;
else if (bdevsw_lookup(devvp->v_rdev) == NULL)
error = ENXIO;
} else {
KDASSERT(v7fsmount);
/*
* Be sure we're still naming the same device
* used for our initial mount
*/
if (devvp != v7fsmount->devvp) {
DPRINTF("devvp %p != %p rootvp=%p\n", devvp,
v7fsmount->devvp, rootvp);
if (rootvp == v7fsmount->devvp) {
vrele(devvp);
devvp = rootvp;
vref(devvp);
} else {
error = EINVAL;
}
}
}
}
/*
* If mount by non-root, then verify that user has necessary
* permissions on the device.
*
* Permission to update a mount is checked higher, so here we presume
* updating the mount is okay (for example, as far as securelevel goes)
* which leaves us with the normal check.
*/
if (error == 0) {
int accessmode = VREAD;
if (update ?
(mp->mnt_iflag & IMNT_WANTRDWR) != 0 :
(mp->mnt_flag & MNT_RDONLY) == 0)
accessmode |= VWRITE;
error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_MOUNT,
KAUTH_REQ_SYSTEM_MOUNT_DEVICE, mp, devvp,
KAUTH_ARG(accessmode));
}
if (error) {
vrele(devvp);
return error;
}
if (!update) {
if ((error = v7fs_openfs(devvp, mp, l))) {
vrele(devvp);
return error;
}
if ((error = v7fs_mountfs(devvp, mp, args->endian))) {
v7fs_closefs(devvp, mp);
VOP_UNLOCK(devvp);
vrele(devvp);
return error;
}
VOP_UNLOCK(devvp);
} else if (mp->mnt_flag & MNT_RDONLY) {
/* XXX: r/w -> read only */
}
return set_statvfs_info(path, UIO_USERSPACE, args->fspec, UIO_USERSPACE,
mp->mnt_op->vfs_name, mp, l);
}
static int
is_v7fs_partition(struct vnode *devvp)
{
struct dkwedge_info dkw;
int error;
if ((error = getdiskinfo(devvp, &dkw)) != 0) {
DPRINTF("getdiskinfo=%d\n", error);
return error;
}
DPRINTF("ptype=%s size=%" PRIu64 "\n", dkw.dkw_ptype, dkw->dkw_size);
return strcmp(dkw.dkw_ptype, DKW_PTYPE_V7) == 0 ? 0 : EINVAL;
}
static int
v7fs_openfs(struct vnode *devvp, struct mount *mp, struct lwp *l)
{
kauth_cred_t cred = l->l_cred;
int oflags;
int error;
/* Flush buffer */
vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
if ((error = vinvalbuf(devvp, V_SAVE, cred, l, 0, 0)))
goto unlock_exit;
/* Open block device */
oflags = FREAD;
if ((mp->mnt_flag & MNT_RDONLY) == 0)
oflags |= FWRITE;
if ((error = VOP_OPEN(devvp, oflags, NOCRED)) != 0) {
DPRINTF("VOP_OPEN=%d\n", error);
goto unlock_exit;
}
return 0; /* lock held */
unlock_exit:
VOP_UNLOCK(devvp);
return error;
}
static void
v7fs_closefs(struct vnode *devvp, struct mount *mp)
{
int oflags = FREAD;
if ((mp->mnt_flag & MNT_RDONLY) == 0)
oflags |= FWRITE;
VOP_CLOSE(devvp, oflags, NOCRED);
}
static int
v7fs_mountfs(struct vnode *devvp, struct mount *mp, int endian)
{
struct v7fs_mount *v7fsmount;
int error;
struct v7fs_mount_device mount;
DPRINTF("%d\n",endian);
v7fsmount = kmem_zalloc(sizeof(*v7fsmount), KM_SLEEP);
if (v7fsmount == NULL) {
return ENOMEM;
}
v7fsmount->devvp = devvp;
v7fsmount->mountp = mp;
mount.device.vnode = devvp;
mount.endian = endian;
if ((error = v7fs_io_init(&v7fsmount->core, &mount, V7FS_BSIZE))) {
goto err_exit;
}
struct v7fs_self *fs = v7fsmount->core;
if ((error = v7fs_superblock_load(fs))) {
v7fs_io_fini(fs);
goto err_exit;
}
LIST_INIT(&v7fsmount->v7fs_node_head);
mp->mnt_data = v7fsmount;
mp->mnt_stat.f_fsidx.__fsid_val[0] = (long)devvp->v_rdev;
mp->mnt_stat.f_fsidx.__fsid_val[1] = makefstype(MOUNT_V7FS);
mp->mnt_stat.f_fsid = mp->mnt_stat.f_fsidx.__fsid_val[0];
mp->mnt_stat.f_namemax = V7FS_NAME_MAX;
mp->mnt_flag |= MNT_LOCAL;
mp->mnt_dev_bshift = V7FS_BSHIFT;
mp->mnt_fs_bshift = V7FS_BSHIFT;
return 0;
err_exit:
kmem_free(v7fsmount, sizeof(*v7fsmount));
return error;
}
int
v7fs_start(struct mount *mp, int flags)
{
DPRINTF("\n");
/* Nothing to do. */
return 0;
}
int
v7fs_unmount(struct mount *mp, int mntflags)
{
struct v7fs_mount *v7fsmount = (void *)mp->mnt_data;
int error;
DPRINTF("%p\n", v7fsmount);
if ((error = vflush(mp, NULLVP,
mntflags & MNT_FORCE ? FORCECLOSE : 0)) != 0)
return error;
vn_lock(v7fsmount->devvp, LK_EXCLUSIVE | LK_RETRY);
error = VOP_CLOSE(v7fsmount->devvp, FREAD, NOCRED);
vput(v7fsmount->devvp);
v7fs_io_fini(v7fsmount->core);
kmem_free(v7fsmount, sizeof(*v7fsmount));
mp->mnt_data = NULL;
mp->mnt_flag &= ~MNT_LOCAL;
return 0;
}
int
v7fs_root(struct mount *mp, struct vnode **vpp)
{
struct vnode *vp;
int error;
DPRINTF("\n");
if ((error = VFS_VGET(mp, V7FS_ROOT_INODE, &vp)) != 0) {
DPRINTF("error=%d\n", error);
return error;
}
*vpp = vp;
DPRINTF("done.\n");
return 0;
}
int
v7fs_statvfs(struct mount *mp, struct statvfs *f)
{
struct v7fs_mount *v7fsmount = mp->mnt_data;
struct v7fs_self *fs = v7fsmount->core;
DPRINTF("scratch remain=%d\n", fs->scratch_remain);
v7fs_superblock_status(fs);
f->f_bsize = V7FS_BSIZE;
f->f_frsize = V7FS_BSIZE;
f->f_iosize = V7FS_BSIZE;
f->f_blocks = fs->stat.total_blocks;
f->f_bfree = fs->stat.free_blocks;
f->f_bavail = fs->stat.free_blocks;
f->f_bresvd = 0;
f->f_files = fs->stat.total_files;
f->f_ffree = fs->stat.free_inode;
f->f_favail = f->f_ffree;
f->f_fresvd = 0;
copy_statvfs_info(f, mp);
return 0;
}
int
v7fs_sync(struct mount *mp, int waitfor, kauth_cred_t cred)
{
struct v7fs_mount *v7fsmount = mp->mnt_data;
struct v7fs_self *fs = v7fsmount->core;
struct v7fs_node *v7fs_node;
struct v7fs_inode *inode;
struct vnode *v;
int err, error;
int retry_cnt;
DPRINTF("\n");
v7fs_superblock_writeback(fs);
for (retry_cnt = 0; retry_cnt < 2; retry_cnt++) {
error = 0;
mutex_enter(&mntvnode_lock);
for (v7fs_node = LIST_FIRST(&v7fsmount->v7fs_node_head);
v7fs_node != NULL; v7fs_node = LIST_NEXT(v7fs_node, link)) {
inode = &v7fs_node->inode;
if (!v7fs_inode_allocated(inode)) {
continue;
}
v = v7fs_node->vnode;
mutex_enter(v->v_interlock);
mutex_exit(&mntvnode_lock);
err = vget(v, LK_EXCLUSIVE | LK_NOWAIT);
if (err == 0) {
err = VOP_FSYNC(v, cred, FSYNC_WAIT, 0, 0);
vput(v);
}
if (err != 0)
error = err;
mutex_enter(&mntvnode_lock);
}
mutex_exit(&mntvnode_lock);
if (error == 0)
break;
}
return error;
}
static enum vtype
v7fs_mode_to_vtype (v7fs_mode_t mode)
{
enum vtype table[] = { VCHR, VDIR, VBLK, VREG, VLNK, VSOCK };
if ((mode & V7FS_IFMT) == V7FSBSD_IFFIFO)
return VFIFO;
return table[((mode >> 13) & 7) - 1];
}
int
v7fs_vget(struct mount *mp, ino_t ino, struct vnode **vpp)
{
struct v7fs_mount *v7fsmount = mp->mnt_data;
struct v7fs_self *fs = v7fsmount->core;
struct vnode *vp;
struct v7fs_node *v7fs_node;
struct v7fs_inode inode;
int error;
/* Lookup requested i-node */
if ((error = v7fs_inode_load(fs, &inode, ino))) {
DPRINTF("v7fs_inode_load failed.\n");
return error;
}
retry:
mutex_enter(&mntvnode_lock);
for (v7fs_node = LIST_FIRST(&v7fsmount->v7fs_node_head);
v7fs_node != NULL; v7fs_node = LIST_NEXT(v7fs_node, link)) {
if (v7fs_node->inode.inode_number == ino) {
vp = v7fs_node->vnode;
mutex_enter(vp->v_interlock);
mutex_exit(&mntvnode_lock);
if (vget(vp, LK_EXCLUSIVE) == 0) {
*vpp = vp;
return 0;
} else {
DPRINTF("retry!\n");
goto retry;
}
}
}
mutex_exit(&mntvnode_lock);
/* Allocate v-node. */
if ((error = getnewvnode(VT_V7FS, mp, v7fs_vnodeop_p, NULL, &vp))) {
DPRINTF("getnewvnode error.\n");
return error;
}
/* Lock vnode here */
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
/* Allocate i-node */
vp->v_data = pool_get(&v7fs_node_pool, PR_WAITOK);
memset(vp->v_data, 0, sizeof(*v7fs_node));
v7fs_node = vp->v_data;
mutex_enter(&mntvnode_lock);
LIST_INSERT_HEAD(&v7fsmount->v7fs_node_head, v7fs_node, link);
mutex_exit(&mntvnode_lock);
v7fs_node->vnode = vp;
v7fs_node->v7fsmount = v7fsmount;
v7fs_node->inode = inode;/*structure copy */
v7fs_node->lockf = NULL; /* advlock */
genfs_node_init(vp, &v7fs_genfsops);
uvm_vnp_setsize(vp, v7fs_inode_filesize(&inode));
if (ino == V7FS_ROOT_INODE) {
vp->v_type = VDIR;
vp->v_vflag |= VV_ROOT;
} else {
vp->v_type = v7fs_mode_to_vtype(inode.mode);
if (vp->v_type == VBLK || vp->v_type == VCHR) {
dev_t rdev = inode.device;
vp->v_op = v7fs_specop_p;
spec_node_init(vp, rdev);
} else if (vp->v_type == VFIFO) {
vp->v_op = v7fs_fifoop_p;
}
}
*vpp = vp;
return 0;
}
int
v7fs_fhtovp(struct mount *mp, struct fid *fid, struct vnode **vpp)
{
DPRINTF("\n");
/* notyet */
return EOPNOTSUPP;
}
int
v7fs_vptofh(struct vnode *vpp, struct fid *fid, size_t *fh_size)
{
DPRINTF("\n");
/* notyet */
return EOPNOTSUPP;
}
void
v7fs_init(void)
{
DPRINTF("\n");
pool_init(&v7fs_node_pool, sizeof(struct v7fs_node), 0, 0, 0,
"v7fs_node_pool", &pool_allocator_nointr, IPL_NONE);
}
void
v7fs_reinit(void)
{
/* Nothing to do. */
DPRINTF("\n");
}
void
v7fs_done(void)
{
DPRINTF("\n");
pool_destroy(&v7fs_node_pool);
}
int
v7fs_gop_alloc(struct vnode *vp, off_t off, off_t len, int flags,
kauth_cred_t cred)
{
DPRINTF("\n");
return 0;
}
int
v7fs_mountroot(void)
{
struct mount *mp;
int error;
DPRINTF("");
/* On mountroot, devvp (rootdev) is opened by vfs_mountroot */
if ((error = is_v7fs_partition (rootvp)))
return error;
if ((error = vfs_rootmountalloc(MOUNT_V7FS, "root_device", &mp))) {
DPRINTF("mountalloc error=%d\n", error);
vrele(rootvp);
return error;
}
if ((error = v7fs_mountfs(rootvp, mp, _BYTE_ORDER))) {
DPRINTF("mountfs error=%d\n", error);
vfs_unbusy(mp, false, NULL);
vfs_destroy(mp);
return error;
}
mountlist_append(mp);
vfs_unbusy(mp, false, NULL);
return 0;
}
/* Reload disk inode information */
int
v7fs_vnode_reload(struct mount *mp, struct vnode *vp)
{
struct v7fs_mount *v7fsmount = mp->mnt_data;
struct v7fs_self *fs = v7fsmount->core;
struct v7fs_node *v7fs_node;
struct v7fs_inode *inode = &((struct v7fs_node *)vp->v_data)->inode;
int target_ino = inode->inode_number;
int error = 0;
DPRINTF("#%d\n", target_ino);
mutex_enter(&mntvnode_lock);
for (v7fs_node = LIST_FIRST(&v7fsmount->v7fs_node_head);
v7fs_node != NULL; v7fs_node = LIST_NEXT(v7fs_node, link)) {
inode = &v7fs_node->inode;
if (!v7fs_inode_allocated(inode)) {
continue;
}
if (inode->inode_number == target_ino) {
error = v7fs_inode_load(fs, &v7fs_node->inode,
target_ino);
DPRINTF("sync #%d error=%d\n", target_ino, error);
break;
}
}
mutex_exit(&mntvnode_lock);
return error;
}

1328
sys/fs/v7fs/v7fs_vnops.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -15,7 +15,7 @@ SUBDIR= \
\ \
\ \
link \ link \
\ makefs \
mtree \ mtree \
\ \
\ \

37
usr.sbin/makefs/Makefile Normal file
View file

@ -0,0 +1,37 @@
# $NetBSD: Makefile,v 1.36 2013/08/05 14:41:57 reinoud Exp $
#
WARNS?= 5
.include <bsd.own.mk>
PROG= makefs
SRCS= cd9660.c chfs.c ffs.c v7fs.c msdos.c udf.c\
getid.c \
makefs.c misc.c \
pack_dev.c \
spec.c \
walk.c
MAN= makefs.8
MKNODSRC= ${NETBSDSRCDIR}/sbin/mknod
MTREESRC= ${NETBSDSRCDIR}/usr.sbin/mtree
CPPFLAGS+= -I${.CURDIR} -I${MKNODSRC} -I${MTREESRC} -DMAKEFS
#CPPFLAGS+= -DMSDOSFS_DEBUG
.PATH: ${MKNODSRC} ${MTREESRC}
.include "${.CURDIR}/cd9660/Makefile.inc"
.include "${.CURDIR}/chfs/Makefile.inc"
.include "${.CURDIR}/ffs/Makefile.inc"
.include "${.CURDIR}/v7fs/Makefile.inc"
.include "${.CURDIR}/msdos/Makefile.inc"
.include "${.CURDIR}/udf/Makefile.inc"
.if !defined(HOSTPROG)
DPADD+= ${LIBUTIL}
LDADD+= -lutil
.endif
.include <bsd.prog.mk>
# DO NOT DELETE

129
usr.sbin/makefs/README Normal file
View file

@ -0,0 +1,129 @@
$NetBSD: README,v 1.5 2011/07/18 08:58:38 uch Exp $
makefs - build a file system image from a directory tree
NOTES:
* This tool uses modified local copies of source found in other
parts of the tree. This is intentional.
* makefs is a work in progress, and subject to change.
user overview:
--------------
makefs creates a file system image from a given directory tree.
the following file system types can be built:
ffs BSD fast file system
cd9660 ISO 9660 file system
v7fs 7th edition(V7) file system
Support for the following file systems maybe be added in the future
ext2fs Linux EXT2 file system
fat MS-DOS `FAT' file system (FAT12, FAT16, FAT32)
Various file system independent parameters and contraints can be
specified, such as:
- minimum file system size (in KB)
- maximum file system size (in KB)
- free inodes
- free blocks (in KB)
- mtree(8) specification file containing permissions and ownership
to use in image, overridding the settings in the directory tree
- file containing list of files to specifically exclude or include
- fnmatch(3) pattern of filenames to exclude or include
- endianness of target file system
File system specific parameters can be given as well, with a command
line option such as "-o fsspeccific-options,comma-separated".
For example, ffs would allow tuning of:
- block & fragment size
- cylinder groups
- number of blocks per inode
- minimum free space
Other file systems might have controls on how to "munge" file names to
fit within the constraints of the target file system.
Exit codes:
0 all ok
1 fatal error
2 some files couldn't be added during image creation
(bad perms, missing file, etc). image will continue
to be made
Implementation overview:
------------------------
The implementation must allow for easy addition of extra file systems
with minimal changes to the file system independent sections.
The main program will:
- parse the options, including calling fs-specific routines to
validate fs-specific options
- walk the tree, building up a data structure which represents
the tree to stuff into the image. The structure will
probably be a similar tree to what mtree(8) uses internally;
a linked list of entries per directory with a child pointer
to children of directories. ".." won't be stored in the list;
the fs-specific tree walker should add this if required by the fs.
this builder have the smarts to handle hard links correctly.
- (optionally) Change the permissions in the tree according to
the mtree(8) specfile
- Call an fs-specific routine to build the image based on the
data structures.
Each fs-specific module should have the following external interfaces:
prepare_options optional file system specific defaults that need to be
setup before parsing fs-specific options.
parse_options parse the string for fs-specific options, feeding
errors back to the user as appropriate
cleanup_options optional file system specific data that need to be
cleaned up when done with this filesystem.
make_fs take the data structures representing the
directory tree and fs parameters,
validate that the parameters are valid
(e.g, the requested image will be large enough),
create the image, and
populate the image
prepare_options and cleanup_options are optional and can be NULL.
NOTE: All file system specific options are referenced via the fs_specific
pointer from the fsinfo_t strucutre. It is up to the filesystem to allocate
and free any data needed for this via the prepare and cleanup callbacks.
Each fs-specific module will need to add it's routines to the dispatch array
in makefs.c and add prototypes for these to makefs.h
All other implementation details should not need to change any of the
generic code.
ffs implementation
------------------
In the ffs case, we can leverage off sbin/newfs/mkfs.c to actually build
the image. When building and populating the image, the implementation
can be greatly simplified if some assumptions are made:
- the total required size (in blocks and inodes) is determined
as part of the validation phase
- a "file" (including a directory) has a known size, so
support for growing a file is not necessary
Two underlying primitives are provided:
make_inode create an inode, returning the inode number
write_file write file (from memory if DIR, file descriptor
if FILE or SYMLINK), referencing given inode.
it is smart enough to know if a short symlink
can be stuffed into the inode, etc.
When creating a directory, the directory entries in the previously
built tree data structure is scanned and built in memory so it can
be written entirely as a single write_file() operation.

41
usr.sbin/makefs/TODO Normal file
View file

@ -0,0 +1,41 @@
$NetBSD: TODO,v 1.7 2007/12/10 23:54:35 dyoung Exp $
todo
----
- read files from multiple directories with or without root
specification, e.g., makefs -t cd9660 output.iso dir1 root2=dir2
dir3 root4=dir4
- display block numbers for a given file (e.g, /boot)
- finish makefs.8
- testing
- even more testing
- add support for converting a tar file (instead of a directory tree);
suggested by kpneal@pobox.com
outstanding bugs
----------------
- size estimation is still out (need to take into account indirect blocks!)
- parameter checking when density is rather high or low.
- filling up a file system (running out of inodes or whatever)
doesn't do the right thing.
discuss
-------
- consider replacing ffs_balloc() et al with own code that doesn't
need hacked-up buf.c code
- whacking on newfs/mkfs.c to allow .PATH-ing directly into makefs(8).
this would involve passing all of mkfs()'s parameters in a single
struct rather than a lot of global vars, etc.

2148
usr.sbin/makefs/cd9660.c Normal file

File diff suppressed because it is too large Load diff

357
usr.sbin/makefs/cd9660.h Normal file
View file

@ -0,0 +1,357 @@
/* $NetBSD: cd9660.h,v 1.20 2013/01/29 15:52:25 christos Exp $ */
/*
* Copyright (c) 2005 Daniel Watt, Walter Deignan, Ryan Gabrys, Alan
* Perez-Rathke and Ram Vedam. All rights reserved.
*
* This code was written by Daniel Watt, Walter Deignan, Ryan Gabrys,
* Alan Perez-Rathke and Ram Vedam.
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY DANIEL WATT, WALTER DEIGNAN, RYAN
* GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL DANIEL WATT, WALTER DEIGNAN, RYAN
* GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE,DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*/
#ifndef _MAKEFS_CD9660_H
#define _MAKEFS_CD9660_H
#if HAVE_NBTOOL_CONFIG_H
#include "nbtool_config.h"
#endif
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include <limits.h>
#include <sys/queue.h>
#include <sys/param.h>
#include <sys/endian.h>
#include "makefs.h"
#include "iso.h"
#include "iso_rrip.h"
#include "cd9660/cd9660_eltorito.h"
#ifdef DEBUG
#define INODE_WARNX(__x) warnx __x
#else /* DEBUG */
#define INODE_WARNX(__x)
#endif /* DEBUG */
#define CD9660MAXPATH 4096
#define ISO_STRING_FILTER_NONE = 0x00
#define ISO_STRING_FILTER_DCHARS = 0x01
#define ISO_STRING_FILTER_ACHARS = 0x02
/*
Extended preferences type, in the spirit of what makefs gives us (only ints)
*/
typedef struct {
const char *shortName; /* Short option */
const char *name; /* option name */
char *value; /* where to stuff the value */
int minLength; /* minimum for value */
int maxLength; /* maximum for value */
const char *desc; /* option description */
int filterFlags;
} string_option_t;
/******** STRUCTURES **********/
/*Defaults*/
#define ISO_DEFAULT_VOLUMEID "MAKEFS_CD9660_IMAGE"
#define ISO_DEFAULT_APPID "MAKEFS"
#define ISO_DEFAULT_PUBLISHER "MAKEFS"
#define ISO_DEFAULT_PREPARER "MAKEFS"
#define ISO_VOLUME_DESCRIPTOR_STANDARD_ID "CD001"
#define ISO_VOLUME_DESCRIPTOR_BOOT 0
#define ISO_VOLUME_DESCRIPTOR_PVD 1
#define ISO_VOLUME_DESCRIPTOR_TERMINATOR 255
/*30 for name and extension, as well as version number and padding bit*/
#define ISO_FILENAME_MAXLENGTH_BEFORE_VERSION 30
#define ISO_FILENAME_MAXLENGTH 36
#define ISO_FILENAME_MAXLENGTH_WITH_PADDING 37
#define ISO_FLAG_CLEAR 0x00
#define ISO_FLAG_HIDDEN 0x01
#define ISO_FLAG_DIRECTORY 0x02
#define ISO_FLAG_ASSOCIATED 0x04
#define ISO_FLAG_PERMISSIONS 0x08
#define ISO_FLAG_RESERVED5 0x10
#define ISO_FLAG_RESERVED6 0x20
#define ISO_FLAG_FINAL_RECORD 0x40
#define ISO_PATHTABLE_ENTRY_BASESIZE 8
#define ISO_RRIP_DEFAULT_MOVE_DIR_NAME "RR_MOVED"
#define RRIP_DEFAULT_MOVE_DIR_NAME ".rr_moved"
#define CD9660_BLOCKS(__sector_size, __bytes) \
howmany((__bytes), (__sector_size))
#define CD9660_MEM_ALLOC_ERROR(_F) \
err(EXIT_FAILURE, "%s, %s l. %d", _F, __FILE__, __LINE__)
#define CD9660_TYPE_FILE 0x01
#define CD9660_TYPE_DIR 0x02
#define CD9660_TYPE_DOT 0x04
#define CD9660_TYPE_DOTDOT 0x08
#define CD9660_TYPE_VIRTUAL 0x80
#define CD9660_INODE_HASH_SIZE 1024
#define CD9660_SECTOR_SIZE 2048
#define CD9660_END_PADDING 150
/* Slight modification of the ISO structure in iso.h */
typedef struct _iso_directory_record_cd9660 {
u_char length [ISODCL (1, 1)]; /* 711 */
u_char ext_attr_length [ISODCL (2, 2)]; /* 711 */
u_char extent [ISODCL (3, 10)]; /* 733 */
u_char size [ISODCL (11, 18)]; /* 733 */
u_char date [ISODCL (19, 25)]; /* 7 by 711 */
u_char flags [ISODCL (26, 26)];
u_char file_unit_size [ISODCL (27, 27)]; /* 711 */
u_char interleave [ISODCL (28, 28)]; /* 711 */
u_char volume_sequence_number [ISODCL (29, 32)]; /* 723 */
u_char name_len [ISODCL (33, 33)]; /* 711 */
char name [ISO_FILENAME_MAXLENGTH_WITH_PADDING];
} iso_directory_record_cd9660;
/* TODO: Lots of optimization of this structure */
typedef struct _cd9660node {
u_char type;/* Used internally */
/* Tree structure */
struct _cd9660node *parent; /* parent (NULL if root) */
TAILQ_HEAD(cd9660_children_head, _cd9660node) cn_children;
TAILQ_ENTRY(_cd9660node) cn_next_child;
struct _cd9660node *dot_record; /* For directories, used mainly in RRIP */
struct _cd9660node *dot_dot_record;
fsnode *node; /* pointer to fsnode */
struct _iso_directory_record_cd9660 *isoDirRecord;
struct iso_extended_attributes *isoExtAttributes;
/***** SIZE CALCULATION *****/
/*already stored in isoDirRecord, but this is an int version, and will be
copied to isoDirRecord on writing*/
uint32_t fileDataSector;
/*
* same thing, though some notes:
* If a file, this is the file size
* If a directory, this is the size of all its children's
* directory records
* plus necessary padding
*/
int64_t fileDataLength;
int64_t fileSectorsUsed;
int fileRecordSize;/*copy of a variable, int for quicker calculations*/
/* Old name, used for renaming - needs to be optimized but low priority */
char o_name [ISO_FILENAME_MAXLENGTH_WITH_PADDING];
/***** SPACE RESERVED FOR EXTENSIONS *****/
/* For memory efficiency's sake - we should move this to a separate struct
and point to null if not needed */
/* For Rock Ridge */
struct _cd9660node *rr_real_parent, *rr_relocated;
int64_t susp_entry_size;
int64_t susp_dot_entry_size;
int64_t susp_dot_dot_entry_size;
/* Continuation area stuff */
int64_t susp_entry_ce_start;
int64_t susp_dot_ce_start;
int64_t susp_dot_dot_ce_start;
int64_t susp_entry_ce_length;
int64_t susp_dot_ce_length;
int64_t susp_dot_dot_ce_length;
/* Data to put at the end of the System Use field */
int64_t su_tail_size;
char *su_tail_data;
/*** PATH TABLE STUFF ***/
int level; /*depth*/
int ptnumber;
struct _cd9660node *ptnext, *ptprev, *ptlast;
/* SUSP entries */
TAILQ_HEAD(susp_linked_list, ISO_SUSP_ATTRIBUTES) head;
} cd9660node;
typedef struct _path_table_entry
{
u_char length[ISODCL (1, 1)];
u_char extended_attribute_length[ISODCL (2, 2)];
u_char first_sector[ISODCL (3, 6)];
u_char parent_number[ISODCL (7, 8)];
u_char name[ISO_FILENAME_MAXLENGTH_WITH_PADDING];
} path_table_entry;
typedef struct _volume_descriptor
{
u_char *volumeDescriptorData; /*ALWAYS 2048 bytes long*/
int64_t sector;
struct _volume_descriptor *next;
} volume_descriptor;
typedef struct _iso9660_disk {
int sectorSize;
struct iso_primary_descriptor primaryDescriptor;
struct iso_supplementary_descriptor supplementaryDescriptor;
volume_descriptor *firstVolumeDescriptor;
cd9660node *rootNode;
/* Important sector numbers here */
/* primaryDescriptor.type_l_path_table*/
int64_t primaryBigEndianTableSector;
/* primaryDescriptor.type_m_path_table*/
int64_t primaryLittleEndianTableSector;
/* primaryDescriptor.opt_type_l_path_table*/
int64_t secondaryBigEndianTableSector;
/* primaryDescriptor.opt_type_m_path_table*/
int64_t secondaryLittleEndianTableSector;
/* primaryDescriptor.path_table_size*/
int pathTableLength;
int64_t dataFirstSector;
int64_t totalSectors;
/* OPTIONS GO HERE */
int isoLevel;
int include_padding_areas;
int follow_sym_links;
int verbose_level;
int displayHelp;
int keep_bad_images;
/* SUSP options and variables */
int64_t susp_continuation_area_start_sector;
int64_t susp_continuation_area_size;
int64_t susp_continuation_area_current_free;
int rock_ridge_enabled;
/* Other Rock Ridge Variables */
char *rock_ridge_renamed_dir_name;
int rock_ridge_move_count;
cd9660node *rr_moved_dir;
int archimedes_enabled;
int chrp_boot;
/* Spec breaking options */
u_char allow_deep_trees;
u_char allow_start_dot;
u_char allow_max_name; /* Allow 37 char filenames*/
u_char allow_illegal_chars; /* ~, !, # */
u_char allow_lowercase;
u_char allow_multidot;
u_char omit_trailing_period;
/* BOOT INFORMATION HERE */
int has_generic_bootimage; /* Default to 0 */
char *generic_bootimage;
int is_bootable;/* Default to 0 */
int64_t boot_catalog_sector;
boot_volume_descriptor *boot_descriptor;
char * boot_image_directory;
TAILQ_HEAD(boot_image_list,cd9660_boot_image) boot_images;
int image_serialno;
LIST_HEAD(boot_catalog_entries,boot_catalog_entry) boot_entries;
} iso9660_disk;
/************ FUNCTIONS **************/
int cd9660_valid_a_chars(const char *);
int cd9660_valid_d_chars(const char *);
void cd9660_uppercase_characters(char *, int);
/* ISO Data Types */
void cd9660_721(uint16_t, unsigned char *);
void cd9660_731(uint32_t, unsigned char *);
void cd9660_722(uint16_t, unsigned char *);
void cd9660_732(uint32_t, unsigned char *);
void cd9660_bothendian_dword(uint32_t dw, unsigned char *);
void cd9660_bothendian_word(uint16_t dw, unsigned char *);
void cd9660_set_date(char *, time_t);
void cd9660_time_8426(unsigned char *, time_t);
void cd9660_time_915(unsigned char *, time_t);
/*** Boot Functions ***/
int cd9660_write_generic_bootimage(FILE *);
int cd9660_write_boot(iso9660_disk *, FILE *);
int cd9660_add_boot_disk(iso9660_disk *, const char *);
int cd9660_eltorito_add_boot_option(iso9660_disk *, const char *,
const char *);
int cd9660_setup_boot(iso9660_disk *, int);
int cd9660_setup_boot_volume_descriptor(iso9660_disk *,
volume_descriptor *);
/*** Write Functions ***/
int cd9660_write_image(iso9660_disk *, const char *image);
int cd9660_copy_file(iso9660_disk *, FILE *, off_t, const char *);
void cd9660_compute_full_filename(cd9660node *, char *);
int cd9660_compute_record_size(iso9660_disk *, cd9660node *);
/* Debugging functions */
void debug_print_tree(iso9660_disk *, cd9660node *,int);
void debug_print_path_tree(cd9660node *);
void debug_print_volume_descriptor_information(iso9660_disk *);
void debug_dump_to_xml_ptentry(path_table_entry *,int, int);
void debug_dump_to_xml_path_table(FILE *, off_t, int, int);
void debug_dump_to_xml(FILE *);
int debug_get_encoded_number(unsigned char *, int);
void debug_dump_integer(const char *, char *,int);
void debug_dump_string(const char *,unsigned char *,int);
void debug_dump_directory_record_9_1(unsigned char *);
void debug_dump_to_xml_volume_descriptor(unsigned char *,int);
void cd9660_pad_string_spaces(char *, int);
#endif

View file

@ -0,0 +1,15 @@
# $NetBSD: Makefile.inc,v 1.3 2012/08/10 12:10:29 joerg Exp $
#
.PATH: ${.CURDIR}/cd9660 ${NETBSDSRCDIR}/sys/fs/cd9660
CPPFLAGS+=-I${NETBSDSRCDIR}/sys/fs/cd9660
SRCS+= cd9660_strings.c cd9660_debug.c cd9660_eltorito.c
SRCS+= cd9660_write.c cd9660_conversion.c iso9660_rrip.c cd9660_archimedes.c
.if !defined(HOSTPROGNAME)
.for f in cd9660_debug cd9660_write
COPTS.${f}.c+= -Wno-pointer-sign
.endfor
.endif

View file

@ -0,0 +1,130 @@
/* $NetBSD: cd9660_archimedes.c,v 1.2 2013/01/28 21:03:28 christos Exp $ */
/*-
* Copyright (c) 1998, 2009 Ben Harris
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* cd9660_archimedes.c - support for RISC OS "ARCHIMEDES" extension
*
* RISC OS CDFS looks for a special block at the end of the System Use
* Field for each file. If present, this contains the RISC OS load
* and exec address (used to hold the file timestamp and type), the
* file attributes, and a flag indicating whether the first character
* of the filename should be replaced with '!' (since many special
* RISC OS filenames do).
*/
#if HAVE_NBTOOL_CONFIG_H
#include "nbtool_config.h"
#endif
#include <sys/cdefs.h>
#if defined(__RCSID) && !defined(__lint)
__RCSID("$NetBSD: cd9660_archimedes.c,v 1.2 2013/01/28 21:03:28 christos Exp $");
#endif /* !__lint */
#include <assert.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <util.h>
#include "makefs.h"
#include "cd9660.h"
#include "cd9660_archimedes.h"
/*
* Convert a Unix time_t (non-leap seconds since 1970-01-01) to a RISC
* OS time (non-leap(?) centiseconds since 1900-01-01(?)).
*/
static u_int64_t
riscos_date(time_t unixtime)
{
u_int64_t base;
base = 31536000ULL * 70 + 86400 * 17;
return (((u_int64_t)unixtime) + base)*100;
}
/*
* Add "ARCHIMEDES" metadata to a node if that seems appropriate.
*
* We touch regular files with names matching /,[0-9a-f]{3}$/ and
* directories matching /^!/.
*/
static void
archimedes_convert_node(cd9660node *node)
{
struct ISO_ARCHIMEDES *arc;
size_t len;
int type = -1;
uint64_t stamp;
if (node->su_tail_data != NULL)
/* Something else already has the tail. */
return;
len = strlen(node->node->name);
if (len < 1) return;
if (len >= 4 && node->node->name[len-4] == ',')
/* XXX should support ,xxx and ,lxa */
type = strtoul(node->node->name + len - 3, NULL, 16);
if (type == -1 && node->node->name[0] != '!')
return;
if (type == -1) type = 0;
assert(sizeof(*arc) == 32);
arc = ecalloc(1, sizeof(*arc));
stamp = riscos_date(node->node->inode->st.st_mtime);
memcpy(arc->magic, "ARCHIMEDES", 10);
cd9660_731(0xfff00000 | (type << 8) | (stamp >> 32), arc->loadaddr);
cd9660_731(stamp & 0x00ffffffffULL, arc->execaddr);
arc->ro_attr = RO_ACCESS_UR | RO_ACCESS_OR;
arc->cdfs_attr = node->node->name[0] == '!' ? CDFS_PLING : 0;
node->su_tail_data = (void *)arc;
node->su_tail_size = sizeof(*arc);
}
/*
* Add "ARCHIMEDES" metadata to an entire tree recursively.
*/
void
archimedes_convert_tree(cd9660node *node)
{
cd9660node *cn;
assert(node != NULL);
archimedes_convert_node(node);
/* Recurse on children. */
TAILQ_FOREACH(cn, &node->cn_children, cn_next_child)
archimedes_convert_tree(cn);
}

View file

@ -0,0 +1,48 @@
/* $NetBSD: cd9660_archimedes.h,v 1.1 2009/01/10 22:06:29 bjh21 Exp $ */
/*-
* Copyright (c) 1998, 2009 Ben Harris
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* cd9660_archimedes.c - support for RISC OS "ARCHIMEDES" extension
*/
struct ISO_ARCHIMEDES {
char magic[10]; /* "ARCHIMEDES" */
unsigned char loadaddr[4]; /* Load address, little-endian */
unsigned char execaddr[4]; /* Exec address, little-endian */
unsigned char ro_attr; /* RISC OS attributes */
#define RO_ACCESS_UR 0x01 /* Owner read */
#define RO_ACCESS_UW 0x02 /* Owner write */
#define RO_ACCESS_L 0x04 /* Locked */
#define RO_ACCESS_OR 0x10 /* Public read */
#define RO_ACCESS_OW 0x20 /* Public write */
unsigned char cdfs_attr; /* Extra attributes for CDFS */
#define CDFS_PLING 0x01 /* Filename begins with '!' */
char reserved[12];
};
extern void archimedes_convert_tree(cd9660node *);

View file

@ -0,0 +1,203 @@
/* $NetBSD: cd9660_conversion.c,v 1.4 2007/03/14 14:11:17 christos Exp $ */
/*
* Copyright (c) 2005 Daniel Watt, Walter Deignan, Ryan Gabrys, Alan
* Perez-Rathke and Ram Vedam. All rights reserved.
*
* This code was written by Daniel Watt, Walter Deignan, Ryan Gabrys,
* Alan Perez-Rathke and Ram Vedam.
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY DANIEL WATT, WALTER DEIGNAN, RYAN
* GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL DANIEL WATT, WALTER DEIGNAN, RYAN
* GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE,DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*/
#include "cd9660.h"
#include <sys/cdefs.h>
#if defined(__RCSID) && !defined(__lint)
__RCSID("$NetBSD: cd9660_conversion.c,v 1.4 2007/03/14 14:11:17 christos Exp $");
#endif /* !__lint */
static char cd9660_compute_gm_offset(time_t);
#if 0
static inline int
cd9660_pad_even(length)
int length;
{
return length + (length & 0x01);
}
#endif
/*
* These can probably be implemented using a macro
*/
/* Little endian */
void
cd9660_721(uint16_t w, unsigned char *twochar)
{
#if BYTE_ORDER == BIG_ENDIAN
w = bswap16(w);
#endif
memcpy(twochar,&w,2);
}
void
cd9660_731(uint32_t w, unsigned char *fourchar)
{
#if BYTE_ORDER == BIG_ENDIAN
w = bswap32(w);
#endif
memcpy(fourchar,&w,4);
}
/* Big endian */
void
cd9660_722(uint16_t w, unsigned char *twochar)
{
#if BYTE_ORDER == LITTLE_ENDIAN
w = bswap16(w);
#endif
memcpy(twochar,&w,2);
}
void
cd9660_732(uint32_t w, unsigned char *fourchar)
{
#if BYTE_ORDER == LITTLE_ENDIAN
w = bswap32(w);
#endif
memcpy(fourchar,&w,4);
}
/**
* Convert a dword into a double endian string of eight characters
* @param int The double word to convert
* @param char* The string to write the both endian double word to - It is assumed this is allocated and at least
* eight characters long
*/
void
cd9660_bothendian_dword(uint32_t dw, unsigned char *eightchar)
{
uint32_t le, be;
#if BYTE_ORDER == LITTLE_ENDIAN
le = dw;
be = bswap32(dw);
#endif
#if BYTE_ORDER == BIG_ENDIAN
be = dw;
le = bswap32(dw);
#endif
memcpy(eightchar, &le, 4);
memcpy((eightchar+4), &be, 4);
}
/**
* Convert a word into a double endian string of four characters
* @param int The word to convert
* @param char* The string to write the both endian word to - It is assumed this is allocated and at least
* four characters long
*/
void
cd9660_bothendian_word(uint16_t dw, unsigned char *fourchar)
{
uint16_t le, be;
#if BYTE_ORDER == LITTLE_ENDIAN
le = dw;
be = bswap16(dw);
#endif
#if BYTE_ORDER == BIG_ENDIAN
be = dw;
le = bswap16(dw);
#endif
memcpy(fourchar, &le, 2);
memcpy((fourchar+2), &be, 2);
}
void
cd9660_pad_string_spaces(char *str, int len)
{
int i;
for (i = 0; i < len; i ++) {
if (str[i] == '\0')
str[i] = 0x20;
}
}
static char
cd9660_compute_gm_offset(time_t tim)
{
struct tm t, gm;
(void)localtime_r(&tim, &t);
(void)gmtime_r(&tim, &gm);
gm.tm_year -= t.tm_year;
gm.tm_yday -= t.tm_yday;
gm.tm_hour -= t.tm_hour;
gm.tm_min -= t.tm_min;
if (gm.tm_year < 0)
gm.tm_yday = -1;
else if (gm.tm_year > 0)
gm.tm_yday = 1;
return (char)(-(gm.tm_min + 60* (24 * gm.tm_yday + gm.tm_hour)) / 15);
}
/* Long dates: 17 characters */
void
cd9660_time_8426(unsigned char *buf, time_t tim)
{
struct tm t;
char temp[18];
(void)localtime_r(&tim, &t);
(void)snprintf(temp, sizeof(temp), "%04i%02i%02i%02i%02i%02i%02i",
1900+(int)t.tm_year,
(int)t.tm_mon+1,
(int)t.tm_mday,
(int)t.tm_hour,
(int)t.tm_min,
(int)t.tm_sec,
0);
(void)memcpy(buf, temp, 16);
buf[16] = cd9660_compute_gm_offset(tim);
}
/* Short dates: 7 characters */
void
cd9660_time_915(unsigned char *buf, time_t tim)
{
struct tm t;
(void)localtime_r(&tim, &t);
buf[0] = t.tm_year;
buf[1] = t.tm_mon+1;
buf[2] = t.tm_mday;
buf[3] = t.tm_hour;
buf[4] = t.tm_min;
buf[5] = t.tm_sec;
buf[6] = cd9660_compute_gm_offset(tim);
}

View file

@ -0,0 +1,498 @@
/* $NetBSD: cd9660_debug.c,v 1.13 2013/10/19 17:16:37 christos Exp $ */
/*
* Copyright (c) 2005 Daniel Watt, Walter Deignan, Ryan Gabrys, Alan
* Perez-Rathke and Ram Vedam. All rights reserved.
*
* This code was written by Daniel Watt, Walter Deignan, Ryan Gabrys,
* Alan Perez-Rathke and Ram Vedam.
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY DANIEL WATT, WALTER DEIGNAN, RYAN
* GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL DANIEL WATT, WALTER DEIGNAN, RYAN
* GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE,DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*/
#if HAVE_NBTOOL_CONFIG_H
#include "nbtool_config.h"
#endif
#include <sys/cdefs.h>
#include <sys/param.h>
#if defined(__RCSID) && !defined(__lint)
__RCSID("$NetBSD: cd9660_debug.c,v 1.13 2013/10/19 17:16:37 christos Exp $");
#endif /* !__lint */
#if !HAVE_NBTOOL_CONFIG_H
#include <sys/mount.h>
#endif
#include "makefs.h"
#include "cd9660.h"
#include "iso9660_rrip.h"
static void debug_print_susp_attrs(cd9660node *, int);
static void debug_dump_to_xml_padded_hex_output(const char *, unsigned char *,
int);
static inline void
print_n_tabs(int n)
{
int i;
for (i = 1; i <= n; i ++)
printf("\t");
}
#if 0
void
debug_print_rrip_info(n)
cd9660node *n;
{
struct ISO_SUSP_ATTRIBUTES *t;
TAILQ_FOREACH(t, &node->head, rr_ll) {
}
}
#endif
static void
debug_print_susp_attrs(cd9660node *n, int indent)
{
struct ISO_SUSP_ATTRIBUTES *t;
TAILQ_FOREACH(t, &n->head, rr_ll) {
print_n_tabs(indent);
printf("-");
printf("%c%c: L:%i",t->attr.su_entry.SP.h.type[0],
t->attr.su_entry.SP.h.type[1],
(int)t->attr.su_entry.SP.h.length[0]);
printf("\n");
}
}
void
debug_print_tree(iso9660_disk *diskStructure, cd9660node *node, int level)
{
#if !HAVE_NBTOOL_CONFIG_H
cd9660node *cn;
print_n_tabs(level);
if (node->type & CD9660_TYPE_DOT) {
printf(". (%i)\n",
isonum_733(node->isoDirRecord->extent));
} else if (node->type & CD9660_TYPE_DOTDOT) {
printf("..(%i)\n",
isonum_733(node->isoDirRecord->extent));
} else if (node->isoDirRecord->name[0]=='\0') {
printf("(ROOT) (%" PRIu32 " to %" PRId64 ")\n",
node->fileDataSector,
node->fileDataSector +
node->fileSectorsUsed - 1);
} else {
printf("%s (%s) (%" PRIu32 " to %" PRId64 ")\n",
node->isoDirRecord->name,
(node->isoDirRecord->flags[0]
& ISO_FLAG_DIRECTORY) ? "DIR" : "FILE",
node->fileDataSector,
(node->fileSectorsUsed == 0) ?
node->fileDataSector :
node->fileDataSector
+ node->fileSectorsUsed - 1);
}
if (diskStructure->rock_ridge_enabled)
debug_print_susp_attrs(node, level + 1);
TAILQ_FOREACH(cn, &node->cn_children, cn_next_child)
debug_print_tree(diskStructure, cn, level + 1);
#else
printf("Sorry, debugging is not supported in host-tools mode.\n");
#endif
}
void
debug_print_path_tree(cd9660node *n)
{
cd9660node *iterator = n;
/* Only display this message when called with the root node */
if (n->parent == NULL)
printf("debug_print_path_table: Dumping path table contents\n");
while (iterator != NULL) {
if (iterator->isoDirRecord->name[0] == '\0')
printf("0) (ROOT)\n");
else
printf("%i) %s\n", iterator->level,
iterator->isoDirRecord->name);
iterator = iterator->ptnext;
}
}
void
debug_print_volume_descriptor_information(iso9660_disk *diskStructure)
{
volume_descriptor *tmp = diskStructure->firstVolumeDescriptor;
char temp[CD9660_SECTOR_SIZE];
printf("==Listing Volume Descriptors==\n");
while (tmp != NULL) {
memset(temp, 0, CD9660_SECTOR_SIZE);
memcpy(temp, tmp->volumeDescriptorData + 1, 5);
printf("Volume descriptor in sector %" PRId64
": type %i, ID %s\n",
tmp->sector, tmp->volumeDescriptorData[0], temp);
switch(tmp->volumeDescriptorData[0]) {
case 0:/*boot record*/
break;
case 1: /* PVD */
break;
case 2: /* SVD */
break;
case 3: /* Volume Partition Descriptor */
break;
case 255: /* terminator */
break;
}
tmp = tmp->next;
}
printf("==Done Listing Volume Descriptors==\n");
}
void
debug_dump_to_xml_ptentry(path_table_entry *pttemp, int num, int mode)
{
printf("<ptentry num=\"%i\">\n" ,num);
printf("<length>%i</length>\n", pttemp->length[0]);
printf("<extended_attribute_length>%i</extended_attribute_length>\n",
pttemp->extended_attribute_length[0]);
printf("<parent_number>%i</parent_number>\n",
debug_get_encoded_number(pttemp->parent_number,mode));
debug_dump_to_xml_padded_hex_output("name",
pttemp->name, pttemp->length[0]);
printf("</ptentry>\n");
}
void
debug_dump_to_xml_path_table(FILE *fd, off_t sector, int size, int mode)
{
path_table_entry pttemp;
int t = 0;
int n = 0;
if (fseeko(fd, CD9660_SECTOR_SIZE * sector, SEEK_SET) == -1)
err(1, "fseeko");
while (t < size) {
/* Read fixed data first */
fread(&pttemp, 1, 8, fd);
t += 8;
/* Read variable */
fread(((unsigned char*)&pttemp) + 8, 1, pttemp.length[0], fd);
t += pttemp.length[0];
debug_dump_to_xml_ptentry(&pttemp, n, mode);
n++;
}
}
/*
* XML Debug output functions
* Dump hierarchy of CD, as well as volume info, to XML
* Can be used later to diff against a standard,
* or just provide easy to read detailed debug output
*/
void
debug_dump_to_xml(FILE *fd)
{
unsigned char buf[CD9660_SECTOR_SIZE];
off_t sector;
int t, t2;
struct iso_primary_descriptor primaryVD;
struct _boot_volume_descriptor bootVD;
memset(&primaryVD, 0, sizeof(primaryVD));
printf("<cd9660dump>\n");
/* Display Volume Descriptors */
sector = 16;
do {
if (fseeko(fd, CD9660_SECTOR_SIZE * sector, SEEK_SET) == -1)
err(1, "fseeko");
fread(buf, 1, CD9660_SECTOR_SIZE, fd);
t = (int)((unsigned char)buf[0]);
switch (t) {
case 0:
memcpy(&bootVD, buf, CD9660_SECTOR_SIZE);
break;
case 1:
memcpy(&primaryVD, buf, CD9660_SECTOR_SIZE);
break;
}
debug_dump_to_xml_volume_descriptor(buf, sector);
sector++;
} while (t != 255);
t = debug_get_encoded_number((u_char *)primaryVD.type_l_path_table,
731);
t2 = debug_get_encoded_number((u_char *)primaryVD.path_table_size, 733);
printf("Path table 1 located at sector %i and is %i bytes long\n",
t,t2);
debug_dump_to_xml_path_table(fd, t, t2, 721);
t = debug_get_encoded_number((u_char *)primaryVD.type_m_path_table,
731);
debug_dump_to_xml_path_table(fd, t, t2, 722);
printf("</cd9660dump>\n");
}
static void
debug_dump_to_xml_padded_hex_output(const char *element, unsigned char *buf,
int len)
{
int i;
int t;
printf("<%s>",element);
for (i = 0; i < len; i++) {
t = (unsigned char)buf[i];
if (t >= 32 && t < 127)
printf("%c",t);
}
printf("</%s>\n",element);
printf("<%s:hex>",element);
for (i = 0; i < len; i++) {
t = (unsigned char)buf[i];
printf(" %x",t);
}
printf("</%s:hex>\n",element);
}
int
debug_get_encoded_number(unsigned char* buf, int mode)
{
#if !HAVE_NBTOOL_CONFIG_H
switch (mode) {
/* 711: Single bite */
case 711:
return isonum_711(buf);
/* 712: Single signed byte */
case 712:
return isonum_712((signed char *)buf);
/* 721: 16 bit LE */
case 721:
return isonum_721(buf);
/* 731: 32 bit LE */
case 731:
return isonum_731(buf);
/* 722: 16 bit BE */
case 722:
return isonum_722(buf);
/* 732: 32 bit BE */
case 732:
return isonum_732(buf);
/* 723: 16 bit bothE */
case 723:
return isonum_723(buf);
/* 733: 32 bit bothE */
case 733:
return isonum_733(buf);
}
#endif
return 0;
}
void
debug_dump_integer(const char *element, char* buf, int mode)
{
printf("<%s>%i</%s>\n", element,
debug_get_encoded_number((unsigned char *)buf, mode), element);
}
void
debug_dump_string(const char *element __unused, unsigned char *buf __unused, int len __unused)
{
}
void
debug_dump_directory_record_9_1(unsigned char* buf)
{
printf("<directoryrecord>\n");
debug_dump_integer("length",
((struct iso_directory_record*) buf)->length, 711);
debug_dump_integer("ext_attr_length",
((struct iso_directory_record*) buf)->ext_attr_length,711);
debug_dump_integer("extent",
(char *)((struct iso_directory_record*) buf)->extent, 733);
debug_dump_integer("size",
(char *)((struct iso_directory_record*) buf)->size, 733);
debug_dump_integer("flags",
((struct iso_directory_record*) buf)->flags, 711);
debug_dump_integer("file_unit_size",
((struct iso_directory_record*) buf)->file_unit_size,711);
debug_dump_integer("interleave",
((struct iso_directory_record*) buf)->interleave, 711);
debug_dump_integer("volume_sequence_number",
((struct iso_directory_record*) buf)->volume_sequence_number,
723);
debug_dump_integer("name_len",
((struct iso_directory_record*) buf)->name_len, 711);
debug_dump_to_xml_padded_hex_output("name",
(u_char *)((struct iso_directory_record*) buf)->name,
debug_get_encoded_number((u_char *)
((struct iso_directory_record*) buf)->length, 711));
printf("</directoryrecord>\n");
}
void
debug_dump_to_xml_volume_descriptor(unsigned char* buf, int sector)
{
printf("<volumedescriptor sector=\"%i\">\n", sector);
printf("<vdtype>");
switch(buf[0]) {
case 0:
printf("boot");
break;
case 1:
printf("primary");
break;
case 2:
printf("supplementary");
break;
case 3:
printf("volume partition descriptor");
break;
case 255:
printf("terminator");
break;
}
printf("</vdtype>\n");
switch(buf[0]) {
case 1:
debug_dump_integer("type",
((struct iso_primary_descriptor*)buf)->type, 711);
debug_dump_to_xml_padded_hex_output("id",
(u_char *)((struct iso_primary_descriptor*) buf)->id,
ISODCL ( 2, 6));
debug_dump_integer("version",
((struct iso_primary_descriptor*)buf)->version,
711);
debug_dump_to_xml_padded_hex_output("system_id",
(u_char *)((struct iso_primary_descriptor*)buf)->system_id,
ISODCL(9,40));
debug_dump_to_xml_padded_hex_output("volume_id",
(u_char *)((struct iso_primary_descriptor*)buf)->volume_id,
ISODCL(41,72));
debug_dump_integer("volume_space_size",
((struct iso_primary_descriptor*)buf)->volume_space_size,
733);
debug_dump_integer("volume_set_size",
((struct iso_primary_descriptor*)buf)->volume_set_size,
733);
debug_dump_integer("volume_sequence_number",
((struct iso_primary_descriptor*)buf)->volume_sequence_number,
723);
debug_dump_integer("logical_block_size",
((struct iso_primary_descriptor*)buf)->logical_block_size,
723);
debug_dump_integer("path_table_size",
((struct iso_primary_descriptor*)buf)->path_table_size,
733);
debug_dump_integer("type_l_path_table",
((struct iso_primary_descriptor*)buf)->type_l_path_table,
731);
debug_dump_integer("opt_type_l_path_table",
((struct iso_primary_descriptor*)buf)->opt_type_l_path_table,
731);
debug_dump_integer("type_m_path_table",
((struct iso_primary_descriptor*)buf)->type_m_path_table,
732);
debug_dump_integer("opt_type_m_path_table",
((struct iso_primary_descriptor*)buf)->opt_type_m_path_table,732);
debug_dump_directory_record_9_1(
(u_char *)((struct iso_primary_descriptor*)buf)->root_directory_record);
debug_dump_to_xml_padded_hex_output("volume_set_id",
(u_char *)((struct iso_primary_descriptor*) buf)->volume_set_id,
ISODCL (191, 318));
debug_dump_to_xml_padded_hex_output("publisher_id",
(u_char *)((struct iso_primary_descriptor*) buf)->publisher_id,
ISODCL (319, 446));
debug_dump_to_xml_padded_hex_output("preparer_id",
(u_char *)((struct iso_primary_descriptor*) buf)->preparer_id,
ISODCL (447, 574));
debug_dump_to_xml_padded_hex_output("application_id",
(u_char *)((struct iso_primary_descriptor*) buf)->application_id,
ISODCL (575, 702));
debug_dump_to_xml_padded_hex_output("copyright_file_id",
(u_char *)((struct iso_primary_descriptor*) buf)->copyright_file_id,
ISODCL (703, 739));
debug_dump_to_xml_padded_hex_output("abstract_file_id",
(u_char *)((struct iso_primary_descriptor*) buf)->abstract_file_id,
ISODCL (740, 776));
debug_dump_to_xml_padded_hex_output("bibliographic_file_id",
(u_char *)((struct iso_primary_descriptor*) buf)->bibliographic_file_id,
ISODCL (777, 813));
debug_dump_to_xml_padded_hex_output("creation_date",
(u_char *)((struct iso_primary_descriptor*) buf)->creation_date,
ISODCL (814, 830));
debug_dump_to_xml_padded_hex_output("modification_date",
(u_char *)((struct iso_primary_descriptor*) buf)->modification_date,
ISODCL (831, 847));
debug_dump_to_xml_padded_hex_output("expiration_date",
(u_char *)((struct iso_primary_descriptor*) buf)->expiration_date,
ISODCL (848, 864));
debug_dump_to_xml_padded_hex_output("effective_date",
(u_char *)((struct iso_primary_descriptor*) buf)->effective_date,
ISODCL (865, 881));
debug_dump_to_xml_padded_hex_output("file_structure_version",
(u_char *)((struct iso_primary_descriptor*) buf)->file_structure_version,
ISODCL(882,882));
break;
}
printf("</volumedescriptor>\n");
}

View file

@ -0,0 +1,698 @@
/* $NetBSD: cd9660_eltorito.c,v 1.20 2013/01/28 21:03:28 christos Exp $ */
/*
* Copyright (c) 2005 Daniel Watt, Walter Deignan, Ryan Gabrys, Alan
* Perez-Rathke and Ram Vedam. All rights reserved.
*
* This code was written by Daniel Watt, Walter Deignan, Ryan Gabrys,
* Alan Perez-Rathke and Ram Vedam.
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY DANIEL WATT, WALTER DEIGNAN, RYAN
* GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL DANIEL WATT, WALTER DEIGNAN, RYAN
* GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE,DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*/
#include "cd9660.h"
#include "cd9660_eltorito.h"
#include <sys/bootblock.h>
#include <util.h>
#include <sys/cdefs.h>
#if defined(__RCSID) && !defined(__lint)
__RCSID("$NetBSD: cd9660_eltorito.c,v 1.20 2013/01/28 21:03:28 christos Exp $");
#endif /* !__lint */
#ifdef DEBUG
#define ELTORITO_DPRINTF(__x) printf __x
#else
#define ELTORITO_DPRINTF(__x)
#endif
#include <util.h>
static struct boot_catalog_entry *cd9660_init_boot_catalog_entry(void);
static struct boot_catalog_entry *cd9660_boot_setup_validation_entry(char);
static struct boot_catalog_entry *cd9660_boot_setup_default_entry(
struct cd9660_boot_image *);
static struct boot_catalog_entry *cd9660_boot_setup_section_head(char);
static struct boot_catalog_entry *cd9660_boot_setup_validation_entry(char);
#if 0
static u_char cd9660_boot_get_system_type(struct cd9660_boot_image *);
#endif
int
cd9660_add_boot_disk(iso9660_disk *diskStructure, const char *boot_info)
{
struct stat stbuf;
const char *mode_msg;
char *temp;
char *sysname;
char *filename;
struct cd9660_boot_image *new_image, *tmp_image;
assert(boot_info != NULL);
if (*boot_info == '\0') {
warnx("Error: Boot disk information must be in the "
"format 'system;filename'");
return 0;
}
/* First decode the boot information */
temp = estrdup(boot_info);
sysname = temp;
filename = strchr(sysname, ';');
if (filename == NULL) {
warnx("supply boot disk information in the format "
"'system;filename'");
free(temp);
return 0;
}
*filename++ = '\0';
if (diskStructure->verbose_level > 0) {
printf("Found bootdisk with system %s, and filename %s\n",
sysname, filename);
}
new_image = ecalloc(1, sizeof(*new_image));
new_image->loadSegment = 0; /* default for now */
/* Decode System */
if (strcmp(sysname, "i386") == 0)
new_image->system = ET_SYS_X86;
else if (strcmp(sysname, "powerpc") == 0)
new_image->system = ET_SYS_PPC;
else if (strcmp(sysname, "macppc") == 0 ||
strcmp(sysname, "mac68k") == 0)
new_image->system = ET_SYS_MAC;
else {
warnx("boot disk system must be "
"i386, powerpc, macppc, or mac68k");
free(temp);
free(new_image);
return 0;
}
new_image->filename = estrdup(filename);
free(temp);
/* Get information about the file */
if (lstat(new_image->filename, &stbuf) == -1)
err(EXIT_FAILURE, "%s: lstat(\"%s\")", __func__,
new_image->filename);
switch (stbuf.st_size) {
case 1440 * 1024:
new_image->targetMode = ET_MEDIA_144FDD;
mode_msg = "Assigned boot image to 1.44 emulation mode";
break;
case 1200 * 1024:
new_image->targetMode = ET_MEDIA_12FDD;
mode_msg = "Assigned boot image to 1.2 emulation mode";
break;
case 2880 * 1024:
new_image->targetMode = ET_MEDIA_288FDD;
mode_msg = "Assigned boot image to 2.88 emulation mode";
break;
default:
new_image->targetMode = ET_MEDIA_NOEM;
mode_msg = "Assigned boot image to no emulation mode";
break;
}
if (diskStructure->verbose_level > 0)
printf("%s\n", mode_msg);
new_image->size = stbuf.st_size;
new_image->num_sectors =
howmany(new_image->size, diskStructure->sectorSize) *
howmany(diskStructure->sectorSize, 512);
if (diskStructure->verbose_level > 0) {
printf("New image has size %d, uses %d 512-byte sectors\n",
new_image->size, new_image->num_sectors);
}
new_image->sector = -1;
/* Bootable by default */
new_image->bootable = ET_BOOTABLE;
/* Add boot disk */
/* Group images for the same platform together. */
TAILQ_FOREACH(tmp_image, &diskStructure->boot_images, image_list) {
if (tmp_image->system != new_image->system)
break;
}
if (tmp_image == NULL) {
TAILQ_INSERT_HEAD(&diskStructure->boot_images, new_image,
image_list);
} else
TAILQ_INSERT_BEFORE(tmp_image, new_image, image_list);
new_image->serialno = diskStructure->image_serialno++;
/* TODO : Need to do anything about the boot image in the tree? */
diskStructure->is_bootable = 1;
return 1;
}
int
cd9660_eltorito_add_boot_option(iso9660_disk *diskStructure,
const char *option_string, const char *value)
{
char *eptr;
struct cd9660_boot_image *image;
assert(option_string != NULL);
/* Find the last image added */
TAILQ_FOREACH(image, &diskStructure->boot_images, image_list) {
if (image->serialno + 1 == diskStructure->image_serialno)
break;
}
if (image == NULL)
errx(EXIT_FAILURE, "Attempted to add boot option, "
"but no boot images have been specified");
if (strcmp(option_string, "no-emul-boot") == 0) {
image->targetMode = ET_MEDIA_NOEM;
} else if (strcmp(option_string, "no-boot") == 0) {
image->bootable = ET_NOT_BOOTABLE;
} else if (strcmp(option_string, "hard-disk-boot") == 0) {
image->targetMode = ET_MEDIA_HDD;
} else if (strcmp(option_string, "boot-load-segment") == 0) {
image->loadSegment = strtoul(value, &eptr, 16);
if (eptr == value || *eptr != '\0' || errno != ERANGE) {
warn("%s: strtoul", __func__);
return 0;
}
} else {
return 0;
}
return 1;
}
static struct boot_catalog_entry *
cd9660_init_boot_catalog_entry(void)
{
return ecalloc(1, sizeof(struct boot_catalog_entry));
}
static struct boot_catalog_entry *
cd9660_boot_setup_validation_entry(char sys)
{
struct boot_catalog_entry *entry;
boot_catalog_validation_entry *ve;
int16_t checksum;
unsigned char *csptr;
size_t i;
entry = cd9660_init_boot_catalog_entry();
ve = &entry->entry_data.VE;
ve->header_id[0] = 1;
ve->platform_id[0] = sys;
ve->key[0] = 0x55;
ve->key[1] = 0xAA;
/* Calculate checksum */
checksum = 0;
cd9660_721(0, ve->checksum);
csptr = (unsigned char*)ve;
for (i = 0; i < sizeof(*ve); i += 2) {
checksum += (int16_t)csptr[i];
checksum += 256 * (int16_t)csptr[i + 1];
}
checksum = -checksum;
cd9660_721(checksum, ve->checksum);
ELTORITO_DPRINTF(("%s: header_id %d, platform_id %d, key[0] %d, key[1] %d, "
"checksum %04x\n", __func__, ve->header_id[0], ve->platform_id[0],
ve->key[0], ve->key[1], checksum));
return entry;
}
static struct boot_catalog_entry *
cd9660_boot_setup_default_entry(struct cd9660_boot_image *disk)
{
struct boot_catalog_entry *default_entry;
boot_catalog_initial_entry *ie;
default_entry = cd9660_init_boot_catalog_entry();
if (default_entry == NULL)
return NULL;
ie = &default_entry->entry_data.IE;
ie->boot_indicator[0] = disk->bootable;
ie->media_type[0] = disk->targetMode;
cd9660_721(disk->loadSegment, ie->load_segment);
ie->system_type[0] = disk->system;
cd9660_721(disk->num_sectors, ie->sector_count);
cd9660_731(disk->sector, ie->load_rba);
ELTORITO_DPRINTF(("%s: boot indicator %d, media type %d, "
"load segment %04x, system type %d, sector count %d, "
"load rba %d\n", __func__, ie->boot_indicator[0],
ie->media_type[0], disk->loadSegment, ie->system_type[0],
disk->num_sectors, disk->sector));
return default_entry;
}
static struct boot_catalog_entry *
cd9660_boot_setup_section_head(char platform)
{
struct boot_catalog_entry *entry;
boot_catalog_section_header *sh;
entry = cd9660_init_boot_catalog_entry();
if (entry == NULL)
return NULL;
sh = &entry->entry_data.SH;
/* More by default. The last one will manually be set to 0x91 */
sh->header_indicator[0] = ET_SECTION_HEADER_MORE;
sh->platform_id[0] = platform;
sh->num_section_entries[0] = 0;
return entry;
}
static struct boot_catalog_entry *
cd9660_boot_setup_section_entry(struct cd9660_boot_image *disk)
{
struct boot_catalog_entry *entry;
boot_catalog_section_entry *se;
if ((entry = cd9660_init_boot_catalog_entry()) == NULL)
return NULL;
se = &entry->entry_data.SE;
se->boot_indicator[0] = ET_BOOTABLE;
se->media_type[0] = disk->targetMode;
cd9660_721(disk->loadSegment, se->load_segment);
cd9660_721(disk->num_sectors, se->sector_count);
cd9660_731(disk->sector, se->load_rba);
return entry;
}
#if 0
static u_char
cd9660_boot_get_system_type(struct cd9660_boot_image *disk)
{
/*
For hard drive booting, we need to examine the MBR to figure
out what the partition type is
*/
return 0;
}
#endif
/*
* Set up the BVD, Boot catalog, and the boot entries, but do no writing
*/
int
cd9660_setup_boot(iso9660_disk *diskStructure, int first_sector)
{
int sector;
int used_sectors;
int num_entries = 0;
int catalog_sectors;
struct boot_catalog_entry *x86_head, *mac_head, *ppc_head,
*valid_entry, *default_entry, *temp, *head, **headp, *next;
struct cd9660_boot_image *tmp_disk;
headp = NULL;
x86_head = mac_head = ppc_head = NULL;
/* If there are no boot disks, don't bother building boot information */
if (TAILQ_EMPTY(&diskStructure->boot_images))
return 0;
/* Point to catalog: For now assume it consumes one sector */
ELTORITO_DPRINTF(("Boot catalog will go in sector %d\n", first_sector));
diskStructure->boot_catalog_sector = first_sector;
cd9660_bothendian_dword(first_sector,
diskStructure->boot_descriptor->boot_catalog_pointer);
/* Step 1: Generate boot catalog */
/* Step 1a: Validation entry */
valid_entry = cd9660_boot_setup_validation_entry(ET_SYS_X86);
if (valid_entry == NULL)
return -1;
/*
* Count how many boot images there are,
* and how many sectors they consume.
*/
num_entries = 1;
used_sectors = 0;
TAILQ_FOREACH(tmp_disk, &diskStructure->boot_images, image_list) {
used_sectors += tmp_disk->num_sectors;
/* One default entry per image */
num_entries++;
}
catalog_sectors = howmany(num_entries * 0x20, diskStructure->sectorSize);
used_sectors += catalog_sectors;
if (diskStructure->verbose_level > 0) {
printf("%s: there will be %i entries consuming %i sectors. "
"Catalog is %i sectors\n", __func__, num_entries,
used_sectors, catalog_sectors);
}
/* Populate sector numbers */
sector = first_sector + catalog_sectors;
TAILQ_FOREACH(tmp_disk, &diskStructure->boot_images, image_list) {
tmp_disk->sector = sector;
sector += tmp_disk->num_sectors;
}
LIST_INSERT_HEAD(&diskStructure->boot_entries, valid_entry, ll_struct);
/* Step 1b: Initial/default entry */
/* TODO : PARAM */
tmp_disk = TAILQ_FIRST(&diskStructure->boot_images);
default_entry = cd9660_boot_setup_default_entry(tmp_disk);
if (default_entry == NULL) {
warnx("Error: memory allocation failed in cd9660_setup_boot");
return -1;
}
LIST_INSERT_AFTER(valid_entry, default_entry, ll_struct);
/* Todo: multiple default entries? */
tmp_disk = TAILQ_NEXT(tmp_disk, image_list);
temp = default_entry;
/* If multiple boot images are given : */
while (tmp_disk != NULL) {
/* Step 2: Section header */
switch (tmp_disk->system) {
case ET_SYS_X86:
headp = &x86_head;
break;
case ET_SYS_PPC:
headp = &ppc_head;
break;
case ET_SYS_MAC:
headp = &mac_head;
break;
default:
warnx("%s: internal error: unknown system type",
__func__);
return -1;
}
if (*headp == NULL) {
head =
cd9660_boot_setup_section_head(tmp_disk->system);
if (head == NULL) {
warnx("Error: memory allocation failed in "
"cd9660_setup_boot");
return -1;
}
LIST_INSERT_AFTER(default_entry, head, ll_struct);
*headp = head;
} else
head = *headp;
head->entry_data.SH.num_section_entries[0]++;
/* Step 2a: Section entry and extensions */
temp = cd9660_boot_setup_section_entry(tmp_disk);
if (temp == NULL) {
warn("%s: cd9660_boot_setup_section_entry", __func__);
return -1;
}
while ((next = LIST_NEXT(head, ll_struct)) != NULL &&
next->entry_type == ET_ENTRY_SE)
head = next;
LIST_INSERT_AFTER(head, temp, ll_struct);
tmp_disk = TAILQ_NEXT(tmp_disk, image_list);
}
/* TODO: Remaining boot disks when implemented */
return first_sector + used_sectors;
}
int
cd9660_setup_boot_volume_descriptor(iso9660_disk *diskStructure,
volume_descriptor *bvd)
{
boot_volume_descriptor *bvdData =
(boot_volume_descriptor*)bvd->volumeDescriptorData;
bvdData->boot_record_indicator[0] = ISO_VOLUME_DESCRIPTOR_BOOT;
memcpy(bvdData->identifier, ISO_VOLUME_DESCRIPTOR_STANDARD_ID, 5);
bvdData->version[0] = 1;
memcpy(bvdData->boot_system_identifier, ET_ID, 23);
memcpy(bvdData->identifier, ISO_VOLUME_DESCRIPTOR_STANDARD_ID, 5);
diskStructure->boot_descriptor =
(boot_volume_descriptor*) bvd->volumeDescriptorData;
return 1;
}
static int
cd9660_write_mbr_partition_entry(FILE *fd, int idx, off_t sector_start,
off_t nsectors, int type)
{
uint8_t val;
uint32_t lba;
if (fseeko(fd, (off_t)(idx) * 16 + 0x1be, SEEK_SET) == -1)
err(1, "fseeko");
val = 0x80; /* Bootable */
fwrite(&val, sizeof(val), 1, fd);
val = 0xff; /* CHS begin */
fwrite(&val, sizeof(val), 1, fd);
fwrite(&val, sizeof(val), 1, fd);
fwrite(&val, sizeof(val), 1, fd);
val = type; /* Part type */
fwrite(&val, sizeof(val), 1, fd);
val = 0xff; /* CHS end */
fwrite(&val, sizeof(val), 1, fd);
fwrite(&val, sizeof(val), 1, fd);
fwrite(&val, sizeof(val), 1, fd);
/* LBA extent */
lba = htole32(sector_start);
fwrite(&lba, sizeof(lba), 1, fd);
lba = htole32(nsectors);
fwrite(&lba, sizeof(lba), 1, fd);
return 0;
}
static int
cd9660_write_apm_partition_entry(FILE *fd, int idx, int total_partitions,
off_t sector_start, off_t nsectors, off_t sector_size,
const char *part_name, const char *part_type)
{
uint32_t apm32, part_status;
uint16_t apm16;
/* See Apple Tech Note 1189 for the details about the pmPartStatus
* flags.
* Below the flags which are default:
* - IsValid 0x01
* - IsAllocated 0x02
* - IsReadable 0x10
* - IsWritable 0x20
*/
part_status = APPLE_PS_VALID | APPLE_PS_ALLOCATED | APPLE_PS_READABLE |
APPLE_PS_WRITABLE;
if (fseeko(fd, (off_t)(idx + 1) * sector_size, SEEK_SET) == -1)
err(1, "fseeko");
/* Signature */
apm16 = htobe16(0x504d);
fwrite(&apm16, sizeof(apm16), 1, fd);
apm16 = 0;
fwrite(&apm16, sizeof(apm16), 1, fd);
/* Total number of partitions */
apm32 = htobe32(total_partitions);
fwrite(&apm32, sizeof(apm32), 1, fd);
/* Bounds */
apm32 = htobe32(sector_start);
fwrite(&apm32, sizeof(apm32), 1, fd);
apm32 = htobe32(nsectors);
fwrite(&apm32, sizeof(apm32), 1, fd);
fwrite(part_name, strlen(part_name) + 1, 1, fd);
fseek(fd, 32 - strlen(part_name) - 1, SEEK_CUR);
fwrite(part_type, strlen(part_type) + 1, 1, fd);
fseek(fd, 32 - strlen(part_type) - 1, SEEK_CUR);
apm32 = 0;
/* pmLgDataStart */
fwrite(&apm32, sizeof(apm32), 1, fd);
/* pmDataCnt */
apm32 = htobe32(nsectors);
fwrite(&apm32, sizeof(apm32), 1, fd);
/* pmPartStatus */
apm32 = htobe32(part_status);
fwrite(&apm32, sizeof(apm32), 1, fd);
return 0;
}
int
cd9660_write_boot(iso9660_disk *diskStructure, FILE *fd)
{
struct boot_catalog_entry *e;
struct cd9660_boot_image *t;
int apm_partitions = 0;
int mbr_partitions = 0;
/* write boot catalog */
if (fseeko(fd, (off_t)diskStructure->boot_catalog_sector *
diskStructure->sectorSize, SEEK_SET) == -1)
err(1, "fseeko");
if (diskStructure->verbose_level > 0) {
printf("Writing boot catalog to sector %" PRId64 "\n",
diskStructure->boot_catalog_sector);
}
LIST_FOREACH(e, &diskStructure->boot_entries, ll_struct) {
if (diskStructure->verbose_level > 0) {
printf("Writing catalog entry of type %d\n",
e->entry_type);
}
/*
* It doesnt matter which one gets written
* since they are the same size
*/
fwrite(&(e->entry_data.VE), 1, 32, fd);
}
if (diskStructure->verbose_level > 0)
printf("Finished writing boot catalog\n");
/* copy boot images */
TAILQ_FOREACH(t, &diskStructure->boot_images, image_list) {
if (diskStructure->verbose_level > 0) {
printf("Writing boot image from %s to sectors %d\n",
t->filename, t->sector);
}
cd9660_copy_file(diskStructure, fd, t->sector, t->filename);
if (t->system == ET_SYS_MAC)
apm_partitions++;
if (t->system == ET_SYS_PPC)
mbr_partitions++;
}
/* some systems need partition tables as well */
if (mbr_partitions > 0 || diskStructure->chrp_boot) {
uint16_t sig;
fseek(fd, 0x1fe, SEEK_SET);
sig = htole16(0xaa55);
fwrite(&sig, sizeof(sig), 1, fd);
mbr_partitions = 0;
/* Write ISO9660 descriptor, enclosing the whole disk */
if (diskStructure->chrp_boot)
cd9660_write_mbr_partition_entry(fd, mbr_partitions++,
0, diskStructure->totalSectors *
(diskStructure->sectorSize / 512), 0x96);
/* Write all partition entries */
TAILQ_FOREACH(t, &diskStructure->boot_images, image_list) {
if (t->system != ET_SYS_PPC)
continue;
cd9660_write_mbr_partition_entry(fd, mbr_partitions++,
t->sector * (diskStructure->sectorSize / 512),
t->num_sectors * (diskStructure->sectorSize / 512),
0x41 /* PReP Boot */);
}
}
if (apm_partitions > 0) {
/* Write DDR and global APM info */
uint32_t apm32;
uint16_t apm16;
int total_parts;
fseek(fd, 0, SEEK_SET);
apm16 = htobe16(0x4552);
fwrite(&apm16, sizeof(apm16), 1, fd);
/* Device block size */
apm16 = htobe16(512);
fwrite(&apm16, sizeof(apm16), 1, fd);
/* Device block count */
apm32 = htobe32(diskStructure->totalSectors *
(diskStructure->sectorSize / 512));
fwrite(&apm32, sizeof(apm32), 1, fd);
/* Device type/id */
apm16 = htobe16(1);
fwrite(&apm16, sizeof(apm16), 1, fd);
fwrite(&apm16, sizeof(apm16), 1, fd);
/* Count total needed entries */
total_parts = 2 + apm_partitions; /* Self + ISO9660 */
/* Write self-descriptor */
cd9660_write_apm_partition_entry(fd, 0, total_parts, 1,
total_parts, 512, "Apple", "Apple_partition_map");
/* Write all partition entries */
apm_partitions = 0;
TAILQ_FOREACH(t, &diskStructure->boot_images, image_list) {
if (t->system != ET_SYS_MAC)
continue;
cd9660_write_apm_partition_entry(fd,
1 + apm_partitions++, total_parts,
t->sector * (diskStructure->sectorSize / 512),
t->num_sectors * (diskStructure->sectorSize / 512),
512, "CD Boot", "Apple_Bootstrap");
}
/* Write ISO9660 descriptor, enclosing the whole disk */
cd9660_write_apm_partition_entry(fd, 2 + apm_partitions,
total_parts, 0, diskStructure->totalSectors *
(diskStructure->sectorSize / 512), 512, "ISO9660",
"CD_ROM_Mode_1");
}
return 0;
}

View file

@ -0,0 +1,162 @@
/* $NetBSD: cd9660_eltorito.h,v 1.5 2009/07/04 14:31:38 ahoka Exp $ */
/*
* Copyright (c) 2005 Daniel Watt, Walter Deignan, Ryan Gabrys, Alan
* Perez-Rathke and Ram Vedam. All rights reserved.
*
* This code was written by Daniel Watt, Walter Deignan, Ryan Gabrys,
* Alan Perez-Rathke and Ram Vedam.
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY DANIEL WATT, WALTER DEIGNAN, RYAN
* GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL DANIEL WATT, WALTER DEIGNAN, RYAN
* GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE,DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*/
#ifndef _CD9660_ELTORITO_H_
#define _CD9660_ELTORITO_H_
/* Boot defines */
#define ET_ID "EL TORITO SPECIFICATION"
#define ET_SYS_X86 0
#define ET_SYS_PPC 1
#define ET_SYS_MAC 2
#define ET_BOOT_ENTRY_SIZE 0x20
#define ET_BOOTABLE 0x88
#define ET_NOT_BOOTABLE 0
#define ET_MEDIA_NOEM 0
#define ET_MEDIA_12FDD 1
#define ET_MEDIA_144FDD 2
#define ET_MEDIA_288FDD 3
#define ET_MEDIA_HDD 4
#define ET_INDICATOR_HEADERMORE 0x90
#define ET_INDICATOR_HEADERLAST 0x91
#define ET_INDICATOR_EXTENSION 0x44
/*** Boot Structures ***/
typedef struct _boot_volume_descriptor {
u_char boot_record_indicator [ISODCL(0x00,0x00)];
u_char identifier [ISODCL(0x01,0x05)];
u_char version [ISODCL(0x06,0x06)];
u_char boot_system_identifier [ISODCL(0x07,0x26)];
u_char unused1 [ISODCL(0x27,0x46)];
u_char boot_catalog_pointer [ISODCL(0x47,0x4A)];
u_char unused2 [ISODCL(0x4B,0x7FF)];
} boot_volume_descriptor;
typedef struct _boot_catalog_validation_entry {
u_char header_id [ISODCL(0x00,0x00)];
u_char platform_id [ISODCL(0x01,0x01)];
u_char reserved1 [ISODCL(0x02,0x03)];
u_char manufacturer [ISODCL(0x04,0x1B)];
u_char checksum [ISODCL(0x1C,0x1D)];
u_char key [ISODCL(0x1E,0x1F)];
} boot_catalog_validation_entry;
typedef struct _boot_catalog_initial_entry {
u_char boot_indicator [ISODCL(0x00,0x00)];
u_char media_type [ISODCL(0x01,0x01)];
u_char load_segment [ISODCL(0x02,0x03)];
u_char system_type [ISODCL(0x04,0x04)];
u_char unused_1 [ISODCL(0x05,0x05)];
u_char sector_count [ISODCL(0x06,0x07)];
u_char load_rba [ISODCL(0x08,0x0B)];
u_char unused_2 [ISODCL(0x0C,0x1F)];
} boot_catalog_initial_entry;
#define ET_SECTION_HEADER_MORE 0x90
#define ET_SECTION_HEADER_LAST 0x91
typedef struct _boot_catalog_section_header {
u_char header_indicator [ISODCL(0x00,0x00)];
u_char platform_id [ISODCL(0x01,0x01)];
u_char num_section_entries [ISODCL(0x02,0x03)];
u_char id_string [ISODCL(0x04,0x1F)];
} boot_catalog_section_header;
typedef struct _boot_catalog_section_entry {
u_char boot_indicator [ISODCL(0x00,0x00)];
u_char media_type [ISODCL(0x01,0x01)];
u_char load_segment [ISODCL(0x02,0x03)];
u_char system_type [ISODCL(0x04,0x04)];
u_char unused_1 [ISODCL(0x05,0x05)];
u_char sector_count [ISODCL(0x06,0x07)];
u_char load_rba [ISODCL(0x08,0x0B)];
u_char selection_criteria [ISODCL(0x0C,0x0C)];
u_char vendor_criteria [ISODCL(0x0D,0x1F)];
} boot_catalog_section_entry;
typedef struct _boot_catalog_section_entry_extension {
u_char extension_indicator [ISODCL(0x00,0x00)];
u_char flags [ISODCL(0x01,0x01)];
u_char vendor_criteria [ISODCL(0x02,0x1F)];
} boot_catalog_section_entry_extension;
#define ET_ENTRY_VE 1
#define ET_ENTRY_IE 2
#define ET_ENTRY_SH 3
#define ET_ENTRY_SE 4
#define ET_ENTRY_EX 5
struct boot_catalog_entry {
char entry_type;
union {
boot_catalog_validation_entry VE;
boot_catalog_initial_entry IE;
boot_catalog_section_header SH;
boot_catalog_section_entry SE;
boot_catalog_section_entry_extension EX;
} entry_data;
LIST_ENTRY(boot_catalog_entry) ll_struct;
};
/* Temporary structure */
struct cd9660_boot_image {
char *filename;
int size;
int sector; /* copied to LoadRBA */
int num_sectors;
unsigned int loadSegment;
u_char targetMode;
u_char system;
u_char bootable;
/*
* If the boot image exists in the filesystem
* already, this is a pointer to that node. For the sake
* of simplicity in future versions, this pointer is only
* to the node in the primary volume. This SHOULD be done
* via a hashtable lookup.
*/
struct _cd9660node *boot_image_node;
TAILQ_ENTRY(cd9660_boot_image) image_list;
int serialno;
};
#endif /* _CD9660_ELTORITO_H_ */

View file

@ -0,0 +1,127 @@
/* $NetBSD: cd9660_strings.c,v 1.5 2011/03/23 13:11:51 christos Exp $ */
/*
* Copyright (c) 2005 Daniel Watt, Walter Deignan, Ryan Gabrys, Alan
* Perez-Rathke and Ram Vedam. All rights reserved.
*
* This code was written by Daniel Watt, Walter Deignan, Ryan Gabrys,
* Alan Perez-Rathke and Ram Vedam.
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY DANIEL WATT, WALTER DEIGNAN, RYAN
* GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL DANIEL WATT, WALTER DEIGNAN, RYAN
* GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE,DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*/
#if HAVE_NBTOOL_CONFIG_H
#include "nbtool_config.h"
#else
#include <sys/mount.h>
#endif
#include <sys/cdefs.h>
#include <sys/param.h>
#include <ctype.h>
#include "makefs.h"
#include "cd9660.h"
#if defined(__RCSID) && !defined(__lint)
__RCSID("$NetBSD: cd9660_strings.c,v 1.5 2011/03/23 13:11:51 christos Exp $");
#endif /* !__lint */
void
cd9660_uppercase_characters(char *str, int len)
{
int p;
for (p = 0; p < len; p++) {
if (islower((unsigned char)str[p]) )
str[p] -= 32;
}
}
static inline int
cd9660_is_d_char(char c)
{
return (isupper((unsigned char)c)
|| c == '_'
|| (c >= '0' && c <= '9'));
}
static inline int
cd9660_is_a_char(char c)
{
return (isupper((unsigned char)c)
|| c == '_'
|| (c >= '%' && c <= '?')
|| (c >= ' ' && c <= '\"'));
}
/*
* Test a string to see if it is composed of valid a characters
* @param const char* The string to test
* @returns int 1 if valid, 2 if valid if characters are converted to
* upper case, 0 otherwise
*/
int
cd9660_valid_a_chars(const char *str)
{
const char *c = str;
int upperFound = 0;
while ((*c) != '\0') {
if (!(cd9660_is_a_char(*c))) {
if (islower((unsigned char)*c) )
upperFound = 1;
else
return 0;
}
c++;
}
return upperFound + 1;
}
/*
* Test a string to see if it is composed of valid d characters
* @param const char* The string to test
* @returns int 1 if valid, 2 if valid if characters are converted to
* upper case, 0 otherwise
*/
int
cd9660_valid_d_chars(const char *str)
{
const char *c=str;
int upperFound = 0;
while ((*c) != '\0') {
if (!(cd9660_is_d_char(*c))) {
if (islower((unsigned char)*c) )
upperFound = 1;
else
return 0;
}
c++;
}
return upperFound + 1;
}

View file

@ -0,0 +1,509 @@
/* $NetBSD: cd9660_write.c,v 1.17 2013/10/19 17:16:37 christos Exp $ */
/*
* Copyright (c) 2005 Daniel Watt, Walter Deignan, Ryan Gabrys, Alan
* Perez-Rathke and Ram Vedam. All rights reserved.
*
* This code was written by Daniel Watt, Walter Deignan, Ryan Gabrys,
* Alan Perez-Rathke and Ram Vedam.
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY DANIEL WATT, WALTER DEIGNAN, RYAN
* GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL DANIEL WATT, WALTER DEIGNAN, RYAN
* GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE,DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*/
#include "cd9660.h"
#include "iso9660_rrip.h"
#include <sys/cdefs.h>
#if defined(__RCSID) && !defined(__lint)
__RCSID("$NetBSD: cd9660_write.c,v 1.17 2013/10/19 17:16:37 christos Exp $");
#endif /* !__lint */
#include <util.h>
static int cd9660_write_volume_descriptors(iso9660_disk *, FILE *);
static int cd9660_write_path_table(iso9660_disk *, FILE *, off_t, int);
static int cd9660_write_path_tables(iso9660_disk *, FILE *);
static int cd9660_write_file(iso9660_disk *, FILE *, cd9660node *);
static int cd9660_write_filedata(iso9660_disk *, FILE *, off_t,
const unsigned char *, int);
#if 0
static int cd9660_write_buffered(FILE *, off_t, int, const unsigned char *);
#endif
static void cd9660_write_rr(iso9660_disk *, FILE *, cd9660node *, off_t, off_t);
/*
* Write the image
* Writes the entire image
* @param const char* The filename for the image
* @returns int 1 on success, 0 on failure
*/
int
cd9660_write_image(iso9660_disk *diskStructure, const char* image)
{
FILE *fd;
int status;
char buf[CD9660_SECTOR_SIZE];
if ((fd = fopen(image, "w+")) == NULL) {
err(EXIT_FAILURE, "%s: Can't open `%s' for writing", __func__,
image);
}
if (diskStructure->verbose_level > 0)
printf("Writing image\n");
if (diskStructure->has_generic_bootimage) {
status = cd9660_copy_file(diskStructure, fd, 0,
diskStructure->generic_bootimage);
if (status == 0) {
warnx("%s: Error writing generic boot image",
__func__);
goto cleanup_bad_image;
}
}
/* Write the volume descriptors */
status = cd9660_write_volume_descriptors(diskStructure, fd);
if (status == 0) {
warnx("%s: Error writing volume descriptors to image",
__func__);
goto cleanup_bad_image;
}
if (diskStructure->verbose_level > 0)
printf("Volume descriptors written\n");
/*
* Write the path tables: there are actually four, but right
* now we are only concearned with two.
*/
status = cd9660_write_path_tables(diskStructure, fd);
if (status == 0) {
warnx("%s: Error writing path tables to image", __func__);
goto cleanup_bad_image;
}
if (diskStructure->verbose_level > 0)
printf("Path tables written\n");
/* Write the directories and files */
status = cd9660_write_file(diskStructure, fd, diskStructure->rootNode);
if (status == 0) {
warnx("%s: Error writing files to image", __func__);
goto cleanup_bad_image;
}
if (diskStructure->is_bootable) {
cd9660_write_boot(diskStructure, fd);
}
/* Write padding bits. This is temporary */
memset(buf, 0, CD9660_SECTOR_SIZE);
cd9660_write_filedata(diskStructure, fd,
diskStructure->totalSectors - 1, buf, 1);
if (diskStructure->verbose_level > 0)
printf("Files written\n");
fclose(fd);
if (diskStructure->verbose_level > 0)
printf("Image closed\n");
return 1;
cleanup_bad_image:
fclose(fd);
if (!diskStructure->keep_bad_images)
unlink(image);
if (diskStructure->verbose_level > 0)
printf("Bad image cleaned up\n");
return 0;
}
static int
cd9660_write_volume_descriptors(iso9660_disk *diskStructure, FILE *fd)
{
volume_descriptor *vd_temp = diskStructure->firstVolumeDescriptor;
while (vd_temp != NULL) {
cd9660_write_filedata(diskStructure, fd, vd_temp->sector,
vd_temp->volumeDescriptorData, 1);
vd_temp = vd_temp->next;
}
return 1;
}
/*
* Write out an individual path table
* Used just to keep redundant code to a minimum
* @param FILE *fd Valid file pointer
* @param int Sector to start writing path table to
* @param int Endian mode : BIG_ENDIAN or LITTLE_ENDIAN
* @returns int 1 on success, 0 on failure
*/
static int
cd9660_write_path_table(iso9660_disk *diskStructure, FILE *fd, off_t sector,
int mode)
{
int path_table_sectors = CD9660_BLOCKS(diskStructure->sectorSize,
diskStructure->pathTableLength);
unsigned char *buffer;
unsigned char *buffer_head;
int len;
path_table_entry temp_entry;
cd9660node *ptcur;
buffer = ecalloc(path_table_sectors, diskStructure->sectorSize);
buffer_head = buffer;
ptcur = diskStructure->rootNode;
while (ptcur != NULL) {
memset(&temp_entry, 0, sizeof(path_table_entry));
temp_entry.length[0] = ptcur->isoDirRecord->name_len[0];
temp_entry.extended_attribute_length[0] =
ptcur->isoDirRecord->ext_attr_length[0];
memcpy(temp_entry.name, ptcur->isoDirRecord->name,
temp_entry.length[0] + 1);
/* round up */
len = temp_entry.length[0] + 8 + (temp_entry.length[0] & 0x01);
/* todo: function pointers instead */
if (mode == LITTLE_ENDIAN) {
cd9660_731(ptcur->fileDataSector,
temp_entry.first_sector);
cd9660_721((ptcur->parent == NULL ?
1 : ptcur->parent->ptnumber),
temp_entry.parent_number);
} else {
cd9660_732(ptcur->fileDataSector,
temp_entry.first_sector);
cd9660_722((ptcur->parent == NULL ?
1 : ptcur->parent->ptnumber),
temp_entry.parent_number);
}
memcpy(buffer, &temp_entry, len);
buffer += len;
ptcur = ptcur->ptnext;
}
return cd9660_write_filedata(diskStructure, fd, sector, buffer_head,
path_table_sectors);
}
/*
* Write out the path tables to disk
* Each file descriptor should be pointed to by the PVD, so we know which
* sector to copy them to. One thing to watch out for: the only path tables
* stored are in the endian mode that the application is compiled for. So,
* the first thing to do is write out that path table, then to write the one
* in the other endian mode requires to convert the endianness of each entry
* in the table. The best way to do this would be to create a temporary
* path_table_entry structure, then for each path table entry, copy it to
* the temporary entry, translate, then copy that to disk.
*
* @param FILE* Valid file descriptor
* @returns int 0 on failure, 1 on success
*/
static int
cd9660_write_path_tables(iso9660_disk *diskStructure, FILE *fd)
{
if (cd9660_write_path_table(diskStructure, fd,
diskStructure->primaryLittleEndianTableSector, LITTLE_ENDIAN) == 0)
return 0;
if (cd9660_write_path_table(diskStructure, fd,
diskStructure->primaryBigEndianTableSector, BIG_ENDIAN) == 0)
return 0;
/* @TODO: handle remaining two path tables */
return 1;
}
/*
* Write a file to disk
* Writes a file, its directory record, and its data to disk
* This file is designed to be called RECURSIVELY, so initially call it
* with the root node. All of the records should store what sector the
* file goes in, so no computation should be necessary.
*
* @param int fd Valid file descriptor
* @param struct cd9660node* writenode Pointer to the file to be written
* @returns int 0 on failure, 1 on success
*/
static int
cd9660_write_file(iso9660_disk *diskStructure, FILE *fd, cd9660node *writenode)
{
char *buf;
char *temp_file_name;
int ret;
off_t working_sector;
int cur_sector_offset;
iso_directory_record_cd9660 temp_record;
cd9660node *temp;
int rv = 0;
/* Todo : clean up variables */
temp_file_name = ecalloc(CD9660MAXPATH + 1, 1);
buf = emalloc(diskStructure->sectorSize);
if ((writenode->level != 0) &&
!(writenode->node->type & S_IFDIR)) {
fsinode *inode = writenode->node->inode;
/* Only attempt to write unwritten files that have length. */
if ((inode->flags & FI_WRITTEN) != 0) {
INODE_WARNX(("%s: skipping written inode %d", __func__,
(int)inode->st.st_ino));
} else if (writenode->fileDataLength > 0) {
INODE_WARNX(("%s: writing inode %d blocks at %" PRIu32,
__func__, (int)inode->st.st_ino, inode->ino));
inode->flags |= FI_WRITTEN;
cd9660_compute_full_filename(writenode,
temp_file_name);
ret = cd9660_copy_file(diskStructure, fd,
writenode->fileDataSector, temp_file_name);
if (ret == 0)
goto out;
}
} else {
/*
* Here is a new revelation that ECMA didnt explain
* (at least not well).
* ALL . and .. records store the name "\0" and "\1"
* resepctively. So, for each directory, we have to
* make a new node.
*
* This is where it gets kinda messy, since we have to
* be careful of sector boundaries
*/
cur_sector_offset = 0;
working_sector = writenode->fileDataSector;
if (fseeko(fd, working_sector * diskStructure->sectorSize,
SEEK_SET) == -1)
err(1, "fseeko");
/*
* Now loop over children, writing out their directory
* records - beware of sector boundaries
*/
TAILQ_FOREACH(temp, &writenode->cn_children, cn_next_child) {
/*
* Copy the temporary record and adjust its size
* if necessary
*/
memcpy(&temp_record, temp->isoDirRecord,
sizeof(iso_directory_record_cd9660));
temp_record.length[0] =
cd9660_compute_record_size(diskStructure, temp);
if (temp_record.length[0] + cur_sector_offset >=
diskStructure->sectorSize) {
cur_sector_offset = 0;
working_sector++;
/* Seek to the next sector. */
if (fseeko(fd, working_sector *
diskStructure->sectorSize, SEEK_SET) == -1)
err(1, "fseeko");
}
/* Write out the basic ISO directory record */
(void)fwrite(&temp_record, 1,
temp->isoDirRecord->length[0], fd);
if (diskStructure->rock_ridge_enabled) {
cd9660_write_rr(diskStructure, fd, temp,
cur_sector_offset, working_sector);
}
if (fseeko(fd, working_sector *
diskStructure->sectorSize + cur_sector_offset +
temp_record.length[0] - temp->su_tail_size,
SEEK_SET) == -1)
err(1, "fseeko");
if (temp->su_tail_size > 0)
fwrite(temp->su_tail_data, 1,
temp->su_tail_size, fd);
if (ferror(fd)) {
warnx("%s: write error", __func__);
goto out;
}
cur_sector_offset += temp_record.length[0];
}
/*
* Recurse on children.
*/
TAILQ_FOREACH(temp, &writenode->cn_children, cn_next_child) {
if ((ret = cd9660_write_file(diskStructure, fd, temp))
== 0)
goto out;
}
}
rv = 1;
out:
free(temp_file_name);
free(buf);
return rv;
}
/*
* Wrapper function to write a buffer (one sector) to disk.
* Seeks and writes the buffer.
* NOTE: You dont NEED to use this function, but it might make your
* life easier if you have to write things that align to a sector
* (such as volume descriptors).
*
* @param int fd Valid file descriptor
* @param int sector Sector number to write to
* @param const unsigned char* Buffer to write. This should be the
* size of a sector, and if only a portion
* is written, the rest should be set to 0.
*/
static int
cd9660_write_filedata(iso9660_disk *diskStructure, FILE *fd, off_t sector,
const unsigned char *buf, int numsecs)
{
off_t curpos;
size_t success;
curpos = ftello(fd);
if (fseeko(fd, sector * diskStructure->sectorSize, SEEK_SET) == -1)
err(1, "fseeko");
success = fwrite(buf, diskStructure->sectorSize * numsecs, 1, fd);
if (fseeko(fd, curpos, SEEK_SET) == -1)
err(1, "fseeko");
if (success == 1)
success = diskStructure->sectorSize * numsecs;
return success;
}
#if 0
static int
cd9660_write_buffered(FILE *fd, off_t offset, int buff_len,
const unsigned char* buffer)
{
static int working_sector = -1;
static char buf[CD9660_SECTOR_SIZE];
return 0;
}
#endif
int
cd9660_copy_file(iso9660_disk *diskStructure, FILE *fd, off_t start_sector,
const char *filename)
{
FILE *rf;
int bytes_read;
off_t sector = start_sector;
int buf_size = diskStructure->sectorSize;
char *buf;
buf = emalloc(buf_size);
if ((rf = fopen(filename, "rb")) == NULL) {
warn("%s: cannot open %s", __func__, filename);
free(buf);
return 0;
}
if (diskStructure->verbose_level > 1)
printf("Writing file: %s\n",filename);
if (fseeko(fd, start_sector * diskStructure->sectorSize, SEEK_SET) == -1)
err(1, "fseeko");
while (!feof(rf)) {
bytes_read = fread(buf,1,buf_size,rf);
if (ferror(rf)) {
warn("%s: fread", __func__);
free(buf);
(void)fclose(rf);
return 0;
}
fwrite(buf,1,bytes_read,fd);
if (ferror(fd)) {
warn("%s: fwrite", __func__);
free(buf);
(void)fclose(rf);
return 0;
}
sector++;
}
fclose(rf);
free(buf);
return 1;
}
static void
cd9660_write_rr(iso9660_disk *diskStructure, FILE *fd, cd9660node *writenode,
off_t offset, off_t sector)
{
int in_ca = 0;
struct ISO_SUSP_ATTRIBUTES *myattr;
offset += writenode->isoDirRecord->length[0];
if (fseeko(fd, sector * diskStructure->sectorSize + offset, SEEK_SET) ==
-1)
err(1, "fseeko");
/* Offset now points at the end of the record */
TAILQ_FOREACH(myattr, &writenode->head, rr_ll) {
fwrite(&(myattr->attr), CD9660_SUSP_ENTRY_SIZE(myattr), 1, fd);
if (!in_ca) {
offset += CD9660_SUSP_ENTRY_SIZE(myattr);
if (myattr->last_in_suf) {
/*
* Point the offset to the start of this
* record's CE area
*/
if (fseeko(fd, ((off_t)diskStructure->
susp_continuation_area_start_sector *
diskStructure->sectorSize)
+ writenode->susp_entry_ce_start,
SEEK_SET) == -1)
err(1, "fseeko");
in_ca = 1;
}
}
}
/*
* If we had to go to the continuation area, head back to
* where we should be.
*/
if (in_ca)
if (fseeko(fd, sector * diskStructure->sectorSize + offset,
SEEK_SET) == -1)
err(1, "fseeko");
}

View file

@ -0,0 +1,838 @@
/* $NetBSD: iso9660_rrip.c,v 1.13 2013/07/30 16:02:23 reinoud Exp $ */
/*
* Copyright (c) 2005 Daniel Watt, Walter Deignan, Ryan Gabrys, Alan
* Perez-Rathke and Ram Vedam. All rights reserved.
*
* This code was written by Daniel Watt, Walter Deignan, Ryan Gabrys,
* Alan Perez-Rathke and Ram Vedam.
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY DANIEL WATT, WALTER DEIGNAN, RYAN
* GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL DANIEL WATT, WALTER DEIGNAN, RYAN
* GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE,DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*/
/* This will hold all the function definitions
* defined in iso9660_rrip.h
*/
#include "makefs.h"
#include "cd9660.h"
#include "iso9660_rrip.h"
#include <sys/queue.h>
#include <stdio.h>
#include <util.h>
#include <sys/cdefs.h>
#if defined(__RCSID) && !defined(__lint)
__RCSID("$NetBSD: iso9660_rrip.c,v 1.13 2013/07/30 16:02:23 reinoud Exp $");
#endif /* !__lint */
static void cd9660_rrip_initialize_inode(cd9660node *);
static int cd9660_susp_handle_continuation(iso9660_disk *, cd9660node *);
static int cd9660_susp_handle_continuation_common(iso9660_disk *, cd9660node *,
int);
int
cd9660_susp_initialize(iso9660_disk *diskStructure, cd9660node *node,
cd9660node *parent, cd9660node *grandparent)
{
cd9660node *cn;
int r;
/* Make sure the node is not NULL. If it is, there are major problems */
assert(node != NULL);
if (!(node->type & CD9660_TYPE_DOT) &&
!(node->type & CD9660_TYPE_DOTDOT))
TAILQ_INIT(&(node->head));
if (node->dot_record != 0)
TAILQ_INIT(&(node->dot_record->head));
if (node->dot_dot_record != 0)
TAILQ_INIT(&(node->dot_dot_record->head));
/* SUSP specific entries here */
if ((r = cd9660_susp_initialize_node(diskStructure, node)) < 0)
return r;
/* currently called cd9660node_rrip_init_links */
r = cd9660_rrip_initialize_node(diskStructure, node, parent, grandparent);
if (r < 0)
return r;
/*
* See if we need a CE record, and set all of the
* associated counters.
*
* This should be called after all extensions. After
* this is called, no new records should be added.
*/
if ((r = cd9660_susp_handle_continuation(diskStructure, node)) < 0)
return r;
/* Recurse on children. */
TAILQ_FOREACH(cn, &node->cn_children, cn_next_child) {
if ((r = cd9660_susp_initialize(diskStructure, cn, node, parent)) < 0)
return 0;
}
return 1;
}
int
cd9660_susp_finalize(iso9660_disk *diskStructure, cd9660node *node)
{
cd9660node *temp;
int r;
assert(node != NULL);
if (node == diskStructure->rootNode)
diskStructure->susp_continuation_area_current_free = 0;
if ((r = cd9660_susp_finalize_node(diskStructure, node)) < 0)
return r;
if ((r = cd9660_rrip_finalize_node(diskStructure, node)) < 0)
return r;
TAILQ_FOREACH(temp, &node->cn_children, cn_next_child) {
if ((r = cd9660_susp_finalize(diskStructure, temp)) < 0)
return r;
}
return 1;
}
/*
* If we really wanted to speed things up, we could have some sort of
* lookup table on the SUSP entry type that calls a functor. Or, we could
* combine the functions. These functions are kept separate to allow
* easier addition of other extensions.
* For the sake of simplicity and clarity, we won't be doing that for now.
*/
/*
* SUSP needs to update the following types:
* CE (continuation area)
*/
int
cd9660_susp_finalize_node(iso9660_disk *diskStructure, cd9660node *node)
{
struct ISO_SUSP_ATTRIBUTES *t;
/* Handle CE counters */
if (node->susp_entry_ce_length > 0) {
node->susp_entry_ce_start =
diskStructure->susp_continuation_area_current_free;
diskStructure->susp_continuation_area_current_free +=
node->susp_entry_ce_length;
}
TAILQ_FOREACH(t, &node->head, rr_ll) {
if (t->susp_type != SUSP_TYPE_SUSP ||
t->entry_type != SUSP_ENTRY_SUSP_CE)
continue;
cd9660_bothendian_dword(
diskStructure->
susp_continuation_area_start_sector,
t->attr.su_entry.CE.ca_sector);
cd9660_bothendian_dword(
diskStructure->
susp_continuation_area_start_sector,
t->attr.su_entry.CE.ca_sector);
cd9660_bothendian_dword(node->susp_entry_ce_start,
t->attr.su_entry.CE.offset);
cd9660_bothendian_dword(node->susp_entry_ce_length,
t->attr.su_entry.CE.length);
}
return 0;
}
int
cd9660_rrip_finalize_node(iso9660_disk *diskStructure __unused,
cd9660node *node)
{
struct ISO_SUSP_ATTRIBUTES *t;
TAILQ_FOREACH(t, &node->head, rr_ll) {
if (t->susp_type != SUSP_TYPE_RRIP)
continue;
switch (t->entry_type) {
case SUSP_ENTRY_RRIP_CL:
/* Look at rr_relocated*/
if (node->rr_relocated == NULL)
return -1;
cd9660_bothendian_dword(
node->rr_relocated->fileDataSector,
(unsigned char *)
t->attr.rr_entry.CL.dir_loc);
break;
case SUSP_ENTRY_RRIP_PL:
/* Look at rr_real_parent */
if (node->parent == NULL ||
node->parent->rr_real_parent == NULL)
return -1;
cd9660_bothendian_dword(
node->parent->rr_real_parent->fileDataSector,
(unsigned char *)
t->attr.rr_entry.PL.dir_loc);
break;
}
}
return 0;
}
static int
cd9660_susp_handle_continuation_common(iso9660_disk *diskStructure,
cd9660node *node, int space)
{
int ca_used, susp_used, susp_used_pre_ce, working;
struct ISO_SUSP_ATTRIBUTES *temp, *pre_ce, *last, *CE, *ST;
pre_ce = last = NULL;
working = 254 - space;
if (node->su_tail_size > 0)
/* Allow 4 bytes for "ST" record. */
working -= node->su_tail_size + 4;
/* printf("There are %i bytes to work with\n",working); */
susp_used_pre_ce = susp_used = 0;
ca_used = 0;
TAILQ_FOREACH(temp, &node->head, rr_ll) {
if (working < 0)
break;
/*
* printf("SUSP Entry found, length is %i\n",
* CD9660_SUSP_ENTRY_SIZE(temp));
*/
working -= CD9660_SUSP_ENTRY_SIZE(temp);
if (working >= 0) {
last = temp;
susp_used += CD9660_SUSP_ENTRY_SIZE(temp);
}
if (working >= 28) {
/*
* Remember the last entry after which we
* could insert a "CE" entry.
*/
pre_ce = last;
susp_used_pre_ce = susp_used;
}
}
/* A CE entry is needed */
if (working <= 0) {
CE = cd9660node_susp_create_node(SUSP_TYPE_SUSP,
SUSP_ENTRY_SUSP_CE, "CE", SUSP_LOC_ENTRY);
cd9660_susp_ce(CE, node);
/* This will automatically insert at the appropriate location */
if (pre_ce != NULL)
TAILQ_INSERT_AFTER(&node->head, pre_ce, CE, rr_ll);
else
TAILQ_INSERT_HEAD(&node->head, CE, rr_ll);
last = CE;
susp_used = susp_used_pre_ce + 28;
/* Count how much CA data is necessary */
for (temp = TAILQ_NEXT(last, rr_ll); temp != NULL;
temp = TAILQ_NEXT(temp, rr_ll)) {
ca_used += CD9660_SUSP_ENTRY_SIZE(temp);
}
}
/* An ST entry is needed */
if (node->su_tail_size > 0) {
ST = cd9660node_susp_create_node(SUSP_TYPE_SUSP,
SUSP_ENTRY_SUSP_ST, "ST", SUSP_LOC_ENTRY);
cd9660_susp_st(ST, node);
if (last != NULL)
TAILQ_INSERT_AFTER(&node->head, last, ST, rr_ll);
else
TAILQ_INSERT_HEAD(&node->head, ST, rr_ll);
last = ST;
susp_used += 4;
}
if (last != NULL)
last->last_in_suf = 1;
node->susp_entry_size = susp_used;
node->susp_entry_ce_length = ca_used;
diskStructure->susp_continuation_area_size += ca_used;
return 1;
}
/* See if a continuation entry is needed for each of the different types */
static int
cd9660_susp_handle_continuation(iso9660_disk *diskStructure, cd9660node *node)
{
assert (node != NULL);
/* Entry */
if (cd9660_susp_handle_continuation_common(diskStructure,
node,(int)(node->isoDirRecord->length[0])) < 0)
return 0;
return 1;
}
int
cd9660_susp_initialize_node(iso9660_disk *diskStructure, cd9660node *node)
{
struct ISO_SUSP_ATTRIBUTES *temp;
/*
* Requirements/notes:
* CE: is added for us where needed
* ST: not sure if it is even required, but if so, should be
* handled by the CE code
* PD: isnt needed (though might be added for testing)
* SP: is stored ONLY on the . record of the root directory
* ES: not sure
*/
/* Check for root directory, add SP and ER if needed. */
if (node->type & CD9660_TYPE_DOT) {
if (node->parent == diskStructure->rootNode) {
temp = cd9660node_susp_create_node(SUSP_TYPE_SUSP,
SUSP_ENTRY_SUSP_SP, "SP", SUSP_LOC_DOT);
cd9660_susp_sp(temp, node);
/* Should be first entry. */
TAILQ_INSERT_HEAD(&node->head, temp, rr_ll);
}
}
return 1;
}
static void
cd9660_rrip_initialize_inode(cd9660node *node)
{
struct ISO_SUSP_ATTRIBUTES *attr;
/*
* Inode dependent values - this may change,
* but for now virtual files and directories do
* not have an inode structure
*/
if ((node->node != NULL) && (node->node->inode != NULL)) {
/* PX - POSIX attributes */
attr = cd9660node_susp_create_node(SUSP_TYPE_RRIP,
SUSP_ENTRY_RRIP_PX, "PX", SUSP_LOC_ENTRY);
cd9660node_rrip_px(attr, node->node);
TAILQ_INSERT_TAIL(&node->head, attr, rr_ll);
/* TF - timestamp */
attr = cd9660node_susp_create_node(SUSP_TYPE_RRIP,
SUSP_ENTRY_RRIP_TF, "TF", SUSP_LOC_ENTRY);
cd9660node_rrip_tf(attr, node->node);
TAILQ_INSERT_TAIL(&node->head, attr, rr_ll);
/* SL - Symbolic link */
/* ?????????? Dan - why is this here? */
if (TAILQ_EMPTY(&node->cn_children) &&
node->node->inode != NULL &&
S_ISLNK(node->node->inode->st.st_mode))
cd9660_createSL(node);
/* PN - device number */
if (node->node->inode != NULL &&
((S_ISCHR(node->node->inode->st.st_mode) ||
S_ISBLK(node->node->inode->st.st_mode)))) {
attr =
cd9660node_susp_create_node(SUSP_TYPE_RRIP,
SUSP_ENTRY_RRIP_PN, "PN",
SUSP_LOC_ENTRY);
cd9660node_rrip_pn(attr, node->node);
TAILQ_INSERT_TAIL(&node->head, attr, rr_ll);
}
}
}
int
cd9660_rrip_initialize_node(iso9660_disk *diskStructure, cd9660node *node,
cd9660node *parent, cd9660node *grandparent)
{
struct ISO_SUSP_ATTRIBUTES *current = NULL;
assert(node != NULL);
if (node->type & CD9660_TYPE_DOT) {
/*
* Handle ER - should be the only entry to appear on
* a "." record
*/
if (node->parent == diskStructure->rootNode) {
cd9660_susp_ER(node, 1, SUSP_RRIP_ER_EXT_ID,
SUSP_RRIP_ER_EXT_DES, SUSP_RRIP_ER_EXT_SRC);
}
if (parent != NULL && parent->node != NULL &&
parent->node->inode != NULL) {
/* PX - POSIX attributes */
current = cd9660node_susp_create_node(SUSP_TYPE_RRIP,
SUSP_ENTRY_RRIP_PX, "PX", SUSP_LOC_ENTRY);
cd9660node_rrip_px(current, parent->node);
TAILQ_INSERT_TAIL(&node->head, current, rr_ll);
}
} else if (node->type & CD9660_TYPE_DOTDOT) {
if (grandparent != NULL && grandparent->node != NULL &&
grandparent->node->inode != NULL) {
/* PX - POSIX attributes */
current = cd9660node_susp_create_node(SUSP_TYPE_RRIP,
SUSP_ENTRY_RRIP_PX, "PX", SUSP_LOC_ENTRY);
cd9660node_rrip_px(current, grandparent->node);
TAILQ_INSERT_TAIL(&node->head, current, rr_ll);
}
/* Handle PL */
if (parent != NULL && parent->rr_real_parent != NULL) {
current = cd9660node_susp_create_node(SUSP_TYPE_RRIP,
SUSP_ENTRY_RRIP_PL, "PL", SUSP_LOC_DOTDOT);
cd9660_rrip_PL(current,node);
TAILQ_INSERT_TAIL(&node->head, current, rr_ll);
}
} else {
cd9660_rrip_initialize_inode(node);
/*
* Not every node needs a NM set - only if the name is
* actually different. IE: If a file is TEST -> TEST,
* no NM. test -> TEST, need a NM
*
* The rr_moved_dir needs to be assigned a NM record as well.
*/
if (node == diskStructure->rr_moved_dir) {
cd9660_rrip_add_NM(node, RRIP_DEFAULT_MOVE_DIR_NAME);
}
else if ((node->node != NULL) &&
((strlen(node->node->name) !=
(uint8_t)node->isoDirRecord->name_len[0]) ||
(memcmp(node->node->name,node->isoDirRecord->name,
(uint8_t)node->isoDirRecord->name_len[0]) != 0))) {
cd9660_rrip_NM(node);
}
/* Rock ridge directory relocation code here. */
/* First handle the CL for the placeholder file. */
if (node->rr_relocated != NULL) {
current = cd9660node_susp_create_node(SUSP_TYPE_RRIP,
SUSP_ENTRY_RRIP_CL, "CL", SUSP_LOC_ENTRY);
cd9660_rrip_CL(current, node);
TAILQ_INSERT_TAIL(&node->head, current, rr_ll);
}
/* Handle RE*/
if (node->rr_real_parent != NULL) {
current = cd9660node_susp_create_node(SUSP_TYPE_RRIP,
SUSP_ENTRY_RRIP_RE, "RE", SUSP_LOC_ENTRY);
cd9660_rrip_RE(current,node);
TAILQ_INSERT_TAIL(&node->head, current, rr_ll);
}
}
return 1;
}
struct ISO_SUSP_ATTRIBUTES*
cd9660node_susp_create_node(int susp_type, int entry_type, const char *type_id,
int write_loc)
{
struct ISO_SUSP_ATTRIBUTES* temp;
temp = emalloc(sizeof(*temp));
temp->susp_type = susp_type;
temp->entry_type = entry_type;
temp->last_in_suf = 0;
/* Phase this out */
temp->type_of[0] = type_id[0];
temp->type_of[1] = type_id[1];
temp->write_location = write_loc;
/*
* Since the first four bytes is common, lets go ahead and
* set the type identifier, since we are passing that to this
* function anyhow.
*/
temp->attr.su_entry.SP.h.type[0] = type_id[0];
temp->attr.su_entry.SP.h.type[1] = type_id[1];
return temp;
}
int
cd9660_rrip_PL(struct ISO_SUSP_ATTRIBUTES* p, cd9660node *node __unused)
{
p->attr.rr_entry.PL.h.length[0] = 12;
p->attr.rr_entry.PL.h.version[0] = 1;
return 1;
}
int
cd9660_rrip_CL(struct ISO_SUSP_ATTRIBUTES *p, cd9660node *node __unused)
{
p->attr.rr_entry.CL.h.length[0] = 12;
p->attr.rr_entry.CL.h.version[0] = 1;
return 1;
}
int
cd9660_rrip_RE(struct ISO_SUSP_ATTRIBUTES *p, cd9660node *node __unused)
{
p->attr.rr_entry.RE.h.length[0] = 4;
p->attr.rr_entry.RE.h.version[0] = 1;
return 1;
}
void
cd9660_createSL(cd9660node *node)
{
struct ISO_SUSP_ATTRIBUTES* current;
int path_count, dir_count, done, i, j, dir_copied;
char temp_cr[255];
char temp_sl[255]; /* used in copying continuation entry*/
char* sl_ptr;
sl_ptr = node->node->symlink;
done = 0;
path_count = 0;
dir_count = 0;
dir_copied = 0;
current = cd9660node_susp_create_node(SUSP_TYPE_RRIP,
SUSP_ENTRY_RRIP_SL, "SL", SUSP_LOC_ENTRY);
current->attr.rr_entry.SL.h.version[0] = 1;
current->attr.rr_entry.SL.flags[0] = SL_FLAGS_NONE;
if (*sl_ptr == '/') {
temp_cr[0] = SL_FLAGS_ROOT;
temp_cr[1] = 0;
memcpy(current->attr.rr_entry.SL.component + path_count,
temp_cr, 2);
path_count += 2;
sl_ptr++;
}
for (i = 0; i < (dir_count + 2); i++)
temp_cr[i] = '\0';
while (!done) {
while ((*sl_ptr != '/') && (*sl_ptr != '\0')) {
dir_copied = 1;
if (*sl_ptr == '.') {
if ((*(sl_ptr + 1) == '/') || (*(sl_ptr + 1)
== '\0')) {
temp_cr[0] = SL_FLAGS_CURRENT;
sl_ptr++;
} else if(*(sl_ptr + 1) == '.') {
if ((*(sl_ptr + 2) == '/') ||
(*(sl_ptr + 2) == '\0')) {
temp_cr[0] = SL_FLAGS_PARENT;
sl_ptr += 2;
}
} else {
temp_cr[dir_count+2] = *sl_ptr;
sl_ptr++;
dir_count++;
}
} else {
temp_cr[dir_count + 2] = *sl_ptr;
sl_ptr++;
dir_count++;
}
}
if ((path_count + dir_count) >= 249) {
current->attr.rr_entry.SL.flags[0] |= SL_FLAGS_CONTINUE;
j = 0;
if (path_count <= 249) {
while(j != (249 - path_count)) {
temp_sl[j] = temp_cr[j];
j++;
}
temp_sl[0] = SL_FLAGS_CONTINUE;
temp_sl[1] = j - 2;
memcpy(
current->attr.rr_entry.SL.component +
path_count,
temp_sl, j);
}
path_count += j;
current->attr.rr_entry.SL.h.length[0] = path_count + 5;
TAILQ_INSERT_TAIL(&node->head, current, rr_ll);
current= cd9660node_susp_create_node(SUSP_TYPE_RRIP,
SUSP_ENTRY_RRIP_SL, "SL", SUSP_LOC_ENTRY);
current->attr.rr_entry.SL.h.version[0] = 1;
current->attr.rr_entry.SL.flags[0] = SL_FLAGS_NONE;
path_count = 0;
if (dir_count > 2) {
while (j != dir_count + 2) {
current->attr.rr_entry.SL.component[
path_count + 2] = temp_cr[j];
j++;
path_count++;
}
current->attr.rr_entry.SL.component[1]
= path_count;
path_count+= 2;
} else {
while(j != dir_count) {
current->attr.rr_entry.SL.component[
path_count+2] = temp_cr[j];
j++;
path_count++;
}
}
} else {
if (dir_copied == 1) {
temp_cr[1] = dir_count;
memcpy(current->attr.rr_entry.SL.component +
path_count,
temp_cr, dir_count + 2);
path_count += dir_count + 2;
}
}
if (*sl_ptr == '\0') {
done = 1;
current->attr.rr_entry.SL.h.length[0] = path_count + 5;
TAILQ_INSERT_TAIL(&node->head, current, rr_ll);
} else {
sl_ptr++;
dir_count = 0;
dir_copied = 0;
for(i = 0; i < 255; i++) {
temp_cr[i] = '\0';
}
}
}
}
int
cd9660node_rrip_px(struct ISO_SUSP_ATTRIBUTES *v, fsnode *pxinfo)
{
v->attr.rr_entry.PX.h.length[0] = 36;
v->attr.rr_entry.PX.h.version[0] = 1;
cd9660_bothendian_dword(pxinfo->inode->st.st_mode,
v->attr.rr_entry.PX.mode);
cd9660_bothendian_dword(pxinfo->inode->st.st_nlink,
v->attr.rr_entry.PX.links);
cd9660_bothendian_dword(pxinfo->inode->st.st_uid,
v->attr.rr_entry.PX.uid);
cd9660_bothendian_dword(pxinfo->inode->st.st_gid,
v->attr.rr_entry.PX.gid);
/* Ignoring the serial number for now */
return 1;
}
int
cd9660node_rrip_pn(struct ISO_SUSP_ATTRIBUTES *pn_field, fsnode *fnode)
{
pn_field->attr.rr_entry.PN.h.length[0] = 20;
pn_field->attr.rr_entry.PN.h.version[0] = 1;
if (sizeof (fnode->inode->st.st_dev) > 32)
cd9660_bothendian_dword((uint64_t)fnode->inode->st.st_dev >> 32,
pn_field->attr.rr_entry.PN.high);
else
cd9660_bothendian_dword(0, pn_field->attr.rr_entry.PN.high);
cd9660_bothendian_dword(fnode->inode->st.st_dev & 0xffffffff,
pn_field->attr.rr_entry.PN.low);
return 1;
}
#if 0
int
cd9660node_rrip_nm(struct ISO_SUSP_ATTRIBUTES *p, cd9660node *file_node)
{
int nm_length = strlen(file_node->isoDirRecord->name) + 5;
p->attr.rr_entry.NM.h.type[0] = 'N';
p->attr.rr_entry.NM.h.type[1] = 'M';
sprintf(p->attr.rr_entry.NM.altname, "%s", file_node->isoDirRecord->name);
p->attr.rr_entry.NM.h.length[0] = (unsigned char)nm_length;
p->attr.rr_entry.NM.h.version[0] = (unsigned char)1;
p->attr.rr_entry.NM.flags[0] = (unsigned char) NM_PARENT;
return 1;
}
#endif
int
cd9660node_rrip_tf(struct ISO_SUSP_ATTRIBUTES *p, fsnode *_node)
{
p->attr.rr_entry.TF.flags[0] = TF_MODIFY | TF_ACCESS | TF_ATTRIBUTES;
p->attr.rr_entry.TF.h.length[0] = 5;
p->attr.rr_entry.TF.h.version[0] = 1;
/*
* Need to add creation time, backup time,
* expiration time, and effective time.
*/
cd9660_time_915(p->attr.rr_entry.TF.timestamp,
_node->inode->st.st_atime);
p->attr.rr_entry.TF.h.length[0] += 7;
cd9660_time_915(p->attr.rr_entry.TF.timestamp + 7,
_node->inode->st.st_mtime);
p->attr.rr_entry.TF.h.length[0] += 7;
cd9660_time_915(p->attr.rr_entry.TF.timestamp + 14,
_node->inode->st.st_ctime);
p->attr.rr_entry.TF.h.length[0] += 7;
return 1;
}
int
cd9660_susp_sp(struct ISO_SUSP_ATTRIBUTES *p, cd9660node *spinfo __unused)
{
p->attr.su_entry.SP.h.length[0] = 7;
p->attr.su_entry.SP.h.version[0] = 1;
p->attr.su_entry.SP.check[0] = 0xBE;
p->attr.su_entry.SP.check[1] = 0xEF;
p->attr.su_entry.SP.len_skp[0] = 0;
return 1;
}
int
cd9660_susp_st(struct ISO_SUSP_ATTRIBUTES *p, cd9660node *stinfo __unused)
{
p->attr.su_entry.ST.h.type[0] = 'S';
p->attr.su_entry.ST.h.type[1] = 'T';
p->attr.su_entry.ST.h.length[0] = 4;
p->attr.su_entry.ST.h.version[0] = 1;
return 1;
}
int
cd9660_susp_ce(struct ISO_SUSP_ATTRIBUTES *p, cd9660node *spinfo __unused)
{
p->attr.su_entry.CE.h.length[0] = 28;
p->attr.su_entry.CE.h.version[0] = 1;
/* Other attributes dont matter right now, will be updated later */
return 1;
}
int
cd9660_susp_pd(struct ISO_SUSP_ATTRIBUTES *p __unused, int length __unused)
{
return 1;
}
void
cd9660_rrip_add_NM(cd9660node *node, const char *name)
{
int working,len;
const char *p;
struct ISO_SUSP_ATTRIBUTES *r;
/*
* Each NM record has 254 byes to work with. This means that
* the name data itself only has 249 bytes to work with. So, a
* name with 251 characters would require two nm records.
*/
p = name;
working = 1;
while (working) {
r = cd9660node_susp_create_node(SUSP_TYPE_RRIP,
SUSP_ENTRY_RRIP_NM, "NM", SUSP_LOC_ENTRY);
r->attr.rr_entry.NM.h.version[0] = 1;
r->attr.rr_entry.NM.flags[0] = RRIP_NM_FLAGS_NONE;
len = strlen(p);
if (len > 249) {
len = 249;
r->attr.rr_entry.NM.flags[0] = RRIP_NM_FLAGS_CONTINUE;
} else {
working = 0;
}
memcpy(r->attr.rr_entry.NM.altname, p, len);
r->attr.rr_entry.NM.h.length[0] = 5 + len;
TAILQ_INSERT_TAIL(&node->head, r, rr_ll);
p += len;
}
}
void
cd9660_rrip_NM(cd9660node *node)
{
cd9660_rrip_add_NM(node, node->node->name);
}
struct ISO_SUSP_ATTRIBUTES*
cd9660_susp_ER(cd9660node *node,
u_char ext_version, const char* ext_id, const char* ext_des,
const char* ext_src)
{
int l;
struct ISO_SUSP_ATTRIBUTES *r;
r = cd9660node_susp_create_node(SUSP_TYPE_SUSP,
SUSP_ENTRY_SUSP_ER, "ER", SUSP_LOC_DOT);
/* Fixed data is 8 bytes */
r->attr.su_entry.ER.h.length[0] = 8;
r->attr.su_entry.ER.h.version[0] = 1;
r->attr.su_entry.ER.len_id[0] = (u_char)strlen(ext_id);
r->attr.su_entry.ER.len_des[0] = (u_char)strlen(ext_des);
r->attr.su_entry.ER.len_src[0] = (u_char)strlen(ext_src);
l = r->attr.su_entry.ER.len_id[0] +
r->attr.su_entry.ER.len_src[0] +
r->attr.su_entry.ER.len_des[0];
/* Everything must fit. */
assert(l + r->attr.su_entry.ER.h.length[0] <= 254);
r->attr.su_entry.ER.h.length[0] += (u_char)l;
r->attr.su_entry.ER.ext_ver[0] = ext_version;
memcpy(r->attr.su_entry.ER.ext_data, ext_id,
(int)r->attr.su_entry.ER.len_id[0]);
l = (int) r->attr.su_entry.ER.len_id[0];
memcpy(r->attr.su_entry.ER.ext_data + l,ext_des,
(int)r->attr.su_entry.ER.len_des[0]);
l += (int)r->attr.su_entry.ER.len_des[0];
memcpy(r->attr.su_entry.ER.ext_data + l,ext_src,
(int)r->attr.su_entry.ER.len_src[0]);
TAILQ_INSERT_TAIL(&node->head, r, rr_ll);
return r;
}
struct ISO_SUSP_ATTRIBUTES*
cd9660_susp_ES(struct ISO_SUSP_ATTRIBUTES *last __unused, cd9660node *node __unused)
{
return NULL;
}

View file

@ -0,0 +1,290 @@
/* $NetBSD: iso9660_rrip.h,v 1.6 2013/01/28 21:03:28 christos Exp $ */
/*
* Copyright (c) 2005 Daniel Watt, Walter Deignan, Ryan Gabrys, Alan
* Perez-Rathke and Ram Vedam. All rights reserved.
*
* This code was written by Daniel Watt, Walter Deignan, Ryan Gabrys,
* Alan Perez-Rathke and Ram Vedam.
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY DANIEL WATT, WALTER DEIGNAN, RYAN
* GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL DANIEL WATT, WALTER DEIGNAN, RYAN
* GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE,DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*/
#ifndef __ISO9660_RRIP_H__
#define __ISO9660_RRIP_H__
/*
* This will hold all the functions needed to
* write an ISO 9660 image with Rock Ridge Extensions
*/
/* For writing must use ISO_RRIP_EXTREF structure */
#include "makefs.h"
#include <cd9660_rrip.h>
#include "cd9660.h"
#include <sys/queue.h>
#define PX_LENGTH 0x2C
#define PN_LENGTH 0x14
#define TF_CREATION 0x00
#define TF_MODIFY 0x01
#define TF_ACCESS 0x02
#define TF_ATTRIBUTES 0x04
#define TF_BACKUP 0x08
#define TF_EXPIRATION 0x10
#define TF_EFFECTIVE 0x20
#define TF_LONGFORM 0x40
#define NM_CONTINUE 0x80
#define NM_CURRENT 0x100
#define NM_PARENT 0x200
#define SUSP_LOC_ENTRY 0x01
#define SUSP_LOC_DOT 0x02
#define SUSP_LOC_DOTDOT 0x04
#define SUSP_TYPE_SUSP 1
#define SUSP_TYPE_RRIP 2
#define SUSP_ENTRY_SUSP_CE 1
#define SUSP_ENTRY_SUSP_PD 2
#define SUSP_ENTRY_SUSP_SP 3
#define SUSP_ENTRY_SUSP_ST 4
#define SUSP_ENTRY_SUSP_ER 5
#define SUSP_ENTRY_SUSP_ES 6
#define SUSP_ENTRY_RRIP_PX 1
#define SUSP_ENTRY_RRIP_PN 2
#define SUSP_ENTRY_RRIP_SL 3
#define SUSP_ENTRY_RRIP_NM 4
#define SUSP_ENTRY_RRIP_CL 5
#define SUSP_ENTRY_RRIP_PL 6
#define SUSP_ENTRY_RRIP_RE 7
#define SUSP_ENTRY_RRIP_TF 8
#define SUSP_ENTRY_RRIP_SF 9
#define SUSP_RRIP_ER_EXT_ID "IEEE_P1282"
#define SUSP_RRIP_ER_EXT_DES "THE IEEE P1282 PROTOCOL PROVIDES SUPPORT FOR POSIX FILE SYSTEM SEMANTICS."
#define SUSP_RRIP_ER_EXT_SRC "PLEASE CONTACT THE IEEE STANDARDS DEPARTMENT, PISCATAWAY, NJ, USA FOR THE P1282 SPECIFICATION."
#define SL_FLAGS_NONE 0
#define SL_FLAGS_CONTINUE 1
#define SL_FLAGS_CURRENT 2
#define SL_FLAGS_PARENT 4
#define SL_FLAGS_ROOT 8
typedef struct {
ISO_SUSP_HEADER h;
u_char mode [ISODCL(5,12)];
u_char links [ISODCL(13,20)];
u_char uid [ISODCL(21,28)];
u_char gid [ISODCL(29,36)];
u_char serial [ISODCL(37,44)];/* Not used */
} ISO_RRIP_PX;
typedef struct {
ISO_SUSP_HEADER h;
u_char high [ISODCL(5,12)];
u_char low [ISODCL(13,20)];
} ISO_RRIP_PN;
typedef struct {
ISO_SUSP_HEADER h;
u_char flags [ISODCL ( 4, 4)];
u_char component [ISODCL ( 4, 256)];
u_int nBytes;
} ISO_RRIP_SL;
typedef struct {
ISO_SUSP_HEADER h;
u_char flags [ISODCL ( 4, 4)];
u_char timestamp [ISODCL ( 5, 256)];
} ISO_RRIP_TF;
#define RRIP_NM_FLAGS_NONE 0x00
#define RRIP_NM_FLAGS_CONTINUE 0x01
#define RRIP_NM_FLAGS_CURRENT 0x02
#define RRIP_NM_FLAGS_PARENT 0x04
typedef struct {
ISO_SUSP_HEADER h;
u_char flags [ISODCL ( 4, 4)];
u_char altname [ISODCL ( 4, 256)];
} ISO_RRIP_NM;
/* Note that this is the same structure as cd9660_rrip.h : ISO_RRIP_CONT */
typedef struct {
ISO_SUSP_HEADER h;
u_char ca_sector [ISODCL ( 5, 12)];
u_char offset [ISODCL ( 13, 20)];
u_char length [ISODCL ( 21, 28)];
} ISO_SUSP_CE;
typedef struct {
ISO_SUSP_HEADER h;
u_char padding_area [ISODCL ( 4, 256)];
} ISO_SUSP_PD;
typedef struct {
ISO_SUSP_HEADER h;
u_char check [ISODCL ( 4, 5)];
u_char len_skp [ISODCL ( 6, 6)];
} ISO_SUSP_SP;
typedef struct {
ISO_SUSP_HEADER h;
} ISO_SUSP_ST;
typedef struct {
ISO_SUSP_HEADER h;
u_char len_id [ISODCL ( 4, 4)];
u_char len_des [ISODCL ( 5, 5)];
u_char len_src [ISODCL ( 6, 6)];
u_char ext_ver [ISODCL ( 7, 7)];
u_char ext_data [ISODCL (8,256)];
/* u_char ext_id [ISODCL ( 8, 256)];
u_char ext_des [ISODCL ( 257, 513)];
u_char ext_src [ISODCL ( 514, 770)];*/
} ISO_SUSP_ER;
typedef struct {
ISO_SUSP_HEADER h;
u_char ext_seq [ISODCL ( 4, 4)];
} ISO_SUSP_ES;
typedef union {
ISO_RRIP_PX PX;
ISO_RRIP_PN PN;
ISO_RRIP_SL SL;
ISO_RRIP_NM NM;
ISO_RRIP_CLINK CL;
ISO_RRIP_PLINK PL;
ISO_RRIP_RELDIR RE;
ISO_RRIP_TF TF;
} rrip_entry;
typedef union {
ISO_SUSP_CE CE;
ISO_SUSP_PD PD;
ISO_SUSP_SP SP;
ISO_SUSP_ST ST;
ISO_SUSP_ER ER;
ISO_SUSP_ES ES;
} susp_entry;
typedef union {
susp_entry su_entry;
rrip_entry rr_entry;
} SUSP_ENTRIES;
struct ISO_SUSP_ATTRIBUTES {
SUSP_ENTRIES attr;
int type;
char type_of[2];
char last_in_suf; /* last entry in the System Use Field? */
/* Dan's addons - will merge later. This allows use of a switch */
char susp_type; /* SUSP or RRIP */
char entry_type; /* Record type */
char write_location;
TAILQ_ENTRY(ISO_SUSP_ATTRIBUTES) rr_ll;
};
#define CD9660_SUSP_ENTRY_SIZE(entry)\
((int) ((entry)->attr.su_entry.SP.h.length[0]))
/* Recursive function - move later to func pointer code*/
int cd9660_susp_finalize(iso9660_disk *, cd9660node *);
/* These two operate on single nodes */
int cd9660_susp_finalize_node(iso9660_disk *, cd9660node *);
int cd9660_rrip_finalize_node(iso9660_disk *, cd9660node *);
/* POSIX File attribute */
int cd9660node_rrip_px(struct ISO_SUSP_ATTRIBUTES *, fsnode *);
/* Device number */
int cd9660node_rrip_pn(struct ISO_SUSP_ATTRIBUTES *, fsnode *);
/* Symbolic link */
int cd9660node_rrip_SL(struct ISO_SUSP_ATTRIBUTES *, fsnode *);
/* Alternate Name function */
void cd9660_rrip_NM(cd9660node *);
void cd9660_rrip_add_NM(cd9660node *,const char *);
/* Parent and child link function */
int cd9660_rrip_PL(struct ISO_SUSP_ATTRIBUTES *, cd9660node *);
int cd9660_rrip_CL(struct ISO_SUSP_ATTRIBUTES *, cd9660node *);
int cd9660_rrip_RE(struct ISO_SUSP_ATTRIBUTES *, cd9660node *);
int cd9660node_rrip_tf(struct ISO_SUSP_ATTRIBUTES *, fsnode *);
/*
* Relocation directory function. I'm not quite sure what
* sort of parameters are needed, but personally I don't think
* any parameters are needed except for the memory address where
* the information needs to be put in
*/
int cd9660node_rrip_re(void *, fsnode *);
/*
* Don't know if this function is needed because it apparently is an
* optional feature that does not really need to be implemented but I
* thought I should add it anyway.
*/
int cd9660_susp_ce (struct ISO_SUSP_ATTRIBUTES *, cd9660node *);
int cd9660_susp_pd (struct ISO_SUSP_ATTRIBUTES *, int);
int cd9660_susp_sp (struct ISO_SUSP_ATTRIBUTES *, cd9660node *);
int cd9660_susp_st (struct ISO_SUSP_ATTRIBUTES *, cd9660node *);
struct ISO_SUSP_ATTRIBUTES *cd9660_susp_ER(cd9660node *, u_char, const char *,
const char *, const char *);
struct ISO_SUSP_ATTRIBUTES *cd9660_susp_ES(struct ISO_SUSP_ATTRIBUTES*,
cd9660node *);
/* Helper functions */
/* Common SUSP/RRIP functions */
int cd9660_susp_initialize(iso9660_disk *, cd9660node *, cd9660node *,
cd9660node *);
int cd9660_susp_initialize_node(iso9660_disk *, cd9660node *);
struct ISO_SUSP_ATTRIBUTES *cd9660node_susp_create_node(int, int, const char *,
int);
struct ISO_SUSP_ATTRIBUTES *cd9660node_susp_add_entry(cd9660node *,
struct ISO_SUSP_ATTRIBUTES *, struct ISO_SUSP_ATTRIBUTES *, int);
/* RRIP specific functions */
int cd9660_rrip_initialize_node(iso9660_disk *, cd9660node *, cd9660node *,
cd9660node *);
void cd9660_createSL(cd9660node *);
/* Functions that probably can be removed */
/* int cd9660node_initialize_node(int, char *); */
#endif

222
usr.sbin/makefs/chfs.c Normal file
View file

@ -0,0 +1,222 @@
/*-
* Copyright (c) 2012 Department of Software Engineering,
* University of Szeged, Hungary
* Copyright (c) 2012 Tamas Toth <ttoth@inf.u-szeged.hu>
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by the Department of Software Engineering, University of Szeged, Hungary
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if HAVE_NBTOOL_CONFIG_H
#include "nbtool_config.h"
#endif
#include <sys/param.h>
#include <assert.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <util.h>
#include "makefs.h"
#include "chfs_makefs.h"
#include "chfs/chfs_mkfs.h"
static void chfs_validate(const char *, fsnode *, fsinfo_t *);
static int chfs_create_image(const char *, fsinfo_t *);
static int chfs_populate_dir(const char *, fsnode *, fsnode *, fsinfo_t *);
void
chfs_prep_opts(fsinfo_t *fsopts)
{
chfs_opt_t *chfs_opts = ecalloc(1, sizeof(*chfs_opts));
const option_t chfs_options[] = {
{ 'p', "pagesize", &chfs_opts->pagesize, OPT_INT32,
1, INT_MAX, "page size" },
{ 'e', "eraseblock", &chfs_opts->eraseblock, OPT_INT32,
1, INT_MAX, "eraseblock size" },
{ 'm', "mediatype", &chfs_opts->mediatype, OPT_INT32,
0, 1, "type of the media, 0 (nor) or 1 (nand)" },
{ .name = NULL }
};
chfs_opts->pagesize = -1;
chfs_opts->eraseblock = -1;
chfs_opts->mediatype = -1;
fsopts->size = 0;
fsopts->fs_specific = chfs_opts;
fsopts->fs_options = copy_opts(chfs_options);
}
void
chfs_cleanup_opts(fsinfo_t *fsopts)
{
free(fsopts->fs_specific);
free(fsopts->fs_options);
}
int
chfs_parse_opts(const char *option, fsinfo_t *fsopts)
{
assert(option != NULL);
assert(fsopts != NULL);
return set_option(fsopts->fs_options, option, NULL, 0) != -1;
}
void
chfs_makefs(const char *image, const char *dir, fsnode *root, fsinfo_t *fsopts)
{
struct timeval start;
assert(image != NULL);
assert(dir != NULL);
assert(root != NULL);
assert(fsopts != NULL);
TIMER_START(start);
chfs_validate(dir, root, fsopts);
TIMER_RESULTS(start, "chfs_validate");
printf("Creating `%s'\n", image);
TIMER_START(start);
if (chfs_create_image(image, fsopts) == -1) {
errx(EXIT_FAILURE, "Image file `%s' not created", image);
}
TIMER_RESULTS(start, "chfs_create_image");
fsopts->curinode = CHFS_ROOTINO;
root->inode->ino = CHFS_ROOTINO;
printf("Populating `%s'\n", image);
TIMER_START(start);
write_eb_header(fsopts);
if (!chfs_populate_dir(dir, root, root, fsopts)) {
errx(EXIT_FAILURE, "Image file `%s' not populated", image);
}
TIMER_RESULTS(start, "chfs_populate_dir");
padblock(fsopts);
if (close(fsopts->fd) == -1) {
err(EXIT_FAILURE, "Closing `%s'", image);
}
fsopts->fd = -1;
printf("Image `%s' complete\n", image);
}
static void
chfs_validate(const char* dir, fsnode *root, fsinfo_t *fsopts)
{
chfs_opt_t *chfs_opts;
assert(dir != NULL);
assert(root != NULL);
assert(fsopts != NULL);
chfs_opts = fsopts->fs_specific;
if (chfs_opts->pagesize == -1) {
chfs_opts->pagesize = DEFAULT_PAGESIZE;
}
if (chfs_opts->eraseblock == -1) {
chfs_opts->eraseblock = DEFAULT_ERASEBLOCK;
}
if (chfs_opts->mediatype == -1) {
chfs_opts->mediatype = DEFAULT_MEDIATYPE;
}
}
static int
chfs_create_image(const char *image, fsinfo_t *fsopts)
{
assert(image != NULL);
assert(fsopts != NULL);
if ((fsopts->fd = open(image, O_RDWR | O_CREAT | O_TRUNC, 0666)) == -1) {
warn("Can't open `%s' for writing", image);
return -1;
}
return fsopts->fd;
}
static int
chfs_populate_dir(const char *dir, fsnode *root, fsnode *parent,
fsinfo_t *fsopts)
{
fsnode *cur;
char path[MAXPATHLEN + 1];
assert(dir != NULL);
assert(root != NULL);
assert(fsopts != NULL);
for (cur = root->next; cur != NULL; cur = cur->next) {
if ((cur->inode->flags & FI_ALLOCATED) == 0) {
cur->inode->flags |= FI_ALLOCATED;
if (cur != root) {
fsopts->curinode++;
cur->inode->ino = fsopts->curinode;
cur->parent = parent;
}
}
if (cur->inode->flags & FI_WRITTEN) {
continue; // hard link
}
cur->inode->flags |= FI_WRITTEN;
write_vnode(fsopts, cur);
write_dirent(fsopts, cur);
if (!S_ISDIR(cur->type & S_IFMT)) {
write_file(fsopts, cur, dir);
}
}
for (cur = root; cur != NULL; cur = cur->next) {
if (cur->child == NULL) {
continue;
}
if ((size_t)snprintf(path, sizeof(path), "%s/%s", dir,
cur->name) >= sizeof(path)) {
errx(EXIT_FAILURE, "Pathname too long");
}
if (!chfs_populate_dir(path, cur->child, cur, fsopts)) {
return 0;
}
}
return 1;
}

View file

@ -0,0 +1,11 @@
CHFS= ${NETBSDSRCDIR}/sys/ufs/chfs
.PATH: ${.CURDIR}/chfs ${NETBSDSRCDIR}/sys/ufs/chfs
CPPFLAGS+= -I${CHFS}
SRCS+= chfs_mkfs.c
.if !defined(HOSTPROG)
LDADD+= -lz
DPADD+= ${LIBZ}
.endif

View file

@ -0,0 +1,307 @@
/*-
* Copyright (c) 2012 Department of Software Engineering,
* University of Szeged, Hungary
* Copyright (c) 2012 Tamas Toth <ttoth@inf.u-szeged.hu>
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by the Department of Software Engineering, University of Szeged, Hungary
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if HAVE_NBTOOL_CONFIG_H
#include "nbtool_config.h"
#endif
#include <sys/param.h>
#include <sys/stat.h>
#include <assert.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <zlib.h>
#include <util.h>
#if defined(__minix)
#include <unistd.h>
#endif
#include "makefs.h"
#include "chfs_makefs.h"
#include "media.h"
#include "ebh.h"
#include "chfs/chfs_mkfs.h"
static uint32_t img_ofs = 0;
static uint64_t version = 0;
static uint64_t max_serial = 0;
static int lebnumber = 0;
static const unsigned char ffbuf[16] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
};
static void
buf_write(fsinfo_t *fsopts, const void *buf, size_t len)
{
ssize_t retval;
const char *charbuf = buf;
while (len > 0) {
retval = write(fsopts->fd, charbuf, len);
if (retval == -1) {
err(EXIT_FAILURE, "ERROR while writing");
}
len -= retval;
charbuf += retval;
img_ofs += retval;
}
}
void
padblock(fsinfo_t *fsopts)
{
chfs_opt_t *chfs_opts = fsopts->fs_specific;
while (img_ofs % chfs_opts->eraseblock) {
buf_write(fsopts, ffbuf, MIN(sizeof(ffbuf),
chfs_opts->eraseblock - (img_ofs % chfs_opts->eraseblock)));
}
}
static void
padword(fsinfo_t *fsopts)
{
if (img_ofs % 4) {
buf_write(fsopts, ffbuf, 4 - img_ofs % 4);
}
}
static void
pad_block_if_less_than(fsinfo_t *fsopts, int req)
{
chfs_opt_t *chfs_opts = fsopts->fs_specific;
if ((img_ofs % chfs_opts->eraseblock) + req >
(uint32_t)chfs_opts->eraseblock) {
padblock(fsopts);
write_eb_header(fsopts);
}
}
void
write_eb_header(fsinfo_t *fsopts)
{
chfs_opt_t *opts;
struct chfs_eb_hdr ebhdr;
char *buf;
opts = fsopts->fs_specific;
#define MINSIZE MAX(MAX(CHFS_EB_EC_HDR_SIZE, CHFS_EB_HDR_NOR_SIZE), \
CHFS_EB_HDR_NAND_SIZE)
if ((uint32_t)opts->pagesize < MINSIZE)
errx(EXIT_FAILURE, "pagesize cannot be less than %zu", MINSIZE);
buf = emalloc(opts->pagesize);
memset(buf, 0xFF, opts->pagesize);
ebhdr.ec_hdr.magic = htole32(CHFS_MAGIC_BITMASK);
ebhdr.ec_hdr.erase_cnt = htole32(1);
ebhdr.ec_hdr.crc_ec = htole32(crc32(0,
(uint8_t *)&ebhdr.ec_hdr + 8, 4));
memcpy(buf, &ebhdr.ec_hdr, CHFS_EB_EC_HDR_SIZE);
buf_write(fsopts, buf, opts->pagesize);
memset(buf, 0xFF, opts->pagesize);
if (opts->mediatype == TYPE_NAND) {
ebhdr.u.nand_hdr.lid = htole32(lebnumber++);
ebhdr.u.nand_hdr.serial = htole64(++(max_serial));
ebhdr.u.nand_hdr.crc = htole32(crc32(0,
(uint8_t *)&ebhdr.u.nand_hdr + 4,
CHFS_EB_HDR_NAND_SIZE - 4));
memcpy(buf, &ebhdr.u.nand_hdr, CHFS_EB_HDR_NAND_SIZE);
} else {
ebhdr.u.nor_hdr.lid = htole32(lebnumber++);
ebhdr.u.nor_hdr.crc = htole32(crc32(0,
(uint8_t *)&ebhdr.u.nor_hdr + 4,
CHFS_EB_HDR_NOR_SIZE - 4));
memcpy(buf, &ebhdr.u.nor_hdr, CHFS_EB_HDR_NOR_SIZE);
}
buf_write(fsopts, buf, opts->pagesize);
free(buf);
}
void
write_vnode(fsinfo_t *fsopts, fsnode *node)
{
struct chfs_flash_vnode fvnode;
memset(&fvnode, 0, sizeof(fvnode));
fvnode.magic = htole16(CHFS_FS_MAGIC_BITMASK);
fvnode.type = htole16(CHFS_NODETYPE_VNODE);
fvnode.length = htole32(CHFS_PAD(sizeof(fvnode)));
fvnode.hdr_crc = htole32(crc32(0, (uint8_t *)&fvnode,
CHFS_NODE_HDR_SIZE - 4));
fvnode.vno = htole64(node->inode->ino);
fvnode.version = htole64(version++);
fvnode.mode = htole32(node->inode->st.st_mode);
fvnode.dn_size = htole32(node->inode->st.st_size);
fvnode.atime = htole32(node->inode->st.st_atime);
fvnode.ctime = htole32(node->inode->st.st_ctime);
fvnode.mtime = htole32(node->inode->st.st_mtime);
fvnode.gid = htole32(node->inode->st.st_uid);
fvnode.uid = htole32(node->inode->st.st_gid);
fvnode.node_crc = htole32(crc32(0, (uint8_t *)&fvnode,
sizeof(fvnode) - 4));
pad_block_if_less_than(fsopts, sizeof(fvnode));
buf_write(fsopts, &fvnode, sizeof(fvnode));
padword(fsopts);
}
void
write_dirent(fsinfo_t *fsopts, fsnode *node)
{
struct chfs_flash_dirent_node fdirent;
char *name;
name = emalloc(strlen(node->name));
memcpy(name, node->name, strlen(node->name));
memset(&fdirent, 0, sizeof(fdirent));
fdirent.magic = htole16(CHFS_FS_MAGIC_BITMASK);
fdirent.type = htole16(CHFS_NODETYPE_DIRENT);
fdirent.length = htole32(CHFS_PAD(sizeof(fdirent) + strlen(name)));
fdirent.hdr_crc = htole32(crc32(0, (uint8_t *)&fdirent,
CHFS_NODE_HDR_SIZE - 4));
fdirent.vno = htole64(node->inode->ino);
if (node->parent != NULL) {
fdirent.pvno = htole64(node->parent->inode->ino);
} else {
fdirent.pvno = htole64(node->inode->ino);
}
fdirent.version = htole64(version++);
fdirent.mctime = 0;
fdirent.nsize = htole32(strlen(name));
fdirent.dtype = htole32(IFTOCHT(node->type & S_IFMT));
fdirent.name_crc = htole32(crc32(0, (uint8_t *)name, fdirent.nsize));
fdirent.node_crc = htole32(crc32(0, (uint8_t *)&fdirent,
sizeof(fdirent) - 4));
pad_block_if_less_than(fsopts, sizeof(fdirent) + fdirent.nsize);
buf_write(fsopts, &fdirent, sizeof(fdirent));
buf_write(fsopts, name, fdirent.nsize);
padword(fsopts);
}
void
write_file(fsinfo_t *fsopts, fsnode *node, const char *dir)
{
int fd;
ssize_t len;
char *name = node->name;
chfs_opt_t *opts;
unsigned char *buf;
uint32_t fileofs = 0;
opts = fsopts->fs_specific;
buf = emalloc(opts->pagesize);
if (node->type == S_IFREG || node->type == S_IFSOCK) {
char *longname;
if (asprintf(&longname, "%s/%s", dir, name) == 1)
goto out;
fd = open(longname, O_RDONLY, 0444);
if (fd == -1)
err(EXIT_FAILURE, "Cannot open `%s'", longname);
while ((len = read(fd, buf, opts->pagesize))) {
if (len < 0) {
warn("ERROR while reading %s", longname);
free(longname);
free(buf);
close(fd);
return;
}
write_data(fsopts, node, buf, len, fileofs);
fileofs += len;
}
free(longname);
close(fd);
} else if (node->type == S_IFLNK) {
len = strlen(node->symlink);
memcpy(buf, node->symlink, len);
write_data(fsopts, node, buf, len, 0);
} else if (node->type == S_IFCHR || node->type == S_IFBLK ||
node->type == S_IFIFO) {
len = sizeof(dev_t);
memcpy(buf, &(node->inode->st.st_rdev), len);
write_data(fsopts, node, buf, len, 0);
}
free(buf);
return;
out:
err(EXIT_FAILURE, "Memory allocation failed");
}
void
write_data(fsinfo_t *fsopts, fsnode *node, unsigned char *buf, size_t len,
uint32_t ofs)
{
struct chfs_flash_data_node fdata;
memset(&fdata, 0, sizeof(fdata));
if (len == 0) {
return;
}
pad_block_if_less_than(fsopts, sizeof(fdata) + len);
fdata.magic = htole16(CHFS_FS_MAGIC_BITMASK);
fdata.type = htole16(CHFS_NODETYPE_DATA);
fdata.length = htole32(CHFS_PAD(sizeof(fdata) + len));
fdata.hdr_crc = htole32(crc32(0, (uint8_t *)&fdata,
CHFS_NODE_HDR_SIZE - 4));
fdata.vno = htole64(node->inode->ino);
fdata.data_length = htole32(len);
fdata.offset = htole32(ofs);
fdata.data_crc = htole32(crc32(0, (uint8_t *)buf, len));
fdata.node_crc = htole32(crc32(0,
(uint8_t *)&fdata, sizeof(fdata) - 4));
buf_write(fsopts, &fdata, sizeof(fdata));
buf_write(fsopts, buf, len);
padword(fsopts);
}

View file

@ -0,0 +1,44 @@
/*-
* Copyright (c) 2012 Department of Software Engineering,
* University of Szeged, Hungary
* Copyright (c) 2012 Tamas Toth <ttoth@inf.u-szeged.hu>
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by the Department of Software Engineering, University of Szeged, Hungary
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef _CHFS_MKFS_H
#define _CHFS_MKFS_H
#include "chfs.h"
void padblock(fsinfo_t *);
void write_eb_header(fsinfo_t *);
void write_vnode(fsinfo_t *, fsnode *);
void write_dirent(fsinfo_t *, fsnode *);
void write_file(fsinfo_t *, fsnode *, const char *);
void write_data(fsinfo_t *, fsnode *, unsigned char *, size_t, uint32_t);
#endif

View file

@ -0,0 +1,48 @@
/*-
* Copyright (c) 2012 Department of Software Engineering,
* University of Szeged, Hungary
* Copyright (c) 2012 Tamas Toth <ttoth@inf.u-szeged.hu>
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by the Department of Software Engineering, University of Szeged, Hungary
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef _CHFS_MAKEFS_H
#define _CHFS_MAKEFS_H
#define TYPE_NOR 0
#define TYPE_NAND 1
#define DEFAULT_PAGESIZE 2048
#define DEFAULT_ERASEBLOCK 131072
#define DEFAULT_MEDIATYPE TYPE_NAND
typedef struct {
int pagesize; /* page size */
int eraseblock; /* eraseblock size */
int mediatype; /* type of the media, 0 (nor) or 1 (nand) */
} chfs_opt_t;
#endif

1155
usr.sbin/makefs/ffs.c Normal file

File diff suppressed because it is too large Load diff

68
usr.sbin/makefs/ffs.h Normal file
View file

@ -0,0 +1,68 @@
/* $NetBSD: ffs.h,v 1.2 2011/10/09 21:33:43 christos Exp $ */
/*
* Copyright (c) 2001-2003 Wasabi Systems, Inc.
* All rights reserved.
*
* Written by Luke Mewburn for Wasabi Systems, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed for the NetBSD Project by
* Wasabi Systems, Inc.
* 4. The name of Wasabi Systems, Inc. may not be used to endorse
* or promote products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _FFS_H
#define _FFS_H
#include <ufs/ufs/dinode.h>
#include <ufs/ffs/fs.h>
typedef struct {
char label[MAXVOLLEN]; /* volume name/label */
int bsize; /* block size */
int fsize; /* fragment size */
int cpg; /* cylinders per group */
int cpgflg; /* cpg was specified by user */
int density; /* bytes per inode */
int ntracks; /* number of tracks */
int nsectors; /* number of sectors */
int rpm; /* rpm */
int minfree; /* free space threshold */
int optimization; /* optimization (space or time) */
int maxcontig; /* max contiguous blocks to allocate */
int rotdelay; /* rotational delay between blocks */
int maxbpg; /* maximum blocks per file in a cyl group */
int nrpos; /* # of distinguished rotational positions */
int avgfilesize; /* expected average file size */
int avgfpdir; /* expected # of files per directory */
int version; /* filesystem version (1 = FFS, 2 = UFS2) */
int maxbsize; /* maximum extent size */
int maxblkspercg; /* max # of blocks per cylinder group */
/* XXX: support `old' file systems ? */
} ffs_opt_t;
#endif /* _FFS_H */

View file

@ -0,0 +1,7 @@
# $NetBSD: Makefile.inc,v 1.1 2009/01/16 19:39:52 pooka Exp $
#
.PATH: ${.CURDIR}/ffs ${NETBSDSRCDIR}/sys/ufs/ffs
SRCS+= ffs_alloc.c ffs_balloc.c ffs_bswap.c ffs_subr.c ffs_tables.c ufs_bmap.c
SRCS+= buf.c mkfs.c

220
usr.sbin/makefs/ffs/buf.c Normal file
View file

@ -0,0 +1,220 @@
/* $NetBSD: buf.c,v 1.21 2013/02/03 03:21:21 christos Exp $ */
/*
* Copyright (c) 2001 Wasabi Systems, Inc.
* All rights reserved.
*
* Written by Luke Mewburn for Wasabi Systems, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed for the NetBSD Project by
* Wasabi Systems, Inc.
* 4. The name of Wasabi Systems, Inc. may not be used to endorse
* or promote products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#if HAVE_NBTOOL_CONFIG_H
#include "nbtool_config.h"
#endif
#include <sys/cdefs.h>
#if defined(__RCSID) && !defined(__lint)
__RCSID("$NetBSD: buf.c,v 1.21 2013/02/03 03:21:21 christos Exp $");
#endif /* !__lint */
#include <sys/param.h>
#include <sys/time.h>
#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <util.h>
#include "makefs.h"
#include "buf.h"
TAILQ_HEAD(buftailhead,buf) buftail;
int
bread(struct vnode *vp, daddr_t blkno, int size, struct kauth_cred *u1 __unused,
int u2 __unused, struct buf **bpp)
{
off_t offset;
ssize_t rv;
fsinfo_t *fs = vp->fs;
assert (bpp != NULL);
if (debug & DEBUG_BUF_BREAD)
printf("bread: blkno %lld size %d\n", (long long)blkno, size);
*bpp = getblk(vp, blkno, size, 0, 0);
offset = (*bpp)->b_blkno * fs->sectorsize + fs->offset;
if (debug & DEBUG_BUF_BREAD)
printf("bread: blkno %lld offset %lld bcount %ld\n",
(long long)(*bpp)->b_blkno, (long long) offset,
(*bpp)->b_bcount);
if (lseek((*bpp)->b_fs->fd, offset, SEEK_SET) == -1)
err(1, "%s: lseek %lld (%lld)", __func__,
(long long)(*bpp)->b_blkno, (long long)offset);
rv = read((*bpp)->b_fs->fd, (*bpp)->b_data, (*bpp)->b_bcount);
if (debug & DEBUG_BUF_BREAD)
printf("bread: read %ld (%lld) returned %zd\n",
(*bpp)->b_bcount, (long long)offset, rv);
if (rv == -1) /* read error */
err(1, "%s: read %ld (%lld) returned %zd", __func__,
(*bpp)->b_bcount, (long long)offset, rv);
else if (rv != (*bpp)->b_bcount) /* short read */
err(1, "%s: read %ld (%lld) returned %zd", __func__,
(*bpp)->b_bcount, (long long)offset, rv);
else
return (0);
}
void
brelse(struct buf *bp, int u1 __unused)
{
assert (bp != NULL);
assert (bp->b_data != NULL);
if (bp->b_lblkno < 0) {
/*
* XXX don't remove any buffers with negative logical block
* numbers (lblkno), so that we retain the mapping
* of negative lblkno -> real blkno that ffs_balloc()
* sets up.
*
* if we instead released these buffers, and implemented
* ufs_strategy() (and ufs_bmaparray()) and called those
* from bread() and bwrite() to convert the lblkno to
* a real blkno, we'd add a lot more code & complexity
* and reading off disk, for little gain, because this
* simple hack works for our purpose.
*/
bp->b_bcount = 0;
return;
}
TAILQ_REMOVE(&buftail, bp, b_tailq);
free(bp->b_data);
free(bp);
}
int
bwrite(struct buf *bp)
{
off_t offset;
ssize_t rv;
int bytes;
fsinfo_t *fs = bp->b_fs;
assert (bp != NULL);
offset = bp->b_blkno * fs->sectorsize + fs->offset;
bytes = bp->b_bcount;
if (debug & DEBUG_BUF_BWRITE)
printf("bwrite: blkno %lld offset %lld bcount %d\n",
(long long)bp->b_blkno, (long long) offset, bytes);
if (lseek(bp->b_fs->fd, offset, SEEK_SET) == -1)
return (errno);
rv = write(bp->b_fs->fd, bp->b_data, bytes);
if (debug & DEBUG_BUF_BWRITE)
printf("bwrite: write %ld (offset %lld) returned %lld\n",
bp->b_bcount, (long long)offset, (long long)rv);
brelse(bp, 0);
if (rv == bytes)
return (0);
else if (rv == -1) /* write error */
return (errno);
else /* short write ? */
return (EAGAIN);
}
void
bcleanup(void)
{
struct buf *bp;
/*
* XXX this really shouldn't be necessary, but i'm curious to
* know why there's still some buffers lying around that
* aren't brelse()d
*/
if (TAILQ_EMPTY(&buftail))
return;
printf("bcleanup: unflushed buffers:\n");
TAILQ_FOREACH(bp, &buftail, b_tailq) {
printf("\tlblkno %10lld blkno %10lld count %6ld bufsize %6ld\n",
(long long)bp->b_lblkno, (long long)bp->b_blkno,
bp->b_bcount, bp->b_bufsize);
}
printf("bcleanup: done\n");
}
struct buf *
getblk(struct vnode *vp, daddr_t blkno, int size, int u1 __unused,
int u2 __unused)
{
static int buftailinitted;
struct buf *bp;
void *n;
if (debug & DEBUG_BUF_GETBLK)
printf("getblk: blkno %lld size %d\n", (long long)blkno, size);
bp = NULL;
if (!buftailinitted) {
if (debug & DEBUG_BUF_GETBLK)
printf("getblk: initialising tailq\n");
TAILQ_INIT(&buftail);
buftailinitted = 1;
} else {
TAILQ_FOREACH(bp, &buftail, b_tailq) {
if (bp->b_lblkno != blkno)
continue;
break;
}
}
if (bp == NULL) {
bp = ecalloc(1, sizeof(*bp));
bp->b_bufsize = 0;
bp->b_blkno = bp->b_lblkno = blkno;
bp->b_fs = vp->fs;
bp->b_data = NULL;
TAILQ_INSERT_HEAD(&buftail, bp, b_tailq);
}
bp->b_bcount = size;
if (bp->b_data == NULL || bp->b_bcount > bp->b_bufsize) {
n = erealloc(bp->b_data, size);
memset(n, 0, size);
bp->b_data = n;
bp->b_bufsize = size;
}
return (bp);
}

117
usr.sbin/makefs/ffs/buf.h Normal file
View file

@ -0,0 +1,117 @@
/* $NetBSD: buf.h,v 1.9 2013/01/30 19:19:19 christos Exp $ */
/*
* Copyright (c) 2001 Wasabi Systems, Inc.
* All rights reserved.
*
* Written by Luke Mewburn for Wasabi Systems, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed for the NetBSD Project by
* Wasabi Systems, Inc.
* 4. The name of Wasabi Systems, Inc. may not be used to endorse
* or promote products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _FFS_BUF_H
#define _FFS_BUF_H
#include <sys/param.h>
#include <sys/queue.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#include <stddef.h>
#include <stdlib.h>
#include <err.h>
struct componentname {
char *cn_nameptr;
size_t cn_namelen;
};
struct makefs_fsinfo;
struct vnode {
struct makefs_fsinfo *fs;
void *v_data;
};
#define vput(a) ((void)(a))
struct buf {
void * b_data;
long b_bufsize;
long b_bcount;
daddr_t b_blkno;
daddr_t b_lblkno;
struct makefs_fsinfo * b_fs;
TAILQ_ENTRY(buf) b_tailq;
};
struct kauth_cred;
void bcleanup(void);
int bread(struct vnode *, daddr_t, int, struct kauth_cred *,
int, struct buf **);
void brelse(struct buf *, int);
int bwrite(struct buf *);
struct buf * getblk(struct vnode *, daddr_t, int, int, int);
#define bdwrite(bp) bwrite(bp)
#define clrbuf(bp) memset((bp)->b_data, 0, (u_int)(bp)->b_bcount)
#define B_MODIFY 0
#define BC_AGE 0
#define min(a, b) MIN((a), (b))
#define microtime(tv) gettimeofday((tv), NULL)
#define KASSERT(a)
#define IO_SYNC 1
struct pool {
size_t size;
};
#define pool_init(p, s, a1, a2, a3, a4, a5, a6) (p)->size = (s)
#define pool_get(p, f) ecalloc(1, (p)->size)
#define pool_put(p, a) free(a)
#define pool_destroy(p)
#define MALLOC_DECLARE(a)
#define malloc_type_attach(a)
#define malloc_type_detach(a)
#define mutex_enter(m)
#define mutex_exit(m)
#define mutex_init(m, t, i)
#define mutex_destroy(m)
#define desiredvnodes 10000
#define NOCRED NULL
#define DEV_BSHIFT 9
#endif /* _FFS_BUF_H */

View file

@ -0,0 +1,597 @@
/* $NetBSD: ffs_alloc.c,v 1.27 2013/06/23 22:03:34 dholland Exp $ */
/* From: NetBSD: ffs_alloc.c,v 1.50 2001/09/06 02:16:01 lukem Exp */
/*
* Copyright (c) 2002 Networks Associates Technology, Inc.
* All rights reserved.
*
* This software was developed for the FreeBSD Project by Marshall
* Kirk McKusick and Network Associates Laboratories, the Security
* Research Division of Network Associates, Inc. under DARPA/SPAWAR
* contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA CHATS
* research program
*
* Copyright (c) 1982, 1986, 1989, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)ffs_alloc.c 8.19 (Berkeley) 7/13/95
*/
#if HAVE_NBTOOL_CONFIG_H
#include "nbtool_config.h"
#endif
#include <sys/cdefs.h>
#if defined(__RCSID) && !defined(__lint)
__RCSID("$NetBSD: ffs_alloc.c,v 1.27 2013/06/23 22:03:34 dholland Exp $");
#endif /* !__lint */
#include <sys/param.h>
#include <sys/time.h>
#include <errno.h>
#include "makefs.h"
#include <ufs/ufs/dinode.h>
#include <ufs/ufs/ufs_bswap.h>
#include <ufs/ffs/fs.h>
#include "ffs/buf.h"
#include "ffs/ufs_inode.h"
#include "ffs/ffs_extern.h"
static int scanc(u_int, const u_char *, const u_char *, int);
static daddr_t ffs_alloccg(struct inode *, int, daddr_t, int);
static daddr_t ffs_alloccgblk(struct inode *, struct buf *, daddr_t);
static daddr_t ffs_hashalloc(struct inode *, int, daddr_t, int,
daddr_t (*)(struct inode *, int, daddr_t, int));
static int32_t ffs_mapsearch(struct fs *, struct cg *, daddr_t, int);
/* in ffs_tables.c */
extern const int inside[], around[];
extern const u_char * const fragtbl[];
/*
* Allocate a block in the file system.
*
* The size of the requested block is given, which must be some
* multiple of fs_fsize and <= fs_bsize.
* A preference may be optionally specified. If a preference is given
* the following hierarchy is used to allocate a block:
* 1) allocate the requested block.
* 2) allocate a rotationally optimal block in the same cylinder.
* 3) allocate a block in the same cylinder group.
* 4) quadradically rehash into other cylinder groups, until an
* available block is located.
* If no block preference is given the following hierarchy is used
* to allocate a block:
* 1) allocate a block in the cylinder group that contains the
* inode for the file.
* 2) quadradically rehash into other cylinder groups, until an
* available block is located.
*/
int
ffs_alloc(struct inode *ip, daddr_t lbn __unused, daddr_t bpref, int size,
daddr_t *bnp)
{
struct fs *fs = ip->i_fs;
daddr_t bno;
int cg;
*bnp = 0;
if (size > fs->fs_bsize || ffs_fragoff(fs, size) != 0) {
errx(1, "ffs_alloc: bad size: bsize %d size %d",
fs->fs_bsize, size);
}
if (size == fs->fs_bsize && fs->fs_cstotal.cs_nbfree == 0)
goto nospace;
if (bpref >= fs->fs_size)
bpref = 0;
if (bpref == 0)
cg = ino_to_cg(fs, ip->i_number);
else
cg = dtog(fs, bpref);
bno = ffs_hashalloc(ip, cg, bpref, size, ffs_alloccg);
if (bno > 0) {
DIP_ADD(ip, blocks, size / DEV_BSIZE);
*bnp = bno;
return (0);
}
nospace:
return (ENOSPC);
}
/*
* Select the desired position for the next block in a file. The file is
* logically divided into sections. The first section is composed of the
* direct blocks. Each additional section contains fs_maxbpg blocks.
*
* If no blocks have been allocated in the first section, the policy is to
* request a block in the same cylinder group as the inode that describes
* the file. If no blocks have been allocated in any other section, the
* policy is to place the section in a cylinder group with a greater than
* average number of free blocks. An appropriate cylinder group is found
* by using a rotor that sweeps the cylinder groups. When a new group of
* blocks is needed, the sweep begins in the cylinder group following the
* cylinder group from which the previous allocation was made. The sweep
* continues until a cylinder group with greater than the average number
* of free blocks is found. If the allocation is for the first block in an
* indirect block, the information on the previous allocation is unavailable;
* here a best guess is made based upon the logical block number being
* allocated.
*
* If a section is already partially allocated, the policy is to
* contiguously allocate fs_maxcontig blocks. The end of one of these
* contiguous blocks and the beginning of the next is physically separated
* so that the disk head will be in transit between them for at least
* fs_rotdelay milliseconds. This is to allow time for the processor to
* schedule another I/O transfer.
*/
/* XXX ondisk32 */
daddr_t
ffs_blkpref_ufs1(struct inode *ip, daddr_t lbn, int indx, int32_t *bap)
{
struct fs *fs;
int cg;
int avgbfree, startcg;
fs = ip->i_fs;
if (indx % fs->fs_maxbpg == 0 || bap[indx - 1] == 0) {
if (lbn < UFS_NDADDR + FFS_NINDIR(fs)) {
cg = ino_to_cg(fs, ip->i_number);
return (fs->fs_fpg * cg + fs->fs_frag);
}
/*
* Find a cylinder with greater than average number of
* unused data blocks.
*/
if (indx == 0 || bap[indx - 1] == 0)
startcg =
ino_to_cg(fs, ip->i_number) + lbn / fs->fs_maxbpg;
else
startcg = dtog(fs,
ufs_rw32(bap[indx - 1], UFS_FSNEEDSWAP(fs)) + 1);
startcg %= fs->fs_ncg;
avgbfree = fs->fs_cstotal.cs_nbfree / fs->fs_ncg;
for (cg = startcg; cg < fs->fs_ncg; cg++)
if (fs->fs_cs(fs, cg).cs_nbfree >= avgbfree)
return (fs->fs_fpg * cg + fs->fs_frag);
for (cg = 0; cg <= startcg; cg++)
if (fs->fs_cs(fs, cg).cs_nbfree >= avgbfree)
return (fs->fs_fpg * cg + fs->fs_frag);
return (0);
}
/*
* We just always try to lay things out contiguously.
*/
return ufs_rw32(bap[indx - 1], UFS_FSNEEDSWAP(fs)) + fs->fs_frag;
}
daddr_t
ffs_blkpref_ufs2(struct inode *ip, daddr_t lbn, int indx, int64_t *bap)
{
struct fs *fs;
int cg;
int avgbfree, startcg;
fs = ip->i_fs;
if (indx % fs->fs_maxbpg == 0 || bap[indx - 1] == 0) {
if (lbn < UFS_NDADDR + FFS_NINDIR(fs)) {
cg = ino_to_cg(fs, ip->i_number);
return (fs->fs_fpg * cg + fs->fs_frag);
}
/*
* Find a cylinder with greater than average number of
* unused data blocks.
*/
if (indx == 0 || bap[indx - 1] == 0)
startcg =
ino_to_cg(fs, ip->i_number) + lbn / fs->fs_maxbpg;
else
startcg = dtog(fs,
ufs_rw64(bap[indx - 1], UFS_FSNEEDSWAP(fs)) + 1);
startcg %= fs->fs_ncg;
avgbfree = fs->fs_cstotal.cs_nbfree / fs->fs_ncg;
for (cg = startcg; cg < fs->fs_ncg; cg++)
if (fs->fs_cs(fs, cg).cs_nbfree >= avgbfree) {
return (fs->fs_fpg * cg + fs->fs_frag);
}
for (cg = 0; cg < startcg; cg++)
if (fs->fs_cs(fs, cg).cs_nbfree >= avgbfree) {
return (fs->fs_fpg * cg + fs->fs_frag);
}
return (0);
}
/*
* We just always try to lay things out contiguously.
*/
return ufs_rw64(bap[indx - 1], UFS_FSNEEDSWAP(fs)) + fs->fs_frag;
}
/*
* Implement the cylinder overflow algorithm.
*
* The policy implemented by this algorithm is:
* 1) allocate the block in its requested cylinder group.
* 2) quadradically rehash on the cylinder group number.
* 3) brute force search for a free block.
*
* `size': size for data blocks, mode for inodes
*/
/*VARARGS5*/
static daddr_t
ffs_hashalloc(struct inode *ip, int cg, daddr_t pref, int size,
daddr_t (*allocator)(struct inode *, int, daddr_t, int))
{
struct fs *fs;
daddr_t result;
int i, icg = cg;
fs = ip->i_fs;
/*
* 1: preferred cylinder group
*/
result = (*allocator)(ip, cg, pref, size);
if (result)
return (result);
/*
* 2: quadratic rehash
*/
for (i = 1; i < fs->fs_ncg; i *= 2) {
cg += i;
if (cg >= fs->fs_ncg)
cg -= fs->fs_ncg;
result = (*allocator)(ip, cg, 0, size);
if (result)
return (result);
}
/*
* 3: brute force search
* Note that we start at i == 2, since 0 was checked initially,
* and 1 is always checked in the quadratic rehash.
*/
cg = (icg + 2) % fs->fs_ncg;
for (i = 2; i < fs->fs_ncg; i++) {
result = (*allocator)(ip, cg, 0, size);
if (result)
return (result);
cg++;
if (cg == fs->fs_ncg)
cg = 0;
}
return (0);
}
/*
* Determine whether a block can be allocated.
*
* Check to see if a block of the appropriate size is available,
* and if it is, allocate it.
*/
static daddr_t
ffs_alloccg(struct inode *ip, int cg, daddr_t bpref, int size)
{
struct cg *cgp;
struct buf *bp;
daddr_t bno, blkno;
int error, frags, allocsiz, i;
struct fs *fs = ip->i_fs;
const int needswap = UFS_FSNEEDSWAP(fs);
if (fs->fs_cs(fs, cg).cs_nbfree == 0 && size == fs->fs_bsize)
return (0);
error = bread(ip->i_devvp, FFS_FSBTODB(fs, cgtod(fs, cg)),
(int)fs->fs_cgsize, NULL, 0, &bp);
if (error) {
return (0);
}
cgp = (struct cg *)bp->b_data;
if (!cg_chkmagic(cgp, needswap) ||
(cgp->cg_cs.cs_nbfree == 0 && size == fs->fs_bsize)) {
brelse(bp, 0);
return (0);
}
if (size == fs->fs_bsize) {
bno = ffs_alloccgblk(ip, bp, bpref);
bwrite(bp);
return (bno);
}
/*
* check to see if any fragments are already available
* allocsiz is the size which will be allocated, hacking
* it down to a smaller size if necessary
*/
frags = ffs_numfrags(fs, size);
for (allocsiz = frags; allocsiz < fs->fs_frag; allocsiz++)
if (cgp->cg_frsum[allocsiz] != 0)
break;
if (allocsiz == fs->fs_frag) {
/*
* no fragments were available, so a block will be
* allocated, and hacked up
*/
if (cgp->cg_cs.cs_nbfree == 0) {
brelse(bp, 0);
return (0);
}
bno = ffs_alloccgblk(ip, bp, bpref);
bpref = dtogd(fs, bno);
for (i = frags; i < fs->fs_frag; i++)
setbit(cg_blksfree(cgp, needswap), bpref + i);
i = fs->fs_frag - frags;
ufs_add32(cgp->cg_cs.cs_nffree, i, needswap);
fs->fs_cstotal.cs_nffree += i;
fs->fs_cs(fs, cg).cs_nffree += i;
fs->fs_fmod = 1;
ufs_add32(cgp->cg_frsum[i], 1, needswap);
bdwrite(bp);
return (bno);
}
bno = ffs_mapsearch(fs, cgp, bpref, allocsiz);
for (i = 0; i < frags; i++)
clrbit(cg_blksfree(cgp, needswap), bno + i);
ufs_add32(cgp->cg_cs.cs_nffree, -frags, needswap);
fs->fs_cstotal.cs_nffree -= frags;
fs->fs_cs(fs, cg).cs_nffree -= frags;
fs->fs_fmod = 1;
ufs_add32(cgp->cg_frsum[allocsiz], -1, needswap);
if (frags != allocsiz)
ufs_add32(cgp->cg_frsum[allocsiz - frags], 1, needswap);
blkno = cg * fs->fs_fpg + bno;
bdwrite(bp);
return blkno;
}
/*
* Allocate a block in a cylinder group.
*
* This algorithm implements the following policy:
* 1) allocate the requested block.
* 2) allocate a rotationally optimal block in the same cylinder.
* 3) allocate the next available block on the block rotor for the
* specified cylinder group.
* Note that this routine only allocates fs_bsize blocks; these
* blocks may be fragmented by the routine that allocates them.
*/
static daddr_t
ffs_alloccgblk(struct inode *ip, struct buf *bp, daddr_t bpref)
{
struct cg *cgp;
daddr_t blkno;
int32_t bno;
struct fs *fs = ip->i_fs;
const int needswap = UFS_FSNEEDSWAP(fs);
u_int8_t *blksfree;
cgp = (struct cg *)bp->b_data;
blksfree = cg_blksfree(cgp, needswap);
if (bpref == 0 || dtog(fs, bpref) != ufs_rw32(cgp->cg_cgx, needswap)) {
bpref = ufs_rw32(cgp->cg_rotor, needswap);
} else {
bpref = ffs_blknum(fs, bpref);
bno = dtogd(fs, bpref);
/*
* if the requested block is available, use it
*/
if (ffs_isblock(fs, blksfree, ffs_fragstoblks(fs, bno)))
goto gotit;
}
/*
* Take the next available one in this cylinder group.
*/
bno = ffs_mapsearch(fs, cgp, bpref, (int)fs->fs_frag);
if (bno < 0)
return (0);
cgp->cg_rotor = ufs_rw32(bno, needswap);
gotit:
blkno = ffs_fragstoblks(fs, bno);
ffs_clrblock(fs, blksfree, (long)blkno);
ffs_clusteracct(fs, cgp, blkno, -1);
ufs_add32(cgp->cg_cs.cs_nbfree, -1, needswap);
fs->fs_cstotal.cs_nbfree--;
fs->fs_cs(fs, ufs_rw32(cgp->cg_cgx, needswap)).cs_nbfree--;
fs->fs_fmod = 1;
blkno = ufs_rw32(cgp->cg_cgx, needswap) * fs->fs_fpg + bno;
return (blkno);
}
/*
* Free a block or fragment.
*
* The specified block or fragment is placed back in the
* free map. If a fragment is deallocated, a possible
* block reassembly is checked.
*/
void
ffs_blkfree(struct inode *ip, daddr_t bno, long size)
{
struct cg *cgp;
struct buf *bp;
int32_t fragno, cgbno;
int i, error, cg, blk, frags, bbase;
struct fs *fs = ip->i_fs;
const int needswap = UFS_FSNEEDSWAP(fs);
if (size > fs->fs_bsize || ffs_fragoff(fs, size) != 0 ||
ffs_fragnum(fs, bno) + ffs_numfrags(fs, size) > fs->fs_frag) {
errx(1, "blkfree: bad size: bno %lld bsize %d size %ld",
(long long)bno, fs->fs_bsize, size);
}
cg = dtog(fs, bno);
if (bno >= fs->fs_size) {
warnx("bad block %lld, ino %llu", (long long)bno,
(unsigned long long)ip->i_number);
return;
}
error = bread(ip->i_devvp, FFS_FSBTODB(fs, cgtod(fs, cg)),
(int)fs->fs_cgsize, NULL, 0, &bp);
if (error) {
brelse(bp, 0);
return;
}
cgp = (struct cg *)bp->b_data;
if (!cg_chkmagic(cgp, needswap)) {
brelse(bp, 0);
return;
}
cgbno = dtogd(fs, bno);
if (size == fs->fs_bsize) {
fragno = ffs_fragstoblks(fs, cgbno);
if (!ffs_isfreeblock(fs, cg_blksfree(cgp, needswap), fragno)) {
errx(1, "blkfree: freeing free block %lld",
(long long)bno);
}
ffs_setblock(fs, cg_blksfree(cgp, needswap), fragno);
ffs_clusteracct(fs, cgp, fragno, 1);
ufs_add32(cgp->cg_cs.cs_nbfree, 1, needswap);
fs->fs_cstotal.cs_nbfree++;
fs->fs_cs(fs, cg).cs_nbfree++;
} else {
bbase = cgbno - ffs_fragnum(fs, cgbno);
/*
* decrement the counts associated with the old frags
*/
blk = blkmap(fs, cg_blksfree(cgp, needswap), bbase);
ffs_fragacct(fs, blk, cgp->cg_frsum, -1, needswap);
/*
* deallocate the fragment
*/
frags = ffs_numfrags(fs, size);
for (i = 0; i < frags; i++) {
if (isset(cg_blksfree(cgp, needswap), cgbno + i)) {
errx(1, "blkfree: freeing free frag: block %lld",
(long long)(cgbno + i));
}
setbit(cg_blksfree(cgp, needswap), cgbno + i);
}
ufs_add32(cgp->cg_cs.cs_nffree, i, needswap);
fs->fs_cstotal.cs_nffree += i;
fs->fs_cs(fs, cg).cs_nffree += i;
/*
* add back in counts associated with the new frags
*/
blk = blkmap(fs, cg_blksfree(cgp, needswap), bbase);
ffs_fragacct(fs, blk, cgp->cg_frsum, 1, needswap);
/*
* if a complete block has been reassembled, account for it
*/
fragno = ffs_fragstoblks(fs, bbase);
if (ffs_isblock(fs, cg_blksfree(cgp, needswap), fragno)) {
ufs_add32(cgp->cg_cs.cs_nffree, -fs->fs_frag, needswap);
fs->fs_cstotal.cs_nffree -= fs->fs_frag;
fs->fs_cs(fs, cg).cs_nffree -= fs->fs_frag;
ffs_clusteracct(fs, cgp, fragno, 1);
ufs_add32(cgp->cg_cs.cs_nbfree, 1, needswap);
fs->fs_cstotal.cs_nbfree++;
fs->fs_cs(fs, cg).cs_nbfree++;
}
}
fs->fs_fmod = 1;
bdwrite(bp);
}
static int
scanc(u_int size, const u_char *cp, const u_char table[], int mask)
{
const u_char *end = &cp[size];
while (cp < end && (table[*cp] & mask) == 0)
cp++;
return (end - cp);
}
/*
* Find a block of the specified size in the specified cylinder group.
*
* It is a panic if a request is made to find a block if none are
* available.
*/
static int32_t
ffs_mapsearch(struct fs *fs, struct cg *cgp, daddr_t bpref, int allocsiz)
{
int32_t bno;
int start, len, loc, i;
int blk, field, subfield, pos;
int ostart, olen;
const int needswap = UFS_FSNEEDSWAP(fs);
/*
* find the fragment by searching through the free block
* map for an appropriate bit pattern
*/
if (bpref)
start = dtogd(fs, bpref) / NBBY;
else
start = ufs_rw32(cgp->cg_frotor, needswap) / NBBY;
len = howmany(fs->fs_fpg, NBBY) - start;
ostart = start;
olen = len;
loc = scanc((u_int)len,
(const u_char *)&cg_blksfree(cgp, needswap)[start],
(const u_char *)fragtbl[fs->fs_frag],
(1 << (allocsiz - 1 + (fs->fs_frag % NBBY))));
if (loc == 0) {
len = start + 1;
start = 0;
loc = scanc((u_int)len,
(const u_char *)&cg_blksfree(cgp, needswap)[0],
(const u_char *)fragtbl[fs->fs_frag],
(1 << (allocsiz - 1 + (fs->fs_frag % NBBY))));
if (loc == 0) {
errx(1,
"ffs_alloccg: map corrupted: start %d len %d offset %d %ld",
ostart, olen,
ufs_rw32(cgp->cg_freeoff, needswap),
(long)cg_blksfree(cgp, needswap) - (long)cgp);
/* NOTREACHED */
}
}
bno = (start + len - loc) * NBBY;
cgp->cg_frotor = ufs_rw32(bno, needswap);
/*
* found the byte in the map
* sift through the bits to find the selected frag
*/
for (i = bno + NBBY; bno < i; bno += fs->fs_frag) {
blk = blkmap(fs, cg_blksfree(cgp, needswap), bno);
blk <<= 1;
field = around[allocsiz];
subfield = inside[allocsiz];
for (pos = 0; pos <= fs->fs_frag - allocsiz; pos++) {
if ((blk & field) == subfield)
return (bno + pos);
field <<= 1;
subfield <<= 1;
}
}
errx(1, "ffs_alloccg: block not in map: bno %lld", (long long)bno);
return (-1);
}

View file

@ -0,0 +1,584 @@
/* $NetBSD: ffs_balloc.c,v 1.20 2013/06/23 07:28:37 dholland Exp $ */
/* From NetBSD: ffs_balloc.c,v 1.25 2001/08/08 08:36:36 lukem Exp */
/*
* Copyright (c) 1982, 1986, 1989, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)ffs_balloc.c 8.8 (Berkeley) 6/16/95
*/
#if HAVE_NBTOOL_CONFIG_H
#include "nbtool_config.h"
#endif
#include <sys/cdefs.h>
#if defined(__RCSID) && !defined(__lint)
__RCSID("$NetBSD: ffs_balloc.c,v 1.20 2013/06/23 07:28:37 dholland Exp $");
#endif /* !__lint */
#include <sys/param.h>
#include <sys/time.h>
#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "makefs.h"
#include <ufs/ufs/dinode.h>
#include <ufs/ufs/ufs_bswap.h>
#include <ufs/ffs/fs.h>
#include "ffs/buf.h"
#include "ffs/ufs_inode.h"
#include "ffs/ffs_extern.h"
static int ffs_balloc_ufs1(struct inode *, off_t, int, struct buf **);
static int ffs_balloc_ufs2(struct inode *, off_t, int, struct buf **);
/*
* Balloc defines the structure of file system storage
* by allocating the physical blocks on a device given
* the inode and the logical block number in a file.
*
* Assume: flags == B_SYNC | B_CLRBUF
*/
int
ffs_balloc(struct inode *ip, off_t offset, int bufsize, struct buf **bpp)
{
if (ip->i_fs->fs_magic == FS_UFS2_MAGIC)
return ffs_balloc_ufs2(ip, offset, bufsize, bpp);
else
return ffs_balloc_ufs1(ip, offset, bufsize, bpp);
}
static int
ffs_balloc_ufs1(struct inode *ip, off_t offset, int bufsize, struct buf **bpp)
{
daddr_t lbn, lastlbn;
int size;
int32_t nb;
struct buf *bp, *nbp;
struct fs *fs = ip->i_fs;
struct indir indirs[UFS_NIADDR + 2];
daddr_t newb, pref;
int32_t *bap;
int osize, nsize, num, i, error;
int32_t *allocblk, allociblk[UFS_NIADDR + 1];
int32_t *allocib;
const int needswap = UFS_FSNEEDSWAP(fs);
lbn = ffs_lblkno(fs, offset);
size = ffs_blkoff(fs, offset) + bufsize;
if (bpp != NULL) {
*bpp = NULL;
}
assert(size <= fs->fs_bsize);
if (lbn < 0)
return (EFBIG);
/*
* If the next write will extend the file into a new block,
* and the file is currently composed of a fragment
* this fragment has to be extended to be a full block.
*/
lastlbn = ffs_lblkno(fs, ip->i_ffs1_size);
if (lastlbn < UFS_NDADDR && lastlbn < lbn) {
nb = lastlbn;
osize = ffs_blksize(fs, ip, nb);
if (osize < fs->fs_bsize && osize > 0) {
warnx("need to ffs_realloccg; not supported!");
abort();
}
}
/*
* The first UFS_NDADDR blocks are direct blocks
*/
if (lbn < UFS_NDADDR) {
nb = ufs_rw32(ip->i_ffs1_db[lbn], needswap);
if (nb != 0 && ip->i_ffs1_size >= ffs_lblktosize(fs, lbn + 1)) {
/*
* The block is an already-allocated direct block
* and the file already extends past this block,
* thus this must be a whole block.
* Just read the block (if requested).
*/
if (bpp != NULL) {
error = bread(ip->i_devvp, lbn, fs->fs_bsize,
NULL, 0, bpp);
if (error) {
brelse(*bpp, 0);
return (error);
}
}
return (0);
}
if (nb != 0) {
/*
* Consider need to reallocate a fragment.
*/
osize = ffs_fragroundup(fs, ffs_blkoff(fs, ip->i_ffs1_size));
nsize = ffs_fragroundup(fs, size);
if (nsize <= osize) {
/*
* The existing block is already
* at least as big as we want.
* Just read the block (if requested).
*/
if (bpp != NULL) {
error = bread(ip->i_devvp, lbn, osize,
NULL, 0, bpp);
if (error) {
brelse(*bpp, 0);
return (error);
}
}
return 0;
} else {
warnx("need to ffs_realloccg; not supported!");
abort();
}
} else {
/*
* the block was not previously allocated,
* allocate a new block or fragment.
*/
if (ip->i_ffs1_size < ffs_lblktosize(fs, lbn + 1))
nsize = ffs_fragroundup(fs, size);
else
nsize = fs->fs_bsize;
error = ffs_alloc(ip, lbn,
ffs_blkpref_ufs1(ip, lbn, (int)lbn,
&ip->i_ffs1_db[0]),
nsize, &newb);
if (error)
return (error);
if (bpp != NULL) {
bp = getblk(ip->i_devvp, lbn, nsize, 0, 0);
bp->b_blkno = FFS_FSBTODB(fs, newb);
clrbuf(bp);
*bpp = bp;
}
}
ip->i_ffs1_db[lbn] = ufs_rw32((int32_t)newb, needswap);
return (0);
}
/*
* Determine the number of levels of indirection.
*/
pref = 0;
if ((error = ufs_getlbns(ip, lbn, indirs, &num)) != 0)
return (error);
if (num < 1) {
warnx("ffs_balloc: ufs_getlbns returned indirect block");
abort();
}
/*
* Fetch the first indirect block allocating if necessary.
*/
--num;
nb = ufs_rw32(ip->i_ffs1_ib[indirs[0].in_off], needswap);
allocib = NULL;
allocblk = allociblk;
if (nb == 0) {
pref = ffs_blkpref_ufs1(ip, lbn, 0, (int32_t *)0);
error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb);
if (error)
return error;
nb = newb;
*allocblk++ = nb;
bp = getblk(ip->i_devvp, indirs[1].in_lbn, fs->fs_bsize, 0, 0);
bp->b_blkno = FFS_FSBTODB(fs, nb);
clrbuf(bp);
/*
* Write synchronously so that indirect blocks
* never point at garbage.
*/
if ((error = bwrite(bp)) != 0)
return error;
allocib = &ip->i_ffs1_ib[indirs[0].in_off];
*allocib = ufs_rw32((int32_t)nb, needswap);
}
/*
* Fetch through the indirect blocks, allocating as necessary.
*/
for (i = 1;;) {
error = bread(ip->i_devvp, indirs[i].in_lbn, fs->fs_bsize,
NULL, 0, &bp);
if (error) {
brelse(bp, 0);
return error;
}
bap = (int32_t *)bp->b_data;
nb = ufs_rw32(bap[indirs[i].in_off], needswap);
if (i == num)
break;
i++;
if (nb != 0) {
brelse(bp, 0);
continue;
}
if (pref == 0)
pref = ffs_blkpref_ufs1(ip, lbn, 0, (int32_t *)0);
error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb);
if (error) {
brelse(bp, 0);
return error;
}
nb = newb;
*allocblk++ = nb;
nbp = getblk(ip->i_devvp, indirs[i].in_lbn, fs->fs_bsize, 0, 0);
nbp->b_blkno = FFS_FSBTODB(fs, nb);
clrbuf(nbp);
/*
* Write synchronously so that indirect blocks
* never point at garbage.
*/
if ((error = bwrite(nbp)) != 0) {
brelse(bp, 0);
return error;
}
bap[indirs[i - 1].in_off] = ufs_rw32(nb, needswap);
bwrite(bp);
}
/*
* Get the data block, allocating if necessary.
*/
if (nb == 0) {
pref = ffs_blkpref_ufs1(ip, lbn, indirs[num].in_off, &bap[0]);
error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb);
if (error) {
brelse(bp, 0);
return error;
}
nb = newb;
*allocblk++ = nb;
if (bpp != NULL) {
nbp = getblk(ip->i_devvp, lbn, fs->fs_bsize, 0, 0);
nbp->b_blkno = FFS_FSBTODB(fs, nb);
clrbuf(nbp);
*bpp = nbp;
}
bap[indirs[num].in_off] = ufs_rw32(nb, needswap);
/*
* If required, write synchronously, otherwise use
* delayed write.
*/
bwrite(bp);
return (0);
}
brelse(bp, 0);
if (bpp != NULL) {
error = bread(ip->i_devvp, lbn, (int)fs->fs_bsize, NULL, 0,
&nbp);
if (error) {
brelse(nbp, 0);
return error;
}
*bpp = nbp;
}
return (0);
}
static int
ffs_balloc_ufs2(struct inode *ip, off_t offset, int bufsize, struct buf **bpp)
{
daddr_t lbn, lastlbn;
int size;
struct buf *bp, *nbp;
struct fs *fs = ip->i_fs;
struct indir indirs[UFS_NIADDR + 2];
daddr_t newb, pref, nb;
int64_t *bap;
int osize, nsize, num, i, error;
int64_t *allocblk, allociblk[UFS_NIADDR + 1];
int64_t *allocib;
const int needswap = UFS_FSNEEDSWAP(fs);
lbn = ffs_lblkno(fs, offset);
size = ffs_blkoff(fs, offset) + bufsize;
if (bpp != NULL) {
*bpp = NULL;
}
assert(size <= fs->fs_bsize);
if (lbn < 0)
return (EFBIG);
/*
* If the next write will extend the file into a new block,
* and the file is currently composed of a fragment
* this fragment has to be extended to be a full block.
*/
lastlbn = ffs_lblkno(fs, ip->i_ffs2_size);
if (lastlbn < UFS_NDADDR && lastlbn < lbn) {
nb = lastlbn;
osize = ffs_blksize(fs, ip, nb);
if (osize < fs->fs_bsize && osize > 0) {
warnx("need to ffs_realloccg; not supported!");
abort();
}
}
/*
* The first UFS_NDADDR blocks are direct blocks
*/
if (lbn < UFS_NDADDR) {
nb = ufs_rw64(ip->i_ffs2_db[lbn], needswap);
if (nb != 0 && ip->i_ffs2_size >= ffs_lblktosize(fs, lbn + 1)) {
/*
* The block is an already-allocated direct block
* and the file already extends past this block,
* thus this must be a whole block.
* Just read the block (if requested).
*/
if (bpp != NULL) {
error = bread(ip->i_devvp, lbn, fs->fs_bsize,
NULL, 0, bpp);
if (error) {
brelse(*bpp, 0);
return (error);
}
}
return (0);
}
if (nb != 0) {
/*
* Consider need to reallocate a fragment.
*/
osize = ffs_fragroundup(fs, ffs_blkoff(fs, ip->i_ffs2_size));
nsize = ffs_fragroundup(fs, size);
if (nsize <= osize) {
/*
* The existing block is already
* at least as big as we want.
* Just read the block (if requested).
*/
if (bpp != NULL) {
error = bread(ip->i_devvp, lbn, osize,
NULL, 0, bpp);
if (error) {
brelse(*bpp, 0);
return (error);
}
}
return 0;
} else {
warnx("need to ffs_realloccg; not supported!");
abort();
}
} else {
/*
* the block was not previously allocated,
* allocate a new block or fragment.
*/
if (ip->i_ffs2_size < ffs_lblktosize(fs, lbn + 1))
nsize = ffs_fragroundup(fs, size);
else
nsize = fs->fs_bsize;
error = ffs_alloc(ip, lbn,
ffs_blkpref_ufs2(ip, lbn, (int)lbn,
&ip->i_ffs2_db[0]),
nsize, &newb);
if (error)
return (error);
if (bpp != NULL) {
bp = getblk(ip->i_devvp, lbn, nsize, 0, 0);
bp->b_blkno = FFS_FSBTODB(fs, newb);
clrbuf(bp);
*bpp = bp;
}
}
ip->i_ffs2_db[lbn] = ufs_rw64(newb, needswap);
return (0);
}
/*
* Determine the number of levels of indirection.
*/
pref = 0;
if ((error = ufs_getlbns(ip, lbn, indirs, &num)) != 0)
return (error);
if (num < 1) {
warnx("ffs_balloc: ufs_getlbns returned indirect block");
abort();
}
/*
* Fetch the first indirect block allocating if necessary.
*/
--num;
nb = ufs_rw64(ip->i_ffs2_ib[indirs[0].in_off], needswap);
allocib = NULL;
allocblk = allociblk;
if (nb == 0) {
pref = ffs_blkpref_ufs2(ip, lbn, 0, (int64_t *)0);
error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb);
if (error)
return error;
nb = newb;
*allocblk++ = nb;
bp = getblk(ip->i_devvp, indirs[1].in_lbn, fs->fs_bsize, 0, 0);
bp->b_blkno = FFS_FSBTODB(fs, nb);
clrbuf(bp);
/*
* Write synchronously so that indirect blocks
* never point at garbage.
*/
if ((error = bwrite(bp)) != 0)
return error;
allocib = &ip->i_ffs2_ib[indirs[0].in_off];
*allocib = ufs_rw64(nb, needswap);
}
/*
* Fetch through the indirect blocks, allocating as necessary.
*/
for (i = 1;;) {
error = bread(ip->i_devvp, indirs[i].in_lbn, fs->fs_bsize,
NULL, 0, &bp);
if (error) {
brelse(bp, 0);
return error;
}
bap = (int64_t *)bp->b_data;
nb = ufs_rw64(bap[indirs[i].in_off], needswap);
if (i == num)
break;
i++;
if (nb != 0) {
brelse(bp, 0);
continue;
}
if (pref == 0)
pref = ffs_blkpref_ufs2(ip, lbn, 0, (int64_t *)0);
error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb);
if (error) {
brelse(bp, 0);
return error;
}
nb = newb;
*allocblk++ = nb;
nbp = getblk(ip->i_devvp, indirs[i].in_lbn, fs->fs_bsize, 0, 0);
nbp->b_blkno = FFS_FSBTODB(fs, nb);
clrbuf(nbp);
/*
* Write synchronously so that indirect blocks
* never point at garbage.
*/
if ((error = bwrite(nbp)) != 0) {
brelse(bp, 0);
return error;
}
bap[indirs[i - 1].in_off] = ufs_rw64(nb, needswap);
bwrite(bp);
}
/*
* Get the data block, allocating if necessary.
*/
if (nb == 0) {
pref = ffs_blkpref_ufs2(ip, lbn, indirs[num].in_off, &bap[0]);
error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb);
if (error) {
brelse(bp, 0);
return error;
}
nb = newb;
*allocblk++ = nb;
if (bpp != NULL) {
nbp = getblk(ip->i_devvp, lbn, fs->fs_bsize, 0, 0);
nbp->b_blkno = FFS_FSBTODB(fs, nb);
clrbuf(nbp);
*bpp = nbp;
}
bap[indirs[num].in_off] = ufs_rw64(nb, needswap);
/*
* If required, write synchronously, otherwise use
* delayed write.
*/
bwrite(bp);
return (0);
}
brelse(bp, 0);
if (bpp != NULL) {
error = bread(ip->i_devvp, lbn, (int)fs->fs_bsize, NULL, 0,
&nbp);
if (error) {
brelse(nbp, 0);
return error;
}
*bpp = nbp;
}
return (0);
}

View file

@ -0,0 +1,76 @@
/* $NetBSD: ffs_extern.h,v 1.6 2003/08/07 11:25:33 agc Exp $ */
/* From: NetBSD: ffs_extern.h,v 1.19 2001/08/17 02:18:48 lukem Exp */
/*-
* Copyright (c) 1991, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)ffs_extern.h 8.6 (Berkeley) 3/30/95
*/
#include "ffs/buf.h"
/*
* Structure used to pass around logical block paths generated by
* ufs_getlbns and used by truncate and bmap code.
*/
struct indir {
daddr_t in_lbn; /* Logical block number. */
int in_off; /* Offset in buffer. */
int in_exists; /* Flag if the block exists. */
};
/* ffs.c */
void panic(const char *, ...)
__attribute__((__noreturn__,__format__(__printf__,1,2)));
/* ffs_alloc.c */
int ffs_alloc(struct inode *, daddr_t, daddr_t, int, daddr_t *);
daddr_t ffs_blkpref_ufs1(struct inode *, daddr_t, int, int32_t *);
daddr_t ffs_blkpref_ufs2(struct inode *, daddr_t, int, int64_t *);
void ffs_blkfree(struct inode *, daddr_t, long);
void ffs_clusteracct(struct fs *, struct cg *, int32_t, int);
/* ffs_balloc.c */
int ffs_balloc(struct inode *, off_t, int, struct buf **);
/* ffs_bswap.c */
void ffs_sb_swap(struct fs*, struct fs *);
void ffs_dinode1_swap(struct ufs1_dinode *, struct ufs1_dinode *);
void ffs_dinode2_swap(struct ufs2_dinode *, struct ufs2_dinode *);
void ffs_csum_swap(struct csum *, struct csum *, int);
void ffs_cg_swap(struct cg *, struct cg *, struct fs *);
/* ffs_subr.c */
void ffs_fragacct(struct fs *, int, int32_t[], int, int);
int ffs_isblock(struct fs *, u_char *, int32_t);
int ffs_isfreeblock(struct fs *, u_char *, int32_t);
void ffs_clrblock(struct fs *, u_char *, int32_t);
void ffs_setblock(struct fs *, u_char *, int32_t);
/* ufs_bmap.c */
int ufs_getlbns(struct inode *, daddr_t, struct indir *, int *);

Some files were not shown because too many files have changed in this diff Show more