summaryrefslogtreecommitdiff
path: root/command/cp.c
diff options
context:
space:
mode:
authorTyler Murphy <tylerm@tylerm.dev>2023-06-07 21:33:44 -0400
committerTyler Murphy <tylerm@tylerm.dev>2023-06-07 21:33:44 -0400
commit47e9c333620a0ca186efc00d2495b44fc887882f (patch)
treeb94c4d0238d186d0f8d3a7fb5485d0cf784714de /command/cp.c
parentslight refactor and start documenting (diff)
downloadlazysphere-47e9c333620a0ca186efc00d2495b44fc887882f.tar.gz
lazysphere-47e9c333620a0ca186efc00d2495b44fc887882f.tar.bz2
lazysphere-47e9c333620a0ca186efc00d2495b44fc887882f.zip
more documentation
Diffstat (limited to '')
-rw-r--r--command/cp.c151
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]);
}