3 public import "FileSystemIterator"
5 public class FileSystemCacheIterator : InterfaceFileSystemIterator
10 bool Iterate(char * startPath, bool followLinks)
15 if(cache && cache.objects.count)
17 o = cache.FetchObject(startPath);
21 FileSystemCacheIteratorStackFrame frame = null;
22 Array<FileSystemCacheIteratorStackFrame> stack { };
26 listDirEntries = OnObject(owner, o.name, path, o.stats, true);
31 OnEnteringDirectory(owner, path);
32 stack.Add((frame = { path, o.firstChild }));
40 // else { /* TODO: frame is not initialized!! */ }
47 frame.o = o.nextSibling;
49 listDirEntries = OnObject(owner, o.name, path, o.stats, !iterateStartPath && stack.count == 1);
54 OnEnteringDirectory(owner, path);
55 stack.Add((frame = { path, o.firstChild }));
65 if(stack.count > (iterateStartPath ? 0 : 1))
66 OnLeavingDirectory(owner, frame.path);
68 stack.lastIterator.Remove();
69 frame = stack.count == 0 ? null : stack.lastIterator.data;
81 class FileSystemCacheIteratorStackFrame : struct
88 ~FileSystemCacheIteratorStackFrame()
94 class FileSystemCacheBits
99 public class DummyFileSystemCacheWindow : Window
102 FileSystemCache cache { };
105 public class FileSystemCache
108 Map<FSCacheObject, FSCacheRoot> roots { };
109 Array<FSCacheObject> objects { };
110 Array<FSCacheObject> normalParentStack;
111 Map<uint, FileSystemDeviceCache> deviceCaches { };
113 property bool indexInodes { set { bits.indexInodes = value; } get { return bits.indexInodes; } };
115 void/*FileSystemCache*/ ::Cache(char * path, bool indexInodes, DummyFileSystemCacheWindow dummyWindow)
117 FileSystemCache cache = dummyWindow.cache;
118 // TOIMP: for now we will assume the cache includes files from a single domain (partition/share)
119 // TOIMP: would like to use full blown file iterator driver system to support other types of file system, archives, etc
120 FileAttribs pathAttribs = FileExists(path);
123 cache = dummyWindow.cache;// = { };
124 cache.indexInodes = indexInodes;
125 cache.normalParentStack = { };
126 //cache.domainParentStack = { };
127 if(pathAttribs.isDirectory)
129 FileSystemIterator fsi
131 owner = dummyWindow; //owner = (void *)this;
132 iterateStartPath = true;
134 // COMPILER TOFIX: this will not compile (error: method class must be derived from class) -- bool Whatever/*FileSystemCache*/::OnFolder(...)
135 bool /*FileSystemCache*/DummyFileSystemCacheWindow::OnObject(const char * name, const char * path, FileStats stats, bool isRootObject)
138 FileSystemCache cache = this.cache;
139 //uint dev = stats.dev;
140 //uint inode = stats.inode;
142 FSCacheObject parent = isRootObject ? null : cache.normalParentStack.lastIterator.data;
143 FSCacheObject o { parent, name = CopyString(isRootObject ? path : name), stats = stats };
147 // TODO see if we can find a parent for it
148 // see if we already have a FSCacheObject for it, if so, update
149 // distant parents -- when there are gaps.. maybe the parent's parent is present but not the parent
150 // keep a list of those and see if they can be pluged in after a Cache run
151 cache.roots[o] = FSCacheRoot { cache.objects.count, GetPathDirNamesArray(path) };
155 if(!parent.firstChild)
156 parent.firstChild = parent.lastChild = o;
159 parent.lastChild.nextSibling = o;
160 o.prevSibling = parent.lastChild;
161 parent.lastChild = o;
164 cache.objects.Add(o);
167 if(cache.objects.count % 1000 == 0)
168 PrintLn(path, " ----- ", cache.objects.count / 1000, " --------- ", dev);
170 //FileGetStatsLink(path, s);
183 for(c = 0; c < cache.normalParentStack.count; c++)
186 p = cache.normalParentStack[c].GetPath();
194 if(dev && inode && cache.bits.indexInodes)
196 FileSystemDeviceCache devCache = cache.deviceCaches[dev];
198 cache.deviceCaches[dev] = devCache = { };
200 Array<FSCacheObject> inodes = devCache.inodes[inode];
202 devCache.inodes[inode] = inodes = { };
203 else if(inodes.count == 1)
204 devCache.nonSingleLinks[inode] = true;
212 void /*FileSystemCache*/DummyFileSystemCacheWindow::OnEnteringDirectory(const char * path)
214 FileSystemCache cache = this.cache;
215 FSCacheObject o = cache.objects.lastIterator.data;
216 cache.normalParentStack.Add(o);
219 void /*FileSystemCache*/DummyFileSystemCacheWindow::OnLeavingDirectory(const char * path)
221 FileSystemCache cache = this.cache;
222 cache.normalParentStack.lastIterator.Remove();
225 fsi.Iterate(path, false);
227 if(cache.objects.count)
229 for(dev : cache.deviceCaches)
231 PrintLn("# of inodes (dev", &dev, "): ", dev.inodes.count);
233 if(dev.nonSingleLinks.count)
235 for(inode : dev.nonSingleLinks)
237 PrintLn(" ", &inode);
238 for(o : dev.inodes[&inode])
240 char * path = o.GetPath();
249 delete cache.normalParentStack;
256 FSCacheObject FetchObject(char * path)
258 FSCacheObject result = null;
261 FSCacheObject o = &root;
262 Array<String> names = GetPathDirNamesArray(path);
263 int c, max = Min(names.count, root.names.count);
264 for(c = 0; c < max; c++)
266 if(strcmp(names[c], root.names[c]))
275 for(; c < names.count; c++)
277 FSCacheObject child = o.firstChild;
281 if(!strcmp(child.name, names[c]))
286 child = child.nextSibling;
301 bool FileGetStats(char * path, FileStats stats)
303 FSCacheObject o = FetchObject(path);
311 Map<uint, Map<uint, bool>> devsInodesDone { };
312 Map<String, bool> linksPaths { };
313 void Special(char * path/*, Map<String, bool> linksPaths*//*Map<uint, Map<uint, bool>> devsInodesDone*/, DummyFileSystemCacheWindow dummyWindow)
315 FileSystemCacheIterator fsci { owner = dummyWindow, cache = this, iterateStartPath = true;
316 bool /*FileSystemCache*/DummyFileSystemCacheWindow::OnObject(const char * name, const char * path,
317 FileStats stats, bool isRootObject)
321 uint dev = stats.dev;
322 uint inode = stats.inode;
323 FileSystemCache cache = this.cache;
326 FileSystemDeviceCache devCache = cache.deviceCaches[dev];
329 Array<FSCacheObject> links = devCache.inodes[inode];
330 if(links && links.count)
334 Map<uint, bool> inodesDone = cache.devsInodesDone[dev];
335 Map<String, bool> linksPaths = cache.linksPaths;
338 cache.devsInodesDone[dev] = inodesDone = { };
339 done = inodesDone[inode];
342 inodesDone[inode] = true;
343 //PrintLn(" ", &inode);
346 char * path = o.GetPath();
349 linksPaths[path] = true;
355 PrintLn("no links/count!!");
358 PrintLn("no devCache!!");
361 PrintLn("no dev/inode");
366 fsci.Iterate(path, false);
371 MapNode<String, bool> mn;
372 PrintLn(" -------------------------------------------- Special -------------------------------------------- ");
373 PrintLn(" ------------------------------------------------------------------------------------------------- ");
374 for(mn = linksPaths.root.minimum; mn; mn = mn.next)
381 FileSystemCacheBits bits;
390 public class FileSystemDeviceCache : struct
393 Map<uint, Array<FSCacheObject>> inodes { };
394 Map<uint, bool> nonSingleLinks { }; // using a map presuming it will be faster than Array::Find() //Array<uint> nonSingleLinks { };
399 class FSCacheRoot : struct
417 enum FSCacheObjectType { normal };
419 class FSCacheObjectBits
421 FSCacheObjectType type:4;
426 public class FSCacheObject : struct
429 FSCacheObject parent;
432 FSCacheObject firstChild;
433 FSCacheObject lastChild;
434 FSCacheObject prevSibling;
435 FSCacheObject nextSibling;
440 char path[MAX_LOCATION] = "";
442 Array<FSCacheObject> stack { };
443 for(o = this; o; o = o.parent)
445 for(c = stack.count - 1; c >= 0; c--)
448 if(c < stack.count - 1)
449 strcat(path, DIR_SEPS);
450 strcat(path, o.name);
453 return CopyString(path);
457 // FSCacheObjectBits bits;
465 Array<String> GetPathDirNamesArray(const char * path)
470 const char * p = path;
471 char rest[MAX_LOCATION];
472 char name[MAX_FILENAME];
476 SplitDirectory(p, name, rest);
477 if(p == path) p = rest;
478 names.Add(CopyString(name));