└── hw1 ├── .gitignore ├── Makefile ├── beargit.c ├── beargit.h ├── init_test ├── main.c ├── tester.pyc └── util.h /hw1/.gitignore: -------------------------------------------------------------------------------- 1 | autotest 2 | test 3 | beargit 4 | -------------------------------------------------------------------------------- /hw1/Makefile: -------------------------------------------------------------------------------- 1 | beargit: main.c beargit.c beargit.h util.h 2 | gcc -std=c99 main.c beargit.c -o beargit 3 | 4 | clean: 5 | rm -rf beargit autotest test 6 | 7 | check:: 8 | ifndef INSTMANPATH 9 | $(error You need to run 'make check' on an instructional machine, such as hive*.cs.berkeley.edu) 10 | endif 11 | python2.7 tester.pyc beargit.c 12 | -------------------------------------------------------------------------------- /hw1/beargit.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | 7 | #include "beargit.h" 8 | #include "util.h" 9 | 10 | /* Implementation Notes: 11 | * 12 | * - Functions return 0 if successful, 1 if there is an error. 13 | * - All error conditions in the function description need to be implemented 14 | * and written to stderr. We catch some additional errors for you in main.c. 15 | * - Output to stdout needs to be exactly as specified in the function description. 16 | * - Only edit this file (beargit.c) 17 | * - You are given the following helper functions: 18 | * * fs_mkdir(dirname): create directory 19 | * * fs_rm(filename): delete file 20 | * * fs_mv(src,dst): move file to , overwriting if it exists 21 | * * fs_cp(src,dst): copy file to , overwriting if it exists 22 | * * write_string_to_file(filename,str): write to filename (overwriting contents) 23 | * * read_string_from_file(filename,str,size): read a string of at most (incl. 24 | * NULL character) from file and store it into . Note that 25 | * needs to be large enough to hold that string. 26 | * - You NEED to test your code. The autograder we provide does not contain the 27 | * full set of tests that we will run on your code. See "Step 5" in the homework spec. 28 | */ 29 | 30 | /* beargit init 31 | * 32 | * - Create .beargit directory 33 | * - Create empty .beargit/.index file 34 | * - Create .beargit/.prev file containing 0..0 commit id 35 | * 36 | * Output (to stdout): 37 | * - None if successful 38 | */ 39 | 40 | int beargit_init(void) { 41 | fs_mkdir(".beargit"); 42 | 43 | FILE* findex = fopen(".beargit/.index", "w"); 44 | fclose(findex); 45 | 46 | write_string_to_file(".beargit/.prev", "0000000000000000000000000000000000000000"); 47 | 48 | return 0; 49 | } 50 | 51 | 52 | /* beargit add 53 | * 54 | * - Append filename to list in .beargit/.index if it isn't in there yet 55 | * 56 | * Possible errors (to stderr): 57 | * >> ERROR: File already added 58 | * 59 | * Output (to stdout): 60 | * - None if successful 61 | */ 62 | 63 | int beargit_add(const char* filename) { 64 | FILE* findex = fopen(".beargit/.index", "r"); 65 | FILE *fnewindex = fopen(".beargit/.newindex", "w"); 66 | 67 | char line[FILENAME_SIZE]; 68 | while(fgets(line, sizeof(line), findex)) { 69 | strtok(line, "\n"); 70 | if (strcmp(line, filename) == 0) { 71 | fprintf(stderr, "ERROR: File %s already added\n", filename); 72 | fclose(findex); 73 | fclose(fnewindex); 74 | fs_rm(".beargit/.newindex"); 75 | return 3; 76 | } 77 | 78 | fprintf(fnewindex, "%s\n", line); 79 | } 80 | 81 | fprintf(fnewindex, "%s\n", filename); 82 | fclose(findex); 83 | fclose(fnewindex); 84 | 85 | fs_mv(".beargit/.newindex", ".beargit/.index"); 86 | 87 | return 0; 88 | } 89 | 90 | 91 | /* beargit rm 92 | * 93 | * See "Step 2" in the homework 1 spec. 94 | * 95 | */ 96 | 97 | int beargit_rm(const char* filename) { 98 | /* COMPLETE THE REST */ 99 | 100 | return 0; 101 | } 102 | 103 | /* beargit commit -m 104 | * 105 | * See "Step 3" in the homework 1 spec. 106 | * 107 | */ 108 | 109 | const char* go_bears = "GO BEARS!"; 110 | 111 | int is_commit_msg_ok(const char* msg) { 112 | /* COMPLETE THE REST */ 113 | return 0; 114 | } 115 | 116 | void next_commit_id(char* commit_id) { 117 | /* COMPLETE THE REST */ 118 | } 119 | 120 | int beargit_commit(const char* msg) { 121 | if (!is_commit_msg_ok(msg)) { 122 | fprintf(stderr, "ERROR: Message must contain \"%s\"\n", go_bears); 123 | return 1; 124 | } 125 | 126 | char commit_id[COMMIT_ID_SIZE]; 127 | read_string_from_file(".beargit/.prev", commit_id, COMMIT_ID_SIZE); 128 | next_commit_id(commit_id); 129 | 130 | /* COMPLETE THE REST */ 131 | 132 | return 0; 133 | } 134 | 135 | /* beargit status 136 | * 137 | * See "Step 1" in the homework 1 spec. 138 | * 139 | */ 140 | 141 | int beargit_status() { 142 | /* COMPLETE THE REST */ 143 | 144 | return 0; 145 | } 146 | 147 | /* beargit log 148 | * 149 | * See "Step 4" in the homework 1 spec. 150 | * 151 | */ 152 | 153 | int beargit_log() { 154 | /* COMPLETE THE REST */ 155 | 156 | return 0; 157 | } 158 | -------------------------------------------------------------------------------- /hw1/beargit.h: -------------------------------------------------------------------------------- 1 | int beargit_init(void); 2 | int beargit_add(const char* filename); 3 | int beargit_rm(const char* filename); 4 | int beargit_commit(const char* message); 5 | int beargit_status(); 6 | int beargit_log(); 7 | 8 | // Number of bytes in a commit id 9 | #define COMMIT_ID_BYTES 40 10 | 11 | // Preprocessor macros capturing the maximum size of different structures 12 | #define FILENAME_SIZE 512 13 | #define COMMIT_ID_SIZE (COMMIT_ID_BYTES+1) 14 | #define MSG_SIZE 512 15 | -------------------------------------------------------------------------------- /hw1/init_test: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ ! -f "beargit.c" ]; then 4 | echo "ERROR: Need to run "source init_test" from your source directory" 5 | return 6 | fi 7 | 8 | if [ -d "test" ]; then 9 | if [ -f "test/.BEARGIT_TEST_IGNORE_ME" ]; then 10 | rm -rf test 11 | else 12 | echo "ERROR: A test directory already exists, but it was not created by make. Please manually delete or move this directory and try again." 13 | return 14 | fi 15 | fi 16 | 17 | make beargit 18 | 19 | mkdir test 20 | touch test/.BEARGIT_TEST_IGNORE_ME 21 | 22 | if [[ ! "$PATH" =~ "$PWD" ]]; then 23 | export PATH=$PWD:$PATH 24 | fi 25 | 26 | cd test 27 | echo 28 | echo '*** WELCOME TO YOUR BEARGIT TEST DIRECTORY ***' 29 | echo 30 | echo 'You are now in the $PWD directory, which is a brand-new directory created for' 31 | echo 'you to test out your beargit implementation. Your source directory has also' 32 | echo 'been added to the PATH, so you can just type commands such as "beargit init" to' 33 | echo 'try out your implementation.' 34 | echo 35 | echo 'To get back to your source code, just go one directory up. You can delete this' 36 | echo 'directory and create a new one anytime by typing "source init_test" again from' 37 | echo 'your source directory.' 38 | echo 39 | echo 'Hint: You may want to use the "touch " command to generate files for' 40 | echo 'testing. This will create an empty file with a certain name.' 41 | echo 42 | -------------------------------------------------------------------------------- /hw1/main.c: -------------------------------------------------------------------------------- 1 | /** 2 | * This file contains functionality to parse command line arguments. Do not modify! 3 | */ 4 | 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | 11 | #include "beargit.h" 12 | 13 | int check_initialized(void) { 14 | struct stat s; 15 | int ret_code = stat(".beargit", &s); 16 | return !(ret_code == -1 || !(S_ISDIR(s.st_mode))); 17 | } 18 | 19 | int check_filename(const char* filename) { 20 | if (strlen(filename) > FILENAME_SIZE-1 || strlen(filename) == 0) 21 | return 0; 22 | 23 | if (filename[0] == '.') 24 | return 0; 25 | 26 | struct stat s; 27 | int ret_code = stat(filename, &s); 28 | return (ret_code != -1 && !(S_ISDIR(s.st_mode))); 29 | } 30 | 31 | int main(int argc, char **argv) { 32 | if (argc < 2) { 33 | fprintf(stderr, "Usage: %s []\n", argv[0]); 34 | return 2; 35 | } 36 | 37 | // TODO: If students aren't going to write this themselves, replace by clean 38 | // implementation using function pointers. 39 | if (strcmp(argv[1], "init") == 0) { 40 | 41 | if (check_initialized()) { 42 | fprintf(stderr, "ERROR: Repository is already initialized\n"); 43 | return 1; 44 | } 45 | 46 | return beargit_init(); 47 | 48 | } else { 49 | 50 | if (!check_initialized()) { 51 | fprintf(stderr, "ERROR: Repository is not initialized\n"); 52 | return 1; 53 | } 54 | 55 | if (strcmp(argv[1], "add") == 0 || strcmp(argv[1], "rm") == 0) { 56 | 57 | if (argc < 3 || !check_filename(argv[2])) { 58 | fprintf(stderr, "ERROR: No or invalid filname given\n"); 59 | return 1; 60 | } 61 | 62 | if (strcmp(argv[1], "rm") == 0) { 63 | return beargit_rm(argv[2]); 64 | } else { 65 | return beargit_add(argv[2]); 66 | } 67 | 68 | } else if (strcmp(argv[1], "commit") == 0) { 69 | 70 | if (argc < 4 || strcmp(argv[2], "-m") != 0) { 71 | fprintf(stderr, "ERROR: Need a commit message (-m )\n"); 72 | return 1; 73 | } 74 | 75 | if (strlen(argv[3]) > MSG_SIZE-1) { 76 | fprintf(stderr, "ERROR: Message is too long!\n"); 77 | return 1; 78 | } 79 | 80 | return beargit_commit(argv[3]); 81 | 82 | } else if (strcmp(argv[1], "status") == 0) { 83 | return beargit_status(); 84 | } else if (strcmp(argv[1], "log") == 0) { 85 | return beargit_log(); 86 | } else { 87 | fprintf(stderr, "ERROR: Unknown command \"%s\"\n", argv[1]); 88 | return 1; 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /hw1/tester.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cs61c-spring2015/hw1_starter/HEAD/hw1/tester.pyc -------------------------------------------------------------------------------- /hw1/util.h: -------------------------------------------------------------------------------- 1 | /** 2 | * This file contains utility functions to use in the homework. Do not modify! 3 | */ 4 | #include 5 | 6 | #define ASSERT_ERROR_MESSAGE(fn, msg) \ 7 | if (!(fn)) { \ 8 | fprintf(stderr, "\n *** AN ERROR OCCURRED IN %s ***\n\n", __func__); \ 9 | fprintf(stderr, " This should not happen. Most likely, you tried to access\n"); \ 10 | fprintf(stderr, " or manipulate a file that doesn't exist, or create one\n"); \ 11 | fprintf(stderr, " that already does. You should first try to delete the\n"); \ 12 | fprintf(stderr, " .beargit directory and start over; maybe a previous run\n"); \ 13 | fprintf(stderr, " corrupted it. If not, you need to fix the problem in\n"); \ 14 | fprintf(stderr, " your program -- the following error message might give\n"); \ 15 | fprintf(stderr, " more information about what went wrong:\n\n"); \ 16 | fprintf(stderr, " Error in %s: %s\n\n", __func__, msg); \ 17 | exit(1); \ 18 | } 19 | 20 | int is_sane_path(const char* path) { 21 | if (strlen(path) > 512) 22 | return 0; 23 | 24 | // Only allow modifying files in .beargit directory 25 | const char* prefix = ".beargit"; 26 | if (strncmp(prefix, path, strlen(prefix)) != 0) 27 | return 0; 28 | 29 | return 1; 30 | } 31 | 32 | static void fs_mkdir(const char* dirname) { 33 | ASSERT_ERROR_MESSAGE(dirname != NULL, "dirname is not a valid string"); 34 | ASSERT_ERROR_MESSAGE(is_sane_path(dirname), "dirname is not a valid path within .beargit"); 35 | int ret = mkdir(dirname, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); 36 | ASSERT_ERROR_MESSAGE(ret == 0, "creating directory failed"); 37 | } 38 | 39 | static void fs_rm(const char* filename) { 40 | ASSERT_ERROR_MESSAGE(filename != NULL, "filename is not a valid string"); 41 | ASSERT_ERROR_MESSAGE(is_sane_path(filename), "filename is not a valid path within .beargit"); 42 | int ret = unlink(filename); 43 | ASSERT_ERROR_MESSAGE(ret == 0, "deleting/unlinking file failed"); 44 | } 45 | 46 | static void fs_mv(const char* src, const char* dst) { 47 | ASSERT_ERROR_MESSAGE(src != NULL, "src is not a valid string"); 48 | ASSERT_ERROR_MESSAGE(dst != NULL, "dst is not a valid string"); 49 | ASSERT_ERROR_MESSAGE(is_sane_path(src), "src is not a valid path within .beargit"); 50 | ASSERT_ERROR_MESSAGE(is_sane_path(dst), "dst is not a valid path within .beargit"); 51 | int ret = rename(src, dst); 52 | ASSERT_ERROR_MESSAGE(ret == 0, "renaming file failed"); 53 | } 54 | 55 | static void fs_cp(const char* src, const char* dst) { 56 | ASSERT_ERROR_MESSAGE(src != NULL, "src is not a valid string"); 57 | ASSERT_ERROR_MESSAGE(dst != NULL, "dst is not a valid string"); 58 | ASSERT_ERROR_MESSAGE(is_sane_path(dst), "dst is not a valid path within .beargit"); 59 | 60 | FILE* fin = fopen(src, "r"); 61 | ASSERT_ERROR_MESSAGE(fin != NULL, "couldn't open source file"); 62 | FILE* fout = fopen(dst, "w"); 63 | ASSERT_ERROR_MESSAGE(fout != NULL, "couldn't open destination file"); 64 | 65 | char buffer[4096]; 66 | int size; 67 | 68 | while ((size = fread(buffer, 1, 4096, fin)) > 0) { 69 | fwrite(buffer, 1, size, fout); 70 | } 71 | 72 | fclose(fin); 73 | fclose(fout); 74 | } 75 | 76 | static void write_string_to_file(const char* filename, const char* str) { 77 | FILE* fout = fopen(filename, "w"); 78 | ASSERT_ERROR_MESSAGE(fout != NULL, "couldn't open file"); 79 | fwrite(str, 1, strlen(str)+1, fout); 80 | fclose(fout); 81 | } 82 | 83 | static void read_string_from_file(const char* filename, char* str, int size) { 84 | FILE* fin = fopen(filename, "r"); 85 | ASSERT_ERROR_MESSAGE(fin != NULL, "couldn't open file"); 86 | int real_size = fread(str, 1, size, fin); 87 | fclose(fin); 88 | } 89 | 90 | --------------------------------------------------------------------------------