import netbsd makefs tool

This commit is contained in:
Sam Leffler 2008-12-19 18:47:46 +00:00
commit d347a0da97
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=186335
22 changed files with 7262 additions and 0 deletions

28
usr.sbin/makefs/Makefile Normal file
View File

@ -0,0 +1,28 @@
# $FreeBSD$
PROG= makefs
MAN= makefs.8
WARNS?= 2
CFLAGS+=-I.
SRCS= ffs.c getid.c makefs.c walk.c
.PATH: ${.CURDIR}/ffs
CFLAGS+=-Iffs
CFLAGS+=-DHAVE_STRUCT_STAT_ST_FLAGS=1
CFLAGS+=-DHAVE_STRUCT_STAT_ST_GEN=1
SRCS+= buf.c ffs_alloc.c ffs_balloc.c ffs_bswap.c ffs_subr.c mkfs.c ufs_bmap.c
.PATH: ${.CURDIR}/compat
CFLAGS+=-Icompat
SRCS+= pwcache.c strsuftoll.c
.PATH: ${.CURDIR}/../mtree
CFLAGS+=-I../mtree
SRCS+= misc.c spec.c
.PATH: ${.CURDIR}/../../sys/ufs/ffs
SRCS+= ffs_tables.c
.include <bsd.prog.mk>

View File

@ -0,0 +1,623 @@
/* $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.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#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>
#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
#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;
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 */

View File

@ -0,0 +1,73 @@
/* $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
* $FreeBSD$
*/
/*
* 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;

View File

@ -0,0 +1,229 @@
/* $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.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#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.
*
*/
/*
* 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;
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);
}
/* 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);
}

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

File diff suppressed because it is too large Load Diff

222
usr.sbin/makefs/ffs/buf.c Normal file
View File

@ -0,0 +1,222 @@
/* $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.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#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);
}

67
usr.sbin/makefs/ffs/buf.h Normal file
View File

@ -0,0 +1,67 @@
/* $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.
*
* $FreeBSD$
*/
#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 */

View File

@ -0,0 +1,683 @@
/* $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
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/time.h>
#include <errno.h>
#include "makefs.h"
#include <ufs/ufs/dinode.h>
#include <ufs/ffs/fs.h>
#include "ffs/ufs_bswap.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);
/*
* 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_swap(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_swap(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_swap(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_swap(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_swap(cgp, needswap)) {
brelse(bp);
return;
}
cgbno = dtogd(fs, bno);
if (size == fs->fs_bsize) {
fragno = fragstoblks(fs, cgbno);
if (!ffs_isfreeblock(fs, cg_blksfree_swap(cgp, needswap), fragno)) {
errx(1, "blkfree: freeing free block %lld",
(long long)bno);
}
ffs_setblock(fs, cg_blksfree_swap(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_swap(cgp, needswap), bbase);
ffs_fragacct_swap(fs, blk, cgp->cg_frsum, -1, needswap);
/*
* deallocate the fragment
*/
frags = numfrags(fs, size);
for (i = 0; i < frags; i++) {
if (isset(cg_blksfree_swap(cgp, needswap), cgbno + i)) {
errx(1, "blkfree: freeing free frag: block %lld",
(long long)(cgbno + i));
}
setbit(cg_blksfree_swap(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_swap(cgp, needswap), bbase);
ffs_fragacct_swap(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_swap(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_swap(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_swap(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_swap(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_swap(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_swap(cgp, needswap);
sump = cg_clustersum_swap(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;
}

View File

@ -0,0 +1,578 @@
/* $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
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#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/ffs/fs.h>
#include "ffs/ufs_bswap.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);
}

View 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.
*
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#if defined(_KERNEL)
#include <sys/systm.h>
#endif
#include <ufs/ufs/dinode.h>
#include "ffs/ufs_bswap.h"
#include <ufs/ffs/fs.h>
/* XXX temporary */
struct ufsmount;
struct bufobj;
struct mount;
struct vnode;
typedef int vfs_vget_t(struct mount *mp, ino_t ino, int flags,
struct vnode **vpp);
#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
#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 */
void ffs_csum_swap(struct csum *o, struct csum *n, int size);
void ffs_csumtotal_swap(struct csum_total *o, struct csum_total *n);
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]);
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]);
}

View File

@ -0,0 +1,77 @@
/* $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
* $FreeBSD$
*/
#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 *);

View File

@ -0,0 +1,202 @@
/* $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
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <ufs/ufs/dinode.h>
#include <ufs/ffs/fs.h>
/* XXX temporary */
struct ufsmount;
struct bufobj;
struct mount;
struct vnode;
typedef int vfs_vget_t(struct mount *mp, ino_t ino, int flags,
struct vnode **vpp);
#include <ufs/ffs/ffs_extern.h>
#include "ffs/ufs_bswap.h"
void panic __P((const char *, ...))
__attribute__((__noreturn__,__format__(__printf__,1,2)));
/*
* Update the frsum fields to reflect addition or deletion
* of some frags.
*/
void
ffs_fragacct_swap(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;
}
}
}
/*
* 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);
}
}

832
usr.sbin/makefs/ffs/mkfs.c Normal file
View File

@ -0,0 +1,832 @@
/* $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.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#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/ffs/fs.h>
#include "ffs/ufs_bswap.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 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;
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_swap(&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_swap(&acg, 0), blkno);
if (sblock.fs_contigsumsize > 0)
setbit(cg_clustersfree_swap(&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_swap(&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_swap(&acg, 0), blkno);
if (sblock.fs_contigsumsize > 0)
setbit(cg_clustersfree_swap(&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_swap(&acg, 0), d);
acg.cg_cs.cs_nffree++;
}
}
if (sblock.fs_contigsumsize > 0) {
int32_t *sump = cg_clustersum_swap(&acg, 0);
u_char *mapp = cg_clustersfree_swap(&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);
}

View File

@ -0,0 +1,41 @@
/* $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.
*
* $FreeBSD$
*/
/* 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

View File

@ -0,0 +1,142 @@
/* $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
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#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/ffs/fs.h>
#include "ffs/ufs_bswap.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);
}

View File

@ -0,0 +1,94 @@
/* $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.
*
* $FreeBSD$
*/
#ifndef _UFS_UFS_BSWAP_H_
#define _UFS_UFS_BSWAP_H_
#if defined(_KERNEL_OPT)
#include "opt_ffs.h"
#endif
#include <sys/endian.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_ */

View File

@ -0,0 +1,97 @@
/* $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
* $FreeBSD$
*/
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)

436
usr.sbin/makefs/getid.c Normal file
View File

@ -0,0 +1,436 @@
/* $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.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#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 "makefs.h"
#include "mtree.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;
}

288
usr.sbin/makefs/makefs.8 Normal file
View File

@ -0,0 +1,288 @@
.\" $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.
.\"
.\" $FreeBSD$
.\"
.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 .

314
usr.sbin/makefs/makefs.c Normal file
View File

@ -0,0 +1,314 @@
/* $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.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#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);
}

305
usr.sbin/makefs/makefs.h Normal file
View File

@ -0,0 +1,305 @@
/* $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.
*
* $FreeBSD$
*/
#ifndef _MAKEFS_H
#define _MAKEFS_H
#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), (long) td.tv_sec, (long) td.tv_usec); \
}
#ifndef DEFAULT_FSTYPE
#define DEFAULT_FSTYPE "ffs"
#endif
/*
* ffs specific settings
* ---------------------
*/
#define FFS_EI /* for opposite endian support in ffs headers */
/*
* Write-arounds/compat shims for endian-agnostic support.
* These belong in the kernel if/when it's possible to mount
* filesystems w/ either byte order.
*/
/*
* 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 */
#define FS_ISCLEAN 1
#define DINODE1_SIZE (sizeof(struct ufs1_dinode))
#define DINODE2_SIZE (sizeof(struct ufs2_dinode))
#define MAXSYMLINKLEN_UFS1 ((NDADDR + NIADDR) * sizeof(ufs1_daddr_t))
#define MAXSYMLINKLEN_UFS2 ((NDADDR + NIADDR) * sizeof(ufs2_daddr_t))
#if (BYTE_ORDER == LITTLE_ENDIAN)
#define DIRSIZ_SWAP(oldfmt, dp, needswap) \
(((oldfmt) && !(needswap)) ? \
DIRECTSIZ((dp)->d_type) : DIRECTSIZ((dp)->d_namlen))
#else
#define DIRSIZ_SWAP(oldfmt, dp, needswap) \
(((oldfmt) && (needswap)) ? \
DIRECTSIZ((dp)->d_type) : DIRECTSIZ((dp)->d_namlen))
#endif
#define cg_chkmagic_swap(cgp, ns) \
(ufs_rw32((cgp)->cg_magic, (ns)) == CG_MAGIC)
#define cg_inosused_swap(cgp, ns) \
((u_int8_t *)((u_int8_t *)(cgp) + ufs_rw32((cgp)->cg_iusedoff, (ns))))
#define cg_blksfree_swap(cgp, ns) \
((u_int8_t *)((u_int8_t *)(cgp) + ufs_rw32((cgp)->cg_freeoff, (ns))))
#define cg_clustersfree_swap(cgp, ns) \
((u_int8_t *)((u_int8_t *)(cgp) + ufs_rw32((cgp)->cg_clusteroff, (ns))))
#define cg_clustersum_swap(cgp, ns) \
((int32_t *)((uintptr_t)(cgp) + ufs_rw32((cgp)->cg_clustersumoff, ns)))
struct fs;
void ffs_fragacct_swap(struct fs *, int, int32_t [], int, int);
/*
* Declarations for compat routines.
*/
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);
struct passwd;
int uid_from_user(const char *, uid_t *);
int pwcache_userdb(int (*)(int), void (*)(void),
struct passwd * (*)(const char *), struct passwd * (*)(uid_t));
struct group;
int gid_from_group(const char *, gid_t *);
int pwcache_groupdb(int (*)(int), void (*)(void),
struct group * (*)(const char *), struct group * (*)(gid_t));
int setup_getid(const char *dir);
#endif /* _MAKEFS_H */

568
usr.sbin/makefs/walk.c Normal file
View File

@ -0,0 +1,568 @@
/* $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.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#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"
#include "extern.h" /* NB: mtree */
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 = mtree_readspec(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 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;
case F_SOCK:
return S_IFSOCK;
default:
printf("unknown type %d", type);
abort();
}
/* NOTREACHED */
}
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");
#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
#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.
*/
const char *
inode_type(mode_t mode)
{
if (S_ISREG(mode))
return ("file");
if (S_ISLNK(mode))
return ("symlink");
if (S_ISDIR(mode))
return ("dir");
if (S_ISLNK(mode))
return ("link");
if (S_ISFIFO(mode))
return ("fifo");
if (S_ISSOCK(mode))
return ("socket");
/* XXX should not happen but handle them */
if (S_ISCHR(mode))
return ("char");
if (S_ISBLK(mode))
return ("block");
return ("unknown");
}
/*
* 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);
}