1 /*******************************************************************************
2 
3         copyright:      Copyright (c) 2007 Tango. All rights reserved
4 
5         license:        BSD style: $(LICENSE)
6 
7         version:        Jul 2007: Initial version
8 
9         author:         Lars Ivar, Kris
10 
11 *******************************************************************************/
12 
13 module tango.io.vfs.model.Vfs;
14 
15 
16 
17 private import tango.time.Time : Time;
18 
19 private import tango.io.model.IConduit;
20 
21 private import tango.io.model.IFile : FileInfo;
22 
23 /*******************************************************************************
24 
25         alias FileInfo for filtering
26 
27 *******************************************************************************/
28 
29 alias FileInfo VfsFilterInfo;
30 alias VfsFilterInfo* VfsInfo;
31 
32 // return false to exclude something
33 alias bool delegate(VfsInfo) VfsFilter;
34 
35 
36 /*******************************************************************************
37 
38 *******************************************************************************/
39 
40 struct VfsStats
41 {
42         ulong   bytes;                  // byte count of files
43         size_t  files,                  // number of files
44                 folders;                // number of folders
45 }
46 
47 /*******************************************************************************
48 
49 ******************************************************************************/
50 
51 interface VfsHost : VfsFolder
52 {
53         /**********************************************************************
54 
55                 Add a child folder. The child cannot 'overlap' with others
56                 in the tree of the same type. Circular references across a
57                 tree of virtual folders are detected and trapped.
58 
59                 The second argument represents an optional name that the
60                 mount should be known as, instead of the name exposed by
61                 the provided folder (it is not an alias).
62 
63         **********************************************************************/
64 
65         VfsHost mount (VfsFolder folder, const(char)[] name=null);
66 
67         /***********************************************************************
68 
69                 Add a set of child folders. The children cannot 'overlap'
70                 with others in the tree of the same type. Circular references
71                 are detected and trapped.
72 
73         ***********************************************************************/
74 
75         VfsHost mount (VfsFolders group);
76 
77         /**********************************************************************
78 
79                 Unhook a child folder
80 
81         **********************************************************************/
82 
83         VfsHost dismount (VfsFolder folder);
84 
85         /**********************************************************************
86 
87                 Add a symbolic link to another file. These are referenced
88                 by file() alone, and do not show up in tree traversals
89 
90         **********************************************************************/
91 
92         VfsHost map (VfsFile target, const(char)[] name);
93 
94         /***********************************************************************
95 
96                 Add a symbolic link to another folder. These are referenced
97                 by folder() alone, and do not show up in tree traversals
98 
99         ***********************************************************************/
100 
101         VfsHost map (VfsFolderEntry target, const(char)[] name);
102 }
103 
104 
105 /*******************************************************************************
106 
107         Supports a model a bit like CSS selectors, where a selection
108         of operands is made before applying some operation. For example:
109         ---
110         // count of files in this folder
111         auto count = folder.self.files;
112 
113         // accumulated file byte-count
114         auto bytes = folder.self.bytes;
115 
116         // a group of one folder (itself)
117         auto folders = folder.self;
118         ---
119 
120         The same approach is used to select the subtree descending from
121         a folder:
122         ---
123         // count of files in this tree
124         auto count = folder.tree.files;
125 
126         // accumulated file byte-count
127         auto bytes = folder.tree.bytes;
128 
129         // the group of child folders
130         auto folders = folder.tree;
131         ---
132 
133         Filtering can be applied to the tree resulting in a sub-group.
134         Group operations remain applicable. Note that various wildcard
135         characters may be used in the filtering:
136         ---
137         // select a subset of the resultant tree
138         auto folders = folder.tree.subset("install");
139 
140         // get total file bytes for a tree subset, using wildcards
141         auto bytes = folder.tree.subset("foo*").bytes;
142         ---
143 
144         Files are selected from a set of folders in a similar manner:
145         ---
146         // files called "readme.txt" in this folder
147         auto count = folder.self.catalog("readme.txt").files;
148 
149         // files called "read*.*" in this tree
150         auto count = folder.tree.catalog("read*.*").files;
151 
152         // all txt files belonging to folders starting with "ins"
153         auto count = folder.tree.subset("ins*").catalog("*.txt").files;
154 
155         // custom-filtered files within a subtree
156         auto count = folder.tree.catalog(&filter).files;
157         ---
158 
159         Sets of folders and files support iteration via foreach:
160         ---
161         foreach (folder; root.tree)
162                  Stdout.formatln ("folder name:{}", folder.name);
163 
164         foreach (folder; root.tree.subset("ins*"))
165                  Stdout.formatln ("folder name:{}", folder.name);
166 
167         foreach (file; root.tree.catalog("*.d"))
168                  Stdout.formatln ("file name:{}", file.name);
169         ---
170 
171         Creating and opening a sub-folder is supported in a similar
172         manner, where the single instance is 'selected' before the
173         operation is applied. Open differs from create in that the
174         folder must exist for the former:
175         ---
176         root.folder("myNewFolder").create;
177 
178         root.folder("myExistingFolder").open;
179         ---
180 
181         File manipulation is handled in much the same way:
182         ---
183         root.file("myNewFile").create;
184 
185         auto source = root.file("myExistingFile");
186         root.file("myCopiedFile").copy(source);
187         ---
188 
189         The principal benefits of these approaches are twofold: 1) it
190         turns out to be notably more efficient in terms of traversal, and
191         2) there's no casting required, since there is a clean separation
192         between files and folders.
193 
194         See VfsFile for more information on file handling
195 
196 *******************************************************************************/
197 
198 interface VfsFolder
199 {
200         /***********************************************************************
201 
202                 Return a short name
203 
204         ***********************************************************************/
205 
206         @property const(char)[] name ();
207 
208         /***********************************************************************
209 
210                 Return a long name
211 
212         ***********************************************************************/
213 
214         string toString ();
215 
216         /***********************************************************************
217 
218                 Return a contained file representation
219 
220         ***********************************************************************/
221 
222         @property VfsFile file (const(char)[] path);
223 
224         /***********************************************************************
225 
226                 Return a contained folder representation
227 
228         ***********************************************************************/
229 
230         @property VfsFolderEntry folder (const(char)[] path);
231 
232         /***********************************************************************
233 
234                 Returns a folder set containing only this one. Statistics
235                 are inclusive of entries within this folder only
236 
237         ***********************************************************************/
238 
239         @property VfsFolders self ();
240 
241         /***********************************************************************
242 
243                 Returns a subtree of folders. Statistics are inclusive of
244                 files within this folder and all others within the tree
245 
246         ***********************************************************************/
247 
248         @property VfsFolders tree ();
249 
250         /***********************************************************************
251 
252                 Iterate over the set of immediate child folders. This is
253                 useful for reflecting the hierarchy
254 
255         ***********************************************************************/
256 
257         int opApply (scope int delegate(ref VfsFolder) dg);
258 
259         /***********************************************************************
260 
261                 Clear all content from this folder and subordinates
262 
263         ***********************************************************************/
264 
265         VfsFolder clear ();
266 
267         /***********************************************************************
268 
269                 Is folder writable?
270 
271         ***********************************************************************/
272 
273         @property bool writable ();
274 
275         /***********************************************************************
276 
277                 Close and/or synchronize changes made to this folder. Each
278                 driver should take advantage of this as appropriate, perhaps
279                 combining multiple files together, or possibly copying to a
280                 remote location
281 
282         ***********************************************************************/
283 
284         VfsFolder close (bool commit = true);
285 
286         /***********************************************************************
287 
288                 A folder is being added or removed from the hierarchy. Use
289                 this to test for validity (or whatever) and throw exceptions
290                 as necessary
291 
292         ***********************************************************************/
293 
294         void verify (VfsFolder folder, bool mounting);
295 
296         //VfsFolder copy(VfsFolder from, const(char)[] to);
297         //VfsFolder move(Entry from, VfsFolder toFolder, const(char)[] toName);
298         //const(char)[] absolutePath(const(char)[] path);
299 }
300 
301 
302 /*******************************************************************************
303 
304         Operations upon a set of folders
305 
306 *******************************************************************************/
307 
308 interface VfsFolders
309 {
310         /***********************************************************************
311 
312                 Iterate over the set of contained VfsFolder instances
313 
314         ***********************************************************************/
315 
316         int opApply (scope int delegate(ref VfsFolder) dg);
317 
318         /***********************************************************************
319 
320                 Return the number of files
321 
322         ***********************************************************************/
323 
324         @property size_t files ();
325 
326         /***********************************************************************
327 
328                 Return the number of folders
329 
330         ***********************************************************************/
331 
332         @property size_t folders ();
333 
334         /***********************************************************************
335 
336                 Return the total number of entries (files + folders)
337 
338         ***********************************************************************/
339 
340         @property size_t entries ();
341 
342         /***********************************************************************
343 
344                 Return the total size of contained files
345 
346         ***********************************************************************/
347 
348         @property ulong bytes ();
349 
350         /***********************************************************************
351 
352                 Return a subset of folders matching the given pattern
353 
354         ***********************************************************************/
355 
356         VfsFolders subset (const(char)[]  pattern);
357 
358        /***********************************************************************
359 
360                 Return a set of files matching the given pattern
361 
362         ***********************************************************************/
363 
364         @property VfsFiles catalog (const(char)[]  pattern);
365 
366         /***********************************************************************
367 
368                 Return a set of files matching the given filter
369 
370         ***********************************************************************/
371 
372         @property VfsFiles catalog (VfsFilter filter = null);
373 }
374 
375 
376 /*******************************************************************************
377 
378         Operations upon a set of files
379 
380 *******************************************************************************/
381 
382 interface VfsFiles
383 {
384         /***********************************************************************
385 
386                 Iterate over the set of contained VfsFile instances
387 
388         ***********************************************************************/
389 
390         int opApply (scope int delegate(ref VfsFile) dg);
391 
392         /***********************************************************************
393 
394                 Return the total number of entries
395 
396         ***********************************************************************/
397 
398         @property size_t files ();
399 
400         /***********************************************************************
401 
402                 Return the total size of all files
403 
404         ***********************************************************************/
405 
406         @property ulong bytes ();
407 }
408 
409 
410 /*******************************************************************************
411 
412         A specific file representation
413 
414 *******************************************************************************/
415 
416 interface VfsFile
417 {
418         /***********************************************************************
419 
420                 Return a short name
421 
422         ***********************************************************************/
423 
424         @property const(char)[] name ();
425 
426         /**********************************************************************
427  
428                 Return a long name
429 
430         ***********************************************************************/
431 
432         immutable(char)[] toString ();
433 
434         /***********************************************************************
435 
436                 Does this file exist?
437 
438         ***********************************************************************/
439 
440         @property bool exists ();
441 
442         /***********************************************************************
443 
444                 Return the file size
445 
446         ***********************************************************************/
447 
448         @property ulong size ();
449 
450         /***********************************************************************
451 
452                 Create and copy the given source
453 
454         ***********************************************************************/
455 
456         VfsFile copy (VfsFile source);
457 
458         /***********************************************************************
459 
460                 Create and copy the given source, and remove the source
461 
462         ***********************************************************************/
463 
464         VfsFile move (VfsFile source);
465 
466         /***********************************************************************
467 
468                 Create a new file instance
469 
470         ***********************************************************************/
471 
472         VfsFile create ();
473 
474         /***********************************************************************
475 
476                 Create a new file instance and populate with stream
477 
478         ***********************************************************************/
479 
480         VfsFile create (InputStream stream);
481 
482         /***********************************************************************
483 
484                 Remove this file
485 
486         ***********************************************************************/
487 
488         VfsFile remove ();
489 
490         /***********************************************************************
491 
492                 Return the input stream. Don't forget to close it
493 
494         ***********************************************************************/
495 
496         @property InputStream input ();
497 
498         /***********************************************************************
499 
500                 Return the output stream. Don't forget to close it
501 
502         ***********************************************************************/
503 
504         @property OutputStream output ();
505 
506         /***********************************************************************
507 
508                 Duplicate this entry
509 
510         ***********************************************************************/
511 
512         @property VfsFile dup ();
513 
514         /***********************************************************************
515 
516                 The modified time of the folder
517 
518         ***********************************************************************/
519 
520         @property Time modified ();
521 }
522 
523 
524 /*******************************************************************************
525 
526         Handler for folder operations. Needs some work ...
527 
528 *******************************************************************************/
529 
530 interface VfsFolderEntry
531 {
532         /***********************************************************************
533 
534                 Open a folder
535 
536         ***********************************************************************/
537 
538         VfsFolder open ();
539 
540         /***********************************************************************
541 
542                 Create a new folder
543 
544         ***********************************************************************/
545 
546         VfsFolder create ();
547 
548         /***********************************************************************
549 
550                 Test to see if a folder exists
551 
552         ***********************************************************************/
553 
554         @property bool exists ();
555 }
556 
557 
558 /*******************************************************************************
559 
560     Would be used for things like zip files, where the
561     implementation mantains the contents in memory or on disk, and where
562     the actual zip file isn't/shouldn't be written until one is finished
563     filling it up (for zip due to inefficient file format).
564 
565 *******************************************************************************/
566 
567 interface VfsSync
568 {
569         /***********************************************************************
570 
571         ***********************************************************************/
572 
573         VfsFolder sync ();
574 }
575