Commit a24cc15b authored by Mike Hibler's avatar Mike Hibler

Imagezip groks (BSD) inodes. Since I have not enabled the "more dubious"

optimization, this will only affect UFS2 filesystems.

> /*
>  * If DO_INODES is defined, we look at the inode list in each cylinder group
>  * and try to make further space reducing optimizations.  If there are
>  * uninitialized inodes (UFS2 only) we add those blocks to the skip list.
>  *
>  * If CLEAR_FREE_INODES is also defined, we make a more dubious optimization.
>  * Initialized but free inodes will go into the image data, but we first zero
>  * everything except the (usually randomized) generation number in an attempt
>  * to reduce the compressed size of the data.
>  */
> #define DO_INODES
> #undef CLEAR_FREE_INODES
parent 6a0cfa4d
/*-
* 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
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* 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. The names of the authors 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 AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)dinode.h 8.3 (Berkeley) 1/21/94
* $FreeBSD: src/sys/ufs/ufs/dinode.h,v 1.13.2.1 2005/01/31 23:27:01 imp Exp $
*/
#ifndef _UFS_UFS_DINODE_H_
#define _UFS_UFS_DINODE_H_
/*
* The root inode is the root of the filesystem. Inode 0 can't be used for
* normal purposes and historically bad blocks were linked to inode 1, thus
* the root inode is 2. (Inode 1 is no longer used for this purpose, however
* numerous dump tapes make this assumption, so we are stuck with it).
*/
#define ROOTINO ((ino_t)2)
/*
* The Whiteout inode# is a dummy non-zero inode number which will
* never be allocated to a real file. It is used as a place holder
* in the directory entry which has been tagged as a DT_W entry.
* See the comments about ROOTINO above.
*/
#define WINO ((ino_t)1)
/*
* The size of physical and logical block numbers and time fields in UFS.
*/
typedef int32_t ufs1_daddr_t;
typedef int64_t ufs2_daddr_t;
typedef int64_t ufs_lbn_t;
typedef int64_t ufs_time_t;
/* File permissions. */
#define IEXEC 0000100 /* Executable. */
#define IWRITE 0000200 /* Writeable. */
#define IREAD 0000400 /* Readable. */
#define ISVTX 0001000 /* Sticky bit. */
#define ISGID 0002000 /* Set-gid. */
#define ISUID 0004000 /* Set-uid. */
/* File types. */
#define IFMT 0170000 /* Mask of file type. */
#define IFIFO 0010000 /* Named pipe (fifo). */
#define IFCHR 0020000 /* Character device. */
#define IFDIR 0040000 /* Directory file. */
#define IFBLK 0060000 /* Block device. */
#define IFREG 0100000 /* Regular file. */
#define IFLNK 0120000 /* Symbolic link. */
#define IFSOCK 0140000 /* UNIX domain socket. */
#define IFWHT 0160000 /* Whiteout. */
/*
* A dinode contains all the meta-data associated with a UFS2 file.
* This structure defines the on-disk format of a dinode. Since
* this structure describes an on-disk structure, all its fields
* are defined by types with precise widths.
*/
#define NXADDR 2 /* External addresses in inode. */
#define NDADDR 12 /* Direct addresses in inode. */
#define NIADDR 3 /* Indirect addresses in inode. */
struct ufs2_dinode {
u_int16_t di_mode; /* 0: IFMT, permissions; see below. */
int16_t di_nlink; /* 2: File link count. */
u_int32_t di_uid; /* 4: File owner. */
u_int32_t di_gid; /* 8: File group. */
u_int32_t di_blksize; /* 12: Inode blocksize. */
u_int64_t di_size; /* 16: File byte count. */
u_int64_t di_blocks; /* 24: Bytes actually held. */
ufs_time_t di_atime; /* 32: Last access time. */
ufs_time_t di_mtime; /* 40: Last modified time. */
ufs_time_t di_ctime; /* 48: Last inode change time. */
ufs_time_t di_birthtime; /* 56: Inode creation time. */
int32_t di_mtimensec; /* 64: Last modified time. */
int32_t di_atimensec; /* 68: Last access time. */
int32_t di_ctimensec; /* 72: Last inode change time. */
int32_t di_birthnsec; /* 76: Inode creation time. */
int32_t di_gen; /* 80: Generation number. */
u_int32_t di_kernflags; /* 84: Kernel flags. */
u_int32_t di_flags; /* 88: Status flags (chflags). */
int32_t di_extsize; /* 92: External attributes block. */
ufs2_daddr_t di_extb[NXADDR];/* 96: External attributes block. */
ufs2_daddr_t di_db[NDADDR]; /* 112: Direct disk blocks. */
ufs2_daddr_t di_ib[NIADDR]; /* 208: Indirect disk blocks. */
int64_t di_spare[3]; /* 232: Reserved; currently unused */
};
/*
* The di_db fields may be overlaid with other information for
* file types that do not have associated disk storage. Block
* and character devices overlay the first data block with their
* dev_t value. Short symbolic links place their path in the
* di_db area.
*/
#define di_rdev di_db[0]
/*
* A UFS1 dinode contains all the meta-data associated with a UFS1 file.
* This structure defines the on-disk format of a UFS1 dinode. Since
* this structure describes an on-disk structure, all its fields
* are defined by types with precise widths.
*/
struct ufs1_dinode {
u_int16_t di_mode; /* 0: IFMT, permissions; see below. */
int16_t di_nlink; /* 2: File link count. */
union {
u_int16_t oldids[2]; /* 4: Ffs: old user and group ids. */
} di_u;
u_int64_t di_size; /* 8: File byte count. */
int32_t di_atime; /* 16: Last access time. */
int32_t di_atimensec; /* 20: Last access time. */
int32_t di_mtime; /* 24: Last modified time. */
int32_t di_mtimensec; /* 28: Last modified time. */
int32_t di_ctime; /* 32: Last inode change time. */
int32_t di_ctimensec; /* 36: Last inode change time. */
ufs1_daddr_t di_db[NDADDR]; /* 40: Direct disk blocks. */
ufs1_daddr_t di_ib[NIADDR]; /* 88: Indirect disk blocks. */
u_int32_t di_flags; /* 100: Status flags (chflags). */
int32_t di_blocks; /* 104: Blocks actually held. */
int32_t di_gen; /* 108: Generation number. */
u_int32_t di_uid; /* 112: File owner. */
u_int32_t di_gid; /* 116: File group. */
int32_t di_spare[2]; /* 120: Reserved; currently unused */
};
#define di_ogid di_u.oldids[1]
#define di_ouid di_u.oldids[0]
#endif /* _UFS_UFS_DINODE_H_ */
/*
* EMULAB-COPYRIGHT
* Copyright (c) 2000-2004 University of Utah and the Flux Group.
* Copyright (c) 2000-2005 University of Utah and the Flux Group.
* All rights reserved.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <err.h>
#include <assert.h>
#include <sys/param.h>
......@@ -14,9 +16,29 @@
#include "global.h"
#include "imagehdr.h"
/*
* If DO_INODES is defined, we look at the inode list in each cylinder group
* and try to make further space reducing optimizations. If there are
* uninitialized inodes (UFS2 only) we add those blocks to the skip list.
*
* If CLEAR_FREE_INODES is also defined, we make a more dubious optimization.
* Initialized but free inodes will go into the image data, but we first zero
* everything except the (usually randomized) generation number in an attempt
* to reduce the compressed size of the data.
*/
#define DO_INODES
#undef CLEAR_FREE_INODES
#ifndef DO_INODES
#undef CLEAR_FREE_INODES
#endif
static int read_bsdpartition(int infd, struct disklabel *dlabel, int part);
static int read_bsdsblock(int infd, u_int32_t off, int part, struct fs *fsp);
static int read_bsdcg(struct fs *fsp, struct cg *cgp, unsigned int dbstart);
static int read_bsdcg(struct fs *fsp, struct cg *cgp, int cg, u_int32_t off);
#ifdef CLEAR_FREE_INODES
static void inodefixup(void *buf, off_t buflen, void *fdata);
#endif
/* Map partition number to letter */
#define BSDPARTNAME(i) ("abcdefghijklmnop"[(i)])
......@@ -222,10 +244,9 @@ read_bsdpartition(int infd, struct disklabel *dlabel, int part)
freecount = 0;
for (i = 0; i < fs.fs_ncg; i++) {
unsigned long cgoff, dboff;
unsigned long cgoff;
cgoff = fsbtodb(&fs, cgtod(&fs, i)) + offset;
dboff = fsbtodb(&fs, cgbase(&fs, i)) + offset;
if (devlseek(infd, sectobytes(cgoff), SEEK_SET) < 0) {
warn("BSD Partition '%c': "
......@@ -249,7 +270,7 @@ read_bsdpartition(int infd, struct disklabel *dlabel, int part)
i, cgoff, cg.cg.cg_cs.cs_nbfree);
}
rval = read_bsdcg(&fs, &cg.cg, dboff);
rval = read_bsdcg(&fs, &cg.cg, i, offset);
if (rval)
return rval;
}
......@@ -369,11 +390,12 @@ read_bsdsblock(int infd, u_int32_t offset, int part, struct fs *fsp)
}
static int
read_bsdcg(struct fs *fsp, struct cg *cgp, unsigned int dbstart)
read_bsdcg(struct fs *fsp, struct cg *cgp, int cg, u_int32_t offset)
{
int i, max;
u_int8_t *p;
int count, j;
unsigned long dboff, dbcount, dbstart;
max = fsp->fs_fpg;
p = cg_blksfree(cgp);
......@@ -394,13 +416,13 @@ read_bsdcg(struct fs *fsp, struct cg *cgp, unsigned int dbstart)
* we add the bitmap offset. All blocks before cgdmin() will always
* be allocated, but we scan them anyway.
*/
assert(cgbase(fsp, cg) == cgstart(fsp, cg));
dbstart = fsbtodb(fsp, cgbase(fsp, cg)) + offset;
if (debug > 2)
fprintf(stderr, " ");
fprintf(stderr, " ");
for (count = i = 0; i < max; i++)
if (isset(p, i)) {
unsigned long dboff, dbcount;
j = i;
while ((i+1)<max && isset(p, i+1))
i++;
......@@ -413,7 +435,7 @@ read_bsdcg(struct fs *fsp, struct cg *cgp, unsigned int dbstart)
if (count)
fprintf(stderr, ",%s",
count % 4 ?
" " : "\n ");
" " : "\n ");
fprintf(stderr, "%lu:%ld", dboff, dbcount);
}
addskip(dboff, dbcount);
......@@ -421,6 +443,225 @@ read_bsdcg(struct fs *fsp, struct cg *cgp, unsigned int dbstart)
}
if (debug > 2)
fprintf(stderr, "\n");
#ifdef DO_INODES
/*
* Look for free inodes
*/
if (cgp->cg_cs.cs_nifree != 0) {
#ifdef CLEAR_FREE_INODES
static uint32_t ufs1_magic = FS_UFS1_MAGIC;
static uint32_t ufs2_magic = FS_UFS2_MAGIC;
uint32_t *magic;
#endif
int tifree = 0;
unsigned long edboff;
int ino;
p = cg_inosused(cgp);
max = fsp->fs_ipg;
assert(&p[max/NBBY] <= (u_int8_t *)cgp + fsp->fs_cgsize);
/*
* For UFS2, (cylinder-group relative) inode numbers beyond
* initediblk are uninitialized. We do not process those
* now. They are treated as regular free blocks below.
*/
if (fsp->fs_magic == FS_UFS2_MAGIC) {
assert(cgp->cg_initediblk > 0);
assert(cgp->cg_initediblk <= fsp->fs_ipg);
assert((cgp->cg_initediblk % INOPB(fsp)) == 0);
max = cgp->cg_initediblk;
}
ino = cg * fsp->fs_ipg;
#ifdef CLEAR_FREE_INODES
if (debug > 1)
fprintf(stderr,
" \t ifree %9d\n",
cgp->cg_cs.cs_nifree);
if (debug > 2)
fprintf(stderr, " ");
magic = (fsp->fs_magic == FS_UFS2_MAGIC) ?
&ufs2_magic : &ufs1_magic;
for (count = i = 0; i < max; i++) {
if (isset(p, i)) {
continue;
}
if (ino_to_fsbo(fsp, ino+i) == 0) {
j = i;
while ((i+1) < max && !isset(p, i+1))
i++;
dboff = fsbtodb(fsp, ino_to_fsba(fsp, ino+j));
edboff = fsbtodb(fsp, ino_to_fsba(fsp, ino+i));
#if 0
fprintf(stderr, " found free inodes %d-%d"
" db %lu.%u to %lu.%u\n",
ino+j, ino+i,
dboff+offset, ino_to_fsbo(fsp, ino+j),
edboff+offset, ino_to_fsbo(fsp, ino+i));
#endif
tifree += (i+1 - j);
dbcount = edboff - dboff;
if ((i+1) == max)
dbcount++;
if (dbcount == 0)
continue;
addfixupfunc(inodefixup,
sectobytes(dboff+offset),
sectobytes(offset),
sectobytes(dbcount),
magic, sizeof(magic),
RELOC_NONE);
if (debug > 2) {
if (count)
fprintf(stderr, ",%s",
count % 4 ?
" " :
"\n ");
fprintf(stderr, "%lu:%ld",
dboff+offset, dbcount);
}
count++;
} else
tifree++;
}
assert(i == max);
if (debug > 2)
fprintf(stderr, "\n");
#endif
/*
* For UFS2, deal with uninitialized inodes.
* These are sweet, we just add them to the skip list.
*/
if (fsp->fs_magic == FS_UFS2_MAGIC && max < fsp->fs_ipg) {
i = max;
if (debug > 1)
fprintf(stderr,
" \t uninit %9d\n",
fsp->fs_ipg - i);
if (debug > 2)
fprintf(stderr, " ");
max = fsp->fs_ipg;
#if 1
/*
* Paranoia!
*/
j = i;
while ((j+1) < max) {
assert(!isset(p, j+1));
j++;
}
#endif
tifree += (max - i);
dboff = fsbtodb(fsp, ino_to_fsba(fsp, ino+i));
edboff = fsbtodb(fsp, ino_to_fsba(fsp, ino+max-1));
dbcount = edboff - dboff + 1;
if (debug > 2)
fprintf(stderr, "%lu:%ld",
dboff+offset, dbcount);
addskip(dboff+offset, dbcount);
if (debug > 2)
fprintf(stderr, "\n");
}
#ifdef CLEAR_FREE_INODES
if (tifree != cgp->cg_cs.cs_nifree)
fprintf(stderr, "Uh-oh! found %d free inodes, "
"shoulda found %d\n",
tifree, cgp->cg_cs.cs_nifree);
#endif
}
#endif
return 0;
}
#ifdef CLEAR_FREE_INODES
/*
* Simplified from fsck/pass1.c checkinode
*/
static int
inodeisfree(int32_t magic, union dinode *dp)
{
static union dinode zino;
switch (magic) {
case FS_UFS1_MAGIC:
if (dp->dp1.di_mode != 0 || dp->dp1.di_size != 0 ||
memcmp(dp->dp1.di_db, zino.dp1.di_db,
NDADDR * sizeof(ufs1_daddr_t)) ||
memcmp(dp->dp1.di_ib, zino.dp1.di_ib,
NIADDR * sizeof(ufs1_daddr_t)))
return 0;
break;
case FS_UFS2_MAGIC:
if (dp->dp2.di_mode != 0 || dp->dp2.di_size != 0 ||
memcmp(dp->dp2.di_db, zino.dp2.di_db,
NDADDR * sizeof(ufs2_daddr_t)) ||
memcmp(dp->dp2.di_ib, zino.dp2.di_ib,
NIADDR * sizeof(ufs2_daddr_t))) {
fprintf(stderr, "mode=%x, size=%x\n",
dp->dp2.di_mode, (unsigned)dp->dp2.di_size);
return 0;
}
break;
}
return 1;
}
static void
inodefixup(void *bstart, off_t bsize, void *fdata)
{
uint32_t magic = *(uint32_t *)fdata;
void *ptr, *eptr;
int inodesize;
if (debug > 1)
fprintf(stderr, "inodefixup: data [%p-%p], fs=UFS%d\n",
bstart, bstart+bsize-1,
magic == FS_UFS2_MAGIC ? 2 : 1);
switch (magic) {
case FS_UFS1_MAGIC:
inodesize = sizeof(struct ufs1_dinode);
break;
case FS_UFS2_MAGIC:
inodesize = sizeof(struct ufs2_dinode);
break;
default:
fprintf(stderr, "Unknown UFS version: %x\n", magic);
exit(1);
}
assert((bsize % inodesize) == 0);
for (ptr = bstart, eptr = ptr+bsize; ptr < eptr; ptr += inodesize) {
uint32_t gen;
if (!inodeisfree(magic, (union dinode *)ptr)) {
fprintf(stderr, "UFS%d inode is not free!\n",
magic == FS_UFS1_MAGIC ? 1 : 2);
exit(1);
}
/*
* Save off the randomized generation number
* and zap the rest.
*/
gen = DIP(magic, (union dinode *)ptr, di_gen);
memset(ptr, 0, inodesize);
if (magic == FS_UFS1_MAGIC)
((union dinode *)ptr)->dp1.di_gen = gen;
else
((union dinode *)ptr)->dp2.di_gen = gen;
}
}
#endif
/*
* EMULAB-COPYRIGHT
* Copyright (c) 2000-2003 University of Utah and the Flux Group.
* Copyright (c) 2000-2003, 2005 University of Utah and the Flux Group.
* All rights reserved.
*/
/*
* Glue for FreeBSD 5.x <ufs/ffs/fs.h>. This version supports UFS2.
*/
typedef int64_t ufs_time_t;
typedef int32_t ufs1_daddr_t;
typedef int64_t ufs2_daddr_t;
#include "dinode.h"
union dinode {
struct ufs1_dinode dp1;
struct ufs2_dinode dp2;
};
#define DIP(magic, dp, field) \
(((magic) == FS_UFS1_MAGIC) ? (dp)->dp1.field : (dp)->dp2.field)
#ifndef BBSIZE
#define BBSIZE 8192
......
......@@ -18,6 +18,9 @@ extern void addskip(uint32_t start, uint32_t size);
extern void addvalid(uint32_t start, uint32_t size);
extern void addfixup(off_t offset, off_t poffset, off_t size, void *data,
int reloctype);
extern void addfixupfunc(void (*func)(void *, off_t, void *), off_t offset,
off_t poffset, off_t size, void *data, int dsize,
int reloctype);
extern SLICEMAP_PROCESS_PROTO(read_bsdslice);
extern SLICEMAP_PROCESS_PROTO(read_linuxslice);
......
......@@ -25,6 +25,7 @@
#include "imagehash.h"
//#define FOLLOW
#define HASH_FREE
/*
* globals for fetching the HASHSTATS related information
......@@ -53,8 +54,6 @@ struct timeval time_orig_read, time_curr_read, time_hash,
#endif
extern void freeranges(struct range *);
#define HASH_FREE
/*
* hash_free determines what we do when we have overlapping free blocks
* within hash range --
......
......@@ -99,6 +99,7 @@ int mergeranges(struct range *head);
void makeranges(void);
void freeranges(struct range *);
void dumpranges(int verbose);
void dumpfixups(int verbose);
void addvalid(uint32_t start, uint32_t size);
void addreloc(off_t offset, off_t size, int reloctype);
static int cmpfixups(struct range *r1, struct range *r2);
......@@ -250,7 +251,6 @@ devread(int fd, void *buf, size_t nbytes)
else
count = nbytes;
cc = slowread(fd, buf, count, startoffset);
fprintf(stderr, "slowread(fd, buf, %d, %llu) -> %d\n", count, startoffset, cc);
if (cc != count) {
fprintf(stderr, "devread: read failed on sector %u, "
"returning zeros\n",
......@@ -589,6 +589,8 @@ main(int argc, char *argv[])
dumpranges(debug > 1);
sortrange(fixups, 0, cmpfixups);
if (debug > 1)
dumpfixups(debug > 2);
fflush(stderr);
#ifdef WITH_HASH
......@@ -664,7 +666,7 @@ main(int argc, char *argv[])
ms = (stamp.tv_sec - sstamp.tv_sec) * 1000 +
(stamp.tv_usec - sstamp.tv_usec) / 1000;
fprintf(stderr,
"\nFinished in %u.%03u seconds\n",
"Finished in %u.%03u seconds\n",
ms / 1000, ms % 1000);
}
fflush(stderr);
......@@ -1232,14 +1234,22 @@ struct fixup {
off_t poffset; /* partition offset */
off_t size;
int reloctype;
char data[0];
void *data; /* current value of data ptr */
void (*func)(void *, off_t, void *);
};
static int nfixups;
void
addfixup(off_t offset, off_t poffset, off_t size, void *data, int reloctype)
static void
addfixupentry(off_t offset, off_t poffset, off_t size, void *data, off_t dsize,
int reloctype, void (*func)(void *, off_t, void *))
{
struct mydata {
struct fixup _fixup;
char _fdata[0];
} *buf;
struct range *entry;
struct fixup *fixup;
void *fdata;
if (oldstyle) {
static int warned;
......@@ -1251,11 +1261,19 @@ addfixup(off_t offset, off_t poffset, off_t size, void *data, int reloctype)
return;
}
/*
* Malloc the range separate from the fixup data since
* sortranges will swap contents of the former.
*/
if ((entry = malloc(sizeof(*entry))) == NULL ||
(fixup = malloc(sizeof(*fixup) + (int)size)) == NULL) {
(buf = malloc(sizeof(*buf) + (size_t)dsize)) == NULL) {
fprintf(stderr, "Out of memory!\n");
exit(1);
}
assert((void *)buf == (void *)&buf->_fixup);
fixup = &buf->_fixup;
fdata = dsize ? buf->_fdata : NULL;
entry->start = bytestosec(offset);
entry->size = bytestosec(size + secsize - 1);
......@@ -1265,10 +1283,42 @@ addfixup(off_t offset, off_t poffset, off_t size, void *data, int reloctype)
fixup->poffset = poffset;
fixup->size = size;
fixup->reloctype = reloctype;
memcpy(fixup->data, data, size);
fixup->data = fdata;
if (fdata)
memcpy(fixup->data, data, (size_t)dsize);
fixup->func = func;
entry->next = fixups;
fixups = entry;
nfixups++;
}
/*
* Create a fixup to apply to the disk data prior to compressing.
* The given fixup will be applied to the appropriate data and a relocation
* genearated if desired. The region over which the fixup should be
* applied is given by 'offset' and 'size'. That range is replaced by
* the data in 'data'. If 'reloctype' is not 0, a relocation entry of
* the appropraite type is generated. 'poffset' is the partition
* offset which is used when generating relocations to ensure that
* they are partition-relative.
*/
void
addfixup(off_t offset, off_t poffset, off_t size, void *data, int reloctype)
{
addfixupentry(offset, poffset, size, data, size, reloctype, NULL);
}
/*
* Similar to the above but calls a function with the fixup entry and the
* range of data to apply the fixup to. The data arg is passed to the
* function along with the data range.
*/
void
addfixupfunc(void (*func)(void *, off_t, void *), off_t offset,
off_t poffset, off_t size, void *data, int dsize, int reloctype)
{
addfixupentry(offset, poffset, size, data, dsize, reloctype, func);
}
/*
......@@ -1285,6 +1335,11 @@ cmpfixups(struct range *r1, struct range *r2)
return 0;
}
/*
* Look for fixups which overlap the range [offset - offset+size-1].
* If an overlap is found, we overwrite the data for that range with
* that given in the fixup or call the associated function.
*/
void
applyfixups(off_t offset, off_t size, void *data)
{
......@@ -1292,36 +1347,134 @@ applyfixups(off_t offset, off_t size, void *data)
struct fixup *fp;
uint32_t coff, clen;
#ifdef FOLLOW
fprintf(stderr, "D: [%u-%u], %d fixups\n",
bytestosec(offset), bytestosec(offset+size)-1, nfixups);
#endif
prev = &fixups;
while ((entry = *prev) != NULL) {
assert(entry->data != NULL);
fp = entry->data;
#ifdef FOLLOW
fprintf(stderr, " F%p: [%u/%u-%u/%u]: ",
fp,
bytestosec(fp->offset),
(uint32_t)fp->offset % SECSIZE,
bytestosec(fp->offset+fp->size),
(uint32_t)(fp->offset+fp->size) % SECSIZE);
#endif
/*
* Since we sort both the ranges we are processing and
* the fixup ranges, and we remove fixups as we apply them,
* we should never encounter any fixups that fall even
* partially before the data range we are operating on.
*/
assert(fp->offset >= offset);
if (offset < fp->offset+fp->size && offset+size > fp->offset) {
/* XXX lazy: fixup must be totally contained */
assert(offset <= fp->offset);
assert(fp->offset+fp->size <= offset+size);
/*