summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/apk.c4
-rw-r--r--src/apk_defines.h1
-rw-r--r--src/archive.c22
3 files changed, 25 insertions, 2 deletions
diff --git a/src/apk.c b/src/apk.c
index 6c4acd7..eff31ac 100644
--- a/src/apk.c
+++ b/src/apk.c
@@ -57,6 +57,7 @@ static struct apk_option generic_options[] = {
{ 0x108, "repositories-file", "Override repositories file",
required_argument, "REPOFILE" },
{ 0x109, "no-network", "Do not use network (cache is still used)" },
+ { 0x110, "never-overwrite", "Never overwrite existing files" },
};
const char *apk_error_str(int error)
@@ -384,6 +385,9 @@ int main(int argc, char **argv)
case 0x109:
apk_flags |= APK_NO_NETWORK;
break;
+ case 0x110:
+ apk_flags |= APK_NEVER_OVERWRITE;
+ break;
default:
if (applet == NULL || applet->parse == NULL ||
applet->parse(ctx, &dbopts, r,
diff --git a/src/apk_defines.h b/src/apk_defines.h
index a0b297a..c0f4b0f 100644
--- a/src/apk_defines.h
+++ b/src/apk_defines.h
@@ -64,6 +64,7 @@ extern unsigned int apk_flags;
#define APK_INTERACTIVE 0x0400
#define APK_RECURSIVE_DELETE 0x0800
#define APK_NO_NETWORK 0x1000
+#define APK_NEVER_OVERWRITE 0x2000
#define apk_error(args...) do { apk_log("ERROR: ", args); } while (0)
#define apk_warning(args...) do { if (apk_verbosity > 0) { apk_log("WARNING: ", args); } } while (0)
diff --git a/src/archive.c b/src/archive.c
index 58d2573..0ba17c5 100644
--- a/src/archive.c
+++ b/src/archive.c
@@ -339,7 +339,17 @@ int apk_archive_entry_extract(int atfd, const struct apk_file_info *ae,
fn = alloca(PATH_MAX);
snprintf(fn, PATH_MAX, "%s%s", ae->name, suffix);
}
- unlinkat(atfd, fn, 0);
+
+ if ((!S_ISDIR(ae->mode) && !S_ISREG(ae->mode)) ||
+ (ae->link_target != NULL)) {
+ /* non-standard entries need to be deleted first */
+ if (apk_flags & APK_NEVER_OVERWRITE) {
+ if (faccessat(atfd, fn, F_OK, AT_SYMLINK_NOFOLLOW) == 0)
+ return 0;
+ } else {
+ unlinkat(atfd, fn, 0);
+ }
+ }
switch (ae->mode & S_IFMT) {
case S_IFDIR:
@@ -349,8 +359,16 @@ int apk_archive_entry_extract(int atfd, const struct apk_file_info *ae,
break;
case S_IFREG:
if (ae->link_target == NULL) {
- fd = openat(atfd, fn, O_RDWR | O_CREAT, ae->mode & 07777);
+ int flags = O_RDWR | O_CREAT | O_TRUNC;
+
+ if (apk_flags & APK_NEVER_OVERWRITE)
+ flags |= O_EXCL;
+
+ fd = openat(atfd, fn, flags, ae->mode & 07777);
if (fd < 0) {
+ if ((apk_flags & APK_NEVER_OVERWRITE) &&
+ (errno == EEXIST))
+ return 0;
r = -1;
break;
}