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