From ff957efd94499541c3320bd51f0694bf9a3ea396 Mon Sep 17 00:00:00 2001 From: zongor Date: Sat, 3 Sep 2022 23:35:42 -0400 Subject: [PATCH] initial commit --- .rinx.dclean-copy.txt | 0 .rinx.dclean-master.txt | 0 Makefile | 7 + README.md | 1 + dclean-copy.txt | 0 dclean-master.txt | 0 dclean.c | 274 +++++++++++++++++++++++ dclean.h | 51 +++++ iodir.c | 100 +++++++++ recordio.c | 466 ++++++++++++++++++++++++++++++++++++++++ recordio.h | 29 +++ 11 files changed, 928 insertions(+) create mode 100755 .rinx.dclean-copy.txt create mode 100755 .rinx.dclean-master.txt create mode 100755 Makefile create mode 100755 README.md create mode 100755 dclean-copy.txt create mode 100755 dclean-master.txt create mode 100755 dclean.c create mode 100755 dclean.h create mode 100755 iodir.c create mode 100755 recordio.c create mode 100755 recordio.h diff --git a/.rinx.dclean-copy.txt b/.rinx.dclean-copy.txt new file mode 100755 index 0000000..e69de29 diff --git a/.rinx.dclean-master.txt b/.rinx.dclean-master.txt new file mode 100755 index 0000000..e69de29 diff --git a/Makefile b/Makefile new file mode 100755 index 0000000..f44d3da --- /dev/null +++ b/Makefile @@ -0,0 +1,7 @@ +all: dclean iodir + +dclean: dclean.c; gcc -o dclean dclean.c recordio.c + +iodir: iodir.c; gcc -o iodir iodir.c + +clean:; rm -f dclean ; rm -f iodir ; diff --git a/README.md b/README.md new file mode 100755 index 0000000..bdaf262 --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +This is a file cleaner using record i/o, it takes in a `master` and a `copy` directory and will output a shell file which automatically deletes any identical files in the `copy` directory diff --git a/dclean-copy.txt b/dclean-copy.txt new file mode 100755 index 0000000..e69de29 diff --git a/dclean-master.txt b/dclean-master.txt new file mode 100755 index 0000000..e69de29 diff --git a/dclean.c b/dclean.c new file mode 100755 index 0000000..80da5cf --- /dev/null +++ b/dclean.c @@ -0,0 +1,274 @@ +#include "dclean.h" +#include "recordio.h" + +char buffer[512]; // character buffer for sprintf + +int main(int argc, char *argv[]) +{ + if (argc != 3) { + sprintf(buffer, "usage: dclean directory_master directory_copy\n"); + write(1, buffer, strlen(buffer)); + return EXIT_FAILURE; + } + char *master = argv[1]; // read in the arguments + char *copy = argv[2]; + + clean_txt(); // clean the directory + find_directories(master, "dclean-master.txt"); // find all files in the master directory + sortfile("dclean-master.txt", "dclean-master.txt"); // sort the file by filesize + find_directories(copy, "dclean-copy.txt"); // find all of the files in the copy directory + sortfile("dclean-copy.txt", "dclean-copy.txt"); // sort the file by filesize + find_same(); // find which files are the same +} + +//----------------------------------------------------------- +// FUNCTION clean_txt: +// this is mostly here to make sure that all of the .txt files are cleared before the program runs +// PARAMETER USAGE : +// none +// FUNCTION CALLED : +// void run_external_process(int fds[2], const char** args); +//----------------------------------------------------------- +void clean_txt() +{ + const char *a[3] = {"rm", "dclean-master.txt", NULL}; + const char *b[3] = {"rm", "dclean-copy.txt", NULL}; + const char *c[3] = {"rm", ".rinx.dclean-master.txt", NULL}; + const char *d[3] = {"rm", ".rinx.dclean-copy.txt", NULL}; + int s[2]; // pointer for the pipe; (we dont actually use the pipe) + run_external_process(s, a); + run_external_process(s, b); + run_external_process(s, c); + run_external_process(s, d); +} + +//----------------------------------------------------------- +// FUNCTION find_same: +// Seaches through the Master and Copy files and checks to see if the files listed are the same using 'diff' +// PARAMETER USAGE : +// none +// FUNCTION CALLED : +// int rio_open(const char *pathname, int flags, mode_t mode); +// int rio_lseek(int fd, int offset, int whence); +// void * rio_read(int fd, int * return_value); +// int identical(char * file1, char * file2); +//----------------------------------------------------------- +void find_same() +{ + const char s[2] = {'*', '\n'}; //* and \n character for use in tokenizer + char *token; + char *tokencp; + char *rc; + char *rccp; + int r, rcp, i, j, ir, jr, idn, n; + + int fd = rio_open("dclean-master.txt", O_RDONLY, 0644); // open the list of master files + if (fd < 0) + { + fprintf(stderr, "%s\n", strerror(EIO)); + exit(EXIT_FAILURE); + }; // error checking + + int fdcp = rio_open("dclean-copy.txt", O_RDONLY, 0644); // open the list of copy files + if (fdcp < 0) + { + fprintf(stderr, "%s\n", strerror(EIO)); + exit(EXIT_FAILURE); + }; // error checking + + int fdsh = open("clean-duplicates.sh", O_RDWR | O_CREAT | O_TRUNC, 0644); // open the shell script + if (fdsh < 0) + { + fprintf(stderr, "%s\n", strerror(EIO)); + exit(EXIT_FAILURE); + }; // error checking + + n = write(fdsh, "#!/bin/sh\n", strlen("#!/bin/sh\n")); // write this to the top so the .sh works + if (n < 0) + { + fprintf(stderr, "%s\n", strerror(EIO)); + exit(EXIT_FAILURE); + }; // error checking + + int eol = rio_lseek(fd, 0, SEEK_END); // we now know the length of the master file + int eolcp = rio_lseek(fdcp, 0, SEEK_END); // we now know the length of the copy file + r = rio_lseek(fd, 0, SEEK_SET); // seek back to the beginning + rcp = rio_lseek(fdcp, 0, SEEK_SET); + + for (i = 0; i < eol; i++) + { // loop through all files in the master file + ir = i; // we have to use this since rio_read returns a value back through &ir + rc = rio_read(fd, &ir); // read the ith line of the file + token = strtok(rc, s); // the first token will always be the filesize + token = strtok(NULL, s); // this is the filepath + + for (j = 0; j < eolcp; j++) + { // loop through all files in the copy file + jr = j; // we have to use this since rio_read returns a value back through &jr + rccp = rio_read(fdcp, &jr); // read the jth line of the file + + tokencp = strtok(rccp, s); // the first token will always be the filesize + tokencp = strtok(NULL, s); // this is the filepath + + idn = identical(token, tokencp); // see if the two files are identical + + if (idn == 1) + { // if they are identical then add them to the shell script + n = write(fdsh, "rm ", strlen("rm ")); // rm (remove command) + n = write(fdsh, tokencp, strlen(tokencp)); // the file in question + n = write(fdsh, "\n", strlen("\n")); + if (n < 0) + { + fprintf(stderr, "%s\n", strerror(EIO)); + exit(EXIT_FAILURE); + }; // error checking + } + + free(rccp); // we free this as to reset the buffer + } + rio_lseek(fdcp, 0, SEEK_SET); // reset pointer because otherwise we would only search the master file 1 time + free(rc); // free the buffer for the master file + } +} + +//----------------------------------------------------------- +// FUNCTION sortfile: +// Sorts the inputfile using /usr/bin/sort +// PARAMETER USAGE : +// char * inputfile : the file for input +// char * outputfile : the file for output +// FUNCTION CALLED : +// none +//----------------------------------------------------------- +int sortfile(char *inputfile, char *outputfile) +{ + // equivilent to: sort -n dclean-master.txt > sorted.txt + unsigned char byte; + const char *a[4] = {"sort", "-n", inputfile, NULL}; // construct arguments + +#ifdef DEBUG + sprintf(buffer, "Sorting File [%s]\n", inputfile); + write(1, buffer, strlen(buffer)); +#endif + + pid_t pid; // the pid of the child/parent + int status; // the waiting integer + + if ((pid = fork()) == 0) + { // forking diff (child process) + int fd = open(outputfile, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); // open file (create it if it doesnt exist) + if (fd < 0) + { + fprintf(stderr, "Open (outputfile) Failed because of: %s\n", strerror(EIO)); + return -1; + }; + dup2(fd, 1); // make stdout go to file + execvp(a[0], a); // create the sort process + exit(0); // exit the child + } + else if (pid < 0) + { // error checking + sprintf(buffer, "Fork Failed!\n"); + write(1, buffer, strlen(buffer)); + exit(-1); + } + else + { // parent process + while (wait(&status) != pid) + ; // wait for completion; + } + return 0; +} + +//----------------------------------------------------------- +// FUNCTION find_directories: +// Runs "iodir" to generate the .txt files +// PARAMETER USAGE : +// char * file_path : the file for input +// char * out_name : the file for output +// FUNCTION CALLED : +// void run_external_process(int fds[2], const char** args); +//----------------------------------------------------------- +int find_directories(char *file_path, char *out_name) +{ + const char *a[4] = {"iodir", file_path, out_name, NULL}; // construct arguments + int fds[2]; // pointer for the pipe we will create in a line or so +#ifdef DEBUG + sprintf(buffer, "Generating Directory File [%s] For path: [%s]\n", out_name, file_path); + write(1, buffer, strlen(buffer)); +#endif + run_external_process(fds, a); // generate the files using iodir [I edited it slightly] + return 0; +} + +//----------------------------------------------------------- +// FUNCTION identical: +// Runs "diff file1 file2" to generate see if they are the same +// PARAMETER USAGE : +// char * file1 : "master" file +// char * file2 : "copy" file +// FUNCTION CALLED : +// void run_external_process(int fds[2], const char** args); +//----------------------------------------------------------- +int identical(char *file1, char *file2) +{ + const char *a[4] = {"diff", file1, file2, NULL}; // construct arguments + int fds[2]; // pointer for the pipe we will create in a line or so + run_external_process(fds, a); // run diff + // continue with parent process + ssize_t size = read(fds[0], buffer, sizeof(buffer)); // read from the pipe + if (size == 0) + { // diff returns zero when the files are the same +#ifdef DEBUG + sprintf(buffer, "\"%s\" is a copy of \"%s\"\n", file2, file1); + write(1, buffer, strlen(buffer)); +#endif + return 1; // they are identical + } + else + { +#ifdef DEBUG + sprintf(buffer, "\"%s\" and \"%s\" differ\n", file1, file2); + write(1, buffer, strlen(buffer)); +#endif + return 0; // they are different + } + return -1; // something weird went on; throw an error +} + +//----------------------------------------------------------- +// FUNCTION run_external_process: +// Runs child process and returns the childs output to the parent +// PARAMETER USAGE : +// int fds[2] : the pointers to the pipe +// const char** args : the arguments for the execvp +// FUNCTION CALLED : +// none +//----------------------------------------------------------- +void run_external_process(int fds[2], const char **args) +{ + pid_t pid; // the pid of the child/parent + int status; // the waiting integer + pipe(fds); // create a new pipe pipe + + if ((pid = fork()) == 0) + { // forking the child process + close(fds[0]); // close the input of the pipe + close(1); // close stdout + dup(fds[1]); // dup the pipes stdout (pipe now sends child's stdout) + execvp(args[0], args); // create the diff process + exit(0); // exit the child + } + else if (pid < 0) + { // error checking + sprintf(buffer, "Fork Failed!\n"); + write(1, buffer, strlen(buffer)); + exit(-1); + } + else + { // parent process + close(fds[1]); // close output of pipe which redirects stdout of the child + while (wait(&status) != pid) + ; // wait for completion; + } +} diff --git a/dclean.h b/dclean.h new file mode 100755 index 0000000..3d898bc --- /dev/null +++ b/dclean.h @@ -0,0 +1,51 @@ +#ifndef DCLEAN_H_ +#define DCLEAN_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +void run_external_process(int pipe[2], const char** args); +int find_directories(char * file_path, char * out_name); +int sortfile(char *inputfile, char *outputfile); +int identical(char * file1, char * file2); +void list_directory (char * path , char * filename); +void find_same(); +void clean_txt(); + +/* + * dclean + * + * A/ B/ # A/excursion.jpg + * excursion.jpg == 123.jpg => rm B/123.jpg + * + * + * | Addon/ | + * | | + * | xyz.txt | + * | | + * | | + * | .. | + * | . | + * V V + * dclean-master.txt dclean-copy.txt + * [ 1024 | A/excursion.jpg] [ 1024 | B/123.jpg] + * [ 127 | A/Addon/xyz.txt] [ | ] + * + * if filesize A == filesize B then + * + * if they are the same add to the to_be_deleted_list + * + * fork and exec "diff" to see if the same + * + */ + +#endif /* DCLEAN_H_ */ diff --git a/iodir.c b/iodir.c new file mode 100755 index 0000000..bd3c6da --- /dev/null +++ b/iodir.c @@ -0,0 +1,100 @@ +#include "dclean.h" + +struct dirent *dptr; + +void list_directory(char *path, char *filename) +{ + struct stat st, sb; + DIR *dirp; + int n, fd; + + int out = open(filename, O_RDWR | O_CREAT, 0644); // opens file; creates it if it does not exist; + if (out < 0) + { // error check + fprintf(stderr, "cannot open %s because of %s\n", filename, strerror(5)); + exit(EXIT_FAILURE); + } + + if ((dirp = opendir(path)) == NULL) + { + fprintf(stderr, "Opening %s : ", path); + perror("opendir:"); + return; + } + + while ((dptr = readdir(dirp))) + { + char *name = dptr->d_name; + stat(name, &sb); + + if ((strcmp(name, "..") != 0) & (strcmp(name, ".") != 0)) + { +#ifdef DEBUG + printf("st.st_mode : %d\n", st.st_mode); +#endif + if ((sb.st_mode & S_IFMT) == S_IFDIR) + { + char *p; +#ifdef DEBUG + printf("%s/%s/\n", path, name); // uncomment if you want to see the directory name. +#endif + p = malloc(strlen(name) + strlen(path) + 1 + 1); + strcpy(p, path); + strcat(p, "/"); + strcat(p, name); + list_directory(p, filename); + free(p); + } + else if ((sb.st_mode & S_IFMT) == S_IFREG) + { + char *full; + + full = malloc(strlen(path) + 1 + strlen(name) + 1); + strcpy(full, path); + strcat(full, "/"); + strcat(full, name); + + fd = open(full, O_RDONLY); + if (fd < 0) + { + fprintf(stderr, "unable to open file:%s\n", full); + perror("open:"); + } + else + { + stat(full, &st); +#ifdef DEBUG + printf("%s %lld\n", full, st.st_size); +#endif + char number[50] = {}; + sprintf(number, "%lld", st.st_size); + ; + + n = write(out, number, strlen(number)); + n = write(out, "*", strlen("*")); + n = write(out, full, strlen(full)); // write the record descriptor + n = write(out, "\n", strlen("\n")); + + if (n < 0) + { + fprintf(stderr, "%s\n", strerror(EIO)); + exit(EXIT_FAILURE); + }; // error checking + } + close(fd); + + free(full); + } +#ifdef DEBUG + else + printf("---> Not a regular file %s/%s\n", path, name); +#endif + } + } + closedir(dirp); +} + +int main(int argc, char *argv[]) +{ + list_directory(argv[1], argv[2]); +} diff --git a/recordio.c b/recordio.c new file mode 100755 index 0000000..031c569 --- /dev/null +++ b/recordio.c @@ -0,0 +1,466 @@ +#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; +} diff --git a/recordio.h b/recordio.h new file mode 100755 index 0000000..837df7b --- /dev/null +++ b/recordio.h @@ -0,0 +1,29 @@ +#ifndef RECORDIO_H_ +#define RECORDIO_H_ + +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct +{ + int position; + int length; +} record_descriptor; + +int rio_open(const char *pathname, int flags, mode_t mode); +void *rio_read(int fd, int *return_value); +int rio_write(int fd, const void *buf, int count); +int rio_lseek(int fd, int offset, int whence); +int rio_close(int fd); +int16_t encodefd(int d1, int d2); +int8_t decodedfd(int16_t d); +int8_t decodeifd(int16_t d); +void printb(unsigned n); + +#endif /* RECORDIO_H_ */