467 lines
13 KiB
C
467 lines
13 KiB
C
|
#include "recordio.h"
|
||
|
|
||
|
unsigned char readbyte(int fp);
|
||
|
|
||
|
char pbuf[512]; // print buffer
|
||
|
int eof = 1; // flag for end of file
|
||
|
|
||
|
//-----------------------------------------------------------
|
||
|
// FUNCTION rio_open:
|
||
|
// If create is requested, open both the data file and the index file with O CREAT.
|
||
|
// If O RDONLY or O RDWR is requested, make sure that the index file is present and return an error otherwise.
|
||
|
// PARAMETER USAGE :
|
||
|
// const char* pathname : the path of the file to open
|
||
|
// int flags : the type of open
|
||
|
// mode_t mode : file permissions
|
||
|
// FUNCTION CALLED :
|
||
|
// int16_t encodefd(int d1, int d2)
|
||
|
// printb(unsigned n) : for debugging
|
||
|
//-----------------------------------------------------------
|
||
|
int rio_open(const char *pathname, int flags, mode_t mode)
|
||
|
{
|
||
|
ret:;
|
||
|
int d, d1o, d2o; // output file descriptor
|
||
|
char *name_extention = ".rinx."; // all index files must start with this
|
||
|
char *index_filename = malloc(sizeof(char) * (strlen(name_extention) + strlen(pathname))); // allocate space for the index filename
|
||
|
unsigned char byte; // storage as to read in byte by byte
|
||
|
int record_position = 0;
|
||
|
int n, buff; // counters
|
||
|
record_descriptor rd; // record descriptor
|
||
|
buff = 0; // set the initial buffer size
|
||
|
int d1, d2;
|
||
|
|
||
|
strcat(index_filename, name_extention); // construct the index filename
|
||
|
strcat(index_filename, pathname);
|
||
|
|
||
|
int index_tester = open(index_filename, O_RDONLY);
|
||
|
if (index_tester > 0)
|
||
|
{
|
||
|
close(index_tester);
|
||
|
}
|
||
|
|
||
|
int datafile_tester = open(pathname, O_RDONLY);
|
||
|
if (datafile_tester > 0)
|
||
|
{
|
||
|
close(datafile_tester);
|
||
|
}
|
||
|
else
|
||
|
{ // the file doesnt exist
|
||
|
close(datafile_tester);
|
||
|
d1 = open(pathname, flags, mode); // open the data file
|
||
|
if (d1 < 0)
|
||
|
{ // error check
|
||
|
fprintf(stderr, "cannot open %s because of %s\n", pathname, strerror(5));
|
||
|
return -1;
|
||
|
}
|
||
|
d2 = open(index_filename, O_RDWR | O_CREAT | O_EXCL, 0777);
|
||
|
if (d2 < 0)
|
||
|
{ // error check
|
||
|
fprintf(stderr, "cannot open %s because of %s\n", pathname, strerror(5));
|
||
|
return -1;
|
||
|
}
|
||
|
d = encodefd(d1, d2); // encrypt file descriptor
|
||
|
return d;
|
||
|
}
|
||
|
|
||
|
d1 = open(pathname, flags, mode); // open the data file
|
||
|
if (d1 < 0)
|
||
|
{ // error check
|
||
|
fprintf(stderr, "cannot open %s because of %s\n", pathname, strerror(5));
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
if (index_tester < 0)
|
||
|
{ // check if index file doesnt exist
|
||
|
d2 = open(index_filename, O_RDWR | O_CREAT | O_EXCL, 0777);
|
||
|
if (d2 < 0)
|
||
|
{ // error check
|
||
|
fprintf(stderr, "cannot open %s because of %s\n", pathname, strerror(5));
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
while (eof)
|
||
|
{ // read until end of file
|
||
|
byte = readbyte(d1); // read in 1 byte
|
||
|
if (eof == 0)
|
||
|
{ // check to see if you are at the end of file
|
||
|
|
||
|
if (buff > 0)
|
||
|
{ // if the buffer is nonzero then we have a file which doesnt end in an endl
|
||
|
rd.position = record_position - buff; // record position
|
||
|
rd.length = buff; // record length
|
||
|
|
||
|
n = write(d2, &rd, sizeof(record_descriptor)); // write the record descriptor
|
||
|
if (n < 0)
|
||
|
{
|
||
|
fprintf(stderr, "create index eof: %s\n", strerror(EIO));
|
||
|
return -1;
|
||
|
}; // error checking
|
||
|
}
|
||
|
|
||
|
eof = 1;
|
||
|
break; // we are at the end of file
|
||
|
}
|
||
|
|
||
|
record_position += sizeof(byte); // increase bytecount
|
||
|
buff += sizeof(byte); // increase bytecount
|
||
|
|
||
|
if (byte == '\n')
|
||
|
{ // check if the byte is an endline
|
||
|
rd.position = record_position - buff; // record position
|
||
|
rd.length = buff; // record length
|
||
|
|
||
|
n = write(d2, &rd, sizeof(record_descriptor)); // write the record descriptor
|
||
|
if (n < 0)
|
||
|
{
|
||
|
fprintf(stderr, "create index norm: %s\n", strerror(EIO));
|
||
|
return -1;
|
||
|
}; // error checking
|
||
|
buff = 0; // reset the buffer
|
||
|
}
|
||
|
}
|
||
|
close(d1);
|
||
|
close(d2);
|
||
|
goto ret; // This goes back to the top of the function if the file doesn't exist so that the file is created and opened correctly
|
||
|
}
|
||
|
else
|
||
|
{ // file exists
|
||
|
d2 = open(index_filename, O_RDWR, 0777);
|
||
|
if (d2 < 0)
|
||
|
{ // error check
|
||
|
fprintf(stderr, "cannot open %s because of %s\n", pathname, strerror(5));
|
||
|
return -1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
d = encodefd(d1, d2); // encrypt file descriptor
|
||
|
|
||
|
/* ENCODEING/DECODEING CORRECTNESS TEST */
|
||
|
#ifdef DEBUG
|
||
|
printf("d1_in = ");
|
||
|
printb(d1);
|
||
|
printf("d2_in = ");
|
||
|
printb(d2);
|
||
|
printf("d = ");
|
||
|
printb(d);
|
||
|
printf("d1_out = ");
|
||
|
d1o = decodedfd(d);
|
||
|
printb(d1o);
|
||
|
printf("d2_out = ");
|
||
|
d2o = decodeifd(d);
|
||
|
printb(d2o);
|
||
|
#endif
|
||
|
return d;
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------
|
||
|
// FUNCTION rio_read:
|
||
|
// Allocate a buffer large enough to hold the requested buffer,
|
||
|
// read the next record and return the pointer to the allocated area.
|
||
|
// The I/O result should be returned through the return value argument.
|
||
|
// PARAMETER USAGE :
|
||
|
// int fd : the file descriptor
|
||
|
// int * return_value : the record in the index file to read
|
||
|
// FUNCTION CALLED :
|
||
|
// int8_t decodeifd(int16_t d)
|
||
|
// int8_t decodedfd(int16_t d)
|
||
|
//-----------------------------------------------------------
|
||
|
void *rio_read(int fd, int *return_value)
|
||
|
{
|
||
|
|
||
|
void *buffer; // the buffer to be returned
|
||
|
int index_fd, data_fd; // file descriptors
|
||
|
int r; // read error checker
|
||
|
record_descriptor rd; // record descriptor
|
||
|
|
||
|
index_fd = decodeifd(fd); // decrypt index file descriptor
|
||
|
data_fd = decodedfd(fd); // decrypt data file descriptor
|
||
|
|
||
|
r = read(index_fd, &rd, sizeof(rd)); // read in the record
|
||
|
if (r < 0)
|
||
|
{
|
||
|
fprintf(stderr, "rio_read (index): %s\n", strerror(EIO));
|
||
|
return NULL;
|
||
|
}; // error check
|
||
|
|
||
|
int position = rd.position; // the position of the data in the datafile
|
||
|
int length = rd.length; // the size of the data block
|
||
|
|
||
|
buffer = (void *)malloc(length); // allocate buffer memory
|
||
|
|
||
|
int r1 = read(data_fd, buffer, length); // read in the data to the buffer
|
||
|
if (r1 < 0)
|
||
|
{
|
||
|
fprintf(stderr, "rio_read (data)%s\n", strerror(EIO));
|
||
|
return NULL;
|
||
|
}; // error check
|
||
|
|
||
|
*return_value = r1; // The I/O result should be returned through the return value argument.
|
||
|
|
||
|
return buffer; // return the pointer to the allocated area.
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------
|
||
|
// FUNCTION rio_write:
|
||
|
// If appending to the file, create a record descriptor and fill-in the values.
|
||
|
// Write the descriptor to the index file and the supplied data to the data file for the requested length.
|
||
|
// If updating a record, read the record descriptor, check to see if the new record fits in the allocated area and rewrite.
|
||
|
// Return an error otherwise.
|
||
|
// PARAMETER USAGE :
|
||
|
// int fd : the file descriptor
|
||
|
// const void *buf : the buffer to be written
|
||
|
// int count : requested length
|
||
|
// FUNCTION CALLED :
|
||
|
// int8_t decodeifd(int16_t d)
|
||
|
// int8_t decodedfd(int16_t d)
|
||
|
//-----------------------------------------------------------
|
||
|
int rio_write(int fd, const void *buf, int count)
|
||
|
{
|
||
|
int index_fd, data_fd; // file descriptors
|
||
|
int r, w, data_w; // read error checker
|
||
|
record_descriptor rd; // record descriptor
|
||
|
|
||
|
index_fd = decodeifd(fd); // decrypt index file descriptor
|
||
|
data_fd = decodedfd(fd); // decrypt data file descriptor
|
||
|
|
||
|
r = read(index_fd, &rd, sizeof(rd)); // read in the record
|
||
|
if (r < 0)
|
||
|
{
|
||
|
fprintf(stderr, "rio_write (read index [to check if record_descriptor exists]): %s\n", strerror(EIO));
|
||
|
return -1;
|
||
|
}; // error check
|
||
|
|
||
|
if (r > 0)
|
||
|
{
|
||
|
int length = rd.length; // the size of the data block
|
||
|
|
||
|
if (length < count)
|
||
|
{
|
||
|
fprintf(stderr, "rio_write: %s\n", strerror(ENOMEM));
|
||
|
return -1;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{ // we are at the end of the index file || file is empty
|
||
|
|
||
|
int check = lseek(index_fd, 0, SEEK_END); // check to see if the file is empty (newly created)
|
||
|
|
||
|
if (check > 0)
|
||
|
{ // normal case
|
||
|
lseek(index_fd, -sizeof(record_descriptor), SEEK_END);
|
||
|
r = read(index_fd, &rd, sizeof(rd)); // read in the record
|
||
|
if (r < 0)
|
||
|
{
|
||
|
fprintf(stderr, "rio_write (read index to make new record_descriptor): %s\n", strerror(EIO));
|
||
|
return -1;
|
||
|
}; // error check
|
||
|
|
||
|
int position = rd.position; // the position of the data in the datafile
|
||
|
int length = rd.length; // the size of the data block
|
||
|
|
||
|
rd.position = position + length;
|
||
|
rd.length = count;
|
||
|
}
|
||
|
else
|
||
|
{ // special case for empty file
|
||
|
rd.position = 0;
|
||
|
rd.length = count;
|
||
|
}
|
||
|
|
||
|
w = write(index_fd, &rd, sizeof(record_descriptor));
|
||
|
if (w < 0)
|
||
|
{
|
||
|
fprintf(stderr, "rio_write (write index): %s\n", strerror(EIO));
|
||
|
return -1;
|
||
|
}; // error check
|
||
|
|
||
|
lseek(data_fd, rd.position, SEEK_SET); // seek to position in data file
|
||
|
|
||
|
data_w = write(data_fd, buf, count);
|
||
|
if (data_w < 0)
|
||
|
{
|
||
|
fprintf(stderr, "rio_write (write data): %s\n", strerror(EIO));
|
||
|
return -1;
|
||
|
}; // error check
|
||
|
|
||
|
return data_w;
|
||
|
}
|
||
|
|
||
|
rd.length = count;
|
||
|
|
||
|
lseek(index_fd, -sizeof(record_descriptor), SEEK_CUR);
|
||
|
w = write(index_fd, &rd, sizeof(record_descriptor));
|
||
|
if (w < 0)
|
||
|
{
|
||
|
fprintf(stderr, "rio_write (write index): %s\n", strerror(EIO));
|
||
|
return -1;
|
||
|
}; // error check
|
||
|
|
||
|
data_w = write(data_fd, buf, count);
|
||
|
if (data_w < 0)
|
||
|
{
|
||
|
fprintf(stderr, "rio_write (write data): %s\n", strerror(EIO));
|
||
|
return -1;
|
||
|
}; // error check
|
||
|
|
||
|
return w;
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------
|
||
|
// FUNCTION rio_lseek:
|
||
|
// Seek both files to the beginning of the requested record so that the next I/O is performed at the requested position.
|
||
|
// whence assumes the same values as lseek whence argument.
|
||
|
// PARAMETER USAGE :
|
||
|
// int fd : the file descriptor
|
||
|
// int offset : the offset of the index file
|
||
|
// int whence : the "mode" of the seek
|
||
|
// FUNCTION CALLED :
|
||
|
// int8_t decodeifd(int16_t d)
|
||
|
// int8_t decodedfd(int16_t d)
|
||
|
//-----------------------------------------------------------
|
||
|
int rio_lseek(int fd, int offset, int whence)
|
||
|
{
|
||
|
int index_fd, data_fd; // file descriptors
|
||
|
int s1, s2, r; // error values
|
||
|
record_descriptor rd;
|
||
|
|
||
|
index_fd = decodeifd(fd); // decrypt index file descriptor
|
||
|
data_fd = decodedfd(fd); // decrypt data file descriptor
|
||
|
|
||
|
s1 = lseek(index_fd, (offset) * sizeof(record_descriptor), whence); // seek the index file to offset
|
||
|
|
||
|
r = read(index_fd, &rd, sizeof(rd)); // read in the record
|
||
|
if (r < 0)
|
||
|
{
|
||
|
fprintf(stderr, "rio_lseek (SEEK_SET): %s\n", strerror(EIO));
|
||
|
return -1;
|
||
|
}; // error check
|
||
|
|
||
|
s1 = lseek(index_fd, (offset) * sizeof(record_descriptor), whence); // seek back to the index file because you read it in the previous step
|
||
|
|
||
|
int position = rd.position; // the position of the data in the datafile
|
||
|
s2 = lseek(data_fd, position, SEEK_SET); // seek to the position in the datafile @position
|
||
|
|
||
|
return s1 / sizeof(record_descriptor);
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------
|
||
|
// FUNCTION rio_close:
|
||
|
// Close both files.
|
||
|
// PARAMETER USAGE :
|
||
|
// int fd : the file descriptor
|
||
|
// FUNCTION CALLED :
|
||
|
// int8_t decodeifd(int16_t d)
|
||
|
// int8_t decodedfd(int16_t d)
|
||
|
//-----------------------------------------------------------
|
||
|
int rio_close(int fd)
|
||
|
{
|
||
|
int index_fd, data_fd; // file descriptors
|
||
|
|
||
|
index_fd = decodeifd(fd); // decrypt index file descriptor
|
||
|
data_fd = decodedfd(fd); // decrypt data file descriptor
|
||
|
|
||
|
int r1 = close(data_fd);
|
||
|
if (r1 < 0)
|
||
|
{
|
||
|
fprintf(stderr, "rio_close (datafile): %s\n", strerror(EIO));
|
||
|
return -1;
|
||
|
};
|
||
|
int r2 = close(index_fd);
|
||
|
if (r2 < 0)
|
||
|
{
|
||
|
fprintf(stderr, "rio_close (indexfile): %s\n", strerror(EIO));
|
||
|
return -1;
|
||
|
};
|
||
|
|
||
|
return r1;
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------
|
||
|
// FUNCTION encodefd:
|
||
|
// takes the file descriptor of both inputs and turns it into a single file descriptor
|
||
|
// PARAMETER USAGE :
|
||
|
// int d1 : the data file descriptor
|
||
|
// int d2 : the index file descriptor
|
||
|
// FUNCTION CALLED :
|
||
|
// none
|
||
|
//-----------------------------------------------------------
|
||
|
int16_t encodefd(int d1, int d2)
|
||
|
{
|
||
|
int16_t d = (((d1 & 0xff) << 8) | (d2 & 0xff)); // 16 bit handle
|
||
|
return d;
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------
|
||
|
// FUNCTION decodedfd:
|
||
|
// returns the data file descriptor
|
||
|
// PARAMETER USAGE :
|
||
|
// int16_t d : the file descriptor
|
||
|
// FUNCTION CALLED :
|
||
|
// none
|
||
|
//-----------------------------------------------------------
|
||
|
int8_t decodedfd(int16_t d)
|
||
|
{
|
||
|
int8_t d1 = (d >> 8); // take the top 8 bits
|
||
|
return d1;
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------
|
||
|
// FUNCTION decodeifd:
|
||
|
// returns the index file descriptor
|
||
|
// PARAMETER USAGE :
|
||
|
// int16_t d : the file descriptor
|
||
|
// FUNCTION CALLED :
|
||
|
// none
|
||
|
//-----------------------------------------------------------
|
||
|
int8_t decodeifd(int16_t d)
|
||
|
{
|
||
|
int8_t d2 = (d & 0xff); // take the bottom 8 bits
|
||
|
return d2;
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------
|
||
|
// FUNCTION printb:
|
||
|
// prints a 32 bit binary number
|
||
|
// PARAMETER USAGE :
|
||
|
// unsigned : the number
|
||
|
// FUNCTION CALLED :
|
||
|
// none
|
||
|
//-----------------------------------------------------------
|
||
|
void printb(unsigned n)
|
||
|
{
|
||
|
unsigned i;
|
||
|
for (i = 1 << 31; i > 0; i = i / 2)
|
||
|
{
|
||
|
(n & i) ? printf("1") : printf("0");
|
||
|
}
|
||
|
printf("\n");
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------
|
||
|
// FUNCTION readbyte:
|
||
|
// reads 1 byte from stdin and does error checking
|
||
|
// PARAMETER USAGE :
|
||
|
// none
|
||
|
// FUNCTION CALLED :
|
||
|
// ssize_t read(int fildes, void *buf, size_t nbyte)
|
||
|
// int fprintf(FILE * restrict stream, const char * restrict format, ...);
|
||
|
// char * strerror(int errnum);
|
||
|
//-----------------------------------------------------------
|
||
|
unsigned char readbyte(int fp)
|
||
|
{
|
||
|
int r;
|
||
|
unsigned char byte;
|
||
|
|
||
|
r = read(fp, &byte, sizeof(byte));
|
||
|
if (r < 0)
|
||
|
{
|
||
|
fprintf(stderr, "readbyte: %s\n", strerror(EIO));
|
||
|
exit(-1);
|
||
|
};
|
||
|
if (r == 0)
|
||
|
{
|
||
|
eof = 0;
|
||
|
};
|
||
|
return byte;
|
||
|
}
|