summaryrefslogblamecommitdiffstats
path: root/common/sys/record.c
blob: e1b74402cab400c88ac9ddd4428729c41f1e0ba6 (plain) (tree)

































































































































































































                                                                                               
/* $Id$ */

#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <assert.h>
#include "cmsys.h"

#define BUFSIZE 512

/* Functions for fixed size record operations */

int
get_num_records(const char *fpath, size_t size)
{
    struct stat st;

    if (stat(fpath, &st) == -1)
    return 0;

    return st.st_size / size;
}

int
get_records_keep(const char *fpath, void *rptr, size_t size, int id, size_t number, int *fd)
{
    assert(fpath);
    assert(fd);

    if (id < 1)
    return -1;

    if (*fd < 0 && (*fd = open(fpath, O_RDONLY, 0)) == -1)
    return -1;

    if (lseek(*fd, (off_t) (size * (id - 1)), SEEK_SET) == -1)
    return 0;

    if ((id = read(*fd, rptr, size * number)) == -1)
    return -1;

    return id / size;
}

int
get_records(const char *fpath, void *rptr, size_t size, int id, size_t number)
{
    int res, fd = -1;

    res = get_records_keep(fpath, rptr, size, id, number, &fd);
    close(fd);

    return res;
}

#ifndef get_record
int
get_record(const char *fpath, void *rptr, size_t size, int id)
{
    return get_records(fpath, rptr, size, id, 1);
}
#endif

#ifndef get_record_keep
int
get_record_keep(const char *fpath, void *rptr, size_t size, int id, int *fd)
{
    return get_records_keep(fpath, rptr, size, id, 1, fd);
}
#endif

int
substitute_record(const char *fpath, const void *rptr, size_t size, int id)
{
    int fd;
    off_t offset = size * (id - 1);

    if (id < 1 || (fd = open(fpath, O_WRONLY | O_CREAT, 0644)) == -1)
    return -1;

    lseek(fd, offset, SEEK_SET);
    PttLock(fd, offset, size, F_WRLCK);
    write(fd, rptr, size);
    PttLock(fd, offset, size, F_UNLCK);
    close(fd);

    return 0;
}

int
append_record(const char *fpath, const void *record, size_t size)
{
    int fd, index = -2, fsize = 0;

    if ((fd = open(fpath, O_WRONLY | O_CREAT, 0644)) == -1)
    return -1;

    flock(fd, LOCK_EX);

    if ((fsize = lseek(fd, 0, SEEK_END)) < 0)
    goto out;

    index = fsize / size;
    lseek(fd, index * size, SEEK_SET);  // avoid offset

    write(fd, record, size);

out:
    flock(fd, LOCK_UN);
    close(fd);

    return index + 1;
}

int
delete_records(const char *fpath, size_t size, int id, size_t num)
{
    char buf[BUFSIZE];
    int fi, fo, locksize, readsize, c, d=0;
    struct stat st;
    off_t offset = size * (id - 1);

    if ((fi=open(fpath, O_RDONLY, 0)) == -1)
    return -1;

    if ((fo=open(fpath, O_WRONLY, 0)) == -1) {
    close(fi);
    return -1;
    }

    if (fstat(fi, &st)==-1) {
    close(fo);
    close(fi);
    return -1;
    }

    locksize = st.st_size - offset;
    readsize = locksize - size*num;

    if (locksize < 0 ) {
    close(fo);
    close(fi);
    return -1;
    }

    PttLock(fo, offset, locksize, F_WRLCK);

    if (readsize > 0) {
    lseek(fi, offset+size, SEEK_SET);  
    lseek(fo, offset, SEEK_SET);  
    while (d < readsize && (c = read(fi, buf, BUFSIZE)) > 0) {
        write(fo, buf, c);
        d += c;
    }
    }
    close(fi);

    ftruncate(fo, st.st_size - size*num);

    PttLock(fo, offset, locksize, F_UNLCK);

    close(fo);

    return 0;
}

#ifndef delete_record
int delete_record(const char *fpath, size_t size, int id)
{
    return delete_records(fpath, size, id, 1);
}
#endif

int
apply_record(const char *fpath, int (*fptr) (void *item, void *optarg), size_t size, void *arg)
{
    char buf[BUFSIZE];
    int fd;

    assert(size <= sizeof(buf));

    if ((fd = open(fpath, O_RDONLY, 0)) == -1)
    return -1;

    while (read(fd, buf, size) == size)
    if ((*fptr) (buf, arg) == 1) {
        close(fd);
        return 1;
    }

    close(fd);

    return 0;
}