import netbsd makefs tool
This commit is contained in:
commit
d347a0da97
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=186335
28
usr.sbin/makefs/Makefile
Normal file
28
usr.sbin/makefs/Makefile
Normal 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>
|
623
usr.sbin/makefs/compat/pwcache.c
Normal file
623
usr.sbin/makefs/compat/pwcache.c
Normal 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 */
|
73
usr.sbin/makefs/compat/pwcache.h
Normal file
73
usr.sbin/makefs/compat/pwcache.h
Normal 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;
|
229
usr.sbin/makefs/compat/strsuftoll.c
Normal file
229
usr.sbin/makefs/compat/strsuftoll.c
Normal 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
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
222
usr.sbin/makefs/ffs/buf.c
Normal 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
67
usr.sbin/makefs/ffs/buf.h
Normal 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 */
|
683
usr.sbin/makefs/ffs/ffs_alloc.c
Normal file
683
usr.sbin/makefs/ffs/ffs_alloc.c
Normal 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;
|
||||
}
|
578
usr.sbin/makefs/ffs/ffs_balloc.c
Normal file
578
usr.sbin/makefs/ffs/ffs_balloc.c
Normal 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);
|
||||
}
|
270
usr.sbin/makefs/ffs/ffs_bswap.c
Normal file
270
usr.sbin/makefs/ffs/ffs_bswap.c
Normal file
@ -0,0 +1,270 @@
|
||||
/* $NetBSD: ffs_bswap.c,v 1.28 2004/05/25 14:54:59 hannken Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1998 Manuel Bouyer.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by Manuel Bouyer.
|
||||
* 4. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#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]);
|
||||
}
|
77
usr.sbin/makefs/ffs/ffs_extern.h
Normal file
77
usr.sbin/makefs/ffs/ffs_extern.h
Normal 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 *);
|
202
usr.sbin/makefs/ffs/ffs_subr.c
Normal file
202
usr.sbin/makefs/ffs/ffs_subr.c
Normal 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
832
usr.sbin/makefs/ffs/mkfs.c
Normal 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);
|
||||
}
|
41
usr.sbin/makefs/ffs/newfs_extern.h
Normal file
41
usr.sbin/makefs/ffs/newfs_extern.h
Normal 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
|
142
usr.sbin/makefs/ffs/ufs_bmap.c
Normal file
142
usr.sbin/makefs/ffs/ufs_bmap.c
Normal 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);
|
||||
}
|
94
usr.sbin/makefs/ffs/ufs_bswap.h
Normal file
94
usr.sbin/makefs/ffs/ufs_bswap.h
Normal 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_ */
|
97
usr.sbin/makefs/ffs/ufs_inode.h
Normal file
97
usr.sbin/makefs/ffs/ufs_inode.h
Normal 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
436
usr.sbin/makefs/getid.c
Normal 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
288
usr.sbin/makefs/makefs.8
Normal 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
314
usr.sbin/makefs/makefs.c
Normal 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
305
usr.sbin/makefs/makefs.h
Normal 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
568
usr.sbin/makefs/walk.c
Normal 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);
|
||||
}
|
Loading…
Reference in New Issue
Block a user