code dump. unfortunate lack of commits. rick click menu on files/folders. comparative...
[ede] / libede / src / FileSystemCache.ec
1 public import "ecere"
2
3 public import "FileSystemIterator"
4
5 public class FileSystemCacheIterator : InterfaceFileSystemIterator
6 {
7 public:
8    FileSystemCache cache;
9
10    bool Iterate(char * startPath, bool followLinks)
11    {
12       bool result = true;
13       char * path;
14       FSCacheObject o;
15       if(cache && cache.objects.count)
16       {
17          o = cache.FetchObject(startPath);
18          if(o)
19          {
20             bool listDirEntries;
21             FileSystemCacheIteratorStackFrame frame = null;
22             Array<FileSystemCacheIteratorStackFrame> stack { };
23             if(iterateStartPath)
24             {
25                path = o.GetPath();
26                listDirEntries = OnObject(owner, o.name, path, o.stats, true);
27                if(o.firstChild)
28                {
29                   if(listDirEntries)
30                   {
31                      OnEnteringDirectory(owner, path);
32                      stack.Add((frame = { path, o.firstChild }));
33                      path = null;
34                   }
35                   else
36                      result = false;
37                }
38                delete path;
39             }
40             // else { /* TODO: frame is not initialized!! */ }
41
42             while(frame)
43             {
44                o = frame.o;
45                if(o)
46                {
47                   frame.o = o.nextSibling;
48                   path = o.GetPath();
49                   listDirEntries = OnObject(owner, o.name, path, o.stats, !iterateStartPath && stack.count == 1);
50                   if(o.firstChild)
51                   {
52                      if(listDirEntries)
53                      {
54                         OnEnteringDirectory(owner, path);
55                         stack.Add((frame = { path, o.firstChild }));
56                         path = null;
57                      }
58                      else
59                         result = false;
60                   }
61                   delete path;
62                }
63                else
64                {
65                   if(stack.count > (iterateStartPath ? 0 : 1))
66                      OnLeavingDirectory(owner, frame.path);
67                   delete frame;
68                   stack.lastIterator.Remove();
69                   frame = stack.count == 0 ? null : stack.lastIterator.data;
70                }
71             }
72             if(stack.count != 0)
73                PrintLn("dddddddd");
74             delete stack;
75          }
76       }
77       return result;
78    }
79 }
80
81 class FileSystemCacheIteratorStackFrame : struct
82 {
83 public:
84    String path;
85    FSCacheObject o;
86
87 private:
88    ~FileSystemCacheIteratorStackFrame()
89    {
90       delete path;
91    }
92 };
93
94 class FileSystemCacheBits
95 {
96    bool indexInodes:1;
97 }
98
99 public class DummyFileSystemCacheWindow : Window
100 {
101 public:
102    FileSystemCache cache { };
103 }
104
105 public class FileSystemCache
106 {
107 public:
108    Map<FSCacheObject, FSCacheRoot> roots { };
109    Array<FSCacheObject> objects { };
110    Array<FSCacheObject> normalParentStack;
111    Map<uint, FileSystemDeviceCache> deviceCaches { };
112
113    property bool indexInodes { set { bits.indexInodes = value; } get { return bits.indexInodes; } };
114
115    void/*FileSystemCache*/ ::Cache(char * path, bool indexInodes, DummyFileSystemCacheWindow dummyWindow)
116    {
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);
121       if(pathAttribs)
122       {
123          cache = dummyWindow.cache;// = { };
124          cache.indexInodes = indexInodes;
125          cache.normalParentStack = { };
126          //cache.domainParentStack = { };
127          if(pathAttribs.isDirectory)
128          {
129             FileSystemIterator fsi
130             {
131                owner = dummyWindow; //owner = (void *)this;
132                iterateStartPath = true;
133
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)
136                {
137                   bool result = true;
138                   FileSystemCache cache = this.cache;
139                   uint dev = stats.dev;
140                   uint inode = stats.inode;
141                   char * p;
142                   FSCacheObject parent = isRootObject ? null : cache.normalParentStack.lastIterator.data;
143                   FSCacheObject o { parent, name = CopyString(isRootObject ? path : name), stats = stats };
144                   FileStats s;
145                   if(isRootObject)
146                   {
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) };
152                   }
153                   else
154                   {
155                      if(!parent.firstChild)
156                         parent.firstChild = parent.lastChild = o;
157                      else
158                      {
159                         parent.lastChild.nextSibling = o;
160                         o.prevSibling = parent.lastChild;
161                         parent.lastChild = o;
162                      }
163                   }
164                   cache.objects.Add(o);
165 #if _DEBUG
166                   if(cache.objects.count % 1000 == 0)
167                      PrintLn(path, " ----- ", cache.objects.count / 1000, " --------- ", dev);
168                   FileGetStatsLink(path, s);
169                   if(s.inode != inode)
170                   {
171                      PrintLn(s.inode);
172                      PrintLn(inode);
173                      PrintLn("crap");
174                   }
175                   p = o.GetPath();
176                   if(strcmp(p, path))
177                   {
178                      int c;
179                      PrintLn("damn");
180                      PrintLn(p);
181                      for(c = 0; c < cache.normalParentStack.count; c++)
182                      {
183                         delete p;
184                         p = cache.normalParentStack[c].GetPath();
185                         PrintLn(p);
186                      }
187                      PrintLn(path);
188                      PrintLn("bad");
189                   }
190                   delete p;
191 #endif
192                   if(dev && inode && cache.bits.indexInodes)
193                   {
194                      FileSystemDeviceCache devCache = cache.deviceCaches[dev];
195                      if(!devCache)
196                         cache.deviceCaches[dev] = devCache = { };
197                      {
198                         Array<FSCacheObject> inodes = devCache.inodes[inode];
199                         if(!inodes)
200                            devCache.inodes[inode] = inodes = { };
201                         else if(inodes.count == 1)
202                            devCache.nonSingleLinks[inode] = true;
203                         inodes.Add(o);
204                      }
205                   }
206                   return result;
207                }
208
209                void /*FileSystemCache*/DummyFileSystemCacheWindow::OnEnteringDirectory(char * path)
210                {
211                   FileSystemCache cache = this.cache;
212                   FSCacheObject o = cache.objects.lastIterator.data;
213                   cache.normalParentStack.Add(o);
214                }
215
216                void /*FileSystemCache*/DummyFileSystemCacheWindow::OnLeavingDirectory(char * path)
217                {
218                   FileSystemCache cache = this.cache;
219                   cache.normalParentStack.lastIterator.Remove();
220                }
221             };
222             fsi.Iterate(path, false);
223             {
224                if(cache.objects.count)
225                {
226                   for(dev : cache.deviceCaches)
227                   {
228                      PrintLn("# of inodes (dev", &dev, "): ", dev.inodes.count);
229
230                      if(dev.nonSingleLinks.count)
231                      {
232                         for(inode : dev.nonSingleLinks)
233                         {
234                            PrintLn("   ", &inode);
235                            for(o : dev.inodes[&inode])
236                            {
237                               char * path = o.GetPath();
238                               PrintLn(path);
239                               delete path;
240                            }
241                         }
242                      }
243                   }
244                }
245             }
246             delete cache.normalParentStack;
247             delete fsi;
248          }
249       }
250       //return cache;
251    }
252
253    FSCacheObject FetchObject(char * path)
254    {
255       FSCacheObject result = null;
256       for(root : roots)
257       {
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++)
262          {
263             if(strcmp(names[c], root.names[c]))
264                break;
265          }
266          if(c == max)
267          {
268             if(c == names.count)
269                result = o;
270             else
271             {
272                for(; c < names.count; c++)
273                {
274                   FSCacheObject child = o.firstChild;
275                   o = null;
276                   while(child)
277                   {
278                      if(!strcmp(child.name, names[c]))
279                      {
280                         o = child;
281                         break;
282                      }
283                      child = child.nextSibling;
284                   }
285                   if(!o)
286                      break;
287                }
288                if(o)
289                   result = o;
290             }
291             break;
292          }
293          delete names;
294       }
295       return result;
296    }
297
298    bool FileGetStats(char * path, FileStats stats)
299    {
300       FSCacheObject o = FetchObject(path);
301       if(o)
302          stats = o.stats;
303       else
304          stats = { };
305       return o != null;
306    }
307
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)
311    {
312       FileSystemCacheIterator fsci { owner = dummyWindow, cache = this, iterateStartPath = true;
313          bool /*FileSystemCache*/DummyFileSystemCacheWindow::OnObject(char * name, char * path, FileStats stats, bool isRootObject)
314          {
315             uint dev = stats.dev;
316             uint inode = stats.inode;
317             FileSystemCache cache = this.cache;
318             if(dev && inode)
319             {
320                FileSystemDeviceCache devCache = cache.deviceCaches[dev];
321                if(devCache)
322                {
323                   Array<FSCacheObject> links = devCache.inodes[inode];
324                   if(links && links.count)
325                   {
326                      if(links.count > 1)
327                      {
328                         Map<uint, bool> inodesDone = cache.devsInodesDone[dev];
329                         Map<String, bool> linksPaths = cache.linksPaths;
330                         bool done;
331                         if(!inodesDone)
332                            cache.devsInodesDone[dev] = inodesDone = { };
333                         done = inodesDone[inode];
334                         if(!done)
335                         {
336                            inodesDone[inode] = true;
337                            //PrintLn("   ", &inode);
338                            for(o : links)
339                            {
340                               char * path = o.GetPath();
341                               //PrintLn(path);
342                               //delete path;
343                               linksPaths[path] = true;
344                            }
345                         }
346                      }
347                   }
348                   else
349                      PrintLn("no links/count!!");
350                }
351                else
352                   PrintLn("no devCache!!");
353             }
354             else
355                PrintLn("no dev/inode");
356             return true;
357          }
358       };
359       fsci.Iterate(path, false);
360       delete fsci;
361    }
362    void SpecialPrint()
363    {
364       MapNode<String, bool> mn;
365       PrintLn(" -------------------------------------------- Special -------------------------------------------- ");
366       PrintLn(" ------------------------------------------------------------------------------------------------- ");
367       for(mn = linksPaths.root.minimum; mn; mn = mn.next)
368       {
369          PrintLn(mn.key);
370       }
371    }
372
373 private:
374    FileSystemCacheBits bits;
375
376    ~FileSystemCache()
377    {
378       objects.Free();
379       delete objects;
380    }
381 }
382
383 public class FileSystemDeviceCache : struct
384 {
385 public:
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 { };
388
389 private:
390 }
391
392 class FSCacheRoot : struct
393 {
394 public:
395    uint position;
396    Array<String> names;
397
398 private:
399    ~FSCacheRoot()
400    {
401       if(names)
402       {
403          names.Free();
404          delete names;
405       }
406    }
407 }
408
409 /*
410 enum FSCacheObjectType { normal };
411
412 class FSCacheObjectBits
413 {
414    FSCacheObjectType type:4;
415    bool isRoot:1;
416 }
417 */
418
419 public class FSCacheObject : struct
420 {
421 public:
422    FSCacheObject parent;
423    char * name;
424    FileStats stats;
425    FSCacheObject firstChild;
426    FSCacheObject lastChild;
427    FSCacheObject prevSibling;
428    FSCacheObject nextSibling;
429
430    char * GetPath()
431    {
432       int c;
433       char path[MAX_LOCATION] = "";
434       FSCacheObject o;
435       Array<FSCacheObject> stack { };
436       for(o = this; o; o = o.parent)
437          stack.Add(o);
438       for(c = stack.count - 1; c >= 0; c--)
439       {
440          o = stack[c];
441          if(c < stack.count - 1)
442             strcat(path, DIR_SEPS);
443          strcat(path, o.name);
444       }
445       delete stack;
446       return CopyString(path);
447    }
448
449 private:
450 //   FSCacheObjectBits bits;
451
452    ~FSCacheObject()
453    {
454       delete name;
455    }
456 }
457
458 Array<String> GetPathDirNamesArray(char * path)
459 {
460    Array<String> names;
461    if(path && path[0])
462    {
463       char * p = path;
464       char rest[MAX_LOCATION];
465       char name[MAX_FILENAME];
466       names = { };
467       while(strlen(p))
468       {
469          SplitDirectory(p, name, rest);
470          if(p == path) p = rest;
471          names.Add(CopyString(name));
472       }
473    }
474    return names;
475 }