LTP GCOV extension - code coverage report
Current view: directory - src/libutil - archive.cc
Test: app.info
Date: 2004-12-21 Instrumented lines: 178
Code covered: 27.5 % Executed lines: 49

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

Generated by: LTP GCOV extension version 1.1