#include #include #include #include #include #include #include #include #include #include #include "make_path.h" #include "get_stat.h" #include "config.h" static char *f_flag = "cp"; static char r_flag; static char v_flag; static char L_flag; static char copy_reg(int mode, const char *src, const char *dst) { int ret = 1; int ifd = open(src, O_RDONLY); if (ifd < 0) return 1; int ofd = open(dst, O_WRONLY | O_TRUNC | O_CREAT, mode); if (ofd < 0) goto CLOSE_OFD; char buf[BUF_SIZE + 1]; while (1) { ssize_t n = read(ifd, buf, sizeof(buf)); if (n <= 0) { if (n < 0) goto CLOSE; break; } if (write(ofd, buf, n) != n) goto CLOSE; } ret = 0; CLOSE: close(ofd); CLOSE_OFD: close(ifd); return ret; } static char copy_lnk(const char *src, const char *dst) { char path[PATH_MAX + 1]; ssize_t ret = readlink(src, path, sizeof(path)); if (ret < 0) return 1; path[ret] = '\0'; if (symlink(path, dst) < 0) return 1; return 0; } static char copy(struct stat st, const char *src, const char *dst) { if (v_flag) printf("Copying '%s' to '%s'\n", src, dst); if (S_ISLNK(st.st_mode)) return copy_lnk(src, dst); else if (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode) || S_ISFIFO(st.st_mode)) { if (mknod(dst, st.st_mode, st.st_dev) < 0) return 1; } else return copy_reg(st.st_mode, src, dst); return 0; } static int cptree(const char *src, const char *dst) { struct stat src_stat; if (mu_get_stats(f_flag, !L_flag, src, &src_stat)) return 1; if (!S_ISDIR(src_stat.st_mode)) { if (copy(src_stat, src, dst)) { if (f_flag) fprintf(stderr, "cp: %s: %s\n", dst, strerror(errno)); return 1; } return 0; } else if (!r_flag) { if (f_flag) fprintf(stderr, "cp: omitting directory: %s\n", dst); return 1; } else if (mkdir(dst, 0777) < 0) { if (f_flag) fprintf(stderr, "cp: %s: %s\n", dst, strerror(errno)); return 1; } DIR *dir = opendir(src); if (dir == NULL) { if (f_flag) fprintf(stderr, "cp: %s: Can`t open directory\n", src); return 1; } int ret = 0; struct dirent *ep; while ((ep = readdir(dir)) != NULL) { if (!strcmp(ep->d_name, ".") || !strcmp(ep->d_name, "..") || !strcmp(dst, ep->d_name)) continue; /* Copy */ char *src_path = mu_make_path(f_flag, src, ep->d_name); if (src_path == NULL) continue; char *dst_path = mu_make_path(f_flag, dst, ep->d_name); if (dst_path == NULL) { free(src_path); continue; } if (cptree(src_path, dst_path)) ret = 1; free(src_path); free(dst_path); if (ret) break; } closedir(dir); return ret; } int main(int argc, char **argv) { int opt; while ((opt = getopt(argc, argv, "frvL")) != -1) { switch (opt) { case 'f': f_flag = NULL; break; case 'r': r_flag = 1; break; case 'v': v_flag = 1; break; case 'L': L_flag = 1; break; default: printf("cp [frvL] [src1 src2...] [dst]\n\t-f Silent\n\t-r Recursive\n\t-v Verbose\n\t-L Follow all symlinks\n"); return 0; } } argv += optind; argc -= optind; if (argc < 2) { fprintf(stderr, "cp: missing operand\n"); return 1; } int ret = 0; struct stat sb; if (!mu_get_stat(NULL, argv[argc - 1], &sb)) if (S_ISDIR(sb.st_mode)) goto IF_EXSIST; if (argc == 2) ret = cptree(argv[0], argv[argc - 1]); else { IF_EXSIST: for (int i = 0; i < argc - 1; i++) { char *new_path = mu_make_path(f_flag, argv[argc - 1], basename(argv[i])); if (new_path == NULL) return 1; if (cptree(argv[i], new_path)) ret = 1; free(new_path); } } return ret; }