LCOV - code coverage report
Current view: top level - src/split - split.c (source / functions) Hit Total Coverage
Test: dpkg 1.21.11 C code coverage Lines: 84 117 71.8 %
Date: 2022-12-03 00:40:01 Functions: 4 5 80.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 22 52 42.3 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * dpkg-split - splitting and joining of multipart *.deb archives
       3                 :            :  * split.c - splitting archives
       4                 :            :  *
       5                 :            :  * Copyright © 1995 Ian Jackson <ijackson@chiark.greenend.org.uk>
       6                 :            :  * Copyright © 2008-2015 Guillem Jover <guillem@debian.org>
       7                 :            :  *
       8                 :            :  * This is free software; you can redistribute it and/or modify
       9                 :            :  * it under the terms of the GNU General Public License as published by
      10                 :            :  * the Free Software Foundation; either version 2 of the License, or
      11                 :            :  * (at your option) any later version.
      12                 :            :  *
      13                 :            :  * This is distributed in the hope that it will be useful,
      14                 :            :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      15                 :            :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16                 :            :  * GNU General Public License for more details.
      17                 :            :  *
      18                 :            :  * You should have received a copy of the GNU General Public License
      19                 :            :  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
      20                 :            :  */
      21                 :            : 
      22                 :            : #include <config.h>
      23                 :            : #include <compat.h>
      24                 :            : 
      25                 :            : #include <sys/types.h>
      26                 :            : #include <sys/stat.h>
      27                 :            : #include <sys/wait.h>
      28                 :            : 
      29                 :            : #include <errno.h>
      30                 :            : #include <limits.h>
      31                 :            : #include <inttypes.h>
      32                 :            : #include <fcntl.h>
      33                 :            : #include <libgen.h>
      34                 :            : #include <string.h>
      35                 :            : #include <time.h>
      36                 :            : #include <unistd.h>
      37                 :            : #include <stdint.h>
      38                 :            : #include <stdlib.h>
      39                 :            : #include <stdio.h>
      40                 :            : 
      41                 :            : #include <dpkg/i18n.h>
      42                 :            : #include <dpkg/c-ctype.h>
      43                 :            : #include <dpkg/dpkg.h>
      44                 :            : #include <dpkg/dpkg-db.h>
      45                 :            : #include <dpkg/parsedump.h>
      46                 :            : #include <dpkg/path.h>
      47                 :            : #include <dpkg/string.h>
      48                 :            : #include <dpkg/subproc.h>
      49                 :            : #include <dpkg/buffer.h>
      50                 :            : #include <dpkg/ar.h>
      51                 :            : #include <dpkg/options.h>
      52                 :            : 
      53                 :            : #include "dpkg-split.h"
      54                 :            : 
      55                 :            : /**
      56                 :            :  * Parse the control file from a .deb package into a struct pkginfo.
      57                 :            :  */
      58                 :            : static struct pkginfo *
      59                 :          1 : deb_parse_control(const char *filename)
      60                 :            : {
      61                 :            :         struct parsedb_state *ps;
      62                 :            :         struct pkginfo *pkg;
      63                 :            :         pid_t pid;
      64                 :            :         int p[2];
      65                 :            : 
      66                 :          1 :         m_pipe(p);
      67                 :            : 
      68                 :          1 :         pid = subproc_fork();
      69         [ +  + ]:          2 :         if (pid == 0) {
      70                 :            :                 /* Child writes to pipe. */
      71                 :          1 :                 m_dup2(p[1], 1);
      72                 :          1 :                 close(p[0]);
      73                 :          1 :                 close(p[1]);
      74                 :            : 
      75                 :          1 :                 execlp(BACKEND, BACKEND, "--info", filename, "control", NULL);
      76                 :          1 :                 ohshite(_("unable to execute %s (%s)"),
      77                 :            :                         _("package field value extraction"), BACKEND);
      78                 :            :         }
      79                 :          1 :         close(p[1]);
      80                 :            : 
      81                 :            :         /* Parent reads from pipe. */
      82                 :          1 :         ps = parsedb_new(_("<dpkg-deb --info pipe>"), p[0], pdb_parse_binary);
      83                 :          1 :         parsedb_load(ps);
      84                 :          1 :         parsedb_parse(ps, &pkg);
      85                 :          1 :         parsedb_close(ps);
      86                 :            : 
      87                 :          1 :         close(p[0]);
      88                 :            : 
      89                 :          1 :         subproc_reap(pid, _("package field value extraction"), SUBPROC_NOPIPE);
      90                 :            : 
      91                 :          1 :         return pkg;
      92                 :            : }
      93                 :            : 
      94                 :            : static intmax_t
      95                 :          1 : parse_timestamp(const char *value)
      96                 :            : {
      97                 :            :         intmax_t timestamp;
      98                 :            :         char *end;
      99                 :            : 
     100                 :          1 :         errno = 0;
     101                 :          1 :         timestamp = strtoimax(value, &end, 10);
     102   [ +  -  +  -  :          1 :         if (value == end || *end || errno != 0)
                   -  + ]
     103                 :          0 :                 ohshite(_("unable to parse timestamp '%.255s'"), value);
     104                 :            : 
     105                 :          1 :         return timestamp;
     106                 :            : }
     107                 :            : 
     108                 :            : /* Cleanup filename for use in crippled msdos systems. */
     109                 :            : static char *
     110                 :          0 : clean_msdos_filename(char *filename)
     111                 :            : {
     112                 :            :         char *d, *s;
     113                 :            : 
     114         [ #  # ]:          0 :         for (s = d = filename; *s; d++, s++) {
     115         [ #  # ]:          0 :                 if (*s == '+')
     116                 :          0 :                         *d = 'x';
     117         [ #  # ]:          0 :                 else if (c_isupper(*s))
     118                 :          0 :                         *d = c_tolower(*s);
     119   [ #  #  #  # ]:          0 :                 else if (c_islower(*s) || c_isdigit(*s))
     120                 :          0 :                         *d = *s;
     121                 :            :                 else
     122                 :          0 :                         s++;
     123                 :            :         }
     124                 :            : 
     125                 :          0 :         return filename;
     126                 :            : }
     127                 :            : 
     128                 :            : static int
     129                 :          1 : mksplit(const char *file_src, const char *prefix, off_t maxpartsize,
     130                 :            :         bool msdos)
     131                 :            : {
     132                 :            :         struct pkginfo *pkg;
     133                 :            :         struct dpkg_error err;
     134                 :            :         int fd_src;
     135                 :            :         struct stat st;
     136                 :            :         intmax_t timestamp;
     137                 :            :         const char *timestamp_str;
     138                 :            :         const char *version;
     139                 :            :         char hash[MD5HASHLEN + 1];
     140                 :            :         int nparts, curpart;
     141                 :            :         off_t partsize;
     142                 :            :         off_t cur_partsize, last_partsize;
     143                 :          1 :         char *prefixdir = NULL, *msdos_prefix = NULL;
     144                 :          1 :         struct varbuf file_dst = VARBUF_INIT;
     145                 :          1 :         struct varbuf partmagic = VARBUF_INIT;
     146                 :          1 :         struct varbuf partname = VARBUF_INIT;
     147                 :            : 
     148                 :          1 :         fd_src = open(file_src, O_RDONLY);
     149         [ -  + ]:          1 :         if (fd_src < 0)
     150                 :          0 :                 ohshite(_("unable to open source file '%.250s'"), file_src);
     151         [ -  + ]:          1 :         if (fstat(fd_src, &st))
     152                 :          0 :                 ohshite(_("unable to fstat source file"));
     153         [ -  + ]:          1 :         if (!S_ISREG(st.st_mode))
     154                 :          0 :                 ohshit(_("source file '%.250s' not a plain file"), file_src);
     155                 :            : 
     156         [ -  + ]:          1 :         if (fd_md5(fd_src, hash, -1, &err) < 0)
     157                 :          0 :                 ohshit(_("cannot compute MD5 digest for file '%s': %s"),
     158                 :            :                        file_src, err.str);
     159                 :          1 :         lseek(fd_src, 0, SEEK_SET);
     160                 :            : 
     161                 :          1 :         pkg  = deb_parse_control(file_src);
     162                 :          1 :         version = versiondescribe(&pkg->available.version, vdew_nonambig);
     163                 :            : 
     164                 :          1 :         timestamp_str = getenv("SOURCE_DATE_EPOCH");
     165         [ +  - ]:          1 :         if (timestamp_str)
     166                 :          1 :                 timestamp = parse_timestamp(timestamp_str);
     167                 :            :         else
     168                 :          0 :                 timestamp = time(NULL);
     169                 :            : 
     170                 :          1 :         partsize = maxpartsize - HEADERALLOWANCE;
     171                 :          1 :         last_partsize = st.st_size % partsize;
     172         [ -  + ]:          1 :         if (last_partsize == 0)
     173                 :          0 :                 last_partsize = partsize;
     174                 :          1 :         nparts = (st.st_size + partsize - 1) / partsize;
     175                 :            : 
     176                 :          1 :         printf(P_("Splitting package %s into %d part: ",
     177                 :            :                   "Splitting package %s into %d parts: ", nparts),
     178                 :          1 :                pkg->set->name, nparts);
     179                 :            : 
     180         [ -  + ]:          1 :         if (msdos) {
     181                 :            :                 char *t;
     182                 :            : 
     183                 :          0 :                 t = m_strdup(prefix);
     184                 :          0 :                 prefixdir = m_strdup(dirname(t));
     185                 :          0 :                 free(t);
     186                 :            : 
     187                 :          0 :                 msdos_prefix = m_strdup(path_basename(prefix));
     188                 :          0 :                 prefix = clean_msdos_filename(msdos_prefix);
     189                 :            :         }
     190                 :            : 
     191         [ +  + ]:         11 :         for (curpart = 1; curpart <= nparts; curpart++) {
     192                 :            :                 struct dpkg_ar *ar;
     193                 :            : 
     194                 :         10 :                 varbuf_reset(&file_dst);
     195                 :            :                 /* Generate output filename. */
     196         [ -  + ]:         10 :                 if (msdos) {
     197                 :            :                         char *refname;
     198                 :            :                         int prefix_max;
     199                 :            : 
     200                 :          0 :                         refname = str_fmt("%dof%d", curpart, nparts);
     201         [ #  # ]:          0 :                         prefix_max = max(8 - strlen(refname), 0);
     202                 :          0 :                         varbuf_printf(&file_dst, "%s/%.*s%.8s.deb",
     203                 :            :                                       prefixdir, prefix_max, prefix, refname);
     204                 :          0 :                         free(refname);
     205                 :            :                 } else {
     206                 :         10 :                         varbuf_printf(&file_dst, "%s.%dof%d.deb",
     207                 :            :                                       prefix, curpart, nparts);
     208                 :            :                 }
     209                 :            : 
     210         [ +  + ]:         10 :                 if (curpart == nparts)
     211                 :          1 :                         cur_partsize = last_partsize;
     212                 :            :                 else
     213                 :          9 :                         cur_partsize = partsize;
     214                 :            : 
     215         [ -  + ]:         10 :                 if (cur_partsize > maxpartsize) {
     216                 :          0 :                         ohshit(_("header is too long, making part too long; "
     217                 :            :                                  "the package name or version\n"
     218                 :            :                                  "numbers must be extraordinarily long, "
     219                 :            :                                  "or something; giving up"));
     220                 :            :                 }
     221                 :            : 
     222                 :            :                 /* Split the data. */
     223                 :         10 :                 ar = dpkg_ar_create(file_dst.buf, 0644);
     224                 :         10 :                 dpkg_ar_set_mtime(ar, timestamp);
     225                 :            : 
     226                 :            :                 /* Write the ar header. */
     227                 :         10 :                 dpkg_ar_put_magic(ar);
     228                 :            : 
     229                 :            :                 /* Write the debian-split part. */
     230                 :         10 :                 varbuf_printf(&partmagic,
     231                 :            :                               "%s\n%s\n%s\n%s\n%jd\n%jd\n%d/%d\n%s\n",
     232                 :         10 :                               SPLITVERSION, pkg->set->name, version, hash,
     233                 :         10 :                               (intmax_t)st.st_size, (intmax_t)partsize,
     234                 :         10 :                               curpart, nparts, pkg->available.arch->name);
     235                 :         10 :                 dpkg_ar_member_put_mem(ar, PARTMAGIC,
     236                 :         10 :                                        partmagic.buf, partmagic.used);
     237                 :         10 :                 varbuf_reset(&partmagic);
     238                 :            : 
     239                 :            :                 /* Write the data part. */
     240                 :         10 :                 varbuf_printf(&partname, "data.%d", curpart);
     241                 :         10 :                 dpkg_ar_member_put_file(ar, partname.buf,
     242                 :            :                                         fd_src, cur_partsize);
     243                 :         10 :                 varbuf_reset(&partname);
     244                 :            : 
     245                 :         10 :                 dpkg_ar_close(ar);
     246                 :            : 
     247                 :         10 :                 printf("%d ", curpart);
     248                 :            :         }
     249                 :            : 
     250                 :          1 :         varbuf_destroy(&file_dst);
     251                 :          1 :         varbuf_destroy(&partname);
     252                 :          1 :         varbuf_destroy(&partmagic);
     253                 :            : 
     254                 :          1 :         free(prefixdir);
     255                 :          1 :         free(msdos_prefix);
     256                 :            : 
     257                 :          1 :         close(fd_src);
     258                 :            : 
     259                 :          1 :         printf(_("done\n"));
     260                 :            : 
     261                 :          1 :         return 0;
     262                 :            : }
     263                 :            : 
     264                 :            : int
     265                 :          1 : do_split(const char *const *argv)
     266                 :            : {
     267                 :            :         const char *sourcefile, *prefix;
     268                 :            : 
     269                 :          1 :         sourcefile = *argv++;
     270         [ -  + ]:          1 :         if (!sourcefile)
     271                 :          0 :                 badusage(_("--split needs a source filename argument"));
     272                 :          1 :         prefix = *argv++;
     273   [ +  -  -  + ]:          1 :         if (prefix && *argv)
     274                 :          0 :                 badusage(_("--split takes at most a source filename and destination prefix"));
     275         [ -  + ]:          1 :         if (!prefix) {
     276                 :          0 :                 size_t sourcefile_len = strlen(sourcefile);
     277                 :            : 
     278         [ #  # ]:          0 :                 if (str_match_end(sourcefile, DEBEXT))
     279                 :          0 :                         sourcefile_len -= strlen(DEBEXT);
     280                 :            : 
     281                 :          0 :                 prefix = nfstrnsave(sourcefile, sourcefile_len);
     282                 :            :         }
     283                 :            : 
     284                 :          1 :         mksplit(sourcefile, prefix, opt_maxpartsize, opt_msdos);
     285                 :            : 
     286                 :          1 :         return 0;
     287                 :            : }

Generated by: LCOV version 1.16