head     1.1;
branch   ;
access   ;
symbols  ;
locks    kemnitz:1.1; strict;
comment  @ * @;


1.1
date     91.09.25.15.26.22;  author kemnitz;  state Exp;
branches ;
next     ;


desc
@large object API and definer functions.
@



1.1
log
@Initial revision
@
text
@/*
 * large_object.c - routines for manipulating and accessing large objects
 *
 * $Header: RCS/large_object.c,v 1.3 91/09/04 13:48:32 kemnitz Exp $
 */

#include <sys/file.h>
#include "tmp/c.h"
#include "utils/large_object.h"

/*
 * These routines allow the user to import and export Postgres PURE_FILE
 * large objects.
 */


long lo_storage_type = PURE_FILE;

char *
lo_filein(filename)

char *filename;

{
    LargeObject *retval;
    long obj_len, filename_len = strlen(filename) + 1;

    obj_len = filename_len
			+ sizeof(LargeObject) - sizeof(LargeObjectDataPtr)
			+ sizeof(long);

    retval = (LargeObject *) palloc(obj_len);

    retval->lo_length = obj_len;

    retval->lo_storage_type = PURE_FILE;

    /*
     * NOTE: if this is a pure file, these numbers cannot be trusted.
     * They should only be used for a postgres file or relation.
     */

    retval->lo_nblocks = retval->lo_lastoff = retval->lo_version = 0;

    strcpy(retval->lo_ptr.filename, filename);

    return((char *) retval);
}

char *
lo_fileout(object)

LargeObject *object;

{
    char *retval; 

    Assert(PointerIsValid(object));

    retval = (char *) palloc(strlen(object->lo_ptr.filename) + 1);

    strcpy(retval, object->lo_ptr.filename);
    return(retval);
}

/*
 * These next routines are the "internal" large object interface for use by
 * user-defined functions.
 */

/*
 * Eventually, LargeObjectCreate should log all filenames in some type of
 * log - this approach will have problems if an object is destroyed.
 */

LargeObjectDesc *
LOCreate(open_mode)

int open_mode;

{
    char filename[256];
    int file_oid;
    LargeObjectDesc *retval;
    LargeObject *newobj;
    int fd;

    file_oid = newoid();
    sprintf(filename, "LO%d", file_oid);

    fd = (int) FileNameOpenFile(filename, O_CREAT | O_RDWR, 0666);
    if (fd == -1) return(NULL);

	newobj = (LargeObject *) lo_filein(filename);

    retval->object = newobj;
    retval->fd = fd;

    return(retval);
}

LargeObjectDesc *
LOOpen(object, open_mode)

LargeObject *object;
int open_mode;

{
    LargeObjectDesc *retval;
    int fd;

    Assert(PointerIsValid(object));
    Assert(object->lo_storage_type == PURE_FILE);

    fd = FileNameOpenFile(object->lo_ptr.filename, open_mode, 0666);

    if (fd == -1) return(NULL);

    retval = (LargeObjectDesc *) palloc(sizeof(LargeObjectDesc));

    retval->fd = fd;
    retval->object = object;
    return(retval);
}

/*
 * Returns the number of blocks and the byte offset of the last block of
 * the file.  nblocks * LARGE_OBJECT_BLOCK + byte_offset should be equal to
 * the file size.
 */

void
LOStat(obj_desc, nblocks, byte_offset)

LargeObjectDesc *obj_desc;
unsigned int *nblocks, *byte_offset;

{
    unsigned long nbytes;
    unsigned long pos, len;

    Assert(PointerIsValid(obj_desc));
    Assert(PointerIsValid(obj_desc->object));
    Assert(obj_desc->object->lo_storage_type == PURE_FILE);

    /* see where we are now */

    pos = FileTell(obj_desc->fd);

    /* do a seek to find number of bytes */

    len = FileSeek(obj_desc->fd, 0L, L_XTND);

    /* seek back to original position */

    FileSeek(obj_desc->fd, pos, L_SET);

    *nblocks = (len < 0) ? 0 : len / LARGE_OBJECT_BLOCK;
    *byte_offset = len % LARGE_OBJECT_BLOCK;
}

/*
 * Returns the number of bytes read in the last block - zero on failed read.
 */

int
LOBlockRead(obj_desc, buf, nblocks)

LargeObjectDesc *obj_desc;
char *buf;
unsigned long nblocks;

{
    unsigned long nbytes, bytes_read;

    Assert(PointerIsValid(obj_desc));
    Assert(PointerIsValid(obj_desc->object));
    Assert(obj_desc->object->lo_storage_type == PURE_FILE);

    nbytes = LARGE_OBJECT_BLOCK * nblocks;
    bytes_read = FileRead(obj_desc->fd, buf, nbytes);

    if (bytes_read == 0) return(0);

    if (bytes_read % LARGE_OBJECT_BLOCK != 0)
        return(bytes_read % LARGE_OBJECT_BLOCK);
    else
        return(LARGE_OBJECT_BLOCK);
}

/*
 * here, bytes_at_end allows an incomplete block to be written.
 * This should ONLY be used to end a file, since we only allow block-oriented
 * seeking.  IF bytes_in
 */

int
LOBlockWrite(obj_desc, buf, n_whole_blocks, bytes_at_end)

LargeObjectDesc *obj_desc;
char *buf;
unsigned long n_whole_blocks, bytes_at_end;

{
    unsigned long totalbytes;

    Assert(PointerIsValid(obj_desc));
    Assert(PointerIsValid(obj_desc->object));
    Assert(obj_desc->object->lo_storage_type == PURE_FILE);

    totalbytes = LARGE_OBJECT_BLOCK * n_whole_blocks + bytes_at_end;

    return(FileWrite(obj_desc->fd, buf, totalbytes));
}

/*
 * Just like seek, although "offset" is the block offset, and the return
 * value is a block number.
 */

unsigned long
LOBlockSeek(obj_desc, offset, whence)

LargeObjectDesc *obj_desc;
unsigned long offset;
int whence;

{
    unsigned long retval;

    Assert(PointerIsValid(obj_desc));
    Assert(PointerIsValid(obj_desc->object));
    Assert(obj_desc->object->lo_storage_type == PURE_FILE);

    retval = FileSeek(obj_desc->fd, offset * LARGE_OBJECT_BLOCK, whence);

    return(retval * LARGE_OBJECT_BLOCK);
}

/*
 * Closes an existing large object descriptor.
 */

void
LOClose(obj_desc)

LargeObjectDesc *obj_desc;

{
    Assert(PointerIsValid(obj_desc));
    Assert(PointerIsValid(obj_desc->object));
    Assert(obj_desc->object->lo_storage_type == PURE_FILE);

    FileClose(obj_desc->fd);
    pfree(obj_desc);
}

/*
 * Destroys an existing large object, and frees its associated pointers.
 * Currently deletes the large object file.
 */

void
LODestroy(object)

LargeObject *object;

{
    Assert(PointerIsValid(object));
    Assert(object->lo_storage_type == PURE_FILE);

    FileNameUnlink(object->lo_ptr.filename);
    pfree(object);
}

/*
 * To be called at the end of the use of a large object, just before the
 * large object is closed.
 */

LargeObject *
LODescToObject(obj_desc)

LargeObjectDesc *obj_desc;

{
    LargeObject *retval;

    Assert(PointerIsValid(obj_desc));
    Assert(PointerIsValid(obj_desc->object));
    Assert(obj_desc->object->lo_storage_type == PURE_FILE);

    retval = obj_desc->object;
    return(retval);
}
@
