diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/apk.c | 4 | ||||
-rw-r--r-- | src/apk_defines.h | 1 | ||||
-rw-r--r-- | src/archive.c | 22 |
3 files changed, 25 insertions, 2 deletions
@@ -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; } |