LTP GCOV extension - code coverage report
Current view: directory - src/nix-env - profiles.cc
Test: app.info
Date: 2006-10-11 Instrumented lines: 55
Code covered: 90.9 % Executed lines: 50

       1                 : #include "profiles.hh"
       2                 : #include "util.hh"
       3                 : #include "gc.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                 : static bool cmpGensByNumber(const Generation & a, const Generation & b)
      16              63 : {
      17              63 :     return a.number < b.number;
      18                 : }
      19                 : 
      20                 : 
      21                 : /* Parse a generation name of the format
      22                 :    `<profilename>-<number>-link'. */
      23                 : static int parseName(const string & profileName, const string & name)
      24             106 : {
      25             106 :     if (string(name, 0, profileName.size() + 1) != profileName + "-") return -1;
      26              70 :     string s = string(name, profileName.size() + 1);
      27              70 :     string::size_type p = s.find("-link");
      28              70 :     if (p == string::npos) return -1;
      29              70 :     int n;
      30              70 :     if (string2Int(string(s, 0, p), n) && n >= 0)
      31              70 :         return n;
      32                 :     else
      33               0 :         return -1;
      34                 : }
      35                 : 
      36                 : 
      37                 : 
      38                 : Generations findGenerations(Path profile, int & curGen)
      39              20 : {
      40              20 :     Generations gens;
      41                 : 
      42              20 :     Path profileDir = dirOf(profile);
      43              20 :     string profileName = baseNameOf(profile);
      44                 :     
      45              20 :     Strings names = readDirectory(profileDir);
      46             110 :     for (Strings::iterator i = names.begin(); i != names.end(); ++i) {
      47              90 :         int n;
      48              90 :         if ((n = parseName(profileName, *i)) != -1) {
      49              54 :             Generation gen;
      50              54 :             gen.path = profileDir + "/" + *i;
      51              54 :             gen.number = n;
      52              54 :             struct stat st;
      53              54 :             if (lstat(gen.path.c_str(), &st) != 0)
      54               0 :                 throw SysError(format("statting `%1%'") % gen.path);
      55              54 :             gen.creationTime = st.st_mtime;
      56              54 :             gens.push_back(gen);
      57                 :         }
      58                 :     }
      59                 : 
      60              20 :     gens.sort(cmpGensByNumber);
      61                 : 
      62              20 :     curGen = pathExists(profile)
      63                 :         ? parseName(profileName, readLink(profile))
      64                 :         : -1;
      65                 : 
      66              20 :     return gens;
      67                 : }
      68                 : 
      69                 : 
      70                 : static void makeName(const Path & profile, unsigned int num,
      71                 :     Path & outLink)
      72              21 : {
      73              21 :     Path prefix = (format("%1%-%2%") % profile % num).str();
      74              21 :     outLink = prefix + "-link";
      75                 : }
      76                 : 
      77                 : 
      78                 : Path createGeneration(Path profile, Path outPath)
      79              15 : {
      80                 :     /* The new generation number should be higher than old the
      81                 :        previous ones. */
      82              15 :     int dummy;
      83              15 :     Generations gens = findGenerations(profile, dummy);
      84              15 :     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                 :        build 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              15 :     Path generation;
      93              15 :     makeName(profile, num + 1, generation);
      94              15 :     addPermRoot(outPath, generation, false, true);
      95                 : 
      96              15 :     return generation;
      97                 : }
      98                 : 
      99                 : 
     100                 : static void removeFile(const Path & path)
     101               6 : {
     102               6 :     if (remove(path.c_str()) == -1)
     103               0 :         throw SysError(format("cannot unlink `%1%'") % path);
     104                 : }
     105                 : 
     106                 : 
     107                 : void deleteGeneration(const Path & profile, unsigned int gen)
     108               6 : {
     109               6 :     Path generation;
     110               6 :     makeName(profile, gen, generation);
     111               6 :     removeFile(generation);
     112                 : }
     113                 : 
     114                 : 
     115                 : void switchLink(Path link, Path target)
     116              17 : {
     117                 :     /* Hacky. */
     118              17 :     if (dirOf(target) == dirOf(link)) target = baseNameOf(target);
     119                 :     
     120              17 :     Path tmp = canonPath(dirOf(link) + "/.new_" + baseNameOf(link));
     121              17 :     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              17 :     if (rename(tmp.c_str(), link.c_str()) != 0)
     130               0 :         throw SysError(format("renaming `%1%' to `%2%'") % tmp % link);
     131                 : }
     132                 : 
     133                 :  
     134                 : }
     135                 : 

Generated by: LTP GCOV extension version 1.1