From b55abdce7aebb142ce79da3aa3645afe7693a3c4 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Sun, 4 Nov 2007 18:02:25 -0600 Subject: libalpm: use an lstat wrapper so we never dereference dir symlinks Linux lstat follows POSIX standards and dereferences a symlink pointing to a directory if there is a trailing slash. For purposes of libalpm, we don't want this so make a lstat wrapper that suppresses this behavior. Signed-off-by: Dan McGee --- lib/libalpm/add.c | 4 ++-- lib/libalpm/conflict.c | 4 ++-- lib/libalpm/remove.c | 2 +- lib/libalpm/util.c | 26 +++++++++++++++++++++++++- lib/libalpm/util.h | 2 ++ 5 files changed, 32 insertions(+), 6 deletions(-) (limited to 'lib') diff --git a/lib/libalpm/add.c b/lib/libalpm/add.c index a10b20d1..a76f0266 100644 --- a/lib/libalpm/add.c +++ b/lib/libalpm/add.c @@ -371,7 +371,7 @@ static int extract_single_file(struct archive *archive, * S | 7 | 8 | 9 * D | 10 | 11 | 12 * - * 1,2,3- just extract, no magic necessary. lstat will fail here. + * 1,2,3- extract, no magic necessary. lstat (_alpm_lstat) will fail here. * 4,5,6,7,8- conflict checks should have caught this. either overwrite * or backup the file. * 9- follow the symlink, hopefully it is a directory, check it. @@ -381,7 +381,7 @@ static int extract_single_file(struct archive *archive, * 12- skip extraction, dir already exists. */ struct stat lsbuf; - if(lstat(filename, &lsbuf) != 0) { + if(_alpm_lstat(filename, &lsbuf) != 0) { /* cases 1,2,3: couldn't stat an existing file, skip all backup checks */ } else { /* do a stat as well, so we can see what symlinks point to */ diff --git a/lib/libalpm/conflict.c b/lib/libalpm/conflict.c index 0baef8d1..539e06ab 100644 --- a/lib/libalpm/conflict.c +++ b/lib/libalpm/conflict.c @@ -334,7 +334,7 @@ alpm_list_t *_alpm_db_find_conflicts(pmdb_t *db, pmtrans_t *trans, char *root) snprintf(path, PATH_MAX, "%s%s", root, filestr); /* stat the file - if it exists, do some checks */ - if(lstat(path, &buf) != 0) { + if(_alpm_lstat(path, &buf) != 0) { continue; } if(S_ISDIR(buf.st_mode)) { @@ -350,7 +350,7 @@ alpm_list_t *_alpm_db_find_conflicts(pmdb_t *db, pmtrans_t *trans, char *root) unsigned ok = 0; for(k = dbpkg->files; k; k = k->next) { snprintf(str, PATH_MAX, "%s%s", root, (char*)k->data); - if(!lstat(str, &buf2) && buf.st_ino == buf2.st_ino) { + if(!_alpm_lstat(str, &buf2) && buf.st_ino == buf2.st_ino) { ok = 1; _alpm_log(PM_LOG_DEBUG, "conflict was a symlink: %s\n", path); break; diff --git a/lib/libalpm/remove.c b/lib/libalpm/remove.c index 2c8bdc49..6bbb4655 100644 --- a/lib/libalpm/remove.c +++ b/lib/libalpm/remove.c @@ -206,7 +206,7 @@ static void unlink_file(pmpkg_t *info, alpm_list_t *lp, pmtrans_t *trans) } } - if(lstat(file, &buf)) { + if(_alpm_lstat(file, &buf)) { _alpm_log(PM_LOG_DEBUG, "file %s does not exist\n", file); return; } diff --git a/lib/libalpm/util.c b/lib/libalpm/util.c index 016c0f40..5df3a025 100644 --- a/lib/libalpm/util.c +++ b/lib/libalpm/util.c @@ -432,7 +432,7 @@ int _alpm_rmrf(const char *path) char name[PATH_MAX]; struct stat st; - if(lstat(path, &st) == 0) { + if(_alpm_lstat(path, &st) == 0) { if(!S_ISDIR(st.st_mode)) { if(!unlink(path)) { return(0); @@ -597,6 +597,30 @@ const char *_alpm_filecache_setup(void) return(alpm_list_getdata(tmp)); } +/** lstat wrapper that treats /path/dirsymlink/ the same as /path/dirsymlink. + * Linux lstat follows POSIX semantics and still performs a dereference on + * the first, and for uses of lstat in libalpm this is not what we want. + * @param path path to file to lstat + * @param buf structure to fill with stat information + * @return the return code from lstat + */ +int _alpm_lstat(const char *path, struct stat *buf) +{ + int ret; + char *newpath = strdup(path); + int len = strlen(newpath); + + /* strip the trailing slash if one exists */ + if(len != 0 && newpath[len - 1] == '/') { + newpath[len - 1] = '\0'; + } + + ret = lstat(path, buf); + + FREE(newpath); + return(ret); +} + /** Get the md5 sum of file. * @param filename name of the file * @return the checksum on success, NULL on error diff --git a/lib/libalpm/util.h b/lib/libalpm/util.h index e8b1d719..5d0b3693 100644 --- a/lib/libalpm/util.h +++ b/lib/libalpm/util.h @@ -30,6 +30,7 @@ #include #include #include +#include /* struct stat */ #ifdef ENABLE_NLS #include /* here so it doesn't need to be included elsewhere */ @@ -62,6 +63,7 @@ void _alpm_time2string(time_t t, char *buffer); int _alpm_str_cmp(const void *s1, const void *s2); char *_alpm_filecache_find(const char *filename); const char *_alpm_filecache_setup(void); +int _alpm_lstat(const char *path, struct stat *buf); #ifndef HAVE_STRVERSCMP int strverscmp(const char *, const char *); -- cgit v1.2.3-54-g00ecf