From: Sebastian Hammer Date: Tue, 23 Aug 1994 14:41:32 +0000 (+0000) Subject: First functional version. X-Git-Tag: ZEBRA.1.0~894 X-Git-Url: http://git.indexdata.com/?p=idzebra-moved-to-github.git;a=commitdiff_plain;h=f69ee5ec6b2a86b7ac049992c19b9b0410705404 First functional version. --- diff --git a/bfile/Makefile b/bfile/Makefile index 1857ad5..235392d 100644 --- a/bfile/Makefile +++ b/bfile/Makefile @@ -4,7 +4,7 @@ TPROG=btest CFLAGS=-g -Wall DEFS=$(INCLUDE) LIB=../lib/bfile.a -PO = bfile.o +PO = bfile.o mfile.o CPP=cc -E all: $(LIB) diff --git a/bfile/mfile.c b/bfile/mfile.c new file mode 100644 index 0000000..2633f05 --- /dev/null +++ b/bfile/mfile.c @@ -0,0 +1,364 @@ +/* + * Copyright (C) 1994, Index Data I/S + * All rights reserved. + * Sebastian Hammer, Adam Dickmeiss + * + * $Log: mfile.c,v $ + * Revision 1.1 1994-08-23 14:41:33 quinn + * First functional version. + * + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +static MFile_area_struct *open_areas = 0; +static MFile_area_struct *default_area = 0; + +static int scan_areadef(MFile_area ma, const char *name) +{ + const char *ad = res_get(common_resource, name); + int offset = 0, rs, size, multi, rd; + char dirname[FILENAME_MAX+1], unit; + mf_dir **dp = &ma->dirs, *dir = *dp; + + if (!ad) + { + log(LOG_FATAL, "Could not find resource '%s'", name); + return -1; + } + for (;;) + { + rs = sscanf(ad + offset, "%[^:]:%d%c %n", dirname, &size, &unit, &rd); + if (rs <= 1) + break; + if (rs != 3) + { + log(LOG_FATAL, "Illegal directory description: %s", ad + offset); + return -1; + } + switch (unit) + { + case 'B': case 'b': multi = 1; break; + case 'K': case 'k': multi = 1024; break; + case 'M': case 'm': multi = 1048576; break; + default: + log(LOG_FATAL, "Illegal unit: %c in %s", unit, ad + offset); + return -1; + } + *dp = dir = xmalloc(sizeof(mf_dir)); + dir->next = 0; + strcpy(dir->name, dirname); + dir->max_bytes = dir->avail_bytes = size * multi; + dp = &dir->next; + offset += rd; + } + return 0; +} + +static int file_position(MFile mf, int pos) +{ + int off = 0, c = mf->cur_file, ps; + + if ((c > 0 && pos <= mf->files[c-1].top) || + (c < mf->no_files -1 && pos > mf->files[c].top)) + { + c = 0; + while (mf->files[c].top >= 0 && mf->files[c].top < pos) + { + off += mf->files[c].blocks; + c++; + } + assert(c < mf->no_files); + } + else + off = c ? (mf->files[c-1].top + 1) : 0; + if (mf->files[c].fd < 0 && (mf->files[c].fd = open(mf->files[c].path, + mf->wr ? O_RDWR|O_CREAT : O_RDONLY, 0666)) < 0) + { + log(LOG_FATAL|LOG_ERRNO, "Failed to open %s", mf->files[c].path); + return -1; + } + if (lseek(mf->files[c].fd, (ps = pos - off) * mf->blocksize, SEEK_SET) < 0) + { + log(LOG_FATAL|LOG_ERRNO, "Failed to seek in %s", mf->files[c].path); + return -1; + } + mf->cur_file = c; + return ps; +} + +static int cmp_part_file(const void *p1, const void *p2) +{ + return ((part_file *)p1)->number - ((part_file *)p2)->number; +} + +/* + * Create a new area, cotaining metafiles in directories. + * Find the part-files in each directory, and inventory the existing metafiles. + */ +MFile_area mf_init(const char *name) +{ + MFile_area ma = xmalloc(sizeof(MFile_area_struct)), mp; + mf_dir *dirp; + meta_file *meta_f; + part_file *part_f; + DIR *dd; + struct dirent *dent; + int fd, number; + char metaname[FILENAME_MAX+1], tmpnam[FILENAME_MAX+1]; + + for (mp = open_areas; mp; mp = mp->next) + if (!strcmp(name, mp->name)) + abort(); + strcpy(ma->name, name); + ma->next = open_areas; + open_areas = ma; + ma->mfiles = 0; + ma->dirs = 0; + if (scan_areadef(ma, name) < 0) + { + log(LOG_FATAL, "Failed to access description of '%s'", name); + return 0; + } + /* look at each directory */ + for (dirp = ma->dirs; dirp; dirp = dirp->next) + { + if (!(dd = opendir(dirp->name))) + { + log(LOG_FATAL|LOG_ERRNO, "Failed to open %s", dirp->name); + return 0; + } + /* look at each file */ + while ((dent = readdir(dd))) + { + if (*dent->d_name == '.') + continue; + if (sscanf(dent->d_name, "%[^.].%d", metaname, &number) != 2) + { + log(LOG_FATAL, "Failed to resolve part-name %s", dent->d_name); + return 0; + } + for (meta_f = ma->mfiles; meta_f; meta_f = meta_f->next) + { + /* known metafile */ + if (!strcmp(meta_f->name, metaname)) + { + part_f = &meta_f->files[meta_f->no_files++]; + break; + } + } + /* new metafile */ + if (!meta_f) + { + meta_f = xmalloc(sizeof(*meta_f)); + meta_f->ma = ma; + meta_f->next = ma->mfiles; + meta_f->open = 0; + meta_f->cur_file = -1; + ma->mfiles = meta_f; + strcpy(meta_f->name, metaname); + part_f = &meta_f->files[0]; + meta_f->no_files = 1; + } + part_f->number = number; + part_f->dir = dirp; + part_f->fd = -1; + sprintf(tmpnam, "%s/%s", dirp->name, dent->d_name); + part_f->path = xstrdup(tmpnam); + /* get size */ + if ((fd = open(part_f->path, O_RDONLY)) < 0) + { + log(LOG_FATAL|LOG_ERRNO, "Failed to access %s", dent->d_name); + return 0; + } + if ((part_f->bytes = lseek(fd, 0, SEEK_END)) < 0) + { + log(LOG_FATAL|LOG_ERRNO, "Failed to seek in %s", dent->d_name); + return 0; + } + close(fd); + dirp->avail_bytes -= part_f->bytes; + } + closedir(dd); + } + for (meta_f = ma->mfiles; meta_f; meta_f = meta_f->next) + { + log(LOG_DEBUG, "mf_init: %s consists of %d part(s)", meta_f->name, + meta_f->no_files); + qsort(meta_f->files, meta_f->no_files, sizeof(part_file), + cmp_part_file); + } + return ma; +} + +/* + * Open a metafile. + * If !ma, Use MF_DEFAULT_AREA. + */ +MFile mf_open(MFile_area ma, const char *name, int block_size, int wflag) +{ + struct meta_file *new; + int i; + char tmp[FILENAME_MAX+1]; + mf_dir *dp; + + if (!ma) + { + if (!default_area && !(default_area = mf_init(MF_DEFAULT_AREA))) + { + log(LOG_FATAL, "Failed to open default area."); + return 0; + } + ma = default_area; + } + for (new = ma->mfiles; new; new = new->next) + if (!strcmp(name, new->name)) + if (new->open) + abort(); + else + break; + if (!new) + { + new = xmalloc(sizeof(*new)); + strcpy(new->name, name); + /* allocate one, empty file */ + new->no_files = 1; + new->files[0].bytes = new->files[0].blocks = 0; + new->files[0].top = -1; + new->files[0].number = 0; + new->files[0].fd = -1; + new->min_bytes_creat = MF_MIN_BLOCKS_CREAT * block_size; + for (dp = ma->dirs; dp && dp->avail_bytes < new->min_bytes_creat; + dp = dp->next); + if (!dp) + { + log(LOG_FATAL, "Insufficient space for new mfile."); + return 0; + } + new->files[0].dir = dp; + sprintf(tmp, "%s/%s.%d", dp->name, new->name, 0); + new->files[0].path = xstrdup(tmp); + new->ma = ma; + } + new->blocksize = block_size; + new->min_bytes_creat = MF_MIN_BLOCKS_CREAT * block_size; + new->wr=wflag; + new->cur_file = 0; + + for (i = 0; i < new->no_files; i++) + { + new->files[i].blocks = new->files[i].bytes / new->blocksize; + if (i == new->no_files) + new->files[i].top = -1; + else + new->files[i].top = i ? (new->files[i-1].top + new->files[i].blocks) + : (new->files[i].blocks - 1); + } + return new; +} + +/* + * Close a metafile. + */ +int mf_close(MFile mf) +{ + abort(); + return 0; +} + +/* + * Read one block from a metafile. Interface mirrors bfile. + */ +int mf_read(MFile mf, int no, int offset, int num, void *buf) +{ + if (file_position(mf, no) < 0) + exit(1); + if (read(mf->files[mf->cur_file].fd, buf, mf->blocksize) < mf->blocksize) + { + log(LOG_FATAL|LOG_ERRNO, "Read failed"); + exit(1); + } + return 0; +} + +/* + * Write. + */ +int mf_write(MFile mf, int no, int offset, int num, const void *buf) +{ + int ps; + mf_dir *dp; + char tmp[FILENAME_MAX+1]; + + if ((ps = file_position(mf, no)) < 0) + exit(1); + assert(ps <= mf->files[mf->cur_file].blocks); + /* extend table */ + if (ps == mf->files[mf->cur_file].blocks) + { + assert(mf->cur_file == mf->no_files - 1); + /* create new file */ + if (mf->files[mf->cur_file].dir->avail_bytes < + mf->blocksize) + { + log(LOG_DEBUG, "Creating new file."); + for (dp = mf->ma->dirs; dp && dp->avail_bytes < mf->min_bytes_creat; + dp = dp->next); + if (!dp) + { + log(LOG_FATAL, "Cannot allocate more space for %s", mf->name); + exit(1); + } + mf->files[mf->cur_file].top = no - 1; + mf->files[++(mf->cur_file)].top = -1; + mf->files[mf->cur_file].dir = dp; + mf->files[mf->cur_file].number = + mf->files[mf->cur_file-1].number + 1; + mf->files[mf->cur_file].blocks = + mf->files[mf->cur_file].bytes = 0; + mf->files[mf->cur_file].fd = -1; + sprintf(tmp, "%s/%s.%d", dp->name, mf->name, + mf->files[mf->cur_file].number); + mf->files[mf->cur_file].path = xstrdup(tmp); + mf->no_files++; + /* open new file and position at beginning */ + if (file_position(mf, no) < 0) + exit(1); + } + mf->files[mf->cur_file].blocks++; + mf->files[mf->cur_file].bytes += mf->blocksize; + mf->files[mf->cur_file].dir->avail_bytes -= mf->blocksize; + } + if (write(mf->files[mf->cur_file].fd, buf, mf->blocksize) < mf->blocksize) + { + log(LOG_FATAL|LOG_ERRNO, "Write failed"); + exit(1); + } + return 0; +} + +/* + * Destroy a metafile, unlinking component files. File must be open. + */ +int mf_unlink(MFile mf) +{ + abort(); + return 0; +} + +/* + * Unlink the file by name, rather than MFile-handle. File should be closed. + */ +int mf_unlink_name(MFile_area ma, const char *name) +{ + abort(); + return 0; +}