prepare makefs for import to base
This commit is contained in:
commit
b6842439df
22
Makefile
Normal file
22
Makefile
Normal file
@ -0,0 +1,22 @@
|
||||
# $FreeBSD$
|
||||
|
||||
PROG= makefs
|
||||
COMPAT_MTREE= getid.c misc.c spec.c
|
||||
COMPAT= fparseln.c getmode.c pack_dev.c pwcache.c stat_flags.c \
|
||||
strsuftoll.c vis.c
|
||||
SRCS= ffs.c makefs.c walk.c \
|
||||
buf.c ffs_alloc.c ffs_balloc.c mkfs.c ufs_bmap.c \
|
||||
ffs_bswap.c ffs_subr.c ffs_tables.c \
|
||||
${COMPAT} ${COMPAT_MTREE}
|
||||
MAN= makefs.8
|
||||
|
||||
CFLAGS+=-DHAVE_NBTOOL_CONFIG_H=1 -D_FILE_OFFSET_BITS=64
|
||||
CFLAGS+=-I.
|
||||
CFLAGS+=-Icompat -Icompat/mtree
|
||||
CFLAGS+=-Iffs -Isys -Isys/ufs
|
||||
|
||||
.PATH: compat compat/mtree ffs sys/ufs/ufs sys/ufs/ffs
|
||||
|
||||
WARNS?= 2
|
||||
|
||||
.include <bsd.prog.mk>
|
167
compat/compat_defs.h
Normal file
167
compat/compat_defs.h
Normal file
@ -0,0 +1,167 @@
|
||||
/* $NetBSD: compat_defs.h,v 1.43 2004/06/23 11:08:01 tron Exp $ */
|
||||
|
||||
#ifndef __NETBSD_COMPAT_DEFS_H__
|
||||
#define __NETBSD_COMPAT_DEFS_H__
|
||||
|
||||
/* Work around some complete brain damage. */
|
||||
|
||||
#undef _POSIX_SOURCE
|
||||
#undef _POSIX_C_SOURCE
|
||||
|
||||
/* System headers needed for (re)definitions below. */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/param.h>
|
||||
/* time.h needs to be pulled in first at least on netbsd w/o _NETBSD_SOURCE */
|
||||
#include <sys/time.h>
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <grp.h>
|
||||
#include <limits.h>
|
||||
#include <paths.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#if HAVE_SYS_CDEFS_H
|
||||
#include <sys/cdefs.h>
|
||||
#endif
|
||||
#if HAVE_SYS_SYSLIMITS_H
|
||||
#include <sys/syslimits.h>
|
||||
#endif
|
||||
#if HAVE_SYS_SYSMACROS_H
|
||||
/* major(), minor() on SVR4 */
|
||||
#include <sys/sysmacros.h>
|
||||
#endif
|
||||
#if HAVE_INTTYPES_H
|
||||
#include <inttypes.h>
|
||||
#endif
|
||||
#if HAVE_STDDEF_H
|
||||
#include <stddef.h>
|
||||
#endif
|
||||
|
||||
/* We don't include <pwd.h> here, so that "compat_pwd.h" works. */
|
||||
struct passwd;
|
||||
|
||||
/* Some things usually in BSD <sys/cdefs.h>. */
|
||||
#ifndef __RENAME
|
||||
#define __RENAME(x)
|
||||
#endif
|
||||
|
||||
/* Dirent support. */
|
||||
#include <dirent.h>
|
||||
#define NAMLEN(dirent) (strlen((dirent)->d_name))
|
||||
|
||||
#if !HAVE_FPARSELN || defined(__NetBSD__)
|
||||
# define FPARSELN_UNESCESC 0x01
|
||||
# define FPARSELN_UNESCCONT 0x02
|
||||
# define FPARSELN_UNESCCOMM 0x04
|
||||
# define FPARSELN_UNESCREST 0x08
|
||||
# define FPARSELN_UNESCALL 0x0f
|
||||
char *fparseln(FILE *, size_t *, size_t *, const char [3], int);
|
||||
#endif
|
||||
|
||||
#define __nbcompat_bswap16(x) ((((x) << 8) & 0xff00) | (((x) >> 8) & 0x00ff))
|
||||
|
||||
#define __nbcompat_bswap32(x) ((((x) << 24) & 0xff000000) | \
|
||||
(((x) << 8) & 0x00ff0000) | \
|
||||
(((x) >> 8) & 0x0000ff00) | \
|
||||
(((x) >> 24) & 0x000000ff))
|
||||
|
||||
#define __nbcompat_bswap64(x) (((u_int64_t)bswap32((x)) << 32) | \
|
||||
((u_int64_t)bswap32((x) >> 32)))
|
||||
|
||||
#if !HAVE_BSWAP16
|
||||
#ifdef bswap16
|
||||
#undef bswap16
|
||||
#endif
|
||||
#define bswap16(x) __nbcompat_bswap16(x)
|
||||
#endif
|
||||
#if !HAVE_BSWAP32
|
||||
#ifdef bswap32
|
||||
#undef bswap32
|
||||
#endif
|
||||
#define bswap32(x) __nbcompat_bswap32(x)
|
||||
#endif
|
||||
#if !HAVE_BSWAP64
|
||||
#ifdef bswap64
|
||||
#undef bswap64
|
||||
#endif
|
||||
#define bswap64(x) __nbcompat_bswap64(x)
|
||||
#endif
|
||||
|
||||
#if !HAVE_PWCACHE_USERDB
|
||||
int uid_from_user(const char *, uid_t *);
|
||||
int pwcache_userdb(int (*)(int), void (*)(void),
|
||||
struct passwd * (*)(const char *), struct passwd * (*)(uid_t));
|
||||
int gid_from_group(const char *, gid_t *);
|
||||
int pwcache_groupdb(int (*)(int), void (*)(void),
|
||||
struct group * (*)(const char *), struct group * (*)(gid_t));
|
||||
#endif
|
||||
/* Make them use our version */
|
||||
# define user_from_uid __nbcompat_user_from_uid
|
||||
/* Make them use our version */
|
||||
# define group_from_gid __nbcompat_group_from_gid
|
||||
#if HAVE_GROUP_FROM_GID
|
||||
const char *group_from_gid(gid_t, int);
|
||||
#endif
|
||||
|
||||
#if !HAVE_SETENV
|
||||
int setenv(const char *, const char *, int);
|
||||
#endif
|
||||
|
||||
#if !HAVE_STRSUFTOLL
|
||||
long long strsuftoll(const char *, const char *, long long, long long);
|
||||
long long strsuftollx(const char *, const char *,
|
||||
long long, long long, char *, size_t);
|
||||
#endif
|
||||
|
||||
#if !HAVE_USER_FROM_UID
|
||||
const char *user_from_uid(uid_t, int);
|
||||
#endif
|
||||
|
||||
#if !HAVE_GROUP_FROM_GID
|
||||
const char *group_from_gid(gid_t, int);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* getmode() and setmode() are always defined, as these function names
|
||||
* exist but with very different meanings on other OS's. The compat
|
||||
* versions here simply accept an octal mode number; the "u+x,g-w" type
|
||||
* of syntax is not accepted.
|
||||
*/
|
||||
|
||||
#define getmode __nbcompat_getmode
|
||||
#define setmode __nbcompat_setmode
|
||||
|
||||
mode_t getmode(const void *, mode_t);
|
||||
void *setmode(const char *);
|
||||
|
||||
/* Eliminate assertions embedded in binaries. */
|
||||
|
||||
#undef _DIAGASSERT
|
||||
#define _DIAGASSERT(x)
|
||||
|
||||
/* Various sources use this */
|
||||
#undef __RCSID
|
||||
#define __RCSID(x)
|
||||
#undef __SCCSID
|
||||
#define __SCCSID(x)
|
||||
#undef __COPYRIGHT
|
||||
#define __COPYRIGHT(x)
|
||||
#undef __KERNEL_RCSID
|
||||
#define __KERNEL_RCSID(x,y)
|
||||
|
||||
/* Heimdal expects this one. */
|
||||
|
||||
#undef RCSID
|
||||
#define RCSID(x)
|
||||
|
||||
#ifndef MAXFRAG
|
||||
#define MAXFRAG 8
|
||||
#endif
|
||||
|
||||
#endif /* !__NETBSD_COMPAT_DEFS_H__ */
|
248
compat/fparseln.c
Normal file
248
compat/fparseln.c
Normal file
@ -0,0 +1,248 @@
|
||||
/* $NetBSD: fparseln.c,v 1.5 2004/06/20 22:20:15 jmc Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1997 Christos Zoulas. 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 by Christos Zoulas.
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#if defined(LIBC_SCCS) && !defined(lint)
|
||||
__RCSID("$NetBSD: fparseln.c,v 1.5 2004/06/20 22:20:15 jmc Exp $");
|
||||
#endif /* LIBC_SCCS and not lint */
|
||||
|
||||
#include "namespace.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef __weak_alias
|
||||
__weak_alias(fparseln,_fparseln)
|
||||
#endif
|
||||
|
||||
#if ! HAVE_FPARSELN
|
||||
|
||||
#ifndef HAVE_NBTOOL_CONFIG_H
|
||||
#include "reentrant.h"
|
||||
#include "local.h"
|
||||
#else
|
||||
#define FLOCKFILE(fp)
|
||||
#define FUNLOCKFILE(fp)
|
||||
#endif
|
||||
|
||||
#if defined(_REENTRANT) && !HAVE_NBTOOL_CONFIG_H
|
||||
#define __fgetln(f, l) __fgetstr(f, l, '\n')
|
||||
#else
|
||||
#define __fgetln(f, l) fgetln(f, l)
|
||||
#endif
|
||||
|
||||
static int isescaped(const char *, const char *, int);
|
||||
|
||||
/* isescaped():
|
||||
* Return true if the character in *p that belongs to a string
|
||||
* that starts in *sp, is escaped by the escape character esc.
|
||||
*/
|
||||
static int
|
||||
isescaped(const char *sp, const char *p, int esc)
|
||||
{
|
||||
const char *cp;
|
||||
size_t ne;
|
||||
|
||||
_DIAGASSERT(sp != NULL);
|
||||
_DIAGASSERT(p != NULL);
|
||||
|
||||
/* No escape character */
|
||||
if (esc == '\0')
|
||||
return 1;
|
||||
|
||||
/* Count the number of escape characters that precede ours */
|
||||
for (ne = 0, cp = p; --cp >= sp && *cp == esc; ne++)
|
||||
continue;
|
||||
|
||||
/* Return true if odd number of escape characters */
|
||||
return (ne & 1) != 0;
|
||||
}
|
||||
|
||||
|
||||
/* fparseln():
|
||||
* Read a line from a file parsing continuations ending in \
|
||||
* and eliminating trailing newlines, or comments starting with
|
||||
* the comment char.
|
||||
*/
|
||||
char *
|
||||
fparseln(FILE *fp, size_t *size, size_t *lineno, const char str[3], int flags)
|
||||
{
|
||||
static const char dstr[3] = { '\\', '\\', '#' };
|
||||
|
||||
size_t s, len;
|
||||
char *buf;
|
||||
char *ptr, *cp;
|
||||
int cnt;
|
||||
char esc, con, nl, com;
|
||||
|
||||
_DIAGASSERT(fp != NULL);
|
||||
|
||||
len = 0;
|
||||
buf = NULL;
|
||||
cnt = 1;
|
||||
|
||||
if (str == NULL)
|
||||
str = dstr;
|
||||
|
||||
esc = str[0];
|
||||
con = str[1];
|
||||
com = str[2];
|
||||
/*
|
||||
* XXX: it would be cool to be able to specify the newline character,
|
||||
* but unfortunately, fgetln does not let us
|
||||
*/
|
||||
nl = '\n';
|
||||
|
||||
FLOCKFILE(fp);
|
||||
|
||||
while (cnt) {
|
||||
cnt = 0;
|
||||
|
||||
if (lineno)
|
||||
(*lineno)++;
|
||||
|
||||
if ((ptr = __fgetln(fp, &s)) == NULL)
|
||||
break;
|
||||
|
||||
if (s && com) { /* Check and eliminate comments */
|
||||
for (cp = ptr; cp < ptr + s; cp++)
|
||||
if (*cp == com && !isescaped(ptr, cp, esc)) {
|
||||
s = cp - ptr;
|
||||
cnt = s == 0 && buf == NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (s && nl) { /* Check and eliminate newlines */
|
||||
cp = &ptr[s - 1];
|
||||
|
||||
if (*cp == nl)
|
||||
s--; /* forget newline */
|
||||
}
|
||||
|
||||
if (s && con) { /* Check and eliminate continuations */
|
||||
cp = &ptr[s - 1];
|
||||
|
||||
if (*cp == con && !isescaped(ptr, cp, esc)) {
|
||||
s--; /* forget escape */
|
||||
cnt = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (s == 0 && buf != NULL)
|
||||
continue;
|
||||
|
||||
if ((cp = realloc(buf, len + s + 1)) == NULL) {
|
||||
FUNLOCKFILE(fp);
|
||||
free(buf);
|
||||
return NULL;
|
||||
}
|
||||
buf = cp;
|
||||
|
||||
(void) memcpy(buf + len, ptr, s);
|
||||
len += s;
|
||||
buf[len] = '\0';
|
||||
}
|
||||
|
||||
FUNLOCKFILE(fp);
|
||||
|
||||
if ((flags & FPARSELN_UNESCALL) != 0 && esc && buf != NULL &&
|
||||
strchr(buf, esc) != NULL) {
|
||||
ptr = cp = buf;
|
||||
while (cp[0] != '\0') {
|
||||
int skipesc;
|
||||
|
||||
while (cp[0] != '\0' && cp[0] != esc)
|
||||
*ptr++ = *cp++;
|
||||
if (cp[0] == '\0' || cp[1] == '\0')
|
||||
break;
|
||||
|
||||
skipesc = 0;
|
||||
if (cp[1] == com)
|
||||
skipesc += (flags & FPARSELN_UNESCCOMM);
|
||||
if (cp[1] == con)
|
||||
skipesc += (flags & FPARSELN_UNESCCONT);
|
||||
if (cp[1] == esc)
|
||||
skipesc += (flags & FPARSELN_UNESCESC);
|
||||
if (cp[1] != com && cp[1] != con && cp[1] != esc)
|
||||
skipesc = (flags & FPARSELN_UNESCREST);
|
||||
|
||||
if (skipesc)
|
||||
cp++;
|
||||
else
|
||||
*ptr++ = *cp++;
|
||||
*ptr++ = *cp++;
|
||||
}
|
||||
*ptr = '\0';
|
||||
len = strlen(buf);
|
||||
}
|
||||
|
||||
if (size)
|
||||
*size = len;
|
||||
return buf;
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
|
||||
int main(int, char **);
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
char *ptr;
|
||||
size_t size, line;
|
||||
|
||||
line = 0;
|
||||
while ((ptr = fparseln(stdin, &size, &line, NULL,
|
||||
FPARSELN_UNESCALL)) != NULL)
|
||||
printf("line %d (%d) |%s|\n", line, size, ptr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
# This is a test
|
||||
line 1
|
||||
line 2 \
|
||||
line 3 # Comment
|
||||
line 4 \# Not comment \\\\
|
||||
|
||||
# And a comment \
|
||||
line 5 \\\
|
||||
line 6
|
||||
|
||||
*/
|
||||
|
||||
#endif /* TEST */
|
||||
#endif /* ! HAVE_FPARSELN */
|
63
compat/getmode.c
Normal file
63
compat/getmode.c
Normal file
@ -0,0 +1,63 @@
|
||||
/* $NetBSD: getmode.c,v 1.6 2004/01/13 00:53:06 simonb Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2001 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by Todd Vierling.
|
||||
*
|
||||
* 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 NetBSD
|
||||
* Foundation, Inc. and its contributors.
|
||||
* 4. 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 "nbtool_config.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
void *
|
||||
setmode(const char *str)
|
||||
{
|
||||
mode_t *mp = malloc(sizeof(mode_t));
|
||||
|
||||
*mp = strtoul(str, NULL, 8);
|
||||
|
||||
return mp;
|
||||
}
|
||||
|
||||
mode_t
|
||||
getmode(const void *mp, mode_t mode)
|
||||
{
|
||||
mode_t m;
|
||||
|
||||
m = *((const mode_t *)mp);
|
||||
|
||||
mode &= ~ALLPERMS; /* input mode less RWX permissions */
|
||||
m &= ALLPERMS; /* new RWX permissions */
|
||||
|
||||
return m | mode;
|
||||
}
|
0
compat/machine/bswap.h
Normal file
0
compat/machine/bswap.h
Normal file
81
compat/mtree/extern.h
Normal file
81
compat/mtree/extern.h
Normal file
@ -0,0 +1,81 @@
|
||||
/* $NetBSD: extern.h,v 1.28 2003/10/27 00:12:44 lukem Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1991, 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.
|
||||
*
|
||||
* @(#)extern.h 8.1 (Berkeley) 6/6/93
|
||||
*/
|
||||
|
||||
#include "mtree.h"
|
||||
|
||||
#if HAVE_NBTOOL_CONFIG_H
|
||||
#include "nbtool_config.h"
|
||||
#else
|
||||
#define HAVE_STRUCT_STAT_ST_FLAGS 1
|
||||
#endif
|
||||
|
||||
#include <err.h>
|
||||
#include <fts.h>
|
||||
|
||||
#if HAVE_NETDB_H
|
||||
/* For MAXHOSTNAMELEN on some platforms. */
|
||||
#include <netdb.h>
|
||||
#endif
|
||||
|
||||
#ifndef MAXHOSTNAMELEN
|
||||
#define MAXHOSTNAMELEN 256
|
||||
#endif
|
||||
|
||||
void addtag(slist_t *, char *);
|
||||
int check_excludes(const char *, const char *);
|
||||
int compare(NODE *, FTSENT *);
|
||||
int crc(int, u_int32_t *, u_int32_t *);
|
||||
void cwalk(void);
|
||||
void dump_nodes(const char *, NODE *, int);
|
||||
void init_excludes(void);
|
||||
int matchtags(NODE *);
|
||||
void mtree_err(const char *, ...)
|
||||
__attribute__((__format__(__printf__, 1, 2)));
|
||||
const char *nodetype(u_int);
|
||||
u_int parsekey(const char *, int *);
|
||||
void parsetags(slist_t *, char *);
|
||||
u_int parsetype(const char *);
|
||||
void read_excludes_file(const char *);
|
||||
const char *rlink(const char *);
|
||||
int verify(void);
|
||||
|
||||
extern int dflag, eflag, iflag, lflag, mflag, rflag, sflag, tflag, uflag;
|
||||
extern int Wflag;
|
||||
extern size_t mtree_lineno;
|
||||
extern u_int32_t crc_total;
|
||||
extern int ftsoptions, keys;
|
||||
extern char fullpath[];
|
||||
extern slist_t includetags, excludetags;
|
||||
|
||||
|
||||
#include "stat_flags.h"
|
435
compat/mtree/getid.c
Normal file
435
compat/mtree/getid.c
Normal file
@ -0,0 +1,435 @@
|
||||
/* $NetBSD: getid.c,v 1.5 2004/06/20 22:20:18 jmc Exp $ */
|
||||
/* from: NetBSD: getpwent.c,v 1.48 2000/10/03 03:22:26 enami Exp */
|
||||
/* from: NetBSD: getgrent.c,v 1.41 2002/01/12 23:51:30 lukem Exp */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1987, 1988, 1989, 1993, 1994, 1995
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2002 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by Luke Mewburn of Wasabi Systems.
|
||||
*
|
||||
* 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 NetBSD
|
||||
* Foundation, Inc. and its contributors.
|
||||
* 4. 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.
|
||||
*/
|
||||
|
||||
#if HAVE_NBTOOL_CONFIG_H
|
||||
#include "nbtool_config.h"
|
||||
#endif
|
||||
|
||||
#include <sys/param.h>
|
||||
|
||||
#include <grp.h>
|
||||
#include <limits.h>
|
||||
#include <pwd.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "extern.h"
|
||||
|
||||
static struct group * gi_getgrnam(const char *);
|
||||
static struct group * gi_getgrgid(gid_t);
|
||||
static int gi_setgroupent(int);
|
||||
static void gi_endgrent(void);
|
||||
static int grstart(void);
|
||||
static int grscan(int, gid_t, const char *);
|
||||
static int grmatchline(int, gid_t, const char *);
|
||||
|
||||
static struct passwd * gi_getpwnam(const char *);
|
||||
static struct passwd * gi_getpwuid(uid_t);
|
||||
static int gi_setpassent(int);
|
||||
static void gi_endpwent(void);
|
||||
static int pwstart(void);
|
||||
static int pwscan(int, uid_t, const char *);
|
||||
static int pwmatchline(int, uid_t, const char *);
|
||||
|
||||
#define MAXGRP 200
|
||||
#define MAXLINELENGTH 1024
|
||||
|
||||
static FILE *_gr_fp;
|
||||
static struct group _gr_group;
|
||||
static int _gr_stayopen;
|
||||
static int _gr_filesdone;
|
||||
static FILE *_pw_fp;
|
||||
static struct passwd _pw_passwd; /* password structure */
|
||||
static int _pw_stayopen; /* keep fd's open */
|
||||
static int _pw_filesdone;
|
||||
|
||||
static char grfile[MAXPATHLEN];
|
||||
static char pwfile[MAXPATHLEN];
|
||||
|
||||
static char *members[MAXGRP];
|
||||
static char grline[MAXLINELENGTH];
|
||||
static char pwline[MAXLINELENGTH];
|
||||
|
||||
int
|
||||
setup_getid(const char *dir)
|
||||
{
|
||||
if (dir == NULL)
|
||||
return (0);
|
||||
|
||||
/* close existing databases */
|
||||
gi_endgrent();
|
||||
gi_endpwent();
|
||||
|
||||
/* build paths to new databases */
|
||||
snprintf(grfile, sizeof(grfile), "%s/group", dir);
|
||||
snprintf(pwfile, sizeof(pwfile), "%s/master.passwd", dir);
|
||||
|
||||
/* try to open new databases */
|
||||
if (!grstart() || !pwstart())
|
||||
return (0);
|
||||
|
||||
/* switch pwcache(3) lookup functions */
|
||||
if (pwcache_groupdb(gi_setgroupent, gi_endgrent,
|
||||
gi_getgrnam, gi_getgrgid) == -1
|
||||
|| pwcache_userdb(gi_setpassent, gi_endpwent,
|
||||
gi_getpwnam, gi_getpwuid) == -1)
|
||||
return (0);
|
||||
|
||||
return (1);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* group lookup functions
|
||||
*/
|
||||
|
||||
static struct group *
|
||||
gi_getgrnam(const char *name)
|
||||
{
|
||||
int rval;
|
||||
|
||||
if (!grstart())
|
||||
return NULL;
|
||||
rval = grscan(1, 0, name);
|
||||
if (!_gr_stayopen)
|
||||
endgrent();
|
||||
return (rval) ? &_gr_group : NULL;
|
||||
}
|
||||
|
||||
static struct group *
|
||||
gi_getgrgid(gid_t gid)
|
||||
{
|
||||
int rval;
|
||||
|
||||
if (!grstart())
|
||||
return NULL;
|
||||
rval = grscan(1, gid, NULL);
|
||||
if (!_gr_stayopen)
|
||||
endgrent();
|
||||
return (rval) ? &_gr_group : NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
gi_setgroupent(int stayopen)
|
||||
{
|
||||
|
||||
if (!grstart())
|
||||
return 0;
|
||||
_gr_stayopen = stayopen;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
gi_endgrent(void)
|
||||
{
|
||||
|
||||
_gr_filesdone = 0;
|
||||
if (_gr_fp) {
|
||||
(void)fclose(_gr_fp);
|
||||
_gr_fp = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
grstart(void)
|
||||
{
|
||||
|
||||
_gr_filesdone = 0;
|
||||
if (_gr_fp) {
|
||||
rewind(_gr_fp);
|
||||
return 1;
|
||||
}
|
||||
if (grfile[0] == '\0') /* sanity check */
|
||||
return 0;
|
||||
return (_gr_fp = fopen(grfile, "r")) ? 1 : 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
grscan(int search, gid_t gid, const char *name)
|
||||
{
|
||||
|
||||
if (_gr_filesdone)
|
||||
return 0;
|
||||
for (;;) {
|
||||
if (!fgets(grline, sizeof(grline), _gr_fp)) {
|
||||
if (!search)
|
||||
_gr_filesdone = 1;
|
||||
return 0;
|
||||
}
|
||||
/* skip lines that are too big */
|
||||
if (!strchr(grline, '\n')) {
|
||||
int ch;
|
||||
|
||||
while ((ch = getc(_gr_fp)) != '\n' && ch != EOF)
|
||||
;
|
||||
continue;
|
||||
}
|
||||
if (grmatchline(search, gid, name))
|
||||
return 1;
|
||||
}
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
static int
|
||||
grmatchline(int search, gid_t gid, const char *name)
|
||||
{
|
||||
unsigned long id;
|
||||
char **m;
|
||||
char *cp, *bp, *ep;
|
||||
|
||||
/* name may be NULL if search is nonzero */
|
||||
|
||||
bp = grline;
|
||||
memset(&_gr_group, 0, sizeof(_gr_group));
|
||||
_gr_group.gr_name = strsep(&bp, ":\n");
|
||||
if (search && name && strcmp(_gr_group.gr_name, name))
|
||||
return 0;
|
||||
_gr_group.gr_passwd = strsep(&bp, ":\n");
|
||||
if (!(cp = strsep(&bp, ":\n")))
|
||||
return 0;
|
||||
id = strtoul(cp, &ep, 10);
|
||||
if (id > GID_MAX || *ep != '\0')
|
||||
return 0;
|
||||
_gr_group.gr_gid = (gid_t)id;
|
||||
if (search && name == NULL && _gr_group.gr_gid != gid)
|
||||
return 0;
|
||||
cp = NULL;
|
||||
if (bp == NULL)
|
||||
return 0;
|
||||
for (_gr_group.gr_mem = m = members;; bp++) {
|
||||
if (m == &members[MAXGRP - 1])
|
||||
break;
|
||||
if (*bp == ',') {
|
||||
if (cp) {
|
||||
*bp = '\0';
|
||||
*m++ = cp;
|
||||
cp = NULL;
|
||||
}
|
||||
} else if (*bp == '\0' || *bp == '\n' || *bp == ' ') {
|
||||
if (cp) {
|
||||
*bp = '\0';
|
||||
*m++ = cp;
|
||||
}
|
||||
break;
|
||||
} else if (cp == NULL)
|
||||
cp = bp;
|
||||
}
|
||||
*m = NULL;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* user lookup functions
|
||||
*/
|
||||
|
||||
static struct passwd *
|
||||
gi_getpwnam(const char *name)
|
||||
{
|
||||
int rval;
|
||||
|
||||
if (!pwstart())
|
||||
return NULL;
|
||||
rval = pwscan(1, 0, name);
|
||||
if (!_pw_stayopen)
|
||||
endpwent();
|
||||
return (rval) ? &_pw_passwd : NULL;
|
||||
}
|
||||
|
||||
static struct passwd *
|
||||
gi_getpwuid(uid_t uid)
|
||||
{
|
||||
int rval;
|
||||
|
||||
if (!pwstart())
|
||||
return NULL;
|
||||
rval = pwscan(1, uid, NULL);
|
||||
if (!_pw_stayopen)
|
||||
endpwent();
|
||||
return (rval) ? &_pw_passwd : NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
gi_setpassent(int stayopen)
|
||||
{
|
||||
|
||||
if (!pwstart())
|
||||
return 0;
|
||||
_pw_stayopen = stayopen;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
gi_endpwent(void)
|
||||
{
|
||||
|
||||
_pw_filesdone = 0;
|
||||
if (_pw_fp) {
|
||||
(void)fclose(_pw_fp);
|
||||
_pw_fp = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
pwstart(void)
|
||||
{
|
||||
|
||||
_pw_filesdone = 0;
|
||||
if (_pw_fp) {
|
||||
rewind(_pw_fp);
|
||||
return 1;
|
||||
}
|
||||
if (pwfile[0] == '\0') /* sanity check */
|
||||
return 0;
|
||||
return (_pw_fp = fopen(pwfile, "r")) ? 1 : 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
pwscan(int search, uid_t uid, const char *name)
|
||||
{
|
||||
|
||||
if (_pw_filesdone)
|
||||
return 0;
|
||||
for (;;) {
|
||||
if (!fgets(pwline, sizeof(pwline), _pw_fp)) {
|
||||
if (!search)
|
||||
_pw_filesdone = 1;
|
||||
return 0;
|
||||
}
|
||||
/* skip lines that are too big */
|
||||
if (!strchr(pwline, '\n')) {
|
||||
int ch;
|
||||
|
||||
while ((ch = getc(_pw_fp)) != '\n' && ch != EOF)
|
||||
;
|
||||
continue;
|
||||
}
|
||||
if (pwmatchline(search, uid, name))
|
||||
return 1;
|
||||
}
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
static int
|
||||
pwmatchline(int search, uid_t uid, const char *name)
|
||||
{
|
||||
unsigned long id;
|
||||
char *cp, *bp, *ep;
|
||||
|
||||
/* name may be NULL if search is nonzero */
|
||||
|
||||
bp = pwline;
|
||||
memset(&_pw_passwd, 0, sizeof(_pw_passwd));
|
||||
_pw_passwd.pw_name = strsep(&bp, ":\n"); /* name */
|
||||
if (search && name && strcmp(_pw_passwd.pw_name, name))
|
||||
return 0;
|
||||
|
||||
_pw_passwd.pw_passwd = strsep(&bp, ":\n"); /* passwd */
|
||||
|
||||
if (!(cp = strsep(&bp, ":\n"))) /* uid */
|
||||
return 0;
|
||||
id = strtoul(cp, &ep, 10);
|
||||
if (id > UID_MAX || *ep != '\0')
|
||||
return 0;
|
||||
_pw_passwd.pw_uid = (uid_t)id;
|
||||
if (search && name == NULL && _pw_passwd.pw_uid != uid)
|
||||
return 0;
|
||||
|
||||
if (!(cp = strsep(&bp, ":\n"))) /* gid */
|
||||
return 0;
|
||||
id = strtoul(cp, &ep, 10);
|
||||
if (id > GID_MAX || *ep != '\0')
|
||||
return 0;
|
||||
_pw_passwd.pw_gid = (gid_t)id;
|
||||
|
||||
if (!(ep = strsep(&bp, ":"))) /* class */
|
||||
return 0;
|
||||
if (!(ep = strsep(&bp, ":"))) /* change */
|
||||
return 0;
|
||||
if (!(ep = strsep(&bp, ":"))) /* expire */
|
||||
return 0;
|
||||
|
||||
if (!(_pw_passwd.pw_gecos = strsep(&bp, ":\n"))) /* gecos */
|
||||
return 0;
|
||||
if (!(_pw_passwd.pw_dir = strsep(&bp, ":\n"))) /* directory */
|
||||
return 0;
|
||||
if (!(_pw_passwd.pw_shell = strsep(&bp, ":\n"))) /* shell */
|
||||
return 0;
|
||||
|
||||
if (strchr(bp, ':') != NULL)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
295
compat/mtree/misc.c
Normal file
295
compat/mtree/misc.c
Normal file
@ -0,0 +1,295 @@
|
||||
/* $NetBSD: misc.c,v 1.25 2004/06/20 22:20:18 jmc Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1991, 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.
|
||||
*
|
||||
* @(#)misc.c 8.1 (Berkeley) 6/6/93
|
||||
*/
|
||||
|
||||
#if HAVE_NBTOOL_CONFIG_H
|
||||
#include "nbtool_config.h"
|
||||
#endif
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#if defined(__RCSID) && !defined(lint)
|
||||
__RCSID("$NetBSD: misc.c,v 1.25 2004/06/20 22:20:18 jmc Exp $");
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "extern.h"
|
||||
|
||||
typedef struct _key {
|
||||
const char *name; /* key name */
|
||||
u_int val; /* value */
|
||||
|
||||
#define NEEDVALUE 0x01
|
||||
u_int flags;
|
||||
} KEY;
|
||||
|
||||
/* NB: the following tables must be sorted lexically. */
|
||||
static KEY keylist[] = {
|
||||
{"cksum", F_CKSUM, NEEDVALUE},
|
||||
{"device", F_DEV, NEEDVALUE},
|
||||
{"flags", F_FLAGS, NEEDVALUE},
|
||||
{"gid", F_GID, NEEDVALUE},
|
||||
{"gname", F_GNAME, NEEDVALUE},
|
||||
{"ignore", F_IGN, 0},
|
||||
{"link", F_SLINK, NEEDVALUE},
|
||||
{"md5", F_MD5, NEEDVALUE},
|
||||
{"md5digest", F_MD5, NEEDVALUE},
|
||||
{"mode", F_MODE, NEEDVALUE},
|
||||
{"nlink", F_NLINK, NEEDVALUE},
|
||||
{"optional", F_OPT, 0},
|
||||
{"rmd160", F_RMD160, NEEDVALUE},
|
||||
{"rmd160digest",F_RMD160, NEEDVALUE},
|
||||
{"sha1", F_SHA1, NEEDVALUE},
|
||||
{"sha1digest", F_SHA1, NEEDVALUE},
|
||||
{"size", F_SIZE, NEEDVALUE},
|
||||
{"tags", F_TAGS, NEEDVALUE},
|
||||
{"time", F_TIME, NEEDVALUE},
|
||||
{"type", F_TYPE, NEEDVALUE},
|
||||
{"uid", F_UID, NEEDVALUE},
|
||||
{"uname", F_UNAME, NEEDVALUE}
|
||||
};
|
||||
|
||||
static KEY typelist[] = {
|
||||
{"block", F_BLOCK, },
|
||||
{"char", F_CHAR, },
|
||||
{"dir", F_DIR, },
|
||||
{"fifo", F_FIFO, },
|
||||
{"file", F_FILE, },
|
||||
{"link", F_LINK, },
|
||||
{"socket", F_SOCK, },
|
||||
};
|
||||
|
||||
slist_t excludetags, includetags;
|
||||
int keys = KEYDEFAULT;
|
||||
|
||||
|
||||
int keycompare(const void *, const void *);
|
||||
|
||||
u_int
|
||||
parsekey(const char *name, int *needvaluep)
|
||||
{
|
||||
static int allbits;
|
||||
KEY *k, tmp;
|
||||
|
||||
if (allbits == 0) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < sizeof(keylist) / sizeof(KEY); i++)
|
||||
allbits |= keylist[i].val;
|
||||
}
|
||||
tmp.name = name;
|
||||
if (strcmp(name, "all") == 0)
|
||||
return (allbits);
|
||||
k = (KEY *)bsearch(&tmp, keylist, sizeof(keylist) / sizeof(KEY),
|
||||
sizeof(KEY), keycompare);
|
||||
if (k == NULL)
|
||||
mtree_err("unknown keyword `%s'", name);
|
||||
|
||||
if (needvaluep)
|
||||
*needvaluep = k->flags & NEEDVALUE ? 1 : 0;
|
||||
|
||||
return (k->val);
|
||||
}
|
||||
|
||||
u_int
|
||||
parsetype(const char *name)
|
||||
{
|
||||
KEY *k, tmp;
|
||||
|
||||
tmp.name = name;
|
||||
k = (KEY *)bsearch(&tmp, typelist, sizeof(typelist) / sizeof(KEY),
|
||||
sizeof(KEY), keycompare);
|
||||
if (k == NULL)
|
||||
mtree_err("unknown file type `%s'", name);
|
||||
|
||||
return (k->val);
|
||||
}
|
||||
|
||||
int
|
||||
keycompare(const void *a, const void *b)
|
||||
{
|
||||
|
||||
return (strcmp(((const KEY *)a)->name, ((const KEY *)b)->name));
|
||||
}
|
||||
|
||||
void
|
||||
mtree_err(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
vwarnx(fmt, ap);
|
||||
va_end(ap);
|
||||
if (mtree_lineno)
|
||||
warnx("failed at line %lu of the specification",
|
||||
(u_long) mtree_lineno);
|
||||
exit(1);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
void
|
||||
addtag(slist_t *list, char *elem)
|
||||
{
|
||||
|
||||
#define TAG_CHUNK 20
|
||||
|
||||
if ((list->count % TAG_CHUNK) == 0) {
|
||||
char **new;
|
||||
|
||||
new = (char **)realloc(list->list, (list->count + TAG_CHUNK)
|
||||
* sizeof(char *));
|
||||
if (new == NULL)
|
||||
mtree_err("memory allocation error");
|
||||
list->list = new;
|
||||
}
|
||||
list->list[list->count] = elem;
|
||||
list->count++;
|
||||
}
|
||||
|
||||
void
|
||||
parsetags(slist_t *list, char *args)
|
||||
{
|
||||
char *p, *e;
|
||||
int len;
|
||||
|
||||
if (args == NULL) {
|
||||
addtag(list, NULL);
|
||||
return;
|
||||
}
|
||||
while ((p = strsep(&args, ",")) != NULL) {
|
||||
if (*p == '\0')
|
||||
continue;
|
||||
len = strlen(p) + 3; /* "," + p + ",\0" */
|
||||
if ((e = malloc(len)) == NULL)
|
||||
mtree_err("memory allocation error");
|
||||
snprintf(e, len, ",%s,", p);
|
||||
addtag(list, e);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* matchtags
|
||||
* returns 0 if there's a match from the exclude list in the node's tags,
|
||||
* or there's an include list and no match.
|
||||
* return 1 otherwise.
|
||||
*/
|
||||
int
|
||||
matchtags(NODE *node)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (node->tags) {
|
||||
for (i = 0; i < excludetags.count; i++)
|
||||
if (strstr(node->tags, excludetags.list[i]))
|
||||
break;
|
||||
if (i < excludetags.count)
|
||||
return (0);
|
||||
|
||||
for (i = 0; i < includetags.count; i++)
|
||||
if (strstr(node->tags, includetags.list[i]))
|
||||
break;
|
||||
if (i > 0 && i == includetags.count)
|
||||
return (0);
|
||||
} else if (includetags.count > 0) {
|
||||
return (0);
|
||||
}
|
||||
return (1);
|
||||
}
|
||||
|
||||
u_int
|
||||
nodetoino(u_int type)
|
||||
{
|
||||
|
||||
switch (type) {
|
||||
case F_BLOCK:
|
||||
return S_IFBLK;
|
||||
case F_CHAR:
|
||||
return S_IFCHR;
|
||||
case F_DIR:
|
||||
return S_IFDIR;
|
||||
case F_FIFO:
|
||||
return S_IFIFO;
|
||||
case F_FILE:
|
||||
return S_IFREG;
|
||||
case F_LINK:
|
||||
return S_IFLNK;
|
||||
#ifdef S_IFSOCK
|
||||
case F_SOCK:
|
||||
return S_IFSOCK;
|
||||
#endif
|
||||
default:
|
||||
printf("unknown type %d", type);
|
||||
abort();
|
||||
}
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
const char *
|
||||
nodetype(u_int type)
|
||||
{
|
||||
|
||||
return (inotype(nodetoino(type)));
|
||||
}
|
||||
|
||||
|
||||
const char *
|
||||
inotype(u_int type)
|
||||
{
|
||||
|
||||
switch (type & S_IFMT) {
|
||||
case S_IFBLK:
|
||||
return ("block");
|
||||
case S_IFCHR:
|
||||
return ("char");
|
||||
case S_IFDIR:
|
||||
return ("dir");
|
||||
case S_IFIFO:
|
||||
return ("fifo");
|
||||
case S_IFREG:
|
||||
return ("file");
|
||||
case S_IFLNK:
|
||||
return ("link");
|
||||
#ifdef S_IFSOCK
|
||||
case S_IFSOCK:
|
||||
return ("socket");
|
||||
#endif
|
||||
default:
|
||||
return ("unknown");
|
||||
}
|
||||
/* NOTREACHED */
|
||||
}
|
129
compat/mtree/mtree.h
Normal file
129
compat/mtree/mtree.h
Normal file
@ -0,0 +1,129 @@
|
||||
/* $NetBSD: mtree.h,v 1.21 2003/08/07 11:25:36 agc Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1990, 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.
|
||||
*
|
||||
* @(#)mtree.h 8.1 (Berkeley) 6/6/93
|
||||
*/
|
||||
|
||||
#ifndef _MTREE_H_
|
||||
#define _MTREE_H_
|
||||
|
||||
#define KEYDEFAULT (F_GID | F_MODE | F_NLINK | F_SIZE | F_SLINK | \
|
||||
F_TIME | F_TYPE | F_UID | F_FLAGS)
|
||||
|
||||
#define MISMATCHEXIT 2
|
||||
|
||||
typedef struct _node {
|
||||
struct _node *parent, *child; /* up, down */
|
||||
struct _node *prev, *next; /* left, right */
|
||||
off_t st_size; /* size */
|
||||
struct timespec st_mtimespec; /* last modification time */
|
||||
char *slink; /* symbolic link reference */
|
||||
uid_t st_uid; /* uid */
|
||||
gid_t st_gid; /* gid */
|
||||
#define MBITS (S_ISUID|S_ISGID|S_ISTXT|S_IRWXU|S_IRWXG|S_IRWXO)
|
||||
mode_t st_mode; /* mode */
|
||||
dev_t st_rdev; /* device type */
|
||||
u_long st_flags; /* flags */
|
||||
nlink_t st_nlink; /* link count */
|
||||
u_long cksum; /* check sum */
|
||||
char *md5digest; /* MD5 digest */
|
||||
char *rmd160digest; /* RMD-160 digest */
|
||||
char *sha1digest; /* SHA1 digest */
|
||||
char *tags; /* tags, comma delimited */
|
||||
size_t lineno; /* line # entry came from */
|
||||
|
||||
#define F_CKSUM 0x00000001 /* cksum(1) check sum */
|
||||
#define F_DEV 0x00000002 /* device type */
|
||||
#define F_DONE 0x00000004 /* directory done */
|
||||
#define F_FLAGS 0x00000008 /* file flags */
|
||||
#define F_GID 0x00000010 /* gid */
|
||||
#define F_GNAME 0x00000020 /* group name */
|
||||
#define F_IGN 0x00000040 /* ignore */
|
||||
#define F_MAGIC 0x00000080 /* name has magic chars */
|
||||
#define F_MD5 0x00000100 /* MD5 digest */
|
||||
#define F_MODE 0x00000200 /* mode */
|
||||
#define F_NLINK 0x00000400 /* number of links */
|
||||
#define F_OPT 0x00000800 /* existence optional */
|
||||
#define F_RMD160 0x00001000 /* RMD-160 digest */
|
||||
#define F_SHA1 0x00002000 /* SHA1 digest */
|
||||
#define F_SIZE 0x00004000 /* size */
|
||||
#define F_SLINK 0x00008000 /* symbolic link */
|
||||
#define F_TAGS 0x00010000 /* tags */
|
||||
#define F_TIME 0x00020000 /* modification time */
|
||||
#define F_TYPE 0x00040000 /* file type */
|
||||
#define F_UID 0x00080000 /* uid */
|
||||
#define F_UNAME 0x00100000 /* user name */
|
||||
#define F_VISIT 0x00200000 /* file visited */
|
||||
|
||||
int flags; /* items set */
|
||||
|
||||
#define F_BLOCK 0x001 /* block special */
|
||||
#define F_CHAR 0x002 /* char special */
|
||||
#define F_DIR 0x004 /* directory */
|
||||
#define F_FIFO 0x008 /* fifo */
|
||||
#define F_FILE 0x010 /* regular file */
|
||||
#define F_LINK 0x020 /* symbolic link */
|
||||
#define F_SOCK 0x040 /* socket */
|
||||
int type; /* file type */
|
||||
|
||||
char name[1]; /* file name (must be last) */
|
||||
} NODE;
|
||||
|
||||
|
||||
typedef struct {
|
||||
char **list;
|
||||
int count;
|
||||
} slist_t;
|
||||
|
||||
|
||||
/*
|
||||
* prototypes for functions published to other programs which want to use
|
||||
* the specfile parser but don't want to pull in all of "extern.h"
|
||||
*/
|
||||
const char *inotype(u_int);
|
||||
u_int nodetoino(u_int);
|
||||
int setup_getid(const char *);
|
||||
NODE *spec(FILE *);
|
||||
char *vispath(const char *);
|
||||
|
||||
|
||||
#define RP(p) \
|
||||
((p)->fts_path[0] == '.' && (p)->fts_path[1] == '/' ? \
|
||||
(p)->fts_path + 2 : (p)->fts_path)
|
||||
|
||||
#define UF_MASK ((UF_NODUMP | UF_IMMUTABLE | \
|
||||
UF_APPEND | UF_OPAQUE) \
|
||||
& UF_SETTABLE) /* user settable flags */
|
||||
#define SF_MASK ((SF_ARCHIVED | SF_IMMUTABLE | \
|
||||
SF_APPEND) & SF_SETTABLE) /* root settable flags */
|
||||
#define CH_MASK (UF_MASK | SF_MASK) /* all settable flags */
|
||||
#define SP_FLGS (SF_IMMUTABLE | SF_APPEND) /* special flags */
|
||||
|
||||
#endif /* _MTREE_H_ */
|
593
compat/mtree/spec.c
Normal file
593
compat/mtree/spec.c
Normal file
@ -0,0 +1,593 @@
|
||||
/* $NetBSD: spec.c,v 1.56 2004/06/20 22:20:18 jmc Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 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.
|
||||
*/
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2001-2002 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by Luke Mewburn of Wasabi Systems.
|
||||
*
|
||||
* 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 NetBSD
|
||||
* Foundation, Inc. and its contributors.
|
||||
* 4. 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.
|
||||
*/
|
||||
|
||||
#if HAVE_NBTOOL_CONFIG_H
|
||||
#include "nbtool_config.h"
|
||||
#endif
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#if defined(__RCSID) && !defined(lint)
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)spec.c 8.2 (Berkeley) 4/28/95";
|
||||
#else
|
||||
__RCSID("$NetBSD: spec.c,v 1.56 2004/06/20 22:20:18 jmc Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <grp.h>
|
||||
#include <pwd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <vis.h>
|
||||
#include <util.h>
|
||||
|
||||
#include "extern.h"
|
||||
#include "pack_dev.h"
|
||||
|
||||
size_t mtree_lineno; /* Current spec line number */
|
||||
int Wflag; /* Don't "whack" permissions */
|
||||
|
||||
static dev_t parsedev(char *);
|
||||
static void replacenode(NODE *, NODE *);
|
||||
static void set(char *, NODE *);
|
||||
static void unset(char *, NODE *);
|
||||
|
||||
NODE *
|
||||
spec(FILE *fp)
|
||||
{
|
||||
NODE *centry, *last, *pathparent, *cur;
|
||||
char *p, *e, *next;
|
||||
NODE ginfo, *root;
|
||||
char *buf, *tname, *ntname;
|
||||
size_t tnamelen, plen;
|
||||
|
||||
root = NULL;
|
||||
centry = last = NULL;
|
||||
tname = NULL;
|
||||
tnamelen = 0;
|
||||
memset(&ginfo, 0, sizeof(ginfo));
|
||||
for (mtree_lineno = 0;
|
||||
(buf = fparseln(fp, NULL, &mtree_lineno, NULL,
|
||||
FPARSELN_UNESCCOMM | FPARSELN_UNESCCONT | FPARSELN_UNESCESC));
|
||||
free(buf)) {
|
||||
/* Skip leading whitespace. */
|
||||
for (p = buf; *p && isspace((unsigned char)*p); ++p)
|
||||
continue;
|
||||
|
||||
/* If nothing but whitespace, continue. */
|
||||
if (!*p)
|
||||
continue;
|
||||
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "line %lu: {%s}\n",
|
||||
(u_long)mtree_lineno, p);
|
||||
#endif
|
||||
/* Grab file name, "$", "set", or "unset". */
|
||||
next = buf;
|
||||
while ((p = strsep(&next, " \t")) != NULL && *p == '\0')
|
||||
continue;
|
||||
if (p == NULL)
|
||||
mtree_err("missing field");
|
||||
|
||||
if (p[0] == '/') {
|
||||
if (strcmp(p + 1, "set") == 0)
|
||||
set(next, &ginfo);
|
||||
else if (strcmp(p + 1, "unset") == 0)
|
||||
unset(next, &ginfo);
|
||||
else
|
||||
mtree_err("invalid specification `%s'", p);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcmp(p, "..") == 0) {
|
||||
/* Don't go up, if haven't gone down. */
|
||||
if (root == NULL)
|
||||
goto noparent;
|
||||
if (last->type != F_DIR || last->flags & F_DONE) {
|
||||
if (last == root)
|
||||
goto noparent;
|
||||
last = last->parent;
|
||||
}
|
||||
last->flags |= F_DONE;
|
||||
continue;
|
||||
|
||||
noparent: mtree_err("no parent node");
|
||||
}
|
||||
|
||||
plen = strlen(p) + 1;
|
||||
if (plen > tnamelen) {
|
||||
if ((ntname = realloc(tname, plen)) == NULL)
|
||||
mtree_err("realloc: %s", strerror(errno));
|
||||
tname = ntname;
|
||||
tnamelen = plen;
|
||||
}
|
||||
if (strunvis(tname, p) == -1)
|
||||
mtree_err("strunvis failed on `%s'", p);
|
||||
p = tname;
|
||||
|
||||
pathparent = NULL;
|
||||
if (strchr(p, '/') != NULL) {
|
||||
cur = root;
|
||||
for (; (e = strchr(p, '/')) != NULL; p = e+1) {
|
||||
if (p == e)
|
||||
continue; /* handle // */
|
||||
*e = '\0';
|
||||
if (strcmp(p, ".") != 0) {
|
||||
while (cur &&
|
||||
strcmp(cur->name, p) != 0) {
|
||||
cur = cur->next;
|
||||
}
|
||||
}
|
||||
if (cur == NULL || cur->type != F_DIR) {
|
||||
mtree_err("%s: %s", tname,
|
||||
strerror(ENOENT));
|
||||
}
|
||||
*e = '/';
|
||||
pathparent = cur;
|
||||
cur = cur->child;
|
||||
}
|
||||
if (*p == '\0')
|
||||
mtree_err("%s: empty leaf element", tname);
|
||||
}
|
||||
|
||||
if ((centry = calloc(1, sizeof(NODE) + strlen(p))) == NULL)
|
||||
mtree_err("%s", strerror(errno));
|
||||
*centry = ginfo;
|
||||
centry->lineno = mtree_lineno;
|
||||
strcpy(centry->name, p);
|
||||
#define MAGIC "?*["
|
||||
if (strpbrk(p, MAGIC))
|
||||
centry->flags |= F_MAGIC;
|
||||
set(next, centry);
|
||||
|
||||
if (root == NULL) {
|
||||
/*
|
||||
* empty tree
|
||||
*/
|
||||
if (strcmp(centry->name, ".") != 0 ||
|
||||
centry->type != F_DIR)
|
||||
mtree_err(
|
||||
"root node must be the directory `.'");
|
||||
last = root = centry;
|
||||
root->parent = root;
|
||||
} else if (pathparent != NULL) {
|
||||
/*
|
||||
* full path entry
|
||||
*/
|
||||
centry->parent = pathparent;
|
||||
cur = pathparent->child;
|
||||
if (cur == NULL) {
|
||||
pathparent->child = centry;
|
||||
last = centry;
|
||||
} else {
|
||||
for (; cur != NULL; cur = cur->next) {
|
||||
if (strcmp(cur->name, centry->name)
|
||||
== 0) {
|
||||
/* existing entry; replace */
|
||||
replacenode(cur, centry);
|
||||
break;
|
||||
}
|
||||
if (cur->next == NULL) {
|
||||
/* last entry; add new */
|
||||
cur->next = centry;
|
||||
centry->prev = cur;
|
||||
break;
|
||||
}
|
||||
}
|
||||
last = cur;
|
||||
while (last->next != NULL)
|
||||
last = last->next;
|
||||
}
|
||||
} else if (strcmp(centry->name, ".") == 0) {
|
||||
/*
|
||||
* duplicate "." entry; always replace
|
||||
*/
|
||||
replacenode(root, centry);
|
||||
} else if (last->type == F_DIR && !(last->flags & F_DONE)) {
|
||||
/*
|
||||
* new relative child
|
||||
* (no duplicate check)
|
||||
*/
|
||||
centry->parent = last;
|
||||
last = last->child = centry;
|
||||
} else {
|
||||
/*
|
||||
* relative entry, up one directory
|
||||
* (no duplicate check)
|
||||
*/
|
||||
centry->parent = last->parent;
|
||||
centry->prev = last;
|
||||
last = last->next = centry;
|
||||
}
|
||||
}
|
||||
return (root);
|
||||
}
|
||||
|
||||
/*
|
||||
* dump_nodes --
|
||||
* dump the NODEs from `cur', based in the directory `dir'.
|
||||
* if pathlast is none zero, print the path last, otherwise print
|
||||
* it first.
|
||||
*/
|
||||
void
|
||||
dump_nodes(const char *dir, NODE *root, int pathlast)
|
||||
{
|
||||
NODE *cur;
|
||||
char path[MAXPATHLEN];
|
||||
const char *name;
|
||||
|
||||
for (cur = root; cur != NULL; cur = cur->next) {
|
||||
if (cur->type != F_DIR && !matchtags(cur))
|
||||
continue;
|
||||
|
||||
if (snprintf(path, sizeof(path), "%s%s%s",
|
||||
dir, *dir ? "/" : "", cur->name)
|
||||
>= sizeof(path))
|
||||
mtree_err("Pathname too long.");
|
||||
|
||||
if (!pathlast)
|
||||
printf("%s ", vispath(path));
|
||||
|
||||
#define MATCHFLAG(f) ((keys & (f)) && (cur->flags & (f)))
|
||||
if (MATCHFLAG(F_TYPE))
|
||||
printf("type=%s ", nodetype(cur->type));
|
||||
if (MATCHFLAG(F_UID | F_UNAME)) {
|
||||
if (keys & F_UNAME &&
|
||||
(name = user_from_uid(cur->st_uid, 1)) != NULL)
|
||||
printf("uname=%s ", name);
|
||||
else
|
||||
printf("uid=%u ", cur->st_uid);
|
||||
}
|
||||
if (MATCHFLAG(F_GID | F_GNAME)) {
|
||||
if (keys & F_GNAME &&
|
||||
(name = group_from_gid(cur->st_gid, 1)) != NULL)
|
||||
printf("gname=%s ", name);
|
||||
else
|
||||
printf("gid=%u ", cur->st_gid);
|
||||
}
|
||||
if (MATCHFLAG(F_MODE))
|
||||
printf("mode=%#o ", cur->st_mode);
|
||||
if (MATCHFLAG(F_DEV) &&
|
||||
(cur->type == F_BLOCK || cur->type == F_CHAR))
|
||||
printf("device=%#x ", cur->st_rdev);
|
||||
if (MATCHFLAG(F_NLINK))
|
||||
printf("nlink=%d ", cur->st_nlink);
|
||||
if (MATCHFLAG(F_SLINK))
|
||||
printf("link=%s ", cur->slink);
|
||||
if (MATCHFLAG(F_SIZE))
|
||||
printf("size=%lld ", (long long)cur->st_size);
|
||||
if (MATCHFLAG(F_TIME))
|
||||
printf("time=%ld.%ld ", (long)cur->st_mtimespec.tv_sec,
|
||||
cur->st_mtimespec.tv_nsec);
|
||||
if (MATCHFLAG(F_CKSUM))
|
||||
printf("cksum=%lu ", cur->cksum);
|
||||
if (MATCHFLAG(F_MD5))
|
||||
printf("md5=%s ", cur->md5digest);
|
||||
if (MATCHFLAG(F_RMD160))
|
||||
printf("rmd160=%s ", cur->rmd160digest);
|
||||
if (MATCHFLAG(F_SHA1))
|
||||
printf("sha1=%s ", cur->sha1digest);
|
||||
if (MATCHFLAG(F_FLAGS))
|
||||
printf("flags=%s ",
|
||||
flags_to_string(cur->st_flags, "none"));
|
||||
if (MATCHFLAG(F_IGN))
|
||||
printf("ignore ");
|
||||
if (MATCHFLAG(F_OPT))
|
||||
printf("optional ");
|
||||
if (MATCHFLAG(F_TAGS))
|
||||
printf("tags=%s ", cur->tags);
|
||||
puts(pathlast ? vispath(path) : "");
|
||||
|
||||
if (cur->child)
|
||||
dump_nodes(path, cur->child, pathlast);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* vispath --
|
||||
* strsvis(3) encodes path, which must not be longer than MAXPATHLEN
|
||||
* characters long, and returns a pointer to a static buffer containing
|
||||
* the result.
|
||||
*/
|
||||
char *
|
||||
vispath(const char *path)
|
||||
{
|
||||
const char extra[] = { ' ', '\t', '\n', '\\', '#', '\0' };
|
||||
static char pathbuf[4*MAXPATHLEN + 1];
|
||||
|
||||
strsvis(pathbuf, path, VIS_CSTYLE, extra);
|
||||
return(pathbuf);
|
||||
}
|
||||
|
||||
|
||||
static dev_t
|
||||
parsedev(char *arg)
|
||||
{
|
||||
#define MAX_PACK_ARGS 3
|
||||
u_long numbers[MAX_PACK_ARGS];
|
||||
char *p, *ep, *dev;
|
||||
int argc;
|
||||
pack_t *pack;
|
||||
dev_t result;
|
||||
const char *error = NULL;
|
||||
|
||||
if ((dev = strchr(arg, ',')) != NULL) {
|
||||
*dev++='\0';
|
||||
if ((pack = pack_find(arg)) == NULL)
|
||||
mtree_err("unknown format `%s'", arg);
|
||||
argc = 0;
|
||||
while ((p = strsep(&dev, ",")) != NULL) {
|
||||
if (*p == '\0')
|
||||
mtree_err("missing number");
|
||||
numbers[argc++] = strtoul(p, &ep, 0);
|
||||
if (*ep != '\0')
|
||||
mtree_err("invalid number `%s'",
|
||||
p);
|
||||
if (argc > MAX_PACK_ARGS)
|
||||
mtree_err("too many arguments");
|
||||
}
|
||||
if (argc < 2)
|
||||
mtree_err("not enough arguments");
|
||||
result = (*pack)(argc, numbers, &error);
|
||||
if (error != NULL)
|
||||
mtree_err(error);
|
||||
} else {
|
||||
result = (dev_t)strtoul(arg, &ep, 0);
|
||||
if (*ep != '\0')
|
||||
mtree_err("invalid device `%s'", arg);
|
||||
}
|
||||
return (result);
|
||||
}
|
||||
|
||||
static void
|
||||
replacenode(NODE *cur, NODE *new)
|
||||
{
|
||||
|
||||
if (cur->type != new->type)
|
||||
mtree_err("existing entry for `%s', type `%s' does not match type `%s'",
|
||||
cur->name, nodetype(cur->type), nodetype(new->type));
|
||||
#define REPLACE(x) cur->x = new->x
|
||||
#define REPLACESTR(x) if (cur->x) free(cur->x); cur->x = new->x
|
||||
|
||||
REPLACE(st_size);
|
||||
REPLACE(st_mtimespec);
|
||||
REPLACESTR(slink);
|
||||
REPLACE(st_uid);
|
||||
REPLACE(st_gid);
|
||||
REPLACE(st_mode);
|
||||
REPLACE(st_rdev);
|
||||
REPLACE(st_flags);
|
||||
REPLACE(st_nlink);
|
||||
REPLACE(cksum);
|
||||
REPLACESTR(md5digest);
|
||||
REPLACESTR(rmd160digest);
|
||||
REPLACESTR(sha1digest);
|
||||
REPLACESTR(tags);
|
||||
REPLACE(lineno);
|
||||
REPLACE(flags);
|
||||
free(new);
|
||||
}
|
||||
|
||||
static void
|
||||
set(char *t, NODE *ip)
|
||||
{
|
||||
int type, value, len;
|
||||
gid_t gid;
|
||||
uid_t uid;
|
||||
char *kw, *val, *md, *ep;
|
||||
void *m;
|
||||
|
||||
val = NULL;
|
||||
while ((kw = strsep(&t, "= \t")) != NULL) {
|
||||
if (*kw == '\0')
|
||||
continue;
|
||||
if (strcmp(kw, "all") == 0)
|
||||
mtree_err("invalid keyword `all'");
|
||||
ip->flags |= type = parsekey(kw, &value);
|
||||
if (value) {
|
||||
while ((val = strsep(&t, " \t")) != NULL &&
|
||||
*val == '\0')
|
||||
continue;
|
||||
if (val == NULL)
|
||||
mtree_err("missing value");
|
||||
}
|
||||
switch(type) {
|
||||
case F_CKSUM:
|
||||
ip->cksum = strtoul(val, &ep, 10);
|
||||
if (*ep)
|
||||
mtree_err("invalid checksum `%s'", val);
|
||||
break;
|
||||
case F_DEV:
|
||||
ip->st_rdev = parsedev(val);
|
||||
break;
|
||||
case F_FLAGS:
|
||||
if (strcmp("none", val) == 0)
|
||||
ip->st_flags = 0;
|
||||
else if (string_to_flags(&val, &ip->st_flags, NULL)
|
||||
!= 0)
|
||||
mtree_err("invalid flag `%s'", val);
|
||||
break;
|
||||
case F_GID:
|
||||
ip->st_gid = (gid_t)strtoul(val, &ep, 10);
|
||||
if (*ep)
|
||||
mtree_err("invalid gid `%s'", val);
|
||||
break;
|
||||
case F_GNAME:
|
||||
if (Wflag) /* don't parse if whacking */
|
||||
break;
|
||||
if (gid_from_group(val, &gid) == -1)
|
||||
mtree_err("unknown group `%s'", val);
|
||||
ip->st_gid = gid;
|
||||
break;
|
||||
case F_IGN:
|
||||
/* just set flag bit */
|
||||
break;
|
||||
case F_MD5:
|
||||
if (val[0]=='0' && val[1]=='x')
|
||||
md=&val[2];
|
||||
else
|
||||
md=val;
|
||||
if ((ip->md5digest = strdup(md)) == NULL)
|
||||
mtree_err("memory allocation error");
|
||||
break;
|
||||
case F_MODE:
|
||||
if ((m = setmode(val)) == NULL)
|
||||
mtree_err("invalid file mode `%s'", val);
|
||||
ip->st_mode = getmode(m, 0);
|
||||
free(m);
|
||||
break;
|
||||
case F_NLINK:
|
||||
ip->st_nlink = (nlink_t)strtoul(val, &ep, 10);
|
||||
if (*ep)
|
||||
mtree_err("invalid link count `%s'", val);
|
||||
break;
|
||||
case F_OPT:
|
||||
/* just set flag bit */
|
||||
break;
|
||||
case F_RMD160:
|
||||
if (val[0]=='0' && val[1]=='x')
|
||||
md=&val[2];
|
||||
else
|
||||
md=val;
|
||||
if ((ip->rmd160digest = strdup(md)) == NULL)
|
||||
mtree_err("memory allocation error");
|
||||
break;
|
||||
case F_SHA1:
|
||||
if (val[0]=='0' && val[1]=='x')
|
||||
md=&val[2];
|
||||
else
|
||||
md=val;
|
||||
if ((ip->sha1digest = strdup(md)) == NULL)
|
||||
mtree_err("memory allocation error");
|
||||
break;
|
||||
case F_SIZE:
|
||||
ip->st_size = (off_t)strtoll(val, &ep, 10);
|
||||
if (*ep)
|
||||
mtree_err("invalid size `%s'", val);
|
||||
break;
|
||||
case F_SLINK:
|
||||
if ((ip->slink = strdup(val)) == NULL)
|
||||
mtree_err("memory allocation error");
|
||||
break;
|
||||
case F_TAGS:
|
||||
len = strlen(val) + 3; /* "," + str + ",\0" */
|
||||
if ((ip->tags = malloc(len)) == NULL)
|
||||
mtree_err("memory allocation error");
|
||||
snprintf(ip->tags, len, ",%s,", val);
|
||||
break;
|
||||
case F_TIME:
|
||||
ip->st_mtimespec.tv_sec =
|
||||
(time_t)strtoul(val, &ep, 10);
|
||||
if (*ep != '.')
|
||||
mtree_err("invalid time `%s'", val);
|
||||
val = ep + 1;
|
||||
ip->st_mtimespec.tv_nsec = strtoul(val, &ep, 10);
|
||||
if (*ep)
|
||||
mtree_err("invalid time `%s'", val);
|
||||
break;
|
||||
case F_TYPE:
|
||||
ip->type = parsetype(val);
|
||||
break;
|
||||
case F_UID:
|
||||
ip->st_uid = (uid_t)strtoul(val, &ep, 10);
|
||||
if (*ep)
|
||||
mtree_err("invalid uid `%s'", val);
|
||||
break;
|
||||
case F_UNAME:
|
||||
if (Wflag) /* don't parse if whacking */
|
||||
break;
|
||||
if (uid_from_user(val, &uid) == -1)
|
||||
mtree_err("unknown user `%s'", val);
|
||||
ip->st_uid = uid;
|
||||
break;
|
||||
default:
|
||||
mtree_err(
|
||||
"set(): unsupported key type 0x%x (INTERNAL ERROR)",
|
||||
type);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
unset(char *t, NODE *ip)
|
||||
{
|
||||
char *p;
|
||||
|
||||
while ((p = strsep(&t, " \t")) != NULL) {
|
||||
if (*p == '\0')
|
||||
continue;
|
||||
ip->flags &= ~parsekey(p, NULL);
|
||||
}
|
||||
}
|
14
compat/namespace.h
Normal file
14
compat/namespace.h
Normal file
@ -0,0 +1,14 @@
|
||||
/* $NetBSD: namespace.h,v 1.3 2003/10/27 00:12:43 lukem Exp $ */
|
||||
|
||||
/*
|
||||
* Mainly empty header to make reachover bits of libc happy.
|
||||
*
|
||||
* Since all reachover bits will include this, it's a good place to pull
|
||||
* in nbtool_config.h.
|
||||
*/
|
||||
#include "nbtool_config.h"
|
||||
|
||||
/* No aliases in reachover-based libc sources. */
|
||||
#undef __indr_reference
|
||||
#undef __weak_alias
|
||||
#undef __warn_references
|
137
compat/nbtool_config.h
Normal file
137
compat/nbtool_config.h
Normal file
@ -0,0 +1,137 @@
|
||||
/* nbtool_config.h. Generated automatically by configure. */
|
||||
/* $NetBSD: nbtool_config.h.in,v 1.4 2004/06/20 22:20:15 jmc Exp $ */
|
||||
|
||||
#ifndef __NETBSD_NBTOOL_CONFIG_H__
|
||||
#define __NETBSD_NBTOOL_CONFIG_H__
|
||||
|
||||
/* Values set by "configure" based on available functions in the host. */
|
||||
|
||||
#define PATH_BSHELL "/bin/sh"
|
||||
|
||||
/* #undef HAVE_ALLOCA_H */
|
||||
#define HAVE_DIRENT_H 1
|
||||
#define HAVE_ERR_H 1
|
||||
/* #undef HAVE_FEATURES_H */
|
||||
#define HAVE_GETOPT_H 1
|
||||
#define HAVE_INTTYPES_H 1
|
||||
#define HAVE_LIBGEN_H 1
|
||||
/* #undef HAVE_NDIR_H */
|
||||
#define HAVE_NETDB_H 1
|
||||
/* #undef HAVE_MACHINE_BSWAP_H */
|
||||
/* #undef HAVE_MALLOC_H */
|
||||
#define HAVE_SYS_POLL_H 1
|
||||
#define HAVE_STDDEF_H 1
|
||||
#define HAVE_STRING_H 1
|
||||
/* #undef HAVE_SYS_DIR_H */
|
||||
#define HAVE_SYS_ENDIAN_H 1
|
||||
/* #undef HAVE_SYS_NDIR_H */
|
||||
/* #undef HAVE_SYS_SYSLIMITS_H */
|
||||
/* #undef HAVE_SYS_SYSMACROS_H */
|
||||
#define HAVE_SYS_TYPES_H 1
|
||||
#define HAVE_TERMIOS_H 1
|
||||
#define HAVE_UNISTD_H 1
|
||||
#define STDC_HEADERS 1
|
||||
|
||||
#define HAVE_ID_T 1
|
||||
#define HAVE_SOCKLEN_T 1
|
||||
#define HAVE_LONG_LONG 1
|
||||
#define HAVE_U_LONG 1
|
||||
#define HAVE_U_CHAR 1
|
||||
#define HAVE_U_INT 1
|
||||
#define HAVE_U_SHORT 1
|
||||
#define HAVE_U_QUAD_T 1
|
||||
|
||||
/* #undef HAVE_BSWAP16 */
|
||||
/* #undef HAVE_BSWAP32 */
|
||||
/* #undef HAVE_BSWAP64 */
|
||||
/* #undef HAVE_HTOBE16 */
|
||||
/* #undef HAVE_HTOBE32 */
|
||||
/* #undef HAVE_HTOBE64 */
|
||||
/* #undef HAVE_HTOLE16 */
|
||||
/* #undef HAVE_HTOLE32 */
|
||||
/* #undef HAVE_HTOLE64 */
|
||||
/* #undef HAVE_BE16TOH */
|
||||
/* #undef HAVE_BE32TOH */
|
||||
/* #undef HAVE_BE64TOH */
|
||||
/* #undef HAVE_LE16TOH */
|
||||
/* #undef HAVE_LE32TOH */
|
||||
/* #undef HAVE_LE64TOH */
|
||||
|
||||
#define HAVE_DIR_DD_FD 1
|
||||
#define HAVE_STRUCT_DIRENT_D_NAMLEN 1
|
||||
#define HAVE_STRUCT_STAT_ST_FLAGS 1
|
||||
#define HAVE_STRUCT_STAT_ST_GEN 1
|
||||
#define HAVE_STRUCT_STAT_ST_BIRTHTIME 1
|
||||
/* #undef HAVE_STRUCT_STAT_ST_ATIM */
|
||||
/* #undef HAVE_STRUCT_STAT_ST_MTIMENSEC */
|
||||
#define HAVE_STRUCT_STATFS_F_IOSIZE 1
|
||||
|
||||
#define HAVE_DECL_OPTIND 1
|
||||
#define HAVE_DECL_OPTRESET 1
|
||||
#define HAVE_DECL_SYS_SIGNAME 1
|
||||
|
||||
#define HAVE_ASPRINTF 1
|
||||
/* #undef HAVE_ASNPRINTF */
|
||||
#define HAVE_BASENAME 1
|
||||
/* #undef HAVE_CGETNEXT */
|
||||
#define HAVE_DEVNAME 1
|
||||
/* #undef HAVE_DIRFD */
|
||||
#define HAVE_DIRNAME 1
|
||||
#define HAVE_FGETLN 1
|
||||
#define HAVE_FLOCK 1
|
||||
/* #undef HAVE_FPARSELN */
|
||||
#define HAVE_FUTIMES 1
|
||||
#define HAVE_GETOPT 1
|
||||
#define HAVE_GETOPT_LONG 1
|
||||
#define HAVE_GROUP_FROM_GID 1
|
||||
#define HAVE_ISBLANK 1
|
||||
#define HAVE_ISSETUGID 1
|
||||
#define HAVE_LCHFLAGS 1
|
||||
#define HAVE_LCHMOD 1
|
||||
#define HAVE_LCHOWN 1
|
||||
#define HAVE_LUTIMES 1
|
||||
#define HAVE_MKSTEMP 1
|
||||
#define HAVE_MKDTEMP 1
|
||||
#define HAVE_POLL 1
|
||||
#define HAVE_PREAD 1
|
||||
#define HAVE_PUTC_UNLOCKED 1
|
||||
/* #undef HAVE_PWCACHE_USERDB */
|
||||
#define HAVE_PWRITE 1
|
||||
#define HAVE_RANDOM 1
|
||||
#define HAVE_SETENV 1
|
||||
#define HAVE_SETGROUPENT 1
|
||||
#define HAVE_SETPASSENT 1
|
||||
#define HAVE_SETPROGNAME 1
|
||||
#define HAVE_SNPRINTF 1
|
||||
#define HAVE_STRLCAT 1
|
||||
#define HAVE_STRLCPY 1
|
||||
#define HAVE_STRSEP 1
|
||||
/* #undef HAVE_STRSUFTOULL */
|
||||
#define HAVE_STRTOLL 1
|
||||
#define HAVE_USER_FROM_UID 1
|
||||
#define HAVE_VASPRINTF 1
|
||||
/* #undef HAVE_VASNPRINTF */
|
||||
#define HAVE_VSNPRINTF 1
|
||||
|
||||
#define HAVE_DECL_SETGROUPENT 1
|
||||
#define HAVE_DECL_SETPASSENT 1
|
||||
|
||||
/* #undef WORDS_BIGENDIAN */
|
||||
|
||||
/* Typedefs that might be missing. */
|
||||
|
||||
/* #undef size_t */
|
||||
/* #undef uint8_t */
|
||||
/* #undef uint16_t */
|
||||
/* #undef uint32_t */
|
||||
/* #undef uint64_t */
|
||||
/* #undef u_int8_t */
|
||||
/* #undef u_int16_t */
|
||||
/* #undef u_int32_t */
|
||||
/* #undef u_int64_t */
|
||||
|
||||
/* Now pull in the compatibility definitions. */
|
||||
|
||||
#include "compat_defs.h"
|
||||
|
||||
#endif /* !__NETBSD_NBTOOL_CONFIG_H__ */
|
297
compat/pack_dev.c
Normal file
297
compat/pack_dev.c
Normal file
@ -0,0 +1,297 @@
|
||||
/* $NetBSD: pack_dev.c,v 1.8 2004/05/11 17:09:58 christos Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1998, 2001 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by Charles M. Hannum.
|
||||
*
|
||||
* 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 NetBSD
|
||||
* Foundation, Inc. and its contributors.
|
||||
* 4. 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.
|
||||
*/
|
||||
|
||||
#if HAVE_NBTOOL_CONFIG_H
|
||||
#include "nbtool_config.h"
|
||||
#endif
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#if !defined(lint)
|
||||
__RCSID("$NetBSD: pack_dev.c,v 1.8 2004/05/11 17:09:58 christos Exp $");
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "pack_dev.h"
|
||||
|
||||
static pack_t pack_netbsd;
|
||||
static pack_t pack_freebsd;
|
||||
static pack_t pack_8_8;
|
||||
static pack_t pack_12_20;
|
||||
static pack_t pack_14_18;
|
||||
static pack_t pack_8_24;
|
||||
static pack_t pack_bsdos;
|
||||
static int compare_format(const void *, const void *);
|
||||
|
||||
static const char iMajorError[] = "invalid major number";
|
||||
static const char iMinorError[] = "invalid minor number";
|
||||
static const char tooManyFields[] = "too many fields for format";
|
||||
|
||||
/* exported */
|
||||
portdev_t
|
||||
pack_native(int n, u_long numbers[], const char **error)
|
||||
{
|
||||
portdev_t dev = 0;
|
||||
|
||||
if (n == 2) {
|
||||
dev = makedev(numbers[0], numbers[1]);
|
||||
if (major(dev) != numbers[0])
|
||||
*error = iMajorError;
|
||||
else if (minor(dev) != numbers[1])
|
||||
*error = iMinorError;
|
||||
} else
|
||||
*error = tooManyFields;
|
||||
return (dev);
|
||||
}
|
||||
|
||||
|
||||
static portdev_t
|
||||
pack_netbsd(int n, u_long numbers[], const char **error)
|
||||
{
|
||||
portdev_t dev = 0;
|
||||
|
||||
if (n == 2) {
|
||||
dev = makedev_netbsd(numbers[0], numbers[1]);
|
||||
if (major_netbsd(dev) != numbers[0])
|
||||
*error = iMajorError;
|
||||
else if (minor_netbsd(dev) != numbers[1])
|
||||
*error = iMinorError;
|
||||
} else
|
||||
*error = tooManyFields;
|
||||
return (dev);
|
||||
}
|
||||
|
||||
|
||||
#define major_freebsd(x) ((int32_t)(((x) & 0x0000ff00) >> 8))
|
||||
#define minor_freebsd(x) ((int32_t)(((x) & 0xffff00ff) >> 0))
|
||||
#define makedev_freebsd(x,y) ((portdev_t)((((x) << 8) & 0x0000ff00) | \
|
||||
(((y) << 0) & 0xffff00ff)))
|
||||
|
||||
static portdev_t
|
||||
pack_freebsd(int n, u_long numbers[], const char **error)
|
||||
{
|
||||
portdev_t dev = 0;
|
||||
|
||||
if (n == 2) {
|
||||
dev = makedev_freebsd(numbers[0], numbers[1]);
|
||||
if (major_freebsd(dev) != numbers[0])
|
||||
*error = iMajorError;
|
||||
if (minor_freebsd(dev) != numbers[1])
|
||||
*error = iMinorError;
|
||||
} else
|
||||
*error = tooManyFields;
|
||||
return (dev);
|
||||
}
|
||||
|
||||
|
||||
#define major_8_8(x) ((int32_t)(((x) & 0x0000ff00) >> 8))
|
||||
#define minor_8_8(x) ((int32_t)(((x) & 0x000000ff) >> 0))
|
||||
#define makedev_8_8(x,y) ((portdev_t)((((x) << 8) & 0x0000ff00) | \
|
||||
(((y) << 0) & 0x000000ff)))
|
||||
|
||||
static portdev_t
|
||||
pack_8_8(int n, u_long numbers[], const char **error)
|
||||
{
|
||||
portdev_t dev = 0;
|
||||
|
||||
if (n == 2) {
|
||||
dev = makedev_8_8(numbers[0], numbers[1]);
|
||||
if (major_8_8(dev) != numbers[0])
|
||||
*error = iMajorError;
|
||||
if (minor_8_8(dev) != numbers[1])
|
||||
*error = iMinorError;
|
||||
} else
|
||||
*error = tooManyFields;
|
||||
return (dev);
|
||||
}
|
||||
|
||||
|
||||
#define major_12_20(x) ((int32_t)(((x) & 0xfff00000) >> 20))
|
||||
#define minor_12_20(x) ((int32_t)(((x) & 0x000fffff) >> 0))
|
||||
#define makedev_12_20(x,y) ((portdev_t)((((x) << 20) & 0xfff00000) | \
|
||||
(((y) << 0) & 0x000fffff)))
|
||||
|
||||
static portdev_t
|
||||
pack_12_20(int n, u_long numbers[], const char **error)
|
||||
{
|
||||
portdev_t dev = 0;
|
||||
|
||||
if (n == 2) {
|
||||
dev = makedev_12_20(numbers[0], numbers[1]);
|
||||
if (major_12_20(dev) != numbers[0])
|
||||
*error = iMajorError;
|
||||
if (minor_12_20(dev) != numbers[1])
|
||||
*error = iMinorError;
|
||||
} else
|
||||
*error = tooManyFields;
|
||||
return (dev);
|
||||
}
|
||||
|
||||
|
||||
#define major_14_18(x) ((int32_t)(((x) & 0xfffc0000) >> 18))
|
||||
#define minor_14_18(x) ((int32_t)(((x) & 0x0003ffff) >> 0))
|
||||
#define makedev_14_18(x,y) ((portdev_t)((((x) << 18) & 0xfffc0000) | \
|
||||
(((y) << 0) & 0x0003ffff)))
|
||||
|
||||
static portdev_t
|
||||
pack_14_18(int n, u_long numbers[], const char **error)
|
||||
{
|
||||
portdev_t dev = 0;
|
||||
|
||||
if (n == 2) {
|
||||
dev = makedev_14_18(numbers[0], numbers[1]);
|
||||
if (major_14_18(dev) != numbers[0])
|
||||
*error = iMajorError;
|
||||
if (minor_14_18(dev) != numbers[1])
|
||||
*error = iMinorError;
|
||||
} else
|
||||
*error = tooManyFields;
|
||||
return (dev);
|
||||
}
|
||||
|
||||
|
||||
#define major_8_24(x) ((int32_t)(((x) & 0xff000000) >> 24))
|
||||
#define minor_8_24(x) ((int32_t)(((x) & 0x00ffffff) >> 0))
|
||||
#define makedev_8_24(x,y) ((portdev_t)((((x) << 24) & 0xff000000) | \
|
||||
(((y) << 0) & 0x00ffffff)))
|
||||
|
||||
static portdev_t
|
||||
pack_8_24(int n, u_long numbers[], const char **error)
|
||||
{
|
||||
portdev_t dev = 0;
|
||||
|
||||
if (n == 2) {
|
||||
dev = makedev_8_24(numbers[0], numbers[1]);
|
||||
if (major_8_24(dev) != numbers[0])
|
||||
*error = iMajorError;
|
||||
if (minor_8_24(dev) != numbers[1])
|
||||
*error = iMinorError;
|
||||
} else
|
||||
*error = tooManyFields;
|
||||
return (dev);
|
||||
}
|
||||
|
||||
|
||||
#define major_12_12_8(x) ((int32_t)(((x) & 0xfff00000) >> 20))
|
||||
#define unit_12_12_8(x) ((int32_t)(((x) & 0x000fff00) >> 8))
|
||||
#define subunit_12_12_8(x) ((int32_t)(((x) & 0x000000ff) >> 0))
|
||||
#define makedev_12_12_8(x,y,z) ((portdev_t)((((x) << 20) & 0xfff00000) | \
|
||||
(((y) << 8) & 0x000fff00) | \
|
||||
(((z) << 0) & 0x000000ff)))
|
||||
|
||||
static portdev_t
|
||||
pack_bsdos(int n, u_long numbers[], const char **error)
|
||||
{
|
||||
portdev_t dev = 0;
|
||||
|
||||
if (n == 2) {
|
||||
dev = makedev_12_20(numbers[0], numbers[1]);
|
||||
if (major_12_20(dev) != numbers[0])
|
||||
*error = iMajorError;
|
||||
if (minor_12_20(dev) != numbers[1])
|
||||
*error = iMinorError;
|
||||
} else if (n == 3) {
|
||||
dev = makedev_12_12_8(numbers[0], numbers[1], numbers[2]);
|
||||
if (major_12_12_8(dev) != numbers[0])
|
||||
*error = iMajorError;
|
||||
if (unit_12_12_8(dev) != numbers[1])
|
||||
*error = "invalid unit number";
|
||||
if (subunit_12_12_8(dev) != numbers[2])
|
||||
*error = "invalid subunit number";
|
||||
} else
|
||||
*error = tooManyFields;
|
||||
return (dev);
|
||||
}
|
||||
|
||||
|
||||
/* list of formats and pack functions */
|
||||
/* this list must be sorted lexically */
|
||||
struct format {
|
||||
const char *name;
|
||||
pack_t *pack;
|
||||
} formats[] = {
|
||||
{"386bsd", pack_8_8},
|
||||
{"4bsd", pack_8_8},
|
||||
{"bsdos", pack_bsdos},
|
||||
{"freebsd", pack_freebsd},
|
||||
{"hpux", pack_8_24},
|
||||
{"isc", pack_8_8},
|
||||
{"linux", pack_8_8},
|
||||
{"native", pack_native},
|
||||
{"netbsd", pack_netbsd},
|
||||
{"osf1", pack_12_20},
|
||||
{"sco", pack_8_8},
|
||||
{"solaris", pack_14_18},
|
||||
{"sunos", pack_8_8},
|
||||
{"svr3", pack_8_8},
|
||||
{"svr4", pack_14_18},
|
||||
{"ultrix", pack_8_8},
|
||||
};
|
||||
|
||||
static int
|
||||
compare_format(const void *key, const void *element)
|
||||
{
|
||||
const char *name;
|
||||
const struct format *format;
|
||||
|
||||
name = key;
|
||||
format = element;
|
||||
|
||||
return (strcmp(name, format->name));
|
||||
}
|
||||
|
||||
|
||||
pack_t *
|
||||
pack_find(const char *name)
|
||||
{
|
||||
struct format *format;
|
||||
|
||||
format = bsearch(name, formats,
|
||||
sizeof(formats)/sizeof(formats[0]),
|
||||
sizeof(formats[0]), compare_format);
|
||||
if (format == 0)
|
||||
return (NULL);
|
||||
return (format->pack);
|
||||
}
|
59
compat/pack_dev.h
Normal file
59
compat/pack_dev.h
Normal file
@ -0,0 +1,59 @@
|
||||
/* $NetBSD: pack_dev.h,v 1.6 2004/05/11 17:09:58 christos Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1998, 2001 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by Charles M. Hannum.
|
||||
*
|
||||
* 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 NetBSD
|
||||
* Foundation, Inc. and its contributors.
|
||||
* 4. 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.
|
||||
*/
|
||||
|
||||
#ifndef _PACK_DEV_H
|
||||
#define _PACK_DEV_H
|
||||
|
||||
#ifdef __CYGWIN__
|
||||
typedef __dev32_t portdev_t;
|
||||
#else
|
||||
typedef dev_t portdev_t;
|
||||
#endif
|
||||
typedef portdev_t pack_t(int, u_long [], const char **);
|
||||
|
||||
pack_t *pack_find(const char *);
|
||||
pack_t pack_native;
|
||||
|
||||
#define major_netbsd(x) ((int32_t)((((x) & 0x000fff00) >> 8)))
|
||||
#define minor_netbsd(x) ((int32_t)((((x) & 0xfff00000) >> 12) | \
|
||||
(((x) & 0x000000ff) >> 0)))
|
||||
#define makedev_netbsd(x,y) ((dev_t)((((x) << 8) & 0x000fff00) | \
|
||||
(((y) << 12) & 0xfff00000) | \
|
||||
(((y) << 0) & 0x000000ff)))
|
||||
|
||||
#endif /* _PACK_DEV_H */
|
651
compat/pwcache.c
Normal file
651
compat/pwcache.c
Normal file
@ -0,0 +1,651 @@
|
||||
/* $NetBSD: pwcache.c,v 1.29 2004/06/20 22:20:14 jmc Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1992 Keith Muller.
|
||||
* Copyright (c) 1992, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* Keith Muller of the University of California, San Diego.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2002 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.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the NetBSD
|
||||
* Foundation, Inc. and its contributors.
|
||||
* 4. 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.
|
||||
*/
|
||||
|
||||
#if HAVE_NBTOOL_CONFIG_H
|
||||
#include "nbtool_config.h"
|
||||
/*
|
||||
* XXX Undefine the renames of these functions so that we don't
|
||||
* XXX rename the versions found in the host's <pwd.h> by mistake!
|
||||
*/
|
||||
#undef group_from_gid
|
||||
#undef user_from_uid
|
||||
#endif
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#if defined(LIBC_SCCS) && !defined(lint)
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)cache.c 8.1 (Berkeley) 5/31/93";
|
||||
#else
|
||||
__RCSID("$NetBSD: pwcache.c,v 1.29 2004/06/20 22:20:14 jmc Exp $");
|
||||
#endif
|
||||
#endif /* LIBC_SCCS and not lint */
|
||||
|
||||
#include "namespace.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <grp.h>
|
||||
#include <pwd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#if HAVE_NBTOOL_CONFIG_H
|
||||
/* XXX Now, re-apply the renaming that we undid above. */
|
||||
#define group_from_gid __nbcompat_group_from_gid
|
||||
#define user_from_uid __nbcompat_user_from_uid
|
||||
#endif
|
||||
|
||||
#ifdef __weak_alias
|
||||
__weak_alias(user_from_uid,_user_from_uid)
|
||||
__weak_alias(group_from_gid,_group_from_gid)
|
||||
__weak_alias(pwcache_userdb,_pwcache_userdb)
|
||||
__weak_alias(pwcache_groupdb,_pwcache_groupdb)
|
||||
#endif
|
||||
|
||||
#if !HAVE_PWCACHE_USERDB || HAVE_NBTOOL_CONFIG_H
|
||||
#include "pwcache.h"
|
||||
|
||||
/*
|
||||
* routines that control user, group, uid and gid caches (for the archive
|
||||
* member print routine).
|
||||
* IMPORTANT:
|
||||
* these routines cache BOTH hits and misses, a major performance improvement
|
||||
*/
|
||||
|
||||
/*
|
||||
* function pointers to various name lookup routines.
|
||||
* these may be changed as necessary.
|
||||
*/
|
||||
static int (*_pwcache_setgroupent)(int) = setgroupent;
|
||||
static void (*_pwcache_endgrent)(void) = endgrent;
|
||||
static struct group * (*_pwcache_getgrnam)(const char *) = getgrnam;
|
||||
static struct group * (*_pwcache_getgrgid)(gid_t) = getgrgid;
|
||||
static int (*_pwcache_setpassent)(int) = setpassent;
|
||||
static void (*_pwcache_endpwent)(void) = endpwent;
|
||||
static struct passwd * (*_pwcache_getpwnam)(const char *) = getpwnam;
|
||||
static struct passwd * (*_pwcache_getpwuid)(uid_t) = getpwuid;
|
||||
|
||||
/*
|
||||
* internal state
|
||||
*/
|
||||
static int pwopn; /* is password file open */
|
||||
static int gropn; /* is group file open */
|
||||
static UIDC **uidtb; /* uid to name cache */
|
||||
static GIDC **gidtb; /* gid to name cache */
|
||||
static UIDC **usrtb; /* user name to uid cache */
|
||||
static GIDC **grptb; /* group name to gid cache */
|
||||
|
||||
static int uidtb_fail; /* uidtb_start() failed ? */
|
||||
static int gidtb_fail; /* gidtb_start() failed ? */
|
||||
static int usrtb_fail; /* usrtb_start() failed ? */
|
||||
static int grptb_fail; /* grptb_start() failed ? */
|
||||
|
||||
|
||||
static u_int st_hash(const char *, size_t, int);
|
||||
static int uidtb_start(void);
|
||||
static int gidtb_start(void);
|
||||
static int usrtb_start(void);
|
||||
static int grptb_start(void);
|
||||
|
||||
|
||||
static u_int
|
||||
st_hash(const char *name, size_t len, int tabsz)
|
||||
{
|
||||
u_int key = 0;
|
||||
|
||||
_DIAGASSERT(name != NULL);
|
||||
|
||||
while (len--) {
|
||||
key += *name++;
|
||||
key = (key << 8) | (key >> 24);
|
||||
}
|
||||
|
||||
return (key % tabsz);
|
||||
}
|
||||
|
||||
/*
|
||||
* uidtb_start
|
||||
* creates an an empty uidtb
|
||||
* Return:
|
||||
* 0 if ok, -1 otherwise
|
||||
*/
|
||||
static int
|
||||
uidtb_start(void)
|
||||
{
|
||||
|
||||
if (uidtb != NULL)
|
||||
return (0);
|
||||
if (uidtb_fail)
|
||||
return (-1);
|
||||
if ((uidtb = (UIDC **)calloc(UID_SZ, sizeof(UIDC *))) == NULL) {
|
||||
++uidtb_fail;
|
||||
return (-1);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* gidtb_start
|
||||
* creates an an empty gidtb
|
||||
* Return:
|
||||
* 0 if ok, -1 otherwise
|
||||
*/
|
||||
static int
|
||||
gidtb_start(void)
|
||||
{
|
||||
|
||||
if (gidtb != NULL)
|
||||
return (0);
|
||||
if (gidtb_fail)
|
||||
return (-1);
|
||||
if ((gidtb = (GIDC **)calloc(GID_SZ, sizeof(GIDC *))) == NULL) {
|
||||
++gidtb_fail;
|
||||
return (-1);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* usrtb_start
|
||||
* creates an an empty usrtb
|
||||
* Return:
|
||||
* 0 if ok, -1 otherwise
|
||||
*/
|
||||
static int
|
||||
usrtb_start(void)
|
||||
{
|
||||
|
||||
if (usrtb != NULL)
|
||||
return (0);
|
||||
if (usrtb_fail)
|
||||
return (-1);
|
||||
if ((usrtb = (UIDC **)calloc(UNM_SZ, sizeof(UIDC *))) == NULL) {
|
||||
++usrtb_fail;
|
||||
return (-1);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* grptb_start
|
||||
* creates an an empty grptb
|
||||
* Return:
|
||||
* 0 if ok, -1 otherwise
|
||||
*/
|
||||
static int
|
||||
grptb_start(void)
|
||||
{
|
||||
|
||||
if (grptb != NULL)
|
||||
return (0);
|
||||
if (grptb_fail)
|
||||
return (-1);
|
||||
if ((grptb = (GIDC **)calloc(GNM_SZ, sizeof(GIDC *))) == NULL) {
|
||||
++grptb_fail;
|
||||
return (-1);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* user_from_uid()
|
||||
* caches the name (if any) for the uid. If noname clear, we always
|
||||
* return the stored name (if valid or invalid match).
|
||||
* We use a simple hash table.
|
||||
* Return
|
||||
* Pointer to stored name (or a empty string)
|
||||
*/
|
||||
const char *
|
||||
user_from_uid(uid_t uid, int noname)
|
||||
{
|
||||
struct passwd *pw;
|
||||
UIDC *ptr, **pptr;
|
||||
|
||||
if ((uidtb == NULL) && (uidtb_start() < 0))
|
||||
return (NULL);
|
||||
|
||||
/*
|
||||
* see if we have this uid cached
|
||||
*/
|
||||
pptr = uidtb + (uid % UID_SZ);
|
||||
ptr = *pptr;
|
||||
|
||||
if ((ptr != NULL) && (ptr->valid > 0) && (ptr->uid == uid)) {
|
||||
/*
|
||||
* have an entry for this uid
|
||||
*/
|
||||
if (!noname || (ptr->valid == VALID))
|
||||
return (ptr->name);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* No entry for this uid, we will add it
|
||||
*/
|
||||
if (!pwopn) {
|
||||
if (_pwcache_setpassent != NULL)
|
||||
(*_pwcache_setpassent)(1);
|
||||
++pwopn;
|
||||
}
|
||||
|
||||
if (ptr == NULL)
|
||||
*pptr = ptr = (UIDC *)malloc(sizeof(UIDC));
|
||||
|
||||
if ((pw = (*_pwcache_getpwuid)(uid)) == NULL) {
|
||||
/*
|
||||
* no match for this uid in the local password file
|
||||
* a string that is the uid in numeric format
|
||||
*/
|
||||
if (ptr == NULL)
|
||||
return (NULL);
|
||||
ptr->uid = uid;
|
||||
(void)snprintf(ptr->name, UNMLEN, "%lu", (long) uid);
|
||||
ptr->valid = INVALID;
|
||||
if (noname)
|
||||
return (NULL);
|
||||
} else {
|
||||
/*
|
||||
* there is an entry for this uid in the password file
|
||||
*/
|
||||
if (ptr == NULL)
|
||||
return (pw->pw_name);
|
||||
ptr->uid = uid;
|
||||
(void)strlcpy(ptr->name, pw->pw_name, UNMLEN);
|
||||
ptr->valid = VALID;
|
||||
}
|
||||
return (ptr->name);
|
||||
}
|
||||
|
||||
/*
|
||||
* group_from_gid()
|
||||
* caches the name (if any) for the gid. If noname clear, we always
|
||||
* return the stored name (if valid or invalid match).
|
||||
* We use a simple hash table.
|
||||
* Return
|
||||
* Pointer to stored name (or a empty string)
|
||||
*/
|
||||
const char *
|
||||
group_from_gid(gid_t gid, int noname)
|
||||
{
|
||||
struct group *gr;
|
||||
GIDC *ptr, **pptr;
|
||||
|
||||
if ((gidtb == NULL) && (gidtb_start() < 0))
|
||||
return (NULL);
|
||||
|
||||
/*
|
||||
* see if we have this gid cached
|
||||
*/
|
||||
pptr = gidtb + (gid % GID_SZ);
|
||||
ptr = *pptr;
|
||||
|
||||
if ((ptr != NULL) && (ptr->valid > 0) && (ptr->gid == gid)) {
|
||||
/*
|
||||
* have an entry for this gid
|
||||
*/
|
||||
if (!noname || (ptr->valid == VALID))
|
||||
return (ptr->name);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* No entry for this gid, we will add it
|
||||
*/
|
||||
if (!gropn) {
|
||||
if (_pwcache_setgroupent != NULL)
|
||||
(*_pwcache_setgroupent)(1);
|
||||
++gropn;
|
||||
}
|
||||
|
||||
if (ptr == NULL)
|
||||
*pptr = ptr = (GIDC *)malloc(sizeof(GIDC));
|
||||
|
||||
if ((gr = (*_pwcache_getgrgid)(gid)) == NULL) {
|
||||
/*
|
||||
* no match for this gid in the local group file, put in
|
||||
* a string that is the gid in numberic format
|
||||
*/
|
||||
if (ptr == NULL)
|
||||
return (NULL);
|
||||
ptr->gid = gid;
|
||||
(void)snprintf(ptr->name, GNMLEN, "%lu", (long) gid);
|
||||
ptr->valid = INVALID;
|
||||
if (noname)
|
||||
return (NULL);
|
||||
} else {
|
||||
/*
|
||||
* there is an entry for this group in the group file
|
||||
*/
|
||||
if (ptr == NULL)
|
||||
return (gr->gr_name);
|
||||
ptr->gid = gid;
|
||||
(void)strlcpy(ptr->name, gr->gr_name, GNMLEN);
|
||||
ptr->valid = VALID;
|
||||
}
|
||||
return (ptr->name);
|
||||
}
|
||||
|
||||
/*
|
||||
* uid_from_user()
|
||||
* caches the uid for a given user name. We use a simple hash table.
|
||||
* Return
|
||||
* the uid (if any) for a user name, or a -1 if no match can be found
|
||||
*/
|
||||
int
|
||||
uid_from_user(const char *name, uid_t *uid)
|
||||
{
|
||||
struct passwd *pw;
|
||||
UIDC *ptr, **pptr;
|
||||
size_t namelen;
|
||||
|
||||
/*
|
||||
* return -1 for mangled names
|
||||
*/
|
||||
if (name == NULL || ((namelen = strlen(name)) == 0))
|
||||
return (-1);
|
||||
if ((usrtb == NULL) && (usrtb_start() < 0))
|
||||
return (-1);
|
||||
|
||||
/*
|
||||
* look up in hash table, if found and valid return the uid,
|
||||
* if found and invalid, return a -1
|
||||
*/
|
||||
pptr = usrtb + st_hash(name, namelen, UNM_SZ);
|
||||
ptr = *pptr;
|
||||
|
||||
if ((ptr != NULL) && (ptr->valid > 0) && !strcmp(name, ptr->name)) {
|
||||
if (ptr->valid == INVALID)
|
||||
return (-1);
|
||||
*uid = ptr->uid;
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (!pwopn) {
|
||||
if (_pwcache_setpassent != NULL)
|
||||
(*_pwcache_setpassent)(1);
|
||||
++pwopn;
|
||||
}
|
||||
|
||||
if (ptr == NULL)
|
||||
*pptr = ptr = (UIDC *)malloc(sizeof(UIDC));
|
||||
|
||||
/*
|
||||
* no match, look it up, if no match store it as an invalid entry,
|
||||
* or store the matching uid
|
||||
*/
|
||||
if (ptr == NULL) {
|
||||
if ((pw = (*_pwcache_getpwnam)(name)) == NULL)
|
||||
return (-1);
|
||||
*uid = pw->pw_uid;
|
||||
return (0);
|
||||
}
|
||||
(void)strlcpy(ptr->name, name, UNMLEN);
|
||||
if ((pw = (*_pwcache_getpwnam)(name)) == NULL) {
|
||||
ptr->valid = INVALID;
|
||||
return (-1);
|
||||
}
|
||||
ptr->valid = VALID;
|
||||
*uid = ptr->uid = pw->pw_uid;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* gid_from_group()
|
||||
* caches the gid for a given group name. We use a simple hash table.
|
||||
* Return
|
||||
* the gid (if any) for a group name, or a -1 if no match can be found
|
||||
*/
|
||||
int
|
||||
gid_from_group(const char *name, gid_t *gid)
|
||||
{
|
||||
struct group *gr;
|
||||
GIDC *ptr, **pptr;
|
||||
size_t namelen;
|
||||
|
||||
/*
|
||||
* return -1 for mangled names
|
||||
*/
|
||||
if (name == NULL || ((namelen = strlen(name)) == 0))
|
||||
return (-1);
|
||||
if ((grptb == NULL) && (grptb_start() < 0))
|
||||
return (-1);
|
||||
|
||||
/*
|
||||
* look up in hash table, if found and valid return the uid,
|
||||
* if found and invalid, return a -1
|
||||
*/
|
||||
pptr = grptb + st_hash(name, namelen, GID_SZ);
|
||||
ptr = *pptr;
|
||||
|
||||
if ((ptr != NULL) && (ptr->valid > 0) && !strcmp(name, ptr->name)) {
|
||||
if (ptr->valid == INVALID)
|
||||
return (-1);
|
||||
*gid = ptr->gid;
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (!gropn) {
|
||||
if (_pwcache_setgroupent != NULL)
|
||||
(*_pwcache_setgroupent)(1);
|
||||
++gropn;
|
||||
}
|
||||
|
||||
if (ptr == NULL)
|
||||
*pptr = ptr = (GIDC *)malloc(sizeof(GIDC));
|
||||
|
||||
/*
|
||||
* no match, look it up, if no match store it as an invalid entry,
|
||||
* or store the matching gid
|
||||
*/
|
||||
if (ptr == NULL) {
|
||||
if ((gr = (*_pwcache_getgrnam)(name)) == NULL)
|
||||
return (-1);
|
||||
*gid = gr->gr_gid;
|
||||
return (0);
|
||||
}
|
||||
|
||||
(void)strlcpy(ptr->name, name, GNMLEN);
|
||||
if ((gr = (*_pwcache_getgrnam)(name)) == NULL) {
|
||||
ptr->valid = INVALID;
|
||||
return (-1);
|
||||
}
|
||||
ptr->valid = VALID;
|
||||
*gid = ptr->gid = gr->gr_gid;
|
||||
return (0);
|
||||
}
|
||||
|
||||
#define FLUSHTB(arr, len, fail) \
|
||||
do { \
|
||||
if (arr != NULL) { \
|
||||
for (i = 0; i < len; i++) \
|
||||
if (arr[i] != NULL) \
|
||||
free(arr[i]); \
|
||||
arr = NULL; \
|
||||
} \
|
||||
fail = 0; \
|
||||
} while (/* CONSTCOND */0);
|
||||
|
||||
int
|
||||
pwcache_userdb(
|
||||
int (*a_setpassent)(int),
|
||||
void (*a_endpwent)(void),
|
||||
struct passwd * (*a_getpwnam)(const char *),
|
||||
struct passwd * (*a_getpwuid)(uid_t))
|
||||
{
|
||||
int i;
|
||||
|
||||
/* a_setpassent and a_endpwent may be NULL */
|
||||
if (a_getpwnam == NULL || a_getpwuid == NULL)
|
||||
return (-1);
|
||||
|
||||
if (_pwcache_endpwent != NULL)
|
||||
(*_pwcache_endpwent)();
|
||||
FLUSHTB(uidtb, UID_SZ, uidtb_fail);
|
||||
FLUSHTB(usrtb, UNM_SZ, usrtb_fail);
|
||||
pwopn = 0;
|
||||
_pwcache_setpassent = a_setpassent;
|
||||
_pwcache_endpwent = a_endpwent;
|
||||
_pwcache_getpwnam = a_getpwnam;
|
||||
_pwcache_getpwuid = a_getpwuid;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
pwcache_groupdb(
|
||||
int (*a_setgroupent)(int),
|
||||
void (*a_endgrent)(void),
|
||||
struct group * (*a_getgrnam)(const char *),
|
||||
struct group * (*a_getgrgid)(gid_t))
|
||||
{
|
||||
int i;
|
||||
|
||||
/* a_setgroupent and a_endgrent may be NULL */
|
||||
if (a_getgrnam == NULL || a_getgrgid == NULL)
|
||||
return (-1);
|
||||
|
||||
if (_pwcache_endgrent != NULL)
|
||||
(*_pwcache_endgrent)();
|
||||
FLUSHTB(gidtb, GID_SZ, gidtb_fail);
|
||||
FLUSHTB(grptb, GNM_SZ, grptb_fail);
|
||||
gropn = 0;
|
||||
_pwcache_setgroupent = a_setgroupent;
|
||||
_pwcache_endgrent = a_endgrent;
|
||||
_pwcache_getgrnam = a_getgrnam;
|
||||
_pwcache_getgrgid = a_getgrgid;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
#ifdef TEST_PWCACHE
|
||||
|
||||
struct passwd *
|
||||
test_getpwnam(const char *name)
|
||||
{
|
||||
static struct passwd foo;
|
||||
|
||||
memset(&foo, 0, sizeof(foo));
|
||||
if (strcmp(name, "toor") == 0) {
|
||||
foo.pw_uid = 666;
|
||||
return &foo;
|
||||
}
|
||||
return (getpwnam(name));
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
uid_t u;
|
||||
int r, i;
|
||||
|
||||
printf("pass 1 (default userdb)\n");
|
||||
for (i = 1; i < argc; i++) {
|
||||
printf("i: %d, pwopn %d usrtb_fail %d usrtb %p\n",
|
||||
i, pwopn, usrtb_fail, usrtb);
|
||||
r = uid_from_user(argv[i], &u);
|
||||
if (r == -1)
|
||||
printf(" uid_from_user %s: failed\n", argv[i]);
|
||||
else
|
||||
printf(" uid_from_user %s: %d\n", argv[i], u);
|
||||
}
|
||||
printf("pass 1 finish: pwopn %d usrtb_fail %d usrtb %p\n",
|
||||
pwopn, usrtb_fail, usrtb);
|
||||
|
||||
puts("");
|
||||
printf("pass 2 (replacement userdb)\n");
|
||||
printf("pwcache_userdb returned %d\n",
|
||||
pwcache_userdb(setpassent, test_getpwnam, getpwuid));
|
||||
printf("pwopn %d usrtb_fail %d usrtb %p\n", pwopn, usrtb_fail, usrtb);
|
||||
|
||||
for (i = 1; i < argc; i++) {
|
||||
printf("i: %d, pwopn %d usrtb_fail %d usrtb %p\n",
|
||||
i, pwopn, usrtb_fail, usrtb);
|
||||
u = -1;
|
||||
r = uid_from_user(argv[i], &u);
|
||||
if (r == -1)
|
||||
printf(" uid_from_user %s: failed\n", argv[i]);
|
||||
else
|
||||
printf(" uid_from_user %s: %d\n", argv[i], u);
|
||||
}
|
||||
printf("pass 2 finish: pwopn %d usrtb_fail %d usrtb %p\n",
|
||||
pwopn, usrtb_fail, usrtb);
|
||||
|
||||
puts("");
|
||||
printf("pass 3 (null pointers)\n");
|
||||
printf("pwcache_userdb returned %d\n",
|
||||
pwcache_userdb(NULL, NULL, NULL));
|
||||
|
||||
return (0);
|
||||
}
|
||||
#endif /* TEST_PWCACHE */
|
||||
#endif /* !HAVE_PWCACHE_USERDB */
|
72
compat/pwcache.h
Normal file
72
compat/pwcache.h
Normal file
@ -0,0 +1,72 @@
|
||||
/* $NetBSD: pwcache.h,v 1.5 2003/11/10 08:51:51 wiz Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1992 Keith Muller.
|
||||
* Copyright (c) 1992, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* Keith Muller of the University of California, San Diego.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @(#)cache.h 8.1 (Berkeley) 5/31/93
|
||||
*/
|
||||
|
||||
/*
|
||||
* Constants and data structures used to implement group and password file
|
||||
* caches. Traditional passwd/group cache routines perform quite poorly with
|
||||
* archives. The chances of hitting a valid lookup with an archive is quite a
|
||||
* bit worse than with files already resident on the file system. These misses
|
||||
* create a MAJOR performance cost. To address this problem, these routines
|
||||
* cache both hits and misses.
|
||||
*
|
||||
* NOTE: name lengths must be as large as those stored in ANY PROTOCOL and
|
||||
* as stored in the passwd and group files. CACHE SIZES MUST BE PRIME
|
||||
*/
|
||||
#define UNMLEN 32 /* >= user name found in any protocol */
|
||||
#define GNMLEN 32 /* >= group name found in any protocol */
|
||||
#define UID_SZ 317 /* size of uid to user_name cache */
|
||||
#define UNM_SZ 317 /* size of user_name to uid cache */
|
||||
#define GID_SZ 251 /* size of gid to group_name cache */
|
||||
#define GNM_SZ 251 /* size of group_name to gid cache */
|
||||
#define VALID 1 /* entry and name are valid */
|
||||
#define INVALID 2 /* entry valid, name NOT valid */
|
||||
|
||||
/*
|
||||
* Node structures used in the user, group, uid, and gid caches.
|
||||
*/
|
||||
|
||||
typedef struct uidc {
|
||||
int valid; /* is this a valid or a miss entry */
|
||||
char name[UNMLEN]; /* uid name */
|
||||
uid_t uid; /* cached uid */
|
||||
} UIDC;
|
||||
|
||||
typedef struct gidc {
|
||||
int valid; /* is this a valid or a miss entry */
|
||||
char name[GNMLEN]; /* gid name */
|
||||
gid_t gid; /* cached gid */
|
||||
} GIDC;
|
185
compat/stat_flags.c
Normal file
185
compat/stat_flags.c
Normal file
@ -0,0 +1,185 @@
|
||||
/* $NetBSD: stat_flags.c,v 1.19 2004/05/25 14:54:55 hannken Exp $ */
|
||||
|
||||
/*-
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#if HAVE_NBTOOL_CONFIG_H
|
||||
#include "nbtool_config.h"
|
||||
#else
|
||||
#define HAVE_STRUCT_STAT_ST_FLAGS 1
|
||||
#endif
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#if !defined(lint)
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)stat_flags.c 8.2 (Berkeley) 7/28/94";
|
||||
#else
|
||||
__RCSID("$NetBSD: stat_flags.c,v 1.19 2004/05/25 14:54:55 hannken Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fts.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "stat_flags.h"
|
||||
|
||||
#define SAPPEND(s) do { \
|
||||
if (prefix != NULL) \
|
||||
(void)strlcat(string, prefix, sizeof(string)); \
|
||||
(void)strlcat(string, s, sizeof(string)); \
|
||||
prefix = ","; \
|
||||
} while (/* CONSTCOND */ 0)
|
||||
|
||||
/*
|
||||
* flags_to_string --
|
||||
* Convert stat flags to a comma-separated string. If no flags
|
||||
* are set, return the default string.
|
||||
*/
|
||||
char *
|
||||
flags_to_string(u_long flags, const char *def)
|
||||
{
|
||||
static char string[128];
|
||||
const char *prefix;
|
||||
|
||||
string[0] = '\0';
|
||||
prefix = NULL;
|
||||
#if HAVE_STRUCT_STAT_ST_FLAGS
|
||||
if (flags & UF_APPEND)
|
||||
SAPPEND("uappnd");
|
||||
if (flags & UF_IMMUTABLE)
|
||||
SAPPEND("uchg");
|
||||
if (flags & UF_NODUMP)
|
||||
SAPPEND("nodump");
|
||||
if (flags & UF_OPAQUE)
|
||||
SAPPEND("opaque");
|
||||
if (flags & SF_APPEND)
|
||||
SAPPEND("sappnd");
|
||||
if (flags & SF_ARCHIVED)
|
||||
SAPPEND("arch");
|
||||
if (flags & SF_IMMUTABLE)
|
||||
SAPPEND("schg");
|
||||
#ifdef SF_SNAPSHOT
|
||||
if (flags & SF_SNAPSHOT)
|
||||
SAPPEND("snap");
|
||||
#endif
|
||||
#endif
|
||||
if (prefix == NULL)
|
||||
strlcpy(string, def, sizeof(string));
|
||||
return (string);
|
||||
}
|
||||
|
||||
#define TEST(a, b, f) { \
|
||||
if (!strcmp(a, b)) { \
|
||||
if (clear) { \
|
||||
if (clrp) \
|
||||
*clrp |= (f); \
|
||||
if (setp) \
|
||||
*setp &= ~(f); \
|
||||
} else { \
|
||||
if (setp) \
|
||||
*setp |= (f); \
|
||||
if (clrp) \
|
||||
*clrp &= ~(f); \
|
||||
} \
|
||||
break; \
|
||||
} \
|
||||
}
|
||||
|
||||
/*
|
||||
* string_to_flags --
|
||||
* Take string of arguments and return stat flags. Return 0 on
|
||||
* success, 1 on failure. On failure, stringp is set to point
|
||||
* to the offending token.
|
||||
*/
|
||||
int
|
||||
string_to_flags(char **stringp, u_long *setp, u_long *clrp)
|
||||
{
|
||||
int clear;
|
||||
char *string, *p;
|
||||
|
||||
if (setp)
|
||||
*setp = 0;
|
||||
if (clrp)
|
||||
*clrp = 0;
|
||||
|
||||
#if HAVE_STRUCT_STAT_ST_FLAGS
|
||||
string = *stringp;
|
||||
while ((p = strsep(&string, "\t ,")) != NULL) {
|
||||
clear = 0;
|
||||
*stringp = p;
|
||||
if (*p == '\0')
|
||||
continue;
|
||||
if (p[0] == 'n' && p[1] == 'o') {
|
||||
clear = 1;
|
||||
p += 2;
|
||||
}
|
||||
switch (p[0]) {
|
||||
case 'a':
|
||||
TEST(p, "arch", SF_ARCHIVED);
|
||||
TEST(p, "archived", SF_ARCHIVED);
|
||||
return (1);
|
||||
case 'd':
|
||||
clear = !clear;
|
||||
TEST(p, "dump", UF_NODUMP);
|
||||
return (1);
|
||||
case 'n':
|
||||
/*
|
||||
* Support `nonodump'. Note that
|
||||
* the state of clear is not changed.
|
||||
*/
|
||||
TEST(p, "nodump", UF_NODUMP);
|
||||
return (1);
|
||||
case 'o':
|
||||
TEST(p, "opaque", UF_OPAQUE);
|
||||
return (1);
|
||||
case 's':
|
||||
TEST(p, "sappnd", SF_APPEND);
|
||||
TEST(p, "sappend", SF_APPEND);
|
||||
TEST(p, "schg", SF_IMMUTABLE);
|
||||
TEST(p, "schange", SF_IMMUTABLE);
|
||||
TEST(p, "simmutable", SF_IMMUTABLE);
|
||||
return (1);
|
||||
case 'u':
|
||||
TEST(p, "uappnd", UF_APPEND);
|
||||
TEST(p, "uappend", UF_APPEND);
|
||||
TEST(p, "uchg", UF_IMMUTABLE);
|
||||
TEST(p, "uchange", UF_IMMUTABLE);
|
||||
TEST(p, "uimmutable", UF_IMMUTABLE);
|
||||
return (1);
|
||||
default:
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return (0);
|
||||
}
|
35
compat/stat_flags.h
Normal file
35
compat/stat_flags.h
Normal file
@ -0,0 +1,35 @@
|
||||
/* $NetBSD: stat_flags.h,v 1.4 2003/08/07 09:05:16 agc Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1991, 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.
|
||||
*
|
||||
* @(#)extern.h 8.1 (Berkeley) 5/31/93
|
||||
*/
|
||||
|
||||
char *flags_to_string(u_long, const char *);
|
||||
int string_to_flags(char **, u_long *, u_long *);
|
247
compat/strsuftoll.c
Normal file
247
compat/strsuftoll.c
Normal file
@ -0,0 +1,247 @@
|
||||
/* $NetBSD: strsuftoll.c,v 1.6 2004/03/05 05:58:29 lukem Exp $ */
|
||||
/*-
|
||||
* Copyright (c) 2001-2002,2004 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by Luke Mewburn.
|
||||
*
|
||||
* 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 NetBSD
|
||||
* Foundation, Inc. and its contributors.
|
||||
* 4. 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.
|
||||
*/
|
||||
/*-
|
||||
* Copyright (c) 1991, 1993, 1994
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* Keith Muller of the University of California, San Diego and Lance
|
||||
* Visser of Convex Computer Corporation.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#if HAVE_NBTOOL_CONFIG_H
|
||||
#include "nbtool_config.h"
|
||||
#endif
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
#if defined(LIBC_SCCS) && !defined(lint)
|
||||
__RCSID("$NetBSD: strsuftoll.c,v 1.6 2004/03/05 05:58:29 lukem Exp $");
|
||||
#endif /* LIBC_SCCS and not lint */
|
||||
|
||||
#ifdef _LIBC
|
||||
#include "namespace.h"
|
||||
#endif
|
||||
|
||||
#if !HAVE_STRSUFTOLL
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef _LIBC
|
||||
# ifdef __weak_alias
|
||||
__weak_alias(strsuftoll, _strsuftoll)
|
||||
__weak_alias(strsuftollx, _strsuftollx)
|
||||
# endif
|
||||
#endif /* LIBC */
|
||||
|
||||
/*
|
||||
* Convert an expression of the following forms to a (u)int64_t.
|
||||
* 1) A positive decimal number.
|
||||
* 2) A positive decimal number followed by a b (mult by 512).
|
||||
* 3) A positive decimal number followed by a k (mult by 1024).
|
||||
* 4) A positive decimal number followed by a m (mult by 1048576).
|
||||
* 5) A positive decimal number followed by a g (mult by 1073741824).
|
||||
* 6) A positive decimal number followed by a t (mult by 1099511627776).
|
||||
* 7) A positive decimal number followed by a w (mult by sizeof int)
|
||||
* 8) Two or more positive decimal numbers (with/without k,b or w).
|
||||
* separated by x (also * for backwards compatibility), specifying
|
||||
* the product of the indicated values.
|
||||
* Returns the result upon successful conversion, or exits with an
|
||||
* appropriate error.
|
||||
*
|
||||
*/
|
||||
/* LONGLONG */
|
||||
long long
|
||||
strsuftoll(const char *desc, const char *val,
|
||||
long long min, long long max)
|
||||
{
|
||||
long long result;
|
||||
char errbuf[100];
|
||||
|
||||
result = strsuftollx(desc, val, min, max, errbuf, sizeof(errbuf));
|
||||
if (*errbuf != '\0')
|
||||
errx(1, "%s", errbuf);
|
||||
return (result);
|
||||
}
|
||||
|
||||
/*
|
||||
* As strsuftoll(), but returns the error message into the provided buffer
|
||||
* rather than exiting with it.
|
||||
*/
|
||||
/* LONGLONG */
|
||||
long long
|
||||
strsuftollx(const char *desc, const char *val,
|
||||
long long min, long long max, char *ebuf, size_t ebuflen)
|
||||
{
|
||||
long long num, t;
|
||||
char *expr;
|
||||
|
||||
_DIAGASSERT(desc != NULL);
|
||||
_DIAGASSERT(val != NULL);
|
||||
_DIAGASSERT(ebuf != NULL);
|
||||
|
||||
errno = 0;
|
||||
ebuf[0] = '\0';
|
||||
|
||||
while (isspace((unsigned char)*val)) /* Skip leading space */
|
||||
val++;
|
||||
|
||||
num = strtoll(val, &expr, 10);
|
||||
if (errno == ERANGE)
|
||||
goto erange; /* Overflow */
|
||||
|
||||
if (expr == val) /* No digits */
|
||||
goto badnum;
|
||||
|
||||
switch (*expr) {
|
||||
case 'b':
|
||||
t = num;
|
||||
num *= 512; /* 1 block */
|
||||
if (t > num)
|
||||
goto erange;
|
||||
++expr;
|
||||
break;
|
||||
case 'k':
|
||||
t = num;
|
||||
num *= 1024; /* 1 kilobyte */
|
||||
if (t > num)
|
||||
goto erange;
|
||||
++expr;
|
||||
break;
|
||||
case 'm':
|
||||
t = num;
|
||||
num *= 1048576; /* 1 megabyte */
|
||||
if (t > num)
|
||||
goto erange;
|
||||
++expr;
|
||||
break;
|
||||
case 'g':
|
||||
t = num;
|
||||
num *= 1073741824; /* 1 gigabyte */
|
||||
if (t > num)
|
||||
goto erange;
|
||||
++expr;
|
||||
break;
|
||||
case 't':
|
||||
t = num;
|
||||
num *= 1099511627776LL; /* 1 terabyte */
|
||||
if (t > num)
|
||||
goto erange;
|
||||
++expr;
|
||||
break;
|
||||
case 'w':
|
||||
t = num;
|
||||
num *= sizeof(int); /* 1 word */
|
||||
if (t > num)
|
||||
goto erange;
|
||||
++expr;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (*expr) {
|
||||
case '\0':
|
||||
break;
|
||||
case '*': /* Backward compatible */
|
||||
case 'x':
|
||||
t = num;
|
||||
num *= strsuftollx(desc, expr + 1, min, max, ebuf, ebuflen);
|
||||
if (*ebuf != '\0')
|
||||
return (0);
|
||||
if (t > num) {
|
||||
erange:
|
||||
snprintf(ebuf, ebuflen,
|
||||
"%s: %s", desc, strerror(ERANGE));
|
||||
return (0);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
badnum: snprintf(ebuf, ebuflen,
|
||||
"%s `%s': illegal number", desc, val);
|
||||
return (0);
|
||||
}
|
||||
if (num < min) {
|
||||
/* LONGLONG */
|
||||
snprintf(ebuf, ebuflen, "%s %lld is less than %lld.",
|
||||
desc, (long long)num, (long long)min);
|
||||
return (0);
|
||||
}
|
||||
if (num > max) {
|
||||
/* LONGLONG */
|
||||
snprintf(ebuf, ebuflen,
|
||||
"%s %lld is greater than %lld.",
|
||||
desc, (long long)num, (long long)max);
|
||||
return (0);
|
||||
}
|
||||
*ebuf = '\0';
|
||||
return (num);
|
||||
}
|
||||
|
||||
#endif /* !HAVE_STRSUFTOLL */
|
0
compat/util.h
Normal file
0
compat/util.h
Normal file
378
compat/vis.c
Normal file
378
compat/vis.c
Normal file
@ -0,0 +1,378 @@
|
||||
/* $NetBSD: vis.c,v 1.27 2004/02/26 23:01:15 enami Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 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. 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.
|
||||
*/
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1999 The NetBSD Foundation, 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 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.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#if defined(LIBC_SCCS) && !defined(lint)
|
||||
__RCSID("$NetBSD: vis.c,v 1.27 2004/02/26 23:01:15 enami Exp $");
|
||||
#endif /* LIBC_SCCS and not lint */
|
||||
|
||||
#include "namespace.h"
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <vis.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef __weak_alias
|
||||
__weak_alias(strsvis,_strsvis)
|
||||
__weak_alias(strsvisx,_strsvisx)
|
||||
__weak_alias(strvis,_strvis)
|
||||
__weak_alias(strvisx,_strvisx)
|
||||
__weak_alias(svis,_svis)
|
||||
__weak_alias(vis,_vis)
|
||||
#endif
|
||||
|
||||
#if !HAVE_VIS || !HAVE_SVIS
|
||||
#include <ctype.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#undef BELL
|
||||
#define BELL '\a'
|
||||
|
||||
#define isoctal(c) (((u_char)(c)) >= '0' && ((u_char)(c)) <= '7')
|
||||
#define iswhite(c) (c == ' ' || c == '\t' || c == '\n')
|
||||
#define issafe(c) (c == '\b' || c == BELL || c == '\r')
|
||||
#define xtoa(c) "0123456789abcdef"[c]
|
||||
|
||||
#define MAXEXTRAS 5
|
||||
|
||||
|
||||
#define MAKEEXTRALIST(flag, extra, orig) \
|
||||
do { \
|
||||
const char *o = orig; \
|
||||
char *e; \
|
||||
while (*o++) \
|
||||
continue; \
|
||||
extra = alloca((size_t)((o - orig) + MAXEXTRAS)); \
|
||||
for (o = orig, e = extra; (*e++ = *o++) != '\0';) \
|
||||
continue; \
|
||||
e--; \
|
||||
if (flag & VIS_SP) *e++ = ' '; \
|
||||
if (flag & VIS_TAB) *e++ = '\t'; \
|
||||
if (flag & VIS_NL) *e++ = '\n'; \
|
||||
if ((flag & VIS_NOSLASH) == 0) *e++ = '\\'; \
|
||||
*e = '\0'; \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
|
||||
/*
|
||||
* This is HVIS, the macro of vis used to HTTP style (RFC 1808)
|
||||
*/
|
||||
#define HVIS(dst, c, flag, nextc, extra) \
|
||||
do \
|
||||
if (!isascii(c) || !isalnum(c) || strchr("$-_.+!*'(),", c) != NULL) { \
|
||||
*dst++ = '%'; \
|
||||
*dst++ = xtoa(((unsigned int)c >> 4) & 0xf); \
|
||||
*dst++ = xtoa((unsigned int)c & 0xf); \
|
||||
} else { \
|
||||
SVIS(dst, c, flag, nextc, extra); \
|
||||
} \
|
||||
while (/*CONSTCOND*/0)
|
||||
|
||||
/*
|
||||
* This is SVIS, the central macro of vis.
|
||||
* dst: Pointer to the destination buffer
|
||||
* c: Character to encode
|
||||
* flag: Flag word
|
||||
* nextc: The character following 'c'
|
||||
* extra: Pointer to the list of extra characters to be
|
||||
* backslash-protected.
|
||||
*/
|
||||
#define SVIS(dst, c, flag, nextc, extra) \
|
||||
do { \
|
||||
int isextra; \
|
||||
isextra = strchr(extra, c) != NULL; \
|
||||
if (!isextra && isascii(c) && (isgraph(c) || iswhite(c) || \
|
||||
((flag & VIS_SAFE) && issafe(c)))) { \
|
||||
*dst++ = c; \
|
||||
break; \
|
||||
} \
|
||||
if (flag & VIS_CSTYLE) { \
|
||||
switch (c) { \
|
||||
case '\n': \
|
||||
*dst++ = '\\'; *dst++ = 'n'; \
|
||||
continue; \
|
||||
case '\r': \
|
||||
*dst++ = '\\'; *dst++ = 'r'; \
|
||||
continue; \
|
||||
case '\b': \
|
||||
*dst++ = '\\'; *dst++ = 'b'; \
|
||||
continue; \
|
||||
case BELL: \
|
||||
*dst++ = '\\'; *dst++ = 'a'; \
|
||||
continue; \
|
||||
case '\v': \
|
||||
*dst++ = '\\'; *dst++ = 'v'; \
|
||||
continue; \
|
||||
case '\t': \
|
||||
*dst++ = '\\'; *dst++ = 't'; \
|
||||
continue; \
|
||||
case '\f': \
|
||||
*dst++ = '\\'; *dst++ = 'f'; \
|
||||
continue; \
|
||||
case ' ': \
|
||||
*dst++ = '\\'; *dst++ = 's'; \
|
||||
continue; \
|
||||
case '\0': \
|
||||
*dst++ = '\\'; *dst++ = '0'; \
|
||||
if (isoctal(nextc)) { \
|
||||
*dst++ = '0'; \
|
||||
*dst++ = '0'; \
|
||||
} \
|
||||
continue; \
|
||||
default: \
|
||||
if (isgraph(c)) { \
|
||||
*dst++ = '\\'; *dst++ = c; \
|
||||
continue; \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
if (isextra || ((c & 0177) == ' ') || (flag & VIS_OCTAL)) { \
|
||||
*dst++ = '\\'; \
|
||||
*dst++ = (u_char)(((u_int32_t)(u_char)c >> 6) & 03) + '0'; \
|
||||
*dst++ = (u_char)(((u_int32_t)(u_char)c >> 3) & 07) + '0'; \
|
||||
*dst++ = (c & 07) + '0'; \
|
||||
} else { \
|
||||
if ((flag & VIS_NOSLASH) == 0) *dst++ = '\\'; \
|
||||
if (c & 0200) { \
|
||||
c &= 0177; *dst++ = 'M'; \
|
||||
} \
|
||||
if (iscntrl(c)) { \
|
||||
*dst++ = '^'; \
|
||||
if (c == 0177) \
|
||||
*dst++ = '?'; \
|
||||
else \
|
||||
*dst++ = c + '@'; \
|
||||
} else { \
|
||||
*dst++ = '-'; *dst++ = c; \
|
||||
} \
|
||||
} \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
|
||||
/*
|
||||
* svis - visually encode characters, also encoding the characters
|
||||
* pointed to by `extra'
|
||||
*/
|
||||
char *
|
||||
svis(dst, c, flag, nextc, extra)
|
||||
char *dst;
|
||||
int c, flag, nextc;
|
||||
const char *extra;
|
||||
{
|
||||
char *nextra;
|
||||
_DIAGASSERT(dst != NULL);
|
||||
_DIAGASSERT(extra != NULL);
|
||||
MAKEEXTRALIST(flag, nextra, extra);
|
||||
if (flag & VIS_HTTPSTYLE)
|
||||
HVIS(dst, c, flag, nextc, nextra);
|
||||
else
|
||||
SVIS(dst, c, flag, nextc, nextra);
|
||||
*dst = '\0';
|
||||
return(dst);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* strsvis, strsvisx - visually encode characters from src into dst
|
||||
*
|
||||
* Extra is a pointer to a \0-terminated list of characters to
|
||||
* be encoded, too. These functions are useful e. g. to
|
||||
* encode strings in such a way so that they are not interpreted
|
||||
* by a shell.
|
||||
*
|
||||
* Dst must be 4 times the size of src to account for possible
|
||||
* expansion. The length of dst, not including the trailing NULL,
|
||||
* is returned.
|
||||
*
|
||||
* Strsvisx encodes exactly len bytes from src into dst.
|
||||
* This is useful for encoding a block of data.
|
||||
*/
|
||||
int
|
||||
strsvis(dst, csrc, flag, extra)
|
||||
char *dst;
|
||||
const char *csrc;
|
||||
int flag;
|
||||
const char *extra;
|
||||
{
|
||||
int c;
|
||||
char *start;
|
||||
char *nextra;
|
||||
const unsigned char *src = (const unsigned char *)csrc;
|
||||
|
||||
_DIAGASSERT(dst != NULL);
|
||||
_DIAGASSERT(src != NULL);
|
||||
_DIAGASSERT(extra != NULL);
|
||||
MAKEEXTRALIST(flag, nextra, extra);
|
||||
if (flag & VIS_HTTPSTYLE) {
|
||||
for (start = dst; (c = *src++) != '\0'; /* empty */)
|
||||
HVIS(dst, c, flag, *src, nextra);
|
||||
} else {
|
||||
for (start = dst; (c = *src++) != '\0'; /* empty */)
|
||||
SVIS(dst, c, flag, *src, nextra);
|
||||
}
|
||||
*dst = '\0';
|
||||
return (dst - start);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
strsvisx(dst, csrc, len, flag, extra)
|
||||
char *dst;
|
||||
const char *csrc;
|
||||
size_t len;
|
||||
int flag;
|
||||
const char *extra;
|
||||
{
|
||||
int c;
|
||||
char *start;
|
||||
char *nextra;
|
||||
const unsigned char *src = (const unsigned char *)csrc;
|
||||
|
||||
_DIAGASSERT(dst != NULL);
|
||||
_DIAGASSERT(src != NULL);
|
||||
_DIAGASSERT(extra != NULL);
|
||||
MAKEEXTRALIST(flag, nextra, extra);
|
||||
|
||||
if (flag & VIS_HTTPSTYLE) {
|
||||
for (start = dst; len > 0; len--) {
|
||||
c = *src++;
|
||||
HVIS(dst, c, flag, len ? *src : '\0', nextra);
|
||||
}
|
||||
} else {
|
||||
for (start = dst; len > 0; len--) {
|
||||
c = *src++;
|
||||
SVIS(dst, c, flag, len ? *src : '\0', nextra);
|
||||
}
|
||||
}
|
||||
*dst = '\0';
|
||||
return (dst - start);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !HAVE_VIS
|
||||
/*
|
||||
* vis - visually encode characters
|
||||
*/
|
||||
char *
|
||||
vis(dst, c, flag, nextc)
|
||||
char *dst;
|
||||
int c, flag, nextc;
|
||||
|
||||
{
|
||||
char *extra;
|
||||
|
||||
_DIAGASSERT(dst != NULL);
|
||||
|
||||
MAKEEXTRALIST(flag, extra, "");
|
||||
if (flag & VIS_HTTPSTYLE)
|
||||
HVIS(dst, c, flag, nextc, extra);
|
||||
else
|
||||
SVIS(dst, c, flag, nextc, extra);
|
||||
*dst = '\0';
|
||||
return (dst);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* strvis, strvisx - visually encode characters from src into dst
|
||||
*
|
||||
* Dst must be 4 times the size of src to account for possible
|
||||
* expansion. The length of dst, not including the trailing NULL,
|
||||
* is returned.
|
||||
*
|
||||
* Strvisx encodes exactly len bytes from src into dst.
|
||||
* This is useful for encoding a block of data.
|
||||
*/
|
||||
int
|
||||
strvis(dst, src, flag)
|
||||
char *dst;
|
||||
const char *src;
|
||||
int flag;
|
||||
{
|
||||
char *extra;
|
||||
|
||||
MAKEEXTRALIST(flag, extra, "");
|
||||
return (strsvis(dst, src, flag, extra));
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
strvisx(dst, src, len, flag)
|
||||
char *dst;
|
||||
const char *src;
|
||||
size_t len;
|
||||
int flag;
|
||||
{
|
||||
char *extra;
|
||||
|
||||
MAKEEXTRALIST(flag, extra, "");
|
||||
return (strsvisx(dst, src, len, flag, extra));
|
||||
}
|
||||
#endif
|
94
compat/vis.h
Normal file
94
compat/vis.h
Normal file
@ -0,0 +1,94 @@
|
||||
/* $NetBSD: vis.h,v 1.14 2003/08/07 09:44:12 agc Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1990, 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.
|
||||
*
|
||||
* @(#)vis.h 8.1 (Berkeley) 6/2/93
|
||||
*/
|
||||
|
||||
#ifndef _VIS_H_
|
||||
#define _VIS_H_
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
/*
|
||||
* to select alternate encoding format
|
||||
*/
|
||||
#define VIS_OCTAL 0x01 /* use octal \ddd format */
|
||||
#define VIS_CSTYLE 0x02 /* use \[nrft0..] where appropiate */
|
||||
|
||||
/*
|
||||
* to alter set of characters encoded (default is to encode all
|
||||
* non-graphic except space, tab, and newline).
|
||||
*/
|
||||
#define VIS_SP 0x04 /* also encode space */
|
||||
#define VIS_TAB 0x08 /* also encode tab */
|
||||
#define VIS_NL 0x10 /* also encode newline */
|
||||
#define VIS_WHITE (VIS_SP | VIS_TAB | VIS_NL)
|
||||
#define VIS_SAFE 0x20 /* only encode "unsafe" characters */
|
||||
|
||||
/*
|
||||
* other
|
||||
*/
|
||||
#define VIS_NOSLASH 0x40 /* inhibit printing '\' */
|
||||
#define VIS_HTTPSTYLE 0x80 /* http-style escape % HEX HEX */
|
||||
|
||||
/*
|
||||
* unvis return codes
|
||||
*/
|
||||
#define UNVIS_VALID 1 /* character valid */
|
||||
#define UNVIS_VALIDPUSH 2 /* character valid, push back passed char */
|
||||
#define UNVIS_NOCHAR 3 /* valid sequence, no character produced */
|
||||
#define UNVIS_SYNBAD -1 /* unrecognized escape sequence */
|
||||
#define UNVIS_ERROR -2 /* decoder in unknown state (unrecoverable) */
|
||||
|
||||
/*
|
||||
* unvis flags
|
||||
*/
|
||||
#define UNVIS_END 1 /* no more characters */
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
char *vis __P((char *, int, int, int));
|
||||
char *svis __P((char *, int, int, int, const char *));
|
||||
int strvis __P((char *, const char *, int));
|
||||
int strsvis __P((char *, const char *, int, const char *));
|
||||
int strvisx __P((char *, const char *, size_t, int));
|
||||
int strsvisx __P((char *, const char *, size_t, int, const char *));
|
||||
int strunvis __P((char *, const char *));
|
||||
int strunvisx __P((char *, const char *, int));
|
||||
#ifdef __LIBC12_SOURCE__
|
||||
int unvis __P((char *, int, int *, int));
|
||||
int __unvis13 __P((char *, int, int *, int));
|
||||
#else
|
||||
int unvis __P((char *, int, int *, int)) __RENAME(__unvis13);
|
||||
#endif
|
||||
__END_DECLS
|
||||
|
||||
#endif /* !_VIS_H_ */
|
228
ffs/buf.c
Normal file
228
ffs/buf.c
Normal file
@ -0,0 +1,228 @@
|
||||
/* $NetBSD: buf.c,v 1.12 2004/06/20 22:20:18 jmc 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.12 2004/06/20 22:20:18 jmc 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 "makefs.h"
|
||||
|
||||
#include <ufs/ufs/dinode.h>
|
||||
#include <ufs/ffs/fs.h>
|
||||
|
||||
#include "ffs/buf.h"
|
||||
#include "ffs/ufs_inode.h"
|
||||
|
||||
extern int sectorsize; /* XXX: from ffs.c & mkfs.c */
|
||||
|
||||
TAILQ_HEAD(buftailhead,buf) buftail;
|
||||
|
||||
int
|
||||
bread(int fd, struct fs *fs, daddr_t blkno, int size, struct buf **bpp)
|
||||
{
|
||||
off_t offset;
|
||||
ssize_t rv;
|
||||
|
||||
assert (fs != NULL);
|
||||
assert (bpp != NULL);
|
||||
|
||||
if (debug & DEBUG_BUF_BREAD)
|
||||
printf("bread: fs %p blkno %lld size %d\n",
|
||||
fs, (long long)blkno, size);
|
||||
*bpp = getblk(fd, fs, blkno, size);
|
||||
offset = (*bpp)->b_blkno * sectorsize; /* XXX */
|
||||
if (debug & DEBUG_BUF_BREAD)
|
||||
printf("bread: bp %p blkno %lld offset %lld bcount %ld\n",
|
||||
(*bpp), (long long)(*bpp)->b_blkno, (long long) offset,
|
||||
(*bpp)->b_bcount);
|
||||
if (lseek((*bpp)->b_fd, offset, SEEK_SET) == -1)
|
||||
err(1, "bread: lseek %lld (%lld)",
|
||||
(long long)(*bpp)->b_blkno, (long long)offset);
|
||||
rv = read((*bpp)->b_fd, (*bpp)->b_data, (*bpp)->b_bcount);
|
||||
if (debug & DEBUG_BUF_BREAD)
|
||||
printf("bread: read %ld (%lld) returned %d\n",
|
||||
(*bpp)->b_bcount, (long long)offset, (int)rv);
|
||||
if (rv == -1) /* read error */
|
||||
err(1, "bread: read %ld (%lld) returned %d",
|
||||
(*bpp)->b_bcount, (long long)offset, (int)rv);
|
||||
else if (rv != (*bpp)->b_bcount) /* short read */
|
||||
err(1, "bread: read %ld (%lld) returned %d",
|
||||
(*bpp)->b_bcount, (long long)offset, (int)rv);
|
||||
else
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
brelse(struct buf *bp)
|
||||
{
|
||||
|
||||
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;
|
||||
|
||||
assert (bp != NULL);
|
||||
offset = bp->b_blkno * sectorsize; /* XXX */
|
||||
if (debug & DEBUG_BUF_BWRITE)
|
||||
printf("bwrite: bp %p blkno %lld offset %lld bcount %ld\n",
|
||||
bp, (long long)bp->b_blkno, (long long) offset,
|
||||
bp->b_bcount);
|
||||
if (lseek(bp->b_fd, offset, SEEK_SET) == -1)
|
||||
return (errno);
|
||||
rv = write(bp->b_fd, bp->b_data, bp->b_bcount);
|
||||
if (debug & DEBUG_BUF_BWRITE)
|
||||
printf("bwrite: write %ld (offset %lld) returned %lld\n",
|
||||
bp->b_bcount, (long long)offset, (long long)rv);
|
||||
if (rv == bp->b_bcount)
|
||||
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(int fd, struct fs *fs, daddr_t blkno, int size)
|
||||
{
|
||||
static int buftailinitted;
|
||||
struct buf *bp;
|
||||
void *n;
|
||||
|
||||
assert (fs != NULL);
|
||||
if (debug & DEBUG_BUF_GETBLK)
|
||||
printf("getblk: fs %p blkno %lld size %d\n", fs,
|
||||
(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) {
|
||||
if ((bp = calloc(1, sizeof(struct buf))) == NULL)
|
||||
err(1, "getblk: calloc");
|
||||
|
||||
bp->b_bufsize = 0;
|
||||
bp->b_blkno = bp->b_lblkno = blkno;
|
||||
bp->b_fd = fd;
|
||||
bp->b_fs = 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 = realloc(bp->b_data, size);
|
||||
if (n == NULL)
|
||||
err(1, "getblk: realloc b_data %ld", bp->b_bcount);
|
||||
bp->b_data = n;
|
||||
bp->b_bufsize = size;
|
||||
}
|
||||
|
||||
return (bp);
|
||||
}
|
65
ffs/buf.h
Normal file
65
ffs/buf.h
Normal file
@ -0,0 +1,65 @@
|
||||
/* $NetBSD: buf.h,v 1.2 2001/11/02 03:12:49 lukem 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>
|
||||
|
||||
struct buf {
|
||||
void * b_data;
|
||||
long b_bufsize;
|
||||
long b_bcount;
|
||||
daddr_t b_blkno;
|
||||
daddr_t b_lblkno;
|
||||
int b_fd;
|
||||
struct fs * b_fs;
|
||||
|
||||
TAILQ_ENTRY(buf) b_tailq;
|
||||
};
|
||||
|
||||
void bcleanup(void);
|
||||
int bread(int, struct fs *, daddr_t, int, struct buf **);
|
||||
void brelse(struct buf *);
|
||||
int bwrite(struct buf *);
|
||||
struct buf * getblk(int, struct fs *, daddr_t, int);
|
||||
|
||||
#define bdwrite(bp) bwrite(bp)
|
||||
#define clrbuf(bp) memset((bp)->b_data, 0, (u_int)(bp)->b_bcount)
|
||||
|
||||
#endif /* _FFS_BUF_H */
|
694
ffs/ffs_alloc.c
Normal file
694
ffs/ffs_alloc.c
Normal file
@ -0,0 +1,694 @@
|
||||
/* $NetBSD: ffs_alloc.c,v 1.14 2004/06/20 22:20:18 jmc 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.14 2004/06/20 22:20:18 jmc 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, daddr_t bpref, int size,
|
||||
daddr_t *bnp)
|
||||
{
|
||||
struct fs *fs = ip->i_fs;
|
||||
daddr_t bno;
|
||||
int cg;
|
||||
|
||||
*bnp = 0;
|
||||
if ((u_int)size > fs->fs_bsize || 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) {
|
||||
if (ip->i_fs->fs_magic == FS_UFS1_MAGIC)
|
||||
ip->i_ffs1_blocks += size / DEV_BSIZE;
|
||||
else
|
||||
ip->i_ffs2_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 < NDADDR + 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(ip, lbn, indx, bap)
|
||||
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 < NDADDR + 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_fd, ip->i_fs, fsbtodb(fs, cgtod(fs, cg)),
|
||||
(int)fs->fs_cgsize, &bp);
|
||||
if (error) {
|
||||
brelse(bp);
|
||||
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);
|
||||
return (0);
|
||||
}
|
||||
if (size == fs->fs_bsize) {
|
||||
bno = ffs_alloccgblk(ip, bp, bpref);
|
||||
bdwrite(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 = 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);
|
||||
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 = blknum(fs, bpref);
|
||||
bno = dtogd(fs, bpref);
|
||||
/*
|
||||
* if the requested block is available, use it
|
||||
*/
|
||||
if (ffs_isblock(fs, blksfree, 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 = 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 ((u_int)size > fs->fs_bsize || fragoff(fs, size) != 0 ||
|
||||
fragnum(fs, bno) + 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 %d", (long long)bno, ip->i_number);
|
||||
return;
|
||||
}
|
||||
error = bread(ip->i_fd, ip->i_fs, fsbtodb(fs, cgtod(fs, cg)),
|
||||
(int)fs->fs_cgsize, &bp);
|
||||
if (error) {
|
||||
brelse(bp);
|
||||
return;
|
||||
}
|
||||
cgp = (struct cg *)bp->b_data;
|
||||
if (!cg_chkmagic(cgp, needswap)) {
|
||||
brelse(bp);
|
||||
return;
|
||||
}
|
||||
cgbno = dtogd(fs, bno);
|
||||
if (size == fs->fs_bsize) {
|
||||
fragno = 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 - 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 = 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 = 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);
|
||||
}
|
||||
|
||||
/*
|
||||
* Update the cluster map because of an allocation or free.
|
||||
*
|
||||
* Cnt == 1 means free; cnt == -1 means allocating.
|
||||
*/
|
||||
void
|
||||
ffs_clusteracct(struct fs *fs, struct cg *cgp, int32_t blkno, int cnt)
|
||||
{
|
||||
int32_t *sump;
|
||||
int32_t *lp;
|
||||
u_char *freemapp, *mapp;
|
||||
int i, start, end, forw, back, map, bit;
|
||||
const int needswap = UFS_FSNEEDSWAP(fs);
|
||||
|
||||
if (fs->fs_contigsumsize <= 0)
|
||||
return;
|
||||
freemapp = cg_clustersfree(cgp, needswap);
|
||||
sump = cg_clustersum(cgp, needswap);
|
||||
/*
|
||||
* Allocate or clear the actual block.
|
||||
*/
|
||||
if (cnt > 0)
|
||||
setbit(freemapp, blkno);
|
||||
else
|
||||
clrbit(freemapp, blkno);
|
||||
/*
|
||||
* Find the size of the cluster going forward.
|
||||
*/
|
||||
start = blkno + 1;
|
||||
end = start + fs->fs_contigsumsize;
|
||||
if (end >= ufs_rw32(cgp->cg_nclusterblks, needswap))
|
||||
end = ufs_rw32(cgp->cg_nclusterblks, needswap);
|
||||
mapp = &freemapp[start / NBBY];
|
||||
map = *mapp++;
|
||||
bit = 1 << (start % NBBY);
|
||||
for (i = start; i < end; i++) {
|
||||
if ((map & bit) == 0)
|
||||
break;
|
||||
if ((i & (NBBY - 1)) != (NBBY - 1)) {
|
||||
bit <<= 1;
|
||||
} else {
|
||||
map = *mapp++;
|
||||
bit = 1;
|
||||
}
|
||||
}
|
||||
forw = i - start;
|
||||
/*
|
||||
* Find the size of the cluster going backward.
|
||||
*/
|
||||
start = blkno - 1;
|
||||
end = start - fs->fs_contigsumsize;
|
||||
if (end < 0)
|
||||
end = -1;
|
||||
mapp = &freemapp[start / NBBY];
|
||||
map = *mapp--;
|
||||
bit = 1 << (start % NBBY);
|
||||
for (i = start; i > end; i--) {
|
||||
if ((map & bit) == 0)
|
||||
break;
|
||||
if ((i & (NBBY - 1)) != 0) {
|
||||
bit >>= 1;
|
||||
} else {
|
||||
map = *mapp--;
|
||||
bit = 1 << (NBBY - 1);
|
||||
}
|
||||
}
|
||||
back = start - i;
|
||||
/*
|
||||
* Account for old cluster and the possibly new forward and
|
||||
* back clusters.
|
||||
*/
|
||||
i = back + forw + 1;
|
||||
if (i > fs->fs_contigsumsize)
|
||||
i = fs->fs_contigsumsize;
|
||||
ufs_add32(sump[i], cnt, needswap);
|
||||
if (back > 0)
|
||||
ufs_add32(sump[back], -cnt, needswap);
|
||||
if (forw > 0)
|
||||
ufs_add32(sump[forw], -cnt, needswap);
|
||||
|
||||
/*
|
||||
* Update cluster summary information.
|
||||
*/
|
||||
lp = &sump[fs->fs_contigsumsize];
|
||||
for (i = fs->fs_contigsumsize; i > 0; i--)
|
||||
if (ufs_rw32(*lp--, needswap) > 0)
|
||||
break;
|
||||
fs->fs_maxcluster[ufs_rw32(cgp->cg_cgx, needswap)] = i;
|
||||
}
|
584
ffs/ffs_balloc.c
Normal file
584
ffs/ffs_balloc.c
Normal file
@ -0,0 +1,584 @@
|
||||
/* $NetBSD: ffs_balloc.c,v 1.13 2004/06/20 22:20:18 jmc 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.13 2004/06/20 22:20:18 jmc 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[NIADDR + 2];
|
||||
daddr_t newb, pref;
|
||||
int32_t *bap;
|
||||
int osize, nsize, num, i, error;
|
||||
int32_t *allocblk, allociblk[NIADDR + 1];
|
||||
int32_t *allocib;
|
||||
const int needswap = UFS_FSNEEDSWAP(fs);
|
||||
|
||||
lbn = lblkno(fs, offset);
|
||||
size = 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 = lblkno(fs, ip->i_ffs1_size);
|
||||
if (lastlbn < NDADDR && lastlbn < lbn) {
|
||||
nb = lastlbn;
|
||||
osize = blksize(fs, ip, nb);
|
||||
if (osize < fs->fs_bsize && osize > 0) {
|
||||
warnx("need to ffs_realloccg; not supported!");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The first NDADDR blocks are direct blocks
|
||||
*/
|
||||
|
||||
if (lbn < NDADDR) {
|
||||
nb = ufs_rw32(ip->i_ffs1_db[lbn], needswap);
|
||||
if (nb != 0 && ip->i_ffs1_size >= 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_fd, ip->i_fs, lbn,
|
||||
fs->fs_bsize, bpp);
|
||||
if (error) {
|
||||
brelse(*bpp);
|
||||
return (error);
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
if (nb != 0) {
|
||||
|
||||
/*
|
||||
* Consider need to reallocate a fragment.
|
||||
*/
|
||||
|
||||
osize = fragroundup(fs, blkoff(fs, ip->i_ffs1_size));
|
||||
nsize = 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_fd, ip->i_fs, lbn,
|
||||
osize, bpp);
|
||||
if (error) {
|
||||
brelse(*bpp);
|
||||
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 < lblktosize(fs, lbn + 1))
|
||||
nsize = 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_fd, ip->i_fs, lbn, nsize);
|
||||
bp->b_blkno = 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_fd, ip->i_fs, indirs[1].in_lbn, fs->fs_bsize);
|
||||
bp->b_blkno = 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_fd, ip->i_fs, indirs[i].in_lbn,
|
||||
fs->fs_bsize, &bp);
|
||||
if (error) {
|
||||
brelse(bp);
|
||||
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);
|
||||
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);
|
||||
return error;
|
||||
}
|
||||
nb = newb;
|
||||
*allocblk++ = nb;
|
||||
nbp = getblk(ip->i_fd, ip->i_fs, indirs[i].in_lbn,
|
||||
fs->fs_bsize);
|
||||
nbp->b_blkno = fsbtodb(fs, nb);
|
||||
clrbuf(nbp);
|
||||
/*
|
||||
* Write synchronously so that indirect blocks
|
||||
* never point at garbage.
|
||||
*/
|
||||
|
||||
if ((error = bwrite(nbp)) != 0) {
|
||||
brelse(bp);
|
||||
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);
|
||||
return error;
|
||||
}
|
||||
nb = newb;
|
||||
*allocblk++ = nb;
|
||||
if (bpp != NULL) {
|
||||
nbp = getblk(ip->i_fd, ip->i_fs, lbn, fs->fs_bsize);
|
||||
nbp->b_blkno = 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);
|
||||
if (bpp != NULL) {
|
||||
error = bread(ip->i_fd, ip->i_fs, lbn, (int)fs->fs_bsize, &nbp);
|
||||
if (error) {
|
||||
brelse(nbp);
|
||||
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[NIADDR + 2];
|
||||
daddr_t newb, pref, nb;
|
||||
int64_t *bap;
|
||||
int osize, nsize, num, i, error;
|
||||
int64_t *allocblk, allociblk[NIADDR + 1];
|
||||
int64_t *allocib;
|
||||
const int needswap = UFS_FSNEEDSWAP(fs);
|
||||
|
||||
lbn = lblkno(fs, offset);
|
||||
size = 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 = lblkno(fs, ip->i_ffs2_size);
|
||||
if (lastlbn < NDADDR && lastlbn < lbn) {
|
||||
nb = lastlbn;
|
||||
osize = blksize(fs, ip, nb);
|
||||
if (osize < fs->fs_bsize && osize > 0) {
|
||||
warnx("need to ffs_realloccg; not supported!");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The first NDADDR blocks are direct blocks
|
||||
*/
|
||||
|
||||
if (lbn < NDADDR) {
|
||||
nb = ufs_rw64(ip->i_ffs2_db[lbn], needswap);
|
||||
if (nb != 0 && ip->i_ffs2_size >= 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_fd, ip->i_fs, lbn,
|
||||
fs->fs_bsize, bpp);
|
||||
if (error) {
|
||||
brelse(*bpp);
|
||||
return (error);
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
if (nb != 0) {
|
||||
|
||||
/*
|
||||
* Consider need to reallocate a fragment.
|
||||
*/
|
||||
|
||||
osize = fragroundup(fs, blkoff(fs, ip->i_ffs2_size));
|
||||
nsize = 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_fd, ip->i_fs, lbn,
|
||||
osize, bpp);
|
||||
if (error) {
|
||||
brelse(*bpp);
|
||||
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 < lblktosize(fs, lbn + 1))
|
||||
nsize = 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_fd, ip->i_fs, lbn, nsize);
|
||||
bp->b_blkno = 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_fd, ip->i_fs, indirs[1].in_lbn, fs->fs_bsize);
|
||||
bp->b_blkno = 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_fd, ip->i_fs, indirs[i].in_lbn,
|
||||
fs->fs_bsize, &bp);
|
||||
if (error) {
|
||||
brelse(bp);
|
||||
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);
|
||||
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);
|
||||
return error;
|
||||
}
|
||||
nb = newb;
|
||||
*allocblk++ = nb;
|
||||
nbp = getblk(ip->i_fd, ip->i_fs, indirs[i].in_lbn,
|
||||
fs->fs_bsize);
|
||||
nbp->b_blkno = fsbtodb(fs, nb);
|
||||
clrbuf(nbp);
|
||||
/*
|
||||
* Write synchronously so that indirect blocks
|
||||
* never point at garbage.
|
||||
*/
|
||||
|
||||
if ((error = bwrite(nbp)) != 0) {
|
||||
brelse(bp);
|
||||
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);
|
||||
return error;
|
||||
}
|
||||
nb = newb;
|
||||
*allocblk++ = nb;
|
||||
if (bpp != NULL) {
|
||||
nbp = getblk(ip->i_fd, ip->i_fs, lbn, fs->fs_bsize);
|
||||
nbp->b_blkno = 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);
|
||||
if (bpp != NULL) {
|
||||
error = bread(ip->i_fd, ip->i_fs, lbn, (int)fs->fs_bsize, &nbp);
|
||||
if (error) {
|
||||
brelse(nbp);
|
||||
return error;
|
||||
}
|
||||
*bpp = nbp;
|
||||
}
|
||||
return (0);
|
||||
}
|
76
ffs/ffs_extern.h
Normal file
76
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 *);
|
846
ffs/mkfs.c
Normal file
846
ffs/mkfs.c
Normal file
@ -0,0 +1,846 @@
|
||||
/* $NetBSD: mkfs.c,v 1.20 2004/06/24 22:30:13 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) 1980, 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.
|
||||
*/
|
||||
|
||||
#if HAVE_NBTOOL_CONFIG_H
|
||||
#include "nbtool_config.h"
|
||||
#endif
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)mkfs.c 8.11 (Berkeley) 5/3/95";
|
||||
#else
|
||||
#ifdef __RCSID
|
||||
__RCSID("$NetBSD: mkfs.c,v 1.20 2004/06/24 22:30:13 lukem Exp $");
|
||||
#endif
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.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/ufs_inode.h"
|
||||
#include "ffs/ffs_extern.h"
|
||||
#include "ffs/newfs_extern.h"
|
||||
|
||||
static void initcg(int, time_t, const fsinfo_t *);
|
||||
static int ilog2(int);
|
||||
|
||||
static int count_digits(int);
|
||||
|
||||
/*
|
||||
* make file system for cylinder-group style file systems
|
||||
*/
|
||||
#define UMASK 0755
|
||||
#define POWEROF2(num) (((num) & ((num) - 1)) == 0)
|
||||
|
||||
union {
|
||||
struct fs fs;
|
||||
char pad[SBLOCKSIZE];
|
||||
} fsun;
|
||||
#define sblock fsun.fs
|
||||
struct csum *fscs;
|
||||
|
||||
union {
|
||||
struct cg cg;
|
||||
char pad[FFS_MAXBSIZE];
|
||||
} cgun;
|
||||
#define acg cgun.cg
|
||||
|
||||
char *iobuf;
|
||||
int iobufsize;
|
||||
|
||||
char writebuf[FFS_MAXBSIZE];
|
||||
|
||||
static int Oflag; /* format as an 4.3BSD file system */
|
||||
static int64_t fssize; /* file system size */
|
||||
static int sectorsize; /* bytes/sector */
|
||||
static int fsize; /* fragment size */
|
||||
static int bsize; /* block size */
|
||||
static int maxbsize; /* maximum clustering */
|
||||
static int maxblkspercg;
|
||||
static int minfree; /* free space threshold */
|
||||
static int opt; /* optimization preference (space or time) */
|
||||
static int density; /* number of bytes per inode */
|
||||
static int maxcontig; /* max contiguous blocks to allocate */
|
||||
static int maxbpg; /* maximum blocks per file in a cyl group */
|
||||
static int bbsize; /* boot block size */
|
||||
static int sbsize; /* superblock size */
|
||||
static int avgfilesize; /* expected average file size */
|
||||
static int avgfpdir; /* expected number of files per directory */
|
||||
|
||||
struct fs *
|
||||
ffs_mkfs(const char *fsys, const fsinfo_t *fsopts)
|
||||
{
|
||||
int fragsperinode, optimalfpg, origdensity, minfpg, lastminfpg;
|
||||
int32_t cylno, i, csfrags;
|
||||
long long sizepb;
|
||||
void *space;
|
||||
int size, blks;
|
||||
int nprintcols, printcolwidth;
|
||||
|
||||
Oflag = fsopts->version;
|
||||
fssize = fsopts->size / fsopts->sectorsize;
|
||||
sectorsize = fsopts->sectorsize;
|
||||
fsize = fsopts->fsize;
|
||||
bsize = fsopts->bsize;
|
||||
maxbsize = fsopts->maxbsize;
|
||||
maxblkspercg = fsopts->maxblkspercg;
|
||||
minfree = fsopts->minfree;
|
||||
opt = fsopts->optimization;
|
||||
density = fsopts->density;
|
||||
maxcontig = fsopts->maxcontig;
|
||||
maxbpg = fsopts->maxbpg;
|
||||
avgfilesize = fsopts->avgfilesize;
|
||||
avgfpdir = fsopts->avgfpdir;
|
||||
bbsize = BBSIZE;
|
||||
sbsize = SBLOCKSIZE;
|
||||
|
||||
if (Oflag == 0) {
|
||||
sblock.fs_old_inodefmt = FS_42INODEFMT;
|
||||
sblock.fs_maxsymlinklen = 0;
|
||||
sblock.fs_old_flags = 0;
|
||||
} else {
|
||||
sblock.fs_old_inodefmt = FS_44INODEFMT;
|
||||
sblock.fs_maxsymlinklen = (Oflag == 1 ? MAXSYMLINKLEN_UFS1 :
|
||||
MAXSYMLINKLEN_UFS2);
|
||||
sblock.fs_old_flags = FS_FLAGS_UPDATED;
|
||||
sblock.fs_flags = 0;
|
||||
}
|
||||
/*
|
||||
* Validate the given file system size.
|
||||
* Verify that its last block can actually be accessed.
|
||||
* Convert to file system fragment sized units.
|
||||
*/
|
||||
if (fssize <= 0) {
|
||||
printf("preposterous size %lld\n", (long long)fssize);
|
||||
exit(13);
|
||||
}
|
||||
ffs_wtfs(fssize - 1, sectorsize, (char *)&sblock, fsopts);
|
||||
|
||||
/*
|
||||
* collect and verify the filesystem density info
|
||||
*/
|
||||
sblock.fs_avgfilesize = avgfilesize;
|
||||
sblock.fs_avgfpdir = avgfpdir;
|
||||
if (sblock.fs_avgfilesize <= 0)
|
||||
printf("illegal expected average file size %d\n",
|
||||
sblock.fs_avgfilesize), exit(14);
|
||||
if (sblock.fs_avgfpdir <= 0)
|
||||
printf("illegal expected number of files per directory %d\n",
|
||||
sblock.fs_avgfpdir), exit(15);
|
||||
/*
|
||||
* collect and verify the block and fragment sizes
|
||||
*/
|
||||
sblock.fs_bsize = bsize;
|
||||
sblock.fs_fsize = fsize;
|
||||
if (!POWEROF2(sblock.fs_bsize)) {
|
||||
printf("block size must be a power of 2, not %d\n",
|
||||
sblock.fs_bsize);
|
||||
exit(16);
|
||||
}
|
||||
if (!POWEROF2(sblock.fs_fsize)) {
|
||||
printf("fragment size must be a power of 2, not %d\n",
|
||||
sblock.fs_fsize);
|
||||
exit(17);
|
||||
}
|
||||
if (sblock.fs_fsize < sectorsize) {
|
||||
printf("fragment size %d is too small, minimum is %d\n",
|
||||
sblock.fs_fsize, sectorsize);
|
||||
exit(18);
|
||||
}
|
||||
if (sblock.fs_bsize < MINBSIZE) {
|
||||
printf("block size %d is too small, minimum is %d\n",
|
||||
sblock.fs_bsize, MINBSIZE);
|
||||
exit(19);
|
||||
}
|
||||
if (sblock.fs_bsize > FFS_MAXBSIZE) {
|
||||
printf("block size %d is too large, maximum is %d\n",
|
||||
sblock.fs_bsize, FFS_MAXBSIZE);
|
||||
exit(19);
|
||||
}
|
||||
if (sblock.fs_bsize < sblock.fs_fsize) {
|
||||
printf("block size (%d) cannot be smaller than fragment size (%d)\n",
|
||||
sblock.fs_bsize, sblock.fs_fsize);
|
||||
exit(20);
|
||||
}
|
||||
|
||||
if (maxbsize < bsize || !POWEROF2(maxbsize)) {
|
||||
sblock.fs_maxbsize = sblock.fs_bsize;
|
||||
printf("Extent size set to %d\n", sblock.fs_maxbsize);
|
||||
} else if (sblock.fs_maxbsize > FS_MAXCONTIG * sblock.fs_bsize) {
|
||||
sblock.fs_maxbsize = FS_MAXCONTIG * sblock.fs_bsize;
|
||||
printf("Extent size reduced to %d\n", sblock.fs_maxbsize);
|
||||
} else {
|
||||
sblock.fs_maxbsize = maxbsize;
|
||||
}
|
||||
sblock.fs_maxcontig = maxcontig;
|
||||
if (sblock.fs_maxcontig < sblock.fs_maxbsize / sblock.fs_bsize) {
|
||||
sblock.fs_maxcontig = sblock.fs_maxbsize / sblock.fs_bsize;
|
||||
printf("Maxcontig raised to %d\n", sblock.fs_maxbsize);
|
||||
}
|
||||
|
||||
if (sblock.fs_maxcontig > 1)
|
||||
sblock.fs_contigsumsize = MIN(sblock.fs_maxcontig,FS_MAXCONTIG);
|
||||
|
||||
sblock.fs_bmask = ~(sblock.fs_bsize - 1);
|
||||
sblock.fs_fmask = ~(sblock.fs_fsize - 1);
|
||||
sblock.fs_qbmask = ~sblock.fs_bmask;
|
||||
sblock.fs_qfmask = ~sblock.fs_fmask;
|
||||
for (sblock.fs_bshift = 0, i = sblock.fs_bsize; i > 1; i >>= 1)
|
||||
sblock.fs_bshift++;
|
||||
for (sblock.fs_fshift = 0, i = sblock.fs_fsize; i > 1; i >>= 1)
|
||||
sblock.fs_fshift++;
|
||||
sblock.fs_frag = numfrags(&sblock, sblock.fs_bsize);
|
||||
for (sblock.fs_fragshift = 0, i = sblock.fs_frag; i > 1; i >>= 1)
|
||||
sblock.fs_fragshift++;
|
||||
if (sblock.fs_frag > MAXFRAG) {
|
||||
printf("fragment size %d is too small, "
|
||||
"minimum with block size %d is %d\n",
|
||||
sblock.fs_fsize, sblock.fs_bsize,
|
||||
sblock.fs_bsize / MAXFRAG);
|
||||
exit(21);
|
||||
}
|
||||
sblock.fs_fsbtodb = ilog2(sblock.fs_fsize / sectorsize);
|
||||
sblock.fs_size = fssize = dbtofsb(&sblock, fssize);
|
||||
|
||||
if (Oflag <= 1) {
|
||||
sblock.fs_magic = FS_UFS1_MAGIC;
|
||||
sblock.fs_sblockloc = SBLOCK_UFS1;
|
||||
sblock.fs_nindir = sblock.fs_bsize / sizeof(int32_t);
|
||||
sblock.fs_inopb = sblock.fs_bsize / sizeof(struct ufs1_dinode);
|
||||
sblock.fs_maxsymlinklen = ((NDADDR + NIADDR) *
|
||||
sizeof (int32_t));
|
||||
sblock.fs_old_inodefmt = FS_44INODEFMT;
|
||||
sblock.fs_old_cgoffset = 0;
|
||||
sblock.fs_old_cgmask = 0xffffffff;
|
||||
sblock.fs_old_size = sblock.fs_size;
|
||||
sblock.fs_old_rotdelay = 0;
|
||||
sblock.fs_old_rps = 60;
|
||||
sblock.fs_old_nspf = sblock.fs_fsize / sectorsize;
|
||||
sblock.fs_old_cpg = 1;
|
||||
sblock.fs_old_interleave = 1;
|
||||
sblock.fs_old_trackskew = 0;
|
||||
sblock.fs_old_cpc = 0;
|
||||
sblock.fs_old_postblformat = 1;
|
||||
sblock.fs_old_nrpos = 1;
|
||||
} else {
|
||||
sblock.fs_magic = FS_UFS2_MAGIC;
|
||||
#if 0 /* XXX makefs is used for small filesystems. */
|
||||
sblock.fs_sblockloc = SBLOCK_UFS2;
|
||||
#else
|
||||
sblock.fs_sblockloc = SBLOCK_UFS1;
|
||||
#endif
|
||||
sblock.fs_nindir = sblock.fs_bsize / sizeof(int64_t);
|
||||
sblock.fs_inopb = sblock.fs_bsize / sizeof(struct ufs2_dinode);
|
||||
sblock.fs_maxsymlinklen = ((NDADDR + NIADDR) *
|
||||
sizeof (int64_t));
|
||||
}
|
||||
|
||||
sblock.fs_sblkno =
|
||||
roundup(howmany(sblock.fs_sblockloc + SBLOCKSIZE, sblock.fs_fsize),
|
||||
sblock.fs_frag);
|
||||
sblock.fs_cblkno = (daddr_t)(sblock.fs_sblkno +
|
||||
roundup(howmany(SBLOCKSIZE, sblock.fs_fsize), sblock.fs_frag));
|
||||
sblock.fs_iblkno = sblock.fs_cblkno + sblock.fs_frag;
|
||||
sblock.fs_maxfilesize = sblock.fs_bsize * NDADDR - 1;
|
||||
for (sizepb = sblock.fs_bsize, i = 0; i < NIADDR; i++) {
|
||||
sizepb *= NINDIR(&sblock);
|
||||
sblock.fs_maxfilesize += sizepb;
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate the number of blocks to put into each cylinder group.
|
||||
*
|
||||
* This algorithm selects the number of blocks per cylinder
|
||||
* group. The first goal is to have at least enough data blocks
|
||||
* in each cylinder group to meet the density requirement. Once
|
||||
* this goal is achieved we try to expand to have at least
|
||||
* 1 cylinder group. Once this goal is achieved, we pack as
|
||||
* many blocks into each cylinder group map as will fit.
|
||||
*
|
||||
* We start by calculating the smallest number of blocks that we
|
||||
* can put into each cylinder group. If this is too big, we reduce
|
||||
* the density until it fits.
|
||||
*/
|
||||
origdensity = density;
|
||||
for (;;) {
|
||||
fragsperinode = MAX(numfrags(&sblock, density), 1);
|
||||
minfpg = fragsperinode * INOPB(&sblock);
|
||||
if (minfpg > sblock.fs_size)
|
||||
minfpg = sblock.fs_size;
|
||||
sblock.fs_ipg = INOPB(&sblock);
|
||||
sblock.fs_fpg = roundup(sblock.fs_iblkno +
|
||||
sblock.fs_ipg / INOPF(&sblock), sblock.fs_frag);
|
||||
if (sblock.fs_fpg < minfpg)
|
||||
sblock.fs_fpg = minfpg;
|
||||
sblock.fs_ipg = roundup(howmany(sblock.fs_fpg, fragsperinode),
|
||||
INOPB(&sblock));
|
||||
sblock.fs_fpg = roundup(sblock.fs_iblkno +
|
||||
sblock.fs_ipg / INOPF(&sblock), sblock.fs_frag);
|
||||
if (sblock.fs_fpg < minfpg)
|
||||
sblock.fs_fpg = minfpg;
|
||||
sblock.fs_ipg = roundup(howmany(sblock.fs_fpg, fragsperinode),
|
||||
INOPB(&sblock));
|
||||
if (CGSIZE(&sblock) < (unsigned long)sblock.fs_bsize)
|
||||
break;
|
||||
density -= sblock.fs_fsize;
|
||||
}
|
||||
if (density != origdensity)
|
||||
printf("density reduced from %d to %d\n", origdensity, density);
|
||||
|
||||
if (maxblkspercg <= 0 || maxblkspercg >= fssize)
|
||||
maxblkspercg = fssize - 1;
|
||||
/*
|
||||
* Start packing more blocks into the cylinder group until
|
||||
* it cannot grow any larger, the number of cylinder groups
|
||||
* drops below 1, or we reach the size requested.
|
||||
*/
|
||||
for ( ; sblock.fs_fpg < maxblkspercg; sblock.fs_fpg += sblock.fs_frag) {
|
||||
sblock.fs_ipg = roundup(howmany(sblock.fs_fpg, fragsperinode),
|
||||
INOPB(&sblock));
|
||||
if (sblock.fs_size / sblock.fs_fpg < 1)
|
||||
break;
|
||||
if (CGSIZE(&sblock) < (unsigned long)sblock.fs_bsize)
|
||||
continue;
|
||||
if (CGSIZE(&sblock) == (unsigned long)sblock.fs_bsize)
|
||||
break;
|
||||
sblock.fs_fpg -= sblock.fs_frag;
|
||||
sblock.fs_ipg = roundup(howmany(sblock.fs_fpg, fragsperinode),
|
||||
INOPB(&sblock));
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* Check to be sure that the last cylinder group has enough blocks
|
||||
* to be viable. If it is too small, reduce the number of blocks
|
||||
* per cylinder group which will have the effect of moving more
|
||||
* blocks into the last cylinder group.
|
||||
*/
|
||||
optimalfpg = sblock.fs_fpg;
|
||||
for (;;) {
|
||||
sblock.fs_ncg = howmany(sblock.fs_size, sblock.fs_fpg);
|
||||
lastminfpg = roundup(sblock.fs_iblkno +
|
||||
sblock.fs_ipg / INOPF(&sblock), sblock.fs_frag);
|
||||
if (sblock.fs_size < lastminfpg) {
|
||||
printf("Filesystem size %lld < minimum size of %d\n",
|
||||
(long long)sblock.fs_size, lastminfpg);
|
||||
exit(28);
|
||||
}
|
||||
if (sblock.fs_size % sblock.fs_fpg >= lastminfpg ||
|
||||
sblock.fs_size % sblock.fs_fpg == 0)
|
||||
break;
|
||||
sblock.fs_fpg -= sblock.fs_frag;
|
||||
sblock.fs_ipg = roundup(howmany(sblock.fs_fpg, fragsperinode),
|
||||
INOPB(&sblock));
|
||||
}
|
||||
if (optimalfpg != sblock.fs_fpg)
|
||||
printf("Reduced frags per cylinder group from %d to %d %s\n",
|
||||
optimalfpg, sblock.fs_fpg, "to enlarge last cyl group");
|
||||
sblock.fs_cgsize = fragroundup(&sblock, CGSIZE(&sblock));
|
||||
sblock.fs_dblkno = sblock.fs_iblkno + sblock.fs_ipg / INOPF(&sblock);
|
||||
if (Oflag <= 1) {
|
||||
sblock.fs_old_spc = sblock.fs_fpg * sblock.fs_old_nspf;
|
||||
sblock.fs_old_nsect = sblock.fs_old_spc;
|
||||
sblock.fs_old_npsect = sblock.fs_old_spc;
|
||||
sblock.fs_old_ncyl = sblock.fs_ncg;
|
||||
}
|
||||
|
||||
/*
|
||||
* fill in remaining fields of the super block
|
||||
*/
|
||||
sblock.fs_csaddr = cgdmin(&sblock, 0);
|
||||
sblock.fs_cssize =
|
||||
fragroundup(&sblock, sblock.fs_ncg * sizeof(struct csum));
|
||||
|
||||
/*
|
||||
* Setup memory for temporary in-core cylgroup summaries.
|
||||
* Cribbed from ffs_mountfs().
|
||||
*/
|
||||
size = sblock.fs_cssize;
|
||||
blks = howmany(size, sblock.fs_fsize);
|
||||
if (sblock.fs_contigsumsize > 0)
|
||||
size += sblock.fs_ncg * sizeof(int32_t);
|
||||
if ((space = (char *)calloc(1, size)) == NULL)
|
||||
err(1, "memory allocation error for cg summaries");
|
||||
sblock.fs_csp = space;
|
||||
space = (char *)space + sblock.fs_cssize;
|
||||
if (sblock.fs_contigsumsize > 0) {
|
||||
int32_t *lp;
|
||||
|
||||
sblock.fs_maxcluster = lp = space;
|
||||
for (i = 0; i < sblock.fs_ncg; i++)
|
||||
*lp++ = sblock.fs_contigsumsize;
|
||||
}
|
||||
|
||||
sblock.fs_sbsize = fragroundup(&sblock, sizeof(struct fs));
|
||||
if (sblock.fs_sbsize > SBLOCKSIZE)
|
||||
sblock.fs_sbsize = SBLOCKSIZE;
|
||||
sblock.fs_minfree = minfree;
|
||||
sblock.fs_maxcontig = maxcontig;
|
||||
sblock.fs_maxbpg = maxbpg;
|
||||
sblock.fs_optim = opt;
|
||||
sblock.fs_cgrotor = 0;
|
||||
sblock.fs_pendingblocks = 0;
|
||||
sblock.fs_pendinginodes = 0;
|
||||
sblock.fs_cstotal.cs_ndir = 0;
|
||||
sblock.fs_cstotal.cs_nbfree = 0;
|
||||
sblock.fs_cstotal.cs_nifree = 0;
|
||||
sblock.fs_cstotal.cs_nffree = 0;
|
||||
sblock.fs_fmod = 0;
|
||||
sblock.fs_ronly = 0;
|
||||
sblock.fs_state = 0;
|
||||
sblock.fs_clean = FS_ISCLEAN;
|
||||
sblock.fs_ronly = 0;
|
||||
sblock.fs_id[0] = start_time.tv_sec;
|
||||
sblock.fs_id[1] = random();
|
||||
sblock.fs_fsmnt[0] = '\0';
|
||||
csfrags = howmany(sblock.fs_cssize, sblock.fs_fsize);
|
||||
sblock.fs_dsize = sblock.fs_size - sblock.fs_sblkno -
|
||||
sblock.fs_ncg * (sblock.fs_dblkno - sblock.fs_sblkno);
|
||||
sblock.fs_cstotal.cs_nbfree =
|
||||
fragstoblks(&sblock, sblock.fs_dsize) -
|
||||
howmany(csfrags, sblock.fs_frag);
|
||||
sblock.fs_cstotal.cs_nffree =
|
||||
fragnum(&sblock, sblock.fs_size) +
|
||||
(fragnum(&sblock, csfrags) > 0 ?
|
||||
sblock.fs_frag - fragnum(&sblock, csfrags) : 0);
|
||||
sblock.fs_cstotal.cs_nifree = sblock.fs_ncg * sblock.fs_ipg - ROOTINO;
|
||||
sblock.fs_cstotal.cs_ndir = 0;
|
||||
sblock.fs_dsize -= csfrags;
|
||||
sblock.fs_time = start_time.tv_sec;
|
||||
if (Oflag <= 1) {
|
||||
sblock.fs_old_time = start_time.tv_sec;
|
||||
sblock.fs_old_dsize = sblock.fs_dsize;
|
||||
sblock.fs_old_csaddr = sblock.fs_csaddr;
|
||||
sblock.fs_old_cstotal.cs_ndir = sblock.fs_cstotal.cs_ndir;
|
||||
sblock.fs_old_cstotal.cs_nbfree = sblock.fs_cstotal.cs_nbfree;
|
||||
sblock.fs_old_cstotal.cs_nifree = sblock.fs_cstotal.cs_nifree;
|
||||
sblock.fs_old_cstotal.cs_nffree = sblock.fs_cstotal.cs_nffree;
|
||||
}
|
||||
/*
|
||||
* Dump out summary information about file system.
|
||||
*/
|
||||
#define B2MBFACTOR (1 / (1024.0 * 1024.0))
|
||||
printf("%s: %.1fMB (%lld sectors) block size %d, "
|
||||
"fragment size %d\n",
|
||||
fsys, (float)sblock.fs_size * sblock.fs_fsize * B2MBFACTOR,
|
||||
(long long)fsbtodb(&sblock, sblock.fs_size),
|
||||
sblock.fs_bsize, sblock.fs_fsize);
|
||||
printf("\tusing %d cylinder groups of %.2fMB, %d blks, "
|
||||
"%d inodes.\n",
|
||||
sblock.fs_ncg,
|
||||
(float)sblock.fs_fpg * sblock.fs_fsize * B2MBFACTOR,
|
||||
sblock.fs_fpg / sblock.fs_frag, sblock.fs_ipg);
|
||||
#undef B2MBFACTOR
|
||||
/*
|
||||
* Now determine how wide each column will be, and calculate how
|
||||
* many columns will fit in a 76 char line. 76 is the width of the
|
||||
* subwindows in sysinst.
|
||||
*/
|
||||
printcolwidth = count_digits(
|
||||
fsbtodb(&sblock, cgsblock(&sblock, sblock.fs_ncg -1)));
|
||||
nprintcols = 76 / (printcolwidth + 2);
|
||||
|
||||
/*
|
||||
* allocate space for superblock, cylinder group map, and
|
||||
* two sets of inode blocks.
|
||||
*/
|
||||
if (sblock.fs_bsize < SBLOCKSIZE)
|
||||
iobufsize = SBLOCKSIZE + 3 * sblock.fs_bsize;
|
||||
else
|
||||
iobufsize = 4 * sblock.fs_bsize;
|
||||
if ((iobuf = malloc(iobufsize)) == 0) {
|
||||
printf("Cannot allocate I/O buffer\n");
|
||||
exit(38);
|
||||
}
|
||||
memset(iobuf, 0, iobufsize);
|
||||
/*
|
||||
* Make a copy of the superblock into the buffer that we will be
|
||||
* writing out in each cylinder group.
|
||||
*/
|
||||
memcpy(writebuf, &sblock, sbsize);
|
||||
if (fsopts->needswap)
|
||||
ffs_sb_swap(&sblock, (struct fs*)writebuf);
|
||||
memcpy(iobuf, writebuf, SBLOCKSIZE);
|
||||
|
||||
printf("super-block backups (for fsck -b #) at:");
|
||||
for (cylno = 0; cylno < sblock.fs_ncg; cylno++) {
|
||||
initcg(cylno, start_time.tv_sec, fsopts);
|
||||
if (cylno % nprintcols == 0)
|
||||
printf("\n");
|
||||
printf(" %*lld,", printcolwidth,
|
||||
(long long)fsbtodb(&sblock, cgsblock(&sblock, cylno)));
|
||||
fflush(stdout);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
/*
|
||||
* Now construct the initial file system,
|
||||
* then write out the super-block.
|
||||
*/
|
||||
sblock.fs_time = start_time.tv_sec;
|
||||
if (Oflag <= 1) {
|
||||
sblock.fs_old_cstotal.cs_ndir = sblock.fs_cstotal.cs_ndir;
|
||||
sblock.fs_old_cstotal.cs_nbfree = sblock.fs_cstotal.cs_nbfree;
|
||||
sblock.fs_old_cstotal.cs_nifree = sblock.fs_cstotal.cs_nifree;
|
||||
sblock.fs_old_cstotal.cs_nffree = sblock.fs_cstotal.cs_nffree;
|
||||
}
|
||||
if (fsopts->needswap)
|
||||
sblock.fs_flags |= FS_SWAPPED;
|
||||
ffs_write_superblock(&sblock, fsopts);
|
||||
return (&sblock);
|
||||
}
|
||||
|
||||
/*
|
||||
* Write out the superblock and its duplicates,
|
||||
* and the cylinder group summaries
|
||||
*/
|
||||
void
|
||||
ffs_write_superblock(struct fs *fs, const fsinfo_t *fsopts)
|
||||
{
|
||||
int cylno, size, blks, i, saveflag;
|
||||
void *space;
|
||||
char *wrbuf;
|
||||
|
||||
saveflag = fs->fs_flags & FS_INTERNAL;
|
||||
fs->fs_flags &= ~FS_INTERNAL;
|
||||
|
||||
memcpy(writebuf, &sblock, sbsize);
|
||||
if (fsopts->needswap)
|
||||
ffs_sb_swap(fs, (struct fs*)writebuf);
|
||||
ffs_wtfs(fs->fs_sblockloc / sectorsize, sbsize, writebuf, fsopts);
|
||||
|
||||
/* Write out the duplicate super blocks */
|
||||
for (cylno = 0; cylno < fs->fs_ncg; cylno++)
|
||||
ffs_wtfs(fsbtodb(fs, cgsblock(fs, cylno)),
|
||||
sbsize, writebuf, fsopts);
|
||||
|
||||
/* Write out the cylinder group summaries */
|
||||
size = fs->fs_cssize;
|
||||
blks = howmany(size, fs->fs_fsize);
|
||||
space = (void *)fs->fs_csp;
|
||||
if ((wrbuf = malloc(size)) == NULL)
|
||||
err(1, "ffs_write_superblock: malloc %d", size);
|
||||
for (i = 0; i < blks; i+= fs->fs_frag) {
|
||||
size = fs->fs_bsize;
|
||||
if (i + fs->fs_frag > blks)
|
||||
size = (blks - i) * fs->fs_fsize;
|
||||
if (fsopts->needswap)
|
||||
ffs_csum_swap((struct csum *)space,
|
||||
(struct csum *)wrbuf, size);
|
||||
else
|
||||
memcpy(wrbuf, space, (u_int)size);
|
||||
ffs_wtfs(fsbtodb(fs, fs->fs_csaddr + i), size, wrbuf, fsopts);
|
||||
space = (char *)space + size;
|
||||
}
|
||||
free(wrbuf);
|
||||
fs->fs_flags |= saveflag;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize a cylinder group.
|
||||
*/
|
||||
static void
|
||||
initcg(int cylno, time_t utime, const fsinfo_t *fsopts)
|
||||
{
|
||||
daddr_t cbase, dmax;
|
||||
int32_t i, j, d, dlower, dupper, blkno;
|
||||
struct ufs1_dinode *dp1;
|
||||
struct ufs2_dinode *dp2;
|
||||
int start;
|
||||
|
||||
/*
|
||||
* Determine block bounds for cylinder group.
|
||||
* Allow space for super block summary information in first
|
||||
* cylinder group.
|
||||
*/
|
||||
cbase = cgbase(&sblock, cylno);
|
||||
dmax = cbase + sblock.fs_fpg;
|
||||
if (dmax > sblock.fs_size)
|
||||
dmax = sblock.fs_size;
|
||||
dlower = cgsblock(&sblock, cylno) - cbase;
|
||||
dupper = cgdmin(&sblock, cylno) - cbase;
|
||||
if (cylno == 0)
|
||||
dupper += howmany(sblock.fs_cssize, sblock.fs_fsize);
|
||||
memset(&acg, 0, sblock.fs_cgsize);
|
||||
acg.cg_time = utime;
|
||||
acg.cg_magic = CG_MAGIC;
|
||||
acg.cg_cgx = cylno;
|
||||
acg.cg_niblk = sblock.fs_ipg;
|
||||
acg.cg_initediblk = sblock.fs_ipg < 2 * INOPB(&sblock) ?
|
||||
sblock.fs_ipg : 2 * INOPB(&sblock);
|
||||
acg.cg_ndblk = dmax - cbase;
|
||||
if (sblock.fs_contigsumsize > 0)
|
||||
acg.cg_nclusterblks = acg.cg_ndblk >> sblock.fs_fragshift;
|
||||
start = &acg.cg_space[0] - (u_char *)(&acg.cg_firstfield);
|
||||
if (Oflag == 2) {
|
||||
acg.cg_iusedoff = start;
|
||||
} else {
|
||||
if (cylno == sblock.fs_ncg - 1)
|
||||
acg.cg_old_ncyl = howmany(acg.cg_ndblk,
|
||||
sblock.fs_fpg / sblock.fs_old_cpg);
|
||||
else
|
||||
acg.cg_old_ncyl = sblock.fs_old_cpg;
|
||||
acg.cg_old_time = acg.cg_time;
|
||||
acg.cg_time = 0;
|
||||
acg.cg_old_niblk = acg.cg_niblk;
|
||||
acg.cg_niblk = 0;
|
||||
acg.cg_initediblk = 0;
|
||||
acg.cg_old_btotoff = start;
|
||||
acg.cg_old_boff = acg.cg_old_btotoff +
|
||||
sblock.fs_old_cpg * sizeof(int32_t);
|
||||
acg.cg_iusedoff = acg.cg_old_boff +
|
||||
sblock.fs_old_cpg * sizeof(u_int16_t);
|
||||
}
|
||||
acg.cg_freeoff = acg.cg_iusedoff + howmany(sblock.fs_ipg, CHAR_BIT);
|
||||
if (sblock.fs_contigsumsize <= 0) {
|
||||
acg.cg_nextfreeoff = acg.cg_freeoff +
|
||||
howmany(sblock.fs_fpg, CHAR_BIT);
|
||||
} else {
|
||||
acg.cg_clustersumoff = acg.cg_freeoff +
|
||||
howmany(sblock.fs_fpg, CHAR_BIT) - sizeof(int32_t);
|
||||
acg.cg_clustersumoff =
|
||||
roundup(acg.cg_clustersumoff, sizeof(int32_t));
|
||||
acg.cg_clusteroff = acg.cg_clustersumoff +
|
||||
(sblock.fs_contigsumsize + 1) * sizeof(int32_t);
|
||||
acg.cg_nextfreeoff = acg.cg_clusteroff +
|
||||
howmany(fragstoblks(&sblock, sblock.fs_fpg), CHAR_BIT);
|
||||
}
|
||||
if (acg.cg_nextfreeoff > sblock.fs_cgsize) {
|
||||
printf("Panic: cylinder group too big\n");
|
||||
exit(37);
|
||||
}
|
||||
acg.cg_cs.cs_nifree += sblock.fs_ipg;
|
||||
if (cylno == 0)
|
||||
for (i = 0; i < ROOTINO; i++) {
|
||||
setbit(cg_inosused(&acg, 0), i);
|
||||
acg.cg_cs.cs_nifree--;
|
||||
}
|
||||
if (cylno > 0) {
|
||||
/*
|
||||
* In cylno 0, beginning space is reserved
|
||||
* for boot and super blocks.
|
||||
*/
|
||||
for (d = 0, blkno = 0; d < dlower;) {
|
||||
ffs_setblock(&sblock, cg_blksfree(&acg, 0), blkno);
|
||||
if (sblock.fs_contigsumsize > 0)
|
||||
setbit(cg_clustersfree(&acg, 0), blkno);
|
||||
acg.cg_cs.cs_nbfree++;
|
||||
d += sblock.fs_frag;
|
||||
blkno++;
|
||||
}
|
||||
}
|
||||
if ((i = (dupper & (sblock.fs_frag - 1))) != 0) {
|
||||
acg.cg_frsum[sblock.fs_frag - i]++;
|
||||
for (d = dupper + sblock.fs_frag - i; dupper < d; dupper++) {
|
||||
setbit(cg_blksfree(&acg, 0), dupper);
|
||||
acg.cg_cs.cs_nffree++;
|
||||
}
|
||||
}
|
||||
for (d = dupper, blkno = dupper >> sblock.fs_fragshift;
|
||||
d + sblock.fs_frag <= acg.cg_ndblk; ) {
|
||||
ffs_setblock(&sblock, cg_blksfree(&acg, 0), blkno);
|
||||
if (sblock.fs_contigsumsize > 0)
|
||||
setbit(cg_clustersfree(&acg, 0), blkno);
|
||||
acg.cg_cs.cs_nbfree++;
|
||||
d += sblock.fs_frag;
|
||||
blkno++;
|
||||
}
|
||||
if (d < acg.cg_ndblk) {
|
||||
acg.cg_frsum[acg.cg_ndblk - d]++;
|
||||
for (; d < acg.cg_ndblk; d++) {
|
||||
setbit(cg_blksfree(&acg, 0), d);
|
||||
acg.cg_cs.cs_nffree++;
|
||||
}
|
||||
}
|
||||
if (sblock.fs_contigsumsize > 0) {
|
||||
int32_t *sump = cg_clustersum(&acg, 0);
|
||||
u_char *mapp = cg_clustersfree(&acg, 0);
|
||||
int map = *mapp++;
|
||||
int bit = 1;
|
||||
int run = 0;
|
||||
|
||||
for (i = 0; i < acg.cg_nclusterblks; i++) {
|
||||
if ((map & bit) != 0) {
|
||||
run++;
|
||||
} else if (run != 0) {
|
||||
if (run > sblock.fs_contigsumsize)
|
||||
run = sblock.fs_contigsumsize;
|
||||
sump[run]++;
|
||||
run = 0;
|
||||
}
|
||||
if ((i & (CHAR_BIT - 1)) != (CHAR_BIT - 1)) {
|
||||
bit <<= 1;
|
||||
} else {
|
||||
map = *mapp++;
|
||||
bit = 1;
|
||||
}
|
||||
}
|
||||
if (run != 0) {
|
||||
if (run > sblock.fs_contigsumsize)
|
||||
run = sblock.fs_contigsumsize;
|
||||
sump[run]++;
|
||||
}
|
||||
}
|
||||
sblock.fs_cs(&sblock, cylno) = acg.cg_cs;
|
||||
/*
|
||||
* Write out the duplicate super block, the cylinder group map
|
||||
* and two blocks worth of inodes in a single write.
|
||||
*/
|
||||
start = sblock.fs_bsize > SBLOCKSIZE ? sblock.fs_bsize : SBLOCKSIZE;
|
||||
memcpy(&iobuf[start], &acg, sblock.fs_cgsize);
|
||||
if (fsopts->needswap)
|
||||
ffs_cg_swap(&acg, (struct cg*)&iobuf[start], &sblock);
|
||||
start += sblock.fs_bsize;
|
||||
dp1 = (struct ufs1_dinode *)(&iobuf[start]);
|
||||
dp2 = (struct ufs2_dinode *)(&iobuf[start]);
|
||||
for (i = 0; i < acg.cg_initediblk; i++) {
|
||||
if (sblock.fs_magic == FS_UFS1_MAGIC) {
|
||||
/* No need to swap, it'll stay random */
|
||||
dp1->di_gen = random();
|
||||
dp1++;
|
||||
} else {
|
||||
dp2->di_gen = random();
|
||||
dp2++;
|
||||
}
|
||||
}
|
||||
ffs_wtfs(fsbtodb(&sblock, cgsblock(&sblock, cylno)), iobufsize, iobuf,
|
||||
fsopts);
|
||||
/*
|
||||
* For the old file system, we have to initialize all the inodes.
|
||||
*/
|
||||
if (Oflag <= 1) {
|
||||
for (i = 2 * sblock.fs_frag;
|
||||
i < sblock.fs_ipg / INOPF(&sblock);
|
||||
i += sblock.fs_frag) {
|
||||
dp1 = (struct ufs1_dinode *)(&iobuf[start]);
|
||||
for (j = 0; j < INOPB(&sblock); j++) {
|
||||
dp1->di_gen = random();
|
||||
dp1++;
|
||||
}
|
||||
ffs_wtfs(fsbtodb(&sblock, cgimin(&sblock, cylno) + i),
|
||||
sblock.fs_bsize, &iobuf[start], fsopts);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* read a block from the file system
|
||||
*/
|
||||
void
|
||||
ffs_rdfs(daddr_t bno, int size, void *bf, const fsinfo_t *fsopts)
|
||||
{
|
||||
int n;
|
||||
off_t offset;
|
||||
|
||||
offset = bno;
|
||||
offset *= fsopts->sectorsize;
|
||||
if (lseek(fsopts->fd, offset, SEEK_SET) < 0)
|
||||
err(1, "ffs_rdfs: seek error for sector %lld: %s\n",
|
||||
(long long)bno, strerror(errno));
|
||||
n = read(fsopts->fd, bf, size);
|
||||
if (n == -1) {
|
||||
abort();
|
||||
err(1, "ffs_rdfs: read error bno %lld size %d", (long long)bno,
|
||||
size);
|
||||
}
|
||||
else if (n != size)
|
||||
errx(1, "ffs_rdfs: read error for sector %lld: %s\n",
|
||||
(long long)bno, strerror(errno));
|
||||
}
|
||||
|
||||
/*
|
||||
* write a block to the file system
|
||||
*/
|
||||
void
|
||||
ffs_wtfs(daddr_t bno, int size, void *bf, const fsinfo_t *fsopts)
|
||||
{
|
||||
int n;
|
||||
off_t offset;
|
||||
|
||||
offset = bno;
|
||||
offset *= fsopts->sectorsize;
|
||||
if (lseek(fsopts->fd, offset, SEEK_SET) < 0)
|
||||
err(1, "wtfs: seek error for sector %lld: %s\n",
|
||||
(long long)bno, strerror(errno));
|
||||
n = write(fsopts->fd, bf, size);
|
||||
if (n == -1)
|
||||
err(1, "wtfs: write error for sector %lld: %s\n",
|
||||
(long long)bno, strerror(errno));
|
||||
else if (n != size)
|
||||
errx(1, "wtfs: write error for sector %lld: %s\n",
|
||||
(long long)bno, strerror(errno));
|
||||
}
|
||||
|
||||
|
||||
/* Determine how many digits are needed to print a given integer */
|
||||
static int
|
||||
count_digits(int num)
|
||||
{
|
||||
int ndig;
|
||||
|
||||
for(ndig = 1; num > 9; num /=10, ndig++);
|
||||
|
||||
return (ndig);
|
||||
}
|
||||
|
||||
static int
|
||||
ilog2(int val)
|
||||
{
|
||||
u_int n;
|
||||
|
||||
for (n = 0; n < sizeof(n) * CHAR_BIT; n++)
|
||||
if (1 << n == val)
|
||||
return (n);
|
||||
errx(1, "ilog2: %d is not a power of 2\n", val);
|
||||
}
|
39
ffs/newfs_extern.h
Normal file
39
ffs/newfs_extern.h
Normal file
@ -0,0 +1,39 @@
|
||||
/* $NetBSD: newfs_extern.h,v 1.2 2004/06/24 22:30:13 lukem Exp $ */
|
||||
/* From: NetBSD: extern.h,v 1.3 2000/12/01 12:03:27 simonb Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1997 Christos Zoulas. 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 by Christos Zoulas.
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* prototypes */
|
||||
struct fs *ffs_mkfs(const char *, const fsinfo_t *);
|
||||
void ffs_write_superblock(struct fs *, const fsinfo_t *);
|
||||
void ffs_rdfs(daddr_t, int, void *, const fsinfo_t *);
|
||||
void ffs_wtfs(daddr_t, int, void *, const fsinfo_t *);
|
||||
|
||||
#define FFS_MAXBSIZE 65536
|
148
ffs/ufs_bmap.c
Normal file
148
ffs/ufs_bmap.c
Normal file
@ -0,0 +1,148 @@
|
||||
/* $NetBSD: ufs_bmap.c,v 1.14 2004/06/20 22:20:18 jmc Exp $ */
|
||||
/* From: NetBSD: ufs_bmap.c,v 1.14 2001/11/08 05:00:51 chs Exp */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1989, 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
* (c) UNIX System Laboratories, Inc.
|
||||
* All or some portions of this file are derived from material licensed
|
||||
* to the University of California by American Telephone and Telegraph
|
||||
* Co. or Unix System Laboratories, Inc. and are reproduced herein with
|
||||
* the permission of UNIX System Laboratories, 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. 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.
|
||||
*
|
||||
* @(#)ufs_bmap.c 8.8 (Berkeley) 8/11/95
|
||||
*/
|
||||
|
||||
#if HAVE_NBTOOL_CONFIG_H
|
||||
#include "nbtool_config.h"
|
||||
#endif
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#if defined(__RCSID) && !defined(__lint)
|
||||
__RCSID("$NetBSD: ufs_bmap.c,v 1.14 2004/06/20 22:20:18 jmc Exp $");
|
||||
#endif /* !__lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <strings.h>
|
||||
|
||||
#include "makefs.h"
|
||||
|
||||
#include <ufs/ufs/dinode.h>
|
||||
#include <ufs/ufs/ufs_bswap.h>
|
||||
#include <ufs/ffs/fs.h>
|
||||
|
||||
#include "ffs/ufs_inode.h"
|
||||
#include "ffs/ffs_extern.h"
|
||||
|
||||
/*
|
||||
* Create an array of logical block number/offset pairs which represent the
|
||||
* path of indirect blocks required to access a data block. The first "pair"
|
||||
* contains the logical block number of the appropriate single, double or
|
||||
* triple indirect block and the offset into the inode indirect block array.
|
||||
* Note, the logical block number of the inode single/double/triple indirect
|
||||
* block appears twice in the array, once with the offset into the i_ffs_ib and
|
||||
* once with the offset into the page itself.
|
||||
*/
|
||||
int
|
||||
ufs_getlbns(struct inode *ip, daddr_t bn, struct indir *ap, int *nump)
|
||||
{
|
||||
daddr_t metalbn, realbn;
|
||||
int64_t blockcnt;
|
||||
int lbc;
|
||||
int i, numlevels, off;
|
||||
u_long lognindir;
|
||||
|
||||
lognindir = ffs(NINDIR(ip->i_fs)) - 1;
|
||||
if (nump)
|
||||
*nump = 0;
|
||||
numlevels = 0;
|
||||
realbn = bn;
|
||||
if ((long)bn < 0)
|
||||
bn = -(long)bn;
|
||||
|
||||
assert (bn >= NDADDR);
|
||||
|
||||
/*
|
||||
* Determine the number of levels of indirection. After this loop
|
||||
* is done, blockcnt indicates the number of data blocks possible
|
||||
* at the given level of indirection, and NIADDR - i is the number
|
||||
* of levels of indirection needed to locate the requested block.
|
||||
*/
|
||||
|
||||
bn -= NDADDR;
|
||||
for (lbc = 0, i = NIADDR;; i--, bn -= blockcnt) {
|
||||
if (i == 0)
|
||||
return (EFBIG);
|
||||
|
||||
lbc += lognindir;
|
||||
blockcnt = (int64_t)1 << lbc;
|
||||
|
||||
if (bn < blockcnt)
|
||||
break;
|
||||
}
|
||||
|
||||
/* Calculate the address of the first meta-block. */
|
||||
if (realbn >= 0)
|
||||
metalbn = -(realbn - bn + NIADDR - i);
|
||||
else
|
||||
metalbn = -(-realbn - bn + NIADDR - i);
|
||||
|
||||
/*
|
||||
* At each iteration, off is the offset into the bap array which is
|
||||
* an array of disk addresses at the current level of indirection.
|
||||
* The logical block number and the offset in that block are stored
|
||||
* into the argument array.
|
||||
*/
|
||||
ap->in_lbn = metalbn;
|
||||
ap->in_off = off = NIADDR - i;
|
||||
ap->in_exists = 0;
|
||||
ap++;
|
||||
for (++numlevels; i <= NIADDR; i++) {
|
||||
/* If searching for a meta-data block, quit when found. */
|
||||
if (metalbn == realbn)
|
||||
break;
|
||||
|
||||
lbc -= lognindir;
|
||||
blockcnt = (int64_t)1 << lbc;
|
||||
off = (bn >> lbc) & (NINDIR(ip->i_fs) - 1);
|
||||
|
||||
++numlevels;
|
||||
ap->in_lbn = metalbn;
|
||||
ap->in_off = off;
|
||||
ap->in_exists = 0;
|
||||
++ap;
|
||||
|
||||
metalbn -= -1 + (off << lbc);
|
||||
}
|
||||
if (nump)
|
||||
*nump = numlevels;
|
||||
return (0);
|
||||
}
|
96
ffs/ufs_inode.h
Normal file
96
ffs/ufs_inode.h
Normal file
@ -0,0 +1,96 @@
|
||||
/* $NetBSD: ufs_inode.h,v 1.3 2003/08/07 11:25:34 agc Exp $ */
|
||||
/* From: NetBSD: inode.h,v 1.27 2001/12/18 10:57:23 fvdl Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1982, 1989, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
* (c) UNIX System Laboratories, Inc.
|
||||
* All or some portions of this file are derived from material licensed
|
||||
* to the University of California by American Telephone and Telegraph
|
||||
* Co. or Unix System Laboratories, Inc. and are reproduced herein with
|
||||
* the permission of UNIX System Laboratories, 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. 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.
|
||||
*
|
||||
* @(#)inode.h 8.9 (Berkeley) 5/14/95
|
||||
*/
|
||||
|
||||
union dinode {
|
||||
struct ufs1_dinode ffs1_din;
|
||||
struct ufs2_dinode ffs2_din;
|
||||
};
|
||||
|
||||
struct inode {
|
||||
ino_t i_number; /* The identity of the inode. */
|
||||
struct fs *i_fs; /* File system */
|
||||
union dinode i_din;
|
||||
int i_fd; /* File descriptor */
|
||||
uint64_t i_size;
|
||||
};
|
||||
|
||||
#define i_ffs1_atime i_din.ffs1_din.di_atime
|
||||
#define i_ffs1_atimensec i_din.ffs1_din.di_atimensec
|
||||
#define i_ffs1_blocks i_din.ffs1_din.di_blocks
|
||||
#define i_ffs1_ctime i_din.ffs1_din.di_ctime
|
||||
#define i_ffs1_ctimensec i_din.ffs1_din.di_ctimensec
|
||||
#define i_ffs1_db i_din.ffs1_din.di_db
|
||||
#define i_ffs1_flags i_din.ffs1_din.di_flags
|
||||
#define i_ffs1_gen i_din.ffs1_din.di_gen
|
||||
#define i_ffs11_gid i_din.ffs1_din.di_gid
|
||||
#define i_ffs1_ib i_din.ffs1_din.di_ib
|
||||
#define i_ffs1_mode i_din.ffs1_din.di_mode
|
||||
#define i_ffs1_mtime i_din.ffs1_din.di_mtime
|
||||
#define i_ffs1_mtimensec i_din.ffs1_din.di_mtimensec
|
||||
#define i_ffs1_nlink i_din.ffs1_din.di_nlink
|
||||
#define i_ffs1_rdev i_din.ffs1_din.di_rdev
|
||||
#define i_ffs1_shortlink i_din.ffs1_din.db
|
||||
#define i_ffs1_size i_din.ffs1_din.di_size
|
||||
#define i_ffs1_uid i_din.ffs1_din.di_uid
|
||||
|
||||
#define i_ffs2_atime i_din.ffs2_din.di_atime
|
||||
#define i_ffs2_atimensec i_din.ffs2_din.di_atimensec
|
||||
#define i_ffs2_blocks i_din.ffs2_din.di_blocks
|
||||
#define i_ffs2_ctime i_din.ffs2_din.di_ctime
|
||||
#define i_ffs2_ctimensec i_din.ffs2_din.di_ctimensec
|
||||
#define i_ffs2_birthtime i_din.ffs2_din.di_birthtime
|
||||
#define i_ffs2_birthnsec i_din.ffs2_din.di_birthnsec
|
||||
#define i_ffs2_db i_din.ffs2_din.di_db
|
||||
#define i_ffs2_flags i_din.ffs2_din.di_flags
|
||||
#define i_ffs2_gen i_din.ffs2_din.di_gen
|
||||
#define i_ffs21_gid i_din.ffs2_din.di_gid
|
||||
#define i_ffs2_ib i_din.ffs2_din.di_ib
|
||||
#define i_ffs2_mode i_din.ffs2_din.di_mode
|
||||
#define i_ffs2_mtime i_din.ffs2_din.di_mtime
|
||||
#define i_ffs2_mtimensec i_din.ffs2_din.di_mtimensec
|
||||
#define i_ffs2_nlink i_din.ffs2_din.di_nlink
|
||||
#define i_ffs2_rdev i_din.ffs2_din.di_rdev
|
||||
#define i_ffs2_shortlink i_din.ffs2_din.db
|
||||
#define i_ffs2_size i_din.ffs2_din.di_size
|
||||
#define i_ffs2_uid i_din.ffs2_din.di_uid
|
||||
|
||||
#undef DIP
|
||||
#define DIP(ip, field) \
|
||||
(((ip)->i_fs->fs_magic == FS_UFS1_MAGIC) ? \
|
||||
(ip)->i_ffs1_##field : (ip)->i_ffs2_##field)
|
286
makefs.8
Normal file
286
makefs.8
Normal file
@ -0,0 +1,286 @@
|
||||
.\" $NetBSD: makefs.8,v 1.13 2004/02/13 17:56:18 wiz 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.
|
||||
.\"
|
||||
.Dd March 30, 2003
|
||||
.Dt MAKEFS 8
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm makefs
|
||||
.Nd create a file system image from a directory tree
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Bk -words
|
||||
.Op Fl t Ar fs-type
|
||||
.Ek
|
||||
.Bk -words
|
||||
.Op Fl o Ar fs-options
|
||||
.Ek
|
||||
.Bk -words
|
||||
.Op Fl d Ar debug-mask
|
||||
.Ek
|
||||
.Bk -words
|
||||
.Op Fl B Ar byte-order
|
||||
.Ek
|
||||
.Bk -words
|
||||
.Op Fl S Ar sector-size
|
||||
.Ek
|
||||
.Bk -words
|
||||
.Op Fl M Ar minimum-size
|
||||
.Ek
|
||||
.Bk -words
|
||||
.Op Fl m Ar maximum-size
|
||||
.Ek
|
||||
.Bk -words
|
||||
.Op Fl s Ar image-size
|
||||
.Ek
|
||||
.Bk -words
|
||||
.Op Fl b Ar free-blocks
|
||||
.Ek
|
||||
.Bk -words
|
||||
.Op Fl f Ar free-files
|
||||
.Ek
|
||||
.Bk -words
|
||||
.Op Fl F Ar specfile
|
||||
.Ek
|
||||
.Op Fl x
|
||||
.Bk -words
|
||||
.Op Fl N Ar userdb-dir
|
||||
.Ek
|
||||
.Ar image-file
|
||||
.Ar directory
|
||||
.Sh DESCRIPTION
|
||||
The utility
|
||||
.Nm
|
||||
creates a file system image into
|
||||
.Ar image-file
|
||||
from the directory tree
|
||||
.Ar directory .
|
||||
No special devices or privileges are required to perform this task.
|
||||
.Pp
|
||||
The options are as follows:
|
||||
.Bl -tag -width flag
|
||||
.It Fl t Ar fs-type
|
||||
Create an
|
||||
.Ar fs-type
|
||||
file system image.
|
||||
The following file system types are supported:
|
||||
.Bl -tag -width ffs -offset indent
|
||||
.It Sy ffs
|
||||
BSD fast file system (default).
|
||||
.El
|
||||
.It Fl o Ar fs-options
|
||||
Set file system specific options.
|
||||
.Ar fs-options
|
||||
is a comma separated list of options.
|
||||
Valid file system specific options are detailed below.
|
||||
.It Fl d Ar debug-mask
|
||||
Enable various levels of debugging, depending upon which bits are set
|
||||
in
|
||||
.Ar debug-mask .
|
||||
XXX: document these
|
||||
.It Fl B Ar byte-order
|
||||
Set the byte order of the image to
|
||||
.Ar byte-order .
|
||||
Valid byte orders are
|
||||
.Ql 4321 ,
|
||||
.Ql big
|
||||
or
|
||||
.Ql be
|
||||
for big endian, and
|
||||
.Ql 1234 ,
|
||||
.Ql little
|
||||
or
|
||||
.Ql le
|
||||
for little endian.
|
||||
Some file systems may have a fixed byte order; in those cases this
|
||||
argument will be ignored.
|
||||
.It Fl S Ar sector-size
|
||||
Set the file system sector size to
|
||||
.Ar sector-size .
|
||||
Defaults to 512.
|
||||
.It Fl M Ar minimum-size
|
||||
Set the minimum size of the file system image to
|
||||
.Ar minimum-size .
|
||||
.It Fl m Ar maximum-size
|
||||
Set the maximum size of the file system image to
|
||||
.Ar maximum-size .
|
||||
An error will be raised if the target file system needs to be larger
|
||||
than this to accommodate the provided directory tree.
|
||||
.It Fl s Ar image-size
|
||||
Set the size of the file system image to
|
||||
.Ar image-size .
|
||||
.It Fl b Ar free-blocks
|
||||
Ensure that a minimum of
|
||||
.Ar free-blocks
|
||||
free blocks exist in the image.
|
||||
An optional
|
||||
.Ql %
|
||||
suffix may be provided to indicate that
|
||||
.Ar free-blocks
|
||||
indicates a percentage of the calculated image size
|
||||
.It Fl f Ar free-files
|
||||
Ensure that a minimum of
|
||||
.Ar free-files
|
||||
free files (inodes) exist in the image.
|
||||
An optional
|
||||
.Ql %
|
||||
suffix may be provided to indicate that
|
||||
.Ar free-blocks
|
||||
indicates a percentage of the calculated image size
|
||||
.It Fl F Ar specfile
|
||||
Use
|
||||
.Ar specfile
|
||||
as an
|
||||
.Xr mtree 8
|
||||
.Sq specfile
|
||||
specification.
|
||||
.Pp
|
||||
If a specfile entry exists in the underlying file system, its permissions and
|
||||
modification time will be used unless specifically overridden by the specfile.
|
||||
An error will be raised if the type of entry in the specfile conflicts
|
||||
with that of an existing entry.
|
||||
.Pp
|
||||
In the opposite case
|
||||
(where a specfile entry does not have an entry in the underlying file system)
|
||||
the following occurs:
|
||||
If the specfile entry is marked
|
||||
.Sy optional ,
|
||||
the specfile entry is ignored.
|
||||
Otherwise, the entry will be created in the image,
|
||||
and it is necessary to specify at least the following parameters
|
||||
in the specfile:
|
||||
.Sy type ,
|
||||
.Sy mode ,
|
||||
.Sy gname
|
||||
or
|
||||
.Sy gid ,
|
||||
and
|
||||
.Sy uname
|
||||
or
|
||||
.Sy uid ,
|
||||
.Sy device
|
||||
(in the case of block or character devices), and
|
||||
.Sy link
|
||||
(in the case of symbolic links).
|
||||
If
|
||||
.Sy time
|
||||
isn't provided, the current time will be used.
|
||||
If
|
||||
.Sy flags
|
||||
isn't provided, the current file flags will be used.
|
||||
Missing regular file entries will be created as zero-length files.
|
||||
.It Fl x
|
||||
Exclude file system nodes not explcitly listed in the specfile.
|
||||
.It Fl N Ar dbdir
|
||||
Use the user database text file
|
||||
.Pa master.passwd
|
||||
and group database text file
|
||||
.Pa group
|
||||
from
|
||||
.Ar dbdir ,
|
||||
rather than using the results from the system's
|
||||
.Xr getpwnam 3
|
||||
and
|
||||
.Xr getgrnam 3
|
||||
(and related) library calls.
|
||||
.El
|
||||
.Pp
|
||||
Where sizes are specified, a decimal number of bytes is expected.
|
||||
Two or more numbers may be separated by an
|
||||
.Dq x
|
||||
to indicate a product.
|
||||
Each number may have one of the following optional suffixes:
|
||||
.Bl -tag -width 3n -offset indent -compact
|
||||
.It b
|
||||
Block; multiply by 512
|
||||
.It k
|
||||
Kilo; multiply by 1024 (1 KB)
|
||||
.It m
|
||||
Mega; multiply by 1048576 (1 MB)
|
||||
.It g
|
||||
Giga; multiply by 1073741824 (1 GB)
|
||||
.It t
|
||||
Tera; multiply by 1099511627776 (1 TB)
|
||||
.It w
|
||||
Word; multiply by the number of bytes in an integer
|
||||
.El
|
||||
.\"
|
||||
.\"
|
||||
.Ss FFS-specific options
|
||||
.Sy ffs
|
||||
images have ffs-specific optional parameters that may be provided.
|
||||
Each of the options consists of a keyword, an equals sign
|
||||
.Pq Ql = ,
|
||||
and a value.
|
||||
The following keywords are supported:
|
||||
.Pp
|
||||
.Bl -tag -width optimization -offset indent -compact
|
||||
.It Sy avgfilesize
|
||||
Expected average file size
|
||||
.It Sy avgfpdir
|
||||
Expected number of files per directory
|
||||
.It Sy bsize
|
||||
Block size
|
||||
.It Sy density
|
||||
Bytes per inode
|
||||
.It Sy fsize
|
||||
Fragment size
|
||||
.It Sy maxbpg
|
||||
Maximum blocks per file in a cylinder group
|
||||
.It Sy minfree
|
||||
Minimum % free
|
||||
.It Sy optimization
|
||||
Optimization preference; one of
|
||||
.Ql space
|
||||
or
|
||||
.Ql time .
|
||||
.It Sy extent
|
||||
Maximum extent size
|
||||
.It Sy maxbpcg
|
||||
Maximum total number of blocks in a cylinder group
|
||||
.It Sy version
|
||||
UFS version. 1 for FFS (default), 2 for UFS2
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr mtree 8 ,
|
||||
.Xr newfs 8
|
||||
.Sh HISTORY
|
||||
The
|
||||
.Nm
|
||||
utility appeared in
|
||||
.Nx 1.6 .
|
||||
.Sh AUTHORS
|
||||
.An Luke Mewburn
|
||||
.Aq lukem@NetBSD.org .
|
320
makefs.c
Normal file
320
makefs.c
Normal file
@ -0,0 +1,320 @@
|
||||
/* $NetBSD: makefs.c,v 1.20 2004/06/20 22:20:18 jmc 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.
|
||||
*/
|
||||
|
||||
#if HAVE_NBTOOL_CONFIG_H
|
||||
#include "nbtool_config.h"
|
||||
#endif
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#if defined(__RCSID) && !defined(__lint)
|
||||
__RCSID("$NetBSD: makefs.c,v 1.20 2004/06/20 22:20:18 jmc Exp $");
|
||||
#endif /* !__lint */
|
||||
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "makefs.h"
|
||||
#include "mtree.h"
|
||||
|
||||
/*
|
||||
* list of supported file systems and dispatch functions
|
||||
*/
|
||||
typedef struct {
|
||||
const char *type;
|
||||
int (*parse_options)(const char *, fsinfo_t *);
|
||||
void (*make_fs)(const char *, const char *, fsnode *,
|
||||
fsinfo_t *);
|
||||
} fstype_t;
|
||||
|
||||
static fstype_t fstypes[] = {
|
||||
{ "ffs", ffs_parse_opts, ffs_makefs },
|
||||
{ NULL },
|
||||
};
|
||||
|
||||
u_int debug;
|
||||
struct timespec start_time;
|
||||
|
||||
static fstype_t *get_fstype(const char *);
|
||||
static void usage(void);
|
||||
int main(int, char *[]);
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
struct timeval start;
|
||||
fstype_t *fstype;
|
||||
fsinfo_t fsoptions;
|
||||
fsnode *root;
|
||||
int ch, len;
|
||||
char *specfile;
|
||||
|
||||
setprogname(argv[0]);
|
||||
|
||||
debug = 0;
|
||||
if ((fstype = get_fstype(DEFAULT_FSTYPE)) == NULL)
|
||||
errx(1, "Unknown default fs type `%s'.", DEFAULT_FSTYPE);
|
||||
|
||||
/* set default fsoptions */
|
||||
(void)memset(&fsoptions, 0, sizeof(fsoptions));
|
||||
fsoptions.fd = -1;
|
||||
fsoptions.sectorsize = -1;
|
||||
fsoptions.bsize= -1;
|
||||
fsoptions.fsize= -1;
|
||||
fsoptions.cpg= -1;
|
||||
fsoptions.density= -1;
|
||||
fsoptions.minfree= -1;
|
||||
fsoptions.optimization= -1;
|
||||
fsoptions.maxcontig= -1;
|
||||
fsoptions.maxbpg= -1;
|
||||
fsoptions.avgfilesize= -1;
|
||||
fsoptions.avgfpdir= -1;
|
||||
fsoptions.version = 1;
|
||||
|
||||
specfile = NULL;
|
||||
if (gettimeofday(&start, NULL) == -1)
|
||||
err(1, "Unable to get system time");
|
||||
|
||||
start_time.tv_sec = start.tv_sec;
|
||||
start_time.tv_nsec = start.tv_usec * 1000;
|
||||
|
||||
while ((ch = getopt(argc, argv, "B:b:d:f:F:M:m:N:o:s:S:t:x")) != -1) {
|
||||
switch (ch) {
|
||||
|
||||
case 'B':
|
||||
if (strcmp(optarg, "be") == 0 ||
|
||||
strcmp(optarg, "4321") == 0 ||
|
||||
strcmp(optarg, "big") == 0) {
|
||||
#if BYTE_ORDER == LITTLE_ENDIAN
|
||||
fsoptions.needswap = 1;
|
||||
#endif
|
||||
} else if (strcmp(optarg, "le") == 0 ||
|
||||
strcmp(optarg, "1234") == 0 ||
|
||||
strcmp(optarg, "little") == 0) {
|
||||
#if BYTE_ORDER == BIG_ENDIAN
|
||||
fsoptions.needswap = 1;
|
||||
#endif
|
||||
} else {
|
||||
warnx("Invalid endian `%s'.", optarg);
|
||||
usage();
|
||||
}
|
||||
break;
|
||||
|
||||
case 'b':
|
||||
len = strlen(optarg) - 1;
|
||||
if (optarg[len] == '%') {
|
||||
optarg[len] = '\0';
|
||||
fsoptions.freeblockpc =
|
||||
strsuftoll("free block percentage",
|
||||
optarg, 0, 99);
|
||||
} else {
|
||||
fsoptions.freeblocks =
|
||||
strsuftoll("free blocks",
|
||||
optarg, 0, LLONG_MAX);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
debug =
|
||||
(int)strsuftoll("debug mask", optarg, 0, UINT_MAX);
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
len = strlen(optarg) - 1;
|
||||
if (optarg[len] == '%') {
|
||||
optarg[len] = '\0';
|
||||
fsoptions.freefilepc =
|
||||
strsuftoll("free file percentage",
|
||||
optarg, 0, 99);
|
||||
} else {
|
||||
fsoptions.freefiles =
|
||||
strsuftoll("free files",
|
||||
optarg, 0, LLONG_MAX);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'F':
|
||||
specfile = optarg;
|
||||
break;
|
||||
|
||||
case 'M':
|
||||
fsoptions.minsize =
|
||||
strsuftoll("minimum size", optarg, 1LL, LLONG_MAX);
|
||||
break;
|
||||
|
||||
case 'N':
|
||||
if (! setup_getid(optarg))
|
||||
errx(1,
|
||||
"Unable to use user and group databases in `%s'",
|
||||
optarg);
|
||||
break;
|
||||
|
||||
case 'm':
|
||||
fsoptions.maxsize =
|
||||
strsuftoll("maximum size", optarg, 1LL, LLONG_MAX);
|
||||
break;
|
||||
|
||||
case 'o':
|
||||
{
|
||||
char *p;
|
||||
|
||||
while ((p = strsep(&optarg, ",")) != NULL) {
|
||||
if (*p == '\0')
|
||||
errx(1, "Empty option");
|
||||
if (! fstype->parse_options(p, &fsoptions))
|
||||
usage();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 's':
|
||||
fsoptions.minsize = fsoptions.maxsize =
|
||||
strsuftoll("size", optarg, 1LL, LLONG_MAX);
|
||||
break;
|
||||
|
||||
case 'S':
|
||||
fsoptions.sectorsize =
|
||||
(int)strsuftoll("sector size", optarg,
|
||||
1LL, INT_MAX);
|
||||
break;
|
||||
|
||||
case 't':
|
||||
if ((fstype = get_fstype(optarg)) == NULL)
|
||||
errx(1, "Unknown fs type `%s'.", optarg);
|
||||
break;
|
||||
|
||||
case 'x':
|
||||
fsoptions.onlyspec = 1;
|
||||
break;
|
||||
|
||||
case '?':
|
||||
default:
|
||||
usage();
|
||||
/* NOTREACHED */
|
||||
|
||||
}
|
||||
}
|
||||
if (debug) {
|
||||
printf("debug mask: 0x%08x\n", debug);
|
||||
printf("start time: %ld.%ld, %s",
|
||||
(long)start_time.tv_sec, (long)start_time.tv_nsec,
|
||||
ctime(&start_time.tv_sec));
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if (argc != 2)
|
||||
usage();
|
||||
|
||||
/* -x must be accompanied by -F */
|
||||
if (fsoptions.onlyspec != 0 && specfile == NULL)
|
||||
errx(1, "-x requires -F mtree-specfile.");
|
||||
|
||||
/* walk the tree */
|
||||
TIMER_START(start);
|
||||
root = walk_dir(argv[1], NULL);
|
||||
TIMER_RESULTS(start, "walk_dir");
|
||||
|
||||
if (specfile) { /* apply a specfile */
|
||||
TIMER_START(start);
|
||||
apply_specfile(specfile, argv[1], root);
|
||||
TIMER_RESULTS(start, "apply_specfile");
|
||||
}
|
||||
|
||||
if (debug & DEBUG_DUMP_FSNODES) {
|
||||
printf("\nparent: %s\n", argv[1]);
|
||||
dump_fsnodes(".", root);
|
||||
putchar('\n');
|
||||
}
|
||||
|
||||
/* build the file system */
|
||||
TIMER_START(start);
|
||||
fstype->make_fs(argv[0], argv[1], root, &fsoptions);
|
||||
TIMER_RESULTS(start, "make_fs");
|
||||
|
||||
exit(0);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
set_option(option_t *options, const char *var, const char *val)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; options[i].name != NULL; i++) {
|
||||
if (strcmp(options[i].name, var) != 0)
|
||||
continue;
|
||||
*options[i].value = (int)strsuftoll(options[i].desc, val,
|
||||
options[i].minimum, options[i].maximum);
|
||||
return (1);
|
||||
}
|
||||
warnx("Unknown option `%s'", var);
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
static fstype_t *
|
||||
get_fstype(const char *type)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; fstypes[i].type != NULL; i++)
|
||||
if (strcmp(fstypes[i].type, type) == 0)
|
||||
return (&fstypes[i]);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
const char *prog;
|
||||
|
||||
prog = getprogname();
|
||||
fprintf(stderr,
|
||||
"usage: %s [-t fs-type] [-o fs-options] [-d debug-mask] [-B endian]\n"
|
||||
"\t[-S sector-size] [-M minimum-size] [-m maximum-size] [-s image-size]\n"
|
||||
"\t[-b free-blocks] [-f free-files] [-F mtree-specfile] [-x]\n"
|
||||
"\t[-N userdb-dir] image-file directory\n",
|
||||
prog);
|
||||
exit(1);
|
||||
}
|
251
makefs.h
Normal file
251
makefs.h
Normal file
@ -0,0 +1,251 @@
|
||||
/* $NetBSD: makefs.h,v 1.14 2004/06/20 22:20:18 jmc 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 _MAKEFS_H
|
||||
#define _MAKEFS_H
|
||||
|
||||
#if HAVE_NBTOOL_CONFIG_H
|
||||
#include "nbtool_config.h"
|
||||
#else
|
||||
#define HAVE_STRUCT_STAT_ST_FLAGS 1
|
||||
#define HAVE_STRUCT_STAT_ST_GEN 1
|
||||
#define HAVE_STRUCT_STAT_ST_MTIMENSEC 1
|
||||
#define HAVE_STRUCT_STATVFS_F_IOSIZE 1
|
||||
#define HAVE_STRUCT_STAT_BIRTHTIME 1
|
||||
#endif
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <err.h>
|
||||
|
||||
/*
|
||||
* fsnode -
|
||||
* a component of the tree; contains a filename, a pointer to
|
||||
* fsinode, optional symlink name, and tree pointers
|
||||
*
|
||||
* fsinode -
|
||||
* equivalent to an inode, containing target file system inode number,
|
||||
* refcount (nlink), and stat buffer
|
||||
*
|
||||
* A tree of fsnodes looks like this:
|
||||
*
|
||||
* name "." "bin" "netbsd"
|
||||
* type S_IFDIR S_IFDIR S_IFREG
|
||||
* next > > NULL
|
||||
* parent NULL NULL NULL
|
||||
* child NULL v
|
||||
*
|
||||
* name "." "ls"
|
||||
* type S_IFDIR S_IFREG
|
||||
* next > NULL
|
||||
* parent ^ ^ (to "bin")
|
||||
* child NULL NULL
|
||||
*
|
||||
* Notes:
|
||||
* - first always points to first entry, at current level, which
|
||||
* must be "." when the tree has been built; during build it may
|
||||
* not be if "." hasn't yet been found by readdir(2).
|
||||
*/
|
||||
|
||||
enum fi_flags {
|
||||
FI_SIZED = 1<<0, /* inode sized */
|
||||
FI_ALLOCATED = 1<<1, /* fsinode->ino allocated */
|
||||
FI_WRITTEN = 1<<2, /* inode written */
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
uint32_t ino; /* inode number used on target fs */
|
||||
uint32_t nlink; /* number of links to this entry */
|
||||
enum fi_flags flags; /* flags used by fs specific code */
|
||||
struct stat st; /* stat entry */
|
||||
} fsinode;
|
||||
|
||||
typedef struct _fsnode {
|
||||
struct _fsnode *parent; /* parent (NULL if root) */
|
||||
struct _fsnode *child; /* child (if type == S_IFDIR) */
|
||||
struct _fsnode *next; /* next */
|
||||
struct _fsnode *first; /* first node of current level (".") */
|
||||
uint32_t type; /* type of entry */
|
||||
fsinode *inode; /* actual inode data */
|
||||
char *symlink; /* symlink target */
|
||||
char *name; /* file name */
|
||||
int flags; /* misc flags */
|
||||
} fsnode;
|
||||
|
||||
#define FSNODE_F_HASSPEC 0x01 /* fsnode has a spec entry */
|
||||
|
||||
/*
|
||||
* fsinfo_t - contains various settings and parameters pertaining to
|
||||
* the image, including current settings, global options, and fs
|
||||
* specific options
|
||||
*/
|
||||
typedef struct {
|
||||
/* current settings */
|
||||
off_t size; /* total size */
|
||||
off_t inodes; /* number of inodes */
|
||||
uint32_t curinode; /* current inode */
|
||||
|
||||
/* image settings */
|
||||
int fd; /* file descriptor of image */
|
||||
void *superblock; /* superblock */
|
||||
int onlyspec; /* only add entries in specfile */
|
||||
|
||||
|
||||
/* global options */
|
||||
off_t minsize; /* minimum size image should be */
|
||||
off_t maxsize; /* maximum size image can be */
|
||||
off_t freefiles; /* free file entries to leave */
|
||||
int freefilepc; /* free file % */
|
||||
off_t freeblocks; /* free blocks to leave */
|
||||
int freeblockpc; /* free block % */
|
||||
int needswap; /* non-zero if byte swapping needed */
|
||||
int sectorsize; /* sector size */
|
||||
|
||||
/* ffs specific options */
|
||||
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 ? */
|
||||
} fsinfo_t;
|
||||
|
||||
|
||||
/*
|
||||
* option_t - contains option name, description, pointer to location to store
|
||||
* result, and range checks for the result. Used to simplify fs specific
|
||||
* option setting
|
||||
*/
|
||||
typedef struct {
|
||||
const char *name; /* option name */
|
||||
int *value; /* where to stuff the value */
|
||||
int minimum; /* minimum for value */
|
||||
int maximum; /* maximum for value */
|
||||
const char *desc; /* option description */
|
||||
} option_t;
|
||||
|
||||
|
||||
void apply_specfile(const char *, const char *, fsnode *);
|
||||
void dump_fsnodes(const char *, fsnode *);
|
||||
const char * inode_type(mode_t);
|
||||
int set_option(option_t *, const char *, const char *);
|
||||
fsnode * walk_dir(const char *, fsnode *);
|
||||
|
||||
int ffs_parse_opts(const char *, fsinfo_t *);
|
||||
void ffs_makefs(const char *, const char *, fsnode *, fsinfo_t *);
|
||||
|
||||
|
||||
|
||||
extern u_int debug;
|
||||
extern struct timespec start_time;
|
||||
|
||||
/*
|
||||
* If -x is specified, we want to exclude nodes which do not appear
|
||||
* in the spec file.
|
||||
*/
|
||||
#define FSNODE_EXCLUDE_P(opts, fsnode) \
|
||||
((opts)->onlyspec != 0 && ((fsnode)->flags & FSNODE_F_HASSPEC) == 0)
|
||||
|
||||
#define DEBUG_TIME 0x00000001
|
||||
/* debug bits 1..3 unused at this time */
|
||||
#define DEBUG_WALK_DIR 0x00000010
|
||||
#define DEBUG_WALK_DIR_NODE 0x00000020
|
||||
#define DEBUG_WALK_DIR_LINKCHECK 0x00000040
|
||||
#define DEBUG_DUMP_FSNODES 0x00000080
|
||||
#define DEBUG_DUMP_FSNODES_VERBOSE 0x00000100
|
||||
#define DEBUG_FS_PARSE_OPTS 0x00000200
|
||||
#define DEBUG_FS_MAKEFS 0x00000400
|
||||
#define DEBUG_FS_VALIDATE 0x00000800
|
||||
#define DEBUG_FS_CREATE_IMAGE 0x00001000
|
||||
#define DEBUG_FS_SIZE_DIR 0x00002000
|
||||
#define DEBUG_FS_SIZE_DIR_NODE 0x00004000
|
||||
#define DEBUG_FS_SIZE_DIR_ADD_DIRENT 0x00008000
|
||||
#define DEBUG_FS_POPULATE 0x00010000
|
||||
#define DEBUG_FS_POPULATE_DIRBUF 0x00020000
|
||||
#define DEBUG_FS_POPULATE_NODE 0x00040000
|
||||
#define DEBUG_FS_WRITE_FILE 0x00080000
|
||||
#define DEBUG_FS_WRITE_FILE_BLOCK 0x00100000
|
||||
#define DEBUG_FS_MAKE_DIRBUF 0x00200000
|
||||
#define DEBUG_FS_WRITE_INODE 0x00400000
|
||||
#define DEBUG_BUF_BREAD 0x00800000
|
||||
#define DEBUG_BUF_BWRITE 0x01000000
|
||||
#define DEBUG_BUF_GETBLK 0x02000000
|
||||
#define DEBUG_APPLY_SPECFILE 0x04000000
|
||||
#define DEBUG_APPLY_SPECENTRY 0x08000000
|
||||
|
||||
|
||||
#define TIMER_START(x) \
|
||||
if (debug & DEBUG_TIME) \
|
||||
gettimeofday(&(x), NULL)
|
||||
|
||||
#define TIMER_RESULTS(x,d) \
|
||||
if (debug & DEBUG_TIME) { \
|
||||
struct timeval end, td; \
|
||||
gettimeofday(&end, NULL); \
|
||||
timersub(&end, &(x), &td); \
|
||||
printf("%s took %ld.%06ld seconds\n", \
|
||||
(d), td.tv_sec, td.tv_usec); \
|
||||
}
|
||||
|
||||
|
||||
#ifndef DEFAULT_FSTYPE
|
||||
#define DEFAULT_FSTYPE "ffs"
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* ffs specific settings
|
||||
* ---------------------
|
||||
*/
|
||||
|
||||
#define FFS_EI /* for opposite endian support in ffs headers */
|
||||
|
||||
|
||||
#endif /* _MAKEFS_H */
|
612
sys/sys/queue.h
Normal file
612
sys/sys/queue.h
Normal file
@ -0,0 +1,612 @@
|
||||
/* $NetBSD: queue.h,v 1.39 2004/04/18 14:25:34 lukem Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1991, 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.
|
||||
*
|
||||
* @(#)queue.h 8.5 (Berkeley) 8/20/94
|
||||
*/
|
||||
|
||||
#ifndef _SYS_QUEUE_H_
|
||||
#define _SYS_QUEUE_H_
|
||||
|
||||
/*
|
||||
* This file defines five types of data structures: singly-linked lists,
|
||||
* lists, simple queues, tail queues, and circular queues.
|
||||
*
|
||||
* A singly-linked list is headed by a single forward pointer. The
|
||||
* elements are singly linked for minimum space and pointer manipulation
|
||||
* overhead at the expense of O(n) removal for arbitrary elements. New
|
||||
* elements can be added to the list after an existing element or at the
|
||||
* head of the list. Elements being removed from the head of the list
|
||||
* should use the explicit macro for this purpose for optimum
|
||||
* efficiency. A singly-linked list may only be traversed in the forward
|
||||
* direction. Singly-linked lists are ideal for applications with large
|
||||
* datasets and few or no removals or for implementing a LIFO queue.
|
||||
*
|
||||
* A list is headed by a single forward pointer (or an array of forward
|
||||
* pointers for a hash table header). The elements are doubly linked
|
||||
* so that an arbitrary element can be removed without a need to
|
||||
* traverse the list. New elements can be added to the list before
|
||||
* or after an existing element or at the head of the list. A list
|
||||
* may only be traversed in the forward direction.
|
||||
*
|
||||
* A simple queue is headed by a pair of pointers, one the head of the
|
||||
* list and the other to the tail of the list. The elements are singly
|
||||
* linked to save space, so only elements can only be removed from the
|
||||
* head of the list. New elements can be added to the list after
|
||||
* an existing element, at the head of the list, or at the end of the
|
||||
* list. A simple queue may only be traversed in the forward direction.
|
||||
*
|
||||
* A tail queue is headed by a pair of pointers, one to the head of the
|
||||
* list and the other to the tail of the list. The elements are doubly
|
||||
* linked so that an arbitrary element can be removed without a need to
|
||||
* traverse the list. New elements can be added to the list before or
|
||||
* after an existing element, at the head of the list, or at the end of
|
||||
* the list. A tail queue may be traversed in either direction.
|
||||
*
|
||||
* A circle queue is headed by a pair of pointers, one to the head of the
|
||||
* list and the other to the tail of the list. The elements are doubly
|
||||
* linked so that an arbitrary element can be removed without a need to
|
||||
* traverse the list. New elements can be added to the list before or after
|
||||
* an existing element, at the head of the list, or at the end of the list.
|
||||
* A circle queue may be traversed in either direction, but has a more
|
||||
* complex end of list detection.
|
||||
*
|
||||
* For details on the use of these macros, see the queue(3) manual page.
|
||||
*/
|
||||
|
||||
/*
|
||||
* List definitions.
|
||||
*/
|
||||
#define LIST_HEAD(name, type) \
|
||||
struct name { \
|
||||
struct type *lh_first; /* first element */ \
|
||||
}
|
||||
|
||||
#define LIST_HEAD_INITIALIZER(head) \
|
||||
{ NULL }
|
||||
|
||||
#define LIST_ENTRY(type) \
|
||||
struct { \
|
||||
struct type *le_next; /* next element */ \
|
||||
struct type **le_prev; /* address of previous next element */ \
|
||||
}
|
||||
|
||||
/*
|
||||
* List functions.
|
||||
*/
|
||||
#if defined(_KERNEL) && defined(QUEUEDEBUG)
|
||||
#define QUEUEDEBUG_LIST_INSERT_HEAD(head, elm, field) \
|
||||
if ((head)->lh_first && \
|
||||
(head)->lh_first->field.le_prev != &(head)->lh_first) \
|
||||
panic("LIST_INSERT_HEAD %p %s:%d", (head), __FILE__, __LINE__);
|
||||
#define QUEUEDEBUG_LIST_OP(elm, field) \
|
||||
if ((elm)->field.le_next && \
|
||||
(elm)->field.le_next->field.le_prev != \
|
||||
&(elm)->field.le_next) \
|
||||
panic("LIST_* forw %p %s:%d", (elm), __FILE__, __LINE__);\
|
||||
if (*(elm)->field.le_prev != (elm)) \
|
||||
panic("LIST_* back %p %s:%d", (elm), __FILE__, __LINE__);
|
||||
#define QUEUEDEBUG_LIST_POSTREMOVE(elm, field) \
|
||||
(elm)->field.le_next = (void *)1L; \
|
||||
(elm)->field.le_prev = (void *)1L;
|
||||
#else
|
||||
#define QUEUEDEBUG_LIST_INSERT_HEAD(head, elm, field)
|
||||
#define QUEUEDEBUG_LIST_OP(elm, field)
|
||||
#define QUEUEDEBUG_LIST_POSTREMOVE(elm, field)
|
||||
#endif
|
||||
|
||||
#define LIST_INIT(head) do { \
|
||||
(head)->lh_first = NULL; \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define LIST_INSERT_AFTER(listelm, elm, field) do { \
|
||||
QUEUEDEBUG_LIST_OP((listelm), field) \
|
||||
if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \
|
||||
(listelm)->field.le_next->field.le_prev = \
|
||||
&(elm)->field.le_next; \
|
||||
(listelm)->field.le_next = (elm); \
|
||||
(elm)->field.le_prev = &(listelm)->field.le_next; \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define LIST_INSERT_BEFORE(listelm, elm, field) do { \
|
||||
QUEUEDEBUG_LIST_OP((listelm), field) \
|
||||
(elm)->field.le_prev = (listelm)->field.le_prev; \
|
||||
(elm)->field.le_next = (listelm); \
|
||||
*(listelm)->field.le_prev = (elm); \
|
||||
(listelm)->field.le_prev = &(elm)->field.le_next; \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define LIST_INSERT_HEAD(head, elm, field) do { \
|
||||
QUEUEDEBUG_LIST_INSERT_HEAD((head), (elm), field) \
|
||||
if (((elm)->field.le_next = (head)->lh_first) != NULL) \
|
||||
(head)->lh_first->field.le_prev = &(elm)->field.le_next;\
|
||||
(head)->lh_first = (elm); \
|
||||
(elm)->field.le_prev = &(head)->lh_first; \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define LIST_REMOVE(elm, field) do { \
|
||||
QUEUEDEBUG_LIST_OP((elm), field) \
|
||||
if ((elm)->field.le_next != NULL) \
|
||||
(elm)->field.le_next->field.le_prev = \
|
||||
(elm)->field.le_prev; \
|
||||
*(elm)->field.le_prev = (elm)->field.le_next; \
|
||||
QUEUEDEBUG_LIST_POSTREMOVE((elm), field) \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define LIST_FOREACH(var, head, field) \
|
||||
for ((var) = ((head)->lh_first); \
|
||||
(var); \
|
||||
(var) = ((var)->field.le_next))
|
||||
|
||||
/*
|
||||
* List access methods.
|
||||
*/
|
||||
#define LIST_EMPTY(head) ((head)->lh_first == NULL)
|
||||
#define LIST_FIRST(head) ((head)->lh_first)
|
||||
#define LIST_NEXT(elm, field) ((elm)->field.le_next)
|
||||
|
||||
|
||||
/*
|
||||
* Singly-linked List definitions.
|
||||
*/
|
||||
#define SLIST_HEAD(name, type) \
|
||||
struct name { \
|
||||
struct type *slh_first; /* first element */ \
|
||||
}
|
||||
|
||||
#define SLIST_HEAD_INITIALIZER(head) \
|
||||
{ NULL }
|
||||
|
||||
#define SLIST_ENTRY(type) \
|
||||
struct { \
|
||||
struct type *sle_next; /* next element */ \
|
||||
}
|
||||
|
||||
/*
|
||||
* Singly-linked List functions.
|
||||
*/
|
||||
#define SLIST_INIT(head) do { \
|
||||
(head)->slh_first = NULL; \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \
|
||||
(elm)->field.sle_next = (slistelm)->field.sle_next; \
|
||||
(slistelm)->field.sle_next = (elm); \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define SLIST_INSERT_HEAD(head, elm, field) do { \
|
||||
(elm)->field.sle_next = (head)->slh_first; \
|
||||
(head)->slh_first = (elm); \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define SLIST_REMOVE_HEAD(head, field) do { \
|
||||
(head)->slh_first = (head)->slh_first->field.sle_next; \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define SLIST_REMOVE(head, elm, type, field) do { \
|
||||
if ((head)->slh_first == (elm)) { \
|
||||
SLIST_REMOVE_HEAD((head), field); \
|
||||
} \
|
||||
else { \
|
||||
struct type *curelm = (head)->slh_first; \
|
||||
while(curelm->field.sle_next != (elm)) \
|
||||
curelm = curelm->field.sle_next; \
|
||||
curelm->field.sle_next = \
|
||||
curelm->field.sle_next->field.sle_next; \
|
||||
} \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define SLIST_FOREACH(var, head, field) \
|
||||
for((var) = (head)->slh_first; (var); (var) = (var)->field.sle_next)
|
||||
|
||||
/*
|
||||
* Singly-linked List access methods.
|
||||
*/
|
||||
#define SLIST_EMPTY(head) ((head)->slh_first == NULL)
|
||||
#define SLIST_FIRST(head) ((head)->slh_first)
|
||||
#define SLIST_NEXT(elm, field) ((elm)->field.sle_next)
|
||||
|
||||
|
||||
/*
|
||||
* Singly-linked Tail queue declarations.
|
||||
*/
|
||||
#define STAILQ_HEAD(name, type) \
|
||||
struct name { \
|
||||
struct type *stqh_first; /* first element */ \
|
||||
struct type **stqh_last; /* addr of last next element */ \
|
||||
}
|
||||
|
||||
#define STAILQ_HEAD_INITIALIZER(head) \
|
||||
{ NULL, &(head).stqh_first }
|
||||
|
||||
#define STAILQ_ENTRY(type) \
|
||||
struct { \
|
||||
struct type *stqe_next; /* next element */ \
|
||||
}
|
||||
|
||||
/*
|
||||
* Singly-linked Tail queue functions.
|
||||
*/
|
||||
#define STAILQ_INIT(head) do { \
|
||||
(head)->stqh_first = NULL; \
|
||||
(head)->stqh_last = &(head)->stqh_first; \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define STAILQ_INSERT_HEAD(head, elm, field) do { \
|
||||
if (((elm)->field.stqe_next = (head)->stqh_first) == NULL) \
|
||||
(head)->stqh_last = &(elm)->field.stqe_next; \
|
||||
(head)->stqh_first = (elm); \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define STAILQ_INSERT_TAIL(head, elm, field) do { \
|
||||
(elm)->field.stqe_next = NULL; \
|
||||
*(head)->stqh_last = (elm); \
|
||||
(head)->stqh_last = &(elm)->field.stqe_next; \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define STAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
|
||||
if (((elm)->field.stqe_next = (listelm)->field.stqe_next) == NULL)\
|
||||
(head)->stqh_last = &(elm)->field.stqe_next; \
|
||||
(listelm)->field.stqe_next = (elm); \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define STAILQ_REMOVE_HEAD(head, field) do { \
|
||||
if (((head)->stqh_first = (head)->stqh_first->field.stqe_next) == NULL) \
|
||||
(head)->stqh_last = &(head)->stqh_first; \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define STAILQ_REMOVE(head, elm, type, field) do { \
|
||||
if ((head)->stqh_first == (elm)) { \
|
||||
STAILQ_REMOVE_HEAD((head), field); \
|
||||
} else { \
|
||||
struct type *curelm = (head)->stqh_first; \
|
||||
while (curelm->field.stqe_next != (elm)) \
|
||||
curelm = curelm->field.stqe_next; \
|
||||
if ((curelm->field.stqe_next = \
|
||||
curelm->field.stqe_next->field.stqe_next) == NULL) \
|
||||
(head)->stqh_last = &(curelm)->field.stqe_next; \
|
||||
} \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define STAILQ_FOREACH(var, head, field) \
|
||||
for ((var) = ((head)->stqh_first); \
|
||||
(var); \
|
||||
(var) = ((var)->field.stqe_next))
|
||||
|
||||
/*
|
||||
* Singly-linked Tail queue access methods.
|
||||
*/
|
||||
#define STAILQ_EMPTY(head) ((head)->stqh_first == NULL)
|
||||
#define STAILQ_FIRST(head) ((head)->stqh_first)
|
||||
#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next)
|
||||
|
||||
|
||||
/*
|
||||
* Simple queue definitions.
|
||||
*/
|
||||
#define SIMPLEQ_HEAD(name, type) \
|
||||
struct name { \
|
||||
struct type *sqh_first; /* first element */ \
|
||||
struct type **sqh_last; /* addr of last next element */ \
|
||||
}
|
||||
|
||||
#define SIMPLEQ_HEAD_INITIALIZER(head) \
|
||||
{ NULL, &(head).sqh_first }
|
||||
|
||||
#define SIMPLEQ_ENTRY(type) \
|
||||
struct { \
|
||||
struct type *sqe_next; /* next element */ \
|
||||
}
|
||||
|
||||
/*
|
||||
* Simple queue functions.
|
||||
*/
|
||||
#define SIMPLEQ_INIT(head) do { \
|
||||
(head)->sqh_first = NULL; \
|
||||
(head)->sqh_last = &(head)->sqh_first; \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \
|
||||
if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \
|
||||
(head)->sqh_last = &(elm)->field.sqe_next; \
|
||||
(head)->sqh_first = (elm); \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \
|
||||
(elm)->field.sqe_next = NULL; \
|
||||
*(head)->sqh_last = (elm); \
|
||||
(head)->sqh_last = &(elm)->field.sqe_next; \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
|
||||
if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\
|
||||
(head)->sqh_last = &(elm)->field.sqe_next; \
|
||||
(listelm)->field.sqe_next = (elm); \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define SIMPLEQ_REMOVE_HEAD(head, field) do { \
|
||||
if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \
|
||||
(head)->sqh_last = &(head)->sqh_first; \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define SIMPLEQ_REMOVE(head, elm, type, field) do { \
|
||||
if ((head)->sqh_first == (elm)) { \
|
||||
SIMPLEQ_REMOVE_HEAD((head), field); \
|
||||
} else { \
|
||||
struct type *curelm = (head)->sqh_first; \
|
||||
while (curelm->field.sqe_next != (elm)) \
|
||||
curelm = curelm->field.sqe_next; \
|
||||
if ((curelm->field.sqe_next = \
|
||||
curelm->field.sqe_next->field.sqe_next) == NULL) \
|
||||
(head)->sqh_last = &(curelm)->field.sqe_next; \
|
||||
} \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define SIMPLEQ_FOREACH(var, head, field) \
|
||||
for ((var) = ((head)->sqh_first); \
|
||||
(var); \
|
||||
(var) = ((var)->field.sqe_next))
|
||||
|
||||
/*
|
||||
* Simple queue access methods.
|
||||
*/
|
||||
#define SIMPLEQ_EMPTY(head) ((head)->sqh_first == NULL)
|
||||
#define SIMPLEQ_FIRST(head) ((head)->sqh_first)
|
||||
#define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next)
|
||||
|
||||
|
||||
/*
|
||||
* Tail queue definitions.
|
||||
*/
|
||||
#define TAILQ_HEAD(name, type) \
|
||||
struct name { \
|
||||
struct type *tqh_first; /* first element */ \
|
||||
struct type **tqh_last; /* addr of last next element */ \
|
||||
}
|
||||
|
||||
#define TAILQ_HEAD_INITIALIZER(head) \
|
||||
{ NULL, &(head).tqh_first }
|
||||
|
||||
#define TAILQ_ENTRY(type) \
|
||||
struct { \
|
||||
struct type *tqe_next; /* next element */ \
|
||||
struct type **tqe_prev; /* address of previous next element */ \
|
||||
}
|
||||
|
||||
/*
|
||||
* Tail queue functions.
|
||||
*/
|
||||
#if defined(_KERNEL) && defined(QUEUEDEBUG)
|
||||
#define QUEUEDEBUG_TAILQ_INSERT_HEAD(head, elm, field) \
|
||||
if ((head)->tqh_first && \
|
||||
(head)->tqh_first->field.tqe_prev != &(head)->tqh_first) \
|
||||
panic("TAILQ_INSERT_HEAD %p %s:%d", (head), __FILE__, __LINE__);
|
||||
#define QUEUEDEBUG_TAILQ_INSERT_TAIL(head, elm, field) \
|
||||
if (*(head)->tqh_last != NULL) \
|
||||
panic("TAILQ_INSERT_TAIL %p %s:%d", (head), __FILE__, __LINE__);
|
||||
#define QUEUEDEBUG_TAILQ_OP(elm, field) \
|
||||
if ((elm)->field.tqe_next && \
|
||||
(elm)->field.tqe_next->field.tqe_prev != \
|
||||
&(elm)->field.tqe_next) \
|
||||
panic("TAILQ_* forw %p %s:%d", (elm), __FILE__, __LINE__);\
|
||||
if (*(elm)->field.tqe_prev != (elm)) \
|
||||
panic("TAILQ_* back %p %s:%d", (elm), __FILE__, __LINE__);
|
||||
#define QUEUEDEBUG_TAILQ_PREREMOVE(head, elm, field) \
|
||||
if ((elm)->field.tqe_next == NULL && \
|
||||
(head)->tqh_last != &(elm)->field.tqe_next) \
|
||||
panic("TAILQ_PREREMOVE head %p elm %p %s:%d", \
|
||||
(head), (elm), __FILE__, __LINE__);
|
||||
#define QUEUEDEBUG_TAILQ_POSTREMOVE(elm, field) \
|
||||
(elm)->field.tqe_next = (void *)1L; \
|
||||
(elm)->field.tqe_prev = (void *)1L;
|
||||
#else
|
||||
#define QUEUEDEBUG_TAILQ_INSERT_HEAD(head, elm, field)
|
||||
#define QUEUEDEBUG_TAILQ_INSERT_TAIL(head, elm, field)
|
||||
#define QUEUEDEBUG_TAILQ_OP(elm, field)
|
||||
#define QUEUEDEBUG_TAILQ_PREREMOVE(head, elm, field)
|
||||
#define QUEUEDEBUG_TAILQ_POSTREMOVE(elm, field)
|
||||
#endif
|
||||
|
||||
#define TAILQ_INIT(head) do { \
|
||||
(head)->tqh_first = NULL; \
|
||||
(head)->tqh_last = &(head)->tqh_first; \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define TAILQ_INSERT_HEAD(head, elm, field) do { \
|
||||
QUEUEDEBUG_TAILQ_INSERT_HEAD((head), (elm), field) \
|
||||
if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \
|
||||
(head)->tqh_first->field.tqe_prev = \
|
||||
&(elm)->field.tqe_next; \
|
||||
else \
|
||||
(head)->tqh_last = &(elm)->field.tqe_next; \
|
||||
(head)->tqh_first = (elm); \
|
||||
(elm)->field.tqe_prev = &(head)->tqh_first; \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define TAILQ_INSERT_TAIL(head, elm, field) do { \
|
||||
QUEUEDEBUG_TAILQ_INSERT_TAIL((head), (elm), field) \
|
||||
(elm)->field.tqe_next = NULL; \
|
||||
(elm)->field.tqe_prev = (head)->tqh_last; \
|
||||
*(head)->tqh_last = (elm); \
|
||||
(head)->tqh_last = &(elm)->field.tqe_next; \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
|
||||
QUEUEDEBUG_TAILQ_OP((listelm), field) \
|
||||
if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\
|
||||
(elm)->field.tqe_next->field.tqe_prev = \
|
||||
&(elm)->field.tqe_next; \
|
||||
else \
|
||||
(head)->tqh_last = &(elm)->field.tqe_next; \
|
||||
(listelm)->field.tqe_next = (elm); \
|
||||
(elm)->field.tqe_prev = &(listelm)->field.tqe_next; \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \
|
||||
QUEUEDEBUG_TAILQ_OP((listelm), field) \
|
||||
(elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
|
||||
(elm)->field.tqe_next = (listelm); \
|
||||
*(listelm)->field.tqe_prev = (elm); \
|
||||
(listelm)->field.tqe_prev = &(elm)->field.tqe_next; \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define TAILQ_REMOVE(head, elm, field) do { \
|
||||
QUEUEDEBUG_TAILQ_PREREMOVE((head), (elm), field) \
|
||||
QUEUEDEBUG_TAILQ_OP((elm), field) \
|
||||
if (((elm)->field.tqe_next) != NULL) \
|
||||
(elm)->field.tqe_next->field.tqe_prev = \
|
||||
(elm)->field.tqe_prev; \
|
||||
else \
|
||||
(head)->tqh_last = (elm)->field.tqe_prev; \
|
||||
*(elm)->field.tqe_prev = (elm)->field.tqe_next; \
|
||||
QUEUEDEBUG_TAILQ_POSTREMOVE((elm), field); \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define TAILQ_FOREACH(var, head, field) \
|
||||
for ((var) = ((head)->tqh_first); \
|
||||
(var); \
|
||||
(var) = ((var)->field.tqe_next))
|
||||
|
||||
#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \
|
||||
for ((var) = (*(((struct headname *)((head)->tqh_last))->tqh_last)); \
|
||||
(var); \
|
||||
(var) = (*(((struct headname *)((var)->field.tqe_prev))->tqh_last)))
|
||||
|
||||
/*
|
||||
* Tail queue access methods.
|
||||
*/
|
||||
#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL)
|
||||
#define TAILQ_FIRST(head) ((head)->tqh_first)
|
||||
#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
|
||||
|
||||
#define TAILQ_LAST(head, headname) \
|
||||
(*(((struct headname *)((head)->tqh_last))->tqh_last))
|
||||
#define TAILQ_PREV(elm, headname, field) \
|
||||
(*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
|
||||
|
||||
|
||||
/*
|
||||
* Circular queue definitions.
|
||||
*/
|
||||
#define CIRCLEQ_HEAD(name, type) \
|
||||
struct name { \
|
||||
struct type *cqh_first; /* first element */ \
|
||||
struct type *cqh_last; /* last element */ \
|
||||
}
|
||||
|
||||
#define CIRCLEQ_HEAD_INITIALIZER(head) \
|
||||
{ (void *)&head, (void *)&head }
|
||||
|
||||
#define CIRCLEQ_ENTRY(type) \
|
||||
struct { \
|
||||
struct type *cqe_next; /* next element */ \
|
||||
struct type *cqe_prev; /* previous element */ \
|
||||
}
|
||||
|
||||
/*
|
||||
* Circular queue functions.
|
||||
*/
|
||||
#define CIRCLEQ_INIT(head) do { \
|
||||
(head)->cqh_first = (void *)(head); \
|
||||
(head)->cqh_last = (void *)(head); \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
|
||||
(elm)->field.cqe_next = (listelm)->field.cqe_next; \
|
||||
(elm)->field.cqe_prev = (listelm); \
|
||||
if ((listelm)->field.cqe_next == (void *)(head)) \
|
||||
(head)->cqh_last = (elm); \
|
||||
else \
|
||||
(listelm)->field.cqe_next->field.cqe_prev = (elm); \
|
||||
(listelm)->field.cqe_next = (elm); \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \
|
||||
(elm)->field.cqe_next = (listelm); \
|
||||
(elm)->field.cqe_prev = (listelm)->field.cqe_prev; \
|
||||
if ((listelm)->field.cqe_prev == (void *)(head)) \
|
||||
(head)->cqh_first = (elm); \
|
||||
else \
|
||||
(listelm)->field.cqe_prev->field.cqe_next = (elm); \
|
||||
(listelm)->field.cqe_prev = (elm); \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \
|
||||
(elm)->field.cqe_next = (head)->cqh_first; \
|
||||
(elm)->field.cqe_prev = (void *)(head); \
|
||||
if ((head)->cqh_last == (void *)(head)) \
|
||||
(head)->cqh_last = (elm); \
|
||||
else \
|
||||
(head)->cqh_first->field.cqe_prev = (elm); \
|
||||
(head)->cqh_first = (elm); \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \
|
||||
(elm)->field.cqe_next = (void *)(head); \
|
||||
(elm)->field.cqe_prev = (head)->cqh_last; \
|
||||
if ((head)->cqh_first == (void *)(head)) \
|
||||
(head)->cqh_first = (elm); \
|
||||
else \
|
||||
(head)->cqh_last->field.cqe_next = (elm); \
|
||||
(head)->cqh_last = (elm); \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define CIRCLEQ_REMOVE(head, elm, field) do { \
|
||||
if ((elm)->field.cqe_next == (void *)(head)) \
|
||||
(head)->cqh_last = (elm)->field.cqe_prev; \
|
||||
else \
|
||||
(elm)->field.cqe_next->field.cqe_prev = \
|
||||
(elm)->field.cqe_prev; \
|
||||
if ((elm)->field.cqe_prev == (void *)(head)) \
|
||||
(head)->cqh_first = (elm)->field.cqe_next; \
|
||||
else \
|
||||
(elm)->field.cqe_prev->field.cqe_next = \
|
||||
(elm)->field.cqe_next; \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define CIRCLEQ_FOREACH(var, head, field) \
|
||||
for ((var) = ((head)->cqh_first); \
|
||||
(var) != (void *)(head); \
|
||||
(var) = ((var)->field.cqe_next))
|
||||
|
||||
#define CIRCLEQ_FOREACH_REVERSE(var, head, field) \
|
||||
for ((var) = ((head)->cqh_last); \
|
||||
(var) != (void *)(head); \
|
||||
(var) = ((var)->field.cqe_prev))
|
||||
|
||||
/*
|
||||
* Circular queue access methods.
|
||||
*/
|
||||
#define CIRCLEQ_EMPTY(head) ((head)->cqh_first == (void *)(head))
|
||||
#define CIRCLEQ_FIRST(head) ((head)->cqh_first)
|
||||
#define CIRCLEQ_LAST(head) ((head)->cqh_last)
|
||||
#define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next)
|
||||
#define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev)
|
||||
|
||||
#endif /* !_SYS_QUEUE_H_ */
|
270
sys/ufs/ffs/ffs_bswap.c
Normal file
270
sys/ufs/ffs/ffs_bswap.c
Normal file
@ -0,0 +1,270 @@
|
||||
/* $NetBSD: ffs_bswap.c,v 1.28 2004/05/25 14:54:59 hannken 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.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by Manuel Bouyer.
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#if HAVE_NBTOOL_CONFIG_H
|
||||
#include "nbtool_config.h"
|
||||
#endif
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: ffs_bswap.c,v 1.28 2004/05/25 14:54:59 hannken Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
#if defined(_KERNEL)
|
||||
#include <sys/systm.h>
|
||||
#endif
|
||||
|
||||
#include <ufs/ufs/dinode.h>
|
||||
#include <ufs/ufs/ufs_bswap.h>
|
||||
#include <ufs/ffs/fs.h>
|
||||
#include <ufs/ffs/ffs_extern.h>
|
||||
|
||||
#if !defined(_KERNEL)
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#define panic(x) printf("%s\n", (x)), abort()
|
||||
#endif
|
||||
|
||||
void
|
||||
ffs_sb_swap(struct fs *o, struct fs *n)
|
||||
{
|
||||
int i;
|
||||
u_int32_t *o32, *n32;
|
||||
|
||||
/*
|
||||
* In order to avoid a lot of lines, as the first N fields (52)
|
||||
* of the superblock up to fs_fmod are u_int32_t, we just loop
|
||||
* here to convert them.
|
||||
*/
|
||||
o32 = (u_int32_t *)o;
|
||||
n32 = (u_int32_t *)n;
|
||||
for (i = 0; i < offsetof(struct fs, fs_fmod) / sizeof(u_int32_t); i++)
|
||||
n32[i] = bswap32(o32[i]);
|
||||
|
||||
n->fs_swuid = bswap64(o->fs_swuid);
|
||||
n->fs_cgrotor = bswap32(o->fs_cgrotor); /* Unused */
|
||||
n->fs_old_cpc = bswap32(o->fs_old_cpc);
|
||||
|
||||
/* These fields overlap with a possible location for the
|
||||
* historic FS_DYNAMICPOSTBLFMT postbl table, and with the
|
||||
* first half of the historic FS_42POSTBLFMT postbl table.
|
||||
*/
|
||||
n->fs_maxbsize = bswap32(o->fs_maxbsize);
|
||||
n->fs_sblockloc = bswap64(o->fs_sblockloc);
|
||||
ffs_csumtotal_swap(&o->fs_cstotal, &n->fs_cstotal);
|
||||
n->fs_time = bswap64(o->fs_time);
|
||||
n->fs_size = bswap64(o->fs_size);
|
||||
n->fs_dsize = bswap64(o->fs_dsize);
|
||||
n->fs_csaddr = bswap64(o->fs_csaddr);
|
||||
n->fs_pendingblocks = bswap64(o->fs_pendingblocks);
|
||||
n->fs_pendinginodes = bswap32(o->fs_pendinginodes);
|
||||
|
||||
/* These fields overlap with the second half of the
|
||||
* historic FS_42POSTBLFMT postbl table
|
||||
*/
|
||||
for (i = 0; i < FSMAXSNAP; i++)
|
||||
n->fs_snapinum[i] = bswap32(o->fs_snapinum[i]);
|
||||
n->fs_avgfilesize = bswap32(o->fs_avgfilesize);
|
||||
n->fs_avgfpdir = bswap32(o->fs_avgfpdir);
|
||||
/* fs_sparecon[28] - ignore for now */
|
||||
n->fs_flags = bswap32(o->fs_flags);
|
||||
n->fs_contigsumsize = bswap32(o->fs_contigsumsize);
|
||||
n->fs_maxsymlinklen = bswap32(o->fs_maxsymlinklen);
|
||||
n->fs_old_inodefmt = bswap32(o->fs_old_inodefmt);
|
||||
n->fs_maxfilesize = bswap64(o->fs_maxfilesize);
|
||||
n->fs_qbmask = bswap64(o->fs_qbmask);
|
||||
n->fs_qfmask = bswap64(o->fs_qfmask);
|
||||
n->fs_state = bswap32(o->fs_state);
|
||||
n->fs_old_postblformat = bswap32(o->fs_old_postblformat);
|
||||
n->fs_old_nrpos = bswap32(o->fs_old_nrpos);
|
||||
n->fs_old_postbloff = bswap32(o->fs_old_postbloff);
|
||||
n->fs_old_rotbloff = bswap32(o->fs_old_rotbloff);
|
||||
|
||||
n->fs_magic = bswap32(o->fs_magic);
|
||||
}
|
||||
|
||||
void
|
||||
ffs_dinode1_swap(struct ufs1_dinode *o, struct ufs1_dinode *n)
|
||||
{
|
||||
|
||||
n->di_mode = bswap16(o->di_mode);
|
||||
n->di_nlink = bswap16(o->di_nlink);
|
||||
n->di_u.oldids[0] = bswap16(o->di_u.oldids[0]);
|
||||
n->di_u.oldids[1] = bswap16(o->di_u.oldids[1]);
|
||||
n->di_size = bswap64(o->di_size);
|
||||
n->di_atime = bswap32(o->di_atime);
|
||||
n->di_atimensec = bswap32(o->di_atimensec);
|
||||
n->di_mtime = bswap32(o->di_mtime);
|
||||
n->di_mtimensec = bswap32(o->di_mtimensec);
|
||||
n->di_ctime = bswap32(o->di_ctime);
|
||||
n->di_ctimensec = bswap32(o->di_ctimensec);
|
||||
memcpy(n->di_db, o->di_db, (NDADDR + NIADDR) * sizeof(u_int32_t));
|
||||
n->di_flags = bswap32(o->di_flags);
|
||||
n->di_blocks = bswap32(o->di_blocks);
|
||||
n->di_gen = bswap32(o->di_gen);
|
||||
n->di_uid = bswap32(o->di_uid);
|
||||
n->di_gid = bswap32(o->di_gid);
|
||||
}
|
||||
|
||||
void
|
||||
ffs_dinode2_swap(struct ufs2_dinode *o, struct ufs2_dinode *n)
|
||||
{
|
||||
n->di_mode = bswap16(o->di_mode);
|
||||
n->di_nlink = bswap16(o->di_nlink);
|
||||
n->di_uid = bswap32(o->di_uid);
|
||||
n->di_gid = bswap32(o->di_gid);
|
||||
n->di_blksize = bswap32(o->di_blksize);
|
||||
n->di_size = bswap64(o->di_size);
|
||||
n->di_blocks = bswap64(o->di_blocks);
|
||||
n->di_atime = bswap64(o->di_atime);
|
||||
n->di_atimensec = bswap32(o->di_atimensec);
|
||||
n->di_mtime = bswap64(o->di_mtime);
|
||||
n->di_mtimensec = bswap32(o->di_mtimensec);
|
||||
n->di_ctime = bswap64(o->di_ctime);
|
||||
n->di_ctimensec = bswap32(o->di_ctimensec);
|
||||
n->di_birthtime = bswap64(o->di_ctime);
|
||||
n->di_birthnsec = bswap32(o->di_ctimensec);
|
||||
n->di_gen = bswap32(o->di_gen);
|
||||
n->di_kernflags = bswap32(o->di_kernflags);
|
||||
n->di_flags = bswap32(o->di_flags);
|
||||
n->di_extsize = bswap32(o->di_extsize);
|
||||
memcpy(n->di_extb, o->di_extb, (NXADDR + NDADDR + NIADDR) * 8);
|
||||
}
|
||||
|
||||
void
|
||||
ffs_csum_swap(struct csum *o, struct csum *n, int size)
|
||||
{
|
||||
int i;
|
||||
u_int32_t *oint, *nint;
|
||||
|
||||
oint = (u_int32_t*)o;
|
||||
nint = (u_int32_t*)n;
|
||||
|
||||
for (i = 0; i < size / sizeof(u_int32_t); i++)
|
||||
nint[i] = bswap32(oint[i]);
|
||||
}
|
||||
|
||||
void
|
||||
ffs_csumtotal_swap(struct csum_total *o, struct csum_total *n)
|
||||
{
|
||||
n->cs_ndir = bswap64(o->cs_ndir);
|
||||
n->cs_nbfree = bswap64(o->cs_nbfree);
|
||||
n->cs_nifree = bswap64(o->cs_nifree);
|
||||
n->cs_nffree = bswap64(o->cs_nffree);
|
||||
}
|
||||
|
||||
/*
|
||||
* Note that ffs_cg_swap may be called with o == n.
|
||||
*/
|
||||
void
|
||||
ffs_cg_swap(struct cg *o, struct cg *n, struct fs *fs)
|
||||
{
|
||||
int i;
|
||||
u_int32_t *n32, *o32;
|
||||
u_int16_t *n16, *o16;
|
||||
int32_t btotoff, boff, clustersumoff;
|
||||
|
||||
n->cg_firstfield = bswap32(o->cg_firstfield);
|
||||
n->cg_magic = bswap32(o->cg_magic);
|
||||
n->cg_old_time = bswap32(o->cg_old_time);
|
||||
n->cg_cgx = bswap32(o->cg_cgx);
|
||||
n->cg_old_ncyl = bswap16(o->cg_old_ncyl);
|
||||
n->cg_old_niblk = bswap16(o->cg_old_niblk);
|
||||
n->cg_ndblk = bswap32(o->cg_ndblk);
|
||||
n->cg_cs.cs_ndir = bswap32(o->cg_cs.cs_ndir);
|
||||
n->cg_cs.cs_nbfree = bswap32(o->cg_cs.cs_nbfree);
|
||||
n->cg_cs.cs_nifree = bswap32(o->cg_cs.cs_nifree);
|
||||
n->cg_cs.cs_nffree = bswap32(o->cg_cs.cs_nffree);
|
||||
n->cg_rotor = bswap32(o->cg_rotor);
|
||||
n->cg_frotor = bswap32(o->cg_frotor);
|
||||
n->cg_irotor = bswap32(o->cg_irotor);
|
||||
for (i = 0; i < MAXFRAG; i++)
|
||||
n->cg_frsum[i] = bswap32(o->cg_frsum[i]);
|
||||
|
||||
if ((fs->fs_magic != FS_UFS2_MAGIC) &&
|
||||
(fs->fs_old_postblformat == FS_42POSTBLFMT)) { /* old format */
|
||||
struct ocg *on, *oo;
|
||||
int j;
|
||||
on = (struct ocg *)n;
|
||||
oo = (struct ocg *)o;
|
||||
|
||||
for (i = 0; i < 32; i++) {
|
||||
on->cg_btot[i] = bswap32(oo->cg_btot[i]);
|
||||
for (j = 0; j < 8; j++)
|
||||
on->cg_b[i][j] = bswap16(oo->cg_b[i][j]);
|
||||
}
|
||||
memmove(on->cg_iused, oo->cg_iused, 256);
|
||||
on->cg_magic = bswap32(oo->cg_magic);
|
||||
} else { /* new format */
|
||||
|
||||
n->cg_old_btotoff = bswap32(o->cg_old_btotoff);
|
||||
n->cg_old_boff = bswap32(o->cg_old_boff);
|
||||
n->cg_iusedoff = bswap32(o->cg_iusedoff);
|
||||
n->cg_freeoff = bswap32(o->cg_freeoff);
|
||||
n->cg_nextfreeoff = bswap32(o->cg_nextfreeoff);
|
||||
n->cg_clustersumoff = bswap32(o->cg_clustersumoff);
|
||||
n->cg_clusteroff = bswap32(o->cg_clusteroff);
|
||||
n->cg_nclusterblks = bswap32(o->cg_nclusterblks);
|
||||
n->cg_niblk = bswap32(o->cg_niblk);
|
||||
n->cg_initediblk = bswap32(o->cg_initediblk);
|
||||
n->cg_time = bswap64(o->cg_time);
|
||||
|
||||
if (fs->fs_magic == FS_UFS2_MAGIC)
|
||||
return;
|
||||
|
||||
if (n->cg_magic == CG_MAGIC) {
|
||||
btotoff = n->cg_old_btotoff;
|
||||
boff = n->cg_old_boff;
|
||||
clustersumoff = n->cg_clustersumoff;
|
||||
} else {
|
||||
btotoff = bswap32(n->cg_old_btotoff);
|
||||
boff = bswap32(n->cg_old_boff);
|
||||
clustersumoff = bswap32(n->cg_clustersumoff);
|
||||
}
|
||||
n32 = (u_int32_t *)((u_int8_t *)n + btotoff);
|
||||
o32 = (u_int32_t *)((u_int8_t *)o + btotoff);
|
||||
n16 = (u_int16_t *)((u_int8_t *)n + boff);
|
||||
o16 = (u_int16_t *)((u_int8_t *)o + boff);
|
||||
|
||||
for (i = 0; i < fs->fs_old_cpg; i++)
|
||||
n32[i] = bswap32(o32[i]);
|
||||
|
||||
for (i = 0; i < fs->fs_old_cpg * fs->fs_old_nrpos; i++)
|
||||
n16[i] = bswap16(o16[i]);
|
||||
|
||||
n32 = (u_int32_t *)((u_int8_t *)n + clustersumoff);
|
||||
o32 = (u_int32_t *)((u_int8_t *)o + clustersumoff);
|
||||
for (i = 1; i < fs->fs_contigsumsize + 1; i++)
|
||||
n32[i] = bswap32(o32[i]);
|
||||
}
|
||||
}
|
202
sys/ufs/ffs/ffs_extern.h
Normal file
202
sys/ufs/ffs/ffs_extern.h
Normal file
@ -0,0 +1,202 @@
|
||||
/* $NetBSD: ffs_extern.h,v 1.40 2004/06/04 07:43:56 he 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
|
||||
*/
|
||||
|
||||
#ifndef _UFS_FFS_FFS_EXTERN_H_
|
||||
#define _UFS_FFS_FFS_EXTERN_H_
|
||||
|
||||
/*
|
||||
* Sysctl values for the fast filesystem.
|
||||
*/
|
||||
#define FFS_CLUSTERREAD 1 /* cluster reading enabled */
|
||||
#define FFS_CLUSTERWRITE 2 /* cluster writing enabled */
|
||||
#define FFS_REALLOCBLKS 3 /* block reallocation enabled */
|
||||
#define FFS_ASYNCFREE 4 /* asynchronous block freeing enabled */
|
||||
#define FFS_LOG_CHANGEOPT 5 /* log optimalization strategy change */
|
||||
#define FFS_MAXID 6 /* number of valid ffs ids */
|
||||
|
||||
#define FFS_NAMES { \
|
||||
{ 0, 0 }, \
|
||||
{ "doclusterread", CTLTYPE_INT }, \
|
||||
{ "doclusterwrite", CTLTYPE_INT }, \
|
||||
{ "doreallocblks", CTLTYPE_INT }, \
|
||||
{ "doasyncfree", CTLTYPE_INT }, \
|
||||
{ "log_changeopt", CTLTYPE_INT }, \
|
||||
}
|
||||
|
||||
struct buf;
|
||||
struct fid;
|
||||
struct fs;
|
||||
struct inode;
|
||||
struct ufs1_dinode;
|
||||
struct ufs2_dinode;
|
||||
struct mount;
|
||||
struct nameidata;
|
||||
struct proc;
|
||||
struct statvfs;
|
||||
struct timeval;
|
||||
struct timespec;
|
||||
struct ucred;
|
||||
struct ufsmount;
|
||||
struct uio;
|
||||
struct vnode;
|
||||
struct mbuf;
|
||||
struct cg;
|
||||
|
||||
extern struct pool ffs_inode_pool; /* memory pool for inodes */
|
||||
extern struct pool ffs_dinode1_pool; /* memory pool for UFS1 dinodes */
|
||||
extern struct pool ffs_dinode2_pool; /* memory pool for UFS2 dinodes */
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
/* ffs_alloc.c */
|
||||
int ffs_alloc __P((struct inode *, daddr_t, daddr_t , int, struct ucred *,
|
||||
daddr_t *));
|
||||
int ffs_realloccg __P((struct inode *, daddr_t, daddr_t, int, int ,
|
||||
struct ucred *, struct buf **, daddr_t *));
|
||||
int ffs_reallocblks __P((void *));
|
||||
int ffs_valloc __P((void *));
|
||||
daddr_t ffs_blkpref_ufs1 __P((struct inode *, daddr_t, int, int32_t *));
|
||||
daddr_t ffs_blkpref_ufs2 __P((struct inode *, daddr_t, int, int64_t *));
|
||||
void ffs_blkfree __P((struct fs *, struct vnode *, daddr_t, long, ino_t));
|
||||
int ffs_vfree __P((void *));
|
||||
void ffs_clusteracct __P((struct fs *, struct cg *, int32_t, int));
|
||||
int ffs_checkfreefile __P((struct fs *, struct vnode *, ino_t));
|
||||
|
||||
/* ffs_balloc.c */
|
||||
int ffs_balloc __P((void *));
|
||||
|
||||
/* ffs_bswap.c */
|
||||
void ffs_sb_swap __P((struct fs*, struct fs *));
|
||||
void ffs_dinode1_swap __P((struct ufs1_dinode *, struct ufs1_dinode *));
|
||||
void ffs_dinode2_swap __P((struct ufs2_dinode *, struct ufs2_dinode *));
|
||||
void ffs_csum_swap __P((struct csum *, struct csum *, int));
|
||||
void ffs_csumtotal_swap __P((struct csum_total *, struct csum_total *));
|
||||
void ffs_cg_swap __P((struct cg *, struct cg *, struct fs *));
|
||||
|
||||
/* ffs_inode.c */
|
||||
int ffs_update __P((void *));
|
||||
int ffs_truncate __P((void *));
|
||||
|
||||
/* ffs_subr.c */
|
||||
void ffs_load_inode __P((struct buf *, struct inode *, struct fs *, ino_t));
|
||||
int ffs_blkatoff __P((void *));
|
||||
int ffs_freefile __P((void *));
|
||||
void ffs_fragacct __P((struct fs *, int, int32_t[], int, int));
|
||||
#ifdef DIAGNOSTIC
|
||||
void ffs_checkoverlap __P((struct buf *, struct inode *));
|
||||
#endif
|
||||
int ffs_isblock __P((struct fs *, u_char *, int32_t));
|
||||
int ffs_isfreeblock __P((struct fs *, u_char *, int32_t));
|
||||
void ffs_clrblock __P((struct fs *, u_char *, int32_t));
|
||||
void ffs_setblock __P((struct fs *, u_char *, int32_t));
|
||||
|
||||
/* ffs_vfsops.c */
|
||||
void ffs_init __P((void));
|
||||
void ffs_reinit __P((void));
|
||||
void ffs_done __P((void));
|
||||
int ffs_mountroot __P((void));
|
||||
int ffs_mount __P((struct mount *, const char *, void *, struct nameidata *,
|
||||
struct proc *));
|
||||
int ffs_reload __P((struct mount *, struct ucred *, struct proc *));
|
||||
int ffs_mountfs __P((struct vnode *, struct mount *, struct proc *));
|
||||
int ffs_unmount __P((struct mount *, int, struct proc *));
|
||||
int ffs_flushfiles __P((struct mount *, int, struct proc *));
|
||||
int ffs_statvfs __P((struct mount *, struct statvfs *, struct proc *));
|
||||
int ffs_sync __P((struct mount *, int, struct ucred *, struct proc *));
|
||||
int ffs_vget __P((struct mount *, ino_t, struct vnode **));
|
||||
int ffs_fhtovp __P((struct mount *, struct fid *, struct vnode **));
|
||||
int ffs_vptofh __P((struct vnode *, struct fid *));
|
||||
int ffs_sbupdate __P((struct ufsmount *, int));
|
||||
int ffs_cgupdate __P((struct ufsmount *, int));
|
||||
|
||||
/* ffs_appleufs.c */
|
||||
u_int16_t ffs_appleufs_cksum __P((const struct appleufslabel *));
|
||||
int ffs_appleufs_validate __P((const char*,const struct appleufslabel *,struct appleufslabel *));
|
||||
void ffs_appleufs_set __P((struct appleufslabel *, const char *, time_t, uint64_t));
|
||||
|
||||
|
||||
/* ffs_vnops.c */
|
||||
int ffs_read __P((void *));
|
||||
int ffs_write __P((void *));
|
||||
int ffs_fsync __P((void *));
|
||||
int ffs_reclaim __P((void *));
|
||||
int ffs_getpages __P((void *));
|
||||
int ffs_putpages __P((void *));
|
||||
void ffs_gop_size __P((struct vnode *, off_t, off_t *, int));
|
||||
|
||||
#ifdef SYSCTL_SETUP_PROTO
|
||||
SYSCTL_SETUP_PROTO(sysctl_vfs_ffs_setup);
|
||||
#endif /* SYSCTL_SETUP_PROTO */
|
||||
|
||||
__END_DECLS
|
||||
|
||||
|
||||
/*
|
||||
* Snapshot function prototypes.
|
||||
*/
|
||||
int ffs_snapblkfree(struct fs *, struct vnode *, daddr_t, long, ino_t);
|
||||
void ffs_snapremove(struct vnode *);
|
||||
int ffs_snapshot(struct mount *, struct vnode *, struct timespec *);
|
||||
void ffs_snapshot_mount(struct mount *);
|
||||
void ffs_snapshot_unmount(struct mount *);
|
||||
void ffs_snapgone(struct inode *);
|
||||
|
||||
/*
|
||||
* Soft dependency function prototypes.
|
||||
*/
|
||||
void softdep_initialize __P((void));
|
||||
void softdep_reinitialize __P((void));
|
||||
int softdep_mount __P((struct vnode *, struct mount *, struct fs *,
|
||||
struct ucred *));
|
||||
int softdep_flushworklist __P((struct mount *, int *, struct proc *));
|
||||
int softdep_flushfiles __P((struct mount *, int, struct proc *));
|
||||
void softdep_update_inodeblock __P((struct inode *, struct buf *, int));
|
||||
void softdep_load_inodeblock __P((struct inode *));
|
||||
void softdep_freefile __P((void *));
|
||||
void softdep_setup_freeblocks __P((struct inode *, off_t, int));
|
||||
void softdep_setup_inomapdep __P((struct buf *, struct inode *, ino_t));
|
||||
void softdep_setup_blkmapdep __P((struct buf *, struct fs *, daddr_t));
|
||||
void softdep_setup_allocdirect __P((struct inode *, daddr_t, daddr_t,
|
||||
daddr_t, long, long, struct buf *));
|
||||
void softdep_setup_allocindir_meta __P((struct buf *, struct inode *,
|
||||
struct buf *, int, daddr_t));
|
||||
void softdep_setup_allocindir_page __P((struct inode *, daddr_t,
|
||||
struct buf *, int, daddr_t, daddr_t, struct buf *));
|
||||
void softdep_fsync_mountdev __P((struct vnode *));
|
||||
int softdep_sync_metadata __P((void *));
|
||||
|
||||
extern int (**ffs_vnodeop_p) __P((void *));
|
||||
extern int (**ffs_specop_p) __P((void *));
|
||||
extern int (**ffs_fifoop_p) __P((void *));
|
||||
|
||||
#endif /* !_UFS_FFS_FFS_EXTERN_H_ */
|
351
sys/ufs/ffs/ffs_subr.c
Normal file
351
sys/ufs/ffs/ffs_subr.c
Normal file
@ -0,0 +1,351 @@
|
||||
/* $NetBSD: ffs_subr.c,v 1.32 2003/12/30 12:33:24 pk 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_subr.c 8.5 (Berkeley) 3/21/95
|
||||
*/
|
||||
|
||||
#if HAVE_NBTOOL_CONFIG_H
|
||||
#include "nbtool_config.h"
|
||||
#endif
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: ffs_subr.c,v 1.32 2003/12/30 12:33:24 pk Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
|
||||
/* in ffs_tables.c */
|
||||
extern const int inside[], around[];
|
||||
extern const u_char * const fragtbl[];
|
||||
|
||||
#ifndef _KERNEL
|
||||
#include <ufs/ufs/dinode.h>
|
||||
#include <ufs/ffs/fs.h>
|
||||
#include <ufs/ffs/ffs_extern.h>
|
||||
#include <ufs/ufs/ufs_bswap.h>
|
||||
void panic __P((const char *, ...))
|
||||
__attribute__((__noreturn__,__format__(__printf__,1,2)));
|
||||
|
||||
#else /* _KERNEL */
|
||||
#include <sys/systm.h>
|
||||
#include <sys/vnode.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/buf.h>
|
||||
#include <sys/inttypes.h>
|
||||
#include <sys/pool.h>
|
||||
#include <ufs/ufs/inode.h>
|
||||
#include <ufs/ufs/ufsmount.h>
|
||||
#include <ufs/ufs/ufs_extern.h>
|
||||
#include <ufs/ffs/fs.h>
|
||||
#include <ufs/ffs/ffs_extern.h>
|
||||
#include <ufs/ufs/ufs_bswap.h>
|
||||
|
||||
/*
|
||||
* Return buffer with the contents of block "offset" from the beginning of
|
||||
* directory "ip". If "res" is non-zero, fill it in with a pointer to the
|
||||
* remaining space in the directory.
|
||||
*/
|
||||
int
|
||||
ffs_blkatoff(v)
|
||||
void *v;
|
||||
{
|
||||
struct vop_blkatoff_args /* {
|
||||
struct vnode *a_vp;
|
||||
off_t a_offset;
|
||||
char **a_res;
|
||||
struct buf **a_bpp;
|
||||
} */ *ap = v;
|
||||
struct inode *ip;
|
||||
struct fs *fs;
|
||||
struct buf *bp;
|
||||
daddr_t lbn;
|
||||
int bsize, error;
|
||||
|
||||
ip = VTOI(ap->a_vp);
|
||||
fs = ip->i_fs;
|
||||
lbn = lblkno(fs, ap->a_offset);
|
||||
bsize = blksize(fs, ip, lbn);
|
||||
|
||||
*ap->a_bpp = NULL;
|
||||
if ((error = bread(ap->a_vp, lbn, bsize, NOCRED, &bp)) != 0) {
|
||||
brelse(bp);
|
||||
return (error);
|
||||
}
|
||||
if (ap->a_res)
|
||||
*ap->a_res = (char *)bp->b_data + blkoff(fs, ap->a_offset);
|
||||
*ap->a_bpp = bp;
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Load up the contents of an inode and copy the appropriate pieces
|
||||
* to the incore copy.
|
||||
*/
|
||||
void
|
||||
ffs_load_inode(bp, ip, fs, ino)
|
||||
struct buf *bp;
|
||||
struct inode *ip;
|
||||
struct fs *fs;
|
||||
ino_t ino;
|
||||
{
|
||||
struct ufs1_dinode *dp1;
|
||||
struct ufs2_dinode *dp2;
|
||||
|
||||
if (ip->i_ump->um_fstype == UFS1) {
|
||||
dp1 = (struct ufs1_dinode *)bp->b_data + ino_to_fsbo(fs, ino);
|
||||
#ifdef FFS_EI
|
||||
if (UFS_FSNEEDSWAP(fs))
|
||||
ffs_dinode1_swap(dp1, ip->i_din.ffs1_din);
|
||||
else
|
||||
#endif
|
||||
*ip->i_din.ffs1_din = *dp1;
|
||||
|
||||
ip->i_mode = ip->i_ffs1_mode;
|
||||
ip->i_nlink = ip->i_ffs1_nlink;
|
||||
ip->i_size = ip->i_ffs1_size;
|
||||
ip->i_flags = ip->i_ffs1_flags;
|
||||
ip->i_gen = ip->i_ffs1_gen;
|
||||
ip->i_uid = ip->i_ffs1_uid;
|
||||
ip->i_gid = ip->i_ffs1_gid;
|
||||
} else {
|
||||
dp2 = (struct ufs2_dinode *)bp->b_data + ino_to_fsbo(fs, ino);
|
||||
#ifdef FFS_EI
|
||||
if (UFS_FSNEEDSWAP(fs))
|
||||
ffs_dinode2_swap(dp2, ip->i_din.ffs2_din);
|
||||
else
|
||||
#endif
|
||||
*ip->i_din.ffs2_din = *dp2;
|
||||
|
||||
ip->i_mode = ip->i_ffs2_mode;
|
||||
ip->i_nlink = ip->i_ffs2_nlink;
|
||||
ip->i_size = ip->i_ffs2_size;
|
||||
ip->i_flags = ip->i_ffs2_flags;
|
||||
ip->i_gen = ip->i_ffs2_gen;
|
||||
ip->i_uid = ip->i_ffs2_uid;
|
||||
ip->i_gid = ip->i_ffs2_gid;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* _KERNEL */
|
||||
|
||||
/*
|
||||
* Update the frsum fields to reflect addition or deletion
|
||||
* of some frags.
|
||||
*/
|
||||
void
|
||||
ffs_fragacct(fs, fragmap, fraglist, cnt, needswap)
|
||||
struct fs *fs;
|
||||
int fragmap;
|
||||
int32_t fraglist[];
|
||||
int cnt;
|
||||
int needswap;
|
||||
{
|
||||
int inblk;
|
||||
int field, subfield;
|
||||
int siz, pos;
|
||||
|
||||
inblk = (int)(fragtbl[fs->fs_frag][fragmap]) << 1;
|
||||
fragmap <<= 1;
|
||||
for (siz = 1; siz < fs->fs_frag; siz++) {
|
||||
if ((inblk & (1 << (siz + (fs->fs_frag & (NBBY - 1))))) == 0)
|
||||
continue;
|
||||
field = around[siz];
|
||||
subfield = inside[siz];
|
||||
for (pos = siz; pos <= fs->fs_frag; pos++) {
|
||||
if ((fragmap & field) == subfield) {
|
||||
fraglist[siz] = ufs_rw32(
|
||||
ufs_rw32(fraglist[siz], needswap) + cnt,
|
||||
needswap);
|
||||
pos += siz;
|
||||
field <<= siz;
|
||||
subfield <<= siz;
|
||||
}
|
||||
field <<= 1;
|
||||
subfield <<= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(_KERNEL) && defined(DIAGNOSTIC)
|
||||
void
|
||||
ffs_checkoverlap(bp, ip)
|
||||
struct buf *bp;
|
||||
struct inode *ip;
|
||||
{
|
||||
#if 0
|
||||
struct buf *ebp, *ep;
|
||||
daddr_t start, last;
|
||||
struct vnode *vp;
|
||||
|
||||
ebp = &buf[nbuf];
|
||||
start = bp->b_blkno;
|
||||
last = start + btodb(bp->b_bcount) - 1;
|
||||
for (ep = buf; ep < ebp; ep++) {
|
||||
if (ep == bp || (ep->b_flags & B_INVAL) ||
|
||||
ep->b_vp == NULLVP)
|
||||
continue;
|
||||
if (VOP_BMAP(ep->b_vp, (daddr_t)0, &vp, (daddr_t)0, NULL))
|
||||
continue;
|
||||
if (vp != ip->i_devvp)
|
||||
continue;
|
||||
/* look for overlap */
|
||||
if (ep->b_bcount == 0 || ep->b_blkno > last ||
|
||||
ep->b_blkno + btodb(ep->b_bcount) <= start)
|
||||
continue;
|
||||
vprint("Disk overlap", vp);
|
||||
printf("\tstart %" PRId64 ", end %" PRId64 " overlap start "
|
||||
"%" PRId64 ", end %" PRId64 "\n",
|
||||
start, last, ep->b_blkno,
|
||||
ep->b_blkno + btodb(ep->b_bcount) - 1);
|
||||
panic("Disk buffer overlap");
|
||||
}
|
||||
#else
|
||||
printf("ffs_checkoverlap disabled due to buffer cache implementation changes\n");
|
||||
#endif
|
||||
}
|
||||
#endif /* _KERNEL && DIAGNOSTIC */
|
||||
|
||||
/*
|
||||
* block operations
|
||||
*
|
||||
* check if a block is available
|
||||
* returns true if all the correponding bits in the free map are 1
|
||||
* returns false if any corresponding bit in the free map is 0
|
||||
*/
|
||||
int
|
||||
ffs_isblock(fs, cp, h)
|
||||
struct fs *fs;
|
||||
u_char *cp;
|
||||
int32_t h;
|
||||
{
|
||||
u_char mask;
|
||||
|
||||
switch ((int)fs->fs_fragshift) {
|
||||
case 3:
|
||||
return (cp[h] == 0xff);
|
||||
case 2:
|
||||
mask = 0x0f << ((h & 0x1) << 2);
|
||||
return ((cp[h >> 1] & mask) == mask);
|
||||
case 1:
|
||||
mask = 0x03 << ((h & 0x3) << 1);
|
||||
return ((cp[h >> 2] & mask) == mask);
|
||||
case 0:
|
||||
mask = 0x01 << (h & 0x7);
|
||||
return ((cp[h >> 3] & mask) == mask);
|
||||
default:
|
||||
panic("ffs_isblock: unknown fs_fragshift %d",
|
||||
(int)fs->fs_fragshift);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* check if a block is completely allocated
|
||||
* returns true if all the corresponding bits in the free map are 0
|
||||
* returns false if any corresponding bit in the free map is 1
|
||||
*/
|
||||
int
|
||||
ffs_isfreeblock(fs, cp, h)
|
||||
struct fs *fs;
|
||||
u_char *cp;
|
||||
int32_t h;
|
||||
{
|
||||
|
||||
switch ((int)fs->fs_fragshift) {
|
||||
case 3:
|
||||
return (cp[h] == 0);
|
||||
case 2:
|
||||
return ((cp[h >> 1] & (0x0f << ((h & 0x1) << 2))) == 0);
|
||||
case 1:
|
||||
return ((cp[h >> 2] & (0x03 << ((h & 0x3) << 1))) == 0);
|
||||
case 0:
|
||||
return ((cp[h >> 3] & (0x01 << (h & 0x7))) == 0);
|
||||
default:
|
||||
panic("ffs_isfreeblock: unknown fs_fragshift %d",
|
||||
(int)fs->fs_fragshift);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* take a block out of the map
|
||||
*/
|
||||
void
|
||||
ffs_clrblock(fs, cp, h)
|
||||
struct fs *fs;
|
||||
u_char *cp;
|
||||
int32_t h;
|
||||
{
|
||||
|
||||
switch ((int)fs->fs_fragshift) {
|
||||
case 3:
|
||||
cp[h] = 0;
|
||||
return;
|
||||
case 2:
|
||||
cp[h >> 1] &= ~(0x0f << ((h & 0x1) << 2));
|
||||
return;
|
||||
case 1:
|
||||
cp[h >> 2] &= ~(0x03 << ((h & 0x3) << 1));
|
||||
return;
|
||||
case 0:
|
||||
cp[h >> 3] &= ~(0x01 << (h & 0x7));
|
||||
return;
|
||||
default:
|
||||
panic("ffs_clrblock: unknown fs_fragshift %d",
|
||||
(int)fs->fs_fragshift);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* put a block into the map
|
||||
*/
|
||||
void
|
||||
ffs_setblock(fs, cp, h)
|
||||
struct fs *fs;
|
||||
u_char *cp;
|
||||
int32_t h;
|
||||
{
|
||||
|
||||
switch ((int)fs->fs_fragshift) {
|
||||
case 3:
|
||||
cp[h] = 0xff;
|
||||
return;
|
||||
case 2:
|
||||
cp[h >> 1] |= (0x0f << ((h & 0x1) << 2));
|
||||
return;
|
||||
case 1:
|
||||
cp[h >> 2] |= (0x03 << ((h & 0x3) << 1));
|
||||
return;
|
||||
case 0:
|
||||
cp[h >> 3] |= (0x01 << (h & 0x7));
|
||||
return;
|
||||
default:
|
||||
panic("ffs_setblock: unknown fs_fragshift %d",
|
||||
(int)fs->fs_fragshift);
|
||||
}
|
||||
}
|
141
sys/ufs/ffs/ffs_tables.c
Normal file
141
sys/ufs/ffs/ffs_tables.c
Normal file
@ -0,0 +1,141 @@
|
||||
/* $NetBSD: ffs_tables.c,v 1.7 2003/10/27 00:12:42 lukem Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1982, 1986, 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_tables.c 8.1 (Berkeley) 6/11/93
|
||||
*/
|
||||
|
||||
#if HAVE_NBTOOL_CONFIG_H
|
||||
#include "nbtool_config.h"
|
||||
#endif
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: ffs_tables.c,v 1.7 2003/10/27 00:12:42 lukem Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
|
||||
/*
|
||||
* Bit patterns for identifying fragments in the block map
|
||||
* used as ((map & around) == inside)
|
||||
*/
|
||||
const int around[9] = {
|
||||
0x3, 0x7, 0xf, 0x1f, 0x3f, 0x7f, 0xff, 0x1ff, 0x3ff
|
||||
};
|
||||
const int inside[9] = {
|
||||
0x0, 0x2, 0x6, 0xe, 0x1e, 0x3e, 0x7e, 0xfe, 0x1fe
|
||||
};
|
||||
|
||||
/*
|
||||
* Given a block map bit pattern, the frag tables tell whether a
|
||||
* particular size fragment is available.
|
||||
*
|
||||
* used as:
|
||||
* if ((1 << (size - 1)) & fragtbl[fs->fs_frag][map] {
|
||||
* at least one fragment of the indicated size is available
|
||||
* }
|
||||
*
|
||||
* These tables are used by the scanc instruction on the VAX to
|
||||
* quickly find an appropriate fragment.
|
||||
*/
|
||||
const u_char fragtbl124[256] = {
|
||||
0x00, 0x16, 0x16, 0x2a, 0x16, 0x16, 0x26, 0x4e,
|
||||
0x16, 0x16, 0x16, 0x3e, 0x2a, 0x3e, 0x4e, 0x8a,
|
||||
0x16, 0x16, 0x16, 0x3e, 0x16, 0x16, 0x36, 0x5e,
|
||||
0x16, 0x16, 0x16, 0x3e, 0x3e, 0x3e, 0x5e, 0x9e,
|
||||
0x16, 0x16, 0x16, 0x3e, 0x16, 0x16, 0x36, 0x5e,
|
||||
0x16, 0x16, 0x16, 0x3e, 0x3e, 0x3e, 0x5e, 0x9e,
|
||||
0x2a, 0x3e, 0x3e, 0x2a, 0x3e, 0x3e, 0x2e, 0x6e,
|
||||
0x3e, 0x3e, 0x3e, 0x3e, 0x2a, 0x3e, 0x6e, 0xaa,
|
||||
0x16, 0x16, 0x16, 0x3e, 0x16, 0x16, 0x36, 0x5e,
|
||||
0x16, 0x16, 0x16, 0x3e, 0x3e, 0x3e, 0x5e, 0x9e,
|
||||
0x16, 0x16, 0x16, 0x3e, 0x16, 0x16, 0x36, 0x5e,
|
||||
0x16, 0x16, 0x16, 0x3e, 0x3e, 0x3e, 0x5e, 0x9e,
|
||||
0x26, 0x36, 0x36, 0x2e, 0x36, 0x36, 0x26, 0x6e,
|
||||
0x36, 0x36, 0x36, 0x3e, 0x2e, 0x3e, 0x6e, 0xae,
|
||||
0x4e, 0x5e, 0x5e, 0x6e, 0x5e, 0x5e, 0x6e, 0x4e,
|
||||
0x5e, 0x5e, 0x5e, 0x7e, 0x6e, 0x7e, 0x4e, 0xce,
|
||||
0x16, 0x16, 0x16, 0x3e, 0x16, 0x16, 0x36, 0x5e,
|
||||
0x16, 0x16, 0x16, 0x3e, 0x3e, 0x3e, 0x5e, 0x9e,
|
||||
0x16, 0x16, 0x16, 0x3e, 0x16, 0x16, 0x36, 0x5e,
|
||||
0x16, 0x16, 0x16, 0x3e, 0x3e, 0x3e, 0x5e, 0x9e,
|
||||
0x16, 0x16, 0x16, 0x3e, 0x16, 0x16, 0x36, 0x5e,
|
||||
0x16, 0x16, 0x16, 0x3e, 0x3e, 0x3e, 0x5e, 0x9e,
|
||||
0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x7e,
|
||||
0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x7e, 0xbe,
|
||||
0x2a, 0x3e, 0x3e, 0x2a, 0x3e, 0x3e, 0x2e, 0x6e,
|
||||
0x3e, 0x3e, 0x3e, 0x3e, 0x2a, 0x3e, 0x6e, 0xaa,
|
||||
0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x7e,
|
||||
0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x7e, 0xbe,
|
||||
0x4e, 0x5e, 0x5e, 0x6e, 0x5e, 0x5e, 0x6e, 0x4e,
|
||||
0x5e, 0x5e, 0x5e, 0x7e, 0x6e, 0x7e, 0x4e, 0xce,
|
||||
0x8a, 0x9e, 0x9e, 0xaa, 0x9e, 0x9e, 0xae, 0xce,
|
||||
0x9e, 0x9e, 0x9e, 0xbe, 0xaa, 0xbe, 0xce, 0x8a,
|
||||
};
|
||||
|
||||
const u_char fragtbl8[256] = {
|
||||
0x00, 0x01, 0x01, 0x02, 0x01, 0x01, 0x02, 0x04,
|
||||
0x01, 0x01, 0x01, 0x03, 0x02, 0x03, 0x04, 0x08,
|
||||
0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05,
|
||||
0x02, 0x03, 0x03, 0x02, 0x04, 0x05, 0x08, 0x10,
|
||||
0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05,
|
||||
0x01, 0x01, 0x01, 0x03, 0x03, 0x03, 0x05, 0x09,
|
||||
0x02, 0x03, 0x03, 0x02, 0x03, 0x03, 0x02, 0x06,
|
||||
0x04, 0x05, 0x05, 0x06, 0x08, 0x09, 0x10, 0x20,
|
||||
0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05,
|
||||
0x01, 0x01, 0x01, 0x03, 0x03, 0x03, 0x05, 0x09,
|
||||
0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05,
|
||||
0x03, 0x03, 0x03, 0x03, 0x05, 0x05, 0x09, 0x11,
|
||||
0x02, 0x03, 0x03, 0x02, 0x03, 0x03, 0x02, 0x06,
|
||||
0x03, 0x03, 0x03, 0x03, 0x02, 0x03, 0x06, 0x0a,
|
||||
0x04, 0x05, 0x05, 0x06, 0x05, 0x05, 0x06, 0x04,
|
||||
0x08, 0x09, 0x09, 0x0a, 0x10, 0x11, 0x20, 0x40,
|
||||
0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05,
|
||||
0x01, 0x01, 0x01, 0x03, 0x03, 0x03, 0x05, 0x09,
|
||||
0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05,
|
||||
0x03, 0x03, 0x03, 0x03, 0x05, 0x05, 0x09, 0x11,
|
||||
0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05,
|
||||
0x01, 0x01, 0x01, 0x03, 0x03, 0x03, 0x05, 0x09,
|
||||
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x07,
|
||||
0x05, 0x05, 0x05, 0x07, 0x09, 0x09, 0x11, 0x21,
|
||||
0x02, 0x03, 0x03, 0x02, 0x03, 0x03, 0x02, 0x06,
|
||||
0x03, 0x03, 0x03, 0x03, 0x02, 0x03, 0x06, 0x0a,
|
||||
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x07,
|
||||
0x02, 0x03, 0x03, 0x02, 0x06, 0x07, 0x0a, 0x12,
|
||||
0x04, 0x05, 0x05, 0x06, 0x05, 0x05, 0x06, 0x04,
|
||||
0x05, 0x05, 0x05, 0x07, 0x06, 0x07, 0x04, 0x0c,
|
||||
0x08, 0x09, 0x09, 0x0a, 0x09, 0x09, 0x0a, 0x0c,
|
||||
0x10, 0x11, 0x11, 0x12, 0x20, 0x21, 0x40, 0x80,
|
||||
};
|
||||
|
||||
/*
|
||||
* The actual fragtbl array.
|
||||
*/
|
||||
const u_char * const fragtbl[MAXFRAG + 1] = {
|
||||
0, fragtbl124, fragtbl124, 0, fragtbl124, 0, 0, 0, fragtbl8,
|
||||
};
|
728
sys/ufs/ffs/fs.h
Normal file
728
sys/ufs/ffs/fs.h
Normal file
@ -0,0 +1,728 @@
|
||||
/* $NetBSD: fs.h,v 1.44 2004/05/25 14:54:59 hannken Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1982, 1986, 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.
|
||||
*
|
||||
* @(#)fs.h 8.13 (Berkeley) 3/21/95
|
||||
*/
|
||||
|
||||
#ifndef _UFS_FFS_FS_H_
|
||||
#define _UFS_FFS_FS_H_
|
||||
|
||||
/*
|
||||
* Each disk drive contains some number of file systems.
|
||||
* A file system consists of a number of cylinder groups.
|
||||
* Each cylinder group has inodes and data.
|
||||
*
|
||||
* A file system is described by its super-block, which in turn
|
||||
* describes the cylinder groups. The super-block is critical
|
||||
* data and is replicated in each cylinder group to protect against
|
||||
* catastrophic loss. This is done at `newfs' time and the critical
|
||||
* super-block data does not change, so the copies need not be
|
||||
* referenced further unless disaster strikes.
|
||||
*
|
||||
* For file system fs, the offsets of the various blocks of interest
|
||||
* are given in the super block as:
|
||||
* [fs->fs_sblkno] Super-block
|
||||
* [fs->fs_cblkno] Cylinder group block
|
||||
* [fs->fs_iblkno] Inode blocks
|
||||
* [fs->fs_dblkno] Data blocks
|
||||
* The beginning of cylinder group cg in fs, is given by
|
||||
* the ``cgbase(fs, cg)'' macro.
|
||||
*
|
||||
* Depending on the architecture and the media, the superblock may
|
||||
* reside in any one of four places. For tiny media where every block
|
||||
* counts, it is placed at the very front of the partition. Historically,
|
||||
* UFS1 placed it 8K from the front to leave room for the disk label and
|
||||
* a small bootstrap. For UFS2 it got moved to 64K from the front to leave
|
||||
* room for the disk label and a bigger bootstrap, and for really piggy
|
||||
* systems we check at 256K from the front if the first three fail. In
|
||||
* all cases the size of the superblock will be SBLOCKSIZE. All values are
|
||||
* given in byte-offset form, so they do not imply a sector size. The
|
||||
* SBLOCKSEARCH specifies the order in which the locations should be searched.
|
||||
*
|
||||
* Unfortunately the UFS2/FFSv2 change was done without adequate consideration
|
||||
* of backward compatibility. In particular 'newfs' for a FFSv2 partition
|
||||
* must overwrite any old FFSv1 superblock at 8k, and preferrably as many
|
||||
* of the alternates as it can find - otherwise attempting to mount on a
|
||||
* system that only supports FFSv1 is likely to succeed!.
|
||||
* For a small FFSv1 filesystem, an old FFSv2 superblock can be left on
|
||||
* the disk, and a system that tries to find an FFSv2 filesystem in preference
|
||||
* to and FFSv1 one (as NetBSD does) can mount the old FFSv2 filesystem.
|
||||
* As a added bonus, the 'first alternate' superblock of a FFSv1 filesystem
|
||||
* with 64k blocks is at 64k - just where the code looks first when playing
|
||||
* 'hunt the superblock'.
|
||||
*
|
||||
* The ffsv2 superblock layout (which might contain an ffsv1 filesystem)
|
||||
* can be detected by checking for sb->fs_old_flags & FS_FLAGS_UPDATED.
|
||||
* This is the default suberblock type for NetBSD since ffsv2 support was added.
|
||||
*/
|
||||
#define BBSIZE 8192
|
||||
#define BBOFF ((off_t)(0))
|
||||
#define BBLOCK ((daddr_t)(0))
|
||||
|
||||
#define SBLOCK_FLOPPY 0
|
||||
#define SBLOCK_UFS1 8192
|
||||
#define SBLOCK_UFS2 65536
|
||||
#define SBLOCK_PIGGY 262144
|
||||
#define SBLOCKSIZE 8192
|
||||
/*
|
||||
* NB: Do not, under any circumstances, look for an ffsv1 filesystem at
|
||||
* SBLOCK_UFS2. Doing so will find the wrong superblock for filesystems
|
||||
* with a 64k block size.
|
||||
*/
|
||||
#define SBLOCKSEARCH \
|
||||
{ SBLOCK_UFS2, SBLOCK_UFS1, SBLOCK_FLOPPY, SBLOCK_PIGGY, -1 }
|
||||
|
||||
/*
|
||||
* Max number of fragments per block. This value is NOT tweakable.
|
||||
*/
|
||||
#define MAXFRAG 8
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Addresses stored in inodes are capable of addressing fragments
|
||||
* of `blocks'. File system blocks of at most size MAXBSIZE can
|
||||
* be optionally broken into 2, 4, or 8 pieces, each of which is
|
||||
* addressable; these pieces may be DEV_BSIZE, or some multiple of
|
||||
* a DEV_BSIZE unit.
|
||||
*
|
||||
* Large files consist of exclusively large data blocks. To avoid
|
||||
* undue wasted disk space, the last data block of a small file may be
|
||||
* allocated as only as many fragments of a large block as are
|
||||
* necessary. The file system format retains only a single pointer
|
||||
* to such a fragment, which is a piece of a single large block that
|
||||
* has been divided. The size of such a fragment is determinable from
|
||||
* information in the inode, using the ``blksize(fs, ip, lbn)'' macro.
|
||||
*
|
||||
* The file system records space availability at the fragment level;
|
||||
* to determine block availability, aligned fragments are examined.
|
||||
*/
|
||||
|
||||
/*
|
||||
* MINBSIZE is the smallest allowable block size.
|
||||
* In order to insure that it is possible to create files of size
|
||||
* 2^32 with only two levels of indirection, MINBSIZE is set to 4096.
|
||||
* MINBSIZE must be big enough to hold a cylinder group block,
|
||||
* thus changes to (struct cg) must keep its size within MINBSIZE.
|
||||
* Note that super blocks are always of size SBSIZE,
|
||||
* and that both SBSIZE and MAXBSIZE must be >= MINBSIZE.
|
||||
*/
|
||||
#define MINBSIZE 4096
|
||||
|
||||
/*
|
||||
* The path name on which the file system is mounted is maintained
|
||||
* in fs_fsmnt. MAXMNTLEN defines the amount of space allocated in
|
||||
* the super block for this name.
|
||||
*/
|
||||
#define MAXMNTLEN 468
|
||||
|
||||
/*
|
||||
* The volume name for this filesystem is maintained in fs_volname.
|
||||
* MAXVOLLEN defines the length of the buffer allocated.
|
||||
* This space used to be part of of fs_fsmnt.
|
||||
*/
|
||||
#define MAXVOLLEN 32
|
||||
|
||||
/*
|
||||
* There is a 128-byte region in the superblock reserved for in-core
|
||||
* pointers to summary information. Originally this included an array
|
||||
* of pointers to blocks of struct csum; now there are just four
|
||||
* pointers and the remaining space is padded with fs_ocsp[].
|
||||
* NOCSPTRS determines the size of this padding. One pointer (fs_csp)
|
||||
* is taken away to point to a contiguous array of struct csum for
|
||||
* all cylinder groups; a second (fs_maxcluster) points to an array
|
||||
* of cluster sizes that is computed as cylinder groups are inspected;
|
||||
* the third (fs_contigdirs) points to an array that tracks the
|
||||
* creation of new directories; and the fourth (fs_active) is used
|
||||
* by snapshots.
|
||||
*/
|
||||
#define NOCSPTRS ((128 / sizeof(void *)) - 4)
|
||||
|
||||
/*
|
||||
* A summary of contiguous blocks of various sizes is maintained
|
||||
* in each cylinder group. Normally this is set by the initial
|
||||
* value of fs_maxcontig. To conserve space, a maximum summary size
|
||||
* is set by FS_MAXCONTIG.
|
||||
*/
|
||||
#define FS_MAXCONTIG 16
|
||||
|
||||
/*
|
||||
* The maximum number of snapshot nodes that can be associated
|
||||
* with each filesystem. This limit affects only the number of
|
||||
* snapshot files that can be recorded within the superblock so
|
||||
* that they can be found when the filesystem is mounted. However,
|
||||
* maintaining too many will slow the filesystem performance, so
|
||||
* having this limit is a good idea.
|
||||
*/
|
||||
#define FSMAXSNAP 20
|
||||
|
||||
/*
|
||||
* Used to identify special blocks in snapshots:
|
||||
*
|
||||
* BLK_NOCOPY - A block that was unallocated at the time the snapshot
|
||||
* was taken, hence does not need to be copied when written.
|
||||
* BLK_SNAP - A block held by another snapshot that is not needed by this
|
||||
* snapshot. When the other snapshot is freed, the BLK_SNAP entries
|
||||
* are converted to BLK_NOCOPY. These are needed to allow fsck to
|
||||
* identify blocks that are in use by other snapshots (which are
|
||||
* expunged from this snapshot).
|
||||
*/
|
||||
#define BLK_NOCOPY ((daddr_t)(1))
|
||||
#define BLK_SNAP ((daddr_t)(2))
|
||||
|
||||
/*
|
||||
* MINFREE gives the minimum acceptable percentage of file system
|
||||
* blocks which may be free. If the freelist drops below this level
|
||||
* only the superuser may continue to allocate blocks. This may
|
||||
* be set to 0 if no reserve of free blocks is deemed necessary,
|
||||
* however throughput drops by fifty percent if the file system
|
||||
* is run at between 95% and 100% full; thus the minimum default
|
||||
* value of fs_minfree is 5%. However, to get good clustering
|
||||
* performance, 10% is a better choice. hence we use 10% as our
|
||||
* default value. With 10% free space, fragmentation is not a
|
||||
* problem, so we choose to optimize for time.
|
||||
*/
|
||||
#define MINFREE 5
|
||||
#define DEFAULTOPT FS_OPTTIME
|
||||
|
||||
/*
|
||||
* Grigoriy Orlov <gluk@ptci.ru> has done some extensive work to fine
|
||||
* tune the layout preferences for directories within a filesystem.
|
||||
* His algorithm can be tuned by adjusting the following parameters
|
||||
* which tell the system the average file size and the average number
|
||||
* of files per directory. These defaults are well selected for typical
|
||||
* filesystems, but may need to be tuned for odd cases like filesystems
|
||||
* being used for squid caches or news spools.
|
||||
*/
|
||||
#define AVFILESIZ 16384 /* expected average file size */
|
||||
#define AFPDIR 64 /* expected number of files per directory */
|
||||
|
||||
/*
|
||||
* Per cylinder group information; summarized in blocks allocated
|
||||
* from first cylinder group data blocks. These blocks have to be
|
||||
* read in from fs_csaddr (size fs_cssize) in addition to the
|
||||
* super block.
|
||||
*/
|
||||
struct csum {
|
||||
int32_t cs_ndir; /* number of directories */
|
||||
int32_t cs_nbfree; /* number of free blocks */
|
||||
int32_t cs_nifree; /* number of free inodes */
|
||||
int32_t cs_nffree; /* number of free frags */
|
||||
};
|
||||
|
||||
struct csum_total {
|
||||
int64_t cs_ndir; /* number of directories */
|
||||
int64_t cs_nbfree; /* number of free blocks */
|
||||
int64_t cs_nifree; /* number of free inodes */
|
||||
int64_t cs_nffree; /* number of free frags */
|
||||
int64_t cs_spare[4]; /* future expansion */
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Super block for an FFS file system in memory.
|
||||
*/
|
||||
struct fs {
|
||||
int32_t fs_firstfield; /* historic file system linked list, */
|
||||
int32_t fs_unused_1; /* used for incore super blocks */
|
||||
int32_t fs_sblkno; /* addr of super-block in filesys */
|
||||
int32_t fs_cblkno; /* offset of cyl-block in filesys */
|
||||
int32_t fs_iblkno; /* offset of inode-blocks in filesys */
|
||||
int32_t fs_dblkno; /* offset of first data after cg */
|
||||
int32_t fs_old_cgoffset; /* cylinder group offset in cylinder */
|
||||
int32_t fs_old_cgmask; /* used to calc mod fs_ntrak */
|
||||
int32_t fs_old_time; /* last time written */
|
||||
int32_t fs_old_size; /* number of blocks in fs */
|
||||
int32_t fs_old_dsize; /* number of data blocks in fs */
|
||||
int32_t fs_ncg; /* number of cylinder groups */
|
||||
int32_t fs_bsize; /* size of basic blocks in fs */
|
||||
int32_t fs_fsize; /* size of frag blocks in fs */
|
||||
int32_t fs_frag; /* number of frags in a block in fs */
|
||||
/* these are configuration parameters */
|
||||
int32_t fs_minfree; /* minimum percentage of free blocks */
|
||||
int32_t fs_old_rotdelay; /* num of ms for optimal next block */
|
||||
int32_t fs_old_rps; /* disk revolutions per second */
|
||||
/* these fields can be computed from the others */
|
||||
int32_t fs_bmask; /* ``blkoff'' calc of blk offsets */
|
||||
int32_t fs_fmask; /* ``fragoff'' calc of frag offsets */
|
||||
int32_t fs_bshift; /* ``lblkno'' calc of logical blkno */
|
||||
int32_t fs_fshift; /* ``numfrags'' calc number of frags */
|
||||
/* these are configuration parameters */
|
||||
int32_t fs_maxcontig; /* max number of contiguous blks */
|
||||
int32_t fs_maxbpg; /* max number of blks per cyl group */
|
||||
/* these fields can be computed from the others */
|
||||
int32_t fs_fragshift; /* block to frag shift */
|
||||
int32_t fs_fsbtodb; /* fsbtodb and dbtofsb shift constant */
|
||||
int32_t fs_sbsize; /* actual size of super block */
|
||||
int32_t fs_spare1[2]; /* old fs_csmask */
|
||||
/* old fs_csshift */
|
||||
int32_t fs_nindir; /* value of NINDIR */
|
||||
int32_t fs_inopb; /* value of INOPB */
|
||||
int32_t fs_old_nspf; /* value of NSPF */
|
||||
/* yet another configuration parameter */
|
||||
int32_t fs_optim; /* optimization preference, see below */
|
||||
/* these fields are derived from the hardware */
|
||||
int32_t fs_old_npsect; /* # sectors/track including spares */
|
||||
int32_t fs_old_interleave; /* hardware sector interleave */
|
||||
int32_t fs_old_trackskew; /* sector 0 skew, per track */
|
||||
/* fs_id takes the space of the unused fs_headswitch and fs_trkseek fields */
|
||||
int32_t fs_id[2]; /* unique file system id */
|
||||
/* sizes determined by number of cylinder groups and their sizes */
|
||||
int32_t fs_old_csaddr; /* blk addr of cyl grp summary area */
|
||||
int32_t fs_cssize; /* size of cyl grp summary area */
|
||||
int32_t fs_cgsize; /* cylinder group size */
|
||||
/* these fields are derived from the hardware */
|
||||
int32_t fs_spare2; /* old fs_ntrak */
|
||||
int32_t fs_old_nsect; /* sectors per track */
|
||||
int32_t fs_old_spc; /* sectors per cylinder */
|
||||
int32_t fs_old_ncyl; /* cylinders in file system */
|
||||
int32_t fs_old_cpg; /* cylinders per group */
|
||||
int32_t fs_ipg; /* inodes per group */
|
||||
int32_t fs_fpg; /* blocks per group * fs_frag */
|
||||
/* this data must be re-computed after crashes */
|
||||
struct csum fs_old_cstotal; /* cylinder summary information */
|
||||
/* these fields are cleared at mount time */
|
||||
int8_t fs_fmod; /* super block modified flag */
|
||||
int8_t fs_clean; /* file system is clean flag */
|
||||
int8_t fs_ronly; /* mounted read-only flag */
|
||||
uint8_t fs_old_flags; /* see FS_ flags below */
|
||||
u_char fs_fsmnt[MAXMNTLEN]; /* name mounted on */
|
||||
u_char fs_volname[MAXVOLLEN]; /* volume name */
|
||||
uint64_t fs_swuid; /* system-wide uid */
|
||||
int32_t fs_pad;
|
||||
/* these fields retain the current block allocation info */
|
||||
int32_t fs_cgrotor; /* last cg searched (UNUSED) */
|
||||
void *fs_ocsp[NOCSPTRS]; /* padding; was list of fs_cs buffers */
|
||||
u_int8_t *fs_contigdirs; /* # of contiguously allocated dirs */
|
||||
struct csum *fs_csp; /* cg summary info buffer for fs_cs */
|
||||
int32_t *fs_maxcluster; /* max cluster in each cyl group */
|
||||
u_char *fs_active; /* used by snapshots to track fs */
|
||||
int32_t fs_old_cpc; /* cyl per cycle in postbl */
|
||||
/* this area is otherwise allocated unless fs_old_flags & FS_FLAGS_UPDATED */
|
||||
int32_t fs_maxbsize; /* maximum blocking factor permitted */
|
||||
int64_t fs_sparecon64[17]; /* old rotation block list head */
|
||||
int64_t fs_sblockloc; /* byte offset of standard superblock */
|
||||
struct csum_total fs_cstotal; /* cylinder summary information */
|
||||
int64_t fs_time; /* last time written */
|
||||
int64_t fs_size; /* number of blocks in fs */
|
||||
int64_t fs_dsize; /* number of data blocks in fs */
|
||||
int64_t fs_csaddr; /* blk addr of cyl grp summary area */
|
||||
int64_t fs_pendingblocks; /* blocks in process of being freed */
|
||||
int32_t fs_pendinginodes; /* inodes in process of being freed */
|
||||
int32_t fs_snapinum[FSMAXSNAP];/* list of snapshot inode numbers */
|
||||
/* back to stuff that has been around a while */
|
||||
int32_t fs_avgfilesize; /* expected average file size */
|
||||
int32_t fs_avgfpdir; /* expected # of files per directory */
|
||||
int32_t fs_save_cgsize; /* save real cg size to use fs_bsize */
|
||||
int32_t fs_sparecon32[26]; /* reserved for future constants */
|
||||
uint32_t fs_flags; /* see FS_ flags below */
|
||||
/* back to stuff that has been around a while (again) */
|
||||
int32_t fs_contigsumsize; /* size of cluster summary array */
|
||||
int32_t fs_maxsymlinklen; /* max length of an internal symlink */
|
||||
int32_t fs_old_inodefmt; /* format of on-disk inodes */
|
||||
u_int64_t fs_maxfilesize; /* maximum representable file size */
|
||||
int64_t fs_qbmask; /* ~fs_bmask for use with 64-bit size */
|
||||
int64_t fs_qfmask; /* ~fs_fmask for use with 64-bit size */
|
||||
int32_t fs_state; /* validate fs_clean field (UNUSED) */
|
||||
int32_t fs_old_postblformat; /* format of positional layout tables */
|
||||
int32_t fs_old_nrpos; /* number of rotational positions */
|
||||
int32_t fs_spare5[2]; /* old fs_postbloff */
|
||||
/* old fs_rotbloff */
|
||||
int32_t fs_magic; /* magic number */
|
||||
};
|
||||
|
||||
#define fs_old_postbloff fs_spare5[0]
|
||||
#define fs_old_rotbloff fs_spare5[1]
|
||||
#define fs_old_postbl_start fs_maxbsize
|
||||
#define fs_old_headswitch fs_id[0]
|
||||
#define fs_old_trkseek fs_id[1]
|
||||
#define fs_old_csmask fs_spare1[0]
|
||||
#define fs_old_csshift fs_spare1[1]
|
||||
|
||||
#define FS_42POSTBLFMT -1 /* 4.2BSD rotational table format */
|
||||
#define FS_DYNAMICPOSTBLFMT 1 /* dynamic rotational table format */
|
||||
|
||||
#define old_fs_postbl(fs_, cylno, opostblsave) \
|
||||
((((fs_)->fs_old_postblformat == FS_42POSTBLFMT) || \
|
||||
((fs_)->fs_old_postbloff == offsetof(struct fs, fs_old_postbl_start))) \
|
||||
? ((int16_t *)(opostblsave) + (cylno) * (fs_)->fs_old_nrpos) \
|
||||
: ((int16_t *)((uint8_t *)(fs_) + \
|
||||
(fs_)->fs_old_postbloff) + (cylno) * (fs_)->fs_old_nrpos))
|
||||
#define old_fs_rotbl(fs) \
|
||||
(((fs)->fs_old_postblformat == FS_42POSTBLFMT) \
|
||||
? ((uint8_t *)(&(fs)->fs_magic+1)) \
|
||||
: ((uint8_t *)((uint8_t *)(fs) + (fs)->fs_old_rotbloff)))
|
||||
|
||||
/*
|
||||
* File system identification
|
||||
*/
|
||||
#define FS_UFS1_MAGIC 0x011954 /* UFS1 fast file system magic number */
|
||||
#define FS_UFS2_MAGIC 0x19540119 /* UFS2 fast file system magic number */
|
||||
#define FS_UFS1_MAGIC_SWAPPED 0x54190100
|
||||
#define FS_UFS2_MAGIC_SWAPPED 0x19015419
|
||||
#define FS_OKAY 0x7c269d38 /* superblock checksum */
|
||||
#define FS_42INODEFMT -1 /* 4.2BSD inode format */
|
||||
#define FS_44INODEFMT 2 /* 4.4BSD inode format */
|
||||
|
||||
/*
|
||||
* File system clean flags
|
||||
*/
|
||||
#define FS_ISCLEAN 0x01
|
||||
#define FS_WASCLEAN 0x02
|
||||
|
||||
/*
|
||||
* Preference for optimization.
|
||||
*/
|
||||
#define FS_OPTTIME 0 /* minimize allocation time */
|
||||
#define FS_OPTSPACE 1 /* minimize disk fragmentation */
|
||||
|
||||
/*
|
||||
* File system flags
|
||||
*/
|
||||
#define FS_UNCLEAN 0x01 /* file system not clean at mount (unused) */
|
||||
#define FS_DOSOFTDEP 0x02 /* file system using soft dependencies */
|
||||
#define FS_NEEDSFSCK 0x04 /* needs sync fsck (FreeBSD compat, unused) */
|
||||
#define FS_INDEXDIRS 0x08 /* kernel supports indexed directories */
|
||||
#define FS_ACLS 0x10 /* file system has ACLs enabled */
|
||||
#define FS_MULTILABEL 0x20 /* file system is MAC multi-label */
|
||||
#define FS_FLAGS_UPDATED 0x80 /* flags have been moved to new location */
|
||||
|
||||
/*
|
||||
* File system internal flags, also in fs_flags.
|
||||
* (Pick highest number to avoid conflicts with others)
|
||||
*/
|
||||
#define FS_SWAPPED 0x80000000 /* file system is endian swapped */
|
||||
#define FS_INTERNAL 0x80000000 /* mask for internal flags */
|
||||
|
||||
/*
|
||||
* Macros to access bits in the fs_active array.
|
||||
*/
|
||||
#define ACTIVECG_SET(fs, cg) \
|
||||
do { \
|
||||
if ((fs)->fs_active != NULL) \
|
||||
setbit((fs)->fs_active, (cg)); \
|
||||
} while (/*CONSTCOND*/ 0)
|
||||
#define ACTIVECG_CLR(fs, cg) \
|
||||
do { \
|
||||
if ((fs)->fs_active != NULL) \
|
||||
clrbit((fs)->fs_active, (cg)); \
|
||||
} while (/*CONSTCOND*/ 0)
|
||||
#define ACTIVECG_ISSET(fs, cg) \
|
||||
((fs)->fs_active != NULL && isset((fs)->fs_active, (cg)))
|
||||
|
||||
/*
|
||||
* The size of a cylinder group is calculated by CGSIZE. The maximum size
|
||||
* is limited by the fact that cylinder groups are at most one block.
|
||||
* Its size is derived from the size of the maps maintained in the
|
||||
* cylinder group and the (struct cg) size.
|
||||
*/
|
||||
#define CGSIZE_IF(fs, ipg, fpg) \
|
||||
/* base cg */ (sizeof(struct cg) + sizeof(int32_t) + \
|
||||
/* old btotoff */ (fs)->fs_old_cpg * sizeof(int32_t) + \
|
||||
/* old boff */ (fs)->fs_old_cpg * sizeof(u_int16_t) + \
|
||||
/* inode map */ howmany((ipg), NBBY) + \
|
||||
/* block map */ howmany((fpg), NBBY) +\
|
||||
/* if present */ ((fs)->fs_contigsumsize <= 0 ? 0 : \
|
||||
/* cluster sum */ (fs)->fs_contigsumsize * sizeof(int32_t) + \
|
||||
/* cluster map */ howmany(fragstoblks(fs, (fpg)), NBBY)))
|
||||
|
||||
#define CGSIZE(fs) CGSIZE_IF((fs), (fs)->fs_ipg, (fs)->fs_fpg)
|
||||
|
||||
/*
|
||||
* The minimal number of cylinder groups that should be created.
|
||||
*/
|
||||
#define MINCYLGRPS 4
|
||||
|
||||
|
||||
/*
|
||||
* Convert cylinder group to base address of its global summary info.
|
||||
*/
|
||||
#define fs_cs(fs, indx) fs_csp[indx]
|
||||
|
||||
/*
|
||||
* Cylinder group block for a file system.
|
||||
*/
|
||||
#define CG_MAGIC 0x090255
|
||||
struct cg {
|
||||
int32_t cg_firstfield; /* historic cyl groups linked list */
|
||||
int32_t cg_magic; /* magic number */
|
||||
int32_t cg_old_time; /* time last written */
|
||||
int32_t cg_cgx; /* we are the cgx'th cylinder group */
|
||||
int16_t cg_old_ncyl; /* number of cyl's this cg */
|
||||
int16_t cg_old_niblk; /* number of inode blocks this cg */
|
||||
int32_t cg_ndblk; /* number of data blocks this cg */
|
||||
struct csum cg_cs; /* cylinder summary information */
|
||||
int32_t cg_rotor; /* position of last used block */
|
||||
int32_t cg_frotor; /* position of last used frag */
|
||||
int32_t cg_irotor; /* position of last used inode */
|
||||
int32_t cg_frsum[MAXFRAG]; /* counts of available frags */
|
||||
int32_t cg_old_btotoff; /* (int32) block totals per cylinder */
|
||||
int32_t cg_old_boff; /* (u_int16) free block positions */
|
||||
int32_t cg_iusedoff; /* (u_int8) used inode map */
|
||||
int32_t cg_freeoff; /* (u_int8) free block map */
|
||||
int32_t cg_nextfreeoff; /* (u_int8) next available space */
|
||||
int32_t cg_clustersumoff; /* (u_int32) counts of avail clusters */
|
||||
int32_t cg_clusteroff; /* (u_int8) free cluster map */
|
||||
int32_t cg_nclusterblks; /* number of clusters this cg */
|
||||
int32_t cg_niblk; /* number of inode blocks this cg */
|
||||
int32_t cg_initediblk; /* last initialized inode */
|
||||
int32_t cg_sparecon32[3]; /* reserved for future use */
|
||||
int64_t cg_time; /* time last written */
|
||||
int64_t cg_sparecon64[3]; /* reserved for future use */
|
||||
u_int8_t cg_space[1]; /* space for cylinder group maps */
|
||||
/* actually longer */
|
||||
};
|
||||
|
||||
/*
|
||||
* The following structure is defined
|
||||
* for compatibility with old file systems.
|
||||
*/
|
||||
struct ocg {
|
||||
int32_t cg_firstfield; /* historic linked list of cyl groups */
|
||||
int32_t cg_unused_1; /* used for incore cyl groups */
|
||||
int32_t cg_time; /* time last written */
|
||||
int32_t cg_cgx; /* we are the cgx'th cylinder group */
|
||||
int16_t cg_ncyl; /* number of cyl's this cg */
|
||||
int16_t cg_niblk; /* number of inode blocks this cg */
|
||||
int32_t cg_ndblk; /* number of data blocks this cg */
|
||||
struct csum cg_cs; /* cylinder summary information */
|
||||
int32_t cg_rotor; /* position of last used block */
|
||||
int32_t cg_frotor; /* position of last used frag */
|
||||
int32_t cg_irotor; /* position of last used inode */
|
||||
int32_t cg_frsum[8]; /* counts of available frags */
|
||||
int32_t cg_btot[32]; /* block totals per cylinder */
|
||||
int16_t cg_b[32][8]; /* positions of free blocks */
|
||||
u_int8_t cg_iused[256]; /* used inode map */
|
||||
int32_t cg_magic; /* magic number */
|
||||
u_int8_t cg_free[1]; /* free block map */
|
||||
/* actually longer */
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Macros for access to cylinder group array structures.
|
||||
*/
|
||||
#define old_cg_blktot_old(cgp, ns) \
|
||||
(((struct ocg *)(cgp))->cg_btot)
|
||||
#define old_cg_blks_old(fs, cgp, cylno, ns) \
|
||||
(((struct ocg *)(cgp))->cg_b[cylno])
|
||||
|
||||
#define old_cg_blktot_new(cgp, ns) \
|
||||
((int32_t *)((u_int8_t *)(cgp) + \
|
||||
ufs_rw32((cgp)->cg_old_btotoff, (ns))))
|
||||
#define old_cg_blks_new(fs, cgp, cylno, ns) \
|
||||
((int16_t *)((u_int8_t *)(cgp) + \
|
||||
ufs_rw32((cgp)->cg_old_boff, (ns))) + (cylno) * (fs)->fs_old_nrpos)
|
||||
|
||||
#define old_cg_blktot(cgp, ns) \
|
||||
((ufs_rw32((cgp)->cg_magic, (ns)) != CG_MAGIC) ? \
|
||||
old_cg_blktot_old(cgp, ns) : old_cg_blktot_new(cgp, ns))
|
||||
#define old_cg_blks(fs, cgp, cylno, ns) \
|
||||
((ufs_rw32((cgp)->cg_magic, (ns)) != CG_MAGIC) ? \
|
||||
old_cg_blks_old(fs, cgp, cylno, ns) : old_cg_blks_new(fs, cgp, cylno, ns))
|
||||
|
||||
#define cg_inosused_new(cgp, ns) \
|
||||
((u_int8_t *)((u_int8_t *)(cgp) + \
|
||||
ufs_rw32((cgp)->cg_iusedoff, (ns))))
|
||||
#define cg_blksfree_new(cgp, ns) \
|
||||
((u_int8_t *)((u_int8_t *)(cgp) + \
|
||||
ufs_rw32((cgp)->cg_freeoff, (ns))))
|
||||
#define cg_chkmagic_new(cgp, ns) \
|
||||
(ufs_rw32((cgp)->cg_magic, (ns)) == CG_MAGIC)
|
||||
|
||||
#define cg_inosused_old(cgp, ns) \
|
||||
(((struct ocg *)(cgp))->cg_iused)
|
||||
#define cg_blksfree_old(cgp, ns) \
|
||||
(((struct ocg *)(cgp))->cg_free)
|
||||
#define cg_chkmagic_old(cgp, ns) \
|
||||
(ufs_rw32(((struct ocg *)(cgp))->cg_magic, (ns)) == CG_MAGIC)
|
||||
|
||||
#define cg_inosused(cgp, ns) \
|
||||
((ufs_rw32((cgp)->cg_magic, (ns)) != CG_MAGIC) ? \
|
||||
cg_inosused_old(cgp, ns) : cg_inosused_new(cgp, ns))
|
||||
#define cg_blksfree(cgp, ns) \
|
||||
((ufs_rw32((cgp)->cg_magic, (ns)) != CG_MAGIC) ? \
|
||||
cg_blksfree_old(cgp, ns) : cg_blksfree_new(cgp, ns))
|
||||
#define cg_chkmagic(cgp, ns) \
|
||||
(cg_chkmagic_new(cgp, ns) || cg_chkmagic_old(cgp, ns))
|
||||
|
||||
#define cg_clustersfree(cgp, ns) \
|
||||
((u_int8_t *)((u_int8_t *)(cgp) + \
|
||||
ufs_rw32((cgp)->cg_clusteroff, (ns))))
|
||||
#define cg_clustersum(cgp, ns) \
|
||||
((int32_t *)((u_int8_t *)(cgp) + \
|
||||
ufs_rw32((cgp)->cg_clustersumoff, (ns))))
|
||||
|
||||
|
||||
/*
|
||||
* Turn file system block numbers into disk block addresses.
|
||||
* This maps file system blocks to device size blocks.
|
||||
*/
|
||||
#define fsbtodb(fs, b) ((b) << (fs)->fs_fsbtodb)
|
||||
#define dbtofsb(fs, b) ((b) >> (fs)->fs_fsbtodb)
|
||||
|
||||
/*
|
||||
* Cylinder group macros to locate things in cylinder groups.
|
||||
* They calc file system addresses of cylinder group data structures.
|
||||
*/
|
||||
#define cgbase(fs, c) (((daddr_t)(fs)->fs_fpg) * (c))
|
||||
#define cgstart_ufs1(fs, c) \
|
||||
(cgbase(fs, c) + (fs)->fs_old_cgoffset * ((c) & ~((fs)->fs_old_cgmask)))
|
||||
#define cgstart_ufs2(fs, c) cgbase((fs), (c))
|
||||
#define cgstart(fs, c) ((fs)->fs_magic == FS_UFS2_MAGIC \
|
||||
? cgstart_ufs2((fs), (c)) : cgstart_ufs1((fs), (c)))
|
||||
#define cgdmin(fs, c) (cgstart(fs, c) + (fs)->fs_dblkno) /* 1st data */
|
||||
#define cgimin(fs, c) (cgstart(fs, c) + (fs)->fs_iblkno) /* inode blk */
|
||||
#define cgsblock(fs, c) (cgstart(fs, c) + (fs)->fs_sblkno) /* super blk */
|
||||
#define cgtod(fs, c) (cgstart(fs, c) + (fs)->fs_cblkno) /* cg block */
|
||||
|
||||
/*
|
||||
* Macros for handling inode numbers:
|
||||
* inode number to file system block offset.
|
||||
* inode number to cylinder group number.
|
||||
* inode number to file system block address.
|
||||
*/
|
||||
#define ino_to_cg(fs, x) ((x) / (fs)->fs_ipg)
|
||||
#define ino_to_fsba(fs, x) \
|
||||
((daddr_t)(cgimin(fs, ino_to_cg(fs, x)) + \
|
||||
(blkstofrags((fs), (((x) % (fs)->fs_ipg) / INOPB(fs))))))
|
||||
#define ino_to_fsbo(fs, x) ((x) % INOPB(fs))
|
||||
|
||||
/*
|
||||
* Give cylinder group number for a file system block.
|
||||
* Give cylinder group block number for a file system block.
|
||||
*/
|
||||
#define dtog(fs, d) ((d) / (fs)->fs_fpg)
|
||||
#define dtogd(fs, d) ((d) % (fs)->fs_fpg)
|
||||
|
||||
/*
|
||||
* Extract the bits for a block from a map.
|
||||
* Compute the cylinder and rotational position of a cyl block addr.
|
||||
*/
|
||||
#define blkmap(fs, map, loc) \
|
||||
(((map)[(loc) / NBBY] >> ((loc) % NBBY)) & (0xff >> (NBBY - (fs)->fs_frag)))
|
||||
#define old_cbtocylno(fs, bno) \
|
||||
(fsbtodb(fs, bno) / (fs)->fs_old_spc)
|
||||
#define old_cbtorpos(fs, bno) \
|
||||
((fs)->fs_old_nrpos <= 1 ? 0 : \
|
||||
(fsbtodb(fs, bno) % (fs)->fs_old_spc / (fs)->fs_old_nsect * (fs)->fs_old_trackskew + \
|
||||
fsbtodb(fs, bno) % (fs)->fs_old_spc % (fs)->fs_old_nsect * (fs)->fs_old_interleave) % \
|
||||
(fs)->fs_old_nsect * (fs)->fs_old_nrpos / (fs)->fs_old_npsect)
|
||||
|
||||
/*
|
||||
* The following macros optimize certain frequently calculated
|
||||
* quantities by using shifts and masks in place of divisions
|
||||
* modulos and multiplications.
|
||||
*/
|
||||
#define blkoff(fs, loc) /* calculates (loc % fs->fs_bsize) */ \
|
||||
((loc) & (fs)->fs_qbmask)
|
||||
#define fragoff(fs, loc) /* calculates (loc % fs->fs_fsize) */ \
|
||||
((loc) & (fs)->fs_qfmask)
|
||||
#define lfragtosize(fs, frag) /* calculates ((off_t)frag * fs->fs_fsize) */ \
|
||||
(((off_t)(frag)) << (fs)->fs_fshift)
|
||||
#define lblktosize(fs, blk) /* calculates ((off_t)blk * fs->fs_bsize) */ \
|
||||
(((off_t)(blk)) << (fs)->fs_bshift)
|
||||
#define lblkno(fs, loc) /* calculates (loc / fs->fs_bsize) */ \
|
||||
((loc) >> (fs)->fs_bshift)
|
||||
#define numfrags(fs, loc) /* calculates (loc / fs->fs_fsize) */ \
|
||||
((loc) >> (fs)->fs_fshift)
|
||||
#define blkroundup(fs, size) /* calculates roundup(size, fs->fs_bsize) */ \
|
||||
(((size) + (fs)->fs_qbmask) & (fs)->fs_bmask)
|
||||
#define fragroundup(fs, size) /* calculates roundup(size, fs->fs_fsize) */ \
|
||||
(((size) + (fs)->fs_qfmask) & (fs)->fs_fmask)
|
||||
#define fragstoblks(fs, frags) /* calculates (frags / fs->fs_frag) */ \
|
||||
((frags) >> (fs)->fs_fragshift)
|
||||
#define blkstofrags(fs, blks) /* calculates (blks * fs->fs_frag) */ \
|
||||
((blks) << (fs)->fs_fragshift)
|
||||
#define fragnum(fs, fsb) /* calculates (fsb % fs->fs_frag) */ \
|
||||
((fsb) & ((fs)->fs_frag - 1))
|
||||
#define blknum(fs, fsb) /* calculates rounddown(fsb, fs->fs_frag) */ \
|
||||
((fsb) &~ ((fs)->fs_frag - 1))
|
||||
|
||||
/*
|
||||
* Determine the number of available frags given a
|
||||
* percentage to hold in reserve.
|
||||
*/
|
||||
#define freespace(fs, percentreserved) \
|
||||
(blkstofrags((fs), (fs)->fs_cstotal.cs_nbfree) + \
|
||||
(fs)->fs_cstotal.cs_nffree - \
|
||||
(((off_t)((fs)->fs_dsize)) * (percentreserved) / 100))
|
||||
|
||||
/*
|
||||
* Determining the size of a file block in the file system.
|
||||
*/
|
||||
#define blksize(fs, ip, lbn) \
|
||||
(((lbn) >= NDADDR || (ip)->i_size >= lblktosize(fs, (lbn) + 1)) \
|
||||
? (fs)->fs_bsize \
|
||||
: (fragroundup(fs, blkoff(fs, (ip)->i_size))))
|
||||
|
||||
#define sblksize(fs, size, lbn) \
|
||||
(((lbn) >= NDADDR || (size) >= ((lbn) + 1) << (fs)->fs_bshift) \
|
||||
? (fs)->fs_bsize \
|
||||
: (fragroundup(fs, blkoff(fs, (size)))))
|
||||
|
||||
|
||||
/*
|
||||
* Number of inodes in a secondary storage block/fragment.
|
||||
*/
|
||||
#define INOPB(fs) ((fs)->fs_inopb)
|
||||
#define INOPF(fs) ((fs)->fs_inopb >> (fs)->fs_fragshift)
|
||||
|
||||
/*
|
||||
* Number of indirects in a file system block.
|
||||
*/
|
||||
#define NINDIR(fs) ((fs)->fs_nindir)
|
||||
|
||||
/*
|
||||
* Apple UFS Label:
|
||||
* We check for this to decide to use APPLEUFS_DIRBLKSIZ
|
||||
*/
|
||||
#define APPLEUFS_LABEL_MAGIC 0x4c41424c /* LABL */
|
||||
#define APPLEUFS_LABEL_SIZE 1024
|
||||
#define APPLEUFS_LABEL_OFFSET (BBSIZE - APPLEUFS_LABEL_SIZE) /* located at 7k */
|
||||
#define APPLEUFS_LABEL_VERSION 1
|
||||
#define APPLEUFS_MAX_LABEL_NAME 512
|
||||
|
||||
struct appleufslabel {
|
||||
u_int32_t ul_magic;
|
||||
u_int16_t ul_checksum;
|
||||
u_int16_t ul_unused0;
|
||||
u_int32_t ul_version;
|
||||
u_int32_t ul_time;
|
||||
u_int16_t ul_namelen;
|
||||
u_char ul_name[APPLEUFS_MAX_LABEL_NAME]; /* Warning: may not be null terminated */
|
||||
u_int16_t ul_unused1;
|
||||
u_int64_t ul_uuid; /* Note this is only 4 byte aligned */
|
||||
u_char ul_reserved[24];
|
||||
u_char ul_unused[460];
|
||||
} __attribute__((__packed__));
|
||||
|
||||
|
||||
#endif /* !_UFS_FFS_FS_H_ */
|
175
sys/ufs/ufs/dinode.h
Normal file
175
sys/ufs/ufs/dinode.h
Normal file
@ -0,0 +1,175 @@
|
||||
/* $NetBSD: dinode.h,v 1.18 2003/08/07 16:34:42 agc 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, 1989, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
* (c) UNIX System Laboratories, Inc.
|
||||
* All or some portions of this file are derived from material licensed
|
||||
* to the University of California by American Telephone and Telegraph
|
||||
* Co. or Unix System Laboratories, Inc. and are reproduced herein with
|
||||
* the permission of UNIX System Laboratories, 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. 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.
|
||||
*
|
||||
* @(#)dinode.h 8.9 (Berkeley) 3/29/95
|
||||
*/
|
||||
|
||||
#ifndef _UFS_UFS_DINODE_H_
|
||||
#define _UFS_UFS_DINODE_H_
|
||||
|
||||
/*
|
||||
* The root inode is the root of the file system. Inode 0 can't be used for
|
||||
* normal purposes and historically bad blocks were linked to inode 1, thus
|
||||
* the root inode is 2. (Inode 1 is no longer used for this purpose, however
|
||||
* numerous dump tapes make this assumption, so we are stuck with it).
|
||||
*/
|
||||
#define ROOTINO ((ino_t)2)
|
||||
|
||||
/*
|
||||
* The Whiteout inode# is a dummy non-zero inode number which will
|
||||
* never be allocated to a real file. It is used as a place holder
|
||||
* in the directory entry which has been tagged as a DT_W entry.
|
||||
* See the comments about ROOTINO above.
|
||||
*/
|
||||
#define WINO ((ino_t)1)
|
||||
|
||||
/*
|
||||
* A dinode contains all the meta-data associated with a UFS file.
|
||||
* This structure defines the on-disk format of a dinode. Since
|
||||
* this structure describes an on-disk structure, all its fields
|
||||
* are defined by types with precise widths.
|
||||
*/
|
||||
|
||||
#define NXADDR 2
|
||||
#define NDADDR 12 /* Direct addresses in inode. */
|
||||
#define NIADDR 3 /* Indirect addresses in inode. */
|
||||
|
||||
struct ufs1_dinode {
|
||||
u_int16_t di_mode; /* 0: IFMT, permissions; see below. */
|
||||
int16_t di_nlink; /* 2: File link count. */
|
||||
union {
|
||||
u_int16_t oldids[2]; /* 4: Ffs: old user and group ids. */
|
||||
u_int32_t inumber; /* 4: Lfs: inode number. */
|
||||
} di_u;
|
||||
u_int64_t di_size; /* 8: File byte count. */
|
||||
int32_t di_atime; /* 16: Last access time. */
|
||||
int32_t di_atimensec; /* 20: Last access time. */
|
||||
int32_t di_mtime; /* 24: Last modified time. */
|
||||
int32_t di_mtimensec; /* 28: Last modified time. */
|
||||
int32_t di_ctime; /* 32: Last inode change time. */
|
||||
int32_t di_ctimensec; /* 36: Last inode change time. */
|
||||
int32_t di_db[NDADDR]; /* 40: Direct disk blocks. */
|
||||
int32_t di_ib[NIADDR]; /* 88: Indirect disk blocks. */
|
||||
u_int32_t di_flags; /* 100: Status flags (chflags). */
|
||||
u_int32_t di_blocks; /* 104: Blocks actually held. */
|
||||
int32_t di_gen; /* 108: Generation number. */
|
||||
u_int32_t di_uid; /* 112: File owner. */
|
||||
u_int32_t di_gid; /* 116: File group. */
|
||||
int32_t di_spare[2]; /* 120: Reserved; currently unused */
|
||||
};
|
||||
|
||||
struct ufs2_dinode {
|
||||
u_int16_t di_mode; /* 0: IFMT, permissions; see below. */
|
||||
int16_t di_nlink; /* 2: File link count. */
|
||||
u_int32_t di_uid; /* 4: File owner. */
|
||||
u_int32_t di_gid; /* 8: File group. */
|
||||
u_int32_t di_blksize; /* 12: Inode blocksize. */
|
||||
u_int64_t di_size; /* 16: File byte count. */
|
||||
u_int64_t di_blocks; /* 24: Bytes actually held. */
|
||||
int64_t di_atime; /* 32: Last access time. */
|
||||
int64_t di_mtime; /* 40: Last modified time. */
|
||||
int64_t di_ctime; /* 48: Last inode change time. */
|
||||
int64_t di_birthtime; /* 56: Inode creation time. */
|
||||
int32_t di_mtimensec; /* 64: Last modified time. */
|
||||
int32_t di_atimensec; /* 68: Last access time. */
|
||||
int32_t di_ctimensec; /* 72: Last inode change time. */
|
||||
int32_t di_birthnsec; /* 76: Inode creation time. */
|
||||
int32_t di_gen; /* 80: Generation number. */
|
||||
u_int32_t di_kernflags; /* 84: Kernel flags. */
|
||||
u_int32_t di_flags; /* 88: Status flags (chflags). */
|
||||
int32_t di_extsize; /* 92: External attributes block. */
|
||||
int64_t di_extb[NXADDR];/* 96: External attributes block. */
|
||||
int64_t di_db[NDADDR]; /* 112: Direct disk blocks. */
|
||||
int64_t di_ib[NIADDR]; /* 208: Indirect disk blocks. */
|
||||
int64_t di_spare[3]; /* 232: Reserved; currently unused */
|
||||
};
|
||||
|
||||
/*
|
||||
* The di_db fields may be overlaid with other information for
|
||||
* file types that do not have associated disk storage. Block
|
||||
* and character devices overlay the first data block with their
|
||||
* dev_t value. Short symbolic links place their path in the
|
||||
* di_db area.
|
||||
*/
|
||||
#define di_inumber di_u.inumber
|
||||
#define di_ogid di_u.oldids[1]
|
||||
#define di_ouid di_u.oldids[0]
|
||||
#define di_rdev di_db[0]
|
||||
#define MAXSYMLINKLEN_UFS1 ((NDADDR + NIADDR) * sizeof(int32_t))
|
||||
#define MAXSYMLINKLEN_UFS2 ((NDADDR + NIADDR) * sizeof(int64_t))
|
||||
|
||||
#define MAXSYMLINKLEN(ip) \
|
||||
((ip)->i_ump->um_fstype == UFS1) ? \
|
||||
MAXSYMLINKLEN_UFS1 : MAXSYMLINKLEN_UFS2
|
||||
|
||||
/* NeXT used to keep short symlinks in the inode even when using
|
||||
* FS_42INODEFMT. In that case fs->fs_maxsymlinklen is probably -1,
|
||||
* but short symlinks were stored in inodes shorter than this:
|
||||
*/
|
||||
#define APPLEUFS_MAXSYMLINKLEN 60
|
||||
|
||||
/* File permissions. */
|
||||
#define IEXEC 0000100 /* Executable. */
|
||||
#define IWRITE 0000200 /* Writable. */
|
||||
#define IREAD 0000400 /* Readable. */
|
||||
#define ISVTX 0001000 /* Sticky bit. */
|
||||
#define ISGID 0002000 /* Set-gid. */
|
||||
#define ISUID 0004000 /* Set-uid. */
|
||||
|
||||
/* File types. */
|
||||
#define IFMT 0170000 /* Mask of file type. */
|
||||
#define IFIFO 0010000 /* Named pipe (fifo). */
|
||||
#define IFCHR 0020000 /* Character device. */
|
||||
#define IFDIR 0040000 /* Directory file. */
|
||||
#define IFBLK 0060000 /* Block device. */
|
||||
#define IFREG 0100000 /* Regular file. */
|
||||
#define IFLNK 0120000 /* Symbolic link. */
|
||||
#define IFSOCK 0140000 /* UNIX domain socket. */
|
||||
#define IFWHT 0160000 /* Whiteout. */
|
||||
|
||||
/* Size of the on-disk inode. */
|
||||
#define DINODE1_SIZE (sizeof(struct ufs1_dinode)) /* 128 */
|
||||
#define DINODE2_SIZE (sizeof(struct ufs2_dinode))
|
||||
|
||||
#endif /* !_UFS_UFS_DINODE_H_ */
|
160
sys/ufs/ufs/dir.h
Normal file
160
sys/ufs/ufs/dir.h
Normal file
@ -0,0 +1,160 @@
|
||||
/* $NetBSD: dir.h,v 1.17 2003/08/07 16:34:42 agc Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1982, 1986, 1989, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
* (c) UNIX System Laboratories, Inc.
|
||||
* All or some portions of this file are derived from material licensed
|
||||
* to the University of California by American Telephone and Telegraph
|
||||
* Co. or Unix System Laboratories, Inc. and are reproduced herein with
|
||||
* the permission of UNIX System Laboratories, 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. 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.
|
||||
*
|
||||
* @(#)dir.h 8.5 (Berkeley) 4/27/95
|
||||
*/
|
||||
|
||||
#ifndef _UFS_UFS_DIR_H_
|
||||
#define _UFS_UFS_DIR_H_
|
||||
|
||||
/*
|
||||
* Theoretically, directories can be more than 2Gb in length, however, in
|
||||
* practice this seems unlikely. So, we define the type doff_t as a 32-bit
|
||||
* quantity to keep down the cost of doing lookup on a 32-bit machine.
|
||||
*/
|
||||
#define doff_t int32_t
|
||||
#define MAXDIRSIZE (0x7fffffff)
|
||||
|
||||
/*
|
||||
* A directory consists of some number of blocks of DIRBLKSIZ
|
||||
* bytes, where DIRBLKSIZ is chosen such that it can be transferred
|
||||
* to disk in a single atomic operation (e.g. 512 bytes on most machines).
|
||||
*
|
||||
* Each DIRBLKSIZ byte block contains some number of directory entry
|
||||
* structures, which are of variable length. Each directory entry has
|
||||
* a struct direct at the front of it, containing its inode number,
|
||||
* the length of the entry, and the length of the name contained in
|
||||
* the entry. These are followed by the name padded to a 4 byte boundary.
|
||||
* All names are guaranteed null terminated.
|
||||
* The maximum length of a name in a directory is MAXNAMLEN.
|
||||
*
|
||||
* The macro DIRSIZ(fmt, dp) gives the amount of space required to represent
|
||||
* a directory entry. Free space in a directory is represented by
|
||||
* entries which have dp->d_reclen > DIRSIZ(fmt, dp). All DIRBLKSIZ bytes
|
||||
* in a directory block are claimed by the directory entries. This
|
||||
* usually results in the last entry in a directory having a large
|
||||
* dp->d_reclen. When entries are deleted from a directory, the
|
||||
* space is returned to the previous entry in the same directory
|
||||
* block by increasing its dp->d_reclen. If the first entry of
|
||||
* a directory block is free, then its dp->d_ino is set to 0.
|
||||
* Entries other than the first in a directory do not normally have
|
||||
* dp->d_ino set to 0.
|
||||
*/
|
||||
#undef DIRBLKSIZ
|
||||
#define DIRBLKSIZ DEV_BSIZE
|
||||
#undef MAXNAMLEN
|
||||
#define MAXNAMLEN 255
|
||||
#define APPLEUFS_DIRBLKSIZ 1024
|
||||
|
||||
struct direct {
|
||||
u_int32_t d_ino; /* inode number of entry */
|
||||
u_int16_t d_reclen; /* length of this record */
|
||||
u_int8_t d_type; /* file type, see below */
|
||||
u_int8_t d_namlen; /* length of string in d_name */
|
||||
char d_name[MAXNAMLEN + 1];/* name with length <= MAXNAMLEN */
|
||||
};
|
||||
|
||||
/*
|
||||
* File types
|
||||
*/
|
||||
#define DT_UNKNOWN 0
|
||||
#define DT_FIFO 1
|
||||
#define DT_CHR 2
|
||||
#define DT_DIR 4
|
||||
#define DT_BLK 6
|
||||
#define DT_REG 8
|
||||
#define DT_LNK 10
|
||||
#define DT_SOCK 12
|
||||
#define DT_WHT 14
|
||||
|
||||
/*
|
||||
* Convert between stat structure types and directory types.
|
||||
*/
|
||||
#define IFTODT(mode) (((mode) & 0170000) >> 12)
|
||||
#define DTTOIF(dirtype) ((dirtype) << 12)
|
||||
|
||||
/*
|
||||
* The DIRSIZ macro gives the minimum record length which will hold
|
||||
* the directory entry. This requires the amount of space in struct direct
|
||||
* without the d_name field, plus enough space for the name with a terminating
|
||||
* null byte (dp->d_namlen+1), rounded up to a 4 byte boundary.
|
||||
*/
|
||||
#define DIRECTSIZ(namlen) \
|
||||
((sizeof(struct direct) - (MAXNAMLEN+1)) + (((namlen)+1 + 3) &~ 3))
|
||||
|
||||
#if (BYTE_ORDER == LITTLE_ENDIAN)
|
||||
#define DIRSIZ(oldfmt, dp, needswap) \
|
||||
(((oldfmt) && !(needswap)) ? \
|
||||
DIRECTSIZ((dp)->d_type) : DIRECTSIZ((dp)->d_namlen))
|
||||
#else
|
||||
#define DIRSIZ(oldfmt, dp, needswap) \
|
||||
(((oldfmt) && (needswap)) ? \
|
||||
DIRECTSIZ((dp)->d_type) : DIRECTSIZ((dp)->d_namlen))
|
||||
#endif
|
||||
|
||||
#define OLDDIRFMT 1
|
||||
#define NEWDIRFMT 0
|
||||
|
||||
/*
|
||||
* Template for manipulating directories. Should use struct direct's,
|
||||
* but the name field is MAXNAMLEN - 1, and this just won't do.
|
||||
*/
|
||||
struct dirtemplate {
|
||||
u_int32_t dot_ino;
|
||||
int16_t dot_reclen;
|
||||
u_int8_t dot_type;
|
||||
u_int8_t dot_namlen;
|
||||
char dot_name[4]; /* must be multiple of 4 */
|
||||
u_int32_t dotdot_ino;
|
||||
int16_t dotdot_reclen;
|
||||
u_int8_t dotdot_type;
|
||||
u_int8_t dotdot_namlen;
|
||||
char dotdot_name[4]; /* ditto */
|
||||
};
|
||||
|
||||
/*
|
||||
* This is the old format of directories, sanz type element.
|
||||
*/
|
||||
struct odirtemplate {
|
||||
u_int32_t dot_ino;
|
||||
int16_t dot_reclen;
|
||||
u_int16_t dot_namlen;
|
||||
char dot_name[4]; /* must be multiple of 4 */
|
||||
u_int32_t dotdot_ino;
|
||||
int16_t dotdot_reclen;
|
||||
u_int16_t dotdot_namlen;
|
||||
char dotdot_name[4]; /* ditto */
|
||||
};
|
||||
#endif /* !_UFS_UFS_DIR_H_ */
|
93
sys/ufs/ufs/ufs_bswap.h
Normal file
93
sys/ufs/ufs/ufs_bswap.h
Normal file
@ -0,0 +1,93 @@
|
||||
/* $NetBSD: ufs_bswap.h,v 1.13 2003/10/05 17:48:50 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.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by Manuel Bouyer.
|
||||
* 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 _UFS_UFS_BSWAP_H_
|
||||
#define _UFS_UFS_BSWAP_H_
|
||||
|
||||
#if defined(_KERNEL_OPT)
|
||||
#include "opt_ffs.h"
|
||||
#endif
|
||||
|
||||
#include <machine/bswap.h>
|
||||
|
||||
/* Macros to access UFS flags */
|
||||
#ifdef FFS_EI
|
||||
#define UFS_MPNEEDSWAP(mp) (VFSTOUFS(mp)->um_flags & UFS_NEEDSWAP)
|
||||
#define UFS_FSNEEDSWAP(fs) ((fs)->fs_flags & FS_SWAPPED)
|
||||
#define UFS_IPNEEDSWAP(ip) UFS_MPNEEDSWAP(ITOV(ip)->v_mount)
|
||||
#else
|
||||
#define UFS_MPNEEDSWAP(mp) (0)
|
||||
#define UFS_FSNEEDSWAP(fs) (0)
|
||||
#define UFS_IPNEEDSWAP(ip) (0)
|
||||
#endif
|
||||
|
||||
#if !defined(_KERNEL) || defined(FFS_EI)
|
||||
/* inlines for access to swapped data */
|
||||
static __inline u_int16_t ufs_rw16 __P((u_int16_t, int));
|
||||
static __inline u_int32_t ufs_rw32 __P((u_int32_t, int));
|
||||
static __inline u_int64_t ufs_rw64 __P((u_int64_t, int));
|
||||
|
||||
static __inline u_int16_t
|
||||
ufs_rw16(a, ns)
|
||||
u_int16_t a;
|
||||
int ns;
|
||||
{
|
||||
return ((ns) ? bswap16(a) : (a));
|
||||
}
|
||||
static __inline u_int32_t
|
||||
ufs_rw32(a, ns)
|
||||
u_int32_t a;
|
||||
int ns;
|
||||
{
|
||||
return ((ns) ? bswap32(a) : (a));
|
||||
}
|
||||
static __inline u_int64_t
|
||||
ufs_rw64(a, ns)
|
||||
u_int64_t a;
|
||||
int ns;
|
||||
{
|
||||
return ((ns) ? bswap64(a) : (a));
|
||||
}
|
||||
#else
|
||||
#define ufs_rw16(a, ns) ((uint16_t)(a))
|
||||
#define ufs_rw32(a, ns) ((uint32_t)(a))
|
||||
#define ufs_rw64(a, ns) ((uint64_t)(a))
|
||||
#endif
|
||||
|
||||
#define ufs_add16(a, b, ns) \
|
||||
(a) = ufs_rw16(ufs_rw16((a), (ns)) + (b), (ns))
|
||||
#define ufs_add32(a, b, ns) \
|
||||
(a) = ufs_rw32(ufs_rw32((a), (ns)) + (b), (ns))
|
||||
#define ufs_add64(a, b, ns) \
|
||||
(a) = ufs_rw64(ufs_rw64((a), (ns)) + (b), (ns))
|
||||
|
||||
#endif /* !_UFS_UFS_BSWAP_H_ */
|
540
walk.c
Normal file
540
walk.c
Normal file
@ -0,0 +1,540 @@
|
||||
/* $NetBSD: walk.c,v 1.17 2004/06/20 22:20:18 jmc 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The function link_check() was inspired from NetBSD's usr.bin/du/du.c,
|
||||
* which has the following copyright notice:
|
||||
*
|
||||
*
|
||||
* Copyright (c) 1989, 1993, 1994
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* Chris Newcomb.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#if HAVE_NBTOOL_CONFIG_H
|
||||
#include "nbtool_config.h"
|
||||
#endif
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#if defined(__RCSID) && !defined(__lint)
|
||||
__RCSID("$NetBSD: walk.c,v 1.17 2004/06/20 22:20:18 jmc Exp $");
|
||||
#endif /* !__lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <dirent.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "makefs.h"
|
||||
#include "mtree.h"
|
||||
|
||||
static void apply_specdir(const char *, NODE *, fsnode *);
|
||||
static void apply_specentry(const char *, NODE *, fsnode *);
|
||||
static fsnode *create_fsnode(const char *, struct stat *);
|
||||
static fsinode *link_check(fsinode *);
|
||||
|
||||
|
||||
/*
|
||||
* walk_dir --
|
||||
* build a tree of fsnodes from `dir', with a parent fsnode of `parent'
|
||||
* (which may be NULL for the root of the tree).
|
||||
* each "level" is a directory, with the "." entry guaranteed to be
|
||||
* at the start of the list, and without ".." entries.
|
||||
*/
|
||||
fsnode *
|
||||
walk_dir(const char *dir, fsnode *parent)
|
||||
{
|
||||
fsnode *first, *cur, *prev;
|
||||
DIR *dirp;
|
||||
struct dirent *dent;
|
||||
char path[MAXPATHLEN + 1];
|
||||
struct stat stbuf;
|
||||
|
||||
assert(dir != NULL);
|
||||
|
||||
if (debug & DEBUG_WALK_DIR)
|
||||
printf("walk_dir: %s %p\n", dir, parent);
|
||||
if ((dirp = opendir(dir)) == NULL)
|
||||
err(1, "Can't opendir `%s'", dir);
|
||||
first = prev = NULL;
|
||||
while ((dent = readdir(dirp)) != NULL) {
|
||||
if (strcmp(dent->d_name, "..") == 0)
|
||||
continue;
|
||||
if (debug & DEBUG_WALK_DIR_NODE)
|
||||
printf("scanning %s/%s\n", dir, dent->d_name);
|
||||
if (snprintf(path, sizeof(path), "%s/%s", dir, dent->d_name)
|
||||
>= sizeof(path))
|
||||
errx(1, "Pathname too long.");
|
||||
if (lstat(path, &stbuf) == -1)
|
||||
err(1, "Can't lstat `%s'", path);
|
||||
#ifdef S_ISSOCK
|
||||
if (S_ISSOCK(stbuf.st_mode & S_IFMT)) {
|
||||
if (debug & DEBUG_WALK_DIR_NODE)
|
||||
printf(" skipping socket %s\n", path);
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
cur = create_fsnode(dent->d_name, &stbuf);
|
||||
cur->parent = parent;
|
||||
if (strcmp(dent->d_name, ".") == 0) {
|
||||
/* ensure "." is at the start of the list */
|
||||
cur->next = first;
|
||||
first = cur;
|
||||
if (! prev)
|
||||
prev = cur;
|
||||
} else { /* not "." */
|
||||
if (prev)
|
||||
prev->next = cur;
|
||||
prev = cur;
|
||||
if (!first)
|
||||
first = cur;
|
||||
if (S_ISDIR(cur->type)) {
|
||||
cur->child = walk_dir(path, cur);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (stbuf.st_nlink > 1) {
|
||||
fsinode *curino;
|
||||
|
||||
curino = link_check(cur->inode);
|
||||
if (curino != NULL) {
|
||||
free(cur->inode);
|
||||
cur->inode = curino;
|
||||
cur->inode->nlink++;
|
||||
}
|
||||
}
|
||||
if (S_ISLNK(cur->type)) {
|
||||
char slink[PATH_MAX+1];
|
||||
int llen;
|
||||
|
||||
llen = readlink(path, slink, sizeof(slink) - 1);
|
||||
if (llen == -1)
|
||||
err(1, "Readlink `%s'", path);
|
||||
slink[llen] = '\0';
|
||||
if ((cur->symlink = strdup(slink)) == NULL)
|
||||
err(1, "Memory allocation error");
|
||||
}
|
||||
}
|
||||
for (cur = first; cur != NULL; cur = cur->next)
|
||||
cur->first = first;
|
||||
if (closedir(dirp) == -1)
|
||||
err(1, "Can't closedir `%s'", dir);
|
||||
return (first);
|
||||
}
|
||||
|
||||
static fsnode *
|
||||
create_fsnode(const char *name, struct stat *stbuf)
|
||||
{
|
||||
fsnode *cur;
|
||||
|
||||
if ((cur = calloc(1, sizeof(fsnode))) == NULL ||
|
||||
(cur->name = strdup(name)) == NULL ||
|
||||
(cur->inode = calloc(1, sizeof(fsinode))) == NULL)
|
||||
err(1, "Memory allocation error");
|
||||
cur->type = stbuf->st_mode & S_IFMT;
|
||||
cur->inode->nlink = 1;
|
||||
cur->inode->st = *stbuf;
|
||||
return (cur);
|
||||
}
|
||||
|
||||
/*
|
||||
* apply_specfile --
|
||||
* read in the mtree(8) specfile, and apply it to the tree
|
||||
* at dir,parent. parameters in parent on equivalent types
|
||||
* will be changed to those found in specfile, and missing
|
||||
* entries will be added.
|
||||
*/
|
||||
void
|
||||
apply_specfile(const char *specfile, const char *dir, fsnode *parent)
|
||||
{
|
||||
struct timeval start;
|
||||
FILE *fp;
|
||||
NODE *root;
|
||||
|
||||
assert(specfile != NULL);
|
||||
assert(parent != NULL);
|
||||
|
||||
if (debug & DEBUG_APPLY_SPECFILE)
|
||||
printf("apply_specfile: %s, %s %p\n", specfile, dir, parent);
|
||||
|
||||
/* read in the specfile */
|
||||
if ((fp = fopen(specfile, "r")) == NULL)
|
||||
err(1, "Can't open `%s'", specfile);
|
||||
TIMER_START(start);
|
||||
root = spec(fp);
|
||||
TIMER_RESULTS(start, "spec");
|
||||
if (fclose(fp) == EOF)
|
||||
err(1, "Can't close `%s'", specfile);
|
||||
|
||||
/* perform some sanity checks */
|
||||
if (root == NULL)
|
||||
errx(1, "Specfile `%s' did not contain a tree", specfile);
|
||||
assert(strcmp(root->name, ".") == 0);
|
||||
assert(root->type == F_DIR);
|
||||
|
||||
/* merge in the changes */
|
||||
apply_specdir(dir, root, parent);
|
||||
}
|
||||
|
||||
static void
|
||||
apply_specdir(const char *dir, NODE *specnode, fsnode *dirnode)
|
||||
{
|
||||
char path[MAXPATHLEN + 1];
|
||||
NODE *curnode;
|
||||
fsnode *curfsnode;
|
||||
|
||||
assert(specnode != NULL);
|
||||
assert(dirnode != NULL);
|
||||
|
||||
if (debug & DEBUG_APPLY_SPECFILE)
|
||||
printf("apply_specdir: %s %p %p\n", dir, specnode, dirnode);
|
||||
|
||||
if (specnode->type != F_DIR)
|
||||
errx(1, "Specfile node `%s/%s' is not a directory",
|
||||
dir, specnode->name);
|
||||
if (dirnode->type != S_IFDIR)
|
||||
errx(1, "Directory node `%s/%s' is not a directory",
|
||||
dir, dirnode->name);
|
||||
|
||||
apply_specentry(dir, specnode, dirnode);
|
||||
|
||||
/* now walk specnode->child matching up with dirnode */
|
||||
for (curnode = specnode->child; curnode != NULL;
|
||||
curnode = curnode->next) {
|
||||
if (debug & DEBUG_APPLY_SPECENTRY)
|
||||
printf("apply_specdir: spec %s\n",
|
||||
curnode->name);
|
||||
for (curfsnode = dirnode->next; curfsnode != NULL;
|
||||
curfsnode = curfsnode->next) {
|
||||
#if 0 /* too verbose for now */
|
||||
if (debug & DEBUG_APPLY_SPECENTRY)
|
||||
printf("apply_specdir: dirent %s\n",
|
||||
curfsnode->name);
|
||||
#endif
|
||||
if (strcmp(curnode->name, curfsnode->name) == 0)
|
||||
break;
|
||||
}
|
||||
if (snprintf(path, sizeof(path), "%s/%s",
|
||||
dir, curnode->name) >= sizeof(path))
|
||||
errx(1, "Pathname too long.");
|
||||
if (curfsnode == NULL) { /* need new entry */
|
||||
struct stat stbuf;
|
||||
|
||||
/*
|
||||
* don't add optional spec entries
|
||||
* that lack an existing fs entry
|
||||
*/
|
||||
if ((curnode->flags & F_OPT) &&
|
||||
lstat(path, &stbuf) == -1)
|
||||
continue;
|
||||
|
||||
/* check that enough info is provided */
|
||||
#define NODETEST(t, m) \
|
||||
if (!(t)) \
|
||||
errx(1, "`%s': %s not provided", path, m)
|
||||
NODETEST(curnode->flags & F_TYPE, "type");
|
||||
NODETEST(curnode->flags & F_MODE, "mode");
|
||||
/* XXX: require F_TIME ? */
|
||||
NODETEST(curnode->flags & F_GID ||
|
||||
curnode->flags & F_GNAME, "group");
|
||||
NODETEST(curnode->flags & F_UID ||
|
||||
curnode->flags & F_UNAME, "user");
|
||||
if (curnode->type == F_BLOCK || curnode->type == F_CHAR)
|
||||
NODETEST(curnode->flags & F_DEV,
|
||||
"device number");
|
||||
#undef NODETEST
|
||||
|
||||
if (debug & DEBUG_APPLY_SPECFILE)
|
||||
printf("apply_specdir: adding %s\n",
|
||||
curnode->name);
|
||||
/* build minimal fsnode */
|
||||
memset(&stbuf, 0, sizeof(stbuf));
|
||||
stbuf.st_mode = nodetoino(curnode->type);
|
||||
stbuf.st_nlink = 1;
|
||||
stbuf.st_mtime = stbuf.st_atime =
|
||||
stbuf.st_ctime = start_time.tv_sec;
|
||||
#if HAVE_STRUCT_STAT_ST_MTIMENSEC
|
||||
stbuf.st_mtimensec = stbuf.st_atimensec =
|
||||
stbuf.st_ctimensec = start_time.tv_nsec;
|
||||
#endif
|
||||
curfsnode = create_fsnode(curnode->name, &stbuf);
|
||||
curfsnode->parent = dirnode->parent;
|
||||
curfsnode->first = dirnode;
|
||||
curfsnode->next = dirnode->next;
|
||||
dirnode->next = curfsnode;
|
||||
if (curfsnode->type == S_IFDIR) {
|
||||
/* for dirs, make "." entry as well */
|
||||
curfsnode->child = create_fsnode(".", &stbuf);
|
||||
curfsnode->child->parent = curfsnode;
|
||||
curfsnode->child->first = curfsnode->child;
|
||||
}
|
||||
if (curfsnode->type == S_IFLNK) {
|
||||
assert(curnode->slink != NULL);
|
||||
/* for symlinks, copy the target */
|
||||
if ((curfsnode->symlink =
|
||||
strdup(curnode->slink)) == NULL)
|
||||
err(1, "Memory allocation error");
|
||||
}
|
||||
}
|
||||
apply_specentry(dir, curnode, curfsnode);
|
||||
if (curnode->type == F_DIR) {
|
||||
if (curfsnode->type != S_IFDIR)
|
||||
errx(1, "`%s' is not a directory", path);
|
||||
assert (curfsnode->child != NULL);
|
||||
apply_specdir(path, curnode, curfsnode->child);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
apply_specentry(const char *dir, NODE *specnode, fsnode *dirnode)
|
||||
{
|
||||
|
||||
assert(specnode != NULL);
|
||||
assert(dirnode != NULL);
|
||||
|
||||
if (nodetoino(specnode->type) != dirnode->type)
|
||||
errx(1, "`%s/%s' type mismatch: specfile %s, tree %s",
|
||||
dir, specnode->name, inode_type(nodetoino(specnode->type)),
|
||||
inode_type(dirnode->type));
|
||||
|
||||
if (debug & DEBUG_APPLY_SPECENTRY)
|
||||
printf("apply_specentry: %s/%s\n", dir, dirnode->name);
|
||||
|
||||
#define ASEPRINT(t, b, o, n) \
|
||||
if (debug & DEBUG_APPLY_SPECENTRY) \
|
||||
printf("\t\t\tchanging %s from " b " to " b "\n", \
|
||||
t, o, n)
|
||||
|
||||
if (specnode->flags & (F_GID | F_GNAME)) {
|
||||
ASEPRINT("gid", "%d",
|
||||
dirnode->inode->st.st_gid, specnode->st_gid);
|
||||
dirnode->inode->st.st_gid = specnode->st_gid;
|
||||
}
|
||||
if (specnode->flags & F_MODE) {
|
||||
ASEPRINT("mode", "%#o",
|
||||
dirnode->inode->st.st_mode & ALLPERMS, specnode->st_mode);
|
||||
dirnode->inode->st.st_mode &= ~ALLPERMS;
|
||||
dirnode->inode->st.st_mode |= (specnode->st_mode & ALLPERMS);
|
||||
}
|
||||
/* XXX: ignoring F_NLINK for now */
|
||||
if (specnode->flags & F_SIZE) {
|
||||
ASEPRINT("size", "%lld",
|
||||
(long long)dirnode->inode->st.st_size,
|
||||
(long long)specnode->st_size);
|
||||
dirnode->inode->st.st_size = specnode->st_size;
|
||||
}
|
||||
if (specnode->flags & F_SLINK) {
|
||||
assert(dirnode->symlink != NULL);
|
||||
assert(specnode->slink != NULL);
|
||||
ASEPRINT("symlink", "%s", dirnode->symlink, specnode->slink);
|
||||
free(dirnode->symlink);
|
||||
if ((dirnode->symlink = strdup(specnode->slink)) == NULL)
|
||||
err(1, "Memory allocation error");
|
||||
}
|
||||
if (specnode->flags & F_TIME) {
|
||||
ASEPRINT("time", "%ld",
|
||||
(long)dirnode->inode->st.st_mtime,
|
||||
(long)specnode->st_mtimespec.tv_sec);
|
||||
dirnode->inode->st.st_mtime = specnode->st_mtimespec.tv_sec;
|
||||
dirnode->inode->st.st_atime = specnode->st_mtimespec.tv_sec;
|
||||
dirnode->inode->st.st_ctime = start_time.tv_sec;
|
||||
#if HAVE_STRUCT_STAT_ST_MTIMENSEC
|
||||
dirnode->inode->st.st_mtimensec = specnode->st_mtimespec.tv_nsec;
|
||||
dirnode->inode->st.st_atimensec = specnode->st_mtimespec.tv_nsec;
|
||||
dirnode->inode->st.st_ctimensec = start_time.tv_nsec;
|
||||
#endif
|
||||
}
|
||||
if (specnode->flags & (F_UID | F_UNAME)) {
|
||||
ASEPRINT("uid", "%d",
|
||||
dirnode->inode->st.st_uid, specnode->st_uid);
|
||||
dirnode->inode->st.st_uid = specnode->st_uid;
|
||||
}
|
||||
#if HAVE_STRUCT_STAT_ST_FLAGS
|
||||
if (specnode->flags & F_FLAGS) {
|
||||
ASEPRINT("flags", "%#lX",
|
||||
(unsigned long)dirnode->inode->st.st_flags,
|
||||
(unsigned long)specnode->st_flags);
|
||||
dirnode->inode->st.st_flags = specnode->st_flags;
|
||||
}
|
||||
#endif
|
||||
if (specnode->flags & F_DEV) {
|
||||
ASEPRINT("rdev", "%#x",
|
||||
dirnode->inode->st.st_rdev, specnode->st_rdev);
|
||||
dirnode->inode->st.st_rdev = specnode->st_rdev;
|
||||
}
|
||||
#undef ASEPRINT
|
||||
|
||||
dirnode->flags |= FSNODE_F_HASSPEC;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* dump_fsnodes --
|
||||
* dump the fsnodes from `cur', based in the directory `dir'
|
||||
*/
|
||||
void
|
||||
dump_fsnodes(const char *dir, fsnode *root)
|
||||
{
|
||||
fsnode *cur;
|
||||
char path[MAXPATHLEN + 1];
|
||||
|
||||
assert (dir != NULL);
|
||||
printf("dump_fsnodes: %s %p\n", dir, root);
|
||||
for (cur = root; cur != NULL; cur = cur->next) {
|
||||
if (snprintf(path, sizeof(path), "%s/%s", dir, cur->name)
|
||||
>= sizeof(path))
|
||||
errx(1, "Pathname too long.");
|
||||
|
||||
if (debug & DEBUG_DUMP_FSNODES_VERBOSE)
|
||||
printf("cur=%8p parent=%8p first=%8p ",
|
||||
cur, cur->parent, cur->first);
|
||||
printf("%7s: %s", inode_type(cur->type), path);
|
||||
if (S_ISLNK(cur->type)) {
|
||||
assert(cur->symlink != NULL);
|
||||
printf(" -> %s", cur->symlink);
|
||||
} else {
|
||||
assert (cur->symlink == NULL);
|
||||
}
|
||||
if (cur->inode->nlink > 1)
|
||||
printf(", nlinks=%d", cur->inode->nlink);
|
||||
putchar('\n');
|
||||
|
||||
if (cur->child) {
|
||||
assert (cur->type == S_IFDIR);
|
||||
dump_fsnodes(path, cur->child);
|
||||
}
|
||||
}
|
||||
printf("dump_fsnodes: finished %s\n", dir);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* inode_type --
|
||||
* for a given inode type `mode', return a descriptive string.
|
||||
* for most cases, uses inotype() from mtree/misc.c
|
||||
*/
|
||||
const char *
|
||||
inode_type(mode_t mode)
|
||||
{
|
||||
|
||||
if (S_ISLNK(mode))
|
||||
return ("symlink"); /* inotype() returns "link"... */
|
||||
return (inotype(mode));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* link_check --
|
||||
* return pointer to fsnode matching `entry's st_ino & st_dev if it exists,
|
||||
* otherwise add `entry' to table and return NULL
|
||||
*/
|
||||
static fsinode *
|
||||
link_check(fsinode *entry)
|
||||
{
|
||||
static struct dupnode {
|
||||
uint32_t dev;
|
||||
uint64_t ino;
|
||||
fsinode *dup;
|
||||
} *dups, *newdups;
|
||||
static int ndups, maxdups;
|
||||
|
||||
int i;
|
||||
|
||||
assert (entry != NULL);
|
||||
|
||||
/* XXX; maybe traverse in reverse for speed? */
|
||||
for (i = 0; i < ndups; i++) {
|
||||
if (dups[i].dev == entry->st.st_dev &&
|
||||
dups[i].ino == entry->st.st_ino) {
|
||||
if (debug & DEBUG_WALK_DIR_LINKCHECK)
|
||||
printf("link_check: found [%d,%d]\n",
|
||||
entry->st.st_dev, entry->st.st_ino);
|
||||
return (dups[i].dup);
|
||||
}
|
||||
}
|
||||
|
||||
if (debug & DEBUG_WALK_DIR_LINKCHECK)
|
||||
printf("link_check: no match for [%d, %d]\n",
|
||||
entry->st.st_dev, entry->st.st_ino);
|
||||
if (ndups == maxdups) {
|
||||
if ((newdups = realloc(dups, sizeof(struct dupnode) * (maxdups + 128)))
|
||||
== NULL)
|
||||
err(1, "Memory allocation error");
|
||||
dups = newdups;
|
||||
maxdups += 128;
|
||||
}
|
||||
dups[ndups].dev = entry->st.st_dev;
|
||||
dups[ndups].ino = entry->st.st_ino;
|
||||
dups[ndups].dup = entry;
|
||||
ndups++;
|
||||
|
||||
return (NULL);
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user