From d530cd9d014daea815748a61ea6fe411be94e58e Mon Sep 17 00:00:00 2001 From: vht24 <vht24@tux3.cci.drexel.edu> Date: Sun, 2 Feb 2025 22:31:38 -0500 Subject: [PATCH] asignment 2 --- Assignment2/a2-questions.md | 129 +++++++ Assignment2/db.h | 35 ++ Assignment2/dblayout.png | Bin 0 -> 56255 bytes Assignment2/makefile | 28 ++ Assignment2/sdbsc | Bin 0 -> 25928 bytes Assignment2/sdbsc.c | 690 ++++++++++++++++++++++++++++++++++++ Assignment2/sdbsc.h | 64 ++++ Assignment2/student.db | Bin 0 -> 192 bytes Assignment2/test.sh | 195 ++++++++++ Assignment2/testload.sh | 6 + 10 files changed, 1147 insertions(+) create mode 100644 Assignment2/a2-questions.md create mode 100644 Assignment2/db.h create mode 100644 Assignment2/dblayout.png create mode 100644 Assignment2/makefile create mode 100755 Assignment2/sdbsc create mode 100644 Assignment2/sdbsc.c create mode 100644 Assignment2/sdbsc.h create mode 100644 Assignment2/student.db create mode 100755 Assignment2/test.sh create mode 100755 Assignment2/testload.sh diff --git a/Assignment2/a2-questions.md b/Assignment2/a2-questions.md new file mode 100644 index 0000000..a06cc1c --- /dev/null +++ b/Assignment2/a2-questions.md @@ -0,0 +1,129 @@ +## Assignment 2 Questions + +#### Directions +Please answer the following questions and submit in your repo for the second assignment. Please keep the answers as short and concise as possible. + +1. In this assignment I asked you provide an implementation for the `get_student(...)` function because I think it improves the overall design of the database application. After you implemented your solution do you agree that externalizing `get_student(...)` into it's own function is a good design strategy? Briefly describe why or why not. + + > **Answer**: Yes, externalizing get_student(...) is a good choice. It formalize the logic for retrieving a student, reducing code duplication and improving ease of use. Other functions (e.g., `del_student()`, `print_student()`) reuse it a lot, ensuring consistent behavior when accessing student records. + +2. Another interesting aspect of the `get_student(...)` function is how its function prototype requires the caller to provide the storage for the `student_t` structure: + + ```c + int get_student(int fd, int id, student_t *s); + ``` + + Notice that the last parameter is a pointer to storage **provided by the caller** to be used by this function to populate information about the desired student that is queried from the database file. This is a common convention (called pass-by-reference) in the `C` programming language. + + In other programming languages an approach like the one shown below would be more idiomatic for creating a function like `get_student()` (specifically the storage is provided by the `get_student(...)` function itself): + + ```c + //Lookup student from the database + // IF FOUND: return pointer to student data + // IF NOT FOUND: return NULL + student_t *get_student(int fd, int id){ + student_t student; + bool student_found = false; + + //code that looks for the student and if + //found populates the student structure + //The found_student variable will be set + //to true if the student is in the database + //or false otherwise. + + if (student_found) + return &student; + else + return NULL; + } + ``` + Can you think of any reason why the above implementation would be a **very bad idea** using the C programming language? Specifically, address why the above code introduces a subtle bug that could be hard to identify at runtime? + + > **ANSWER:** This implementation is dangerous because student is a local variable stored on the stack. When the function returns, the stack is deallocated, making `&student` a dangling pointer. This leads to undefined behavior. + +3. Another way the `get_student(...)` function could be implemented is as follows: + + ```c + //Lookup student from the database + // IF FOUND: return pointer to student data + // IF NOT FOUND or memory allocation error: return NULL + student_t *get_student(int fd, int id){ + student_t *pstudent; + bool student_found = false; + + pstudent = malloc(sizeof(student_t)); + if (pstudent == NULL) + return NULL; + + //code that looks for the student and if + //found populates the student structure + //The found_student variable will be set + //to true if the student is in the database + //or false otherwise. + + if (student_found){ + return pstudent; + } + else { + free(pstudent); + return NULL; + } + } + ``` + In this implementation the storage for the student record is allocated on the heap using `malloc()` and passed back to the caller when the function returns. What do you think about this alternative implementation of `get_student(...)`? Address in your answer why it work work, but also think about any potential problems it could cause. + + > **ANSWER:** This approach works because malloc() allocates memory on the heap, ensuring the student record remains valid after the function returns. However, it can cause memory issues: + > - The caller must free() the memory, which can be annoying sometimes, or it causes memory leaks. + > - If the function is called frequently, excessive heap allocations may degrade performance. + > Managing memory explicitly like the current implementation reduce that potential threat. + + +4. Lets take a look at how storage is managed for our simple database. Recall that all student records are stored on disk using the layout of the `student_t` structure (which has a size of 64 bytes). Lets start with a fresh database by deleting the `student.db` file using the command `rm ./student.db`. Now that we have an empty database lets add a few students and see what is happening under the covers. Consider the following sequence of commands: + + ```bash + > ./sdbsc -a 1 john doe 345 + > ls -l ./student.db + -rw-r----- 1 bsm23 bsm23 128 Jan 17 10:01 ./student.db + > du -h ./student.db + 4.0K ./student.db + > ./sdbsc -a 3 jane doe 390 + > ls -l ./student.db + -rw-r----- 1 bsm23 bsm23 256 Jan 17 10:02 ./student.db + > du -h ./student.db + 4.0K ./student.db + > ./sdbsc -a 63 jim doe 285 + > du -h ./student.db + 4.0K ./student.db + > ./sdbsc -a 64 janet doe 310 + > du -h ./student.db + 8.0K ./student.db + > ls -l ./student.db + -rw-r----- 1 bsm23 bsm23 4160 Jan 17 10:03 ./student.db + ``` + + For this question I am asking you to perform some online research to investigate why there is a difference between the size of the file reported by the `ls` command and the actual storage used on the disk reported by the `du` command. Understanding why this happens by design is important since all good systems programmers need to understand things like how linux creates sparse files, and how linux physically stores data on disk using fixed block sizes. Some good google searches to get you started: _"lseek syscall holes and sparse files"_, and _"linux file system blocks"_. After you do some research please answer the following: + + - Please explain why the file size reported by the `ls` command was 128 bytes after adding student with ID=1, 256 after adding student with ID=3, and 4160 after adding the student with ID=64? + + > **ANSWER:** The database uses sparse file allocation. Each student record is 64 bytes, and their position is based on `id * sizeof(student_t)`. + > - ID=1 → First record at offset 1 * 64 = 64 (File size: 128 bytes). + > - ID=3 → Third record at offset 3 * 64 = 192 (File size: 256 bytes). + > - ID=64 → 64th record at offset 64 * 64 = 4096 (File size: 4160 bytes). + > Linux does not store zeros physically in sparse files, so the actual disk usage is just enough to hold the largest id. + + - Why did the total storage used on the disk remain unchanged when we added the student with ID=1, ID=3, and ID=63, but increased from 4K to 8K when we added the student with ID=64? + + > **ANSWER:** Before ID=64, all records fit within the first 4 KB block, adding ID=64 moved into a new 4 KB block, causing real storage allocation to increase to 8 KB. + + - Now lets add one more student with a large student ID number and see what happens: + + ```bash + > ./sdbsc -a 99999 big dude 205 + > ls -l ./student.db + -rw-r----- 1 bsm23 bsm23 6400000 Jan 17 10:28 ./student.db + > du -h ./student.db + 12K ./student.db + ``` + We see from above adding a student with a very large student ID (ID=99999) increased the file size to 6400000 as shown by `ls` but the raw storage only increased to 12K as reported by `du`. Can provide some insight into why this happened? + + > **ANSWER:** `ls` reports the full file size. `du` only reports actual allocated blocks, so when ID 99999 is added, it is stored in another `4K` block, so actual disk usage only increase by `4K` since Linux does not allocate blocks for empty regions. \ No newline at end of file diff --git a/Assignment2/db.h b/Assignment2/db.h new file mode 100644 index 0000000..ac7e122 --- /dev/null +++ b/Assignment2/db.h @@ -0,0 +1,35 @@ +#ifndef __DB_H__ + #define __DB_H__ + +// Basic student database record. Note: +// 1. id must be > 0. A student id==0 means the record has been deleted +// 2. gpa is an int, should be between 0<=gpa<=500, real gpa is gpa/100.0 this +// simplifies dealing with floating point types +// 3. Notice that the student struct was engineered to have a size of +// 64 bytes. There are reasons for using such a number +typedef struct student{ + int id; + char fname[24]; + char lname[32]; + int gpa; +} student_t; + +//Define limits for sudent ids and allowable GPA ranges. Note GPA values will +//be stored as integers but printed as floats. For example a GPA of 450 is really +//that value divided by 100.0 or 4.50. +#define MIN_STD_ID 1 +#define MAX_STD_ID 100000 +#define MIN_STD_GPA 0 +#define MAX_STD_GPA 500 + +//some useful constants you should consider using versus hard coding +//in your program. +static const student_t EMPTY_STUDENT_RECORD = {0}; +static const int STUDENT_RECORD_SIZE = sizeof(struct student); +static const int DELETED_STUDENT_ID = 0; + + +#define DB_FILE "student.db" //name of database file +#define TMP_DB_FILE ".tmp_student.db" //for extra credit + +#endif \ No newline at end of file diff --git a/Assignment2/dblayout.png b/Assignment2/dblayout.png new file mode 100644 index 0000000000000000000000000000000000000000..0aa1ba5aedd5556d13736f0836a36a9ba492626a GIT binary patch literal 56255 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 literal 0 HcmV?d00001 diff --git a/Assignment2/makefile b/Assignment2/makefile new file mode 100644 index 0000000..4f6101c --- /dev/null +++ b/Assignment2/makefile @@ -0,0 +1,28 @@ +# Compiler settings +CC = gcc +CFLAGS = -Wall -Wextra -g + +# Target executable name +TARGET = sdbsc + +# Find all source and header files +SRCS = $(wildcard *.c) +HDRS = $(wildcard *.h) + +# Default target +all: $(TARGET) + +# Compile source to executable +$(TARGET): $(SRCS) $(HDRS) + $(CC) $(CFLAGS) -o $(TARGET) $(SRCS) + +# Clean up build files +clean: + rm -f $(TARGET) + rm -f student.db + +test: + ./test.sh + +# Phony targets +.PHONY: all clean \ No newline at end of file diff --git a/Assignment2/sdbsc b/Assignment2/sdbsc new file mode 100755 index 0000000000000000000000000000000000000000..b462bc0d36d7a217a6bf046b9ab7227604446c86 GIT binary patch literal 25928 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 literal 0 HcmV?d00001 diff --git a/Assignment2/sdbsc.c b/Assignment2/sdbsc.c new file mode 100644 index 0000000..559d2cd --- /dev/null +++ b/Assignment2/sdbsc.c @@ -0,0 +1,690 @@ +#include <stdio.h> +#include <stdlib.h> +#include <fcntl.h> //c library for system call file routines +#include <string.h> +#include <sys/stat.h> +#include <unistd.h> +#include <stdbool.h> + +// database include files +#include "db.h" +#include "sdbsc.h" + +/* + * open_db + * dbFile: name of the database file + * should_truncate: indicates if opening the file also empties it + * + * returns: File descriptor on success, or ERR_DB_FILE on failure + * + * console: Does not produce any console I/O on success + * M_ERR_DB_OPEN on error + * + */ +int open_db(char *dbFile, bool should_truncate) +{ + // Set permissions: rw-rw---- + // see sys/stat.h for constants + mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP; + + // open the file if it exists for Read and Write, + // create it if it does not exist + int flags = O_RDWR | O_CREAT; + + if (should_truncate) + flags += O_TRUNC; + + // Now open file + int fd = open(dbFile, flags, mode); + + if (fd == -1) + { + // Handle the error + printf(M_ERR_DB_OPEN); + return ERR_DB_FILE; + } + + return fd; +} + +/* + * get_student + * fd: linux file descriptor + * id: the student id we are looking forname of the + * *s: a pointer where the located (if found) student data will be + * copied + * + * returns: NO_ERROR student located and copied into *s + * ERR_DB_FILE database file I/O issue + * SRCH_NOT_FOUND student was not located in the database + * + * console: Does not produce any console I/O used by other functions + */ +int get_student(int fd, int id, student_t *s) +{ + // TODO + off_t offset = id * STUDENT_RECORD_SIZE; + if (lseek(fd, offset, SEEK_SET) == -1) { + return ERR_DB_FILE; + } + + ssize_t bytes_read = read(fd, s, STUDENT_RECORD_SIZE); + if (bytes_read != STUDENT_RECORD_SIZE) { + return ERR_DB_FILE; + } + + if (memcmp(s, &EMPTY_STUDENT_RECORD, STUDENT_RECORD_SIZE) == 0) { + return SRCH_NOT_FOUND; + } + + return NO_ERROR; +} + +/* + * add_student + * fd: linux file descriptor + * id: student id (range is defined in db.h ) + * fname: student first name + * lname: student last name + * gpa: GPA as an integer (range defined in db.h) + * + * Adds a new student to the database. After calculating the index for the + * student, check if there is another student already at that location. A good + * way is to use something like memcmp() to ensure that the location for this + * student contains all zero byes indicating the space is empty. + * + * returns: NO_ERROR student added to database + * ERR_DB_FILE database file I/O issue + * ERR_DB_OP database operation logically failed (aka student + * already exists) + * + * + * console: M_STD_ADDED on success + * M_ERR_DB_ADD_DUP student already exists + * M_ERR_DB_READ error reading or seeking the database file + * M_ERR_DB_WRITE error writing to db file (adding student) + * + */ +int add_student(int fd, int id, char *fname, char *lname, int gpa) +{ + // TODO + off_t offset = id * STUDENT_RECORD_SIZE; + student_t exist; + + if (lseek(fd, offset, SEEK_SET) == -1) { + printf(M_ERR_DB_READ); + return ERR_DB_FILE; + } + + ssize_t bytes_read = read(fd, &exist, STUDENT_RECORD_SIZE); + if (bytes_read == 0) { + memset(&exist, 0, sizeof(exist)); + } else if (bytes_read != STUDENT_RECORD_SIZE) { + printf(M_ERR_DB_READ); + return ERR_DB_FILE; + } + + if (memcmp(&exist, &EMPTY_STUDENT_RECORD, STUDENT_RECORD_SIZE) != 0) { + printf(M_ERR_DB_ADD_DUP, id); + return ERR_DB_OP; + } + + student_t new_student = {0}; + new_student.id = id; + strncpy(new_student.fname, fname, sizeof(new_student.fname) - 1); + strncpy(new_student.lname, lname, sizeof(new_student.lname) - 1); + new_student.gpa = gpa; + + if (lseek(fd, offset, SEEK_SET) == -1) { + printf(M_ERR_DB_WRITE); + return ERR_DB_FILE; + } + + if (write(fd, &new_student, STUDENT_RECORD_SIZE) != STUDENT_RECORD_SIZE) { + printf(M_ERR_DB_WRITE); + return ERR_DB_FILE; + } + + printf(M_STD_ADDED, id); + return NO_ERROR; +} + +/* + * del_student + * fd: linux file descriptor + * id: student id to be deleted + * + * Removes a student to the database. Use the get_student() function to + * locate the student to be deleted. If there is a student at that location + * write an empty student record - see EMPTY_STUDENT_RECORD from db.h at + * that location. + * + * returns: NO_ERROR student deleted from database + * ERR_DB_FILE database file I/O issue + * ERR_DB_OP database operation logically failed (aka student + * not in database) + * + * + * console: M_STD_DEL_MSG on success + * M_STD_NOT_FND_MSG student not in database, cant be deleted + * M_ERR_DB_READ error reading or seeking the database file + * M_ERR_DB_WRITE error writing to db file (adding student) + * + */ +int del_student(int fd, int id) +{ + // TODO + student_t student; + int result = get_student(fd, id, &student); + + if (result == SRCH_NOT_FOUND) { + printf(M_STD_NOT_FND_MSG, id); + return ERR_DB_OP; + } else if (result != NO_ERROR) { + return ERR_DB_FILE; + } + + off_t offset = id * STUDENT_RECORD_SIZE; + if (lseek(fd, offset, SEEK_SET) == -1) { + printf(M_ERR_DB_WRITE); + return ERR_DB_FILE; + } + + if (write(fd, &EMPTY_STUDENT_RECORD, STUDENT_RECORD_SIZE) != STUDENT_RECORD_SIZE) { + printf(M_ERR_DB_WRITE); + return ERR_DB_FILE; + } + + printf(M_STD_DEL_MSG, id); + return NO_ERROR; +} + +/* + * count_db_records + * fd: linux file descriptor + * + * Counts the number of records in the database. Start by reading the + * database at the beginning, and continue reading individual records + * until you it EOF. EOF is when the read() syscall returns 0. Check + * if a slot is empty or previously deleted by investigating if all of + * the bytes in the record read are zeros - I would suggest using memory + * compare memcmp() for this. Create a counter variable and initialize it + * to zero, every time a non-zero record is read increment the counter. + * + * returns: <number> returns the number of records in db on success + * ERR_DB_FILE database file I/O issue + * ERR_DB_OP database operation logically failed (aka student + * not in database) + * + * + * console: M_DB_RECORD_CNT on success, to report the number of students in db + * M_DB_EMPTY on success if the record count in db is zero + * M_ERR_DB_READ error reading or seeking the database file + * M_ERR_DB_WRITE error writing to db file (adding student) + * + */ +int count_db_records(int fd) +{ + // TODO + student_t student; + int count = 0; + + if (lseek(fd, 0, SEEK_SET) == -1) { + printf(M_ERR_DB_READ); + return ERR_DB_FILE; + } + + while (read(fd, &student, STUDENT_RECORD_SIZE) == STUDENT_RECORD_SIZE) { + if (memcmp(&student, &EMPTY_STUDENT_RECORD, STUDENT_RECORD_SIZE) != 0) { + count++; + } + } + + if (count == 0) { + printf(M_DB_EMPTY); + } else { + printf(M_DB_RECORD_CNT, count); + } + + return count; +} + +/* + * print_db + * fd: linux file descriptor + * + * Prints all records in the database. Start by reading the + * database at the beginning, and continue reading individual records + * until you it EOF. EOF is when the read() syscall returns 0. Check + * if a slot is empty or previously deleted by investigating if all of + * the bytes in the record read are zeros - I would suggest using memory + * compare memcmp() for this. Be careful as the database might be empty. + * on the first real row encountered print the header for the required output: + * + * printf(STUDENT_PRINT_HDR_STRING, "ID", + * "FIRST_NAME", "LAST_NAME", "GPA"); + * + * then for each valid record encountered print the required output: + * + * printf(STUDENT_PRINT_FMT_STRING, student.id, student.fname, + * student.lname, calculated_gpa_from_student); + * + * The code above assumes you are reading student records into a local + * variable named student that is of type student_t. Also dont forget that + * the GPA in the student structure is an int, to convert it into a real + * gpa divide by 100.0 and store in a float variable. + * + * returns: NO_ERROR on success + * ERR_DB_FILE database file I/O issue + * + * + * console: <see above> on success, print table or database empty + * M_ERR_DB_READ error reading or seeking the database file + * + */ +int print_db(int fd) +{ + // TODO + student_t student; + bool records_available = false; + + if (lseek(fd, 0, SEEK_SET) == -1) { + printf(M_ERR_DB_READ); + return ERR_DB_FILE; + } + + while (read(fd, &student, STUDENT_RECORD_SIZE) == STUDENT_RECORD_SIZE) { + if (memcmp(&student, &EMPTY_STUDENT_RECORD, STUDENT_RECORD_SIZE) != 0) { + if (!records_available) { + printf(STUDENT_PRINT_HDR_STRING, "ID", "FIRST_NAME", "LAST_NAME", "GPA"); + records_available = true; + } + printf(STUDENT_PRINT_FMT_STRING, student.id, student.fname, student.lname, student.gpa / 100.0); + } + } + + if (!records_available) { + printf(M_DB_EMPTY); + } + + return NO_ERROR; +} + +/* + * print_student + * *s: a pointer to a student_t structure that should + * contain a valid student to be printed + * + * Start by ensuring that provided student pointer is valid. To do this + * make sure it is not NULL and that s->id is not zero. After ensuring + * that the student is valid, print it the exact way that is described + * in the print_db() function by first printing the header then the + * student data: + * + * printf(STUDENT_PRINT_HDR_STRING, "ID", + * "FIRST NAME", "LAST_NAME", "GPA"); + * + * printf(STUDENT_PRINT_FMT_STRING, s->id, s->fname, + * student.lname, calculated_gpa_from_s); + * + * Dont forget that the GPA in the student structure is an int, to convert + * it into a real gpa divide by 100.0 and store in a float variable. + * + * returns: nothing, this is a void function + * + * + * console: <see above> on success, print table or database empty + * M_ERR_STD_PRINT if the function argument s is NULL or if + * s->id is zero + * + */ +void print_student(student_t *s) +{ + // TODO + if (s == NULL || s->id == 0) { + printf(M_ERR_STD_PRINT); + return; + } + + printf(STUDENT_PRINT_HDR_STRING, "ID", "FIRST NAME", "LAST NAME", "GPA"); + printf(STUDENT_PRINT_FMT_STRING, s->id, s->fname, s->lname, s->gpa / 100.0); +} + +/* + * NOTE IMPLEMENTING THIS FUNCTION IS EXTRA CREDIT + * + * compress_db + * fd: linux file descriptor + * + * This assignment takes advantage of the way Linux handles sparse files + * on disk. Thus if there is a large hole between student records, Linux + * will not use any physical storage. However, when a database record is + * deleted storage is used to write a blank - see EMPTY_STUDENT_RECORD from + * db.h - record. + * + * Since Linux provides no way to delete data in the middle of a file, and + * deleted records take up physical storage, this function will compress the + * database by rewriting a new database file that only includes valid student + * records. There are a number of ways to do this, but since this is extra credit + * you need to figure this out on your own. + * + * At a high level create a temporary database file then copy all valid students from + * the active database (passed in via fd) to the temporary file. When this is done + * rename the temporary database file to the name of the real database file. See + * the constants in db.h for required file names: + * + * #define DB_FILE "student.db" //name of database file + * #define TMP_DB_FILE ".tmp_student.db" //for extra credit + * + * Note that you are passed in the fd of the database file to be compressed, + * it is very likely you will need to close it to overwrite it with the + * compressed version of the file. To ensure the caller can work with the + * compressed file after you create it, it is a good design to return the fd + * of the new compressed file from this function + * + * returns: <number> returns the fd of the compressed database file + * ERR_DB_FILE database file I/O issue + * + * + * console: M_DB_COMPRESSED_OK on success, the db was successfully compressed. + * M_ERR_DB_OPEN error when opening/creating temporary database file. + * this error should also be returned after you + * compressed the database file and if you are unable + * to open it to pass the fd back to the caller + * M_ERR_DB_CREATE error creating the db file. For instance the + * inability to copy the temporary file back as + * the primary database file. + * M_ERR_DB_READ error reading or seeking the the db or tempdb file + * M_ERR_DB_WRITE error writing to db or tempdb file (adding student) + * + */ +int compress_db(int fd) +{ + // TODO + close(fd); + + fd = open(DB_FILE, O_RDONLY); + if (fd == -1) { + printf(M_ERR_DB_OPEN); + return ERR_DB_FILE; + } + + // Open or make a temp database file in write mode + int tmp_fd = open(TMP_DB_FILE, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); + if (tmp_fd == -1) { + printf(M_ERR_DB_CREATE); + close(fd); + return ERR_DB_FILE; + } + + student_t student; + while (read(fd, &student, STUDENT_RECORD_SIZE) == STUDENT_RECORD_SIZE) { + // Copy only non-empty records + if (memcmp(&student, &EMPTY_STUDENT_RECORD, STUDENT_RECORD_SIZE) != 0) { + if (write(tmp_fd, &student, STUDENT_RECORD_SIZE) != STUDENT_RECORD_SIZE) { + printf(M_ERR_DB_WRITE); + close(fd); + close(tmp_fd); + return ERR_DB_FILE; + } + } + } + + close(fd); + close(tmp_fd); + + // Replace old database with the compressed one + if (rename(TMP_DB_FILE, DB_FILE) == -1) { + printf(M_ERR_DB_CREATE); + return ERR_DB_FILE; + } + + fd = open(DB_FILE, O_RDWR); + if (fd == -1) { + printf(M_ERR_DB_OPEN); + return ERR_DB_FILE; + } + + printf(M_DB_COMPRESSED_OK); + return fd; +} + +/* + * validate_range + * id: proposed student id + * gpa: proposed gpa + * + * This function validates that the id and gpa are in the allowable ranges + * as per the specifications. It checks if the values are within the + * inclusive range using constents in db.h + * + * returns: NO_ERROR on success, both ID and GPA are in range + * EXIT_FAIL_ARGS if either ID or GPA is out of range + * + * console: This function does not produce any output + * + */ +int validate_range(int id, int gpa) +{ + + if ((id < MIN_STD_ID) || (id > MAX_STD_ID)) + return EXIT_FAIL_ARGS; + + if ((gpa < MIN_STD_GPA) || (gpa > MAX_STD_GPA)) + return EXIT_FAIL_ARGS; + + return NO_ERROR; +} + +/* + * usage + * exename: the name of the executable from argv[0] + * + * Prints this programs expected usage + * + * returns: nothing, this is a void function + * + * console: This function prints the usage information + * + */ +void usage(char *exename) +{ + printf("usage: %s -[h|a|c|d|f|p|z] options. Where:\n", exename); + printf("\t-h: prints help\n"); + printf("\t-a id first_name last_name gpa(as 3 digit int): adds a student\n"); + printf("\t-c: counts the records in the database\n"); + printf("\t-d id: deletes a student\n"); + printf("\t-f id: finds and prints a student in the database\n"); + printf("\t-p: prints all records in the student database\n"); + printf("\t-x: compress the database file [EXTRA CREDIT]\n"); + printf("\t-z: zero db file (remove all records)\n"); +} + +// Welcome to main() +int main(int argc, char *argv[]) +{ + char opt; // user selected option + int fd; // file descriptor of database files + int rc; // return code from various operations + int exit_code; // exit code to shell + int id; // userid from argv[2] + int gpa; // gpa from argv[5] + + // space for a student structure which we will get back from + // some of the functions we will be writing such as get_student(), + // and print_student(). + student_t student = {0}; + + // This function must have at least one arg, and the arg must start + // with a dash + if ((argc < 2) || (*argv[1] != '-')) + { + usage(argv[0]); + exit(1); + } + + // The option is the first character after the dash for example + //-h -a -c -d -f -p -x -z + opt = (char)*(argv[1] + 1); // get the option flag + + // handle the help flag and then exit normally + if (opt == 'h') + { + usage(argv[0]); + exit(EXIT_OK); + } + + // now lets open the file and continue if there is no error + // note we are not truncating the file using the second + // parameter + fd = open_db(DB_FILE, false); + if (fd < 0) + { + exit(EXIT_FAIL_DB); + } + + // set rc to the return code of the operation to ensure the program + // use that to determine the proper exit_code. Look at the header + // sdbsc.h for expected values. + + exit_code = EXIT_OK; + switch (opt) + { + case 'a': + // arv[0] arv[1] arv[2] arv[3] arv[4] arv[5] + // prog_name -a id first_name last_name gpa + //------------------------------------------------------- + // example: prog_name -a 1 John Doe 341 + if (argc != 6) + { + usage(argv[0]); + exit_code = EXIT_FAIL_ARGS; + break; + } + + // convert id and gpa to ints from argv. For this assignment assume + // they are valid numbers + id = atoi(argv[2]); + gpa = atoi(argv[5]); + + exit_code = validate_range(id, gpa); + if (exit_code == EXIT_FAIL_ARGS) + { + printf(M_ERR_STD_RNG); + break; + } + + rc = add_student(fd, id, argv[3], argv[4], gpa); + if (rc < 0) + exit_code = EXIT_FAIL_DB; + + break; + + case 'c': + // arv[0] arv[1] + // prog_name -c + //----------------- + // example: prog_name -c + rc = count_db_records(fd); + if (rc < 0) + exit_code = EXIT_FAIL_DB; + break; + + case 'd': + // arv[0] arv[1] arv[2] + // prog_name -d id + //------------------------- + // example: prog_name -d 100 + if (argc != 3) + { + usage(argv[0]); + exit_code = EXIT_FAIL_ARGS; + break; + } + id = atoi(argv[2]); + rc = del_student(fd, id); + if (rc < 0) + exit_code = EXIT_FAIL_DB; + + break; + + case 'f': + // arv[0] arv[1] arv[2] + // prog_name -f id + //------------------------- + // example: prog_name -f 100 + if (argc != 3) + { + usage(argv[0]); + exit_code = EXIT_FAIL_ARGS; + break; + } + id = atoi(argv[2]); + rc = get_student(fd, id, &student); + + switch (rc) + { + case NO_ERROR: + print_student(&student); + break; + case SRCH_NOT_FOUND: + printf(M_STD_NOT_FND_MSG, id); + exit_code = EXIT_FAIL_DB; + break; + default: + printf(M_ERR_DB_READ); + exit_code = EXIT_FAIL_DB; + break; + } + break; + + case 'p': + // arv[0] arv[1] + // prog_name -p + //----------------- + // example: prog_name -p + rc = print_db(fd); + if (rc < 0) + exit_code = EXIT_FAIL_DB; + break; + + case 'x': + // arv[0] arv[1] + // prog_name -x + //----------------- + // example: prog_name -x + + // remember compress_db returns a fd of the compressed database. + // we close it after this switch statement + fd = compress_db(fd); + if (fd < 0) + exit_code = EXIT_FAIL_DB; + break; + + case 'z': + // arv[0] arv[1] + // prog_name -x + //----------------- + // example: prog_name -x + // HINT: close the db file, we already have fd + // and reopen db indicating truncate=true + close(fd); + fd = open_db(DB_FILE, true); + if (fd < 0) + { + exit_code = EXIT_FAIL_DB; + break; + } + printf(M_DB_ZERO_OK); + exit_code = EXIT_OK; + break; + default: + usage(argv[0]); + exit_code = EXIT_FAIL_ARGS; + } + + // dont forget to close the file before exiting, and setting the + // proper exit code - see the header file for expected values + close(fd); + exit(exit_code); +} diff --git a/Assignment2/sdbsc.h b/Assignment2/sdbsc.h new file mode 100644 index 0000000..79b08e7 --- /dev/null +++ b/Assignment2/sdbsc.h @@ -0,0 +1,64 @@ +#ifndef __SDB_H__ + +#include "db.h" //get student record type + +//prototypes for functions go below for this assignment +int open_db(char *dbFile, bool should_truncate); +int add_student(int fd, int id, char *fname, char *lname, int gpa); +int get_student(int fd, int id, student_t *s); +int del_student(int fd, int id); +int compress_db(int fd); +void print_student(student_t *s); +int validate_range(int id, int gpa); +int count_db_records(int fd); +int print_db(int fd); +void usage(char *); + +//error codes to be returned from individual functions +// NO_ERROR is returned if there are no errors +// ERR_DB_FILE is returned if there is are any issues with the database file itself +// ERR_DB_OP is returned if an operation did not work aka add or delete a student +// SRCH_NOT_FOUND is returned if the student is not found (get_student, and del_student) +#define NO_ERROR 0 +#define ERR_DB_FILE -1 +#define ERR_DB_OP -2 +#define SRCH_NOT_FOUND -3 +#define NOT_IMPLEMENTED_YET 0 + + +//error codes to be returned to the shell +// EXIT_OK program executed without error +// EXIT_FAIL_DB a database operation failed +// EXIT_FAIL_ARGS one or more arguments to program were not valid +// EXIT_NOT_IMPL the operation has not been implemented yet +#define EXIT_OK 0 +#define EXIT_FAIL_DB 1 +#define EXIT_FAIL_ARGS 2 +#define EXIT_NOT_IMPL 3 + +//Output messages +#define M_ERR_STD_RNG "Cant add student, either ID or GPA out of allowable range!\n" +#define M_ERR_DB_CREATE "Error creating DB file, exiting!\n" +#define M_ERR_DB_OPEN "Error opening DB file, exiting!\n" +#define M_ERR_DB_READ "Error reading DB file, exiting!\n" +#define M_ERR_DB_WRITE "Error writing DB file, exiting!\n" +#define M_ERR_DB_ADD_DUP "Cant add student with ID=%d, already exists in db.\n" +#define M_ERR_STD_PRINT "Cant print student. Student is NULL or ID is zero\n" + +#define M_STD_ADDED "Student %d added to database.\n" +#define M_STD_DEL_MSG "Student %d was deleted from database.\n" +#define M_STD_NOT_FND_MSG "Student %d was not found in database.\n" +#define M_DB_COMPRESSED_OK "Database successfully compressed!\n" +#define M_DB_ZERO_OK "All database records removed!\n" +#define M_DB_EMPTY "Database contains no student records.\n" +#define M_DB_RECORD_CNT "Database contains %d student record(s).\n" +#define M_NOT_IMPL "The requested operation is not implemented yet!\n" + +//useful format strings for print students +//For example to print the header in the required output: +// printf(STUDENT_PRINT_HDR_STRING, "ID","FIRST NAME", +// "LAST_NAME", "GPA"); +#define STUDENT_PRINT_HDR_STRING "%-6s %-24s %-32s %-3s\n" +#define STUDENT_PRINT_FMT_STRING "%-6d %-24.24s %-32.32s %-3.2f\n" + +#endif \ No newline at end of file diff --git a/Assignment2/student.db b/Assignment2/student.db new file mode 100644 index 0000000000000000000000000000000000000000..7bbdd80cdd5ce2c733b1a45675acf10340bc2567 GIT binary patch literal 192 zcmZQ%U|`6~&&XrI0#fo*v4|psA{iMNm_hmz^ROx;q`!@kfx#Z6KQk9$C=!d1epyBa F1^^j;33vbi literal 0 HcmV?d00001 diff --git a/Assignment2/test.sh b/Assignment2/test.sh new file mode 100755 index 0000000..a013095 --- /dev/null +++ b/Assignment2/test.sh @@ -0,0 +1,195 @@ +#!/usr/bin/env bats + +# The setup function runs before every test +setup_file() { + # Delete the student.db file if it exists + if [ -f "student.db" ]; then + rm "student.db" + fi +} + +@test "Check if database is empty to start" { + run ./sdbsc -p + [ "$status" -eq 0 ] + [ "$output" = "Database contains no student records." ] +} + +@test "Add a student 1 to db" { + run ./sdbsc -a 1 john doe 345 + [ "$status" -eq 0 ] + [ "${lines[0]}" = "Student 1 added to database." ] +} + +@test "Add more students to db" { + run ./sdbsc -a 3 jane doe 390 + [ "$status" -eq 0 ] + [ "${lines[0]}" = "Student 3 added to database." ] || { + echo "Failed Output: $output" + return 1 + } + + run ./sdbsc -a 63 jim doe 285 + [ "$status" -eq 0 ] + [ "${lines[0]}" = "Student 63 added to database." ] || { + echo "Failed Output: $output" + return 1 + } + + run ./sdbsc -a 64 janet doe 310 + [ "$status" -eq 0 ] + [ "${lines[0]}" = "Student 64 added to database." ] || { + echo "Failed Output: $output" + return 1 + } + + run ./sdbsc -a 99999 big dude 205 + [ "$status" -eq 0 ] + [ "${lines[0]}" = "Student 99999 added to database." ] || { + echo "Failed Output: $output" + return 1 + } +} + +@test "Check student count" { + run ./sdbsc -c + [ "$status" -eq 0 ] + [ "${lines[0]}" = "Database contains 5 student record(s)." ] || { + echo "Failed Output: $output" + return 1 + } +} + +@test "Make sure adding duplicate student fails" { + run ./sdbsc -a 63 dup student 300 + [ "$status" -eq 1 ] || { + echo "Expecting status of 1, got: $status" + return 1 + } + [ "${lines[0]}" = "Cant add student with ID=63, already exists in db." ] || { + echo "Failed Output: $output" + return 1 + } +} + +@test "Make sure the file size is correct at this time" { + run stat --format="%s" ./student.db + [ "$status" -eq 0 ] + [ "${lines[0]}" = "6400000" ] || { + echo "Failed Output: $output" + echo "Expected: 64000000" + return 1 + } +} + +@test "Find student 3 in db" { + run ./sdbsc -f 3 + + # Ensure the command ran successfully + [ "$status" -eq 0 ] + + # Use echo with -n to avoid adding extra newline and normalize spaces + normalized_output=$(echo -n "${lines[1]}" | tr -s '[:space:]' ' ') + + # Define the expected output + expected_output="3 jane doe 3.90" + + # Compare the normalized output with the expected output + [ "$normalized_output" = "$expected_output" ] || { + echo "Failed Output: $normalized_output" + echo "Expected: $expected_output" + return 1 + } +} + +@test "Try looking up non-existent student" { + run ./sdbsc -f 4 + [ "$status" -eq 1 ] || { + echo "Expecting status of 1, got: $status" + return 1 + } + [ "${lines[0]}" = "Student 4 was not found in database." ] || { + echo "Failed Output: $output" + return 1 + } +} + +@test "Delete student 64 in db" { + run ./sdbsc -d 64 + [ "$status" -eq 0 ] + [ "${lines[0]}" = "Student 64 was deleted from database." ] || { + echo "Failed Output: $output" + return 1 + } +} + +@test "Try deleting non-existent student" { + run ./sdbsc -d 65 + [ "$status" -eq 1 ] || { + echo "Expecting status of 1, got: $status" + return 1 + } + [ "${lines[0]}" = "Student 65 was not found in database." ] || { + echo "Failed Output: $output" + return 1 + } +} + +@test "Check student count again, should be 4 now" { + run ./sdbsc -c + [ "$status" -eq 0 ] + [ "${lines[0]}" = "Database contains 4 student record(s)." ] || { + echo "Failed Output: $output" + return 1 + } +} + +@test "Print student records" { + # Run the command + run ./sdbsc -p + + # Ensure the command ran successfully + [ "$status" -eq 0 ] + + # Normalize the output by replacing multiple spaces with a single space + normalized_output=$(echo -n "$output" | tr -s '[:space:]' ' ') + + # Define the expected output (normalized) + expected_output="ID FIRST_NAME LAST_NAME GPA 1 john doe 3.45 3 jane doe 3.90 63 jim doe 2.85 99999 big dude 2.05" + + # Compare the normalized output + [ "$normalized_output" = "$expected_output" ] || { + echo "Failed Output: $normalized_output" + echo "Expected Output: $expected_output" + return 1 + } +} + + +@test "Compress db - try 1" { + skip + run ./sdbsc -x + [ "$status" -eq 0 ] + [ "${lines[0]}" = "Database successfully compressed!" ] || { + echo "Failed Output: $output" + return 1 + } +} + + +@test "Delete student 99999 in db" { + run ./sdbsc -d 99999 + [ "$status" -eq 0 ] + [ "${lines[0]}" = "Student 99999 was deleted from database." ] || { + echo "Failed Output: $output" + return 1 + } +} + +@test "Compress db again - try 2" { + run ./sdbsc -x + [ "$status" -eq 0 ] + [ "${lines[0]}" = "Database successfully compressed!" ] || { + echo "Failed Output: $output" + return 1 + } +} \ No newline at end of file diff --git a/Assignment2/testload.sh b/Assignment2/testload.sh new file mode 100755 index 0000000..2f36a92 --- /dev/null +++ b/Assignment2/testload.sh @@ -0,0 +1,6 @@ +#! /bin/bash +./sdbsc -a 1 john doe 3.45 +./sdbsc -a 3 jane doe 3.90 +./sdbsc -a 63 jim doe 2.85 +./sdbsc -a 64 janet doe 3.10 +./sdbsc -a 99999 big dude 2.05 \ No newline at end of file -- GitLab