X-Git-Url: https://ecere.com/cgi-bin/gitweb.cgi?p=ede;a=blobdiff_plain;f=libede%2Fsrc%2FFileSystemCache.ec;fp=libede%2Fsrc%2FFileSystemCache.ec;h=03920bdeae4baf781828ae8dce139dff96161f70;hp=0000000000000000000000000000000000000000;hb=0a9a2099baaa56c453eb0903258f329c9d4bc25d;hpb=3585433f3055c63a80dce62dc68343ba03a3568c diff --git a/libede/src/FileSystemCache.ec b/libede/src/FileSystemCache.ec new file mode 100644 index 0000000..03920bd --- /dev/null +++ b/libede/src/FileSystemCache.ec @@ -0,0 +1,475 @@ +public import "ecere" + +public import "FileSystemIterator" + +public class FileSystemCacheIterator : InterfaceFileSystemIterator +{ +public: + FileSystemCache cache; + + bool Iterate(char * startPath, bool followLinks) + { + bool result = true; + char * path; + FSCacheObject o; + if(cache && cache.objects.count) + { + o = cache.FetchObject(startPath); + if(o) + { + bool listDirEntries; + FileSystemCacheIteratorStackFrame frame = null; + Array stack { }; + if(iterateStartPath) + { + path = o.GetPath(); + listDirEntries = OnObject(owner, o.name, path, o.stats, true); + if(o.firstChild) + { + if(listDirEntries) + { + OnEnteringDirectory(owner, path); + stack.Add((frame = { path, o.firstChild })); + path = null; + } + else + result = false; + } + delete path; + } + // else { /* TODO: frame is not initialized!! */ } + + while(frame) + { + o = frame.o; + if(o) + { + frame.o = o.nextSibling; + path = o.GetPath(); + listDirEntries = OnObject(owner, o.name, path, o.stats, !iterateStartPath && stack.count == 1); + if(o.firstChild) + { + if(listDirEntries) + { + OnEnteringDirectory(owner, path); + stack.Add((frame = { path, o.firstChild })); + path = null; + } + else + result = false; + } + delete path; + } + else + { + if(stack.count > (iterateStartPath ? 0 : 1)) + OnLeavingDirectory(owner, frame.path); + delete frame; + stack.lastIterator.Remove(); + frame = stack.count == 0 ? null : stack.lastIterator.data; + } + } + if(stack.count != 0) + PrintLn("dddddddd"); + delete stack; + } + } + return result; + } +} + +class FileSystemCacheIteratorStackFrame : struct +{ +public: + String path; + FSCacheObject o; + +private: + ~FileSystemCacheIteratorStackFrame() + { + delete path; + } +}; + +class FileSystemCacheBits +{ + bool indexInodes:1; +} + +public class DummyFileSystemCacheWindow : Window +{ +public: + FileSystemCache cache { }; +} + +public class FileSystemCache +{ +public: + Map roots { }; + Array objects { }; + Array normalParentStack; + Map deviceCaches { }; + + property bool indexInodes { set { bits.indexInodes = value; } get { return bits.indexInodes; } }; + + void/*FileSystemCache*/ ::Cache(char * path, bool indexInodes, DummyFileSystemCacheWindow dummyWindow) + { + FileSystemCache cache = dummyWindow.cache; + // TOIMP: for now we will assume the cache includes files from a single domain (partition/share) + // TOIMP: would like to use full blown file iterator driver system to support other types of file system, archives, etc + FileAttribs pathAttribs = FileExists(path); + if(pathAttribs) + { + cache = dummyWindow.cache;// = { }; + cache.indexInodes = indexInodes; + cache.normalParentStack = { }; + //cache.domainParentStack = { }; + if(pathAttribs.isDirectory) + { + FileSystemIterator fsi + { + owner = dummyWindow; //owner = (void *)this; + iterateStartPath = true; + + // COMPILER TOFIX: this will not compile (error: method class must be derived from class) -- bool Whatever/*FileSystemCache*/::OnFolder(...) + bool /*FileSystemCache*/DummyFileSystemCacheWindow::OnObject(char * name, char * path, FileStats stats, bool isRootObject) + { + bool result = true; + FileSystemCache cache = this.cache; + uint dev = stats.dev; + uint inode = stats.inode; + char * p; + FSCacheObject parent = isRootObject ? null : cache.normalParentStack.lastIterator.data; + FSCacheObject o { parent, name = CopyString(isRootObject ? path : name), stats = stats }; + FileStats s; + if(isRootObject) + { + // TODO see if we can find a parent for it + // see if we already have a FSCacheObject for it, if so, update + // distant parents -- when there are gaps.. maybe the parent's parent is present but not the parent + // keep a list of those and see if they can be pluged in after a Cache run + cache.roots[o] = FSCacheRoot { cache.objects.count, GetPathDirNamesArray(path) }; + } + else + { + if(!parent.firstChild) + parent.firstChild = parent.lastChild = o; + else + { + parent.lastChild.nextSibling = o; + o.prevSibling = parent.lastChild; + parent.lastChild = o; + } + } + cache.objects.Add(o); +#if _DEBUG + if(cache.objects.count % 1000 == 0) + PrintLn(path, " ----- ", cache.objects.count / 1000, " --------- ", dev); + FileGetStatsLink(path, s); + if(s.inode != inode) + { + PrintLn(s.inode); + PrintLn(inode); + PrintLn("crap"); + } + p = o.GetPath(); + if(strcmp(p, path)) + { + int c; + PrintLn("damn"); + PrintLn(p); + for(c = 0; c < cache.normalParentStack.count; c++) + { + delete p; + p = cache.normalParentStack[c].GetPath(); + PrintLn(p); + } + PrintLn(path); + PrintLn("bad"); + } + delete p; +#endif + if(dev && inode && cache.bits.indexInodes) + { + FileSystemDeviceCache devCache = cache.deviceCaches[dev]; + if(!devCache) + cache.deviceCaches[dev] = devCache = { }; + { + Array inodes = devCache.inodes[inode]; + if(!inodes) + devCache.inodes[inode] = inodes = { }; + else if(inodes.count == 1) + devCache.nonSingleLinks[inode] = true; + inodes.Add(o); + } + } + return result; + } + + void /*FileSystemCache*/DummyFileSystemCacheWindow::OnEnteringDirectory(char * path) + { + FileSystemCache cache = this.cache; + FSCacheObject o = cache.objects.lastIterator.data; + cache.normalParentStack.Add(o); + } + + void /*FileSystemCache*/DummyFileSystemCacheWindow::OnLeavingDirectory(char * path) + { + FileSystemCache cache = this.cache; + cache.normalParentStack.lastIterator.Remove(); + } + }; + fsi.Iterate(path, false); + { + if(cache.objects.count) + { + for(dev : cache.deviceCaches) + { + PrintLn("# of inodes (dev", &dev, "): ", dev.inodes.count); + + if(dev.nonSingleLinks.count) + { + for(inode : dev.nonSingleLinks) + { + PrintLn(" ", &inode); + for(o : dev.inodes[&inode]) + { + char * path = o.GetPath(); + PrintLn(path); + delete path; + } + } + } + } + } + } + delete cache.normalParentStack; + delete fsi; + } + } + //return cache; + } + + FSCacheObject FetchObject(char * path) + { + FSCacheObject result = null; + for(root : roots) + { + FSCacheObject o = &root; + Array names = GetPathDirNamesArray(path); + int c, max = Min(names.count, root.names.count); + for(c = 0; c < max; c++) + { + if(strcmp(names[c], root.names[c])) + break; + } + if(c == max) + { + if(c == names.count) + result = o; + else + { + for(; c < names.count; c++) + { + FSCacheObject child = o.firstChild; + o = null; + while(child) + { + if(!strcmp(child.name, names[c])) + { + o = child; + break; + } + child = child.nextSibling; + } + if(!o) + break; + } + if(o) + result = o; + } + break; + } + delete names; + } + return result; + } + + bool FileGetStats(char * path, FileStats stats) + { + FSCacheObject o = FetchObject(path); + if(o) + stats = o.stats; + else + stats = { }; + return o != null; + } + + Map> devsInodesDone { }; + Map linksPaths { }; + void Special(char * path/*, Map linksPaths*//*Map> devsInodesDone*/, DummyFileSystemCacheWindow dummyWindow) + { + FileSystemCacheIterator fsci { owner = dummyWindow, cache = this, iterateStartPath = true; + bool /*FileSystemCache*/DummyFileSystemCacheWindow::OnObject(char * name, char * path, FileStats stats, bool isRootObject) + { + uint dev = stats.dev; + uint inode = stats.inode; + FileSystemCache cache = this.cache; + if(dev && inode) + { + FileSystemDeviceCache devCache = cache.deviceCaches[dev]; + if(devCache) + { + Array links = devCache.inodes[inode]; + if(links && links.count) + { + if(links.count > 1) + { + Map inodesDone = cache.devsInodesDone[dev]; + Map linksPaths = cache.linksPaths; + bool done; + if(!inodesDone) + cache.devsInodesDone[dev] = inodesDone = { }; + done = inodesDone[inode]; + if(!done) + { + inodesDone[inode] = true; + //PrintLn(" ", &inode); + for(o : links) + { + char * path = o.GetPath(); + //PrintLn(path); + //delete path; + linksPaths[path] = true; + } + } + } + } + else + PrintLn("no links/count!!"); + } + else + PrintLn("no devCache!!"); + } + else + PrintLn("no dev/inode"); + return true; + } + }; + fsci.Iterate(path, false); + delete fsci; + } + void SpecialPrint() + { + MapNode mn; + PrintLn(" -------------------------------------------- Special -------------------------------------------- "); + PrintLn(" ------------------------------------------------------------------------------------------------- "); + for(mn = linksPaths.root.minimum; mn; mn = mn.next) + { + PrintLn(mn.key); + } + } + +private: + FileSystemCacheBits bits; + + ~FileSystemCache() + { + objects.Free(); + delete objects; + } +} + +public class FileSystemDeviceCache : struct +{ +public: + Map> inodes { }; + Map nonSingleLinks { }; // using a map presuming it will be faster than Array::Find() //Array nonSingleLinks { }; + +private: +} + +class FSCacheRoot : struct +{ +public: + uint position; + Array names; + +private: + ~FSCacheRoot() + { + if(names) + { + names.Free(); + delete names; + } + } +} + +/* +enum FSCacheObjectType { normal }; + +class FSCacheObjectBits +{ + FSCacheObjectType type:4; + bool isRoot:1; +} +*/ + +public class FSCacheObject : struct +{ +public: + FSCacheObject parent; + char * name; + FileStats stats; + FSCacheObject firstChild; + FSCacheObject lastChild; + FSCacheObject prevSibling; + FSCacheObject nextSibling; + + char * GetPath() + { + int c; + char path[MAX_LOCATION] = ""; + FSCacheObject o; + Array stack { }; + for(o = this; o; o = o.parent) + stack.Add(o); + for(c = stack.count - 1; c >= 0; c--) + { + o = stack[c]; + if(c < stack.count - 1) + strcat(path, DIR_SEPS); + strcat(path, o.name); + } + delete stack; + return CopyString(path); + } + +private: +// FSCacheObjectBits bits; + + ~FSCacheObject() + { + delete name; + } +} + +Array GetPathDirNamesArray(char * path) +{ + Array names; + if(path && path[0]) + { + char * p = path; + char rest[MAX_LOCATION]; + char name[MAX_FILENAME]; + names = { }; + while(strlen(p)) + { + SplitDirectory(p, name, rest); + if(p == path) p = rest; + names.Add(CopyString(name)); + } + } + return names; +}