0
|
1 module dmd.File;
|
|
2
|
|
3 import dmd.FileName;
|
|
4 import dmd.Array;
|
|
5 import dmd.Util;
|
|
6
|
|
7 import core.stdc.stdlib;
|
|
8 import core.sys.windows.windows;
|
|
9
|
|
10 import std.string : toStringz;
|
|
11
|
|
12 class File
|
|
13 {
|
|
14 int ref_; // != 0 if this is a reference to someone else's buffer
|
|
15 ubyte* buffer; // data for our file
|
|
16 uint len; // amount of data in buffer[]
|
|
17 void* touchtime; // system time to use for file
|
|
18
|
|
19 FileName name; // name of our file
|
|
20
|
|
21 this(string n)
|
|
22 {
|
|
23 name = new FileName(n);
|
|
24 }
|
|
25
|
|
26 this(FileName n)
|
|
27 {
|
|
28 name = n;
|
|
29 }
|
|
30
|
|
31 ~this()
|
|
32 {
|
|
33 if (buffer !is null) {
|
|
34 if (ref_ == 0) {
|
|
35 free(buffer);
|
|
36 } else {
|
|
37 version (_WIN32) {
|
|
38 if (ref_ == 2) {
|
|
39 UnmapViewOfFile(buffer);
|
|
40 }
|
|
41 }
|
|
42 }
|
|
43 }
|
|
44
|
|
45 if (touchtime !is null) {
|
|
46 free(touchtime);
|
|
47 }
|
|
48 }
|
|
49
|
|
50 void mark()
|
|
51 {
|
|
52 ///mem.mark(buffer);
|
|
53 ///mem.mark(touchtime);
|
|
54 ///mem.mark(name);
|
|
55 }
|
|
56
|
|
57 string toChars()
|
|
58 {
|
|
59 return name.toChars();
|
|
60 }
|
|
61
|
|
62 /* Read file, return !=0 if error
|
|
63 */
|
|
64
|
|
65 int read()
|
|
66 {
|
|
67 version (POSIX) {
|
|
68 int result = 0;
|
|
69
|
|
70 string name = this.name.toChars();
|
|
71
|
|
72 //printf("File::read('%s')\n",name);
|
|
73 int fd = open(name, O_RDONLY);
|
|
74 if (fd == -1) {
|
|
75 result = errno;
|
|
76 //printf("\topen error, errno = %d\n", errno);
|
|
77 goto err1;
|
|
78 }
|
|
79
|
|
80 if (ref_ == 0) {
|
|
81 free(buffer);
|
|
82 }
|
|
83
|
|
84 ref_ = 0; // we own the buffer now
|
|
85
|
|
86 //printf("\tfile opened\n");
|
|
87 stat buf;
|
|
88 if (fstat(fd, &buf)) {
|
|
89 printf("\tfstat error, errno = %d\n", errno);
|
|
90 goto err2;
|
|
91 }
|
|
92
|
|
93 off_t size = buf.st_size;
|
|
94 buffer = cast(ubyte*)malloc(size + 2);
|
|
95 if (buffer is null) {
|
|
96 printf("\tmalloc error, errno = %d\n", errno);
|
|
97 goto err2;
|
|
98 }
|
|
99
|
|
100 ssize_t numread = .read(fd, buffer, size);
|
|
101 if (numread != size) {
|
|
102 printf("\tread error, errno = %d\n",errno);
|
|
103 goto err2;
|
|
104 }
|
|
105
|
|
106 if (touchtime !is null) {
|
|
107 memcpy(touchtime, &buf, buf.sizeof);
|
|
108 }
|
|
109
|
|
110 if (close(fd) == -1) {
|
|
111 printf("\tclose error, errno = %d\n",errno);
|
|
112 goto err;
|
|
113 }
|
|
114
|
|
115 len = size;
|
|
116
|
|
117 // Always store a wchar ^Z past end of buffer so scanner has a sentinel
|
|
118 buffer[size] = 0; // ^Z is obsolete, use 0
|
|
119 buffer[size + 1] = 0;
|
|
120
|
|
121 return 0;
|
|
122
|
|
123 err2:
|
|
124 close(fd);
|
|
125
|
|
126 err:
|
|
127 free(buffer);
|
|
128 buffer = null;
|
|
129 len = 0;
|
|
130
|
|
131 err1:
|
|
132 result = 1;
|
|
133 return result;
|
|
134 } else version (_WIN32) {
|
|
135 DWORD size;
|
|
136 DWORD numread;
|
|
137 HANDLE h;
|
|
138 int result = 0;
|
|
139
|
|
140 string name = this.name.toChars();
|
|
141 //std.stdio.writeln("Open file ", name);
|
|
142
|
|
143 h = CreateFileA(toStringz(name), GENERIC_READ, FILE_SHARE_READ, null, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, HANDLE.init);
|
|
144 if (h == INVALID_HANDLE_VALUE) {
|
|
145 goto err1;
|
|
146 }
|
|
147
|
|
148 if (!ref_) {
|
|
149 free(buffer);
|
|
150 }
|
|
151 ref_ = 0;
|
|
152
|
|
153 size = GetFileSize(h, null);
|
|
154 buffer = cast(ubyte*) malloc(size + 2);
|
|
155 if (!buffer)
|
|
156 goto err2;
|
|
157
|
|
158 if (ReadFile(h, buffer, size, &numread, null) != TRUE)
|
|
159 goto err2;
|
|
160
|
|
161 if (numread != size)
|
|
162 goto err2;
|
|
163
|
|
164 if (touchtime) {
|
|
165 if (!GetFileTime(h, null, null, &(cast(WIN32_FIND_DATA*)touchtime).ftLastWriteTime))
|
|
166 goto err2;
|
|
167 }
|
|
168
|
|
169 if (!CloseHandle(h))
|
|
170 goto err;
|
|
171
|
|
172 len = size;
|
|
173
|
|
174 // Always store a wchar ^Z past end of buffer so scanner has a sentinel
|
|
175 buffer[size] = 0; // ^Z is obsolete, use 0
|
|
176 buffer[size + 1] = 0;
|
|
177 return 0;
|
|
178
|
|
179 err2:
|
|
180 CloseHandle(h);
|
|
181 err:
|
|
182 free(buffer);
|
|
183 buffer = null;
|
|
184 len = 0;
|
|
185
|
|
186 err1:
|
|
187 result = 1;
|
|
188 return result;
|
|
189 } else {
|
|
190 static assert(0);
|
|
191 }
|
|
192 }
|
|
193
|
|
194 /* Write file, either succeed or fail
|
|
195 * with error message & exit.
|
|
196 */
|
|
197
|
|
198 void readv()
|
|
199 {
|
|
200 if (read())
|
|
201 error("Error reading file '%s'\n",name.toChars());
|
|
202 }
|
|
203
|
|
204 /* Read file, return !=0 if error
|
|
205 */
|
|
206
|
|
207 int mmread()
|
|
208 {
|
|
209 assert(false);
|
|
210 }
|
|
211
|
|
212 /* Write file, either succeed or fail
|
|
213 * with error message & exit.
|
|
214 */
|
|
215
|
|
216 void mmreadv()
|
|
217 {
|
|
218 assert(false);
|
|
219 }
|
|
220
|
|
221 /* Write file, return !=0 if error
|
|
222 */
|
|
223
|
|
224 /*********************************************
|
|
225 * Write a file.
|
|
226 * Returns:
|
|
227 * 0 success
|
|
228 */
|
|
229 int write()
|
|
230 {
|
|
231 version (POSIX) {
|
|
232 assert(false);
|
|
233 /+
|
|
234 int fd;
|
|
235 ssize_t numwritten;
|
|
236 char *name;
|
|
237
|
|
238 name = this->name->toChars();
|
|
239 fd = open(name, O_CREAT | O_WRONLY | O_TRUNC, 0644);
|
|
240 if (fd == -1)
|
|
241 goto err;
|
|
242
|
|
243 numwritten = ::write(fd, buffer, len);
|
|
244 if (len != numwritten)
|
|
245 goto err2;
|
|
246
|
|
247 if (close(fd) == -1)
|
|
248 goto err;
|
|
249
|
|
250 if (touchtime)
|
|
251 { struct utimbuf ubuf;
|
|
252
|
|
253 ubuf.actime = ((struct stat *)touchtime)->st_atime;
|
|
254 ubuf.modtime = ((struct stat *)touchtime)->st_mtime;
|
|
255 if (utime(name, &ubuf))
|
|
256 goto err;
|
|
257 }
|
|
258 return 0;
|
|
259
|
|
260 err2:
|
|
261 close(fd);
|
|
262 ::remove(name);
|
|
263 err:
|
|
264 return 1;
|
|
265 +/
|
|
266 } else version (_WIN32) {
|
|
267 HANDLE h;
|
|
268 DWORD numwritten;
|
|
269
|
|
270 const(char)* name = toStringz(this.name.toChars());
|
|
271 h = CreateFileA(name, GENERIC_WRITE, 0, null, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, null);
|
|
272 if (h == INVALID_HANDLE_VALUE)
|
|
273 goto err;
|
|
274
|
|
275 if (WriteFile(h, buffer, len, &numwritten, null) != TRUE)
|
|
276 goto err2;
|
|
277
|
|
278 if (len != numwritten)
|
|
279 goto err2;
|
|
280
|
|
281 if (touchtime) {
|
|
282 SetFileTime(h, null, null, &(cast(WIN32_FIND_DATA*)touchtime).ftLastWriteTime);
|
|
283 }
|
|
284 if (!CloseHandle(h))
|
|
285 goto err;
|
|
286 return 0;
|
|
287
|
|
288 err2:
|
|
289 CloseHandle(h);
|
|
290 DeleteFileA(name);
|
|
291 err:
|
|
292 return 1;
|
|
293 } else {
|
|
294 static assert(false);
|
|
295 }
|
|
296 }
|
|
297
|
|
298 /* Write file, either succeed or fail
|
|
299 * with error message & exit.
|
|
300 */
|
|
301
|
|
302 void writev()
|
|
303 {
|
|
304 if (write()) {
|
|
305 error("Error writing file '%s'\n", name.toChars());
|
|
306 }
|
|
307 }
|
|
308
|
|
309 /* Return !=0 if file exists.
|
|
310 * 0: file doesn't exist
|
|
311 * 1: normal file
|
|
312 * 2: directory
|
|
313 */
|
|
314
|
|
315 /* Append to file, return !=0 if error
|
|
316 */
|
|
317
|
|
318 int append()
|
|
319 {
|
|
320 assert(false);
|
|
321 }
|
|
322
|
|
323 /* Append to file, either succeed or fail
|
|
324 * with error message & exit.
|
|
325 */
|
|
326
|
|
327 void appendv()
|
|
328 {
|
|
329 assert(false);
|
|
330 }
|
|
331
|
|
332 /* Return !=0 if file exists.
|
|
333 * 0: file doesn't exist
|
|
334 * 1: normal file
|
|
335 * 2: directory
|
|
336 */
|
|
337
|
|
338 int exists()
|
|
339 {
|
|
340 assert(false);
|
|
341 }
|
|
342
|
|
343 /* Given wildcard filespec, return an array of
|
|
344 * matching File's.
|
|
345 */
|
|
346
|
|
347 static Array match(char*)
|
|
348 {
|
|
349 assert(false);
|
|
350 }
|
|
351
|
|
352 static Array match(FileName *)
|
|
353 {
|
|
354 assert(false);
|
|
355 }
|
|
356
|
|
357 // Compare file times.
|
|
358 // Return <0 this < f
|
|
359 // =0 this == f
|
|
360 // >0 this > f
|
|
361 int compareTime(File f)
|
|
362 {
|
|
363 assert(false);
|
|
364 }
|
|
365
|
|
366 // Read system file statistics
|
|
367 void stat()
|
|
368 {
|
|
369 assert(false);
|
|
370 }
|
|
371
|
|
372 /* Set buffer
|
|
373 */
|
|
374
|
|
375 void setbuffer(void* buffer, uint len)
|
|
376 {
|
|
377 this.buffer = cast(ubyte*)buffer;
|
|
378 this.len = len;
|
|
379 }
|
|
380
|
|
381 void checkoffset(size_t offset, size_t nbytes)
|
|
382 {
|
|
383 assert(false);
|
|
384 }
|
|
385
|
|
386 void remove() // delete file
|
|
387 {
|
|
388 version (POSIX) {
|
|
389 .remove(this.name.toChars());
|
|
390 } else version (_WIN32) {
|
|
391 DeleteFileA(toStringz(this.name.toChars()));
|
|
392 } else {
|
|
393 assert(0);
|
|
394 }
|
|
395 }
|
|
396 } |