1 : #include <cerrno>
2 : #include <map>
3 :
4 : #include <sys/types.h>
5 : #include <sys/stat.h>
6 : #include <unistd.h>
7 : #include <dirent.h>
8 : #include <fcntl.h>
9 :
10 : #include "references.hh"
11 : #include "hash.hh"
12 :
13 :
14 : static void search(const string & s,
15 : Strings & ids, Strings & seen)
16 34 : {
17 36 : for (Strings::iterator i = ids.begin();
18 : i != ids.end(); )
19 : {
20 96 : checkInterrupt();
21 96 : if (s.find(*i) == string::npos)
22 94 : i++;
23 : else {
24 2 : debug(format("found reference to `%1%'") % *i);
25 2 : seen.push_back(*i);
26 2 : i = ids.erase(i);
27 : }
28 : }
29 : }
30 :
31 :
32 : void checkPath(const string & path,
33 : Strings & ids, Strings & seen)
34 32 : {
35 32 : checkInterrupt();
36 :
37 32 : struct stat st;
38 32 : if (lstat(path.c_str(), &st))
39 0 : throw SysError(format("getting attributes of path `%1%'") % path);
40 :
41 32 : if (S_ISDIR(st.st_mode)) {
42 10 : Strings names = readDirectory(path);
43 22 : for (Strings::iterator i = names.begin(); i != names.end(); i++) {
44 12 : search(*i, ids, seen);
45 12 : checkPath(path + "/" + *i, ids, seen);
46 : }
47 : }
48 :
49 22 : else if (S_ISREG(st.st_mode)) {
50 :
51 20 : debug(format("checking `%1%'") % path);
52 :
53 20 : AutoCloseFD fd = open(path.c_str(), O_RDONLY);
54 20 : if (fd == -1) throw SysError(format("opening file `%1%'") % path);
55 :
56 20 : unsigned char * buf = new unsigned char[st.st_size];
57 :
58 20 : readFull(fd, buf, st.st_size);
59 :
60 20 : search(string((char *) buf, st.st_size), ids, seen);
61 :
62 20 : delete buf; /* !!! autodelete */
63 : }
64 :
65 2 : else if (S_ISLNK(st.st_mode))
66 2 : search(readLink(path), ids, seen);
67 :
68 0 : else throw Error(format("unknown file type: %1%") % path);
69 : }
70 :
71 :
72 : Strings filterReferences(const string & path, const Strings & paths)
73 20 : {
74 20 : map<string, string> backMap;
75 20 : Strings ids;
76 20 : Strings seen;
77 :
78 : /* For efficiency (and a higher hit rate), just search for the
79 : hash part of the file name. (This assumes that all references
80 : have the form `HASH-bla'). */
81 76 : for (Strings::const_iterator i = paths.begin();
82 : i != paths.end(); i++)
83 : {
84 56 : string s = string(baseNameOf(*i), 0, 32);
85 56 : parseHash(s);
86 56 : ids.push_back(s);
87 56 : backMap[s] = *i;
88 : }
89 :
90 20 : checkPath(path, ids, seen);
91 :
92 20 : Strings found;
93 22 : for (Strings::iterator i = seen.begin(); i != seen.end(); i++)
94 : {
95 2 : map<string, string>::iterator j;
96 2 : if ((j = backMap.find(*i)) == backMap.end()) abort();
97 2 : found.push_back(j->second);
98 : }
99 :
100 20 : return found;
101 : }
|