cp.c - sbase - suckless unix tools
 (HTM) git clone git://git.suckless.org/sbase
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
       cp.c (3791B)
       ---
            1 /* See LICENSE file for copyright and license details. */
            2 #include <dirent.h>
            3 #include <errno.h>
            4 #include <fcntl.h>
            5 #include <limits.h>
            6 #include <stdio.h>
            7 #include <stdlib.h>
            8 #include <string.h>
            9 #include <sys/stat.h>
           10 #include <sys/types.h>
           11 #include <unistd.h>
           12 #include <utime.h>
           13 
           14 #include "../fs.h"
           15 #include "../util.h"
           16 
           17 int cp_aflag  = 0;
           18 int cp_fflag  = 0;
           19 int cp_iflag  = 0;
           20 int cp_pflag  = 0;
           21 int cp_rflag  = 0;
           22 int cp_vflag  = 0;
           23 int cp_status = 0;
           24 int cp_follow;
           25 
           26 int
           27 cp(const char *s1, const char *s2, int depth)
           28 {
           29         DIR *dp;
           30         int f1, f2, flags = 0;
           31         struct dirent *d;
           32         struct stat st;
           33         struct timespec times[2];
           34         ssize_t r;
           35         char target[PATH_MAX], ns1[PATH_MAX], ns2[PATH_MAX];
           36 
           37         if (cp_follow == 'P' || (cp_follow == 'H' && depth))
           38                 flags |= AT_SYMLINK_NOFOLLOW;
           39 
           40         if (fstatat(AT_FDCWD, s1, &st, flags) < 0) {
           41                 weprintf("stat %s:", s1);
           42                 cp_status = 1;
           43                 return 0;
           44         }
           45 
           46         if (cp_iflag && access(s2, F_OK) == 0) {
           47                 if (!confirm("overwrite '%s'? ", s2))
           48                         return 0;
           49         }
           50 
           51         if (cp_vflag)
           52                 printf("%s -> %s\n", s1, s2);
           53 
           54         if (S_ISLNK(st.st_mode)) {
           55                 if ((r = readlink(s1, target, sizeof(target) - 1)) >= 0) {
           56                         target[r] = '\0';
           57                         if (cp_fflag && unlink(s2) < 0 && errno != ENOENT) {
           58                                 weprintf("unlink %s:", s2);
           59                                 cp_status = 1;
           60                                 return 0;
           61                         } else if (symlink(target, s2) < 0) {
           62                                 weprintf("symlink %s -> %s:", s2, target);
           63                                 cp_status = 1;
           64                                 return 0;
           65                         }
           66                 }
           67         } else if (S_ISDIR(st.st_mode)) {
           68                 if (!cp_rflag) {
           69                         weprintf("%s is a directory\n", s1);
           70                         cp_status = 1;
           71                         return 0;
           72                 }
           73                 if (!(dp = opendir(s1))) {
           74                         weprintf("opendir %s:", s1);
           75                         cp_status = 1;
           76                         return 0;
           77                 }
           78                 if (mkdir(s2, st.st_mode) < 0 && errno != EEXIST) {
           79                         weprintf("mkdir %s:", s2);
           80                         cp_status = 1;
           81                         closedir(dp);
           82                         return 0;
           83                 }
           84 
           85                 while ((d = readdir(dp))) {
           86                         if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
           87                                 continue;
           88 
           89                         estrlcpy(ns1, s1, sizeof(ns1));
           90                         if (s1[strlen(s1) - 1] != '/')
           91                                 estrlcat(ns1, "/", sizeof(ns1));
           92                         estrlcat(ns1, d->d_name, sizeof(ns1));
           93 
           94                         estrlcpy(ns2, s2, sizeof(ns2));
           95                         if (s2[strlen(s2) - 1] != '/')
           96                                 estrlcat(ns2, "/", sizeof(ns2));
           97                         estrlcat(ns2, d->d_name, sizeof(ns2));
           98 
           99                         fnck(ns1, ns2, cp, depth + 1);
          100                 }
          101 
          102                 closedir(dp);
          103         } else if (cp_aflag && (S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode) ||
          104                    S_ISSOCK(st.st_mode) || S_ISFIFO(st.st_mode))) {
          105                 if (cp_fflag && unlink(s2) < 0 && errno != ENOENT) {
          106                         weprintf("unlink %s:", s2);
          107                         cp_status = 1;
          108                         return 0;
          109                 } else if (mknod(s2, st.st_mode, st.st_rdev) < 0) {
          110                         weprintf("mknod %s:", s2);
          111                         cp_status = 1;
          112                         return 0;
          113                 }
          114         } else {
          115                 if ((f1 = open(s1, O_RDONLY)) < 0) {
          116                         weprintf("open %s:", s1);
          117                         cp_status = 1;
          118                         return 0;
          119                 }
          120                 if ((f2 = creat(s2, st.st_mode)) < 0 && cp_fflag) {
          121                         if (unlink(s2) < 0 && errno != ENOENT) {
          122                                 weprintf("unlink %s:", s2);
          123                                 cp_status = 1;
          124                                 close(f1);
          125                                 return 0;
          126                         }
          127                         f2 = creat(s2, st.st_mode);
          128                 }
          129                 if (f2 < 0) {
          130                         weprintf("creat %s:", s2);
          131                         cp_status = 1;
          132                         close(f1);
          133                         return 0;
          134                 }
          135                 if (concat(f1, s1, f2, s2) < 0) {
          136                         cp_status = 1;
          137                         close(f1);
          138                         close(f2);
          139                         return 0;
          140                 }
          141 
          142                 close(f1);
          143                 close(f2);
          144         }
          145 
          146         if (cp_aflag || cp_pflag) {
          147                 /* atime and mtime */
          148                 times[0] = st.st_atim;
          149                 times[1] = st.st_mtim;
          150                 if (utimensat(AT_FDCWD, s2, times, AT_SYMLINK_NOFOLLOW) < 0) {
          151                         weprintf("utimensat %s:", s2);
          152                         cp_status = 1;
          153                 }
          154 
          155                 /* owner and mode */
          156                 if (!S_ISLNK(st.st_mode)) {
          157                         if (chown(s2, st.st_uid, st.st_gid) < 0) {
          158                                 weprintf("chown %s:", s2);
          159                                 cp_status = 1;
          160                                 st.st_mode &= ~(S_ISUID | S_ISGID);
          161                         }
          162                         if (chmod(s2, st.st_mode) < 0) {
          163                                 weprintf("chmod %s:", s2);
          164                                 cp_status = 1;
          165                         }
          166                 } else {
          167                         if (lchown(s2, st.st_uid, st.st_gid) < 0) {
          168                                 weprintf("lchown %s:", s2);
          169                                 cp_status = 1;
          170                                 return 0;
          171                         }
          172                 }
          173         }
          174 
          175         return 0;
          176 }