This is a refactor and refresh of the code used to find where we should
download packages.

* Incorporate suggestions from FS#25435 to use TMPDIR from the
  environment if set, otherwise fall back to /tmp as before.
* Make the writability tests a bit more in depth. We now do a three part
  check consisting of:
  - S_ISDIR(): is this even a directory
  - access(W_OK): is this directory writable by the current user.
    Unfortunately for root, this almost always returns that it is, but
    in the case of a RO mount or NFS share inaccessible to root, this
    check will exclude the directory.
  - mode & (any write bit): is there a writable bit set on this
    directory. This makes it possible to enforce a read-only cache
    directory by setting permissions to 0555, for example.

Signed-off-by: Dan McGee <[email protected]>
---
 lib/libalpm/util.c |   44 +++++++++++++++++++++++++++++---------------
 1 files changed, 29 insertions(+), 15 deletions(-)

diff --git a/lib/libalpm/util.c b/lib/libalpm/util.c
index 27709c6..7e3bc37 100644
--- a/lib/libalpm/util.c
+++ b/lib/libalpm/util.c
@@ -638,7 +638,7 @@ char *_alpm_filecache_find(alpm_handle_t *handle, const 
char *filename)
        struct stat buf;
 
        /* Loop through the cache dirs until we find a matching file */
-       for(i = alpm_option_get_cachedirs(handle); i; i = i->next) {
+       for(i = handle->cachedirs; i; i = i->next) {
                snprintf(path, PATH_MAX, "%s%s", (char *)alpm_list_getdata(i),
                                filename);
                if(stat(path, &buf) == 0 && S_ISREG(buf.st_mode)) {
@@ -659,11 +659,11 @@ char *_alpm_filecache_find(alpm_handle_t *handle, const 
char *filename)
 const char *_alpm_filecache_setup(alpm_handle_t *handle)
 {
        struct stat buf;
-       alpm_list_t *i, *tmp;
-       char *cachedir;
+       alpm_list_t *i;
+       char *cachedir, *tmpdir;
 
-       /* Loop through the cache dirs until we find a writeable dir */
-       for(i = alpm_option_get_cachedirs(handle); i; i = i->next) {
+       /* Loop through the cache dirs until we find a usable directory */
+       for(i = handle->cachedirs; i; i = i->next) {
                cachedir = alpm_list_getdata(i);
                if(stat(cachedir, &buf) != 0) {
                        /* cache directory does not exist.... try creating it */
@@ -673,21 +673,35 @@ const char *_alpm_filecache_setup(alpm_handle_t *handle)
                                _alpm_log(handle, ALPM_LOG_DEBUG, "using 
cachedir: %s\n", cachedir);
                                return cachedir;
                        }
-               } else if(S_ISDIR(buf.st_mode) && (buf.st_mode & S_IWUSR)) {
+               } else if(!S_ISDIR(buf.st_mode)) {
+                       _alpm_log(handle, ALPM_LOG_DEBUG,
+                                       "skipping cachedir, not a directory: 
%s\n", cachedir);
+               } else if(access(cachedir, W_OK) != 0) {
+                       _alpm_log(handle, ALPM_LOG_DEBUG,
+                                       "skipping cachedir, not writable: 
%s\n", cachedir);
+               } else if(!(buf.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH))) {
+                       _alpm_log(handle, ALPM_LOG_DEBUG,
+                                       "skipping cachedir, no write bits set: 
%s\n", cachedir);
+               } else {
                        _alpm_log(handle, ALPM_LOG_DEBUG, "using cachedir: 
%s\n", cachedir);
                        return cachedir;
-               } else {
-                       _alpm_log(handle, ALPM_LOG_DEBUG, "skipping cachedir: 
%s\n", cachedir);
                }
        }
 
-       /* we didn't find a valid cache directory. use /tmp. */
-       tmp = alpm_list_add(NULL, "/tmp/");
-       alpm_option_set_cachedirs(handle, tmp);
-       alpm_list_free(tmp);
-       _alpm_log(handle, ALPM_LOG_DEBUG, "using cachedir: %s\n", "/tmp/");
-       _alpm_log(handle, ALPM_LOG_WARNING, _("couldn't create package cache, 
using /tmp instead\n"));
-       return "/tmp/";
+       /* we didn't find a valid cache directory. use TMPDIR or /tmp. */
+       if((tmpdir = getenv("TMPDIR")) && stat(tmpdir, &buf) && 
S_ISDIR(buf.st_mode)) {
+               /* TMPDIR was good, we can use it */
+       } else {
+               tmpdir = "/tmp";
+       }
+       i = alpm_list_add(NULL, tmpdir);
+       alpm_option_set_cachedirs(handle, i);
+       alpm_list_free(i);
+       cachedir = handle->cachedirs->data;
+       _alpm_log(handle, ALPM_LOG_DEBUG, "using cachedir: %s\n", cachedir);
+       _alpm_log(handle, ALPM_LOG_WARNING,
+                       _("couldn't find or create package cache, using %s 
instead\n"), cachedir);
+       return cachedir;
 }
 
 /** lstat wrapper that treats /path/dirsymlink/ the same as /path/dirsymlink.
-- 
1.7.6


Reply via email to