www.pudn.com > cryptfs030905.rar > sca_aux.c


/*
 * Copyright (c) 1997-2003 Erez Zadok
 * Copyright (c) 2001-2003 Stony Brook University
 *
 * For specific licensing information, see the COPYING file distributed with
 * this package, or get one from ftp://ftp.filesystems.org/pub/fist/COPYING.
 *
 * This Copyright notice must be kept intact and distributed with all
 * fistgen sources INCLUDING sources generated by fistgen.
 */
/*
 *  $Id: sca_aux.c,v 1.8 2003/07/29 18:17:21 ezk Exp $
 */
#include "sca_aux.h"

int chunksize = DEFAULT_CHUNK_SZ;  /* Size of an encoded chunk */
int do_fast_tails = 0;		   /* Use fast tail algorithm */

int encode_counter = 0;		/* Usage counters */
int decode_counter = 0;
int write_counter = 0;


int
get_page(int gzfd, struct fistfs_header *hdr, int pageno,
	 unsigned char **out, int *outlen)
{
    unsigned char *data = NULL;	/* mmap gzfd */
    struct stat sb;
    unsigned char *ptr;
    int len, rc=0, back;

    if (pageno < 0)
	return(-1);
    if (pageno > hdr->num_pages)
	return(-1);
    if (!(do_fast_tails) && (pageno == hdr->num_pages))
	return(-1);

    if ((fstat(gzfd,&sb)) < 0)
	return(-1);
    if ((data = mmap((void *)data,sb.st_size,PROT_READ,
		     MAP_PRIVATE,gzfd,0)) == NULL) {
	return(-1);
    }

    if (pageno == 0) {
	ptr = data;
	if (hdr->num_pages == 0) {
	    len = sb.st_size;	/* Fast-tail append */
	    rc = 1;
	} else {
	    len = hdr->offsets[0];
	}
    } else {
	ptr = &(data[hdr->offsets[pageno-1]]);
	if (do_fast_tails && (pageno == hdr->num_pages)) { /* Possible fast tail */
	    len = sb.st_size - hdr->offsets[pageno - 1];
	    rc = 1;
	} else {
	    len = hdr->offsets[pageno] - hdr->offsets[pageno-1];
	}
    }

    if (rc) {			/* Fast tail, already done */
	(*out) = (unsigned char *) malloc (len * sizeof(unsigned char));
	if ((*out) == NULL) {
	    perror("malloc");
	    return(-1);
	}
	memcpy(*out, ptr, len);
	*outlen = len;
    } else {
	if ((rc = sca_decode_page(ptr, len, out, &back)) < 0) {
	    fprintf(stderr, "sca_decode_page returns %d\n", rc);
	    return(-1);
	}
	*outlen = rc;
    }
    munmap(data, sb.st_size);
    return(*outlen);
}


int
put_page(int gzfd, struct fistfs_header *hdr, int pageno,
	 unsigned char *data, int datalen)
{
    unsigned char *encdata = NULL;	/* The new data to write */
    unsigned char *tmppage = NULL;	/* Temp page for shifting */
    int rc, curlen, delta, cnt, enclen, tmp;
    struct stat sb;

    write_counter++;

    if (fstat(gzfd, &sb) < 0) {
	return(-1);
    }

    if ((datalen < chunksize) &&
	(pageno == hdr->num_pages) &&
	(do_fast_tails)) {
	/* A fast tail, just write it at the end */
	if (pageno > 0) {
	    cnt = hdr->offsets[hdr->num_pages-1];
	    hdr->real_size -= (sb.st_size - cnt);
	    hdr->real_size += datalen;
	}
	else {
	    hdr->real_size = datalen;
	    cnt = 0;
	}
	lseek(gzfd, cnt, SEEK_SET); /* The beginning is the end */
	rc = 0; tmp = 0;
	while (tmp < datalen) {
	    rc = write(gzfd, data, datalen);
	    if (rc < 0) {
		return(-1);
	    } else {
		tmp += rc;
	    }
	}
	ftruncate(gzfd, cnt+datalen);
	return(0);
    }

    if ((enclen = sca_encode_page(data, datalen, &encdata, &enclen)) < 0) {
	return(enclen);
    }

    if (pageno < hdr->num_pages) { /* Replace an existing page */
	if ((tmppage = (unsigned char *) malloc(sizeof(unsigned char) * chunksize))
	    == NULL) {
	    return(-1);
	}

	if (pageno == 0) {	/* replace first page */
	    curlen = hdr->offsets[0];
	} else {
	    curlen = hdr->offsets[pageno] - hdr->offsets[pageno-1];
	}
	delta = curlen - enclen; /* Positive, it got smaller, shift in from
				    here to end by delta bytes.  Negative,
				    it got bigger, shift out from end to
				    here by delta bytes */

	/* Update size  */
	hdr->real_size -= delta;

	/* Do shifting as appropriate */
	if (delta > 0) {
	    tmp = lseek(gzfd, hdr->offsets[pageno], SEEK_SET);
	    while (tmpoffsets[pageno];
	    while (tmp > 0) {
		if (tmp > chunksize) {
		    lseek(gzfd, hdr->offsets[pageno] + tmp - chunksize, SEEK_SET);
		    rc = read(gzfd, tmppage, chunksize);
		    lseek(gzfd,hdr->offsets[pageno] + tmp + - chunksize +(-delta),
			  SEEK_SET);
		    write(gzfd, tmppage, rc);
		} else {
		    lseek(gzfd, hdr->offsets[pageno], SEEK_SET);
		    rc = read(gzfd, tmppage, tmp);
		    lseek(gzfd, hdr->offsets[pageno] + (-delta), SEEK_SET);
		    write(gzfd, tmppage, tmp);
		}
		tmp -= chunksize;
	    }
	} /* Else it happens to fit exactly! no shifting necessary! */

	/* Update index table */
	for (tmp=pageno; tmpnum_pages; tmp++) {
	    hdr->offsets[tmp] -= delta;
	}

	lseek(gzfd, hdr->offsets[pageno-1], SEEK_SET); /* move to correct offset */
	free(tmppage);
    } else {			/* Add a new page somewhere later in the file */
	delta = pageno - hdr->num_pages;

	hdr->real_size += datalen;

	hdr->num_pages += (delta + 1);
	if ((hdr->offsets = realloc(hdr->offsets, (hdr->num_pages * sizeof(off_t))))
	    == NULL) {
	    return(-1);
	}

	for (; delta>0; delta--) {
	    /* Insert an empty page and an index entry for same */
	    fprintf(stderr, "Should insert an empty page here\n");
	    return(-1);		/* For now */
	}

	if (hdr->num_pages == 1) {
	    hdr->offsets[pageno] = enclen;
	    lseek(gzfd, 0, SEEK_SET);
	} else {
	    hdr->offsets[pageno] = enclen + hdr->offsets[pageno-1];
	    lseek(gzfd, hdr->offsets[pageno-1], SEEK_SET);
	}
    }

    cnt = 0;
    while (cnt < enclen) {
	rc = write(gzfd, encdata, enclen);
	if (rc > 0) {
	    cnt+=rc;
	} else {
	    /* Write error */
	    return(-1);
	}
    }

    free(encdata);		/* This was malloc'ed for us */
    return(0);
}


int
read_idx(char *filename, struct fistfs_header *hdr)
{
    int fd, i;

    if (filename == NULL)
	return(-1);
    if ((fd = open(filename, O_RDONLY)) < 0) {
	return(-1);
    }

    if ((read(fd, &(hdr->num_pages), sizeof(off_t))) < (sizeof(off_t))) {
	fprintf(stderr, "Short read from index file!\n");
	return(-1);
    }

    hdr->flags = hdr->num_pages & 0xfff00000;
    hdr->num_pages &= 0xfffff;

    if ((read(fd, &(hdr->real_size), sizeof(off_t))) < (sizeof(off_t))) {
	fprintf(stderr, "Short read from index file!\n");
	return(-1);
    }

    hdr->offsets = (off_t *) malloc(sizeof(off_t) * hdr->num_pages);
    if (hdr->offsets == NULL) {
	return(-1);
    }

    for (i = 0; i < hdr->num_pages; i++) {
	if ((read(fd, &(hdr->offsets[i]), sizeof(off_t))) != (sizeof(off_t))) {
	    fprintf(stderr, "Short read from index file!\n");
	    return(-1);
	}
    }
    close(fd);
    return(hdr->num_pages);
}


int
write_idx(char *filename, struct fistfs_header *hdr)
{
    int fd, i;

    if ((fd = open(filename, O_RDWR|O_CREAT|O_TRUNC, 0600)) < 0)
	return(-1);

    if (write(fd, &(hdr->num_pages), sizeof(int)) != (sizeof(int))) {
	fprintf(stderr, "Short write to index file!\n");
	return(-1);
    }

    if (write(fd, &(hdr->real_size), sizeof(int)) != (sizeof(int))) {
	fprintf(stderr, "Short write to index file!\n");
	return(-1);
    }

    for (i = 0; i < hdr->num_pages; i++) {
	if (write(fd, &(hdr->offsets[i]), sizeof(off_t)) != (sizeof(off_t))) {
	    fprintf(stderr, "Short write to index file!\n");
	    return(-1);
	}
    }

    close(fd);
    return(hdr->num_pages);
}

/*
 * Local variables:
 * c-basic-offset: 4
 * End:
 */