1 /******************************************************************************* 2 3 copyright: Copyright (c) 2007 Kris Bell. All rights reserved 4 5 license: BSD style: $(LICENSE) 6 7 version: Oct 2007: Initial version 8 9 author: Kris 10 11 *******************************************************************************/ 12 13 module tango.io.vfs.LinkedFolder; 14 15 private import tango.io.vfs.model.Vfs; 16 17 private import tango.core.Exception; 18 19 private import tango.io.vfs.VirtualFolder; 20 21 /******************************************************************************* 22 23 LinkedFolder is derived from VirtualFolder, and behaves exactly the 24 same in all but one aspect: it treats mounted folders as an ordered 25 list of alternatives to look for a file. This supports the notion of 26 file 'overrides', whereby "customized" files can be inserted into a 27 chain of alternatives. 28 29 (overridden folders are not currently supported) 30 31 *******************************************************************************/ 32 33 34 class LinkedFolder : VirtualFolder 35 { 36 private Link* head; 37 38 /*********************************************************************** 39 40 Linked-list of folders 41 42 ***********************************************************************/ 43 44 private struct Link 45 { 46 Link* next; 47 VfsFolder folder; 48 49 static Link* opCall(VfsFolder folder) 50 { 51 auto p = new Link; 52 p.folder = folder; 53 return p; 54 } 55 } 56 57 /*********************************************************************** 58 59 All folder must have a name. No '.' or '/' chars are 60 permitted 61 62 ***********************************************************************/ 63 64 this (const(char)[] name) 65 { 66 super (name); 67 } 68 69 /*********************************************************************** 70 71 Add a child folder. The child cannot 'overlap' with others 72 in the tree of the same type. Circular references across a 73 tree of virtual folders are detected and trapped. 74 75 We add the new child at the end of an ordered list, which 76 we subsequently traverse when looking up a file 77 78 The second argument represents an optional name that the 79 mount should be known as, instead of the name exposed by 80 the provided folder (it is not an alias). 81 82 ***********************************************************************/ 83 84 override final VfsHost mount (VfsFolder folder, const(char)[] name=null) 85 { 86 // traverse to the end of the list 87 auto link = &head; 88 while (*link) 89 link = &(*link).next; 90 91 // hook up the new folder 92 *link = Link (folder); 93 94 // and let superclass deal with it 95 return super.mount (folder, name); 96 } 97 98 /*********************************************************************** 99 100 TODO: unhook a child folder. 101 102 ***********************************************************************/ 103 104 override final VfsHost dismount (VfsFolder folder) 105 { 106 assert (0, "LinkedFolder.dismount not implemented"); 107 } 108 109 /*********************************************************************** 110 111 Return a file representation of the given path. If the 112 path-head does not refer to an immediate child folder, 113 and does not match a symbolic link, it is considered to 114 be unknown. 115 116 We scan the set of mounted folders, in the order mounted, 117 looking for a match. Where one is found, we test to see 118 that it really exists before returning the reference 119 120 ***********************************************************************/ 121 122 @property final override VfsFile file (const(char)[] path) 123 { 124 auto link = head; 125 while (link) 126 { 127 //Stdout.formatln ("looking in {}", link.folder.toString); 128 try { 129 auto file = link.folder.file (path); 130 if (file.exists) 131 return file; 132 } catch (VfsException x) {} 133 link = link.next; 134 } 135 super.error ("file '"~path.idup~"' not found"); 136 return null; 137 } 138 } 139 140 141 debug (LinkedFolder) 142 { 143 /******************************************************************************* 144 145 *******************************************************************************/ 146 147 import tango.io.Stdout; 148 import tango.io.vfs.FileFolder; 149 150 void main() 151 { 152 auto root = new LinkedFolder ("root"); 153 auto sub = new VirtualFolder ("sub"); 154 sub.mount (new FileFolder (r"d:/d/import/temp")); 155 sub.map (sub.file(r"temp/subtree/test.txt"), "wumpus"); 156 157 root.mount (new FileFolder (r"d:/d/import/tango")) 158 .mount (new FileFolder (r"c:/"), "windows"); 159 root.mount (sub); 160 161 auto file = root.file (r"wumpus"); 162 Stdout.formatln ("file = {}", file); 163 } 164 }