OSDN Git Service

Merge branch 'master' of https://android.googlesource.com/platform/external/toybox...
[android-x86/external-toybox.git] / toys / posix / cp.c
index d822b1e..6e035f7 100644 (file)
@@ -251,8 +251,8 @@ int cp_node(struct dirtree *try)
 
         // make symlink, or make block/char/fifo/socket
         if (S_ISLNK(try->st.st_mode)
-            ? (0 < (i = readlinkat(tfd, try->name, toybuf, sizeof(toybuf))) &&
-               sizeof(toybuf) > i && !symlinkat(toybuf, cfd, catch))
+            ? ((i = readlinkat0(tfd, try->name, toybuf, sizeof(toybuf))) &&
+               !symlinkat(toybuf, cfd, catch))
             : !mknodat(cfd, catch, try->st.st_mode, try->st.st_rdev))
         {
           err = 0;
@@ -315,10 +315,10 @@ int cp_node(struct dirtree *try)
       // permission bits already correct for mknod and don't apply to symlink
       // If we can't get a filehandle to the actual object, use racy functions
       if (fdout == AT_FDCWD)
-        rc = fchownat(cfd, catch, try->st.st_uid, try->st.st_gid,
+        fchownat(cfd, catch, try->st.st_uid, try->st.st_gid,
                       AT_SYMLINK_NOFOLLOW);
       else rc = fchown(fdout, try->st.st_uid, try->st.st_gid);
-      if (rc) {
+      if (rc && !geteuid()) {
         char *pp;
 
         perror_msg("chown '%s'", pp = dirtree_path(try, 0));
@@ -345,7 +345,19 @@ int cp_node(struct dirtree *try)
         err = "%s";
   }
 
-  if (err) perror_msg(err, catch);
+  if (err) {
+    char *f = 0;
+
+    if (catch == try->name) {
+      f = dirtree_path(try, 0);
+      while (try->parent) try = try->parent;
+      catch = xmprintf("%s%s", TT.destname, f+strlen(try->name));
+      free(f);
+      f = catch;
+    }
+    perror_msg(err, catch);
+    free(f);
+  }
   return 0;
 }
 
@@ -395,20 +407,23 @@ void cp_main(void)
 
     errno = EXDEV;
     if (CFG_MV && toys.which->name[0] == 'm') {
-      if (!(toys.optflags & FLAG_f)) {
+      int force = toys.optflags & FLAG_f, no_clobber = toys.optflags & FLAG_n;
+
+      if (!force || no_clobber) {
         struct stat st;
+        int exists = !stat(TT.destname, &st);
 
-        // Technically "is writeable" is more complicated (022 is not writeable
-        // by the owner, just everybody _else_) but I don't care.
-        if (!stat(TT.destname, &st)
-          && ((toys.optflags & FLAG_i) || !(st.st_mode & 0222)))
-        {
+        // Prompt if -i or file isn't writable.  Technically "is writable" is
+        // more complicated (022 is not writeable by the owner, just everybody
+        // _else_) but I don't care.
+        if (exists && ((toys.optflags & FLAG_i) || !(st.st_mode & 0222))) {
           fprintf(stderr, "%s: overwrite '%s'", toys.which->name, TT.destname);
           if (!yesno(1)) rc = 0;
           else unlink(TT.destname);
         }
+        // if -n and dest exists, don't try to rename() or copy
+        if (exists && no_clobber) rc = 0;
       }
-
       if (rc) rc = rename(src, TT.destname);
     }
 
@@ -484,8 +499,8 @@ void install_main(void)
   if (flags & FLAG_v) toys.optflags |= cp_flag_v();
   if (flags & (FLAG_p|FLAG_o|FLAG_g)) toys.optflags |= cp_flag_p();
 
-  if (TT.i.user) TT.uid = xgetpwnamid(TT.i.user)->pw_uid;
-  if (TT.i.group) TT.gid = xgetgrnamid(TT.i.group)->gr_gid;
+  if (TT.i.user) TT.uid = xgetuid(TT.i.user);
+  if (TT.i.group) TT.gid = xgetgid(TT.i.group);
 
   TT.callback = install_node;
   cp_main();