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
101 public class DummyFileSystemCacheWindow : Window
104 FileSystemCache cache { };
107 public class FileSystemCache
110 Map<FSCacheObject, FSCacheRoot> roots { };
111 Array<FSCacheObject> objects { };
112 Array<FSCacheObject> normalParentStack;
113 Map<uint, FileSystemDeviceCache> deviceCaches { };
115 Map<String, Array<FSCacheObject>> nameIndex { };
116 Map<String, bool> nonSingleNames { };
117 Map<FileSize, Array<FSCacheObject>> sizeIndex { };
118 Map<FileSize, bool> nonSingleSizes { };
120 property bool indexInodes { set { bits.indexInodes = value; } get { return bits.indexInodes; } };
121 property bool indexByName { set { bits.indexByName = value; } get { return bits.indexByName; } };
122 property bool indexBySize { set { bits.indexBySize = value; } get { return bits.indexBySize; } };
124 void/*FileSystemCache*/ ::Cache(char * path, bool indexInodes, bool indexByName, bool indexBySize, DummyFileSystemCacheWindow dummyWindow)
126 FileSystemCache cache = dummyWindow.cache;
127 // TOIMP: for now we will assume the cache includes files from a single domain (partition/share)
128 // TOIMP: would like to use full blown file iterator driver system to support other types of file system, archives, etc
129 FileAttribs pathAttribs = FileExists(path);
132 cache = dummyWindow.cache;// = { };
133 cache.indexInodes = indexInodes;
134 cache.indexByName = indexByName;
135 cache.indexBySize = indexBySize;
136 cache.normalParentStack = { };
137 //cache.domainParentStack = { };
138 if(pathAttribs.isDirectory)
140 FileSystemIterator fsi
142 owner = dummyWindow; //owner = (void *)this;
143 iterateStartPath = true;
145 // COMPILER TOFIX: this will not compile (error: method class must be derived from class) -- bool Whatever/*FileSystemCache*/::OnFolder(...)
146 bool /*FileSystemCache*/DummyFileSystemCacheWindow::OnObject(char * name, char * path, FileStats stats, bool isRootObject)
149 FileSystemCache cache = this.cache;
150 uint dev = 0;//stats.dev;
151 uint inode = 0;//stats.inode;
153 FSCacheObject parent = isRootObject ? null : cache.normalParentStack.lastIterator.data;
154 FSCacheObject o { parent, name = CopyString(isRootObject ? path : name), stats = stats };
158 // TODO see if we can find a parent for it
159 // see if we already have a FSCacheObject for it, if so, update
160 // distant parents -- when there are gaps.. maybe the parent's parent is present but not the parent
161 // keep a list of those and see if they can be pluged in after a Cache run
162 cache.roots[o] = FSCacheRoot { cache.objects.count, GetPathDirNamesArray(path) };
166 if(!parent.firstChild)
167 parent.firstChild = parent.lastChild = o;
170 parent.lastChild.nextSibling = o;
171 o.prevSibling = parent.lastChild;
172 parent.lastChild = o;
175 cache.objects.Add(o);
177 if(cache.objects.count % 1000 == 0)
178 PrintLn(path, " ----- ", cache.objects.count / 1000, " --------- ", dev);
180 FileGetStatsLink(path, s);
193 for(c = 0; c < cache.normalParentStack.count; c++)
196 p = cache.normalParentStack[c].GetPath();
205 if(!stats.attribs.isDirectory)
207 if(dev && inode && cache.bits.indexInodes)
209 FileSystemDeviceCache devCache = cache.deviceCaches[dev];
211 cache.deviceCaches[dev] = devCache = { };
213 Array<FSCacheObject> files = devCache.inodes[inode];
216 devCache.inodes[inode] = files = { };
217 if(cache.bits.indexBySize)
218 CacheAddFileToIndexBySize(cache, o, stats.size);
220 else if(files.count == 1)
221 devCache.nonSingleLinks[inode] = true;
225 else if(cache.bits.indexBySize)
226 CacheAddFileToIndexBySize(cache, o, stats.size);
227 if(cache.bits.indexByName)
228 CacheAddFileToIndexByName(cache, o, name);
233 void /*FileSystemCache*/DummyFileSystemCacheWindow::OnEnteringDirectory(char * path)
235 FileSystemCache cache = this.cache;
236 FSCacheObject o = cache.objects.lastIterator.data;
237 cache.normalParentStack.Add(o);
240 void /*FileSystemCache*/DummyFileSystemCacheWindow::OnLeavingDirectory(char * path)
242 FileSystemCache cache = this.cache;
243 cache.normalParentStack.lastIterator.Remove();
246 fsi.Iterate(path, false);
248 if(cache.objects.count)
250 for(dev : cache.deviceCaches)
252 PrintLn("# of inodes (dev", &dev, "): ", dev.inodes.count);
254 if(dev.nonSingleLinks.count)
256 for(inode : dev.nonSingleLinks)
258 PrintLn(" ", &inode);
259 for(o : dev.inodes[&inode])
261 char * path = o.GetPath();
270 delete cache.normalParentStack;
277 FSCacheObject FetchObject(char * path)
279 FSCacheObject result = null;
282 FSCacheObject o = &root;
283 Array<String> names = GetPathDirNamesArray(path);
284 int c, max = Min(names.count, root.names.count);
285 for(c = 0; c < max; c++)
287 if(strcmp(names[c], root.names[c]))
296 for(; c < names.count; c++)
298 FSCacheObject child = o.firstChild;
302 if(!strcmp(child.name, names[c]))
307 child = child.nextSibling;
322 bool FileGetStats(char * path, FileStats stats)
324 FSCacheObject o = FetchObject(path);
332 Map<uint, Map<uint, bool>> devsInodesDone { };
333 Map<String, bool> linksPaths { };
335 void Special(char * path/*, Map<String, bool> linksPaths*//*Map<uint, Map<uint, bool>> devsInodesDone*/, DummyFileSystemCacheWindow dummyWindow)
337 FileSystemCacheIterator fsci { owner = dummyWindow, cache = this, iterateStartPath = true;
338 bool /*FileSystemCache*/DummyFileSystemCacheWindow::OnObject(char * name, char * path, FileStats stats, bool isRootObject)
340 uint dev = stats.dev;
341 uint inode = stats.inode;
342 FileSystemCache cache = this.cache;
345 FileSystemDeviceCache devCache = cache.deviceCaches[dev];
348 Array<FSCacheObject> links = devCache.inodes[inode];
349 if(links && links.count)
353 Map<uint, bool> inodesDone = cache.devsInodesDone[dev];
354 Map<String, bool> linksPaths = cache.linksPaths;
357 cache.devsInodesDone[dev] = inodesDone = { };
358 done = inodesDone[inode];
361 inodesDone[inode] = true;
362 //PrintLn(" ", &inode);
365 char * path = o.GetPath();
368 linksPaths[path] = true;
374 PrintLn("no links/count!!");
377 PrintLn("no devCache!!");
380 PrintLn("no dev/inode");
384 fsci.Iterate(path, false);
389 MapNode<String, bool> mn;
390 PrintLn(" -------------------------------------------- Special -------------------------------------------- ");
391 PrintLn(" ------------------------------------------------------------------------------------------------- ");
394 for(mn = linksPaths.root.minimum; mn; mn = mn.next)
400 PrintLn(" no hard linked files");
401 PrintLn(" ------------------------------------------------------------------------------------------------- ");
404 void Special(char * path/*, Map<String, bool> linksPaths*//*Map<uint, Map<uint, bool>> devsInodesDone*/, DummyFileSystemCacheWindow dummyWindow)
409 MapNode<FileSize, bool> mn;
410 PrintLn(" -------------------------------------------- Special -------------------------------------------- ");
411 PrintLn(" ------------------------------------------------------------------------------------------------- ");
412 if(nonSingleSizes.count)
414 for(mn = nonSingleSizes.root.minimum; mn; mn = mn.next)
416 Array<FSCacheObject> files = sizeIndex[mn.key];
417 PrintLn(" size: ", mn.value, "# of files: ", files.count);
420 char * p = o.GetPath();
426 PrintLn(" ------------------------------------------------------------------------------------------------- ");
430 FileSystemCacheBits bits;
440 static inline void CacheAddFileToIndexBySize(FileSystemCache cache, FSCacheObject o, FileSize size)
442 Array<FSCacheObject> files = cache.sizeIndex[size];
444 cache.sizeIndex[size] = files = { };
445 else if(files.count == 1)
446 cache.nonSingleSizes[size] = true;
450 static inline void CacheAddFileToIndexByName(FileSystemCache cache, FSCacheObject o, char * name)
452 Array<FSCacheObject> files = cache.nameIndex[name];
454 cache.nameIndex[name] = files = { };
455 else if(files.count == 1)
456 cache.nonSingleNames[name] = true;
461 public class FileSystemDeviceCache : struct
464 Map<uint, Array<FSCacheObject>> inodes { };
465 Map<uint, bool> nonSingleLinks { }; // using a map presuming it will be faster than Array::Find() //Array<uint> nonSingleLinks { };
470 class FSCacheRoot : struct
488 enum FSCacheObjectType { normal };
490 class FSCacheObjectBits
492 FSCacheObjectType type:4;
497 public class FSCacheObject : struct
500 FSCacheObject parent;
503 FSCacheObject firstChild;
504 FSCacheObject lastChild;
505 FSCacheObject prevSibling;
506 FSCacheObject nextSibling;
511 char path[MAX_LOCATION] = "";
513 Array<FSCacheObject> stack { };
514 for(o = this; o; o = o.parent)
516 for(c = stack.count - 1; c >= 0; c--)
519 if(c < stack.count - 1)
520 strcat(path, DIR_SEPS);
521 strcat(path, o.name);
524 return CopyString(path);
528 // FSCacheObjectBits bits;
536 Array<String> GetPathDirNamesArray(char * path)
542 char rest[MAX_LOCATION];
543 char name[MAX_FILENAME];
547 SplitDirectory(p, name, rest);
548 if(p == path) p = rest;
549 names.Add(CopyString(name));