summaryrefslogtreecommitdiff
path: root/lib/libalpm/util.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libalpm/util.c')
-rw-r--r--lib/libalpm/util.c252
1 files changed, 218 insertions, 34 deletions
diff --git a/lib/libalpm/util.c b/lib/libalpm/util.c
index 72c17bf9..b1c3a402 100644
--- a/lib/libalpm/util.c
+++ b/lib/libalpm/util.c
@@ -48,8 +48,112 @@
#include "error.h"
#include "package.h"
#include "alpm.h"
+#include "alpm_list.h"
+#include "md5.h"
-#ifdef __sun__
+#ifndef HAVE_STRVERSCMP
+/* GNU's strverscmp() function, taken from glibc 2.3.2 sources
+ */
+
+/* Compare strings while treating digits characters numerically.
+ Copyright (C) 1997, 2002 Free Software Foundation, Inc.
+ Contributed by Jean-François Bignolles <bignolle@ecoledoc.ibp.fr>, 1997.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+*/
+
+/* states: S_N: normal, S_I: comparing integral part, S_F: comparing
+ fractionnal parts, S_Z: idem but with leading Zeroes only */
+#define S_N 0x0
+#define S_I 0x4
+#define S_F 0x8
+#define S_Z 0xC
+
+/* result_type: CMP: return diff; LEN: compare using len_diff/diff */
+#define CMP 2
+#define LEN 3
+
+/* Compare S1 and S2 as strings holding indices/version numbers,
+ returning less than, equal to or greater than zero if S1 is less than,
+ equal to or greater than S2 (for more info, see the texinfo doc).
+*/
+
+static int strverscmp (s1, s2)
+ const char *s1;
+ const char *s2;
+{
+ const unsigned char *p1 = (const unsigned char *) s1;
+ const unsigned char *p2 = (const unsigned char *) s2;
+ unsigned char c1, c2;
+ int state;
+ int diff;
+
+ /* Symbol(s) 0 [1-9] others (padding)
+ Transition (10) 0 (01) d (00) x (11) - */
+ static const unsigned int next_state[] =
+ {
+ /* state x d 0 - */
+ /* S_N */ S_N, S_I, S_Z, S_N,
+ /* S_I */ S_N, S_I, S_I, S_I,
+ /* S_F */ S_N, S_F, S_F, S_F,
+ /* S_Z */ S_N, S_F, S_Z, S_Z
+ };
+
+ static const int result_type[] =
+ {
+ /* state x/x x/d x/0 x/- d/x d/d d/0 d/-
+ 0/x 0/d 0/0 0/- -/x -/d -/0 -/- */
+
+ /* S_N */ CMP, CMP, CMP, CMP, CMP, LEN, CMP, CMP,
+ CMP, CMP, CMP, CMP, CMP, CMP, CMP, CMP,
+ /* S_I */ CMP, -1, -1, CMP, +1, LEN, LEN, CMP,
+ +1, LEN, LEN, CMP, CMP, CMP, CMP, CMP,
+ /* S_F */ CMP, CMP, CMP, CMP, CMP, LEN, CMP, CMP,
+ CMP, CMP, CMP, CMP, CMP, CMP, CMP, CMP,
+ /* S_Z */ CMP, +1, +1, CMP, -1, CMP, CMP, CMP,
+ -1, CMP, CMP, CMP
+ };
+
+ if (p1 == p2)
+ return 0;
+
+ c1 = *p1++;
+ c2 = *p2++;
+ /* Hint: '0' is a digit too. */
+ state = S_N | ((c1 == '0') + (isdigit (c1) != 0));
+
+ while ((diff = c1 - c2) == 0 && c1 != '\0')
+ {
+ state = next_state[state];
+ c1 = *p1++;
+ c2 = *p2++;
+ state |= (c1 == '0') + (isdigit (c1) != 0);
+ }
+
+ state = result_type[state << 2 | (((c2 == '0') + (isdigit (c2) != 0)))];
+
+ switch (state)
+ {
+ case CMP:
+ return diff;
+
+ case LEN:
+ while (isdigit (*p1++))
+ if (!isdigit (*p2++))
+ return 1;
+
+ return isdigit (*p2) ? -1 : diff;
+
+ default:
+ return state;
+ }
+}
+#endif
+
+#ifndef HAVE_STRSEP
/* This is a replacement for strsep which is not portable (missing on Solaris).
* Copyright (c) 2001 by François Gouget <fgouget_at_codeweavers.com> */
char* strsep(char** str, const char* delims)
@@ -74,33 +178,6 @@ char* strsep(char** str, const char* delims)
*str=NULL;
return token;
}
-
-/* Backported from Solaris Express 4/06
- * Copyright (c) 2006 Sun Microsystems, Inc. */
-char *mkdtemp(char *template)
-{
- char *t = alloca(strlen(template) + 1);
- char *r;
-
- /* Save template */
- (void) strcpy(t, template);
- for (; ; ) {
- r = mkstemp(template);
-
- if (*r == '\0')
- return (NULL);
-
- if (mkdir(template, 0700) == 0)
- return (r);
-
- /* Other errors indicate persistent conditions. */
- if (errno != EEXIST)
- return (NULL);
-
- /* Reset template */
- (void) strcpy(template, t);
- }
-}
#endif
/* does the same thing as 'mkdir -p' */
@@ -124,7 +201,7 @@ int _alpm_makepath(const char *path)
if(mkdir(full, 0755)) {
FREE(orig);
umask(oldmask);
- _alpm_log(PM_LOG_ERROR, _("failed to make path '%s' : %s"),
+ _alpm_log(PM_LOG_ERROR, _("failed to make path '%s' : %s\n"),
path, strerror(errno));
return(1);
}
@@ -225,7 +302,7 @@ static void _strnadd(char **str, const char *append, unsigned int count)
if(*str) {
*str = realloc(*str, strlen(*str) + count + 1);
} else {
- *str = calloc(sizeof(char), count + 1);
+ *str = calloc(count + 1, sizeof(char));
}
strncat(*str, append, count);
@@ -287,7 +364,7 @@ int _alpm_lckmk()
}
}
- free(dir);
+ FREE(dir);
return(fd > 0 ? fd : -1);
}
@@ -321,8 +398,10 @@ int _alpm_unpack(const char *archive, const char *prefix, const char *fn)
archive_read_support_compression_all(_archive);
archive_read_support_format_all(_archive);
- if(archive_read_open_file(_archive, archive, ARCHIVE_DEFAULT_BYTES_PER_BLOCK) != ARCHIVE_OK) {
- _alpm_log(PM_LOG_ERROR, _("could not open %s: %s\n"), archive, archive_error_string(_archive));
+ if(archive_read_open_filename(_archive, archive,
+ ARCHIVE_DEFAULT_BYTES_PER_BLOCK) != ARCHIVE_OK) {
+ _alpm_log(PM_LOG_ERROR, _("could not open %s: %s\n"), archive,
+ archive_error_string(_archive));
RET_ERR(PM_ERR_PKG_OPEN, -1);
}
@@ -340,7 +419,7 @@ int _alpm_unpack(const char *archive, const char *prefix, const char *fn)
int ret = archive_read_extract(_archive, entry, archive_flags);
if(ret == ARCHIVE_WARN) {
/* operation succeeded but a non-critical error was encountered */
- _alpm_log(PM_LOG_DEBUG, _("warning extracting %s (%s)\n"),
+ _alpm_log(PM_LOG_DEBUG, "warning extracting %s (%s)\n",
entryname, archive_error_string(_archive));
} else if(ret != ARCHIVE_OK) {
_alpm_log(PM_LOG_ERROR, _("could not extract %s (%s)\n"),
@@ -465,5 +544,110 @@ int _alpm_str_cmp(const void *s1, const void *s2)
return(strcmp(s1, s2));
}
+/** Find a package file in an alpm cachedir.
+ * @param filename name of package file to find
+ * @return malloced path of file, NULL if not found
+ */
+char *_alpm_filecache_find(const char* filename)
+{
+ struct stat buf;
+ char path[PATH_MAX];
+ char *retpath;
+ alpm_list_t *i;
+
+ /* Loop through the cache dirs until we find a matching file */
+ for(i = alpm_option_get_cachedirs(); i; i = alpm_list_next(i)) {
+ snprintf(path, PATH_MAX, "%s%s", (char*)alpm_list_getdata(i),
+ filename);
+ if(stat(path, &buf) == 0) {
+ /* TODO maybe check to make sure it is readable? */
+ retpath = strdup(path);
+ _alpm_log(PM_LOG_DEBUG, "found cached pkg: %s\n", retpath);
+ return(retpath);
+ }
+ }
+ /* package wasn't found in any cachedir */
+ return(NULL);
+}
+
+/** Check the alpm cachedirs for existance and find a writable one.
+ * If no valid cache directory can be found, use /tmp.
+ * @return pointer to a writable cache directory.
+ */
+const char *_alpm_filecache_setup(void)
+{
+ struct stat buf;
+ alpm_list_t *i, *tmp;
+ char *cachedir;
+
+ /* Loop through the cache dirs until we find a writeable dir */
+ for(i = alpm_option_get_cachedirs(); i; i = alpm_list_next(i)) {
+ cachedir = alpm_list_getdata(i);
+ if(stat(cachedir, &buf) != 0) {
+ /* cache directory does not exist.... try creating it */
+ _alpm_log(PM_LOG_WARNING, _("no %s cache exists, creating...\n"),
+ cachedir);
+ alpm_logaction("warning: no %s cache exists, creating...",
+ cachedir);
+ if(_alpm_makepath(cachedir) == 0) {
+ _alpm_log(PM_LOG_DEBUG, "using cachedir: %s\n", cachedir);
+ return(cachedir);
+ }
+ } else if(S_ISDIR(buf.st_mode) && (buf.st_mode & S_IWUSR)) {
+ _alpm_log(PM_LOG_DEBUG, "using cachedir: %s\n", cachedir);
+ return(cachedir);
+ }
+ }
+
+ /* we didn't find a valid cache directory. use /tmp. */
+ i = alpm_option_get_cachedirs();
+ tmp = alpm_list_add(NULL, strdup("/tmp/"));
+ FREELIST(i);
+ alpm_option_set_cachedirs(tmp);
+ _alpm_log(PM_LOG_DEBUG, "using cachedir: %s", "/tmp/\n");
+ _alpm_log(PM_LOG_WARNING, _("couldn't create package cache, using /tmp instead\n"));
+ alpm_logaction("warning: couldn't create package cache, using /tmp instead");
+ return(alpm_list_getdata(tmp));
+}
+
+/** Get the md5 sum of file.
+ * @param filename name of the file
+ * @return the checksum on success, NULL on error
+ * @addtogroup alpm_misc
+ */
+char SYMEXPORT *alpm_get_md5sum(const char *filename)
+{
+ unsigned char output[16];
+ char *md5sum;
+ int ret, i;
+
+ ALPM_LOG_FUNC;
+
+ ASSERT(filename != NULL, return(NULL));
+
+ /* allocate 32 chars plus 1 for null */
+ md5sum = calloc(33, sizeof(char));
+ ret = md5_file(filename, output);
+
+ if (ret > 0) {
+ if (ret == 1) {
+ _alpm_log(PM_LOG_ERROR, _("md5: %s can't be opened\n"), filename);
+ } else if (ret == 2) {
+ _alpm_log(PM_LOG_ERROR, _("md5: %s can't be read\n"), filename);
+ }
+
+ return(NULL);
+ }
+
+ /* Convert the result to something readable */
+ for (i = 0; i < 16; i++) {
+ /* sprintf is acceptable here because we know our output */
+ sprintf(md5sum +(i * 2), "%02x", output[i]);
+ }
+ md5sum[32] = '\0';
+
+ _alpm_log(PM_LOG_DEBUG, "md5(%s) = %s\n", filename, md5sum);
+ return(md5sum);
+}
/* vim: set ts=2 sw=2 noet: */