aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorandroid-build-team Robot <android-build-team-robot@google.com>2019-03-30 23:24:36 +0000
committerandroid-build-team Robot <android-build-team-robot@google.com>2019-03-30 23:24:36 +0000
commit55a2e3247c87f7b7bb6c2c231c7267a1f7baef29 (patch)
treef4359d2488477890ab594acbce3373b892063ea5
parentbb242fb0e8b6fc8e3f380a5d728586349fe49dd4 (diff)
parentf2f7b8481072aefbe99b92b535eb524938059ccb (diff)
downloadtoybox-55a2e3247c87f7b7bb6c2c231c7267a1f7baef29.tar.gz
Snap for 5422062 from f2f7b8481072aefbe99b92b535eb524938059ccb to qt-release
Change-Id: I495ed954c300550f84c1d60878484e5ffe5b3d8b
-rw-r--r--.config2
-rw-r--r--Android.bp2
-rw-r--r--generated/config.h4
-rw-r--r--generated/flags.h4
-rw-r--r--generated/globals.h1
-rw-r--r--lib/lib.c8
-rw-r--r--lib/lib.h2
-rw-r--r--lib/xwrap.c10
-rw-r--r--toys/pending/tar.c164
-rw-r--r--toys/posix/cp.c9
10 files changed, 122 insertions, 84 deletions
diff --git a/.config b/.config
index e86da372..eb82ddec 100644
--- a/.config
+++ b/.config
@@ -121,7 +121,7 @@ CONFIG_FREE=y
# CONFIG_FSCK is not set
CONFIG_FSFREEZE=y
# CONFIG_FSTYPE is not set
-# CONFIG_FSYNC is not set
+CONFIG_FSYNC=y
# CONFIG_FTPGET is not set
# CONFIG_FTPPUT is not set
CONFIG_GETCONF=y
diff --git a/Android.bp b/Android.bp
index 722fc18a..91da3ad3 100644
--- a/Android.bp
+++ b/Android.bp
@@ -107,6 +107,7 @@ cc_defaults {
"toys/other/free.c",
"toys/other/freeramdisk.c",
"toys/other/fsfreeze.c",
+ "toys/other/fsync.c",
"toys/other/help.c",
"toys/other/hwclock.c",
"toys/other/i2ctools.c",
@@ -299,6 +300,7 @@ cc_defaults {
"flock",
"fmt",
"free",
+ "fsync",
"getconf",
"getenforce",
"groups",
diff --git a/generated/config.h b/generated/config.h
index eccfc954..d018081a 100644
--- a/generated/config.h
+++ b/generated/config.h
@@ -216,8 +216,8 @@
#define USE_FSFREEZE(...) __VA_ARGS__
#define CFG_FSTYPE 0
#define USE_FSTYPE(...)
-#define CFG_FSYNC 0
-#define USE_FSYNC(...)
+#define CFG_FSYNC 1
+#define USE_FSYNC(...) __VA_ARGS__
#define CFG_FTPGET 0
#define USE_FTPGET(...)
#define CFG_FTPPUT 0
diff --git a/generated/flags.h b/generated/flags.h
index 3be9e367..0e74cc9e 100644
--- a/generated/flags.h
+++ b/generated/flags.h
@@ -934,7 +934,7 @@
#undef FOR_fstype
#endif
-// fsync <1d
+// fsync <1d <1d
#undef OPTSTR_fsync
#define OPTSTR_fsync "<1d"
#ifdef CLEANUP_fsync
@@ -4131,7 +4131,7 @@
#ifndef TT
#define TT this.fsync
#endif
-#define FLAG_d (FORCED_FLAG<<0)
+#define FLAG_d (1<<0)
#endif
#ifdef FOR_ftpget
diff --git a/generated/globals.h b/generated/globals.h
index 79dc6b73..d3d76150 100644
--- a/generated/globals.h
+++ b/generated/globals.h
@@ -809,6 +809,7 @@ struct tar_data {
struct arg_list *exclude;
struct double_list *incl, *excl, *seen;
+ struct string_list *dirs;
void *inodes;
char *cwd;
int fd, ouid, ggid;
diff --git a/lib/lib.c b/lib/lib.c
index a6114321..14cedb60 100644
--- a/lib/lib.c
+++ b/lib/lib.c
@@ -1059,16 +1059,16 @@ char *getbasename(char *name)
return name;
}
-// Is this file under this directory?
-int fileunderdir(char *file, char *dir)
+// Return pointer to xabspath(file) if file is under dir, else 0
+char *fileunderdir(char *file, char *dir)
{
char *s1 = xabspath(dir, 1), *s2 = xabspath(file, -1), *ss = s2;
int rc = s1 && s2 && strstart(&ss, s1) && (!s1[1] || s2[strlen(s1)] == '/');
free(s1);
- free(s2);
+ if (!rc) free(s2);
- return rc;
+ return rc ? s2 : 0;
}
// Execute a callback for each PID that matches a process name from a list.
diff --git a/lib/lib.h b/lib/lib.h
index 8e6514a8..e220962c 100644
--- a/lib/lib.h
+++ b/lib/lib.h
@@ -371,7 +371,7 @@ mode_t string_to_mode(char *mode_str, mode_t base);
void mode_to_string(mode_t mode, char *buf);
char *getdirname(char *name);
char *getbasename(char *name);
-int fileunderdir(char *file, char *dir);
+char *fileunderdir(char *file, char *dir);
void names_to_pid(char **names, int (*callback)(pid_t pid, char *name));
pid_t __attribute__((returns_twice)) xvforkwrap(pid_t pid);
diff --git a/lib/xwrap.c b/lib/xwrap.c
index a8214e57..778cb38d 100644
--- a/lib/xwrap.c
+++ b/lib/xwrap.c
@@ -521,7 +521,7 @@ void xstat(char *path, struct stat *st)
char *xabspath(char *path, int exact)
{
struct string_list *todo, *done = 0;
- int try = 9999, dirfd = open("/", 0), missing = 0;
+ int try = 9999, dirfd = open("/", O_PATH), missing = 0;
char *ret;
// If this isn't an absolute path, start with cwd.
@@ -554,7 +554,7 @@ char *xabspath(char *path, int exact)
if (missing) missing--;
else {
- if (-1 == (x = openat(dirfd, "..", 0))) goto error;
+ if (-1 == (x = openat(dirfd, "..", O_PATH))) goto error;
close(dirfd);
dirfd = x;
}
@@ -578,7 +578,7 @@ char *xabspath(char *path, int exact)
}
if (errno != EINVAL && (exact || todo)) goto error;
- fd = openat(dirfd, new->str, 0);
+ fd = openat(dirfd, new->str, O_PATH);
if (fd == -1 && (exact || todo || errno != ENOENT)) goto error;
close(dirfd);
dirfd = fd;
@@ -591,7 +591,7 @@ char *xabspath(char *path, int exact)
llist_traverse(done, free);
done=0;
close(dirfd);
- dirfd = open("/", 0);
+ dirfd = open("/", O_PATH);
}
free(new);
@@ -611,7 +611,7 @@ char *xabspath(char *path, int exact)
try = 2;
while (done) {
- struct string_list *temp = llist_pop(&done);;
+ struct string_list *temp = llist_pop(&done);
if (todo) try++;
try += strlen(temp->str);
diff --git a/toys/pending/tar.c b/toys/pending/tar.c
index d0d840ba..8fb047bf 100644
--- a/toys/pending/tar.c
+++ b/toys/pending/tar.c
@@ -47,6 +47,7 @@ GLOBALS(
struct arg_list *exclude;
struct double_list *incl, *excl, *seen;
+ struct string_list *dirs;
void *inodes;
char *cwd;
int fd, ouid, ggid;
@@ -335,69 +336,84 @@ static void extract_to_command(void)
}
}
-static void extract_to_disk(void)
+
+// Do pending directory utimes(), NULL to flush all.
+static int dirflush(char *name)
{
- int flags, dst_fd = -1;
- char *s;
- struct stat ex;
-
- flags = strlen(TT.hdr.name);
- if (flags>2)
- if (strstr(TT.hdr.name, "/../") || !strcmp(TT.hdr.name, "../") ||
- !strcmp(TT.hdr.name+flags-3, "/.."))
- error_msg("drop %s", TT.hdr.name);
-
- if (TT.hdr.name[flags-1] == '/') TT.hdr.name[flags-1] = 0;
- //Regular file with preceding path
- if ((s = strrchr(TT.hdr.name, '/')) && mkpath(TT.hdr.name) && errno !=EEXIST)
- return error_msg(":%s: not created", TT.hdr.name);
-
- //remove old file, if exists
- if (!FLAG(k) && !S_ISDIR(TT.hdr.mode) && !lstat(TT.hdr.name, &ex))
- if (unlink(TT.hdr.name)) perror_msg("can't remove: %s", TT.hdr.name);
-
- //hard link
- if (S_ISREG(TT.hdr.mode) && TT.hdr.link_target) {
- if (link(TT.hdr.link_target, TT.hdr.name))
- perror_msg("can't link '%s' -> '%s'", TT.hdr.name, TT.hdr.link_target);
- goto COPY;
+ char *s = s, *ss;
+
+ // Barf if name not in TT.cwd
+ if (name) {
+ ss = s = xabspath(name, -1);
+ if (TT.cwd && (!strstart(&ss, TT.cwd) || (*ss && *ss!='/'))) {
+ error_msg("'%s' not under '%s'", ss, TT.cwd);
+ free(s);
+
+ return 1;
+ }
}
- switch (TT.hdr.mode & S_IFMT) {
- case S_IFREG:
- flags = O_WRONLY|O_CREAT|O_EXCL;
- if (FLAG(overwrite)) flags = O_WRONLY|O_CREAT|O_TRUNC;
- dst_fd = open(TT.hdr.name, flags, TT.hdr.mode & 07777);
- if (dst_fd == -1) perror_msg("%s: can't open", TT.hdr.name);
- break;
- case S_IFDIR:
- if ((mkdir(TT.hdr.name, TT.hdr.mode) == -1) && errno != EEXIST)
- perror_msg("%s: can't create", TT.hdr.name);
- break;
- case S_IFLNK:
- if (symlink(TT.hdr.link_target, TT.hdr.name))
- perror_msg("can't link '%s' -> '%s'", TT.hdr.name, TT.hdr.link_target);
- break;
- case S_IFBLK:
- case S_IFCHR:
- case S_IFIFO:
- if (mknod(TT.hdr.name, TT.hdr.mode, TT.hdr.device))
- perror_msg("can't create '%s'", TT.hdr.name);
- break;
- default:
- printf("type %o not supported\n", TT.hdr.mode);
- break;
+ // Set deferred utimes() for directories this file isn't under.
+ // (Files must be depth-first ordered in tarball for this to matter.)
+ while (TT.dirs) {
+ long long ll = *(long long *)TT.dirs->str;
+ struct timeval times[2] = {{ll, 0},{ll, 0}};
+
+ if (name && strstart(&ss, ss = s) && (!*ss || *ss=='/')) break;
+ if (utimes(TT.dirs->str+sizeof(long long), times)) perror_msg("utimes %lld %s", *(long long *)TT.dirs->str, TT.dirs->str+sizeof(long long));
+ free(llist_pop(&TT.dirs));
}
- //copy file....
-COPY:
- xsendfile_len(TT.fd, dst_fd, TT.hdr.size);
- close(dst_fd);
+ // name was under TT.cwd
+ return 0;
+}
+
+static void extract_to_disk(void)
+{
+ char *name = TT.hdr.name;
+ int ala = TT.hdr.mode;
+
+ if (dirflush(name)) {
+ if (S_ISREG(ala) && !TT.hdr.link_target) skippy(TT.hdr.size);
+
+ return;
+ }
+
+ // create path before file if necessary
+ if (strrchr(name, '/') && mkpath(name) && errno !=EEXIST)
+ return perror_msg(":%s: can't mkdir", name);
+
+ // remove old file, if exists
+ if (!FLAG(k) && !S_ISDIR(ala) && unlink(name) && errno!=ENOENT)
+ return perror_msg("can't remove: %s", name);
+
+ if (S_ISREG(ala)) {
+ // hardlink?
+ if (TT.hdr.link_target) {
+ if (link(TT.hdr.link_target, name))
+ return perror_msg("can't link '%s' -> '%s'", name, TT.hdr.link_target);
+ // write contents
+ } else {
+ int fd = xcreate(name, O_WRONLY|O_CREAT|(FLAG(overwrite)?O_TRUNC:O_EXCL),
+ WARN_ONLY|(ala & 07777));
+ if (fd != -1) {
+ xsendfile_len(TT.fd, fd, TT.hdr.size);
+ close(fd);
+ }
+ }
+ } else if (S_ISDIR(ala)) {
+ if ((mkdir(name, 0700) == -1) && errno != EEXIST)
+ return perror_msg("%s: can't create", TT.hdr.name);
+ } else if (S_ISLNK(ala)) {
+ if (symlink(TT.hdr.link_target, TT.hdr.name))
+ return perror_msg("can't link '%s' -> '%s'", name, TT.hdr.link_target);
+ } else if (mknod(name, ala, TT.hdr.device))
+ return perror_msg("can't create '%s'", name);
+
if (!FLAG(o) && !geteuid()) {
//set ownership..., --no-same-owner, --numeric-owner
- uid_t u = TT.hdr.uid;
- gid_t g = TT.hdr.gid;
+ int u = TT.hdr.uid, g = TT.hdr.gid;
if (TT.owner) u = TT.ouid;
else if (!FLAG(numeric_owner)) {
@@ -411,17 +427,29 @@ COPY:
if (gr) g = gr->gr_gid;
}
- if (lchown(TT.hdr.name, u, g))
- perror_msg("chown %d:%d '%s'", u, g, TT.hdr.name);;
+ if (lchown(name, u, g)) perror_msg("chown %d:%d '%s'", u, g, name);;
}
// || !FLAG(no_same_permissions))
- if (FLAG(p) && !S_ISLNK(TT.hdr.mode)) chmod(TT.hdr.name, TT.hdr.mode);
+ if (FLAG(p) && !S_ISLNK(ala)) chmod(TT.hdr.name, ala);
- //apply mtime
+ // Apply mtime.
if (!FLAG(m)) {
- struct timeval times[2] = {{TT.hdr.mtime, 0},{TT.hdr.mtime, 0}};
- utimes(TT.hdr.name, times);
+ if (S_ISDIR(ala)) {
+ struct string_list *sl;
+
+ // Writing files into a directory changes directory timestamps, so
+ // defer mtime updates until contents written.
+
+ sl = xmalloc(sizeof(struct string_list)+sizeof(long long)+strlen(name)+1);
+ *(long long *)sl->str = TT.hdr.mtime;
+ strcpy(sl->str+sizeof(long long), name);
+ sl->next = TT.dirs;
+ TT.dirs = sl;
+ } else {
+ struct timeval times[2] = {{TT.hdr.mtime, 0},{TT.hdr.mtime, 0}};
+ utimes(TT.hdr.name, times);
+ }
}
}
@@ -435,13 +463,16 @@ static void unpack_tar(void)
for (;;) {
// align to next block and read it
if (TT.hdr.size%512) skippy(512-TT.hdr.size%512);
- if (!(i = readall(TT.fd, &tar, 512))) return;
+ i = readall(TT.fd, &tar, 512);
- if (i != 512) error_exit("read error");
+ if (i && i != 512) error_exit("read error");
// Two consecutive empty headers ends tar even if there's more data
- if (!*tar.name) {
- if (and++) return;
+ if (!i || !*tar.name) {
+ if (!i || and++) {
+ dirflush(0);
+ return;
+ }
TT.hdr.size = 0;
continue;
}
@@ -604,7 +635,8 @@ void tar_main(void)
// Get destination directory
if (TT.C) xchdir(TT.C);
- TT.cwd = xabspath(s = xgetcwd(), 1);
+ s = xgetcwd();
+ TT.cwd = (strcmp(s, "/")) ? xabspath(s = xgetcwd(), 1) : 0;
free(s);
// Are we reading?
diff --git a/toys/posix/cp.c b/toys/posix/cp.c
index 3b30f8a8..751a718c 100644
--- a/toys/posix/cp.c
+++ b/toys/posix/cp.c
@@ -409,12 +409,15 @@ void cp_main(void)
char *s = (toys.optflags&FLAG_D) ? getdirname(src) : getbasename(src);
TT.destname = xmprintf("%s/%s", destname, s);
- if (toys.optflags&FLAG_D) {
+ if (FLAG(D)) {
free(s);
- if (!fileunderdir(TT.destname, destname)) {
+ if (!(s = fileunderdir(TT.destname, destname))) {
error_msg("%s not under %s", TT.destname, destname);
continue;
- } else mkpath(TT.destname);
+ }
+ // TODO: .. follows abspath, not links...
+ free(s);
+ mkpath(TT.destname);
}
} else TT.destname = destname;