LCOV - code coverage report
Current view: top level - src/split - split.c (source / functions) Coverage Total Hit
Test: dpkg 1.22.7-3-g89f48 C code coverage Lines: 71.4 % 119 85
Test Date: 2024-07-17 02:53:43 Functions: 80.0 % 5 4
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 42.3 % 52 22

             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)
     103                 :           0 :                 ohshit(_("unable to parse timestamp '%.255s'"), value);
     104         [ -  + ]:           1 :         else if (errno != 0)
     105                 :           0 :                 ohshite(_("unable to parse timestamp '%.255s'"), value);
     106                 :             : 
     107                 :           1 :         return timestamp;
     108                 :             : }
     109                 :             : 
     110                 :             : /* Cleanup filename for use in crippled msdos systems. */
     111                 :             : static char *
     112                 :           0 : clean_msdos_filename(char *filename)
     113                 :             : {
     114                 :             :         char *d, *s;
     115                 :             : 
     116         [ #  # ]:           0 :         for (s = d = filename; *s; d++, s++) {
     117         [ #  # ]:           0 :                 if (*s == '+')
     118                 :           0 :                         *d = 'x';
     119         [ #  # ]:           0 :                 else if (c_isupper(*s))
     120                 :           0 :                         *d = c_tolower(*s);
     121   [ #  #  #  # ]:           0 :                 else if (c_islower(*s) || c_isdigit(*s))
     122                 :           0 :                         *d = *s;
     123                 :             :                 else
     124                 :           0 :                         s++;
     125                 :             :         }
     126                 :             : 
     127                 :           0 :         return filename;
     128                 :             : }
     129                 :             : 
     130                 :             : static int
     131                 :           1 : mksplit(const char *file_src, const char *prefix, off_t maxpartsize,
     132                 :             :         bool msdos)
     133                 :             : {
     134                 :             :         struct pkginfo *pkg;
     135                 :             :         struct dpkg_error err;
     136                 :             :         int fd_src;
     137                 :             :         struct stat st;
     138                 :             :         intmax_t timestamp;
     139                 :             :         const char *timestamp_str;
     140                 :             :         const char *version;
     141                 :             :         char hash[MD5HASHLEN + 1];
     142                 :             :         int nparts, curpart;
     143                 :             :         off_t partsize;
     144                 :             :         off_t cur_partsize, last_partsize;
     145                 :           1 :         char *prefixdir = NULL, *msdos_prefix = NULL;
     146                 :           1 :         struct varbuf file_dst = VARBUF_INIT;
     147                 :           1 :         struct varbuf partmagic = VARBUF_INIT;
     148                 :           1 :         struct varbuf partname = VARBUF_INIT;
     149                 :             : 
     150                 :           1 :         fd_src = open(file_src, O_RDONLY);
     151         [ -  + ]:           1 :         if (fd_src < 0)
     152                 :           0 :                 ohshite(_("unable to open source file '%.250s'"), file_src);
     153         [ -  + ]:           1 :         if (fstat(fd_src, &st))
     154                 :           0 :                 ohshite(_("unable to fstat source file"));
     155         [ -  + ]:           1 :         if (!S_ISREG(st.st_mode))
     156                 :           0 :                 ohshit(_("source file '%.250s' not a plain file"), file_src);
     157                 :             : 
     158         [ -  + ]:           1 :         if (fd_md5(fd_src, hash, -1, &err) < 0)
     159                 :           0 :                 ohshit(_("cannot compute MD5 digest for file '%s': %s"),
     160                 :             :                        file_src, err.str);
     161                 :           1 :         lseek(fd_src, 0, SEEK_SET);
     162                 :             : 
     163                 :           1 :         pkg  = deb_parse_control(file_src);
     164                 :           1 :         version = versiondescribe(&pkg->available.version, vdew_nonambig);
     165                 :             : 
     166                 :           1 :         timestamp_str = getenv("SOURCE_DATE_EPOCH");
     167         [ +  - ]:           1 :         if (str_is_set(timestamp_str))
     168                 :           1 :                 timestamp = parse_timestamp(timestamp_str);
     169                 :             :         else
     170                 :           0 :                 timestamp = time(NULL);
     171                 :             : 
     172                 :           1 :         partsize = maxpartsize - HEADERALLOWANCE;
     173                 :           1 :         last_partsize = st.st_size % partsize;
     174         [ -  + ]:           1 :         if (last_partsize == 0)
     175                 :           0 :                 last_partsize = partsize;
     176                 :           1 :         nparts = (st.st_size + partsize - 1) / partsize;
     177                 :             : 
     178                 :           1 :         printf(P_("Splitting package %s into %d part: ",
     179                 :             :                   "Splitting package %s into %d parts: ", nparts),
     180                 :           1 :                pkg->set->name, nparts);
     181                 :             : 
     182         [ -  + ]:           1 :         if (msdos) {
     183                 :             :                 char *t;
     184                 :             : 
     185                 :           0 :                 t = m_strdup(prefix);
     186                 :           0 :                 prefixdir = m_strdup(dirname(t));
     187                 :           0 :                 free(t);
     188                 :             : 
     189                 :           0 :                 msdos_prefix = m_strdup(path_basename(prefix));
     190                 :           0 :                 prefix = clean_msdos_filename(msdos_prefix);
     191                 :             :         }
     192                 :             : 
     193         [ +  + ]:          11 :         for (curpart = 1; curpart <= nparts; curpart++) {
     194                 :             :                 struct dpkg_ar *ar;
     195                 :             : 
     196                 :          10 :                 varbuf_reset(&file_dst);
     197                 :             :                 /* Generate output filename. */
     198         [ -  + ]:          10 :                 if (msdos) {
     199                 :             :                         char *refname;
     200                 :             :                         int prefix_max;
     201                 :             : 
     202                 :           0 :                         refname = str_fmt("%dof%d", curpart, nparts);
     203         [ #  # ]:           0 :                         prefix_max = max(8 - strlen(refname), 0);
     204                 :           0 :                         varbuf_printf(&file_dst, "%s/%.*s%.8s" DEBEXT,
     205                 :             :                                       prefixdir, prefix_max, prefix, refname);
     206                 :           0 :                         free(refname);
     207                 :             :                 } else {
     208                 :          10 :                         varbuf_printf(&file_dst, "%s.%dof%d" DEBEXT,
     209                 :             :                                       prefix, curpart, nparts);
     210                 :             :                 }
     211                 :             : 
     212         [ +  + ]:          10 :                 if (curpart == nparts)
     213                 :           1 :                         cur_partsize = last_partsize;
     214                 :             :                 else
     215                 :           9 :                         cur_partsize = partsize;
     216                 :             : 
     217         [ -  + ]:          10 :                 if (cur_partsize > maxpartsize) {
     218                 :           0 :                         ohshit(_("header is too long, making part too long; "
     219                 :             :                                  "the package name or version\n"
     220                 :             :                                  "numbers must be extraordinarily long, "
     221                 :             :                                  "or something; giving up"));
     222                 :             :                 }
     223                 :             : 
     224                 :             :                 /* Split the data. */
     225                 :          10 :                 ar = dpkg_ar_create(file_dst.buf, 0644);
     226                 :          10 :                 dpkg_ar_set_mtime(ar, timestamp);
     227                 :             : 
     228                 :             :                 /* Write the ar header. */
     229                 :          10 :                 dpkg_ar_put_magic(ar);
     230                 :             : 
     231                 :             :                 /* Write the debian-split part. */
     232                 :          10 :                 varbuf_printf(&partmagic,
     233                 :             :                               "%s\n%s\n%s\n%s\n%jd\n%jd\n%d/%d\n%s\n",
     234                 :          10 :                               SPLITVERSION, pkg->set->name, version, hash,
     235                 :          10 :                               (intmax_t)st.st_size, (intmax_t)partsize,
     236                 :          10 :                               curpart, nparts, pkg->available.arch->name);
     237                 :          10 :                 dpkg_ar_member_put_mem(ar, PARTMAGIC,
     238                 :          10 :                                        partmagic.buf, partmagic.used);
     239                 :          10 :                 varbuf_reset(&partmagic);
     240                 :             : 
     241                 :             :                 /* Write the data part. */
     242                 :          10 :                 varbuf_printf(&partname, "data.%d", curpart);
     243                 :          10 :                 dpkg_ar_member_put_file(ar, partname.buf,
     244                 :             :                                         fd_src, cur_partsize);
     245                 :          10 :                 varbuf_reset(&partname);
     246                 :             : 
     247                 :          10 :                 dpkg_ar_close(ar);
     248                 :             : 
     249                 :          10 :                 printf("%d ", curpart);
     250                 :             :         }
     251                 :             : 
     252                 :           1 :         varbuf_destroy(&file_dst);
     253                 :           1 :         varbuf_destroy(&partname);
     254                 :           1 :         varbuf_destroy(&partmagic);
     255                 :             : 
     256                 :           1 :         free(prefixdir);
     257                 :           1 :         free(msdos_prefix);
     258                 :             : 
     259                 :           1 :         close(fd_src);
     260                 :             : 
     261                 :           1 :         printf(_("done\n"));
     262                 :             : 
     263                 :           1 :         return 0;
     264                 :             : }
     265                 :             : 
     266                 :             : int
     267                 :           1 : do_split(const char *const *argv)
     268                 :             : {
     269                 :             :         const char *sourcefile, *prefix;
     270                 :             : 
     271                 :           1 :         sourcefile = *argv++;
     272         [ -  + ]:           1 :         if (!sourcefile)
     273                 :           0 :                 badusage(_("--split needs a source filename argument"));
     274                 :           1 :         prefix = *argv++;
     275   [ +  -  -  + ]:           1 :         if (prefix && *argv)
     276                 :           0 :                 badusage(_("--split takes at most a source filename and destination prefix"));
     277         [ -  + ]:           1 :         if (!prefix) {
     278                 :           0 :                 size_t sourcefile_len = strlen(sourcefile);
     279                 :             : 
     280         [ #  # ]:           0 :                 if (str_match_end(sourcefile, DEBEXT))
     281                 :           0 :                         sourcefile_len -= strlen(DEBEXT);
     282                 :             : 
     283                 :           0 :                 prefix = nfstrnsave(sourcefile, sourcefile_len);
     284                 :             :         }
     285                 :             : 
     286                 :           1 :         mksplit(sourcefile, prefix, opt_maxpartsize, opt_msdos);
     287                 :             : 
     288                 :           1 :         return 0;
     289                 :             : }
        

Generated by: LCOV version 2.0-1