bbcobj.c 5.32 KB
#include "bbclocal.h"

int
__BBC_ObjectSize(BBCHandle h, const char *name)
{
    bbc_hand *hp;
    int rv;
    OSBbStatBuf sb;

    BBC_LOG(MSG_DIAG, "__BBC_ObjectSize %s\n", name);
    if ((rv = __BBC_CheckHandle(h)) != BBC_OK)
	return rv;

    hp = handles[h];

    if ((rv = __BBC_FStat(hp, name, &sb, NULL, 0)) < 0)
        return rv;

    return sb.size;
}

int
__BBC_GetObject(BBCHandle h, const char *name, void *buf, int len)
{
    bbc_hand *hp;
    int rv;
    int fd;
    OSBbStatBuf sb;

    BBC_LOG(MSG_DIAG, "__BBC_GetObject %s\n", name);
    if ((rv = __BBC_CheckHandle(h)) != BBC_OK)
	return rv;
    
    hp = handles[h];

    if ((fd = __BBC_FStat(hp, name, &sb, NULL, 0)) < 0)
        return fd;

    rv = __BBC_FRead(hp, fd, 0, buf, len);
    return rv;
}

#if BBC_DEBUG
#ifndef WIN32
#define BBC_TIME 1
#endif
#endif

int
__BBC_StoreObject(BBCHandle h, const char *name, const char *tmpname, const void *buf, int len)
{
    bbc_hand *hp;
    int rv;

    BBC_LOG(MSG_DIAG, "__BBC_StoreObject %s\n", name);
    if ((rv = __BBC_CheckHandle(h)) != BBC_OK)
	return rv;
    
    hp = handles[h];

    rv = __bbc_write_file(hp, name, tmpname, buf, len);
    return rv;
}

int __BBC_RemoveObject(BBCHandle h, const char *name)
{
    bbc_hand *hp;
    int rv;

    BBC_LOG(MSG_DIAG, "__BBC_RemoveObject %s\n", name);
    if ((rv = __BBC_CheckHandle(h)) != BBC_OK) {
	return rv;
    }
    hp = handles[h];

    rv = __BBC_FDelete(hp, name);
    return rv;
}

int __BBC_RenameObject(BBCHandle h, const char *old, const char *new)
{
    bbc_hand *hp;
    int rv;

    BBC_LOG(MSG_DIAG, "__BBC_RenameObject %s to %s\n", old, new);
    if ((rv = __BBC_CheckHandle(h)) != BBC_OK) {
	return rv;
    }
    hp = handles[h];

    rv = __BBC_FRename(hp, old, new);
    return rv;
}

int __BBC_ListObjects(BBCHandle h)
{
    bbc_hand *hp;
    OSBbDirEnt *dirbuf, *dir;
    int rv, count;

    BBC_LOG(MSG_DIAG, "__BBC_ListObjects\n");
    if ((rv = __BBC_CheckHandle(h)) != BBC_OK) {
        BBC_LOG_BBCERROR("__BBC_ListObjects: __BBC_CheckHandle failed", rv);
	return rv;
    }

    hp = handles[h];
    if ((dirbuf = malloc(MAX_DIR * sizeof(OSBbDirEnt))) == NULL) {
	BBC_LOG_SYSERROR("__BBC_ListObjects: malloc failed");
	return BBC_NOMEM;
    }

    count = __BBC_FReadDir(hp, dirbuf, MAX_DIR);
    if ((rv = count) < 0) {
        BBC_LOG_BBCERROR("__BBC_ListObjects: __BBC_FReadDir failed", rv);
        goto out;
    }

    BBC_LOG(MSG_INFO, "BBCard listing:\n");
    for (dir = dirbuf; count > 0; count--, dir++) {
        BBC_LOG(MSG_INFO, "%s  %u  %d\n", dir->name, dir->size, dir->type);
    }

out:
    return rv;
}

/* 
 * Writes a file by:
 * 1. Removing the temp file
 * 2. Creating and writing the content to the temp file
 * 3. Verifying the data was written correctly to the temp file
 * 4. Renaming the temp file the the desired file name
 * 5. Removing the temp file
 */
int __bbc_write_file(bbc_hand *hp, const char *name, const char *tmpname,
                     const void *buf, int len)
{
    int rv;
    int fd;
    const char *newfile;
#if BBC_TIME
    struct timeval tv1, tv2;
    float t;
#endif

    /* 
     * Check whether to use a tempname
     *
     * The content object case used to pass NULL here, but doesn't
     * anymore.
     */
    newfile = (tmpname != NULL) ? tmpname : name;

    /*
     * If file already exists, delete it
     */
    rv = __BBC_FDelete(hp, newfile);
    if (rv != BBC_OK && rv != BBC_NOFILE) {
        // Abort if file not removed successfully
	BBC_LOG(MSG_ERR, "__bbc_write_file delete %s fails %d\n", newfile, rv);
        return rv;
    }

#if BBC_TIME
    gettimeofday(&tv1, NULL);
#endif
    /*
     * Create the file and write the data
     */
    if ((fd = __BBC_FCreate(hp, newfile, 1, len)) < 0) {
	BBC_LOG(MSG_ERR, "__bbc_write_file create %s fails %d\n", newfile, fd);
	return fd;
    }
    if ((rv = __BBC_FWrite(hp, fd, 0, buf, len)) < len) {
	BBC_LOG(MSG_ERR, "__bbc_write_file write %s fails %d\n", newfile, rv);
	if (rv >= 0)    /* Didn't write as much as expected */
	    rv = BBC_ERROR;
	goto err;
    }

#if BBC_TIME
    gettimeofday(&tv2, NULL);
    t = (float)(tv2.tv_sec-tv1.tv_sec) + (tv2.tv_usec-tv1.tv_usec)/1000000.f;
    BBC_LOG(MSG_DEBUG, "Write %.1f KB %.1f sec %.1f KB/s\n", len/1024.f, t, len/1000.f/t);
#endif

    if ((rv = __BBC_VerifyFile(hp, newfile, buf, len)) != BBC_OK) {
	BBC_LOG(MSG_ERR, "__bbc_write_file verify %s fails %d\n", newfile, rv);
	goto err;
    }

#if BBC_TIME
    gettimeofday(&tv1, NULL);
    t = (float)(tv1.tv_sec-tv2.tv_sec) + (tv1.tv_usec-tv2.tv_usec)/1000000.f;
    BBC_LOG(MSG_DEBUG, "Verify %.1f KB %.1f sec %.1f KB/s\n", len/1024.f, t, len/1000.f/t);
#endif

    /*
     * Everything is successful up to this point, do atomic rename of the temp file to
     * its proper name.  Rename will delete the target if it exists.
     */
    if (tmpname != NULL) {
        if ((rv = __BBC_FRename(hp, newfile, name)) != BBC_OK) {
	    BBC_LOG(MSG_ERR, "__bbc_write_file rename %s to %s fails %d\n", newfile, name, rv);
	    goto err;
        }
    }
    return rv;

err:
    if (tmpname != NULL) {
        if (!BBC_IO_ERR(rv) && !BBC_CARD_ERR(rv)) {
            // Only try to delete tempfile if we didn't get an IO or card error
            int res = __BBC_FDelete(hp, tmpname);
            if (res != BBC_OK)
                BBC_LOG(MSG_ERR, "__bbc_write_file delete %s fails %d\n", TEMPFILE, rv);
        }
    }
    return rv;
}