summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan McGee <dan@archlinux.org>2007-11-04 18:02:25 -0600
committerDan McGee <dan@archlinux.org>2007-11-04 18:02:25 -0600
commitb55abdce7aebb142ce79da3aa3645afe7693a3c4 (patch)
treea19e1595cb92d4a3571a88acd76ad564fea0aead
parent99f42d6bd2116b0bd8f75394fe92255ca1f4c80b (diff)
downloadpacman-b55abdce7aebb142ce79da3aa3645afe7693a3c4.tar.xz
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 <dan@archlinux.org>
-rw-r--r--lib/libalpm/add.c4
-rw-r--r--lib/libalpm/conflict.c4
-rw-r--r--lib/libalpm/remove.c2
-rw-r--r--lib/libalpm/util.c26
-rw-r--r--lib/libalpm/util.h2
5 files changed, 32 insertions, 6 deletions
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 <stdio.h>
#include <stdarg.h>
#include <time.h>
+#include <sys/stat.h> /* struct stat */
#ifdef ENABLE_NLS
#include <libintl.h> /* 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 *);