1 import cPickle, errno, os, tempfile
3 class Error(Exception):
7 def __init__(self, filename):
8 # Map a "dev:ino" node to a list of paths associated with that node.
10 # Map a path to a "dev:ino" node.
12 self._filename = filename
13 self._save_prepared = None
17 f = open(filename, 'r')
19 if e.errno == errno.ENOENT:
25 self._node_paths = cPickle.load(f)
29 # Set up the reverse hard link index.
30 for node, paths in self._node_paths.iteritems():
32 self._path_node[path] = node
34 def prepare_save(self):
35 """ Commit all of the relevant data to disk. Do as much work
36 as possible without actually making the changes visible."""
37 if self._save_prepared:
38 raise Error('save of %r already in progress' % self._filename)
40 (dir, name) = os.path.split(self._filename)
41 (ffd, self._tmpname) = tempfile.mkstemp('.tmp', name, dir)
43 f = os.fdopen(ffd, 'wb', 65536)
48 cPickle.dump(self._node_paths, f, 2)
51 os.unlink(self._tmpname)
57 self._save_prepared = True
59 def commit_save(self):
60 if not self._save_prepared:
61 raise Error('cannot commit save of %r; no save prepared'
64 os.rename(self._tmpname, self._filename)
66 else: # No data -- delete _filename if it exists.
68 os.unlink(self._filename)
70 if e.errno == errno.ENOENT:
74 self._save_prepared = None
78 os.unlink(self._tmpname)
84 def add_path(self, path, dev, ino):
86 node = '%s:%s' % (dev, ino)
87 self._path_node[path] = node
88 link_paths = self._node_paths.get(node)
89 if link_paths and path not in link_paths:
90 link_paths.append(path)
92 self._node_paths[node] = [path]
94 def _del_node_path(self, node, path):
95 link_paths = self._node_paths[node]
96 link_paths.remove(path)
98 del self._node_paths[node]
100 def change_path(self, path, new_dev, new_ino):
101 prev_node = self._path_node.get(path)
103 self._del_node_path(prev_node, path)
104 self.add_path(new_dev, new_ino, path)
106 def del_path(self, path):
107 # Path may not be in db (if updating a pre-hardlink support index).
108 node = self._path_node.get(path)
110 self._del_node_path(node, path)
111 del self._path_node[path]
113 def node_paths(self, dev, ino):
114 node = '%s:%s' % (dev, ino)
115 return self._node_paths[node]