1 // Compiler implementation of the D programming language 2 // Copyright (c) 1999-2015 by Digital Mars 3 // All Rights Reserved 4 // written by Walter Bright 5 // http://www.digitalmars.com 6 // Distributed under the Boost Software License, Version 1.0. 7 // http://www.boost.org/LICENSE_1_0.txt 8 9 module ddmd.root.file; 10 11 import core.stdc.errno, core.stdc.stdio, core.stdc.stdlib, core.stdc..string, core.sys.posix.fcntl, core.sys.posix.sys.types, core.sys.posix.unistd, core.sys.posix.utime, core.sys.windows.windows; 12 import ddmd.root.array, ddmd.root.filename, ddmd.root.rmem; 13 14 version (Windows) alias WIN32_FIND_DATAA = WIN32_FIND_DATA; 15 16 /*********************************************************** 17 */ 18 struct File 19 { 20 int _ref; // != 0 if this is a reference to someone else's buffer 21 ubyte* buffer; // data for our file 22 size_t len; // amount of data in buffer[] 23 const(FileName)* name; // name of our file 24 25 extern (D) this(const(char)* n) 26 { 27 _ref = 0; 28 buffer = null; 29 len = 0; 30 name = new FileName(n); 31 } 32 33 extern (C++) static File* create(const(char)* n) 34 { 35 return new File(n); 36 } 37 38 extern (D) this(const(FileName)* n) 39 { 40 _ref = 0; 41 buffer = null; 42 len = 0; 43 name = n; 44 } 45 46 extern (C++) ~this() 47 { 48 if (buffer) 49 { 50 if (_ref == 0) 51 mem.xfree(buffer); 52 version (Windows) 53 { 54 if (_ref == 2) 55 UnmapViewOfFile(buffer); 56 } 57 } 58 } 59 60 extern (C++) const(char)* toChars() 61 { 62 return name.toChars(); 63 } 64 65 /************************************* 66 */ 67 extern (C++) bool read() 68 { 69 if (len) 70 return false; // already read the file 71 version (Posix) 72 { 73 size_t size; 74 stat_t buf; 75 ssize_t numread; 76 const(char)* name = this.name.toChars(); 77 //printf("File::read('%s')\n",name); 78 int fd = open(name, O_RDONLY); 79 if (fd == -1) 80 { 81 //printf("\topen error, errno = %d\n",errno); 82 goto err1; 83 } 84 if (!_ref) 85 .free(buffer); 86 _ref = 0; // we own the buffer now 87 //printf("\tfile opened\n"); 88 if (fstat(fd, &buf)) 89 { 90 printf("\tfstat error, errno = %d\n", errno); 91 goto err2; 92 } 93 size = cast(size_t)buf.st_size; 94 buffer = cast(ubyte*).malloc(size + 2); 95 if (!buffer) 96 { 97 printf("\tmalloc error, errno = %d\n", errno); 98 goto err2; 99 } 100 numread = .read(fd, buffer, size); 101 if (numread != size) 102 { 103 printf("\tread error, errno = %d\n", errno); 104 goto err2; 105 } 106 if (close(fd) == -1) 107 { 108 printf("\tclose error, errno = %d\n", errno); 109 goto err; 110 } 111 len = size; 112 // Always store a wchar ^Z past end of buffer so scanner has a sentinel 113 buffer[size] = 0; // ^Z is obsolete, use 0 114 buffer[size + 1] = 0; 115 return false; 116 err2: 117 close(fd); 118 err: 119 .free(buffer); 120 buffer = null; 121 len = 0; 122 err1: 123 return true; 124 } 125 else version (Windows) 126 { 127 DWORD size; 128 DWORD numread; 129 const(char)* name = this.name.toChars(); 130 HANDLE h = CreateFileA(name, GENERIC_READ, FILE_SHARE_READ, null, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, null); 131 if (h == INVALID_HANDLE_VALUE) 132 goto err1; 133 if (!_ref) 134 .free(buffer); 135 _ref = 0; 136 size = GetFileSize(h, null); 137 buffer = cast(ubyte*).malloc(size + 2); 138 if (!buffer) 139 goto err2; 140 if (ReadFile(h, buffer, size, &numread, null) != TRUE) 141 goto err2; 142 if (numread != size) 143 goto err2; 144 if (!CloseHandle(h)) 145 goto err; 146 len = size; 147 // Always store a wchar ^Z past end of buffer so scanner has a sentinel 148 buffer[size] = 0; // ^Z is obsolete, use 0 149 buffer[size + 1] = 0; 150 return 0; 151 err2: 152 CloseHandle(h); 153 err: 154 .free(buffer); 155 buffer = null; 156 len = 0; 157 err1: 158 return true; 159 } 160 else 161 { 162 assert(0); 163 } 164 } 165 166 /********************************************* 167 * Write a file. 168 * Returns: 169 * false success 170 */ 171 extern (C++) bool write() 172 { 173 version (Posix) 174 { 175 ssize_t numwritten; 176 const(char)* name = this.name.toChars(); 177 int fd = open(name, O_CREAT | O_WRONLY | O_TRUNC, (6 << 6) | (4 << 3) | 4); 178 if (fd == -1) 179 goto err; 180 numwritten = .write(fd, buffer, len); 181 if (len != numwritten) 182 goto err2; 183 if (close(fd) == -1) 184 goto err; 185 return false; 186 err2: 187 close(fd); 188 .remove(name); 189 err: 190 return true; 191 } 192 else version (Windows) 193 { 194 DWORD numwritten; 195 const(char)* name = this.name.toChars(); 196 HANDLE h = CreateFileA(name, GENERIC_WRITE, 0, null, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, null); 197 if (h == INVALID_HANDLE_VALUE) 198 goto err; 199 if (WriteFile(h, buffer, cast(DWORD)len, &numwritten, null) != TRUE) 200 goto err2; 201 if (len != numwritten) 202 goto err2; 203 if (!CloseHandle(h)) 204 goto err; 205 return false; 206 err2: 207 CloseHandle(h); 208 DeleteFileA(name); 209 err: 210 return true; 211 } 212 else 213 { 214 assert(0); 215 } 216 } 217 218 /* Set buffer 219 */ 220 extern (C++) void setbuffer(void* buffer, size_t len) 221 { 222 this.buffer = cast(ubyte*)buffer; 223 this.len = len; 224 } 225 226 // delete file 227 extern (C++) void remove() 228 { 229 version (Posix) 230 { 231 int dummy = .remove(this.name.toChars()); 232 } 233 else version (Windows) 234 { 235 DeleteFileA(this.name.toChars()); 236 } 237 else 238 { 239 assert(0); 240 } 241 } 242 }