Support downloading from local repository even without libcurl
authorJ. Ali Harlow <ali@juiblex.co.uk>
Thu, 9 Oct 2014 16:27:41 +0000 (17:27 +0100)
committerJ. Ali Harlow <ali@juiblex.co.uk>
Thu, 9 Oct 2014 16:27:41 +0000 (17:27 +0100)
Using the --url option of the razor executable, it is possible
to specify a yum repository on the local machine (eg., on installation
media) and import from there, eg.,:

C> razor --url file:///d:/ import-yum

This will be handled by libcurl if available but if not, an internal
copy routine will be used.

Note that if Microsoft's KTM implementation of atomic transactions is
used, then the current directory must support atomic transactions
(also improve error messages for this, and other, cases).

Makefile.am
configure.ac
librazor/Makefile.am
librazor/error.c
librazor/test-lua.c
librazor/types/Makefile.am
librazor/util.c
src/Makefile.am
src/import-yum.c
src/main.c

index 076084c..5558330 100644 (file)
@@ -4,6 +4,8 @@ SUBDIRS = data docs gl librazor src test po
 
 ACLOCAL_AMFLAGS = -I gl/m4
 
+DISTCHECK_CONFIGURE_FLAGS = --enable-tests
+
 # Creating ChangeLog from git log (taken from cairo/Makefile.am):
 ChangeLog: $(srcdir)/ChangeLog
 
index 259d5f0..e201f36 100644 (file)
@@ -72,11 +72,18 @@ else
     AC_SUBST([RAZOR_HAVE_ATOMIC_ROLLBACK],['#undef RAZOR_HAVE_ATOMIC_ROLLBACK'])
 fi
 
+AC_ARG_ENABLE([tests],
+             [AS_HELP_STRING([--enable-tests],
+                             [install test programs])],
+             [],
+             [enable_tests=no])
+AM_CONDITIONAL(INSTALL_TEST_PROGRAMS, test "$enable_tests" = "yes")
+
 AC_MSG_CHECKING([for Microsoft Windows native API])
 case $host_os in
     *mingw*)   AC_DEFINE([MSWIN_API], 1,
                  [Define to 1 to use Microsoft Windows native API.])
-               EXTRA_LIBS='-lshell32 -lws2_32'
+               EXTRA_LIBS='-lshlwapi -lshell32 -lws2_32'
                mswin_api=yes;;
     *)         mswin_api=no;;
 esac
index a25a05c..b800570 100644 (file)
@@ -14,8 +14,13 @@ INCLUDES = \
        -DPACKAGE_LIB_DIR=\""$(libdir)"\"
 
 lib_LTLIBRARIES = librazor.la
+check_PROGRAMS = test-pfu
 if HAVE_LUA
-  check_PROGRAMS = test-lua
+  check_PROGRAMS += test-lua
+endif
+
+if INSTALL_TEST_PROGRAMS
+  bin_PROGRAMS = $(check_PROGRAMS)
 endif
 
 librazorincludedir = $(includedir)/razor
@@ -29,6 +34,7 @@ librazor_la_SOURCES =                                 \
        razor.c                                         \
        root.c                                          \
        util.c                                          \
+       path.c                                          \
        rpm.c                                           \
        iterator.c                                      \
        importer.c                                      \
@@ -50,12 +56,18 @@ librazor_la_LIBADD = $(ZLIB_LIBS) types/libtypes.la $(LUA_LIBS) \
 librazor_la_LDFLAGS = -no-undefined -export-symbols-regex '^razor_' \
        -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE)
 
+test_pfu_SOURCES = test-pfu.c
+test_pfu_LDADD = path.lo util.lo error.lo types/libtypes.la \
+       ../gl/libgnu.la $(INTLLIBS) $(EXTRA_LIBS)
+
+TESTS = test-pfu
+
 if HAVE_LUA
   test_lua_SOURCES = test-lua.c
   test_lua_LDADD = lua.lo util.lo error.lo types/libtypes.la $(LUA_LIBS) \
        ../gl/libgnu.la $(INTLLIBS) $(EXTRA_LIBS)
 
-  TESTS = test-lua
+  TESTS += test-lua
 endif
 
 EXTRA_DIST =                   \
index 24a00c5..65d512d 100644 (file)
@@ -20,6 +20,9 @@
 
 #ifdef MSWIN_API
 #include <windows.h>
+#ifndef ERROR_TRANSACTIONAL_OPEN_NOT_ALLOWED
+#define ERROR_TRANSACTIONAL_OPEN_NOT_ALLOWED   6832L
+#endif
 #endif
 #include <stdlib.h>
 #include <string.h>
@@ -129,12 +132,28 @@ razor_error_new_mswin(const wchar_t *object, DWORD err)
        if (object)
                error->object = razor_utf16_to_utf8(object, -1);
 
-       FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER|
-                      FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
-                      NULL, err, MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),
-                      (LPWSTR)&buf, 0, NULL);
-       error->str = razor_utf16_to_utf8(buf, -1);
-       LocalFree(buf);
+       switch(err) {
+       case ERROR_TRANSACTIONAL_OPEN_NOT_ALLOWED:
+               /*
+                * Attempting to include files in a transaction on a filesystem
+                * that doesn't support them (only NTFS?) produces this error
+                * for which the default text isn't very informative. Try and
+                * give more useful information.
+                */
+               error->str = strdup("Not allowed (perhaps the filesystem "
+                                   "doesn't support transactions)");
+               break;
+       default:
+               FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER|
+                              FORMAT_MESSAGE_FROM_SYSTEM|
+                              FORMAT_MESSAGE_IGNORE_INSERTS,
+                              NULL, err,
+                              MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),
+                              (LPWSTR)&buf, 0, NULL);
+               error->str = razor_utf16_to_utf8(buf, -1);
+               LocalFree(buf);
+               break;
+       }
 
        return error;
 }
index fc194b4..54bb947 100644 (file)
@@ -91,8 +91,8 @@ int main(int argc, char *argv[])
        }
        fprintf(fp, "#!" LUA_BINARY "\n"
          "print('Abracadabra!')\n");
-       fchmod(fileno(fp), S_IRUSR | S_IWUSR | S_IXUSR);
        fclose(fp);
+       chmod(s, S_IRUSR | S_IWUSR | S_IXUSR);
        free(s);
 
        script = razor_file_get_contents(test_file, &len, 0, &error);
index 9cbd771..9e89a23 100644 (file)
@@ -4,6 +4,10 @@ noinst_LTLIBRARIES = libtypes.la
 check_PROGRAMS = test-hashtable test-graph test-deque
 LDADD = libtypes.la
 
+if INSTALL_TEST_PROGRAMS
+  bin_PROGRAMS = $(check_PROGRAMS)
+endif
+
 libtypes_la_SOURCES =           \
        array.c                 \
        deque.c                 \
index b9994ae..b640939 100644 (file)
@@ -344,24 +344,6 @@ RAZOR_EXPORT char *razor_concat(const char *s, ...)
        return concat;
 }
 
-/**
- * razor_path_add_root:
- *
- * Adds a root to a path. path must be an absolute pathname. In POSIX
- * environments this is equivalent to the concationation of root and path.
- * In Microsoft Windows an adjustment may need to be made for a drive letter
- * in path (which will be dropped).
- *
- * Returns: The new pathname.
- **/
-RAZOR_EXPORT char *razor_path_add_root(const char *path, const char *root)
-{
-       if (root && *root)
-               return razor_concat(root, SKIP_DRIVE_LETTER(path), NULL);
-       else
-               return strdup(path);
-}
-
 RAZOR_EXPORT const char *razor_system_arch(void)
 {
 #ifdef MSWIN_API
@@ -394,12 +376,15 @@ char *razor_utf16_to_utf8(const wchar_t *utf16, int len)
        int n;
        char *utf8;
 
+       if (len == 0)
+               return strdup("");
+
        n = WideCharToMultiByte(CP_UTF8, 0, utf16, len, NULL, 0, NULL, NULL);
-       if (len >= 0 && utf16[len])
+       if (len > 0)
                n++;
        utf8 = malloc(n);
        (void)WideCharToMultiByte(CP_UTF8, 0, utf16, len, utf8, n, NULL, NULL);
-       if (len >= 0 && utf16[len])
+       if (len > 0)
                utf8[n - 1] = 0;
 
        return utf8;
@@ -410,12 +395,17 @@ wchar_t *razor_utf8_to_utf16(const char *utf8, int len)
        int n;
        wchar_t *utf16;
 
+       if (len == 0) {
+               utf16 = calloc(1, sizeof(wchar_t));
+               return utf16;
+       }
+
        n = MultiByteToWideChar(CP_UTF8, 0, utf8, len, NULL, 0);
-       if (len >= 0 && utf8[len])
+       if (len > 0)
                n++;
        utf16 = malloc(n * sizeof(wchar_t));
        (void)MultiByteToWideChar(CP_UTF8, 0, utf8, len, utf16, n);
-       if (len >= 0 && utf8[len])
+       if (len > 0)
                utf16[n - 1] = 0;
 
        return utf16;
index b87e29f..6820b2d 100644 (file)
@@ -19,6 +19,11 @@ bin_PROGRAMS = razor
 noinst_PROGRAMS = rpm
 check_PROGRAMS = test-driver
 
+if INSTALL_TEST_PROGRAMS
+  bin_PROGRAMS = $(check_PROGRAMS)
+  pkgdata_DATA = test.xml
+endif
+
 razor_SOURCES = main.c import-yum.c
 if HAVE_RPMLIB
 razor_SOURCES += import-rpmdb.c
index fd0aa43..34fd44c 100644 (file)
@@ -311,11 +311,15 @@ razor_set_create_from_yum(void)
                                    yum_character_data);
 
        primary = gzopen("primary.xml.gz", "rb");
-       if (primary == NULL)
+       if (primary == NULL) {
+               perror("primary.xml.gz");
                return NULL;
+       }
        filelists = gzopen("filelists.xml.gz", "rb");
-       if (filelists == NULL)
+       if (filelists == NULL) {
+               perror("filelists.xml.gz");
                return NULL;
+       }
 
        ctx.current_parser = ctx.primary_parser;
 
index aa116ba..5eb9e09 100644 (file)
 #include <fcntl.h>
 #include <dirent.h>
 #include <limits.h>
+#ifdef MSWIN_API
+#include <windows.h>
+#include <shlwapi.h>
+#endif
 #ifdef HAVE_CURL
 #include <curl/curl.h>
 #endif
+#if !defined(HAVE_CURL) && !defined(MSWIN_API)
+#include <ctype.h>
+#endif
 #include <fnmatch.h>
 #include <errno.h>
 #include <getopt.h>
@@ -607,6 +614,71 @@ command_what_provides(int argc, char * const argv[])
                                      RAZOR_PROPERTY_PROVIDES);
 }
 
+#ifndef HAVE_CURL
+static int
+download_local(const char *url, const char *file)
+{
+       FILE *wfp, *rfp;
+       char buffer[256], *ptr, *local;
+       size_t nb, n;
+
+       local = razor_path_from_url(url);
+
+       if (local == NULL) {
+               fprintf(stderr,
+                       "%s: download manually (curl not available)\n",
+                       file);
+               return -1;
+       } else {
+               rfp = fopen(local, "rb");
+               if (rfp == NULL) {
+                       perror(local);
+                       free(local);
+                       return -1;
+               }
+
+               wfp = fopen(file, "wb");
+               if (wfp == NULL) {
+                       perror(file);
+                       fclose(rfp);
+                       free(local);
+                       return -1;
+               }
+
+               while((nb = fread(buffer, 1, sizeof(buffer), rfp)) > 0) {
+                       ptr = buffer;
+                       while (nb > 0 && (n = fwrite(ptr, 1, nb, wfp)) > 0) {
+                               ptr += n;
+                               nb -= n;
+                       }
+
+                       if (nb != 0) {
+                               perror(file);
+                               fclose(wfp);
+                               fclose(rfp);
+                               unlink(file);
+                               free(local);
+                               return -1;
+                       }
+               }
+
+               if (ferror(rfp)) {
+                       perror(local);
+                       fclose(wfp);
+                       fclose(rfp);
+                       unlink(file);
+                       free(local);
+                       return -1;
+               }
+
+               fclose(wfp);
+               fclose(rfp);
+               free(local);
+               return 0;
+       }
+}
+#endif /* !HAVE_CURL */
+
 #ifdef HAVE_CURL
 static int
 show_progress(void *clientp,
@@ -620,65 +692,74 @@ show_progress(void *clientp,
 
        return 0;
 }
-#endif /* HAVE_CURL */
 
 static int
-download_if_missing(const char *url, const char *file)
+download_with_curl(const char *url, const char *file)
 {
-#ifndef HAVE_CURL
-       return 1;
-#else
+       FILE *fp;
        CURL *curl;
-       struct stat buf;
        char error[256];
-       FILE *fp;
        CURLcode res;
        long response;
 
        curl = curl_easy_init();
-       if (curl == NULL)
-               return 1;
+       if (curl == NULL) {
+               fprintf(stderr,
+                       "%s: download manually (curl failed)\n", file);
+               return -1;
+       }
 
        curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, error);
        curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0);
        curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, show_progress);
        curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, file);
 
-       if (stat(file, &buf) < 0) {
-               fp = fopen(file, "wb");
-               if (fp == NULL) {
-                       fprintf(stderr,
-                               "failed to open %s for writing\n", file);
-                       return -1;
-               }
-               curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
-               curl_easy_setopt(curl, CURLOPT_URL, url);
-               res = curl_easy_perform(curl);
-               fclose(fp);
-               if (res != CURLE_OK) {
-                       fprintf(stderr, "curl error: %s\n", error);
-                       unlink(file);
-                       return -1;
-               }
-               res = curl_easy_getinfo(curl,
-                                       CURLINFO_RESPONSE_CODE, &response);
-               if (res != CURLE_OK) {
-                       fprintf(stderr, "curl error: %s\n", error);
-                        unlink(file);
-                        return -1;
-               }
-               if (response != 200) {
-                       fprintf(stderr, " - failed %ld\n", response);
-                        unlink(file);
-                        return -1;
-               }
-               fprintf(stderr, "\n");
+       fp = fopen(file, "wb");
+       if (fp == NULL) {
+               perror(file);
+               return -1;
        }
-
+       curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
+       curl_easy_setopt(curl, CURLOPT_URL, url);
+       res = curl_easy_perform(curl);
+       fclose(fp);
+       if (res != CURLE_OK) {
+               fprintf(stderr, "curl error: %s\n", error);
+               unlink(file);
+               return -1;
+       }
+       res = curl_easy_getinfo(curl,
+                               CURLINFO_RESPONSE_CODE, &response);
+       if (res != CURLE_OK) {
+               fprintf(stderr, "curl error: %s\n", error);
+               unlink(file);
+               return -1;
+       }
+       if (response != 200) {
+               fprintf(stderr, " - failed %ld\n", response);
+               unlink(file);
+               return -1;
+       }
+       fprintf(stderr, "\n");
        curl_easy_cleanup(curl);
 
        return 0;
+}
 #endif /* HAVE_CURL */
+
+static int
+download_if_missing(const char *url, const char *file)
+{
+       struct stat buf;
+
+       if (stat(file, &buf) >= 0)
+               return 0;
+
+#ifndef HAVE_CURL
+       return download_local(url, file);
+#else
+       return download_with_curl(url, file);
+#endif
 }
 
 #define YUM_URL "http://download.fedora.redhat.com" \
@@ -704,7 +785,7 @@ command_import_yum(int argc, char * const argv[])
                return 1;
        }
 
-       printf("downloading from %s.\n", yum_url);
+       printf("downloading from '%s'.\n", yum_url);
        snprintf(buffer, sizeof buffer,
                 "%s/repodata/primary.xml.gz", yum_url);
        if (download_if_missing(buffer, "primary.xml.gz") < 0)
@@ -1450,7 +1531,6 @@ command_install_or_update(int argc, char * const argv[], int do_update)
                razor_transaction_destroy(trans);
                razor_set_unref(upstream);
                razor_root_close(root);
-               razor_atomic_destroy(atomic);
                if (relocations)
                        razor_relocations_destroy(relocations);
                 return 1;