Author | Jamozed <[email protected]> |
Date | 2021-03-07 10:52:19 |
Commit | d920c1b2ac2bcd8572bb8c12fdfbbc47997d452f |
Parent | 5604fd4227f55f2664e88e5dba7c239ac1e7c54b |
cp: Add POSIX cp
Diffstat
M | CMakeLists.txt | | | 4 | +--- |
M | README.md | | | 1 | + |
A | src/cp.c | | | 136 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
3 files changed, 138 insertions, 3 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 31d8742..c9c3c12 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,3 @@ -# CMakeLists.txt -# CMakeLists file for OMKOV coreutils - CMAKE_MINIMUM_REQUIRED(VERSION 3.12) PROJECT(coreutils LANGUAGES C) @@ -19,6 +16,7 @@ ADD_EXECUTABLE(basename ${PROJECT_SOURCE_DIR}/src/basename.c) ADD_EXECUTABLE(cat ${PROJECT_SOURCE_DIR}/src/cat.c) ADD_EXECUTABLE(chmod ${PROJECT_SOURCE_DIR}/src/chmod.c) ADD_EXECUTABLE(cksum ${PROJECT_SOURCE_DIR}/src/cksum.c) +ADD_EXECUTABLE(cp ${PROJECT_SOURCE_DIR}/src/cp.c) ADD_EXECUTABLE(dirname ${PROJECT_SOURCE_DIR}/src/dirname.c) ADD_EXECUTABLE(echo ${PROJECT_SOURCE_DIR}/src/echo.c) ADD_EXECUTABLE(env ${PROJECT_SOURCE_DIR}/src/env.c) diff --git a/README.md b/README.md index 3d60fd1..055f54a 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,7 @@ UNIX-like systems. | cat | Concatenate and print files | POSIX | | chmod | Change the file modes | POSIX | | cksum | Write file checksums and sizes | POSIX | +| cp | Copy files | POSIX | | dirname | Return the directory portion of a path | POSIX | | echo | Write arguments to standard output | POSIX | | env | Execute with an altered enviroment | POSIX | diff --git a/src/cp.c b/src/cp.c new file mode 100644 index 0000000..15d877b --- /dev/null +++ b/src/cp.c @@ -0,0 +1,136 @@ +// cp.c, version 0.0.1 +// OMKOV coreutils implementation of POSIX cksum +// Copyright (C) 2021, Jakob Wakeling +// All rights reserved. + +/* +OMKOV Permissive Licence, version 1.0 + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal with +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimers. +* Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimers in the documentation and/or + other materials provided with the distribution. +* Neither the names of the copyright holders, nor the names of its contributors + may be used to endorse or promote products derived from this Software without + specific prior written permission. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT +HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE. +*/ + +#include "lib/error.h" +#include "lib/optget.h" + +#include <sys/stat.h> + +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> + +#define VERSION "0.0.1" + +static struct lop lops[] = { + { "help", ARG_NUL, 256 }, + { "version", ARG_NUL, 257 }, + { NULL, 0, 0 } +}; + +static bool fflag, Hflag, iflag, Lflag, Pflag, pflag, Rflag; + +static inline void cp(const char *src, const char *dst); +static inline bool fsame(FILE *f1, FILE *f2); + +static void hlp(void); +static void ver(void); + +int main(int ac, char *av[]) { A0 = av[0]; + struct opt opt = OPTGET_INIT; opt.str = "fHiLPpR"; opt.lops = lops; + for (int o; (o = optget(&opt, av, 1)) != -1;) switch (o) { + case 'f': { fflag = true; break; } + case 'H': { Hflag = true; break; } + case 'i': { iflag = true; break; } + case 'L': { Lflag = true; break; } + case 'P': { Pflag = true; break; } + case 'p': { pflag = true; break; } + case 'R': { Rflag = true; break; } + case 256: { hlp(); return 0; } + case 257: { ver(); return 0; } + default: { return 1; } + } + + if (opt.ind == ac) { error(1, "missing source operand"); } + else if (opt.ind == ac - 1) { error(1, "missing destination operand"); } + else { cp(av[opt.ind], av[opt.ind + 1]); } + + return warned; +} + +/* Copy a file to a specified destination */ +static inline void cp(const char *src, const char *dst) { + uint8_t b[BUFSIZ * 16]; FILE *fi = NULL, *fo = NULL; struct stat st; + + if (!(fi = fopen(src, "rb"))) { warn("%s: %s", src, serr()); goto end; } + if (!(fo = fopen(dst, "wb"))) { warn("%s: %s", dst, serr()); goto end; } + + if (fsame(fi, fo)) { warn("%s, %s: same file", src, dst); goto end; } + + for (register size_t c; (c = fread(b, 1, sizeof (b), fi));) { + if (fwrite(b, 1, c, fo) != c) { warn("%s: %s", dst, serr()); goto end; } + } + + // Copy permissions from src to destination + if (stat(src, &st)) { warn("%s: %s", src, serr()); goto end; } + if (chmod(dst, st.st_mode)) { warn("%s: %s", dst, serr()); goto end; } + +end:; + if (fi && fclose(fi)) { warn("%s: %s", src, serr()); } + if (fo && fclose(fo)) { warn("%s: %s", dst, serr()); } + return; +} + +/* Check if two FILEs point to the same file */ +static inline bool fsame(FILE *f1, FILE *f2) { + struct stat s1, s2; fstat(fileno(f1), &s1); fstat(fileno(f2), &s2); + return (s1.st_dev == s2.st_dev) && (s1.st_ino == s2.st_ino); +} + +/* Print help information */ +static void hlp(void) { + puts("cp - Copy files"); + puts("\nUsage:"); + puts(" cp [-Pfip] source destination"); + puts(" cp [-Pfip] source... destination"); + puts(" cp -R [-H|-L|-P] [-fip] source... destination"); + puts("\nOptions:"); + puts(" -f UNIMPLEMENTED"); + puts(" -H UNIMPLEMENTED"); + puts(" -i UNIMPLEMENTED"); + puts(" -L UNIMPLEMENTED"); + puts(" -P UNIMPLEMENTED"); + puts(" -p UNIMPLEMENTED"); + puts(" -R UNIMPLEMENTED"); + puts(" --help Display help information"); + puts(" --version Display version information"); + return; +} + +/* Print version information */ +static void ver(void) { + puts("OMKOV coreutils cp, version " VERSION); + puts("Copyright (C) 2021, Jakob Wakeling"); + puts("All rights reserved."); + puts("OMKOV Permissive Licence (https://www.omkov.net/OLPE)"); + return; +}