Bye-bye googledriver.
[beagle.git] / bludgeon / DirectoryObject.cs
blobeaaeb4a5573305b990ee6ef223ae1e3c1beb4d73
2 using System;
3 using System.Collections;
4 using System.IO;
6 using Mono.Unix.Native;
8 using Beagle.Util;
9 using Beagle;
11 namespace Bludgeon {
13 public class DirectoryObject : FileSystemObject {
15 private bool is_root = false;
16 private string root_path = null;
18 int n_files_below = 0;
19 int n_dirs_below = 0;
21 public DirectoryObject ()
23 timestamp = FileSystemObject.PickTimestamp ();
24 AllowChildren ();
27 public DirectoryObject (string root_path)
29 ClearName ();
31 this.is_root = true;
32 this.root_path = Path.GetFullPath (root_path);
34 AllowChildren ();
35 AddOnDisk (null);
38 override public bool IsRoot {
39 get { return is_root; }
42 override public string Name {
43 get {
44 if (is_root)
45 return root_path;
46 return base.Name;
50 override protected string GetChildUri (FileSystemObject child)
52 return Path.Combine (this.Uri, child.Name);
55 override public string Uri {
56 get {
57 if (is_root)
58 return "file://" + root_path;
59 return base.Uri;
63 override public string Extension {
64 get { return is_root ? null : ".dir"; }
67 override public string MimeType {
68 get { return "inode/directory"; }
71 ///////////////////////////////////////////////////////////////////////
73 static private void GetCountDeltas (FileSystemObject fso, out int d_files, out int d_dirs)
75 if (fso is DirectoryObject) {
76 DirectoryObject dir = (DirectoryObject) fso;
77 d_files = dir.n_files_below;
78 d_dirs = dir.n_dirs_below + 1; // add one for ourself
79 } else if (fso is FileObject) {
80 d_files = 1; // just ourself
81 d_dirs = 0;
82 } else {
83 throw new Exception ("Unknown type " + fso);
87 public override void AddChild (FileSystemObject child, EventTracker tracker)
89 // Every time we add a child, we walk up the tree
90 // and adjust the n_*_below counts for every node
91 // above us.
93 int d_files, d_dirs;
94 GetCountDeltas (child, out d_files, out d_dirs);
96 DirectoryObject curr;
97 curr = this;
98 while (curr != null) {
99 curr.n_files_below += d_files;
100 curr.n_dirs_below += d_dirs;
101 curr = (DirectoryObject) curr.Parent;
104 base.AddChild (child, tracker);
107 public override void RemoveChild (FileSystemObject child, EventTracker tracker)
109 // Likewise, we have to walk up the tree and adjust
110 // the n_*_below counts when we remove a child.
112 int d_files, d_dirs;
113 GetCountDeltas (child, out d_files, out d_dirs);
115 DirectoryObject curr;
116 curr = this;
117 while (curr != null) {
118 curr.n_files_below -= d_files;
119 curr.n_dirs_below -= d_dirs;
120 curr = (DirectoryObject) curr.Parent;
123 base.RemoveChild (child, tracker);
126 public override void MoveChild (FileSystemObject child, FileSystemObject new_parent, EventTracker tracker)
128 int d_files, d_dirs;
129 GetCountDeltas (child, out d_files, out d_dirs);
131 DirectoryObject curr;
132 curr = this;
133 while (curr != null) {
134 curr.n_files_below -= d_files;
135 curr.n_dirs_below -= d_dirs;
136 curr = (DirectoryObject) curr.Parent;
138 curr = (DirectoryObject) new_parent;
139 while (curr != null) {
140 curr.n_files_below += d_files;
141 curr.n_dirs_below += d_dirs;
142 curr = (DirectoryObject) curr.Parent;
145 base.MoveChild (child, new_parent, tracker);
148 ///////////////////////////////////////////////////////////////////////
150 override public void AddOnDisk (EventTracker tracker)
152 string full_name;
153 full_name = FullName;
154 if (full_name == null)
155 throw new Exception ("Attempt to instantiate something other than a real file: " + Uri);
157 if (is_root) {
158 // Root directories must already exist.
159 if (! Directory.Exists (full_name))
160 throw new Exception ("Missing root directory " + full_name);
161 } else {
162 Directory.CreateDirectory (full_name);
163 timestamp = Directory.GetLastWriteTimeUtc (full_name);
166 if (tracker != null)
167 tracker.ExpectingAdded (this.Uri);
169 // Recursively add the children
170 foreach (FileSystemObject fso in children.Values)
171 fso.AddOnDisk (tracker);
174 override public void DeleteOnDisk (EventTracker tracker)
176 // Recursively delete the children
177 foreach (FileSystemObject fso in children.Values)
178 fso.DeleteOnDisk (tracker);
180 // Then delete ourselves
181 Syscall.rmdir (FullName);
184 override public void MoveOnDisk (string old_full_name, EventTracker tracker)
186 Syscall.rename (old_full_name, FullName);
189 override public bool VerifyOnDisk ()
191 // Make sure the directory exists.
192 if (! Directory.Exists (FullName)) {
193 Log.Failure ("Missing directory '{0}'", FullName);
194 return false;
197 // Make sure all of the children exist.
198 Hashtable name_hash = new Hashtable ();
199 foreach (FileSystemObject fso in children.Values) {
200 name_hash [fso.FullName] = fso;
201 if (! fso.VerifyOnDisk ())
202 return false;
205 // Make sure there is nothing in the directory that shouldn't be there.
206 foreach (string name in Directory.GetFileSystemEntries (FullName)) {
207 name_hash.Remove (name);
209 if (name_hash.Count > 0) {
210 Log.Failure ("Extra items in directory '{0}'", FullName);
211 foreach (string name in name_hash.Keys)
212 Log.Failure (" extra item: '{0}'", name);
213 return false;
216 return true;
219 ///////////////////////////////////////////////////////////////////////
221 // All of the query parts than can possibly match a directory are handled
222 // in FileSystemObject.MatchesQuery.
223 override protected bool MatchesQueryPart (QueryPart abstract_part)
225 return false;
228 ///////////////////////////////////////////////////////////////////////
230 static Random random = new Random ();
232 public FileObject PickChildFile ()
234 if (n_files_below == 0)
235 return null;
237 int i;
238 i = random.Next (n_files_below);
240 foreach (FileSystemObject fso in Children) {
241 if (fso is FileObject) {
242 if (i == 0)
243 return (FileObject) fso;
244 --i;
245 } else if (fso is DirectoryObject) {
246 int nfb;
247 nfb = ((DirectoryObject) fso).n_files_below;
248 if (i < nfb)
249 return ((DirectoryObject) fso).PickChildFile ();
250 i -= nfb;
254 throw new Exception ("This shouldn't happen!");
257 public DirectoryObject PickChildDirectory ()
259 if (n_dirs_below == 0)
260 return null;
262 int i;
263 i = random.Next (n_dirs_below);
265 foreach (FileSystemObject fso in Children) {
267 DirectoryObject dir = fso as DirectoryObject;
268 if (dir == null)
269 continue;
271 if (i == 0)
272 return dir;
273 --i;
275 if (i < dir.n_dirs_below)
276 return dir.PickChildDirectory ();
277 i -= dir.n_dirs_below;
280 throw new Exception ("This also shouldn't happen!");
283 // Returns a directory, either a child directory or itself.
284 public DirectoryObject PickDirectory ()
286 int i;
287 i = random.Next (n_dirs_below + 1);
288 if (i == 0)
289 return this;
290 return PickChildDirectory ();