1 /** 2 File handling. 3 4 Copyright: © 2012 RejectedSoftware e.K. 5 License: Subject to the terms of the MIT license, as written in the included LICENSE.txt file. 6 Authors: Sönke Ludwig 7 */ 8 module dub.internal.vibecompat.core.file; 9 10 public import dub.internal.vibecompat.inet.url; 11 12 import dub.internal.vibecompat.core.log; 13 14 import std.conv; 15 import std.c.stdio; 16 import std.datetime; 17 import std.exception; 18 import std.file; 19 import std.path; 20 static import std.stream; 21 import std.string; 22 import std.utf; 23 24 25 version(Posix){ 26 private extern(C) int mkstemps(char* templ, int suffixlen); 27 } 28 29 30 /* Add output range support to File 31 */ 32 struct RangeFile { 33 std.stream.File file; 34 35 void put(in ubyte[] bytes) { file.writeExact(bytes.ptr, bytes.length); } 36 void put(in char[] str) { put(cast(ubyte[])str); } 37 void put(char ch) { put((&ch)[0 .. 1]); } 38 void put(dchar ch) { char[4] chars; put(chars[0 .. encode(chars, ch)]); } 39 40 ubyte[] readAll() 41 { 42 file.seek(0, std.stream.SeekPos.End); 43 auto sz = file.position; 44 enforce(sz <= size_t.max, "File is too big to read to memory."); 45 file.seek(0, std.stream.SeekPos.Set); 46 auto ret = new ubyte[cast(size_t)sz]; 47 file.readExact(ret.ptr, ret.length); 48 return ret; 49 } 50 51 void rawRead(ubyte[] dst) { file.readExact(dst.ptr, dst.length); } 52 void write(string str) { put(str); } 53 void close() { file.close(); } 54 void flush() { file.flush(); } 55 @property ulong size() { return file.size; } 56 } 57 58 59 /** 60 Opens a file stream with the specified mode. 61 */ 62 RangeFile openFile(Path path, FileMode mode = FileMode.Read) 63 { 64 std.stream.FileMode fmode; 65 final switch(mode){ 66 case FileMode.Read: fmode = std.stream.FileMode.In; break; 67 case FileMode.ReadWrite: fmode = std.stream.FileMode.Out; break; 68 case FileMode.CreateTrunc: fmode = std.stream.FileMode.OutNew; break; 69 case FileMode.Append: fmode = std.stream.FileMode.Append; break; 70 } 71 auto ret = new std.stream.File(path.toNativeString(), fmode); 72 assert(ret.isOpen()); 73 return RangeFile(ret); 74 } 75 /// ditto 76 RangeFile openFile(string path, FileMode mode = FileMode.Read) 77 { 78 return openFile(Path(path), mode); 79 } 80 81 82 /** 83 Moves or renames a file. 84 */ 85 void moveFile(Path from, Path to) 86 { 87 moveFile(from.toNativeString(), to.toNativeString()); 88 } 89 /// ditto 90 void moveFile(string from, string to) 91 { 92 std.file.rename(from, to); 93 } 94 95 /** 96 Copies a file. 97 98 Note that attributes and time stamps are currently not retained. 99 100 Params: 101 from = Path of the source file 102 to = Path for the destination file 103 overwrite = If true, any file existing at the destination path will be 104 overwritten. If this is false, an excpetion will be thrown should 105 a file already exist at the destination path. 106 107 Throws: 108 An Exception if the copy operation fails for some reason. 109 */ 110 void copyFile(Path from, Path to, bool overwrite = false) 111 { 112 enforce(overwrite || !existsFile(to), "Destination file already exists."); 113 .copy(from.toNativeString(), to.toNativeString()); 114 } 115 /// ditto 116 void copyFile(string from, string to) 117 { 118 copyFile(Path(from), Path(to)); 119 } 120 121 /** 122 Removes a file 123 */ 124 void removeFile(Path path) 125 { 126 removeFile(path.toNativeString()); 127 } 128 /// ditto 129 void removeFile(string path) { 130 std.file.remove(path); 131 } 132 133 /** 134 Checks if a file exists 135 */ 136 bool existsFile(Path path) { 137 return existsFile(path.toNativeString()); 138 } 139 /// ditto 140 bool existsFile(string path) 141 { 142 return std.file.exists(path); 143 } 144 145 /** Stores information about the specified file/directory into 'info' 146 147 Returns false if the file does not exist. 148 */ 149 FileInfo getFileInfo(Path path) 150 { 151 auto ent = std.file.dirEntry(path.toNativeString()); 152 return makeFileInfo(ent); 153 } 154 /// ditto 155 FileInfo getFileInfo(string path) 156 { 157 return getFileInfo(Path(path)); 158 } 159 160 /** 161 Creates a new directory. 162 */ 163 void createDirectory(Path path) 164 { 165 mkdir(path.toNativeString()); 166 } 167 /// ditto 168 void createDirectory(string path) 169 { 170 createDirectory(Path(path)); 171 } 172 173 /** 174 Enumerates all files in the specified directory. 175 */ 176 void listDirectory(Path path, scope bool delegate(FileInfo info) del) 177 { 178 foreach( DirEntry ent; dirEntries(path.toNativeString(), SpanMode.shallow) ) 179 if( !del(makeFileInfo(ent)) ) 180 break; 181 } 182 /// ditto 183 void listDirectory(string path, scope bool delegate(FileInfo info) del) 184 { 185 listDirectory(Path(path), del); 186 } 187 /// ditto 188 int delegate(scope int delegate(ref FileInfo)) iterateDirectory(Path path) 189 { 190 int iterator(scope int delegate(ref FileInfo) del){ 191 int ret = 0; 192 listDirectory(path, (fi){ 193 ret = del(fi); 194 return ret == 0; 195 }); 196 return ret; 197 } 198 return &iterator; 199 } 200 /// ditto 201 int delegate(scope int delegate(ref FileInfo)) iterateDirectory(string path) 202 { 203 return iterateDirectory(Path(path)); 204 } 205 206 207 /** 208 Returns the current working directory. 209 */ 210 Path getWorkingDirectory() 211 { 212 return Path(std.file.getcwd()); 213 } 214 215 216 /** Contains general information about a file. 217 */ 218 struct FileInfo { 219 /// Name of the file (not including the path) 220 string name; 221 222 /// Size of the file (zero for directories) 223 ulong size; 224 225 /// Time of the last modification 226 SysTime timeModified; 227 228 /// Time of creation (not available on all operating systems/file systems) 229 SysTime timeCreated; 230 231 /// True if this is a symlink to an actual file 232 bool isSymlink; 233 234 /// True if this is a directory or a symlink pointing to a directory 235 bool isDirectory; 236 } 237 238 /** 239 Specifies how a file is manipulated on disk. 240 */ 241 enum FileMode { 242 /// The file is opened read-only. 243 Read, 244 /// The file is opened for read-write random access. 245 ReadWrite, 246 /// The file is truncated if it exists and created otherwise and the opened for read-write access. 247 CreateTrunc, 248 /// The file is opened for appending data to it and created if it does not exist. 249 Append 250 } 251 252 /** 253 Accesses the contents of a file as a stream. 254 */ 255 256 private FileInfo makeFileInfo(DirEntry ent) 257 { 258 FileInfo ret; 259 ret.name = baseName(ent.name); 260 if( ret.name.length == 0 ) ret.name = ent.name; 261 assert(ret.name.length > 0); 262 ret.size = ent.size; 263 ret.timeModified = ent.timeLastModified; 264 version(Windows) ret.timeCreated = ent.timeCreated; 265 else ret.timeCreated = ent.timeLastModified; 266 ret.isSymlink = ent.isSymlink; 267 ret.isDirectory = ent.isDir; 268 return ret; 269 } 270