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