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(char * name, 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);
166 if(cache.objects.count % 1000 == 0)
167 PrintLn(path, " ----- ", cache.objects.count / 1000, " --------- ", dev);
168 FileGetStatsLink(path, s);
181 for(c = 0; c < cache.normalParentStack.count; c++)
184 p = cache.normalParentStack[c].GetPath();
192 if(dev && inode && cache.bits.indexInodes)
194 FileSystemDeviceCache devCache = cache.deviceCaches[dev];
196 cache.deviceCaches[dev] = devCache = { };
198 Array<FSCacheObject> inodes = devCache.inodes[inode];
200 devCache.inodes[inode] = inodes = { };
201 else if(inodes.count == 1)
202 devCache.nonSingleLinks[inode] = true;
209 void /*FileSystemCache*/DummyFileSystemCacheWindow::OnEnteringDirectory(char * path)
211 FileSystemCache cache = this.cache;
212 FSCacheObject o = cache.objects.lastIterator.data;
213 cache.normalParentStack.Add(o);
216 void /*FileSystemCache*/DummyFileSystemCacheWindow::OnLeavingDirectory(char * path)
218 FileSystemCache cache = this.cache;
219 cache.normalParentStack.lastIterator.Remove();
222 fsi.Iterate(path, false);
224 if(cache.objects.count)
226 for(dev : cache.deviceCaches)
228 PrintLn("# of inodes (dev", &dev, "): ", dev.inodes.count);
230 if(dev.nonSingleLinks.count)
232 for(inode : dev.nonSingleLinks)
234 PrintLn(" ", &inode);
235 for(o : dev.inodes[&inode])
237 char * path = o.GetPath();
246 delete cache.normalParentStack;
253 FSCacheObject FetchObject(char * path)
255 FSCacheObject result = null;
258 FSCacheObject o = &root;
259 Array<String> names = GetPathDirNamesArray(path);
260 int c, max = Min(names.count, root.names.count);
261 for(c = 0; c < max; c++)
263 if(strcmp(names[c], root.names[c]))
272 for(; c < names.count; c++)
274 FSCacheObject child = o.firstChild;
278 if(!strcmp(child.name, names[c]))
283 child = child.nextSibling;
298 bool FileGetStats(char * path, FileStats stats)
300 FSCacheObject o = FetchObject(path);
308 Map<uint, Map<uint, bool>> devsInodesDone { };
309 Map<String, bool> linksPaths { };
310 void Special(char * path/*, Map<String, bool> linksPaths*//*Map<uint, Map<uint, bool>> devsInodesDone*/, DummyFileSystemCacheWindow dummyWindow)
312 FileSystemCacheIterator fsci { owner = dummyWindow, cache = this, iterateStartPath = true;
313 bool /*FileSystemCache*/DummyFileSystemCacheWindow::OnObject(char * name, char * path, FileStats stats, bool isRootObject)
315 uint dev = stats.dev;
316 uint inode = stats.inode;
317 FileSystemCache cache = this.cache;
320 FileSystemDeviceCache devCache = cache.deviceCaches[dev];
323 Array<FSCacheObject> links = devCache.inodes[inode];
324 if(links && links.count)
328 Map<uint, bool> inodesDone = cache.devsInodesDone[dev];
329 Map<String, bool> linksPaths = cache.linksPaths;
332 cache.devsInodesDone[dev] = inodesDone = { };
333 done = inodesDone[inode];
336 inodesDone[inode] = true;
337 //PrintLn(" ", &inode);
340 char * path = o.GetPath();
343 linksPaths[path] = true;
349 PrintLn("no links/count!!");
352 PrintLn("no devCache!!");
355 PrintLn("no dev/inode");
359 fsci.Iterate(path, false);
364 MapNode<String, bool> mn;
365 PrintLn(" -------------------------------------------- Special -------------------------------------------- ");
366 PrintLn(" ------------------------------------------------------------------------------------------------- ");
367 for(mn = linksPaths.root.minimum; mn; mn = mn.next)
374 FileSystemCacheBits bits;
383 public class FileSystemDeviceCache : struct
386 Map<uint, Array<FSCacheObject>> inodes { };
387 Map<uint, bool> nonSingleLinks { }; // using a map presuming it will be faster than Array::Find() //Array<uint> nonSingleLinks { };
392 class FSCacheRoot : struct
410 enum FSCacheObjectType { normal };
412 class FSCacheObjectBits
414 FSCacheObjectType type:4;
419 public class FSCacheObject : struct
422 FSCacheObject parent;
425 FSCacheObject firstChild;
426 FSCacheObject lastChild;
427 FSCacheObject prevSibling;
428 FSCacheObject nextSibling;
433 char path[MAX_LOCATION] = "";
435 Array<FSCacheObject> stack { };
436 for(o = this; o; o = o.parent)
438 for(c = stack.count - 1; c >= 0; c--)
441 if(c < stack.count - 1)
442 strcat(path, DIR_SEPS);
443 strcat(path, o.name);
446 return CopyString(path);
450 // FSCacheObjectBits bits;
458 Array<String> GetPathDirNamesArray(char * path)
464 char rest[MAX_LOCATION];
465 char name[MAX_FILENAME];
469 SplitDirectory(p, name, rest);
470 if(p == path) p = rest;
471 names.Add(CopyString(name));