extract_single_file: consolidate extraction logic

Also adds checks that the filename does not exceed PATH_MAX.

Signed-off-by: Andrew Gregory <andrew.gregory.8@gmail.com>
This commit is contained in:
Andrew Gregory 2014-10-01 02:26:14 -04:00 committed by Allan McRae
parent ba0d225d93
commit 5167160c0c

View file

@ -178,6 +178,7 @@ static int extract_single_file(alpm_handle_t *handle, struct archive *archive,
const char *hash_orig = NULL; const char *hash_orig = NULL;
int errors = 0; int errors = 0;
struct stat lsbuf; struct stat lsbuf;
size_t filename_len;
if(*entryname == '.') { if(*entryname == '.') {
return extract_db_file(handle, archive, entry, newpkg, entryname); return extract_db_file(handle, archive, entry, newpkg, entryname);
@ -191,7 +192,12 @@ static int extract_single_file(alpm_handle_t *handle, struct archive *archive,
} }
/* build the new entryname relative to handle->root */ /* build the new entryname relative to handle->root */
snprintf(filename, PATH_MAX, "%s%s", handle->root, entryname); filename_len = snprintf(filename, PATH_MAX, "%s%s", handle->root, entryname);
if(filename_len >= PATH_MAX) {
_alpm_log(handle, ALPM_LOG_ERROR,
_("unable to extract %s%s: path too long"), handle->root, entryname);
return 1;
}
/* if a file is in NoExtract then we never extract it */ /* if a file is in NoExtract then we never extract it */
if(_alpm_fnmatch_patterns(handle->noextract, entryname) == 0) { if(_alpm_fnmatch_patterns(handle->noextract, entryname) == 0) {
@ -278,91 +284,13 @@ static int extract_single_file(alpm_handle_t *handle, struct archive *archive,
} }
} }
if(needbackup) { if(notouch || needbackup) {
char *checkfile; if(filename_len + strlen(".pacnew") >= PATH_MAX) {
char *hash_local = NULL, *hash_pkg = NULL; _alpm_log(handle, ALPM_LOG_ERROR,
size_t len; _("unable to extract %s.pacnew: path too long"), filename);
return 1;
len = strlen(filename) + 10;
MALLOC(checkfile, len,
errors++; handle->pm_errno = ALPM_ERR_MEMORY; goto needbackup_cleanup);
snprintf(checkfile, len, "%s.pacnew", filename);
if(perform_extraction(handle, archive, entry, checkfile)) {
errors++;
goto needbackup_cleanup;
} }
strcpy(filename + filename_len, ".pacnew");
hash_local = alpm_compute_md5sum(filename);
hash_pkg = alpm_compute_md5sum(checkfile);
/* update the md5 hash in newpkg's backup (it will be the new original) */
if(backup) {
FREE(backup->hash);
STRDUP(backup->hash, hash_pkg,
errors++; handle->pm_errno = ALPM_ERR_MEMORY; goto needbackup_cleanup);
}
_alpm_log(handle, ALPM_LOG_DEBUG, "checking hashes for %s\n", filename);
_alpm_log(handle, ALPM_LOG_DEBUG, "current: %s\n", hash_local);
_alpm_log(handle, ALPM_LOG_DEBUG, "new: %s\n", hash_pkg);
_alpm_log(handle, ALPM_LOG_DEBUG, "original: %s\n", hash_orig);
if(hash_local && hash_pkg && strcmp(hash_local, hash_pkg) == 0) {
/* local and new files are the same, updating anyway to get
* correct timestamps */
_alpm_log(handle, ALPM_LOG_DEBUG, "action: installing new file: %s\n",
filename);
if(try_rename(handle, checkfile, filename)) {
errors++;
}
} else if(hash_orig && hash_pkg && strcmp(hash_orig, hash_pkg) == 0) {
/* original and new files are the same, leave the local version alone,
* including any user changes */
_alpm_log(handle, ALPM_LOG_DEBUG,
"action: leaving existing file in place\n");
unlink(checkfile);
} else if(hash_orig && hash_local && strcmp(hash_orig, hash_local) == 0) {
/* installed file has NOT been changed by user,
* update to the new version */
_alpm_log(handle, ALPM_LOG_DEBUG, "action: installing new file: %s\n",
filename);
if(try_rename(handle, checkfile, filename)) {
errors++;
}
} else {
/* none of the three files matched another, leave the unpacked
* file alongside the local file */
alpm_event_pacnew_created_t event = {
.type = ALPM_EVENT_PACNEW_CREATED,
.from_noupgrade = 0,
.oldpkg = oldpkg,
.newpkg = newpkg,
.file = filename
};
_alpm_log(handle, ALPM_LOG_DEBUG,
"action: keeping current file and installing"
" new one with .pacnew ending\n");
EVENT(handle, &event);
alpm_logaction(handle, ALPM_CALLER_PREFIX,
"warning: %s installed as %s\n", filename, checkfile);
}
needbackup_cleanup:
free(checkfile);
free(hash_local);
free(hash_pkg);
} else {
size_t len;
/* we didn't need a backup */
if(notouch) {
/* change the path to a .pacnew extension */
_alpm_log(handle, ALPM_LOG_DEBUG, "%s is in NoUpgrade -- skipping\n", filename);
/* remember len so we can get the old filename back for the event */
len = strlen(filename);
strncat(filename, ".pacnew", PATH_MAX - len);
} else {
_alpm_log(handle, ALPM_LOG_DEBUG, "extracting %s\n", filename);
} }
if(handle->trans->flags & ALPM_TRANS_FLAG_FORCE) { if(handle->trans->flags & ALPM_TRANS_FLAG_FORCE) {
@ -372,12 +300,17 @@ needbackup_cleanup:
unlink(filename); unlink(filename);
} }
_alpm_log(handle, ALPM_LOG_DEBUG, "extracting %s\n", filename);
if(perform_extraction(handle, archive, entry, filename)) { if(perform_extraction(handle, archive, entry, filename)) {
/* error */
errors++; errors++;
return errors; return errors;
} }
if(backup) {
FREE(backup->hash);
backup->hash = alpm_compute_md5sum(filename);
}
if(notouch) { if(notouch) {
alpm_event_pacnew_created_t event = { alpm_event_pacnew_created_t event = {
.type = ALPM_EVENT_PACNEW_CREATED, .type = ALPM_EVENT_PACNEW_CREATED,
@ -387,18 +320,67 @@ needbackup_cleanup:
.file = filename .file = filename
}; };
/* "remove" the .pacnew suffix */ /* "remove" the .pacnew suffix */
filename[len] = '\0'; filename[filename_len] = '\0';
EVENT(handle, &event); EVENT(handle, &event);
alpm_logaction(handle, ALPM_CALLER_PREFIX, alpm_logaction(handle, ALPM_CALLER_PREFIX,
"warning: %s installed as %s.pacnew\n", filename, filename); "warning: %s installed as %s.pacnew\n", filename, filename);
/* restore */ } else if(needbackup) {
filename[len] = '.'; char *hash_local = NULL, *hash_pkg = NULL;
char origfile[PATH_MAX] = "";
strncat(origfile, filename, filename_len);
hash_local = alpm_compute_md5sum(origfile);
hash_pkg = backup ? backup->hash : alpm_compute_md5sum(filename);
_alpm_log(handle, ALPM_LOG_DEBUG, "checking hashes for %s\n", origfile);
_alpm_log(handle, ALPM_LOG_DEBUG, "current: %s\n", hash_local);
_alpm_log(handle, ALPM_LOG_DEBUG, "new: %s\n", hash_pkg);
_alpm_log(handle, ALPM_LOG_DEBUG, "original: %s\n", hash_orig);
if(hash_local && hash_pkg && strcmp(hash_local, hash_pkg) == 0) {
/* local and new files are the same, updating anyway to get
* correct timestamps */
_alpm_log(handle, ALPM_LOG_DEBUG, "action: installing new file: %s\n",
origfile);
if(try_rename(handle, filename, origfile)) {
errors++;
}
} else if(hash_orig && hash_pkg && strcmp(hash_orig, hash_pkg) == 0) {
/* original and new files are the same, leave the local version alone,
* including any user changes */
_alpm_log(handle, ALPM_LOG_DEBUG,
"action: leaving existing file in place\n");
unlink(filename);
} else if(hash_orig && hash_local && strcmp(hash_orig, hash_local) == 0) {
/* installed file has NOT been changed by user,
* update to the new version */
_alpm_log(handle, ALPM_LOG_DEBUG, "action: installing new file: %s\n",
origfile);
if(try_rename(handle, filename, origfile)) {
errors++;
}
} else {
/* none of the three files matched another, leave the unpacked
* file alongside the local file */
alpm_event_pacnew_created_t event = {
.type = ALPM_EVENT_PACNEW_CREATED,
.from_noupgrade = 0,
.oldpkg = oldpkg,
.newpkg = newpkg,
.file = origfile
};
_alpm_log(handle, ALPM_LOG_DEBUG,
"action: keeping current file and installing"
" new one with .pacnew ending\n");
EVENT(handle, &event);
alpm_logaction(handle, ALPM_CALLER_PREFIX,
"warning: %s installed as %s\n", origfile, filename);
} }
/* calculate an hash if this is in newpkg's backup */ free(hash_local);
if(backup) { if(!backup) {
FREE(backup->hash); free(hash_pkg);
backup->hash = alpm_compute_md5sum(filename);
} }
} }
return errors; return errors;