Explorer; libede: Fixes to compile, warnings; fixed single window coming up when...
[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(const char * name, const 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                   /*
167                   if(cache.objects.count % 1000 == 0)
168                      PrintLn(path, " ----- ", cache.objects.count / 1000, " --------- ", dev);
169                   */
170                   //FileGetStatsLink(path, s);
171                   /*
172                   if(s.inode != inode)
173                   {
174                      PrintLn(s.inode);
175                      PrintLn(inode);
176                   }
177                   */
178                   p = o.GetPath();
179                   if(strcmp(p, path))
180                   {
181                      int c;
182                      PrintLn(p);
183                      for(c = 0; c < cache.normalParentStack.count; c++)
184                      {
185                         delete p;
186                         p = cache.normalParentStack[c].GetPath();
187                         PrintLn(p);
188                      }
189                      PrintLn(path);
190                   }
191                   delete p;
192 #endif
193                   /*
194                   if(dev && inode && cache.bits.indexInodes)
195                   {
196                      FileSystemDeviceCache devCache = cache.deviceCaches[dev];
197                      if(!devCache)
198                         cache.deviceCaches[dev] = devCache = { };
199                      {
200                         Array<FSCacheObject> inodes = devCache.inodes[inode];
201                         if(!inodes)
202                            devCache.inodes[inode] = inodes = { };
203                         else if(inodes.count == 1)
204                            devCache.nonSingleLinks[inode] = true;
205                         inodes.Add(o);
206                      }
207                   }
208                   */
209                   return result;
210                }
211
212                void /*FileSystemCache*/DummyFileSystemCacheWindow::OnEnteringDirectory(const char * path)
213                {
214                   FileSystemCache cache = this.cache;
215                   FSCacheObject o = cache.objects.lastIterator.data;
216                   cache.normalParentStack.Add(o);
217                }
218
219                void /*FileSystemCache*/DummyFileSystemCacheWindow::OnLeavingDirectory(const char * path)
220                {
221                   FileSystemCache cache = this.cache;
222                   cache.normalParentStack.lastIterator.Remove();
223                }
224             };
225             fsi.Iterate(path, false);
226             {
227                if(cache.objects.count)
228                {
229                   for(dev : cache.deviceCaches)
230                   {
231                      PrintLn("# of inodes (dev", &dev, "): ", dev.inodes.count);
232
233                      if(dev.nonSingleLinks.count)
234                      {
235                         for(inode : dev.nonSingleLinks)
236                         {
237                            PrintLn("   ", &inode);
238                            for(o : dev.inodes[&inode])
239                            {
240                               char * path = o.GetPath();
241                               PrintLn(path);
242                               delete path;
243                            }
244                         }
245                      }
246                   }
247                }
248             }
249             delete cache.normalParentStack;
250             delete fsi;
251          }
252       }
253       //return cache;
254    }
255
256    FSCacheObject FetchObject(char * path)
257    {
258       FSCacheObject result = null;
259       for(root : roots)
260       {
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++)
265          {
266             if(strcmp(names[c], root.names[c]))
267                break;
268          }
269          if(c == max)
270          {
271             if(c == names.count)
272                result = o;
273             else
274             {
275                for(; c < names.count; c++)
276                {
277                   FSCacheObject child = o.firstChild;
278                   o = null;
279                   while(child)
280                   {
281                      if(!strcmp(child.name, names[c]))
282                      {
283                         o = child;
284                         break;
285                      }
286                      child = child.nextSibling;
287                   }
288                   if(!o)
289                      break;
290                }
291                if(o)
292                   result = o;
293             }
294             break;
295          }
296          delete names;
297       }
298       return result;
299    }
300
301    bool FileGetStats(char * path, FileStats stats)
302    {
303       FSCacheObject o = FetchObject(path);
304       if(o)
305          stats = o.stats;
306       else
307          stats = { };
308       return o != null;
309    }
310
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)
314    {
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)
318          {
319                         /*
320
321             uint dev = stats.dev;
322             uint inode = stats.inode;
323             FileSystemCache cache = this.cache;
324             if(dev && inode)
325             {
326                FileSystemDeviceCache devCache = cache.deviceCaches[dev];
327                if(devCache)
328                {
329                   Array<FSCacheObject> links = devCache.inodes[inode];
330                   if(links && links.count)
331                   {
332                      if(links.count > 1)
333                      {
334                         Map<uint, bool> inodesDone = cache.devsInodesDone[dev];
335                         Map<String, bool> linksPaths = cache.linksPaths;
336                         bool done;
337                         if(!inodesDone)
338                            cache.devsInodesDone[dev] = inodesDone = { };
339                         done = inodesDone[inode];
340                         if(!done)
341                         {
342                            inodesDone[inode] = true;
343                            //PrintLn("   ", &inode);
344                            for(o : links)
345                            {
346                               char * path = o.GetPath();
347                               //PrintLn(path);
348                               //delete path;
349                               linksPaths[path] = true;
350                            }
351                         }
352                      }
353                   }
354                   else
355                      PrintLn("no links/count!!");
356                }
357                else
358                   PrintLn("no devCache!!");
359             }
360             else
361                PrintLn("no dev/inode");
362             */
363             return true;
364          }
365       };
366       fsci.Iterate(path, false);
367       delete fsci;
368    }
369    void SpecialPrint()
370    {
371       MapNode<String, bool> mn;
372       PrintLn(" -------------------------------------------- Special -------------------------------------------- ");
373       PrintLn(" ------------------------------------------------------------------------------------------------- ");
374       for(mn = linksPaths.root.minimum; mn; mn = mn.next)
375       {
376          PrintLn(mn.key);
377       }
378    }
379
380 private:
381    FileSystemCacheBits bits;
382
383    ~FileSystemCache()
384    {
385       objects.Free();
386       delete objects;
387    }
388 }
389
390 public class FileSystemDeviceCache : struct
391 {
392 public:
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 { };
395
396 private:
397 }
398
399 class FSCacheRoot : struct
400 {
401 public:
402    uint position;
403    Array<String> names;
404
405 private:
406    ~FSCacheRoot()
407    {
408       if(names)
409       {
410          names.Free();
411          delete names;
412       }
413    }
414 }
415
416 /*
417 enum FSCacheObjectType { normal };
418
419 class FSCacheObjectBits
420 {
421    FSCacheObjectType type:4;
422    bool isRoot:1;
423 }
424 */
425
426 public class FSCacheObject : struct
427 {
428 public:
429    FSCacheObject parent;
430    char * name;
431    FileStats stats;
432    FSCacheObject firstChild;
433    FSCacheObject lastChild;
434    FSCacheObject prevSibling;
435    FSCacheObject nextSibling;
436
437    char * GetPath()
438    {
439       int c;
440       char path[MAX_LOCATION] = "";
441       FSCacheObject o;
442       Array<FSCacheObject> stack { };
443       for(o = this; o; o = o.parent)
444          stack.Add(o);
445       for(c = stack.count - 1; c >= 0; c--)
446       {
447          o = stack[c];
448          if(c < stack.count - 1)
449             strcat(path, DIR_SEPS);
450          strcat(path, o.name);
451       }
452       delete stack;
453       return CopyString(path);
454    }
455
456 private:
457 //   FSCacheObjectBits bits;
458
459    ~FSCacheObject()
460    {
461       delete name;
462    }
463 }
464
465 Array<String> GetPathDirNamesArray(const char * path)
466 {
467    Array<String> names;
468    if(path && path[0])
469    {
470       const char * p = path;
471       char rest[MAX_LOCATION];
472       char name[MAX_FILENAME];
473       names = { };
474       while(strlen(p))
475       {
476          SplitDirectory(p, name, rest);
477          if(p == path) p = rest;
478          names.Add(CopyString(name));
479       }
480    }
481    return names;
482 }