Import makefs from NetBSD
Change-Id: I0ebcc9d0168df9d26cfb0af0fce2bc894ce688af
This commit is contained in:
parent
22ad44d6a9
commit
9f988b7934
122 changed files with 50035 additions and 3 deletions
|
@ -181,6 +181,9 @@
|
|||
./sbin/mkfs.mfs minix-sys
|
||||
./sbin/mknod 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/ping minix-sys
|
||||
./sbin/poweroff minix-sys
|
||||
|
@ -906,6 +909,12 @@
|
|||
./usr/include/fs minix-sys
|
||||
./usr/include/fs/puffs 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/fts.h minix-sys
|
||||
./usr/include/ftw.h minix-sys
|
||||
|
@ -5251,11 +5260,15 @@
|
|||
./usr/man/man8/link.8 minix-sys
|
||||
./usr/man/man8/loadramdisk.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/mknod.8 minix-sys
|
||||
./usr/man/man8/mtree.8 minix-sys
|
||||
./usr/man/man8/netconf.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/nologin.8 minix-sys
|
||||
./usr/man/man8/nonamed.8 minix-sys
|
||||
|
@ -5340,6 +5353,7 @@
|
|||
./usr/sbin/installboot_nbsd minix-sys
|
||||
./usr/sbin/kernel minix-sys
|
||||
./usr/sbin/link minix-sys
|
||||
./usr/sbin/makefs minix-sys
|
||||
./usr/sbin/mkfs.mfsv3 minix-sys
|
||||
./usr/sbin/mkproto minix-sys
|
||||
./usr/sbin/mtree minix-sys
|
||||
|
|
|
@ -15,7 +15,7 @@ SUBDIR= \
|
|||
shutdown \
|
||||
|
||||
# support for various file systems
|
||||
SUBDIR+= newfs_ext2fs fsck_ext2fs
|
||||
SUBDIR+= newfs_ext2fs fsck_ext2fs newfs_msdos newfs_udf newfs_v7fs
|
||||
.if !defined(__MINIX)
|
||||
SUBDIR+= newfs fsck_ffs fsdb dump restore clri tunefs resize_ffs
|
||||
SUBDIR+= newfs_lfs fsck_lfs dump_lfs resize_lfs
|
||||
|
|
89
sbin/mount/fattr.c
Normal file
89
sbin/mount/fattr.c
Normal 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
37
sbin/mount/mountprog.h
Normal 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
25
sbin/newfs_msdos/Makefile
Normal 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>
|
976
sbin/newfs_msdos/mkfs_msdos.c
Normal file
976
sbin/newfs_msdos/mkfs_msdos.c
Normal 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;
|
||||
}
|
71
sbin/newfs_msdos/mkfs_msdos.h
Normal file
71
sbin/newfs_msdos/mkfs_msdos.h
Normal 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 *);
|
241
sbin/newfs_msdos/newfs_msdos.8
Normal file
241
sbin/newfs_msdos/newfs_msdos.8
Normal 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 .
|
253
sbin/newfs_msdos/newfs_msdos.c
Normal file
253
sbin/newfs_msdos/newfs_msdos.c
Normal 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
17
sbin/newfs_udf/Makefile
Normal 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
191
sbin/newfs_udf/newfs_udf.8
Normal 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
896
sbin/newfs_udf/newfs_udf.c
Normal 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;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
67
sbin/newfs_udf/newfs_udf.h
Normal file
67
sbin/newfs_udf/newfs_udf.h
Normal 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
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
283
sbin/newfs_udf/udf_create.h
Normal 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
906
sbin/newfs_udf/udf_write.c
Normal 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;
|
||||
}
|
54
sbin/newfs_udf/udf_write.h
Normal file
54
sbin/newfs_udf/udf_write.h
Normal 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
161
sbin/newfs_udf/unicode.h
Normal 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
21
sbin/newfs_v7fs/Makefile
Normal 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
316
sbin/newfs_v7fs/main.c
Normal 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;
|
||||
}
|
130
sbin/newfs_v7fs/newfs_v7fs.8
Normal file
130
sbin/newfs_v7fs/newfs_v7fs.8
Normal 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
|
240
sbin/newfs_v7fs/newfs_v7fs.c
Normal file
240
sbin/newfs_v7fs/newfs_v7fs.c
Normal 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);
|
||||
}
|
48
sbin/newfs_v7fs/newfs_v7fs.h
Normal file
48
sbin/newfs_v7fs/newfs_v7fs.h
Normal 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_ */
|
|
@ -1,6 +1,6 @@
|
|||
# $NetBSD: Makefile,v 1.20 2011/06/27 11:52:24 uch Exp $
|
||||
|
||||
SUBDIR= cd9660 msdosfs \
|
||||
puffs
|
||||
puffs udf v7fs
|
||||
|
||||
.include <bsd.kinc.mk>
|
||||
|
|
7
sys/fs/udf/Makefile
Normal file
7
sys/fs/udf/Makefile
Normal 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
835
sys/fs/udf/ecma167-udf.h
Normal 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
16
sys/fs/udf/files.udf
Normal 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
426
sys/fs/udf/udf.h
Normal 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
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
76
sys/fs/udf/udf_bswap.h
Normal 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
70
sys/fs/udf/udf_mount.h
Normal 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
514
sys/fs/udf/udf_osta.c
Normal 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
44
sys/fs/udf/udf_osta.h
Normal 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
723
sys/fs/udf/udf_readwrite.c
Normal 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
669
sys/fs/udf/udf_rename.c
Normal 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,
|
||||
};
|
145
sys/fs/udf/udf_strat_bootstrap.c
Normal file
145
sys/fs/udf/udf_strat_bootstrap.c
Normal 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
|
||||
};
|
||||
|
||||
|
454
sys/fs/udf/udf_strat_direct.c
Normal file
454
sys/fs/udf/udf_strat_direct.c
Normal 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, §or, &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, §or, &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
1507
sys/fs/udf/udf_strat_rmw.c
Normal file
File diff suppressed because it is too large
Load diff
687
sys/fs/udf/udf_strat_sequential.c
Normal file
687
sys/fs/udf/udf_strat_sequential.c
Normal 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, §or, &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, §ornr, &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
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
229
sys/fs/udf/udf_subr.h
Normal 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
949
sys/fs/udf/udf_vfsops.c
Normal 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
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
7
sys/fs/v7fs/Makefile
Normal 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
22
sys/fs/v7fs/files.v7fs
Normal 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
180
sys/fs/v7fs/v7fs.h
Normal 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
40
sys/fs/v7fs/v7fs_args.h
Normal 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_ */
|
729
sys/fs/v7fs/v7fs_datablock.c
Normal file
729
sys/fs/v7fs/v7fs_datablock.c
Normal 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
|
52
sys/fs/v7fs/v7fs_datablock.h
Normal file
52
sys/fs/v7fs/v7fs_datablock.h
Normal 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
89
sys/fs/v7fs/v7fs_dirent.c
Normal 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
38
sys/fs/v7fs/v7fs_dirent.h
Normal 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
231
sys/fs/v7fs/v7fs_endian.c
Normal 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
52
sys/fs/v7fs/v7fs_endian.h
Normal 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
262
sys/fs/v7fs/v7fs_extern.c
Normal 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
116
sys/fs/v7fs/v7fs_extern.h
Normal 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
422
sys/fs/v7fs/v7fs_file.c
Normal 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
65
sys/fs/v7fs/v7fs_file.h
Normal 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_ */
|
344
sys/fs/v7fs/v7fs_file_util.c
Normal file
344
sys/fs/v7fs/v7fs_file_util.c
Normal 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
154
sys/fs/v7fs/v7fs_impl.h
Normal 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
301
sys/fs/v7fs/v7fs_inode.c
Normal 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
91
sys/fs/v7fs/v7fs_inode.h
Normal 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_ */
|
128
sys/fs/v7fs/v7fs_inode_util.c
Normal file
128
sys/fs/v7fs/v7fs_inode_util.c
Normal 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
141
sys/fs/v7fs/v7fs_io.c
Normal 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
241
sys/fs/v7fs/v7fs_io_kern.c
Normal 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
172
sys/fs/v7fs/v7fs_io_user.c
Normal 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;
|
||||
}
|
263
sys/fs/v7fs/v7fs_superblock.c
Normal file
263
sys/fs/v7fs/v7fs_superblock.c
Normal 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 */
|
||||
}
|
48
sys/fs/v7fs/v7fs_superblock.h
Normal file
48
sys/fs/v7fs/v7fs_superblock.h
Normal 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_ */
|
101
sys/fs/v7fs/v7fs_superblock_util.c
Normal file
101
sys/fs/v7fs/v7fs_superblock_util.c
Normal 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
617
sys/fs/v7fs/v7fs_vfsops.c
Normal 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
1328
sys/fs/v7fs/v7fs_vnops.c
Normal file
File diff suppressed because it is too large
Load diff
|
@ -15,7 +15,7 @@ SUBDIR= \
|
|||
\
|
||||
\
|
||||
link \
|
||||
\
|
||||
makefs \
|
||||
mtree \
|
||||
\
|
||||
\
|
||||
|
|
37
usr.sbin/makefs/Makefile
Normal file
37
usr.sbin/makefs/Makefile
Normal 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
129
usr.sbin/makefs/README
Normal 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
41
usr.sbin/makefs/TODO
Normal 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
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
357
usr.sbin/makefs/cd9660.h
Normal 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
|
15
usr.sbin/makefs/cd9660/Makefile.inc
Normal file
15
usr.sbin/makefs/cd9660/Makefile.inc
Normal 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
|
130
usr.sbin/makefs/cd9660/cd9660_archimedes.c
Normal file
130
usr.sbin/makefs/cd9660/cd9660_archimedes.c
Normal 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);
|
||||
}
|
48
usr.sbin/makefs/cd9660/cd9660_archimedes.h
Normal file
48
usr.sbin/makefs/cd9660/cd9660_archimedes.h
Normal 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 *);
|
203
usr.sbin/makefs/cd9660/cd9660_conversion.c
Normal file
203
usr.sbin/makefs/cd9660/cd9660_conversion.c
Normal 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);
|
||||
}
|
498
usr.sbin/makefs/cd9660/cd9660_debug.c
Normal file
498
usr.sbin/makefs/cd9660/cd9660_debug.c
Normal 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");
|
||||
}
|
||||
|
698
usr.sbin/makefs/cd9660/cd9660_eltorito.c
Normal file
698
usr.sbin/makefs/cd9660/cd9660_eltorito.c
Normal 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;
|
||||
}
|
162
usr.sbin/makefs/cd9660/cd9660_eltorito.h
Normal file
162
usr.sbin/makefs/cd9660/cd9660_eltorito.h
Normal 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_ */
|
||||
|
127
usr.sbin/makefs/cd9660/cd9660_strings.c
Normal file
127
usr.sbin/makefs/cd9660/cd9660_strings.c
Normal 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;
|
||||
}
|
509
usr.sbin/makefs/cd9660/cd9660_write.c
Normal file
509
usr.sbin/makefs/cd9660/cd9660_write.c
Normal 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");
|
||||
}
|
838
usr.sbin/makefs/cd9660/iso9660_rrip.c
Normal file
838
usr.sbin/makefs/cd9660/iso9660_rrip.c
Normal 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;
|
||||
}
|
290
usr.sbin/makefs/cd9660/iso9660_rrip.h
Normal file
290
usr.sbin/makefs/cd9660/iso9660_rrip.h
Normal 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
222
usr.sbin/makefs/chfs.c
Normal 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;
|
||||
}
|
||||
|
11
usr.sbin/makefs/chfs/Makefile.inc
Normal file
11
usr.sbin/makefs/chfs/Makefile.inc
Normal 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
|
307
usr.sbin/makefs/chfs/chfs_mkfs.c
Normal file
307
usr.sbin/makefs/chfs/chfs_mkfs.c
Normal 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);
|
||||
}
|
44
usr.sbin/makefs/chfs/chfs_mkfs.h
Normal file
44
usr.sbin/makefs/chfs/chfs_mkfs.h
Normal 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
|
||||
|
48
usr.sbin/makefs/chfs_makefs.h
Normal file
48
usr.sbin/makefs/chfs_makefs.h
Normal 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
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
68
usr.sbin/makefs/ffs.h
Normal 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 */
|
7
usr.sbin/makefs/ffs/Makefile.inc
Normal file
7
usr.sbin/makefs/ffs/Makefile.inc
Normal 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
220
usr.sbin/makefs/ffs/buf.c
Normal 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
117
usr.sbin/makefs/ffs/buf.h
Normal 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 */
|
597
usr.sbin/makefs/ffs/ffs_alloc.c
Normal file
597
usr.sbin/makefs/ffs/ffs_alloc.c
Normal 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);
|
||||
}
|
584
usr.sbin/makefs/ffs/ffs_balloc.c
Normal file
584
usr.sbin/makefs/ffs/ffs_balloc.c
Normal 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);
|
||||
}
|
76
usr.sbin/makefs/ffs/ffs_extern.h
Normal file
76
usr.sbin/makefs/ffs/ffs_extern.h
Normal 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
Loading…
Reference in a new issue