diff options
author | Tyler Murphy <tylerm@tylerm.dev> | 2023-06-07 21:33:44 -0400 |
---|---|---|
committer | Tyler Murphy <tylerm@tylerm.dev> | 2023-06-07 21:33:44 -0400 |
commit | 47e9c333620a0ca186efc00d2495b44fc887882f (patch) | |
tree | b94c4d0238d186d0f8d3a7fb5485d0cf784714de /command/cp.c | |
parent | slight refactor and start documenting (diff) | |
download | lazysphere-47e9c333620a0ca186efc00d2495b44fc887882f.tar.gz lazysphere-47e9c333620a0ca186efc00d2495b44fc887882f.tar.bz2 lazysphere-47e9c333620a0ca186efc00d2495b44fc887882f.zip |
more documentation
Diffstat (limited to '')
-rw-r--r-- | command/cp.c | 151 |
1 files changed, 110 insertions, 41 deletions
diff --git a/command/cp.c b/command/cp.c index 4c65a51..576a99b 100644 --- a/command/cp.c +++ b/command/cp.c @@ -1,3 +1,9 @@ +/** + * file: cp.c + * command: cp + * author: Tyler Murphy + */ + #include "command.h" #include "lslib.h" @@ -10,14 +16,20 @@ #include <errno.h> #include <unistd.h> +/** + * Command flags to be used with cp + */ static struct { - bool recurse; - bool preserve; - bool sym_link; - bool hard_link; - bool verbose; + bool recurse; /* Recurse copy directorys */ + bool preserve; /* Preserve file attributes */ + bool sym_link; /* Symlink files instead of copy */ + bool hard_link; /* Hardlink files instead of copy */ + bool verbose; /* Verbose the output */ } flags; +/** + * Help function for cp + */ static void help(void) { printf("Usage: cp [-rplsv] SOURCE... DEST\n\n"); printf("Copy SOURCEs to DEST\n\n"); @@ -27,6 +39,12 @@ static void help(void) { printf("\t-v\tVerbose\n"); } +/** + * Takes in each argument that has a single - and parses it + * @param c the character after the - + * @param next the next argument in argv that hasnt been parsed + * @reutrn if the next arg was used or if the arg was invalid + */ static int short_arg(char c, char* next) { UNUSED(next); switch (c) { @@ -54,24 +72,33 @@ static int short_arg(char c, char* next) { return ARG_UNUSED; } +/** + * Takes in two files paths and copies the data from one path to another + * @param from the file to copy from + * @param to the file to copy to + * @returns if the file successfully coppied + */ static bool copy_file(char* from, char* to) { - #define BS 1024 + #define BS 1024 /* The block size of copy with */ - FILE *from_f, *to_f; - char buf[BS]; - int read; + FILE *from_f, *to_f; /* file pointers to cope data from and to */ + char buf[BS]; /* te file copy buffer */ + int read; /* the amount of bytes read */ + /* attempt to get a read stream from the src file */ from_f = get_file_s(from, "r"); if (from_f == NULL) { return false; } + /* attempt to get a write streams from the dest file */ to_f = get_file_s(to, "w"); if (to_f == NULL) { fclose(from_f); return false; } - + /* while data is read copy the data to the dest */ while ((read = fread(buf, 1, BS, from_f)) > 0) { fwrite(buf, 1, read, to_f); } + /* output if verbose */ if (flags.verbose) { output("copied '%s'", from); } @@ -79,164 +106,206 @@ static bool copy_file(char* from, char* to) { return true; } +/** + * Takes in two file paths and symlinks from one to the other path + * @param from the file to symlink + * @param to the path to put the symlink + * @returns if the file successfully symlinked + */ static bool symlink_file(char* from, char* to) { + /* symlink the file and error if failed */ if (symlink(from, to) < 0) { error_s("failed to symlink '%s'", from); return false; } else if (flags.verbose) { - output("symlinked '%s'", from); + output("symlinked '%s'", from); /* output if verbose */ } return true; } +/** + * Takes in two file paths and hardlinks from one to the other path + * @param from the file to hardlink + * @param the path to put the hardlink + * @returns fi the fule successfully hardlinked + */ static bool hardlink_file(char* from, char* to) { + /* hard link the file and error if failed */ if (link(from, to) < 0) { error_s("failed to hardlink '%s'", from); return false; } else if (flags.verbose) { - output("hardlinked '%s'", from); + output("hardlinked '%s'", from); /* output if verbose */ } return true; } +/** + * Copies data from one path to another using the set path buffers and + * flags. Make sure to set these before running this function. + * @param s the stat of the file being coppied + */ static void run_copy(struct stat* s) { + /* read file paths from the path buffers */ char* from = get_path_buffer(); char* to = get_path_buffer_2(); + /* choose copy method based on given flags */ bool result; - if (flags.sym_link) { - result = symlink_file(from, to); + if (flags.sym_link) { + result = symlink_file(from, to); /* symlink */ } else if (flags.hard_link) { - result = hardlink_file(from, to); + result = hardlink_file(from, to); /* hardlink */ } else { - result = copy_file(from, to); + result = copy_file(from, to); /* copy */ } + /* if failed return */ if (!result) return; if (!flags.preserve) return; + /* if set to preserve file attribs, copy over ownership and permissions */ if (chmod(to, s->st_mode) < 0) { - error_s("cannot chmod '%s'", to); + error_s("cannot chmod '%s'", to); /* error if failed */ return; } if (chown(to, s->st_uid, s->st_gid) < 0) { - error_s("cannot chown '%s'", to); + error_s("cannot chown '%s'", to); /* error if failed */ return; } } +/* predefine function definition */ static void cp_file(char* path); +/** + * Copies all files in a diretory specified in the path buffer, to the dest. + * Make sure both the src and dest path buffers are set before calling. + * @param s the stat of the directory + */ static void cp_directory(struct stat* s) { DIR* d; struct dirent* file; + /* if were not recursing ignore directory and error */ if (!flags.recurse) { error_s("-r not specified; omitting directory '%s'", get_path_buffer()); return; } + /* if we failed to make the directory to copy data into error and return */ if (mkdir(get_path_buffer_2(), s->st_mode) < 0 && errno != EEXIST) { error_s("cannot create directory '%s'", get_path_buffer_2()); return; } + /* open directory, if failed error and return */ d = opendir(get_path_buffer()); - if (d == NULL) { error_s("cannot open directory '%s'", get_path_buffer()); return; } + /* copy each file in the directory */ while ((file = readdir(d)) != NULL) { if (is_dot_dir(file->d_name)) continue; cp_file(file->d_name); } } -static char* get_file_name(char* path) { - int last = 0; - int i = 0; - - if (path[0] == '\0') return path; - - while (true) { - if (path[i+1] == '\0') break; - if (path[i] == '/') { - last = i; - } - i++; - } - - if (last == 0) return path; - else return path + last + 1; -} - +/** + * Copies a given file path to the destination given in the 2nd path buffer + * Make sure path buffer 2 is set before running this function + * @param path the file to copy + */ static void cp_file(char* path) { + /* load src and dest into path buffers */ int save = push_path_buffer(path); - int save2 = push_path_buffer_2(get_file_name(path)); - + int save2 = push_path_buffer_2(get_last_component(path)); + + /* if we cannot get file info error and return */ struct stat s; if (lstat(get_path_buffer(), &s) < 0) { pop_path_buffer(save); error_s("cannot stat '%s'", get_path_buffer()); return; } - + + /* if the file is a directory copy it as a directory, else copy it as a file */ if (S_ISDIR(s.st_mode)) { cp_directory(&s); } else { run_copy(&s); } + /* cleanup */ pop_path_buffer(save); pop_path_buffer_2(save2); } +/** + * Copes file from a src path to a dest path + */ COMMAND(cp_main) { int start, i; struct stat s; + /* define default flags */ flags.hard_link = false; flags.sym_link = false; flags.preserve = false; flags.recurse = false; flags.verbose = false; + /* parse arguments */ start = parse_args(argc, argv, help, short_arg, NULL); + /* if not enough arguments passed show help message and quit */ if (argc - start < 2) { global_help(help); } /* only when 2 args and first is a file, the 2nd will be a file */ if (argc - start == 2) { + + /* if cannot read file info error and exit */ struct stat s; if (lstat(argv[start], &s) < 0) { error("cannot stat '%s'", argv[start]); } + + /* load src and dest into path buffers */ push_path_buffer(argv[argc-2]); push_path_buffer_2(argv[argc-1]); + + /* if the file is a directory copy it as a directory, else copy it as a file */ if (!S_ISDIR(s.st_mode)) { run_copy(&s); } else { cp_directory(&s); } + + /* no need to cleanup path buffers since command is done */ + return EXIT_SUCCESS; } + + /* otherwise treat the dest argument as a directory */ - /* push directory */ + /* push dest directory */ push_path_buffer_2(argv[argc-1]); + /* if we cannot read dest info error and return */ if (lstat(get_path_buffer_2(), &s) < 0) { error("target: '%s'", get_path_buffer_2()); } + /* copy each file into dest directory */ for (i = start; i < argc - 1; i++) { cp_file(argv[i]); } |