LCOV - code coverage report
Current view: top level - libpkg - packing.c (source / functions) Hit Total Coverage
Test: cov.info Lines: 96 201 47.8 %
Date: 2015-08-15 Functions: 7 8 87.5 %

          Line data    Source code
       1             : /*-
       2             :  * Copyright (c) 2011-2014 Baptiste Daroussin <bapt@FreeBSD.org>
       3             :  * Copyright (c) 2011 Will Andrews <will@FreeBSD.org>
       4             :  * All rights reserved.
       5             :  * 
       6             :  * Redistribution and use in source and binary forms, with or without
       7             :  * modification, are permitted provided that the following conditions
       8             :  * are met:
       9             :  * 1. Redistributions of source code must retain the above copyright
      10             :  *    notice, this list of conditions and the following disclaimer
      11             :  *    in this position and unchanged.
      12             :  * 2. Redistributions in binary form must reproduce the above copyright
      13             :  *    notice, this list of conditions and the following disclaimer in the
      14             :  *    documentation and/or other materials provided with the distribution.
      15             :  * 
      16             :  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
      17             :  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
      18             :  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
      19             :  * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
      20             :  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
      21             :  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
      22             :  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      23             :  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
      24             :  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
      25             :  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      26             :  */
      27             : 
      28             : 
      29             : #include <archive.h>
      30             : #include <archive_entry.h>
      31             : #include <assert.h>
      32             : #include <fcntl.h>
      33             : #include <fts.h>
      34             : #include <string.h>
      35             : #include <sys/mman.h>
      36             : #include <pwd.h>
      37             : #include <grp.h>
      38             : 
      39             : #include "pkg.h"
      40             : #include "private/event.h"
      41             : #include "private/pkg.h"
      42             : 
      43             : static const char *packing_set_format(struct archive *a, pkg_formats format);
      44             : 
      45             : struct packing {
      46             :         bool pass;
      47             :         struct archive *aread;
      48             :         struct archive *awrite;
      49             :         struct archive_entry_linkresolver *resolver;
      50             : };
      51             : 
      52             : int
      53          93 : packing_init(struct packing **pack, const char *path, pkg_formats format, bool passmode)
      54             : {
      55             :         char archive_path[MAXPATHLEN];
      56             :         const char *ext;
      57             : 
      58          93 :         assert(pack != NULL);
      59             : 
      60          93 :         if (passmode && !is_dir(path)) {
      61           0 :                 pkg_emit_error("When using passmode, a directory should be provided");
      62           0 :                 return (EPKG_FATAL);
      63             :         }
      64             : 
      65          93 :         if ((*pack = calloc(1, sizeof(struct packing))) == NULL) {
      66           0 :                 pkg_emit_errno("calloc", "packing");
      67           0 :                 return (EPKG_FATAL);
      68             :         }
      69             : 
      70          93 :         (*pack)->aread = archive_read_disk_new();
      71          93 :         archive_read_disk_set_standard_lookup((*pack)->aread);
      72          93 :         archive_read_disk_set_symlink_physical((*pack)->aread);
      73             : 
      74          93 :         if (!passmode) {
      75          92 :                 (*pack)->pass = false;
      76          92 :                 (*pack)->awrite = archive_write_new();
      77          92 :                 archive_write_set_format_pax_restricted((*pack)->awrite);
      78          92 :                 ext = packing_set_format((*pack)->awrite, format);
      79          92 :                 if (ext == NULL) {
      80           0 :                         archive_read_close((*pack)->aread);
      81           0 :                         archive_read_free((*pack)->aread);
      82           0 :                         archive_write_close((*pack)->awrite);
      83           0 :                         archive_write_free((*pack)->awrite);
      84           0 :                         *pack = NULL;
      85           0 :                         return EPKG_FATAL; /* error set by _set_format() */
      86             :                 }
      87          92 :                 snprintf(archive_path, sizeof(archive_path), "%s.%s", path,
      88             :                     ext);
      89             : 
      90          92 :                 pkg_debug(1, "Packing to file '%s'", archive_path);
      91          92 :                 if (archive_write_open_filename(
      92          92 :                     (*pack)->awrite, archive_path) != ARCHIVE_OK) {
      93           0 :                         pkg_emit_errno("archive_write_open_filename",
      94             :                             archive_path);
      95           0 :                         archive_read_close((*pack)->aread);
      96           0 :                         archive_read_free((*pack)->aread);
      97           0 :                         archive_write_close((*pack)->awrite);
      98           0 :                         archive_write_free((*pack)->awrite);
      99           0 :                         *pack = NULL;
     100           0 :                         return EPKG_FATAL;
     101             :                 }
     102             :         } else { /* pass mode directly write to the disk */
     103           1 :                 pkg_debug(1, "Packing to directory '%s' (pass mode)", path);
     104           1 :                 (*pack)->pass = true;
     105           1 :                 (*pack)->awrite = archive_write_disk_new();
     106           1 :                 archive_write_disk_set_options((*pack)->awrite,
     107             :                     EXTRACT_ARCHIVE_FLAGS);
     108             :         }
     109             : 
     110          93 :         (*pack)->resolver = archive_entry_linkresolver_new();
     111          93 :         archive_entry_linkresolver_set_strategy((*pack)->resolver,
     112             :             ARCHIVE_FORMAT_TAR_PAX_RESTRICTED);
     113             : 
     114          93 :         return (EPKG_OK);
     115             : }
     116             : 
     117             : int
     118         118 : packing_append_buffer(struct packing *pack, const char *buffer,
     119             :     const char *path, int size)
     120             : {
     121             :         struct archive_entry *entry;
     122         118 :         int ret = EPKG_OK;
     123             : 
     124         118 :         entry = archive_entry_new();
     125         118 :         archive_entry_clear(entry);
     126         118 :         archive_entry_set_filetype(entry, AE_IFREG);
     127         118 :         archive_entry_set_perm(entry, 0644);
     128         118 :         archive_entry_set_gname(entry, "wheel");
     129         118 :         archive_entry_set_uname(entry, "root");
     130         118 :         archive_entry_set_pathname(entry, path);
     131         118 :         archive_entry_set_size(entry, size);
     132         118 :         if (archive_write_header(pack->awrite, entry) == -1) {
     133           0 :                 pkg_emit_errno("archive_write_header", path);
     134           0 :                 ret = EPKG_FATAL;
     135           0 :                 goto cleanup;
     136             :         }
     137             : 
     138         118 :         if (archive_write_data(pack->awrite, buffer, size) == -1) {
     139           0 :                 pkg_emit_errno("archive_write_data", path);
     140           0 :                 ret = EPKG_FATAL;
     141             :         }
     142             : 
     143             : cleanup:
     144         118 :         archive_entry_free(entry);
     145             : 
     146         118 :         return (ret);
     147             : }
     148             : 
     149             : int
     150          90 : packing_append_file_attr(struct packing *pack, const char *filepath,
     151             :     const char *newpath, const char *uname, const char *gname, mode_t perm,
     152             :     u_long fflags)
     153             : {
     154             :         int fd;
     155             :         char *map;
     156          90 :         int retcode = EPKG_OK;
     157             :         int ret;
     158             :         struct stat st;
     159             :         struct archive_entry *entry, *sparse_entry;
     160             :         bool unset_timestamp;
     161             : 
     162          90 :         entry = archive_entry_new();
     163          90 :         archive_entry_copy_sourcepath(entry, filepath);
     164             : 
     165          90 :         pkg_debug(2, "Packing file '%s'", filepath);
     166             : 
     167          90 :         if (lstat(filepath, &st) != 0) {
     168           0 :                 pkg_emit_errno("lstat", filepath);
     169           0 :                 retcode = EPKG_FATAL;
     170           0 :                 goto cleanup;
     171             :         }
     172             : 
     173          90 :         ret = archive_read_disk_entry_from_file(pack->aread, entry, -1,
     174             :                         &st);
     175          90 :         if (ret != ARCHIVE_OK) {
     176           0 :                 pkg_emit_error("%s: %s", filepath,
     177             :                                 archive_error_string(pack->aread));
     178           0 :                 retcode = EPKG_FATAL;
     179           0 :                 goto cleanup;
     180             :         }
     181             : 
     182          90 :         if (newpath != NULL)
     183          90 :                 archive_entry_set_pathname(entry, newpath);
     184             : 
     185          90 :         if (archive_entry_filetype(entry) != AE_IFREG) {
     186           8 :                 archive_entry_set_size(entry, 0);
     187             :         }
     188             : 
     189          90 :         if (uname != NULL && uname[0] != '\0') {
     190          53 :                 if (pack->pass) {
     191           0 :                         struct passwd* pw = getpwnam(uname);
     192           0 :                         if (pw == NULL) {
     193           0 :                                 pkg_emit_error("Unknown user: '%s'", uname);
     194           0 :                                 retcode = EPKG_FATAL;
     195           0 :                                 goto cleanup;
     196             :                         }
     197           0 :                         archive_entry_set_uid(entry, pw->pw_uid);
     198             :                 }
     199          53 :                 archive_entry_set_uname(entry, uname);
     200             :         }
     201             : 
     202          90 :         if (gname != NULL && gname[0] != '\0') {
     203          53 :                 if (pack->pass) {
     204           0 :                         struct group *gr = (getgrnam(gname));
     205           0 :                         if (gr == NULL) {
     206           0 :                                 pkg_emit_error("Unknown group: '%s'", gname);
     207           0 :                                 retcode = EPKG_FATAL;
     208           0 :                                 goto cleanup;
     209             :                         }
     210           0 :                         archive_entry_set_gid(entry, gr->gr_gid);
     211             :                 }
     212          53 :                 archive_entry_set_gname(entry, gname);
     213             :         }
     214             : 
     215          90 :         if (fflags > 0)
     216           1 :                 archive_entry_set_fflags(entry, fflags, 0);
     217             : 
     218          90 :         if (perm != 0)
     219          34 :                 archive_entry_set_perm(entry, perm);
     220             : 
     221          90 :         unset_timestamp = pkg_object_bool(pkg_config_get("UNSET_TIMESTAMP"));
     222             : 
     223          90 :         if (unset_timestamp) {
     224           0 :                 archive_entry_unset_atime(entry);
     225           0 :                 archive_entry_unset_ctime(entry);
     226           0 :                 archive_entry_unset_mtime(entry);
     227           0 :                 archive_entry_unset_birthtime(entry);
     228             :         }
     229             : 
     230          90 :         archive_entry_linkify(pack->resolver, &entry, &sparse_entry);
     231             : 
     232          90 :         if (sparse_entry != NULL && entry == NULL)
     233           0 :                 entry = sparse_entry;
     234             : 
     235          90 :         archive_write_header(pack->awrite, entry);
     236             : 
     237          90 :         if (archive_entry_size(entry) > 0) {
     238          34 :                 if ((fd = open(filepath, O_RDONLY)) < 0) {
     239           0 :                         pkg_emit_errno("open", filepath);
     240           0 :                         retcode = EPKG_FATAL;
     241           0 :                         goto cleanup;
     242             :                 }
     243             :                 if (st.st_size > SSIZE_MAX) {
     244             :                         char buf[BUFSIZ];
     245             :                         int len;
     246             : 
     247             :                         while ((len = read(fd, buf, sizeof(buf))) > 0)
     248             :                                 if (archive_write_data(pack->awrite, buf, len) == -1) {
     249             :                                         pkg_emit_errno("archive_write_data", "archive write error");
     250             :                                         retcode = EPKG_FATAL;
     251             :                                         break;
     252             :                                 }
     253             : 
     254             :                         if (len == -1) {
     255             :                                 pkg_emit_errno("read", "file read error");
     256             :                                 retcode = EPKG_FATAL;
     257             :                         }
     258             :                         close(fd);
     259             :                 }
     260             :                 else {
     261          34 :                         if ((map = mmap(NULL, st.st_size, PROT_READ,
     262             :                                         MAP_SHARED, fd, 0)) != MAP_FAILED) {
     263          34 :                                 close(fd);
     264          34 :                                 if (archive_write_data(pack->awrite, map, st.st_size) == -1) {
     265           0 :                                         pkg_emit_errno("archive_write_data", "archive write error");
     266           0 :                                         retcode = EPKG_FATAL;
     267             :                                 }
     268          34 :                                 munmap(map, st.st_size);
     269             :                         }
     270             :                         else {
     271           0 :                                 close(fd);
     272           0 :                                 pkg_emit_errno("open", filepath);
     273           0 :                                 retcode = EPKG_FATAL;
     274           0 :                                 goto cleanup;
     275             :                         }
     276             :                 }
     277             :         }
     278             : 
     279             :         cleanup:
     280          90 :         archive_entry_free(entry);
     281          90 :         return (retcode);
     282             : }
     283             : 
     284             : int
     285           0 : packing_append_tree(struct packing *pack, const char *treepath,
     286             :     const char *newroot)
     287             : {
     288           0 :         FTS *fts = NULL;
     289           0 :         FTSENT *fts_e = NULL;
     290             :         size_t treelen;
     291             :         struct sbuf *sb;
     292           0 :         char *paths[2] = { __DECONST(char *, treepath), NULL };
     293             : 
     294           0 :         treelen = strlen(treepath);
     295           0 :         fts = fts_open(paths, FTS_PHYSICAL | FTS_XDEV, NULL);
     296           0 :         if (fts == NULL)
     297           0 :                 goto cleanup;
     298             : 
     299           0 :         sb = sbuf_new_auto();
     300           0 :         while ((fts_e = fts_read(fts)) != NULL) {
     301           0 :                 switch(fts_e->fts_info) {
     302             :                 case FTS_D:
     303             :                 case FTS_DEFAULT:
     304             :                 case FTS_F:
     305             :                 case FTS_SL:
     306             :                 case FTS_SLNONE:
     307             :                          /* Entries not within this tree are irrelevant. */
     308           0 :                          if (fts_e->fts_pathlen <= treelen)
     309           0 :                                   break;
     310           0 :                          sbuf_clear(sb);
     311             :                          /* Strip the prefix to obtain the target path */
     312           0 :                          if (newroot) /* Prepend a root if one is specified */
     313           0 :                                   sbuf_cat(sb, newroot);
     314             :                          /* +1 = skip trailing slash */
     315           0 :                          sbuf_cat(sb, fts_e->fts_path + treelen + 1);
     316           0 :                          sbuf_finish(sb);
     317           0 :                          packing_append_file_attr(pack, fts_e->fts_name,
     318           0 :                             sbuf_data(sb), NULL, NULL, 0, 0);
     319           0 :                          break;
     320             :                 case FTS_DC:
     321             :                 case FTS_DNR:
     322             :                 case FTS_ERR:
     323             :                 case FTS_NS:
     324             :                          /* XXX error cases, check fts_e->fts_errno and
     325             :                           *     bubble up the call chain */
     326           0 :                          break;
     327             :                 default:
     328           0 :                          break;
     329             :                 }
     330             :         }
     331           0 :         sbuf_free(sb);
     332             : cleanup:
     333           0 :         fts_close(fts);
     334           0 :         return EPKG_OK;
     335             : }
     336             : 
     337             : void
     338         100 : packing_finish(struct packing *pack)
     339             : {
     340         100 :         if (pack == NULL)
     341         107 :                 return;
     342             : 
     343          93 :         archive_read_close(pack->aread);
     344          93 :         archive_read_free(pack->aread);
     345             : 
     346          93 :         archive_write_close(pack->awrite);
     347          93 :         archive_write_free(pack->awrite);
     348             : 
     349          93 :         free(pack);
     350             : }
     351             : 
     352             : static const char *
     353          92 : packing_set_format(struct archive *a, pkg_formats format)
     354             : {
     355          92 :         const char *notsupp_fmt = "%s is not supported, trying %s";
     356             : 
     357          92 :         switch (format) {
     358             :         case TXZ:
     359          92 :                 if (archive_write_add_filter_xz(a) == ARCHIVE_OK)
     360          92 :                         return ("txz");
     361             :                 else
     362           0 :                         pkg_emit_error(notsupp_fmt, "xz", "bzip2");
     363             :         case TBZ:
     364           0 :                 if (archive_write_add_filter_bzip2(a) == ARCHIVE_OK)
     365           0 :                         return ("tbz");
     366             :                 else
     367           0 :                         pkg_emit_error(notsupp_fmt, "bzip2", "gzip");
     368             :         case TGZ:
     369           0 :                 if (archive_write_add_filter_gzip(a) == ARCHIVE_OK)
     370           0 :                         return ("tgz");
     371             :                 else
     372           0 :                         pkg_emit_error(notsupp_fmt, "gzip", "plain tar");
     373             :         case TAR:
     374           0 :                 archive_write_add_filter_none(a);
     375           0 :                 return ("tar");
     376             :         }
     377           0 :         return (NULL);
     378             : }
     379             : 
     380             : pkg_formats
     381          34 : packing_format_from_string(const char *str)
     382             : {
     383          34 :         if (str == NULL)
     384           0 :                 return TXZ;
     385          34 :         if (strcmp(str, "txz") == 0)
     386          34 :                 return TXZ;
     387           0 :         if (strcmp(str, "tbz") == 0)
     388           0 :                 return TBZ;
     389           0 :         if (strcmp(str, "tgz") == 0)
     390           0 :                 return TGZ;
     391           0 :         if (strcmp(str, "tar") == 0)
     392           0 :                 return TAR;
     393           0 :         pkg_emit_error("unknown format %s, using txz", str);
     394           0 :         return TXZ;
     395             : }
     396             : 
     397             : const char*
     398         336 : packing_format_to_string(pkg_formats format)
     399             : {
     400         336 :         const char *res = NULL;
     401             : 
     402         336 :         switch (format) {
     403             :         case TXZ:
     404         336 :                 res = "txz";
     405         336 :                 break;
     406             :         case TBZ:
     407           0 :                 res = "tbz";
     408           0 :                 break;
     409             :         case TGZ:
     410           0 :                 res = "tgz";
     411           0 :                 break;
     412             :         case TAR:
     413           0 :                 res = "tar";
     414           0 :                 break;
     415             :         }
     416             : 
     417         336 :         return (res);
     418             : }

Generated by: LCOV version 1.10