LTP GCOV extension - code coverage report
Current view: directory - src/libutil - archive.cc
Test: app.info
Date: 2006-10-11 Instrumented lines: 174
Code covered: 87.9 % Executed lines: 153

       1                 : #include <cerrno>
       2                 : #include <algorithm>
       3                 : #include <vector>
       4                 : 
       5                 : #include <sys/types.h>
       6                 : #include <sys/stat.h>
       7                 : #include <unistd.h>
       8                 : #include <dirent.h>
       9                 : #include <fcntl.h>
      10                 : 
      11                 : #include "archive.hh"
      12                 : #include "util.hh"
      13                 : 
      14                 : 
      15                 : namespace nix {
      16                 : 
      17                 : 
      18             345 : static string archiveVersion1 = "nix-archive-1";
      19                 : 
      20                 : 
      21                 : static void writePadding(unsigned int len, DumpSink & sink)
      22           21448 : {
      23           21448 :     if (len % 8) {
      24           15997 :         unsigned char zero[8];
      25           15997 :         memset(zero, 0, sizeof(zero));
      26           15997 :         sink(zero, 8 - (len % 8));
      27                 :     }
      28                 : }
      29                 : 
      30                 : 
      31                 : static void writeInt(unsigned int n, DumpSink & sink)
      32           21448 : {
      33           21448 :     unsigned char buf[8];
      34           21448 :     memset(buf, 0, sizeof(buf));
      35           21448 :     buf[0] = n & 0xff;
      36           21448 :     buf[1] = (n >> 8) & 0xff;
      37           21448 :     buf[2] = (n >> 16) & 0xff;
      38           21448 :     buf[3] = (n >> 24) & 0xff;
      39           21448 :     sink(buf, sizeof(buf));
      40                 : }
      41                 : 
      42                 : 
      43                 : static void writeString(const string & s, DumpSink & sink)
      44           18597 : {
      45           18597 :     unsigned int len = s.length();
      46           18597 :     writeInt(len, sink);
      47           18597 :     sink((const unsigned char *) s.c_str(), len);
      48           18597 :     writePadding(len, sink);
      49                 : }
      50                 : 
      51                 : 
      52                 : static void dump(const string & path, DumpSink & sink);
      53                 : 
      54                 : 
      55                 : static void dumpEntries(const Path & path, DumpSink & sink)
      56              80 : {
      57              80 :     Strings names = readDirectory(path);
      58              80 :     vector<string> names2(names.begin(), names.end());
      59              80 :     sort(names2.begin(), names2.end());
      60                 : 
      61             215 :     for (vector<string>::iterator it = names2.begin();
      62                 :          it != names2.end(); it++)
      63                 :     {
      64             135 :         writeString("entry", sink);
      65             135 :         writeString("(", sink);
      66             135 :         writeString("name", sink);
      67             135 :         writeString(*it, sink);
      68             135 :         writeString("node", sink);
      69             135 :         dump(path + "/" + *it, sink);
      70             135 :         writeString(")", sink);
      71                 :     }
      72                 : }
      73                 : 
      74                 : 
      75                 : static void dumpContents(const Path & path, unsigned int size, 
      76                 :     DumpSink & sink)
      77            2851 : {
      78            2851 :     writeString("contents", sink);
      79            2851 :     writeInt(size, sink);
      80                 : 
      81            2851 :     AutoCloseFD fd = open(path.c_str(), O_RDONLY);
      82            2851 :     if (fd == -1) throw SysError(format("opening file `%1%'") % path);
      83                 :     
      84            2851 :     unsigned char buf[65536];
      85            2851 :     unsigned int left = size;
      86                 : 
      87            3201 :     while (left > 0) {
      88             350 :         size_t n = left > sizeof(buf) ? sizeof(buf) : left;
      89             350 :         readFull(fd, buf, n);
      90             350 :         left -= n;
      91             350 :         sink(buf, n);
      92                 :     }
      93                 : 
      94            2851 :     writePadding(size, sink);
      95                 : }
      96                 : 
      97                 : 
      98                 : static void dump(const Path & path, DumpSink & sink)
      99            2981 : {
     100            2981 :     struct stat st;
     101            2981 :     if (lstat(path.c_str(), &st))
     102               1 :         throw SysError(format("getting attributes of path `%1%'") % path);
     103                 : 
     104            2980 :     writeString("(", sink);
     105                 : 
     106            2980 :     if (S_ISREG(st.st_mode)) {
     107            2851 :         writeString("type", sink);
     108            2851 :         writeString("regular", sink);
     109            2851 :         if (st.st_mode & S_IXUSR) {
     110              36 :             writeString("executable", sink);
     111              36 :             writeString("", sink);
     112                 :         }
     113            2851 :         dumpContents(path, st.st_size, sink);
     114                 :     } 
     115                 : 
     116             129 :     else if (S_ISDIR(st.st_mode)) {
     117              80 :         writeString("type", sink);
     118              80 :         writeString("directory", sink);
     119              80 :         dumpEntries(path, sink);
     120                 :     }
     121                 : 
     122              49 :     else if (S_ISLNK(st.st_mode)) {
     123              49 :         writeString("type", sink);
     124              49 :         writeString("symlink", sink);
     125              49 :         writeString("target", sink);
     126              49 :         writeString(readLink(path), sink);
     127                 :     }
     128                 : 
     129               0 :     else throw Error("unknown file type: " + path);
     130                 : 
     131            2980 :     writeString(")", sink);
     132                 : }
     133                 : 
     134                 : 
     135                 : void dumpPath(const Path & path, DumpSink & sink)
     136            2846 : {
     137            2846 :     writeString(archiveVersion1, sink);
     138            2846 :     dump(path, sink);
     139                 : }
     140                 : 
     141                 : 
     142                 : static Error badArchive(string s)
     143               0 : {
     144               0 :     return Error("bad archive: " + s);
     145                 : }
     146                 : 
     147                 : 
     148                 : static void readPadding(unsigned int len, RestoreSource & source)
     149             534 : {
     150             534 :     if (len % 8) {
     151             468 :         unsigned char zero[8];
     152             468 :         unsigned int n = 8 - (len % 8);
     153             468 :         source(zero, n);
     154            2495 :         for (unsigned int i = 0; i < n; i++)
     155            2027 :             if (zero[i]) throw badArchive("non-zero padding");
     156                 :     }
     157                 : }
     158                 : 
     159                 : static unsigned int readInt(RestoreSource & source)
     160             534 : {
     161             534 :     unsigned char buf[8];
     162             534 :     source(buf, sizeof(buf));
     163             534 :     if (buf[4] || buf[5] || buf[6] || buf[7])
     164               0 :         throw Error("implementation cannot deal with > 32-bit integers");
     165             534 :     return
     166                 :         buf[0] |
     167                 :         (buf[1] << 8) |
     168                 :         (buf[2] << 16) |
     169                 :         (buf[3] << 24);
     170                 : }
     171                 : 
     172                 : 
     173                 : static string readString(RestoreSource & source)
     174             478 : {
     175             478 :     unsigned int len = readInt(source);
     176             478 :     char buf[len];
     177             478 :     source((unsigned char *) buf, len);
     178             478 :     readPadding(len, source);
     179             478 :     return string(buf, len);
     180                 : }
     181                 : 
     182                 : 
     183                 : static void skipGeneric(RestoreSource & source)
     184               0 : {
     185               0 :     if (readString(source) == "(") {
     186               0 :         while (readString(source) != ")")
     187               0 :             skipGeneric(source);
     188                 :     }
     189                 : }
     190                 : 
     191                 : 
     192                 : static void restore(const Path & path, RestoreSource & source);
     193                 : 
     194                 : 
     195                 : static void restoreEntry(const Path & path, RestoreSource & source)
     196              12 : {
     197              12 :     string s, name;
     198                 : 
     199              12 :     s = readString(source);
     200              12 :     if (s != "(") throw badArchive("expected open tag");
     201                 : 
     202              36 :     while (1) {
     203              36 :         checkInterrupt();
     204                 : 
     205              36 :         s = readString(source);
     206                 : 
     207              36 :         if (s == ")") {
     208              12 :             break;
     209              24 :         } else if (s == "name") {
     210              12 :             name = readString(source);
     211              12 :         } else if (s == "node") {
     212              12 :             if (s == "") throw badArchive("entry name missing");
     213              12 :             restore(path + "/" + name, source);
     214                 :         } else {
     215               0 :             throw badArchive("unknown field " + s);
     216               0 :             skipGeneric(source);
     217                 :         }
     218                 :     }
     219                 : }
     220                 : 
     221                 : 
     222                 : static void restoreContents(int fd, const Path & path, RestoreSource & source)
     223              56 : {
     224              56 :     unsigned int size = readInt(source);
     225              56 :     unsigned int left = size;
     226             112 :     unsigned char buf[65536];
     227                 : 
     228             112 :     while (left) {
     229              56 :         checkInterrupt();
     230              56 :         unsigned int n = sizeof(buf);
     231              56 :         if (n > left) n = left;
     232              56 :         source(buf, n);
     233              56 :         writeFull(fd, buf, n);
     234              56 :         left -= n;
     235                 :     }
     236                 : 
     237              56 :     readPadding(size, source);
     238                 : }
     239                 : 
     240                 : 
     241                 : static void restore(const Path & path, RestoreSource & source)
     242              68 : {
     243              68 :     string s;
     244                 : 
     245              68 :     s = readString(source);
     246              68 :     if (s != "(") throw badArchive("expected open tag");
     247                 : 
     248              68 :     enum { tpUnknown, tpRegular, tpDirectory, tpSymlink } type = tpUnknown;
     249              68 :     AutoCloseFD fd;
     250                 : 
     251             215 :     while (1) {
     252             215 :         checkInterrupt();
     253                 : 
     254             215 :         s = readString(source);
     255                 : 
     256             215 :         if (s == ")") {
     257              68 :             break;
     258                 :         }
     259                 : 
     260             147 :         else if (s == "type") {
     261              68 :             if (type != tpUnknown)
     262               0 :                 throw badArchive("multiple type fields");
     263              68 :             string t = readString(source);
     264                 : 
     265              68 :             if (t == "regular") {
     266              56 :                 type = tpRegular;
     267              56 :                 fd = open(path.c_str(), O_CREAT | O_EXCL | O_WRONLY, 0666);
     268              56 :                 if (fd == -1)
     269               0 :                     throw SysError("creating file " + path);
     270                 :             }
     271                 : 
     272              12 :             else if (t == "directory") {
     273               6 :                 type = tpDirectory;
     274               6 :                 if (mkdir(path.c_str(), 0777) == -1)
     275               0 :                     throw SysError("creating directory " + path);
     276                 :             }
     277                 : 
     278               6 :             else if (t == "symlink") {
     279               6 :                 type = tpSymlink;
     280                 :             }
     281                 :             
     282               0 :             else throw badArchive("unknown file type " + t);
     283                 :             
     284                 :         }
     285                 : 
     286              79 :         else if (s == "contents" && type == tpRegular) {
     287              56 :             restoreContents(fd, path, source);
     288                 :         }
     289                 : 
     290              23 :         else if (s == "executable" && type == tpRegular) {
     291               5 :             readString(source);
     292               5 :             struct stat st;
     293               5 :             if (fstat(fd, &st) == -1)
     294               0 :                 throw SysError("fstat");
     295               5 :             if (fchmod(fd, st.st_mode | (S_IXUSR | S_IXGRP | S_IXOTH)) == -1)
     296               0 :                 throw SysError("fchmod");
     297                 :         }
     298                 : 
     299              18 :         else if (s == "entry" && type == tpDirectory) {
     300              12 :             restoreEntry(path, source);
     301                 :         }
     302                 : 
     303               6 :         else if (s == "target" && type == tpSymlink) {
     304               6 :             string target = readString(source);
     305               6 :             if (symlink(target.c_str(), path.c_str()) == -1)
     306               0 :                 throw SysError("creating symlink " + path);
     307                 :         }
     308                 : 
     309                 :         else {
     310               0 :             throw badArchive("unknown field " + s);
     311               0 :             skipGeneric(source);
     312                 :         }
     313                 :         
     314                 :     }
     315                 : }
     316                 : 
     317                 : 
     318                 : void restorePath(const Path & path, RestoreSource & source)
     319              56 : {
     320              56 :     if (readString(source) != archiveVersion1)
     321               0 :         throw badArchive("expected Nix archive");
     322              56 :     restore(path, source);
     323                 : }
     324                 : 
     325                 :  
     326             345 : }

Generated by: LTP GCOV extension version 1.1