// cp.c, version 0.0.2 // OMKOV coreutils implementation of POSIX cp // Copyright (C) 2021, Jakob Wakeling // MIT Licence #include "util/error.h" #include "util/optget.h" #include #include #include #include #define VERSION "0.0.2" 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 *dst, char *const *src, size_t n); static inline void fcopy(const char *dst, const char *src); 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[ac - 1], &av[opt.ind], ac - opt.ind - 1); } return warned; } /* Copy one or more files to a specified destination */ static inline void cp(const char *dst, char *const *src, size_t n) { return fcopy(dst, *src); } /* Copy a file to a specified destination */ static inline void fcopy(const char *dst, const char *src) { 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"); } /* Print version information */ static void ver(void) { puts("OMKOV coreutils cp, version " VERSION); puts("Copyright (C) 2021, Jakob Wakeling"); puts("MIT Licence (https://opensource.org/licenses/MIT)"); }