1use backend;
6use backend::*;
7use {ErrorKind, Result};
8
9use rand;
10use std;
11use std::collections::BTreeMap;
12use std::iter::Iterator;
13use std::path::{Path, PathBuf};
14
15impl<'env, R: rand::Rng> MutTxn<'env, R> {
16 pub fn mark_inode_moved(&mut self, inode: Inode) {
17 let mut header = None;
18 if let Some(h) = self.get_inodes(inode) {
19 header = Some(h.clone())
20 }
21 if let Some(mut h) = header {
22 h.status = FileStatus::Moved;
23 self.replace_inodes(inode, h).unwrap();
24 }
25 }
26
27 pub fn create_new_inode(&self) -> Inode {
30 let mut already_taken = true;
31 let mut inode: Inode = ROOT_INODE.clone();
32 while already_taken {
33 for i in inode.iter_mut() {
34 *i = rand::random()
35 }
36 already_taken = self.get_revtree(inode).is_some();
37 }
38 inode
39 }
40
41 fn make_new_child(
44 &mut self,
45 parent_inode: Inode,
46 filename: &str,
47 is_dir: bool,
48 child_inode: Option<Inode>,
49 ) -> Result<Inode> {
50 let parent_id = OwnedFileId {
51 parent_inode: parent_inode.clone(),
52 basename: SmallString::from_str(filename),
53 };
54 if let Some(inode) = self.get_tree(&parent_id.as_file_id()) {
55 let mut header = if let Some(header) = self.get_inodes(inode) {
58 header.to_owned()
59 } else {
60 return Err(ErrorKind::AlreadyAdded.into());
61 };
62 if let FileStatus::Ok = header.status {
63 } else {
64 header.status = FileStatus::Ok;
65 self.replace_inodes(inode, header)?;
66 }
67 Ok(inode)
68 } else {
69 let child_inode = match child_inode {
72 None => self.create_new_inode(),
73 Some(i) => i.clone(),
74 };
75 self.put_tree(&parent_id.as_file_id(), child_inode)?;
76 self.put_revtree(child_inode, &parent_id.as_file_id())?;
77
78 if is_dir {
79 let dir_id = OwnedFileId {
82 parent_inode: child_inode.clone(),
83 basename: SmallString::from_str(""),
84 };
85 self.put_tree(&dir_id.as_file_id(), child_inode)?;
86 };
87 Ok(child_inode)
88 }
89 }
90
91 pub fn add_inode(
92 &mut self,
93 inode: Option<Inode>,
94 path: &std::path::Path,
95 is_dir: bool,
96 ) -> Result<()> {
97 if let Some(parent) = path.parent() {
98 let (mut current_inode, unrecorded_path) =
99 self.closest_in_repo_ancestor(&parent).unwrap();
100
101 for c in unrecorded_path {
102 current_inode =
103 self.make_new_child(current_inode, c.as_os_str().to_str().unwrap(), true, None)?
104 }
105
106 self.make_new_child(
107 current_inode,
108 path.file_name().unwrap().to_str().unwrap(),
109 is_dir,
110 inode,
111 )?;
112 }
113 Ok(())
114 }
115
116 pub fn inode_is_ancestor_of(&self, a: Inode, mut b: Inode) -> bool {
117 loop {
118 if a == b {
119 return true;
120 }
121 if let Some(b_parent) = self.get_revtree(b) {
122 b = b_parent.parent_inode
123 } else {
124 return false;
125 }
126 }
127 }
128
129 pub fn move_file(
130 &mut self,
131 path: &std::path::Path,
132 path_: &std::path::Path,
133 is_dir: bool,
134 ) -> Result<()> {
135 debug!("move_file: {:?},{:?}", path, path_);
136 if let Some(parent) = path.parent() {
137 let fileref = OwnedFileId {
138 parent_inode: self.find_inode(parent)?,
139 basename: SmallString::from_str(path.file_name().unwrap().to_str().unwrap()),
140 };
141
142 if let Some(inode) = self.get_tree(&fileref.as_file_id()).map(|i| i.clone()) {
143 debug!("txn.del fileref={:?}", fileref);
145 self.del_tree(&fileref.as_file_id(), None)?;
146 self.del_revtree(inode, None)?;
147
148 debug!("inode={} path_={:?}", inode.to_hex(), path_);
149 self.add_inode(Some(inode), path_, is_dir)?;
150 self.mark_inode_moved(inode);
151
152 return Ok(());
153 }
154 }
155 Err(ErrorKind::FileNotInRepo(path.to_path_buf()).into())
156 }
157
158 pub fn rec_delete(&mut self, key: Inode) -> Result<bool> {
160 debug!("rec_delete, key={:?}", key.to_hex());
161 let file_id = OwnedFileId {
162 parent_inode: key.clone(),
163 basename: SmallString::from_str(""),
164 };
165
166 let children: Vec<(_, Inode)> = self.iter_tree(Some((&file_id.as_file_id(), None)))
167 .take_while(|&(ref k, _)| key == k.parent_inode)
168 .filter(|&(ref k, _)| !k.basename.is_empty())
169 .map(|(k, v)| (k.to_owned(), v.to_owned()))
170 .collect();
171
172 let mut has_recorded_descendants = false;
173 for (_, b) in children {
174 debug!("deleting from tree {:?}", b);
175 has_recorded_descendants |= self.rec_delete(b)?;
176 }
177
178 if let Some(mut header) = self.get_inodes(key).map(|h| h.clone()) {
180 debug!("key {:?}, header = {:?}", key, header);
182 header.status = FileStatus::Deleted;
183 self.replace_inodes(key, header)?;
184 debug!("after = {:?}", self.get_inodes(key).map(|h| h.clone()));
185 } else if !has_recorded_descendants {
186 let parent = self.get_revtree(key).unwrap().to_owned();
188 debug!("key = {:?}, parent = {:?}", key, parent);
189 self.del_tree(&parent.as_file_id(), None)?;
190 self.del_revtree(key, None)?;
191 }
192 Ok(has_recorded_descendants)
193 }
194
195 pub fn remove_file(&mut self, path: &std::path::Path) -> Result<()> {
197 debug!("remove_file");
198 let inode = self.find_inode(path)?;
199 debug!("rec_delete");
200 self.rec_delete(inode)?;
201 debug!("/rec_delete");
202 Ok(())
203 }
204}
205
206impl<A: Transaction, R> backend::GenericTxn<A, R> {
207 fn collect(
209 &self,
210 key: Inode,
211 pb: &Path,
212 basename: &str,
213 files: &mut Vec<PathBuf>,
214 ) -> Result<()> {
215 debug!("collecting {:?},{:?}", key, basename);
216 let add = match self.get_inodes(key) {
217 Some(inode) => {
218 debug!("node = {:?}", inode);
219 inode.status != FileStatus::Deleted
220 }
221 None => true,
222 };
223 if add {
224 debug!("basename = {:?}", basename);
225 let next_pb = pb.join(basename);
226 let next_pb_ = next_pb.clone();
227 if basename.len() > 0 {
228 files.push(next_pb)
229 }
230
231 debug!("starting iterator, key={:?}", key);
232 let fileid = OwnedFileId {
233 parent_inode: key.clone(),
234 basename: SmallString::from_str(""),
235 };
236 for (k, v) in self.iter_tree(Some((&fileid.as_file_id(), None)))
237 .take_while(|&(ref k, _)| k.parent_inode == key)
238 {
239 debug!("iter: {:?} {:?}", k, v);
240 if k.basename.len() > 0 {
241 self.collect(v.to_owned(), next_pb_.as_path(), k.basename.as_str(), files)?;
242 }
243 }
244 debug!("ending iterator {:?}", {
245 let v: Vec<_> = self.iter_tree(Some((&fileid.as_file_id(), None))).collect();
246 v
247 });
248 }
249 Ok(())
250 }
251
252 pub fn list_files(&self, inode: Inode) -> Result<Vec<PathBuf>> {
254 debug!("list_files {:?}", inode);
255 let mut files = Vec::new();
256 let mut pathbuf = PathBuf::new();
257 self.collect(inode, &mut pathbuf, "", &mut files)?;
258 Ok(files)
259 }
260
261 pub fn list_files_under_inode(
263 &self,
264 inode: Inode,
265 ) -> Vec<(SmallString, Option<Key<PatchId>>, Inode)> {
266 let mut result = Vec::new();
267
268 let file_id = OwnedFileId {
269 parent_inode: inode,
270 basename: SmallString::from_str(""),
271 };
272 for (k, v) in self.iter_tree(Some((&file_id.as_file_id(), None)))
273 .take_while(|&(ref k, _)| k.parent_inode == inode)
274 {
275 let header = self.get_inodes(k.parent_inode).map(|x| x.clone());
276 println!("============= {:?} {:?}", k, v);
278 let add = match header {
279 Some(ref h) => h.status == FileStatus::Ok,
280 None => true,
281 };
282 if add && k.basename.len() > 0 {
283 result.push((
284 k.basename.to_owned(),
285 header.map(|h| h.key.clone()),
286 v.clone(),
287 ))
288 }
289 }
290
291 result
292 }
293
294 pub fn list_files_under_node(
296 &self,
297 branch: &Branch,
298 key: Key<PatchId>,
299 ) -> BTreeMap<Key<PatchId>, Vec<(FileMetadata, &str)>> {
300 let mut result = BTreeMap::new();
301
302 let e = Edge::zero(EdgeFlags::FOLDER_EDGE);
303 for (_, child) in self.iter_nodes(branch, Some((key, Some(&e)))).take_while(
304 |&(k, ref v)| k == key && v.flag <= EdgeFlags::FOLDER_EDGE | EdgeFlags::PSEUDO_EDGE,
305 ) {
306 let name = self.get_contents(child.dest).unwrap();
307 let (perms, basename) = name.as_slice().split_at(2);
309 let perms = FileMetadata::from_contents(perms);
310 let basename = std::str::from_utf8(basename).unwrap();
311
312 for (_, grandchild) in self.iter_nodes(branch, Some((child.dest, Some(&e))))
313 .take_while(|&(k, ref v)| {
314 k == child.dest && v.flag <= EdgeFlags::FOLDER_EDGE | EdgeFlags::PSEUDO_EDGE
315 }) {
316 let names = result.entry(grandchild.dest.to_owned()).or_insert(vec![]);
317 names.push((perms, basename))
318 }
319 }
320 result
321 }
322
323 pub fn is_directory(&self, inode: &Inode) -> bool {
324 let file_id = OwnedFileId {
325 parent_inode: inode.clone(),
326 basename: SmallString::from_str(""),
327 };
328 inode == &ROOT_INODE || self.get_tree(&file_id.as_file_id()).is_some()
329 }
330
331 fn closest_in_repo_ancestor<'a>(
335 &self,
336 path: &'a std::path::Path,
337 ) -> Result<(Inode, std::iter::Peekable<std::path::Components<'a>>)> {
338 let mut components = path.components().peekable();
339 let mut fileid = OwnedFileId {
340 parent_inode: ROOT_INODE,
341 basename: SmallString::from_str(""),
342 };
343
344 loop {
345 if let Some(c) = components.peek() {
346 fileid.basename = SmallString::from_str(c.as_os_str().to_str().unwrap());
347 if let Some(v) = self.get_tree(&fileid.as_file_id()) {
348 fileid.parent_inode = v.clone()
349 } else {
350 break;
351 }
352 } else {
353 break;
354 }
355 components.next();
356 }
357 Ok((fileid.parent_inode.clone(), components))
358 }
359
360 pub fn find_inode(&self, path: &std::path::Path) -> Result<Inode> {
362 let (inode, mut remaining_path_components) = self.closest_in_repo_ancestor(path)?;
363 if remaining_path_components.next().is_none() {
364 Ok(inode)
365 } else {
366 Err(ErrorKind::FileNotInRepo(path.to_path_buf()).into())
367 }
368 }
369
370 pub fn file_names(
371 &self,
372 branch: &Branch,
373 key: Key<PatchId>,
374 ) -> Vec<(Key<PatchId>, FileMetadata, &str)> {
375 let mut result = Vec::new();
376 let e = Edge::zero(EdgeFlags::FOLDER_EDGE | EdgeFlags::PARENT_EDGE);
377
378 debug!("file_names, key {:?}", key);
379 for (_, parent) in self.iter_nodes(branch, Some((key, Some(&e))))
380 .take_while(|&(k, _)| k == key)
381 .filter(|&(_, ref v)| {
382 v.flag
383 .contains(EdgeFlags::FOLDER_EDGE | EdgeFlags::PARENT_EDGE)
384 }) {
385 debug!("file_names, parent {:?}", parent);
386 match self.get_contents(parent.dest) {
387 Some(ref name) if name.len() >= 2 => {
388 let (perms, basename) = name.as_slice().split_at(2);
390 let perms = FileMetadata::from_contents(perms);
391 let basename = std::str::from_utf8(basename).unwrap();
392
393 for (_, grandparent) in self.iter_nodes(branch, Some((parent.dest, Some(&e))))
394 .take_while(|&(k, _)| k == parent.dest)
395 .filter(|&(_, ref v)| {
396 v.flag
397 .contains(EdgeFlags::FOLDER_EDGE | EdgeFlags::PARENT_EDGE)
398 }) {
399 result.push((grandparent.dest.to_owned(), perms, basename));
400 break;
401 }
402 }
403 _ => error!("Key: {:?}, file {}, line {}", key, file!(), line!()),
404 }
405 }
406 result
407 }
408
409 pub fn prefix_keys(&self, branch: &Branch, path: &str) -> Result<Vec<Key<PatchId>>> {
410 let mut result = Vec::new();
411 let e = Edge::zero(EdgeFlags::FOLDER_EDGE);
412
413 let mut current_key = ROOT_KEY;
414
415 for comp in path.split(std::path::MAIN_SEPARATOR) {
416 let mut is_first = true;
417 let cur = current_key;
418 for (_, child) in self.iter_nodes(branch, Some((current_key, Some(&e))))
419 .take_while(|&(k, _)| k == cur)
420 .filter(|&(_, ref v)| v.flag.contains(EdgeFlags::FOLDER_EDGE))
421 {
422 let contents = self.get_contents(child.dest).unwrap();
423 if contents.into_cow().split_at(2).1 == comp.as_bytes() {
424 if !is_first {
425 return Err(ErrorKind::FileNameCount(current_key).into());
426 }
427
428 for (_, grandchild) in self.iter_nodes(branch, Some((child.dest, Some(&e))))
429 .take_while(|&(k, _)| k == child.dest)
430 .filter(|&(_, ref v)| v.flag.contains(EdgeFlags::FOLDER_EDGE))
431 {
432 result.push(grandchild.dest);
433 current_key = grandchild.dest;
434 }
435 }
436 }
437 }
438 Ok(result)
439 }
440}