LTP GCOV extension - code coverage report
Current view: directory - src/nix-env - profiles.cc
Test: app.info
Date: 2008-11-20 Instrumented lines: 56
Code covered: 89.3 % Executed lines: 50

       1                 : #include "profiles.hh"
       2                 : #include "store-api.hh"
       3                 : #include "util.hh"
       4                 : 
       5                 : #include <sys/types.h>
       6                 : #include <sys/stat.h>
       7                 : #include <unistd.h>
       8                 : #include <errno.h>
       9                 : #include <stdio.h>
      10                 : 
      11                 : 
      12                 : namespace nix {
      13                 : 
      14                 : 
      15             280 : static bool cmpGensByNumber(const Generation & a, const Generation & b)
      16                 : {
      17             280 :     return a.number < b.number;
      18                 : }
      19                 : 
      20                 : 
      21                 : /* Parse a generation name of the format
      22                 :    `<profilename>-<number>-link'. */
      23             381 : static int parseName(const string & profileName, const string & name)
      24                 : {
      25             381 :     if (string(name, 0, profileName.size() + 1) != profileName + "-") return -1;
      26             269 :     string s = string(name, profileName.size() + 1);
      27             269 :     string::size_type p = s.find("-link");
      28             538 :     if (p == string::npos) return -1;
      29                 :     int n;
      30             269 :     if (string2Int(string(s, 0, p), n) && n >= 0)
      31             269 :         return n;
      32                 :     else
      33               0 :         return -1;
      34                 : }
      35                 : 
      36                 : 
      37                 : 
      38              59 : Generations findGenerations(Path profile, int & curGen)
      39                 : {
      40              59 :     Generations gens;
      41                 : 
      42              59 :     Path profileDir = dirOf(profile);
      43              59 :     string profileName = baseNameOf(profile);
      44                 :     
      45              59 :     Strings names = readDirectory(profileDir);
      46             387 :     for (Strings::iterator i = names.begin(); i != names.end(); ++i) {
      47                 :         int n;
      48             328 :         if ((n = parseName(profileName, *i)) != -1) {
      49             216 :             Generation gen;
      50             216 :             gen.path = profileDir + "/" + *i;
      51             216 :             gen.number = n;
      52                 :             struct stat st;
      53             216 :             if (lstat(gen.path.c_str(), &st) != 0)
      54               0 :                 throw SysError(format("statting `%1%'") % gen.path);
      55             216 :             gen.creationTime = st.st_mtime;
      56             216 :             gens.push_back(gen);
      57                 :         }
      58                 :     }
      59                 : 
      60              59 :     gens.sort(cmpGensByNumber);
      61                 : 
      62                 :     curGen = pathExists(profile)
      63                 :         ? parseName(profileName, readLink(profile))
      64              59 :         : -1;
      65                 : 
      66              59 :     return gens;
      67                 : }
      68                 : 
      69                 : 
      70                 : static void makeName(const Path & profile, unsigned int num,
      71              65 :     Path & outLink)
      72                 : {
      73              65 :     Path prefix = (format("%1%-%2%") % profile % num).str();
      74             130 :     outLink = prefix + "-link";
      75              65 : }
      76                 : 
      77                 : 
      78              43 : Path createGeneration(Path profile, Path outPath)
      79                 : {
      80                 :     /* The new generation number should be higher than old the
      81                 :        previous ones. */
      82                 :     int dummy;
      83              43 :     Generations gens = findGenerations(profile, dummy);
      84              86 :     unsigned int num = gens.size() > 0 ? gens.back().number : 0;
      85                 : 
      86                 :     /* Create the new generation.  Note that addPermRoot() blocks if
      87                 :        the garbage collector is running to prevent the stuff we've
      88                 :        built from moving from the temporary roots (which the GC knows)
      89                 :        to the permanent roots (of which the GC would have a stale
      90                 :        view).  If we didn't do it this way, the GC might remove the
      91                 :        user environment etc. we've just built. */
      92              43 :     Path generation;
      93              43 :     makeName(profile, num + 1, generation);
      94              43 :     addPermRoot(outPath, generation, false, true);
      95                 : 
      96              43 :     return generation;
      97                 : }
      98                 : 
      99                 : 
     100              22 : static void removeFile(const Path & path)
     101                 : {
     102              22 :     if (remove(path.c_str()) == -1)
     103               0 :         throw SysError(format("cannot unlink `%1%'") % path);
     104              22 : }
     105                 : 
     106                 : 
     107              22 : void deleteGeneration(const Path & profile, unsigned int gen)
     108                 : {
     109              22 :     Path generation;
     110              22 :     makeName(profile, gen, generation);
     111              22 :     removeFile(generation);
     112              22 : }
     113                 : 
     114                 : 
     115              49 : void switchLink(Path link, Path target)
     116                 : {
     117                 :     /* Hacky. */
     118              49 :     if (dirOf(target) == dirOf(link)) target = baseNameOf(target);
     119                 :     
     120              49 :     Path tmp = canonPath(dirOf(link) + "/.new_" + baseNameOf(link));
     121              98 :     if (symlink(target.c_str(), tmp.c_str()) != 0)
     122               0 :         throw SysError(format("creating symlink `%1%'") % tmp);
     123                 :     /* The rename() system call is supposed to be essentially atomic
     124                 :        on Unix.  That is, if we have links `current -> X' and
     125                 :        `new_current -> Y', and we rename new_current to current, a
     126                 :        process accessing current will see X or Y, but never a
     127                 :        file-not-found or other error condition.  This is sufficient to
     128                 :        atomically switch user environments. */
     129              49 :     if (rename(tmp.c_str(), link.c_str()) != 0)
     130               0 :         throw SysError(format("renaming `%1%' to `%2%'") % tmp % link);
     131              49 : }
     132                 : 
     133               0 :  
     134                 : }
     135                 : 

Generated by: LTP GCOV extension version 1.6