home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
linuxmafia.com 2016
/
linuxmafia.com.tar
/
linuxmafia.com
/
pub
/
linux
/
backup
/
star-1.3.1.tar.gz
/
star-1.3.1.tar
/
star-1.3.1
/
star
/
hole.c
< prev
next >
Wrap
C/C++ Source or Header
|
2000-05-07
|
17KB
|
727 lines
/*#define DEBUG*/
/* @(#)hole.c 1.18 00/05/07 Copyright 1990 J. Schilling */
#ifndef lint
static char sccsid[] =
"@(#)hole.c 1.18 00/05/07 Copyright 1990 J. Schilling";
#endif
/*
* Handle files with holes (sparse files)
*
* Copyright (c) 1990 J. Schilling
*/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <mconfig.h>
#include <stdio.h>
#include <stdxlib.h>
#include <sys/types.h>
#include <unixstd.h>
#include <standard.h>
#include <schily.h>
#include "star.h"
#include "props.h"
#include "table.h"
#include "starsubs.h"
#ifdef sun
# include <sys/filio.h>
# if _FIOAI == _FIOOBSOLETE67
# undef _FIOAI
# endif
# ifdef _FIOAI
# include <sys/fs/ufs_filio.h>
# endif
#endif /* sun */
#ifdef DEBUG
#define EDEBUG(a) if (debug) error a
#else
#define EDEBUG(a)
#endif
extern int bigcnt;
extern char *bigptr;
extern BOOL debug;
extern BOOL nullout;
char zeroblk[TBLOCK];
typedef struct {
FILE *fh_file;
char *fh_name;
long fh_size;
long fh_newpos;
sp_t *fh_sparse;
int fh_nsparse;
int fh_spindex;
int fh_diffs;
} fh_t;
LOCAL int force_hole_func __PR((fh_t * fh, char* p, int amount));
EXPORT int get_forced_hole __PR((FILE * f, FINFO * info));
LOCAL int get_sparse_func __PR((fh_t * fh, char* p, int amount));
LOCAL int cmp_sparse_func __PR((fh_t * fh, char* p, int amount));
LOCAL int put_sparse_func __PR((fh_t * fh, char* p, int amount));
LOCAL sp_t* grow_sp_list __PR((sp_t * sparse, int* nspp));
LOCAL sp_t* get_sp_list __PR((FINFO * info));
LOCAL int mk_sp_list __PR((int *fp, FINFO * info, sp_t ** spp));
EXPORT int gnu_skip_extended __PR((TCB * ptb));
EXPORT int get_sparse __PR((FILE * f, FINFO * info));
EXPORT BOOL cmp_sparse __PR((FILE * f, FINFO * info));
EXPORT void put_sparse __PR((int *fp, FINFO * info));
LOCAL void put_sp_list __PR((FINFO * info, sp_t * sparse, int nsparse));
#define vp_force_hole_func ((int(*)__PR((void *, char *, int)))force_hole_func)
LOCAL int
force_hole_func(fh, p, amount)
register fh_t *fh;
register char *p;
int amount;
{
register int cnt;
fh->fh_newpos += amount;
if (amount < fh->fh_size &&
cmpbytes(bigptr, zeroblk, amount) >= amount) {
if (lseek(fdown(fh->fh_file), fh->fh_newpos, SEEK_SET) < 0) {
xstats.s_rwerrs++;
errmsg("Error seeking '%s'.\n", fh->fh_name);
}
fh->fh_size -= amount;
return (amount);
}
cnt = ffilewrite(fh->fh_file, p, amount);
fh->fh_size -= amount;
return (cnt);
}
EXPORT BOOL
get_forced_hole(f, info)
FILE *f;
FINFO *info;
{
fh_t fh;
fh.fh_file = f;
fh.fh_name = info->f_name;
fh.fh_size = info->f_rsize;
fh.fh_newpos = 0L;
return (xt_file(info, vp_force_hole_func, &fh, TBLOCK, "writing"));
}
#define vp_get_sparse_func ((int(*)__PR((void *, char *, int)))get_sparse_func)
LOCAL int
get_sparse_func(fh, p, amount)
register fh_t *fh;
register char *p;
int amount;
{
register int cnt;
EDEBUG(("amount: %d newpos: %d index: %d\n",
amount, fh->fh_newpos, fh->fh_spindex));
if (fh->fh_sparse[fh->fh_spindex].sp_offset > fh->fh_newpos) {
EDEBUG(("seek to: %d\n",
fh->fh_sparse[fh->fh_spindex].sp_offset));
if (lseek(fdown(fh->fh_file),
fh->fh_sparse[fh->fh_spindex].sp_offset, SEEK_SET) < 0) {
xstats.s_rwerrs++;
errmsg("Error seeking '%s'.\n", fh->fh_name);
}
fh->fh_newpos = fh->fh_sparse[fh->fh_spindex].sp_offset;
}
EDEBUG(("write %d at: %d\n", amount, fh->fh_newpos));
cnt = ffilewrite(fh->fh_file, p, amount);
fh->fh_size -= cnt;
fh->fh_newpos += cnt;
EDEBUG(("off: %d numb: %d cnt: %d off+numb: %d newpos: %d index: %d\n",
fh->fh_sparse[fh->fh_spindex].sp_offset,
fh->fh_sparse[fh->fh_spindex].sp_numbytes, cnt,
fh->fh_sparse[fh->fh_spindex].sp_offset +
fh->fh_sparse[fh->fh_spindex].sp_numbytes,
fh->fh_newpos,
fh->fh_spindex));
if ((fh->fh_sparse[fh->fh_spindex].sp_offset +
fh->fh_sparse[fh->fh_spindex].sp_numbytes)
<= fh->fh_newpos) {
fh->fh_spindex++;
EDEBUG(("new index: %d\n", fh->fh_spindex));
}
EDEBUG(("return (%d)\n", cnt));
return (cnt);
}
#define vp_cmp_sparse_func ((int(*)__PR((void *, char *, int)))cmp_sparse_func)
LOCAL int
cmp_sparse_func(fh, p, amount)
register fh_t *fh;
register char *p;
int amount;
{
register int cnt;
char *cmp_buf[TBLOCK];
EDEBUG(("amount: %d newpos: %d index: %d\n",
amount, fh->fh_newpos, fh->fh_spindex));
/*
* If we already found diffs we save time and only pass tape ...
*/
if (fh->fh_diffs)
return (amount);
if (fh->fh_sparse[fh->fh_spindex].sp_offset > fh->fh_newpos) {
EDEBUG(("seek to: %d\n",
fh->fh_sparse[fh->fh_spindex].sp_offset));
while (fh->fh_newpos < fh->fh_sparse[fh->fh_spindex].sp_offset){
register int amt;
amt = min(TBLOCK,
fh->fh_sparse[fh->fh_spindex].sp_offset -
fh->fh_newpos);
cnt = ffileread(fh->fh_file, cmp_buf, amt);
if (cnt != amt)
fh->fh_diffs++;
if (cmpbytes(cmp_buf, zeroblk, amt) < cnt)
fh->fh_diffs++;
fh->fh_newpos += cnt;
if (fh->fh_diffs)
return (amount);
}
}
EDEBUG(("read %d at: %d\n", amount, fh->fh_newpos));
cnt = ffileread(fh->fh_file, cmp_buf, amount);
if (cnt != amount)
fh->fh_diffs++;
if (cmpbytes(cmp_buf, p, cnt) < cnt)
fh->fh_diffs++;
fh->fh_size -= cnt;
fh->fh_newpos += cnt;
EDEBUG(("off: %d numb: %d cnt: %d off+numb: %d newpos: %d index: %d\n",
fh->fh_sparse[fh->fh_spindex].sp_offset,
fh->fh_sparse[fh->fh_spindex].sp_numbytes, cnt,
fh->fh_sparse[fh->fh_spindex].sp_offset +
fh->fh_sparse[fh->fh_spindex].sp_numbytes,
fh->fh_newpos,
fh->fh_spindex));
if ((fh->fh_sparse[fh->fh_spindex].sp_offset +
fh->fh_sparse[fh->fh_spindex].sp_numbytes)
<= fh->fh_newpos) {
fh->fh_spindex++;
EDEBUG(("new index: %d\n", fh->fh_spindex));
}
EDEBUG(("return (%d) diffs: %d\n", cnt, fh->fh_diffs));
return (cnt);
}
#define vp_put_sparse_func ((int(*)__PR((void *, char *, int)))put_sparse_func)
LOCAL int
put_sparse_func(fh, p, amount)
register fh_t *fh;
register char *p;
int amount;
{
register int cnt;
EDEBUG(("amount: %d newpos: %d index: %d\n",
amount, fh->fh_newpos, fh->fh_spindex));
if (fh->fh_spindex < fh->fh_nsparse &&
fh->fh_sparse[fh->fh_spindex].sp_offset > fh->fh_newpos) {
EDEBUG(("seek to: %d\n",
fh->fh_sparse[fh->fh_spindex].sp_offset));
if (lseek(*(int *)(fh->fh_file),
fh->fh_sparse[fh->fh_spindex].sp_offset, SEEK_SET) < 0) {
xstats.s_rwerrs++;
errmsg("Error seeking '%s'.\n", fh->fh_name);
}
fh->fh_newpos = fh->fh_sparse[fh->fh_spindex].sp_offset;
}
EDEBUG(("read %d at: %d\n", amount, fh->fh_newpos));
if (nullout) {
cnt = amount;
if (cnt > fh->fh_size)
cnt = fh->fh_size;
} else {
cnt = _fileread((int *)fh->fh_file, p, amount);
}
fh->fh_size -= cnt;
fh->fh_newpos += cnt;
/* if (cnt < TBLOCK)*/
/* fillbytes(&p[cnt], TBLOCK-cnt, '\0');*/
EDEBUG(("off: %d numb: %d cnt: %d off+numb: %d newpos: %d index: %d\n",
fh->fh_sparse[fh->fh_spindex].sp_offset,
fh->fh_sparse[fh->fh_spindex].sp_numbytes, cnt,
fh->fh_sparse[fh->fh_spindex].sp_offset +
fh->fh_sparse[fh->fh_spindex].sp_numbytes,
fh->fh_newpos,
fh->fh_spindex));
if ((fh->fh_sparse[fh->fh_spindex].sp_offset +
fh->fh_sparse[fh->fh_spindex].sp_numbytes)
<= fh->fh_newpos) {
fh->fh_spindex++;
EDEBUG(("new index: %d\n", fh->fh_spindex));
}
EDEBUG(("return (%d)\n", cnt));
return (cnt);
}
LOCAL sp_t *
grow_sp_list(sparse, nspp)
sp_t *sparse;
int *nspp;
{
sp_t *new;
if (*nspp < 512)
*nspp *= 2;
else
*nspp += 512;
new = (sp_t *)realloc(sparse, *nspp*sizeof(sp_t));
if (new == 0) {
errmsg("Cannot grow sparse buf.\n");
free(sparse);
}
return (new);
}
LOCAL sp_t *
get_sp_list(info)
FINFO *info;
{
TCB tb;
TCB *ptb = info->f_tcb;
sp_t *sparse;
int nsparse = 25;
int extended;
register int i;
register int sparse_in_hdr = props.pr_sparse_in_hdr;
register int ind;
char *p;
/*XXX*/extern int hdrtype;
EDEBUG(("rsize: %d\n" , info->f_rsize));
sparse = (sp_t *)malloc(nsparse*sizeof(sp_t));
if (sparse == 0) {
errmsg("Cannot alloc sparse buf.\n");
return (sparse);
}
if (H_TYPE(hdrtype) == H_GNUTAR) {
p = (char *)ptb->gnu_in_dbuf.t_sp;
} else {
p = (char *)ptb->xstar_in_dbuf.t_sp;
if (ptb->xstar_dbuf.t_prefix[0] == '\0' &&
ptb->xstar_in_dbuf.t_sp[0].t_offset[10] != '\0') {
static BOOL warned;
extern BOOL nowarn;
if (!nowarn && !warned) {
errmsgno(EX_BAD, "WARNING: Archive uses old sparse format. Please upgrade!\n");
warned = TRUE;
}
sparse_in_hdr = SPARSE_IN_HDR;
}
}
for (i= 0; i < sparse_in_hdr; i++) {
astoo(p, &sparse[i].sp_offset); p += 12;
astoo(p, &sparse[i].sp_numbytes); p += 12;
if (sparse[i].sp_numbytes == 0)
break;
}
#ifdef DEBUG
if (debug) for (i = 0; i < sparse_in_hdr; i++) {
error("i: %d offset: %d numbytes: %d\n", i,
sparse[i].sp_offset,
sparse[i].sp_numbytes);
if (sparse[i].sp_numbytes == 0)
break;
}
#endif
ind = sparse_in_hdr-SPARSE_EXT_HDR;
if (H_TYPE(hdrtype) == H_GNUTAR)
extended = ptb->gnu_in_dbuf.t_isextended;
else
extended = ptb->xstar_in_dbuf.t_isextended;
extended |= sparse_in_hdr == 0;
EDEBUG(("isextended: %d\n", extended));
ptb = &tb; /* don't destroy orig TCB */
while (extended) {
if (readblock((char *)ptb) == EOF) {
free(sparse);
return (0);
}
if ((props.pr_flags & PR_GNU_SPARSE_BUG) == 0)
info->f_rsize -= TBLOCK;
EDEBUG(("rsize: %d\n" , info->f_rsize));
ind += SPARSE_EXT_HDR;
EDEBUG(("ind: %d\n", ind));
if (i+ind > nsparse+1) {
if ((sparse = grow_sp_list(sparse, &nsparse)) == 0)
return ((sp_t *)0);
}
p = (char *)ptb;
for (i = 0; i < SPARSE_EXT_HDR; i++) {
astoo(p, &sparse[i+ind].sp_offset); p += 12;
astoo(p, &sparse[i+ind].sp_numbytes); p += 12;
EDEBUG(("i: %d offset: %d numbytes: %d\n", i,
sparse[i+ind].sp_offset,
sparse[i+ind].sp_numbytes));
if (sparse[i+ind].sp_numbytes == 0)
break;
}
extended = ptb->gnu_ext_dbuf.t_isextended;
}
#ifdef DEBUG
ind += i;
EDEBUG(("ind: %d\n", ind));
if (debug) for (i = 0; i < ind; i++) {
error("i: %d offset: %d numbytes: %d\n", i,
sparse[i].sp_offset,
sparse[i].sp_numbytes);
if (sparse[i].sp_numbytes == 0)
break;
}
EDEBUG(("rsize: %d\n" , info->f_rsize));
#endif
return (sparse);
}
LOCAL int
mk_sp_list(fp, info, spp)
int *fp;
FINFO *info;
sp_t **spp;
{
char rbuf[TBLOCK];
sp_t *sparse;
int nsparse = 25;
register int amount = 0;
register long pos = 0;
register int i = 0;
register BOOL data = FALSE;
register BOOL use_ai = FALSE;
register BOOL is_hole = FALSE;
#ifdef _FIOAI
int fai_idx;
struct fioai fai;
struct fioai *faip;
# define NFAI 1024
daddr_t fai_arr[NFAI];
#endif /* _FIOAI */
#ifdef _FIOAI
fai.fai_off = 0;
fai.fai_size = 512;
fai.fai_num = 1;
fai.fai_daddr = fai_arr;
use_ai = ioctl(*fp, _FIOAI, &fai) >= 0; /* Use if operational*/
fai_idx = 0;
#endif /* _FIOAI */
*spp = (sp_t *)0;
info->f_rsize = 0;
sparse = (sp_t *)malloc(nsparse*sizeof(sp_t));
if (sparse == 0) {
errmsg("Cannot alloc sparse buf.\n");
return (i);
}
for (;;) {
if (use_ai) {
#ifdef _FIOAI
if (fai_idx >= fai.fai_num) {
fai.fai_off = pos;
fai.fai_size = 512 * NFAI;
fai.fai_num = NFAI;
ioctl(*fp, _FIOAI, &fai);
if (fai.fai_num == 0)
break;
fai_idx = 0;
}
is_hole = fai.fai_daddr[fai_idx++] == _FIOAI_HOLE;
amount = 512;
#endif /* _FIOAI */
} else {
if ((amount = _fileread(fp, rbuf, TBLOCK)) == 0)
break;
is_hole = cmpbytes(rbuf, zeroblk, amount) >= amount;
}
if (is_hole) {
if (data) {
sparse[i].sp_numbytes =
pos - sparse[i].sp_offset;
info->f_rsize += sparse[i].sp_numbytes;
EDEBUG(("i: %d offset: %d numbytes: %d\n", i,
sparse[i].sp_offset,
sparse[i].sp_numbytes));
data = FALSE;
i++;
if (i >= nsparse) {
if ((sparse = grow_sp_list(sparse,
&nsparse)) == 0) {
lseek(*fp, 0L, SEEK_SET);
return (0);
}
}
}
} else {
if (!data) {
sparse[i].sp_offset = pos;
data = TRUE;
}
}
pos += amount;
}
EDEBUG(("data: %d\n", data));
if (data) {
sparse[i].sp_numbytes = pos - sparse[i].sp_offset;
info->f_rsize += sparse[i].sp_numbytes;
EDEBUG(("i: %d offset: %d numbytes: %d\n", i,
sparse[i].sp_offset,
sparse[i].sp_numbytes));
} else {
sparse[i].sp_offset = pos -1;
sparse[i].sp_numbytes = 1;
info->f_rsize += 1;
EDEBUG(("i: %d offset: %d numbytes: %d\n", i,
sparse[i].sp_offset,
sparse[i].sp_numbytes));
}
lseek(*fp, 0L, SEEK_SET);
*spp = sparse;
return (++i);
}
EXPORT int
gnu_skip_extended(ptb)
TCB *ptb;
{
if (ptb->gnu_in_dbuf.t_isextended) do {
if (readblock((char *)ptb) == EOF)
return (EOF);
} while(ptb->gnu_ext_dbuf.t_isextended);
return (0);
}
EXPORT int
get_sparse(f, info)
FILE *f;
FINFO *info;
{
fh_t fh;
sp_t *sparse = get_sp_list(info);
int ret;
if (sparse == 0) {
errmsgno(EX_BAD, "Skipping '%s' sorry ...\n", info->f_name);
errmsgno(EX_BAD, "Warning '%s' is damaged\n", info->f_name);
void_file(info);
return (FALSE);
}
fh.fh_file = f;
fh.fh_name = info->f_name;
fh.fh_size = info->f_rsize;
fh.fh_newpos = 0L;
fh.fh_sparse = sparse;
fh.fh_spindex = 0;
ret = xt_file(info, vp_get_sparse_func, &fh, TBLOCK, "writing");
free(sparse);
return (ret);
}
EXPORT BOOL
cmp_sparse(f, info)
FILE *f;
FINFO *info;
{
fh_t fh;
sp_t *sparse = get_sp_list(info);
if (sparse == 0) {
errmsgno(EX_BAD, "Skipping '%s' sorry ...\n", info->f_name);
void_file(info);
fclose(f);
return (FALSE);
}
fh.fh_file = f;
fh.fh_name = info->f_name;
fh.fh_size = info->f_rsize;
fh.fh_newpos = 0L;
fh.fh_sparse = sparse;
fh.fh_spindex = 0;
fh.fh_diffs = 0;
if (xt_file(info, vp_cmp_sparse_func, &fh, TBLOCK, "reading") < 0)
die(EX_BAD);
if (fclose(f) != 0)
xstats.s_rwerrs++;
free(sparse);
return (fh.fh_diffs == 0);
}
EXPORT void
put_sparse(fp, info)
int *fp;
FINFO *info;
{
fh_t fh;
sp_t *sparse;
int nsparse;
long rsize;
nsparse = mk_sp_list(fp, info, &sparse);
if (nsparse == 0) {
info->f_rsize = info->f_size;
put_tcb(info->f_tcb, info);
vprint(info);
errmsgno(EX_BAD, "Dumping SPARSE '%s' as file\n", info->f_name);
put_file(fp, info);
return;
}
rsize = info->f_rsize;
EDEBUG(("rsize: %d\n", rsize));
put_sp_list(info, sparse, nsparse);
fh.fh_file = (FILE *)fp;
fh.fh_name = info->f_name;
fh.fh_size = info->f_rsize = rsize;
fh.fh_newpos = 0L;
fh.fh_sparse = sparse;
fh.fh_nsparse = nsparse;
fh.fh_spindex = 0;
cr_file(info, vp_put_sparse_func, &fh, TBLOCK, "reading");
free(sparse);
}
LOCAL void
put_sp_list(info, sparse, nsparse)
FINFO *info;
sp_t *sparse;
int nsparse;
{
register int i;
register int sparse_in_hdr = props.pr_sparse_in_hdr;
register char *p;
TCB tb;
TCB *ptb = info->f_tcb;
/*XXX*/extern int hdrtype;
EDEBUG(("1nsparse: %d rsize: %d\n", nsparse, info->f_rsize));
if (nsparse > sparse_in_hdr) {
if ((props.pr_flags & PR_GNU_SPARSE_BUG) == 0)
info->f_rsize +=
(((nsparse-sparse_in_hdr)+SPARSE_EXT_HDR-1)/
SPARSE_EXT_HDR)*TBLOCK;
}
EDEBUG(("2nsparse: %d rsize: %d added: %d\n", nsparse, info->f_rsize,
(((nsparse-sparse_in_hdr)+SPARSE_EXT_HDR-1)/
SPARSE_EXT_HDR)*TBLOCK));
EDEBUG(("addr sp: %d\n", &((TCB *)0)->xstar_in_dbuf.t_sp));
EDEBUG(("addr rs: %d\n", &((TCB *)0)->xstar_in_dbuf.t_realsize));
EDEBUG(("flags: 0x%X\n", info->f_flags));
info->f_xftype = XT_SPARSE;
if (info->f_flags & F_SPLIT_NAME && props.pr_nflags & PR_PREFIX_REUSED)
tcb_undo_split(ptb, info);
info_to_tcb(info, ptb);
if (H_TYPE(hdrtype) == H_GNUTAR)
p = (char *)ptb->gnu_in_dbuf.t_sp;
else
p = (char *)ptb->xstar_in_dbuf.t_sp;
for (i=0; i < sparse_in_hdr && i < nsparse; i++) {
otoa(p, sparse[i].sp_offset, 11); p += 12;
otoa(p, sparse[i].sp_numbytes, 11); p += 12;
}
if (sparse_in_hdr > 0 && nsparse > sparse_in_hdr) {
if (H_TYPE(hdrtype) == H_GNUTAR)
ptb->gnu_in_dbuf.t_isextended = 1;
else
ptb->xstar_in_dbuf.t_isextended = '1';
}
put_tcb(ptb, info);
vprint(info);
nsparse -= sparse_in_hdr;
sparse += sparse_in_hdr;
ptb = &tb;
while (nsparse > 0) {
fillbytes((char *)ptb, TBLOCK, '\0');
p = (char *)ptb;
for (i=0; i < SPARSE_EXT_HDR && i < nsparse; i++) {
otoa(p, sparse[i].sp_offset, 11); p += 12;
otoa(p, sparse[i].sp_numbytes, 11); p += 12;
}
nsparse -= SPARSE_EXT_HDR;
sparse += SPARSE_EXT_HDR;
if (nsparse > 0)
ptb->gnu_ext_dbuf.t_isextended = '1';
writeblock((char *)ptb);
}
}