IKVM11  11
Java SE 11 Virtual Machine for .NET
Loading...
Searching...
No Matches
VfsTable.cs
Go to the documentation of this file.
1using System;
2using System.Collections.Generic;
3using System.IO;
4using System.Linq;
5using System.Reflection;
6using System.Text;
7
9
10namespace IKVM.Runtime.Vfs
11{
12
16 internal class VfsTable
17 {
18
23 public static VfsTable BuildDefaultTable(VfsContext context, string ikvmHome)
24 {
25#if FIRST_PASS || IMPORTER || EXPORTER
26 throw new NotImplementedException();
27#else
28 if (context is null)
29 throw new ArgumentNullException(nameof(context));
30
31 if (Directory.Exists(ikvmHome) == false)
32 throw new DirectoryNotFoundException("Could not locate ikvm.home when establishing VFS.");
33
34 var table = new VfsTable(context);
35 table.AddMount(Path.Combine(ikvmHome, "assembly"), new VfsAssemblyDirectory(context));
36 return table;
37#endif
38 }
39
40 readonly VfsContext context;
41 readonly LinkedList<VfsMount> mounts = new LinkedList<VfsMount>();
42
48 public VfsTable(VfsContext context)
49 {
50 this.context = context ?? throw new ArgumentNullException(nameof(context));
51 }
52
56 public VfsContext Context => context;
57
61 public IReadOnlyCollection<VfsMount> Mounts => mounts;
62
69 public VfsMount AddMount(string path, VfsEntry item)
70 {
71 return mounts.AddFirst(new VfsMount(path, item)).Value;
72 }
73
78 public void RemoveMount(string path)
79 {
80 var mount = mounts.FirstOrDefault(i => i.Path == path);
81 if (mount != null)
82 mounts.Remove(mount);
83 }
84
90 public VfsMount GetMount(string path) => mounts.FirstOrDefault(i => i.IsPath(path));
91
97 public bool IsPath(string path) => GetMount(path) is not null;
98
104 public VfsEntry GetEntry(string path) => GetMount(path) is VfsMount mount ? mount.GetEntry(path.Substring(mount.Path.Length)) : null;
105
111 public string[] List(string path) => GetEntry(path) is VfsDirectory directory ? directory.List() : null;
112
122 public Stream Open(string path, FileMode mode, FileAccess access)
123 {
124 // VFS is currently completely read-only
125 if (mode != FileMode.Open || access != FileAccess.Read)
126 throw new UnauthorizedAccessException("Virtual file system is read-only.");
127
128 // search for the entry in the file system and open it
129 return GetEntry(path) switch
130 {
131 VfsFile file => file.Open(mode, access),
132 VfsDirectory => throw new UnauthorizedAccessException($"Access to '{path}' was denied."),
133 _ => throw new FileNotFoundException("File not found.", path)
134 };
135 }
136
142 public long GetLength(string path)
143 {
144 return GetEntry(path) is VfsFile entry ? entry.Size : 0;
145 }
146
152 public int GetBooleanAttributes(string path)
153 {
154 const int BA_EXISTS = 0x01;
155 const int BA_REGULAR = 0x02;
156 const int BA_DIRECTORY = 0x04;
157
158 return GetEntry(path) switch
159 {
160 VfsDirectory => BA_EXISTS | BA_DIRECTORY,
161 VfsFile => BA_EXISTS | BA_REGULAR,
162 _ => 0,
163 };
164 }
165
173 public static string GetAssemblyClassesPath(VfsContext context, Assembly assembly, string ikvmHome)
174 {
175#if FIRST_PASS || IMPORTER || EXPORTER
176 throw new NotImplementedException();
177#else
178 if (assembly is null)
179 throw new ArgumentNullException(nameof(assembly));
180
181 if (Directory.Exists(ikvmHome) == false)
182 throw new DirectoryNotFoundException("Could not locate IkvmHome when finding VFS.");
183
184 return PathExtensions.EnsureEndingDirectorySeparator(Path.Combine(ikvmHome, "assembly", GetAssemblyDirectoryName(context, assembly), "classes"));
185#endif
186 }
187
195 public static string GetAssemblyResourcesPath(VfsContext context, Assembly assembly, string ikvmHome)
196 {
197#if FIRST_PASS || IMPORTER || EXPORTER
198 throw new NotImplementedException();
199#else
200 if (assembly is null)
201 throw new ArgumentNullException(nameof(assembly));
202
203 if (Directory.Exists(ikvmHome) == false)
204 throw new DirectoryNotFoundException("Could not locate IkvmHome when finding VFS.");
205
206 return PathExtensions.EnsureEndingDirectorySeparator(Path.Combine(ikvmHome, "assembly", GetAssemblyDirectoryName(context, assembly), "resources"));
207#endif
208 }
209
216 static bool IsLoadableAssembly(VfsContext context, Assembly assembly)
217 {
218 if (assembly.ReflectionOnly)
219 return false;
220
221#if NETFRAMEWORK
222 if (assembly.GlobalAssemblyCache)
223 return true;
224#endif
225
226 if (assembly.IsDynamic || assembly.Location == "")
227 return false;
228
229#if NETFRAMEWORK
230 // optimization for the common case where the assembly was loaded from the base directory
231 if (Path.GetDirectoryName(assembly.Location) == Path.GetDirectoryName(AppDomain.CurrentDomain.BaseDirectory))
232 return true;
233#endif
234
235 // attempt to load the assembly from the context
236 if (context.GetAssembly(assembly.GetName()) != null)
237 return true;
238
239 return false;
240 }
241
247 public static string GetAssemblyDirectoryName(VfsContext context, Assembly assembly)
248 {
249 // if we can't load the assembly by name, then use the MVID as the directory
250 if (IsLoadableAssembly(context, assembly) == false)
251 return assembly.ManifestModule.ModuleVersionId.ToString("N");
252
253 var name = assembly.GetName();
254 var simpleName = name.Name;
255 var path = new ValueStringBuilder(simpleName.Length + 4);
256 for (var i = 0; i < simpleName.Length; i++)
257 {
258 if (simpleName[i] == '_')
259 path.Append("_!");
260 else
261 path.Append(simpleName[i]);
262 }
263
264 var publicKeyToken = name.GetPublicKeyToken();
265 if (publicKeyToken != null && publicKeyToken.Length != 0)
266 {
267 var v = name.Version.ToString();
268 path.EnsureCapacity(2 + v.Length + 2 + publicKeyToken.Length * 2);
269
270 path.Append("__");
271 path.Append(v);
272 path.Append("__");
273 for (int i = 0; i < publicKeyToken.Length; i++)
274 path.Append(string.Format("{0:x2}", publicKeyToken[i]));
275 }
276
277 if (name.CultureInfo != null && !string.IsNullOrEmpty(name.CultureInfo.Name))
278 {
279 var n = name.CultureInfo.Name;
280 path.EnsureCapacity(2 + n.Length);
281 path.Append("__");
282 path.Append(name.CultureInfo.Name);
283 }
284
285 return path.ToString();
286 }
287
288 }
289
290}
IKVM.Reflection.Assembly Assembly
Various extension methods for working with paths.
static string EnsureEndingDirectorySeparator(string path)
Ensures the given path ends with a directory separator.