BadScript 2
Loading...
Searching...
No Matches
BadLayeredFileSystem.cs
Go to the documentation of this file.
1using System;
2using System.Collections.Generic;
3using System.IO;
4using System.Linq;
5using BadScript2.IO;
7
9{
10
12 {
14
16 {
17 List<BadLayeredFileSystemInfo> fileSystems = new List<BadLayeredFileSystemInfo>();
18 Dictionary<string,BadLayeredFileSystemFileInfo> files = new Dictionary<string,BadLayeredFileSystemFileInfo>();
19 foreach (var layer in m_Layers)
20 {
21 var fs = layer.FileSystem;
22 fileSystems.Add(new BadLayeredFileSystemInfo() { Writable = fs == GetWritable(), Name = layer.Name, MetaData = layer.MetaData });
23 foreach (var file in fs.GetFiles("/", "", true))
24 {
25 if (!files.TryGetValue(file, out var info))
26 {
28 {
29 Path = file,
30 PresentIn = new List<string>()
31 };
32 files[file] = info;
33 }
34
35 info.PresentIn.Add(layer.Name);
36 }
37 }
38
39 return new BadLayeredFileSystemStackInfo() { FileSystems = fileSystems.ToArray(), Files = files.Values.ToArray() };
40 }
42 {
43 m_Layers = layers;
44 }
45
46 private bool ContentEquals(Stream s1, Stream s2)
47 {
48 if (s1.Length != s2.Length) return false;
49 int b1, b2;
50 do
51 {
52 b1 = s1.ReadByte();
53 b2 = s2.ReadByte();
54 if (b1 != b2) return false;
55 } while (b1 != -1);
56 return true;
57 }
58 public void Optimize()
59 {
60 //Ensure that the writable layer does not have a file that already exists in a read-only layer and has the same content
61 var writable = GetWritable();
62 foreach (var file in writable.GetFiles("/", "", true).ToArray())
63 {
64 foreach (var layer in m_Layers.SkipLast(1))
65 {
66 if (layer.FileSystem.Exists(file) && layer.FileSystem.IsFile(file))
67 {
68 bool equals;
69 using (var wStream = writable.OpenRead(file))
70 {
71 using var rStream = layer.FileSystem.OpenRead(file);
72 equals = ContentEquals(wStream, rStream);
73 }
74 if (equals)
75 {
76 writable.DeleteFile(file);
77 break;
78 }
79 }
80 }
81 }
82 }
83 public bool Restore(string path)
84 {
85 var writable = GetWritable();
86 if (writable.Exists(path))
87 {
88 if (writable.IsFile(path))
89 {
90 writable.DeleteFile(path);
91 }
92 else
93 {
94 writable.DeleteDirectory(path, true);
95 }
96 return true;
97 }
98 return false;
99 }
100 public string GetStartupDirectory()
101 {
103 }
104
105 public bool Exists(string path)
106 {
107 return m_Layers.Any(x => x.FileSystem.Exists(path));
108 }
109
110 public bool IsFile(string path)
111 {
112 return m_Layers.Any(x => x.FileSystem.IsFile(path));
113 }
114
115 public bool IsDirectory(string path)
116 {
117 return m_Layers.Any(x => x.FileSystem.IsDirectory(path));
118 }
119
120 public IEnumerable<string> GetFiles(string path, string extension, bool recursive)
121 {
122 return m_Layers.SelectMany(x =>
123 x.FileSystem.Exists(path) &&
124 x.FileSystem.IsDirectory(path) ?
125 x.FileSystem.GetFiles(path, extension, recursive) :
126 Enumerable.Empty<string>()).Distinct();
127 }
128
129 public IEnumerable<string> GetDirectories(string path, bool recursive)
130 {
131 return m_Layers.SelectMany(x =>
132 x.FileSystem.Exists(path) &&
133 x.FileSystem.IsDirectory(path) ?
134 x.FileSystem.GetDirectories(path, recursive) :
135 Enumerable.Empty<string>()).Distinct();
136 }
137
138 public void CreateDirectory(string path, bool recursive = false)
139 {
140 GetWritable().CreateDirectory(path, recursive);
141 }
142
143 public void DeleteDirectory(string path, bool recursive)
144 {
145 if (!GetWritable().IsDirectory(path)) throw new Exception("Is Readonly");
146 GetWritable().DeleteDirectory(path, recursive);
147 }
148
149 public void DeleteFile(string path)
150 {
151 if (!GetWritable().IsFile(path)) throw new Exception("Is Readonly");
152 GetWritable().DeleteFile(path);
153 }
154
155 public string GetFullPath(string path)
156 {
157 return GetWritable().GetFullPath(path);
158 }
159
160 public Stream OpenRead(string path)
161 {
162 var fs = m_Layers.Last(x => x.FileSystem.IsFile(path))?.FileSystem ?? GetWritable();
163 return fs.OpenRead(path);
164 }
165
166 public Stream OpenWrite(string path, BadWriteMode mode)
167 {
168 var writable = GetWritable();
169 var dir = Path.GetDirectoryName(path);
170 if (dir != null && IsDirectory(dir) && !writable.IsDirectory(dir))
171 {
172 //Create the directory if it does not exist(it exists in some other layer, we need to create it in the writable layer)
173 writable.CreateDirectory(dir, true);
174 }
175 //In order to properly work with Append mode, we need to copy the file to the writable file system if it does not exist
176 if (mode == BadWriteMode.Append && !writable.IsFile(path))
177 {
178 using var src = OpenRead(path);
179 using var dst = writable.OpenWrite(path, BadWriteMode.CreateNew);
180 src.CopyTo(dst);
181 }
182 return writable.OpenWrite(path, mode);
183 }
184
185 public string GetCurrentDirectory()
186 {
188 }
189
190 public void SetCurrentDirectory(string path)
191 {
192 foreach (var fs in m_Layers) fs.FileSystem.SetCurrentDirectory(path);
193 }
194
195 public void Copy(string src, string dst, bool overwrite = true)
196 {
197 if (IsDirectory(src))
198 {
199 if (IsSubfolderOf(src, dst)) throw new IOException("Cannot copy a directory to a subfolder of itself.");
200
201 if (!overwrite && IsDirectory(src)) throw new IOException("Directory already exists.");
202
203 CopyDirectoryToDirectory(src, dst);
204 }
205 else if (IsFile(src))
206 {
207 if (!overwrite && IsFile(src)) throw new IOException("File already exists.");
208
209 CopyFileToFile(src, dst);
210 }
211 else
212 {
213 throw new IOException("Source path is not a file or directory");
214 }
215 }
216
217 public void Move(string src, string dst, bool overwrite = true)
218 {
219 Copy(src, dst, overwrite);
220
221 if (IsDirectory(src))
222 DeleteDirectory(src, true);
223 else
224 DeleteFile(src);
225 }
226
228 {
229 return m_Layers.Last().FileSystem;
230 }
231
232 private bool IsSubfolderOf(string root, string sub)
233 {
234 return GetFullPath(sub).StartsWith(GetFullPath(root));
235 }
236
237 private void CopyDirectoryToDirectory(string src, string dst)
238 {
239 foreach (var directory in GetDirectories(src, true)) CreateDirectory(directory);
240
241 foreach (var file in GetFiles(src, "*", true)) CopyFileToFile(file, file.Replace(src, dst));
242 }
243
244 private void CopyFileToFile(string src, string dst)
245 {
246 using var s = OpenRead(src);
247 using var d = OpenWrite(dst, BadWriteMode.CreateNew);
248 s.CopyTo(d);
249 }
250 }
251}
Stream OpenWrite(string path, BadWriteMode mode)
Opens a file for writing.
void DeleteDirectory(string path, bool recursive)
Deletes a directory.
string GetFullPath(string path)
Returns the full path of the given path.
BadLayeredFileSystem(params BadLayeredFileSystemLayer[] layers)
void Copy(string src, string dst, bool overwrite=true)
Copies a file or directory to a new location.
readonly BadLayeredFileSystemLayer[] m_Layers
void CopyDirectoryToDirectory(string src, string dst)
bool IsFile(string path)
Returns true if the given path is a file.
void CreateDirectory(string path, bool recursive=false)
Creates a new directory.
bool Exists(string path)
Returns true if the given path is a file or directory.
BadLayeredFileSystemStackInfo GetInfo()
void Move(string src, string dst, bool overwrite=true)
Moves a file or directory to a new location.
string GetStartupDirectory()
The Startup Directory of the Application.
bool IsDirectory(string path)
Returns true if the given path is a directory.
Stream OpenRead(string path)
Opens a file for reading.
IEnumerable< string > GetFiles(string path, string extension, bool recursive)
Returns all files in the given directory that match the specified extension.
void SetCurrentDirectory(string path)
Sets the current Directory.
IEnumerable< string > GetDirectories(string path, bool recursive)
Returns all directories in the given directory.
void DeleteFile(string path)
Deletes a file.
string GetCurrentDirectory()
Returns the Current Directory.
Virtual File System Implementation for the BadScript Engine.
string GetCurrentDirectory()
Returns the Current Directory.
string GetStartupDirectory()
The Startup Directory of the Application.
void DeleteDirectory(string path, bool recursive)
Deletes a directory.
string GetFullPath(string path)
Returns the full path of the given path.
void DeleteFile(string path)
Deletes a file.
void CreateDirectory(string path, bool recursive=false)
Creates a new directory.
Contains the Implementation of the BadScript Virtual File System.
Contains IO Implementation for the BadScript2 Runtime.
BadWriteMode
The Write Modes of the File System Abstraction.