From 1f37511e52754f7231c52489ba4f7d8f7de1e2af Mon Sep 17 00:00:00 2001 From: "Brad T. Peters" Date: Thu, 7 Jan 2016 14:37:17 -0800 Subject: [PATCH] swupd-client: Add existence check to staging target Patch adds an stat() check to ensure that: 1. target path for a staged file exists, and 2. target path is indeed a directory Follow-on patch will add correct corrective behavior once verify_fix_path() is implemented Upstream-Status: Backport [v3.0.0+] Signed-off-by: Brad T. Peters --- src/staging.c | 39 ++++++++++++++++++++++++++++++++------- 1 file changed, 32 insertions(+), 7 deletions(-) diff --git a/src/staging.c b/src/staging.c index 3a847e2..b8545c1 100644 --- a/src/staging.c +++ b/src/staging.c @@ -277,9 +277,11 @@ int do_staging(struct file *file) #if SWUPD_LINUX_ROOTFS char *original = NULL; char *target = NULL; + char *targetpath = NULL; + char *symbase = NULL; #endif int ret; - struct stat stat; + struct stat s; tmp = strdup(file->filename); tmp2 = strdup(file->filename); @@ -294,6 +296,29 @@ int do_staging(struct file *file) string_or_die(&original, "%s/staged/%s", STATE_DIR, file->hash); #if SWUPD_LINUX_ROOTFS + string_or_die(&targetpath, "%s%s", path_prefix, rel_dir); + ret = stat(targetpath, &s); + + if (S_ISLNK(s.st_mode)) { + /* Follow symlink to ultimate target and redo stat */ + symbase = realpath(targetpath, NULL); + if (symbase != NULL) { + free(targetpath); + targetpath = strdup(symbase); + ret = stat(targetpath, &s); + free(symbase); + } + } + + /* For now, just report on error conditions. Once we implement + * verify_fix_path(char *path, int targetversion), we'll want to call it here */ + if ((ret == -1) && (errno == ENOENT)) { + printf("Error: Update target directory does not exist: %s\n", targetpath); + } else if (!S_ISDIR(s.st_mode)) { + printf("Error: Update target exists but is NOT a directory: %s\n", targetpath); + } + + free(targetpath); string_or_die(&target, "%s%s/.update.%s", path_prefix, rel_dir, base); ret = swupd_rm(target); if (ret == 0) @@ -306,12 +331,12 @@ int do_staging(struct file *file) string_or_die(&statfile, "%s/%s/%s", STAGING_SUBVOL, rel_dir, base); #endif - memset(&stat, 0, sizeof(struct stat)); - ret = lstat(statfile, &stat); + memset(&s, 0, sizeof(struct stat)); + ret = lstat(statfile, &s); if (ret == 0) { - if ((file->is_dir && !S_ISDIR(stat.st_mode)) || - (file->is_link && !S_ISLNK(stat.st_mode)) || - (file->is_file && !S_ISREG(stat.st_mode))) { + if ((file->is_dir && !S_ISDIR(s.st_mode)) || + (file->is_link && !S_ISLNK(s.st_mode)) || + (file->is_file && !S_ISREG(s.st_mode))) { LOG_INFO(file, "Type changed!", class_osvol_staging, "%s", statfile); //file type changed, move old out of the way for new ret = swupd_rm(statfile); @@ -325,7 +350,7 @@ int do_staging(struct file *file) free(statfile); #if SWUPD_LINUX_ROOTFS - if (file->is_dir || S_ISDIR(stat.st_mode)) { + if (file->is_dir || S_ISDIR(s.st_mode)) { /* In the btrfs only scenario there is an implicit * "create_or_update_dir()" via un-tar-ing a directory.tar after * download and the untar happens in the staging subvolume which -- 2.5.0