Mercurial > projects > ldc
comparison lphobos/std/file.d @ 473:373489eeaf90
Applied downs' lphobos update
author | Tomas Lindquist Olsen <tomas.l.olsen@gmail.com> |
---|---|
date | Mon, 04 Aug 2008 19:28:49 +0200 |
parents | |
children | 88e23f8c2354 |
comparison
equal
deleted
inserted
replaced
472:15c804b6ce77 | 473:373489eeaf90 |
---|---|
1 // Written in the D programming language. | |
2 | |
3 /** | |
4 * Macros: | |
5 * WIKI = Phobos/StdFile | |
6 */ | |
7 | |
8 /* | |
9 * Copyright (C) 2001-2004 by Digital Mars, www.digitalmars.com | |
10 * Written by Walter Bright, Christopher E. Miller, Andre Fornacon | |
11 * | |
12 * This software is provided 'as-is', without any express or implied | |
13 * warranty. In no event will the authors be held liable for any damages | |
14 * arising from the use of this software. | |
15 * | |
16 * Permission is granted to anyone to use this software for any purpose, | |
17 * including commercial applications, and to alter it and redistribute it | |
18 * freely, subject to the following restrictions: | |
19 * | |
20 * o The origin of this software must not be misrepresented; you must not | |
21 * claim that you wrote the original software. If you use this software | |
22 * in a product, an acknowledgment in the product documentation would be | |
23 * appreciated but is not required. | |
24 * o Altered source versions must be plainly marked as such, and must not | |
25 * be misrepresented as being the original software. | |
26 * o This notice may not be removed or altered from any source | |
27 * distribution. | |
28 */ | |
29 | |
30 /* NOTE: This file has been patched from the original DMD distribution to | |
31 work with the GDC compiler. | |
32 | |
33 Modified by David Friedman, March 2006 | |
34 */ | |
35 | |
36 module std.file; | |
37 | |
38 private import std.c.stdio; | |
39 private import std.c.stdlib; | |
40 private import std.c.string; | |
41 private import std.path; | |
42 private import std.string; | |
43 private import std.regexp; | |
44 private import std.gc; | |
45 | |
46 /* =========================== Win32 ======================= */ | |
47 | |
48 version (Win32) | |
49 { | |
50 | |
51 private import std.c.windows.windows; | |
52 private import std.utf; | |
53 private import std.windows.syserror; | |
54 private import std.windows.charset; | |
55 private import std.date; | |
56 | |
57 int useWfuncs = 1; | |
58 | |
59 static this() | |
60 { | |
61 // Win 95, 98, ME do not implement the W functions | |
62 useWfuncs = (GetVersion() < 0x80000000); | |
63 } | |
64 | |
65 /*********************************** | |
66 * Exception thrown for file I/O errors. | |
67 */ | |
68 | |
69 class FileException : Exception | |
70 { | |
71 | |
72 uint errno; // operating system error code | |
73 | |
74 this(char[] name) | |
75 { | |
76 this(name, "file I/O"); | |
77 } | |
78 | |
79 this(char[] name, char[] message) | |
80 { | |
81 super(name ~ ": " ~ message); | |
82 } | |
83 | |
84 this(char[] name, uint errno) | |
85 { | |
86 this(name, sysErrorString(errno)); | |
87 this.errno = errno; | |
88 } | |
89 } | |
90 | |
91 /* ********************************** | |
92 * Basic File operations. | |
93 */ | |
94 | |
95 /******************************************** | |
96 * Read file name[], return array of bytes read. | |
97 * Throws: | |
98 * FileException on error. | |
99 */ | |
100 | |
101 void[] read(char[] name) | |
102 { | |
103 DWORD numread; | |
104 HANDLE h; | |
105 | |
106 if (useWfuncs) | |
107 { | |
108 wchar* namez = std.utf.toUTF16z(name); | |
109 h = CreateFileW(namez,GENERIC_READ,FILE_SHARE_READ,null,OPEN_EXISTING, | |
110 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,cast(HANDLE)null); | |
111 } | |
112 else | |
113 { | |
114 char* namez = toMBSz(name); | |
115 h = CreateFileA(namez,GENERIC_READ,FILE_SHARE_READ,null,OPEN_EXISTING, | |
116 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,cast(HANDLE)null); | |
117 } | |
118 | |
119 if (h == INVALID_HANDLE_VALUE) | |
120 goto err1; | |
121 | |
122 auto size = GetFileSize(h, null); | |
123 if (size == INVALID_FILE_SIZE) | |
124 goto err2; | |
125 | |
126 auto buf = std.gc.malloc(size); | |
127 if (buf) | |
128 std.gc.hasNoPointers(buf.ptr); | |
129 | |
130 if (ReadFile(h,buf.ptr,size,&numread,null) != 1) | |
131 goto err2; | |
132 | |
133 if (numread != size) | |
134 goto err2; | |
135 | |
136 if (!CloseHandle(h)) | |
137 goto err; | |
138 | |
139 return buf[0 .. size]; | |
140 | |
141 err2: | |
142 CloseHandle(h); | |
143 err: | |
144 delete buf; | |
145 err1: | |
146 throw new FileException(name, GetLastError()); | |
147 } | |
148 | |
149 /********************************************* | |
150 * Write buffer[] to file name[]. | |
151 * Throws: FileException on error. | |
152 */ | |
153 | |
154 void write(char[] name, void[] buffer) | |
155 { | |
156 HANDLE h; | |
157 DWORD numwritten; | |
158 | |
159 if (useWfuncs) | |
160 { | |
161 wchar* namez = std.utf.toUTF16z(name); | |
162 h = CreateFileW(namez,GENERIC_WRITE,0,null,CREATE_ALWAYS, | |
163 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,cast(HANDLE)null); | |
164 } | |
165 else | |
166 { | |
167 char* namez = toMBSz(name); | |
168 h = CreateFileA(namez,GENERIC_WRITE,0,null,CREATE_ALWAYS, | |
169 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,cast(HANDLE)null); | |
170 } | |
171 if (h == INVALID_HANDLE_VALUE) | |
172 goto err; | |
173 | |
174 if (WriteFile(h,buffer.ptr,buffer.length,&numwritten,null) != 1) | |
175 goto err2; | |
176 | |
177 if (buffer.length != numwritten) | |
178 goto err2; | |
179 | |
180 if (!CloseHandle(h)) | |
181 goto err; | |
182 return; | |
183 | |
184 err2: | |
185 CloseHandle(h); | |
186 err: | |
187 throw new FileException(name, GetLastError()); | |
188 } | |
189 | |
190 | |
191 /********************************************* | |
192 * Append buffer[] to file name[]. | |
193 * Throws: FileException on error. | |
194 */ | |
195 | |
196 void append(char[] name, void[] buffer) | |
197 { | |
198 HANDLE h; | |
199 DWORD numwritten; | |
200 | |
201 if (useWfuncs) | |
202 { | |
203 wchar* namez = std.utf.toUTF16z(name); | |
204 h = CreateFileW(namez,GENERIC_WRITE,0,null,OPEN_ALWAYS, | |
205 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,cast(HANDLE)null); | |
206 } | |
207 else | |
208 { | |
209 char* namez = toMBSz(name); | |
210 h = CreateFileA(namez,GENERIC_WRITE,0,null,OPEN_ALWAYS, | |
211 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,cast(HANDLE)null); | |
212 } | |
213 if (h == INVALID_HANDLE_VALUE) | |
214 goto err; | |
215 | |
216 SetFilePointer(h, 0, null, FILE_END); | |
217 | |
218 if (WriteFile(h,buffer.ptr,buffer.length,&numwritten,null) != 1) | |
219 goto err2; | |
220 | |
221 if (buffer.length != numwritten) | |
222 goto err2; | |
223 | |
224 if (!CloseHandle(h)) | |
225 goto err; | |
226 return; | |
227 | |
228 err2: | |
229 CloseHandle(h); | |
230 err: | |
231 throw new FileException(name, GetLastError()); | |
232 } | |
233 | |
234 | |
235 /*************************************************** | |
236 * Rename file from[] to to[]. | |
237 * Throws: FileException on error. | |
238 */ | |
239 | |
240 void rename(char[] from, char[] to) | |
241 { | |
242 BOOL result; | |
243 | |
244 if (useWfuncs) | |
245 result = MoveFileW(std.utf.toUTF16z(from), std.utf.toUTF16z(to)); | |
246 else | |
247 result = MoveFileA(toMBSz(from), toMBSz(to)); | |
248 if (!result) | |
249 throw new FileException(to, GetLastError()); | |
250 } | |
251 | |
252 | |
253 /*************************************************** | |
254 * Delete file name[]. | |
255 * Throws: FileException on error. | |
256 */ | |
257 | |
258 void remove(char[] name) | |
259 { | |
260 BOOL result; | |
261 | |
262 if (useWfuncs) | |
263 result = DeleteFileW(std.utf.toUTF16z(name)); | |
264 else | |
265 result = DeleteFileA(toMBSz(name)); | |
266 if (!result) | |
267 throw new FileException(name, GetLastError()); | |
268 } | |
269 | |
270 | |
271 /*************************************************** | |
272 * Get size of file name[]. | |
273 * Throws: FileException on error. | |
274 */ | |
275 | |
276 ulong getSize(char[] name) | |
277 { | |
278 HANDLE findhndl; | |
279 uint resulth; | |
280 uint resultl; | |
281 | |
282 if (useWfuncs) | |
283 { | |
284 WIN32_FIND_DATAW filefindbuf; | |
285 | |
286 findhndl = FindFirstFileW(std.utf.toUTF16z(name), &filefindbuf); | |
287 resulth = filefindbuf.nFileSizeHigh; | |
288 resultl = filefindbuf.nFileSizeLow; | |
289 } | |
290 else | |
291 { | |
292 WIN32_FIND_DATA filefindbuf; | |
293 | |
294 findhndl = FindFirstFileA(toMBSz(name), &filefindbuf); | |
295 resulth = filefindbuf.nFileSizeHigh; | |
296 resultl = filefindbuf.nFileSizeLow; | |
297 } | |
298 | |
299 if (findhndl == cast(HANDLE)-1) | |
300 { | |
301 throw new FileException(name, GetLastError()); | |
302 } | |
303 FindClose(findhndl); | |
304 return (cast(ulong)resulth << 32) + resultl; | |
305 } | |
306 | |
307 /************************* | |
308 * Get creation/access/modified times of file name[]. | |
309 * Throws: FileException on error. | |
310 */ | |
311 | |
312 void getTimes(char[] name, out d_time ftc, out d_time fta, out d_time ftm) | |
313 { | |
314 HANDLE findhndl; | |
315 | |
316 if (useWfuncs) | |
317 { | |
318 WIN32_FIND_DATAW filefindbuf; | |
319 | |
320 findhndl = FindFirstFileW(std.utf.toUTF16z(name), &filefindbuf); | |
321 ftc = std.date.FILETIME2d_time(&filefindbuf.ftCreationTime); | |
322 fta = std.date.FILETIME2d_time(&filefindbuf.ftLastAccessTime); | |
323 ftm = std.date.FILETIME2d_time(&filefindbuf.ftLastWriteTime); | |
324 } | |
325 else | |
326 { | |
327 WIN32_FIND_DATA filefindbuf; | |
328 | |
329 findhndl = FindFirstFileA(toMBSz(name), &filefindbuf); | |
330 ftc = std.date.FILETIME2d_time(&filefindbuf.ftCreationTime); | |
331 fta = std.date.FILETIME2d_time(&filefindbuf.ftLastAccessTime); | |
332 ftm = std.date.FILETIME2d_time(&filefindbuf.ftLastWriteTime); | |
333 } | |
334 | |
335 if (findhndl == cast(HANDLE)-1) | |
336 { | |
337 throw new FileException(name, GetLastError()); | |
338 } | |
339 FindClose(findhndl); | |
340 } | |
341 | |
342 | |
343 /*************************************************** | |
344 * Does file name[] (or directory) exist? | |
345 * Return 1 if it does, 0 if not. | |
346 */ | |
347 | |
348 int exists(char[] name) | |
349 { | |
350 uint result; | |
351 | |
352 if (useWfuncs) | |
353 // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/fileio/base/getfileattributes.asp | |
354 result = GetFileAttributesW(std.utf.toUTF16z(name)); | |
355 else | |
356 result = GetFileAttributesA(toMBSz(name)); | |
357 | |
358 return (result == 0xFFFFFFFF) ? 0 : 1; | |
359 } | |
360 | |
361 /*************************************************** | |
362 * Get file name[] attributes. | |
363 * Throws: FileException on error. | |
364 */ | |
365 | |
366 uint getAttributes(char[] name) | |
367 { | |
368 uint result; | |
369 | |
370 if (useWfuncs) | |
371 result = GetFileAttributesW(std.utf.toUTF16z(name)); | |
372 else | |
373 result = GetFileAttributesA(toMBSz(name)); | |
374 if (result == 0xFFFFFFFF) | |
375 { | |
376 throw new FileException(name, GetLastError()); | |
377 } | |
378 return result; | |
379 } | |
380 | |
381 /**************************************************** | |
382 * Is name[] a file? | |
383 * Throws: FileException if name[] doesn't exist. | |
384 */ | |
385 | |
386 int isfile(char[] name) | |
387 { | |
388 return (getAttributes(name) & FILE_ATTRIBUTE_DIRECTORY) == 0; | |
389 } | |
390 | |
391 /**************************************************** | |
392 * Is name[] a directory? | |
393 * Throws: FileException if name[] doesn't exist. | |
394 */ | |
395 | |
396 int isdir(char[] name) | |
397 { | |
398 return (getAttributes(name) & FILE_ATTRIBUTE_DIRECTORY) != 0; | |
399 } | |
400 | |
401 /**************************************************** | |
402 * Change directory to pathname[]. | |
403 * Throws: FileException on error. | |
404 */ | |
405 | |
406 void chdir(char[] pathname) | |
407 { BOOL result; | |
408 | |
409 if (useWfuncs) | |
410 result = SetCurrentDirectoryW(std.utf.toUTF16z(pathname)); | |
411 else | |
412 result = SetCurrentDirectoryA(toMBSz(pathname)); | |
413 | |
414 if (!result) | |
415 { | |
416 throw new FileException(pathname, GetLastError()); | |
417 } | |
418 } | |
419 | |
420 /**************************************************** | |
421 * Make directory pathname[]. | |
422 * Throws: FileException on error. | |
423 */ | |
424 | |
425 void mkdir(char[] pathname) | |
426 { BOOL result; | |
427 | |
428 if (useWfuncs) | |
429 result = CreateDirectoryW(std.utf.toUTF16z(pathname), null); | |
430 else | |
431 result = CreateDirectoryA(toMBSz(pathname), null); | |
432 | |
433 if (!result) | |
434 { | |
435 throw new FileException(pathname, GetLastError()); | |
436 } | |
437 } | |
438 | |
439 /**************************************************** | |
440 * Remove directory pathname[]. | |
441 * Throws: FileException on error. | |
442 */ | |
443 | |
444 void rmdir(char[] pathname) | |
445 { BOOL result; | |
446 | |
447 if (useWfuncs) | |
448 result = RemoveDirectoryW(std.utf.toUTF16z(pathname)); | |
449 else | |
450 result = RemoveDirectoryA(toMBSz(pathname)); | |
451 | |
452 if (!result) | |
453 { | |
454 throw new FileException(pathname, GetLastError()); | |
455 } | |
456 } | |
457 | |
458 /**************************************************** | |
459 * Get current directory. | |
460 * Throws: FileException on error. | |
461 */ | |
462 | |
463 char[] getcwd() | |
464 { | |
465 if (useWfuncs) | |
466 { | |
467 wchar c; | |
468 | |
469 auto len = GetCurrentDirectoryW(0, &c); | |
470 if (!len) | |
471 goto Lerr; | |
472 auto dir = new wchar[len]; | |
473 len = GetCurrentDirectoryW(len, dir.ptr); | |
474 if (!len) | |
475 goto Lerr; | |
476 return std.utf.toUTF8(dir[0 .. len]); // leave off terminating 0 | |
477 } | |
478 else | |
479 { | |
480 char c; | |
481 | |
482 auto len = GetCurrentDirectoryA(0, &c); | |
483 if (!len) | |
484 goto Lerr; | |
485 auto dir = new char[len]; | |
486 len = GetCurrentDirectoryA(len, dir.ptr); | |
487 if (!len) | |
488 goto Lerr; | |
489 return dir[0 .. len]; // leave off terminating 0 | |
490 } | |
491 | |
492 Lerr: | |
493 throw new FileException("getcwd", GetLastError()); | |
494 } | |
495 | |
496 /*************************************************** | |
497 * Directory Entry | |
498 */ | |
499 | |
500 struct DirEntry | |
501 { | |
502 char[] name; /// file or directory name | |
503 ulong size = ~0UL; /// size of file in bytes | |
504 d_time creationTime = d_time_nan; /// time of file creation | |
505 d_time lastAccessTime = d_time_nan; /// time file was last accessed | |
506 d_time lastWriteTime = d_time_nan; /// time file was last written to | |
507 uint attributes; // Windows file attributes OR'd together | |
508 | |
509 void init(char[] path, WIN32_FIND_DATA *fd) | |
510 { | |
511 wchar[] wbuf; | |
512 size_t clength; | |
513 size_t wlength; | |
514 size_t n; | |
515 | |
516 clength = std.string.strlen(fd.cFileName.ptr); | |
517 | |
518 // Convert cFileName[] to unicode | |
519 wlength = MultiByteToWideChar(0,0,fd.cFileName.ptr,clength,null,0); | |
520 if (wlength > wbuf.length) | |
521 wbuf.length = wlength; | |
522 n = MultiByteToWideChar(0,0,fd.cFileName.ptr,clength,cast(wchar*)wbuf,wlength); | |
523 assert(n == wlength); | |
524 // toUTF8() returns a new buffer | |
525 name = std.path.join(path, std.utf.toUTF8(wbuf[0 .. wlength])); | |
526 | |
527 size = (cast(ulong)fd.nFileSizeHigh << 32) | fd.nFileSizeLow; | |
528 creationTime = std.date.FILETIME2d_time(&fd.ftCreationTime); | |
529 lastAccessTime = std.date.FILETIME2d_time(&fd.ftLastAccessTime); | |
530 lastWriteTime = std.date.FILETIME2d_time(&fd.ftLastWriteTime); | |
531 attributes = fd.dwFileAttributes; | |
532 } | |
533 | |
534 void init(char[] path, WIN32_FIND_DATAW *fd) | |
535 { | |
536 size_t clength = std.string.wcslen(fd.cFileName.ptr); | |
537 name = std.path.join(path, std.utf.toUTF8(fd.cFileName[0 .. clength])); | |
538 size = (cast(ulong)fd.nFileSizeHigh << 32) | fd.nFileSizeLow; | |
539 creationTime = std.date.FILETIME2d_time(&fd.ftCreationTime); | |
540 lastAccessTime = std.date.FILETIME2d_time(&fd.ftLastAccessTime); | |
541 lastWriteTime = std.date.FILETIME2d_time(&fd.ftLastWriteTime); | |
542 attributes = fd.dwFileAttributes; | |
543 } | |
544 | |
545 /**** | |
546 * Return !=0 if DirEntry is a directory. | |
547 */ | |
548 uint isdir() | |
549 { | |
550 return attributes & FILE_ATTRIBUTE_DIRECTORY; | |
551 } | |
552 | |
553 /**** | |
554 * Return !=0 if DirEntry is a file. | |
555 */ | |
556 uint isfile() | |
557 { | |
558 return !(attributes & FILE_ATTRIBUTE_DIRECTORY); | |
559 } | |
560 } | |
561 | |
562 | |
563 /*************************************************** | |
564 * Return contents of directory pathname[]. | |
565 * The names in the contents do not include the pathname. | |
566 * Throws: FileException on error | |
567 * Example: | |
568 * This program lists all the files and subdirectories in its | |
569 * path argument. | |
570 * ---- | |
571 * import std.stdio; | |
572 * import std.file; | |
573 * | |
574 * void main(char[][] args) | |
575 * { | |
576 * auto dirs = std.file.listdir(args[1]); | |
577 * | |
578 * foreach (d; dirs) | |
579 * writefln(d); | |
580 * } | |
581 * ---- | |
582 */ | |
583 | |
584 char[][] listdir(char[] pathname) | |
585 { | |
586 char[][] result; | |
587 | |
588 bool listing(char[] filename) | |
589 { | |
590 result ~= filename; | |
591 return true; // continue | |
592 } | |
593 | |
594 listdir(pathname, &listing); | |
595 return result; | |
596 } | |
597 | |
598 | |
599 /***************************************************** | |
600 * Return all the files in the directory and its subdirectories | |
601 * that match pattern or regular expression r. | |
602 * Params: | |
603 * pathname = Directory name | |
604 * pattern = String with wildcards, such as $(RED "*.d"). The supported | |
605 * wildcard strings are described under fnmatch() in | |
606 * $(LINK2 std_path.html, std.path). | |
607 * r = Regular expression, for more powerful _pattern matching. | |
608 * Example: | |
609 * This program lists all the files with a "d" extension in | |
610 * the path passed as the first argument. | |
611 * ---- | |
612 * import std.stdio; | |
613 * import std.file; | |
614 * | |
615 * void main(char[][] args) | |
616 * { | |
617 * auto d_source_files = std.file.listdir(args[1], "*.d"); | |
618 * | |
619 * foreach (d; d_source_files) | |
620 * writefln(d); | |
621 * } | |
622 * ---- | |
623 * A regular expression version that searches for all files with "d" or | |
624 * "obj" extensions: | |
625 * ---- | |
626 * import std.stdio; | |
627 * import std.file; | |
628 * import std.regexp; | |
629 * | |
630 * void main(char[][] args) | |
631 * { | |
632 * auto d_source_files = std.file.listdir(args[1], RegExp(r"\.(d|obj)$")); | |
633 * | |
634 * foreach (d; d_source_files) | |
635 * writefln(d); | |
636 * } | |
637 * ---- | |
638 */ | |
639 | |
640 char[][] listdir(char[] pathname, char[] pattern) | |
641 { char[][] result; | |
642 | |
643 bool callback(DirEntry* de) | |
644 { | |
645 if (de.isdir) | |
646 listdir(de.name, &callback); | |
647 else | |
648 { if (std.path.fnmatch(de.name, pattern)) | |
649 result ~= de.name; | |
650 } | |
651 return true; // continue | |
652 } | |
653 | |
654 listdir(pathname, &callback); | |
655 return result; | |
656 } | |
657 | |
658 /** Ditto */ | |
659 | |
660 char[][] listdir(char[] pathname, RegExp r) | |
661 { char[][] result; | |
662 | |
663 bool callback(DirEntry* de) | |
664 { | |
665 if (de.isdir) | |
666 listdir(de.name, &callback); | |
667 else | |
668 { if (r.test(de.name)) | |
669 result ~= de.name; | |
670 } | |
671 return true; // continue | |
672 } | |
673 | |
674 listdir(pathname, &callback); | |
675 return result; | |
676 } | |
677 | |
678 /****************************************************** | |
679 * For each file and directory name in pathname[], | |
680 * pass it to the callback delegate. | |
681 * Params: | |
682 * callback = Delegate that processes each | |
683 * filename in turn. Returns true to | |
684 * continue, false to stop. | |
685 * Example: | |
686 * This program lists all the files in its | |
687 * path argument, including the path. | |
688 * ---- | |
689 * import std.stdio; | |
690 * import std.path; | |
691 * import std.file; | |
692 * | |
693 * void main(char[][] args) | |
694 * { | |
695 * auto pathname = args[1]; | |
696 * char[][] result; | |
697 * | |
698 * bool listing(char[] filename) | |
699 * { | |
700 * result ~= std.path.join(pathname, filename); | |
701 * return true; // continue | |
702 * } | |
703 * | |
704 * listdir(pathname, &listing); | |
705 * | |
706 * foreach (name; result) | |
707 * writefln("%s", name); | |
708 * } | |
709 * ---- | |
710 */ | |
711 | |
712 void listdir(char[] pathname, bool delegate(char[] filename) callback) | |
713 { | |
714 bool listing(DirEntry* de) | |
715 { | |
716 return callback(std.path.getBaseName(de.name)); | |
717 } | |
718 | |
719 listdir(pathname, &listing); | |
720 } | |
721 | |
722 /****************************************************** | |
723 * For each file and directory DirEntry in pathname[], | |
724 * pass it to the callback delegate. | |
725 * Params: | |
726 * callback = Delegate that processes each | |
727 * DirEntry in turn. Returns true to | |
728 * continue, false to stop. | |
729 * Example: | |
730 * This program lists all the files in its | |
731 * path argument and all subdirectories thereof. | |
732 * ---- | |
733 * import std.stdio; | |
734 * import std.file; | |
735 * | |
736 * void main(char[][] args) | |
737 * { | |
738 * bool callback(DirEntry* de) | |
739 * { | |
740 * if (de.isdir) | |
741 * listdir(de.name, &callback); | |
742 * else | |
743 * writefln(de.name); | |
744 * return true; | |
745 * } | |
746 * | |
747 * listdir(args[1], &callback); | |
748 * } | |
749 * ---- | |
750 */ | |
751 | |
752 void listdir(char[] pathname, bool delegate(DirEntry* de) callback) | |
753 { | |
754 char[] c; | |
755 HANDLE h; | |
756 DirEntry de; | |
757 | |
758 c = std.path.join(pathname, "*.*"); | |
759 if (useWfuncs) | |
760 { | |
761 WIN32_FIND_DATAW fileinfo; | |
762 | |
763 h = FindFirstFileW(std.utf.toUTF16z(c), &fileinfo); | |
764 if (h != INVALID_HANDLE_VALUE) | |
765 { | |
766 try | |
767 { | |
768 do | |
769 { | |
770 // Skip "." and ".." | |
771 if (std.string.wcscmp(fileinfo.cFileName.ptr, ".") == 0 || | |
772 std.string.wcscmp(fileinfo.cFileName.ptr, "..") == 0) | |
773 continue; | |
774 | |
775 de.init(pathname, &fileinfo); | |
776 if (!callback(&de)) | |
777 break; | |
778 } while (FindNextFileW(h,&fileinfo) != FALSE); | |
779 } | |
780 finally | |
781 { | |
782 FindClose(h); | |
783 } | |
784 } | |
785 } | |
786 else | |
787 { | |
788 WIN32_FIND_DATA fileinfo; | |
789 | |
790 h = FindFirstFileA(toMBSz(c), &fileinfo); | |
791 if (h != INVALID_HANDLE_VALUE) // should we throw exception if invalid? | |
792 { | |
793 try | |
794 { | |
795 do | |
796 { | |
797 // Skip "." and ".." | |
798 if (std.string.strcmp(fileinfo.cFileName.ptr, ".") == 0 || | |
799 std.string.strcmp(fileinfo.cFileName.ptr, "..") == 0) | |
800 continue; | |
801 | |
802 de.init(pathname, &fileinfo); | |
803 if (!callback(&de)) | |
804 break; | |
805 } while (FindNextFileA(h,&fileinfo) != FALSE); | |
806 } | |
807 finally | |
808 { | |
809 FindClose(h); | |
810 } | |
811 } | |
812 } | |
813 } | |
814 | |
815 /****************************************** | |
816 * Since Win 9x does not support the "W" API's, first convert | |
817 * to wchar, then convert to multibyte using the current code | |
818 * page. | |
819 * (Thanks to yaneurao for this) | |
820 * Deprecated: use std.windows.charset.toMBSz instead. | |
821 */ | |
822 | |
823 char* toMBSz(char[] s) | |
824 { | |
825 return std.windows.charset.toMBSz(s); | |
826 } | |
827 | |
828 | |
829 /*************************************************** | |
830 * Copy a file from[] to[]. | |
831 */ | |
832 | |
833 void copy(char[] from, char[] to) | |
834 { | |
835 BOOL result; | |
836 | |
837 if (useWfuncs) | |
838 result = CopyFileW(std.utf.toUTF16z(from), std.utf.toUTF16z(to), false); | |
839 else | |
840 result = CopyFileA(toMBSz(from), toMBSz(to), false); | |
841 if (!result) | |
842 throw new FileException(to, GetLastError()); | |
843 } | |
844 | |
845 | |
846 } | |
847 | |
848 /* =========================== linux ======================= */ | |
849 | |
850 else version (Unix) | |
851 { | |
852 | |
853 version(linux) { | |
854 import std.c.linux.linux; | |
855 alias std.c.linux.linux sys; | |
856 } else { | |
857 import std.c.unix.unix; | |
858 alias std.c.unix.unix sys; | |
859 } | |
860 import std.date, std.c.string; | |
861 | |
862 /*********************************** | |
863 */ | |
864 | |
865 extern(C) char* strerror_r(int errnum, char* buf, size_t buflen); | |
866 class FileException : Exception | |
867 { | |
868 | |
869 uint errno; // operating system error code | |
870 | |
871 this(char[] name) | |
872 { | |
873 this(name, "file I/O"); | |
874 } | |
875 | |
876 this(char[] name, char[] message) | |
877 { | |
878 super(name ~ ": " ~ message); | |
879 } | |
880 | |
881 this(char[] name, uint errno) | |
882 { char[80] buf = void; | |
883 auto s = strerror_r(errno, buf.ptr, buf.length); | |
884 this(name, std.string.toString(s).dup); | |
885 this.errno = errno; | |
886 } | |
887 } | |
888 | |
889 /******************************************** | |
890 * Read a file. | |
891 * Returns: | |
892 * array of bytes read | |
893 */ | |
894 | |
895 void[] read(char[] name) | |
896 { | |
897 uint numread; | |
898 struct_stat statbuf; | |
899 | |
900 auto namez = toStringz(name); | |
901 //printf("file.read('%s')\n",namez); | |
902 auto fd = sys.open(namez, O_RDONLY); | |
903 if (fd == -1) | |
904 { | |
905 //printf("\topen error, errno = %d\n",getErrno()); | |
906 goto err1; | |
907 } | |
908 | |
909 //printf("\tfile opened\n"); | |
910 if (sys.fstat(fd, &statbuf)) | |
911 { | |
912 //printf("\tfstat error, errno = %d\n",getErrno()); | |
913 goto err2; | |
914 } | |
915 auto size = statbuf.st_size; | |
916 if (size > size_t.max) | |
917 goto err2; | |
918 | |
919 auto buf = std.gc.malloc(size); | |
920 if (buf.ptr) | |
921 std.gc.hasNoPointers(buf.ptr); | |
922 | |
923 numread = sys.read(fd, buf.ptr, size); | |
924 if (numread != size) | |
925 { | |
926 //printf("\tread error, errno = %d\n",getErrno()); | |
927 goto err2; | |
928 } | |
929 | |
930 if (sys.close(fd) == -1) | |
931 { | |
932 //printf("\tclose error, errno = %d\n",getErrno()); | |
933 goto err; | |
934 } | |
935 | |
936 return buf[0 .. size]; | |
937 | |
938 err2: | |
939 sys.close(fd); | |
940 err: | |
941 delete buf; | |
942 | |
943 err1: | |
944 throw new FileException(name, getErrno()); | |
945 } | |
946 | |
947 /********************************************* | |
948 * Write a file. | |
949 * Returns: | |
950 * 0 success | |
951 */ | |
952 | |
953 void write(char[] name, void[] buffer) | |
954 { | |
955 int fd; | |
956 char *namez; | |
957 | |
958 namez = toStringz(name); | |
959 fd = sys.open(namez, O_CREAT | O_WRONLY | O_TRUNC, 0660); | |
960 if (fd == -1) | |
961 goto err; | |
962 | |
963 auto numwritten = sys.write(fd, buffer.ptr, buffer.length); | |
964 if (buffer.length != numwritten) | |
965 goto err2; | |
966 | |
967 if (sys.close(fd) == -1) | |
968 goto err; | |
969 | |
970 return; | |
971 | |
972 err2: | |
973 sys.close(fd); | |
974 err: | |
975 throw new FileException(name, getErrno()); | |
976 } | |
977 | |
978 | |
979 /********************************************* | |
980 * Append to a file. | |
981 */ | |
982 | |
983 void append(char[] name, void[] buffer) | |
984 { | |
985 int fd; | |
986 char *namez; | |
987 | |
988 namez = toStringz(name); | |
989 fd = sys.open(namez, O_APPEND | O_WRONLY | O_CREAT, 0660); | |
990 if (fd == -1) | |
991 goto err; | |
992 | |
993 auto numwritten = sys.write(fd, buffer.ptr, buffer.length); | |
994 if (buffer.length != numwritten) | |
995 goto err2; | |
996 | |
997 if (sys.close(fd) == -1) | |
998 goto err; | |
999 | |
1000 return; | |
1001 | |
1002 err2: | |
1003 sys.close(fd); | |
1004 err: | |
1005 throw new FileException(name, getErrno()); | |
1006 } | |
1007 | |
1008 | |
1009 /*************************************************** | |
1010 * Rename a file. | |
1011 */ | |
1012 | |
1013 void rename(char[] from, char[] to) | |
1014 { | |
1015 char *fromz = toStringz(from); | |
1016 char *toz = toStringz(to); | |
1017 | |
1018 if (std.c.stdio.rename(fromz, toz) == -1) | |
1019 throw new FileException(to, getErrno()); | |
1020 } | |
1021 | |
1022 | |
1023 /*************************************************** | |
1024 * Delete a file. | |
1025 */ | |
1026 | |
1027 void remove(char[] name) | |
1028 { | |
1029 if (std.c.stdio.remove(toStringz(name)) == -1) | |
1030 throw new FileException(name, getErrno()); | |
1031 } | |
1032 | |
1033 | |
1034 /*************************************************** | |
1035 * Get file size. | |
1036 */ | |
1037 | |
1038 ulong getSize(char[] name) | |
1039 { | |
1040 uint size; | |
1041 int fd; | |
1042 struct_stat statbuf; | |
1043 char *namez; | |
1044 | |
1045 namez = toStringz(name); | |
1046 //printf("file.getSize('%s')\n",namez); | |
1047 fd = sys.open(namez, O_RDONLY); | |
1048 if (fd == -1) | |
1049 { | |
1050 //printf("\topen error, errno = %d\n",getErrno()); | |
1051 goto err1; | |
1052 } | |
1053 | |
1054 //printf("\tfile opened\n"); | |
1055 if (sys.fstat(fd, &statbuf)) | |
1056 { | |
1057 //printf("\tfstat error, errno = %d\n",getErrno()); | |
1058 goto err2; | |
1059 } | |
1060 size = statbuf.st_size; | |
1061 | |
1062 if (sys.close(fd) == -1) | |
1063 { | |
1064 //printf("\tclose error, errno = %d\n",getErrno()); | |
1065 goto err; | |
1066 } | |
1067 | |
1068 return size; | |
1069 | |
1070 err2: | |
1071 sys.close(fd); | |
1072 err: | |
1073 err1: | |
1074 throw new FileException(name, getErrno()); | |
1075 } | |
1076 | |
1077 | |
1078 /*************************************************** | |
1079 * Get file attributes. | |
1080 */ | |
1081 | |
1082 uint getAttributes(char[] name) | |
1083 { | |
1084 struct_stat statbuf; | |
1085 char *namez; | |
1086 | |
1087 namez = toStringz(name); | |
1088 if (sys.stat(namez, &statbuf)) | |
1089 { | |
1090 throw new FileException(name, getErrno()); | |
1091 } | |
1092 | |
1093 return statbuf.st_mode; | |
1094 } | |
1095 | |
1096 /************************* | |
1097 * Get creation/access/modified times of file name[]. | |
1098 * Throws: FileException on error. | |
1099 */ | |
1100 | |
1101 void getTimes(char[] name, out d_time ftc, out d_time fta, out d_time ftm) | |
1102 { | |
1103 struct_stat statbuf; | |
1104 char *namez; | |
1105 | |
1106 namez = toStringz(name); | |
1107 if (sys.stat(namez, &statbuf)) | |
1108 { | |
1109 throw new FileException(name, getErrno()); | |
1110 } | |
1111 | |
1112 ftc = cast(d_time)statbuf.st_ctime * std.date.TicksPerSecond; | |
1113 fta = cast(d_time)statbuf.st_atime * std.date.TicksPerSecond; | |
1114 ftm = cast(d_time)statbuf.st_mtime * std.date.TicksPerSecond; | |
1115 } | |
1116 | |
1117 | |
1118 /**************************************************** | |
1119 * Does file/directory exist? | |
1120 */ | |
1121 | |
1122 int exists(char[] name) | |
1123 { | |
1124 return access(toStringz(name),0) == 0; | |
1125 | |
1126 /+ | |
1127 struct_stat statbuf; | |
1128 char *namez; | |
1129 | |
1130 namez = toStringz(name); | |
1131 if (sys.stat(namez, &statbuf)) | |
1132 { | |
1133 return 0; | |
1134 } | |
1135 return 1; | |
1136 +/ | |
1137 } | |
1138 | |
1139 unittest | |
1140 { | |
1141 assert(exists(".")); | |
1142 } | |
1143 | |
1144 /**************************************************** | |
1145 * Is name a file? | |
1146 */ | |
1147 | |
1148 int isfile(char[] name) | |
1149 { | |
1150 return (getAttributes(name) & S_IFMT) == S_IFREG; // regular file | |
1151 } | |
1152 | |
1153 /**************************************************** | |
1154 * Is name a directory? | |
1155 */ | |
1156 | |
1157 int isdir(char[] name) | |
1158 { | |
1159 return (getAttributes(name) & S_IFMT) == S_IFDIR; | |
1160 } | |
1161 | |
1162 /**************************************************** | |
1163 * Change directory. | |
1164 */ | |
1165 | |
1166 void chdir(char[] pathname) | |
1167 { | |
1168 if (sys.chdir(toStringz(pathname))) | |
1169 { | |
1170 throw new FileException(pathname, getErrno()); | |
1171 } | |
1172 } | |
1173 | |
1174 /**************************************************** | |
1175 * Make directory. | |
1176 */ | |
1177 | |
1178 void mkdir(char[] pathname) | |
1179 { | |
1180 if (sys.mkdir(toStringz(pathname), 0777)) | |
1181 { | |
1182 throw new FileException(pathname, getErrno()); | |
1183 } | |
1184 } | |
1185 | |
1186 /**************************************************** | |
1187 * Remove directory. | |
1188 */ | |
1189 | |
1190 void rmdir(char[] pathname) | |
1191 { | |
1192 if (sys.rmdir(toStringz(pathname))) | |
1193 { | |
1194 throw new FileException(pathname, getErrno()); | |
1195 } | |
1196 } | |
1197 | |
1198 /**************************************************** | |
1199 * Get current directory. | |
1200 */ | |
1201 | |
1202 char[] getcwd() | |
1203 { | |
1204 version(all) | |
1205 { | |
1206 const PATH_MAX=4096; | |
1207 char buf[PATH_MAX]; | |
1208 if (! sys.getcwd(buf.ptr, buf.length)) | |
1209 { | |
1210 throw new FileException("cannot get cwd", getErrno()); | |
1211 } | |
1212 size_t len = strlen(buf.ptr); | |
1213 char[] result = new char[len]; | |
1214 result[] = buf[0..len]; | |
1215 return result; | |
1216 } | |
1217 else | |
1218 { | |
1219 auto p = sys.getcwd(null, 0); | |
1220 if (!p) | |
1221 { | |
1222 throw new FileException("cannot get cwd", getErrno()); | |
1223 } | |
1224 auto len = std.string.strlen(p); | |
1225 auto buf = new char[len]; | |
1226 buf[] = p[0 .. len]; | |
1227 std.c.stdlib.free(p); | |
1228 return buf; | |
1229 } | |
1230 | |
1231 } | |
1232 | |
1233 /*************************************************** | |
1234 * Directory Entry | |
1235 */ | |
1236 | |
1237 struct DirEntry | |
1238 { | |
1239 char[] name; /// file or directory name | |
1240 ulong _size = ~0UL; // size of file in bytes | |
1241 d_time _creationTime = d_time_nan; // time of file creation | |
1242 d_time _lastAccessTime = d_time_nan; // time file was last accessed | |
1243 d_time _lastWriteTime = d_time_nan; // time file was last written to | |
1244 version (GNU) | |
1245 typeof(struct_stat.st_mode) _st_mode; | |
1246 else | |
1247 ubyte d_type; | |
1248 ubyte didstat; // done lazy evaluation of stat() | |
1249 | |
1250 void init(char[] path, dirent *fd) | |
1251 { size_t len = std.string.strlen(fd.d_name.ptr); | |
1252 name = std.path.join(path, fd.d_name[0 .. len]); | |
1253 version(GNU) | |
1254 { } | |
1255 else | |
1256 d_type = fd.d_type; | |
1257 didstat = 0; | |
1258 } | |
1259 | |
1260 int isdir() | |
1261 { | |
1262 version(GNU) | |
1263 { | |
1264 if (!didstat) | |
1265 doStat(); | |
1266 return (_st_mode & S_IFMT) == S_IFDIR; | |
1267 } | |
1268 else | |
1269 return d_type & DT_DIR; | |
1270 } | |
1271 | |
1272 int isfile() | |
1273 { | |
1274 version(GNU) | |
1275 { | |
1276 if (!didstat) | |
1277 doStat(); | |
1278 return (_st_mode & S_IFMT) == S_IFREG; | |
1279 } | |
1280 else | |
1281 return d_type & DT_REG; | |
1282 } | |
1283 | |
1284 ulong size() | |
1285 { | |
1286 if (!didstat) | |
1287 doStat(); | |
1288 return _size; | |
1289 } | |
1290 | |
1291 d_time creationTime() | |
1292 { | |
1293 if (!didstat) | |
1294 doStat(); | |
1295 return _creationTime; | |
1296 } | |
1297 | |
1298 d_time lastAccessTime() | |
1299 { | |
1300 if (!didstat) | |
1301 doStat(); | |
1302 return _lastAccessTime; | |
1303 } | |
1304 | |
1305 d_time lastWriteTime() | |
1306 { | |
1307 if (!didstat) | |
1308 doStat(); | |
1309 return _lastWriteTime; | |
1310 } | |
1311 | |
1312 /* This is to support lazy evaluation, because doing stat's is | |
1313 * expensive and not always needed. | |
1314 */ | |
1315 | |
1316 void doStat() | |
1317 { | |
1318 int fd; | |
1319 struct_stat statbuf; | |
1320 char* namez; | |
1321 | |
1322 namez = toStringz(name); | |
1323 if (sys.stat(namez, &statbuf)) | |
1324 { | |
1325 //printf("\tstat error, errno = %d\n",getErrno()); | |
1326 return; | |
1327 } | |
1328 _size = statbuf.st_size; | |
1329 _creationTime = cast(d_time)statbuf.st_ctime * std.date.TicksPerSecond; | |
1330 _lastAccessTime = cast(d_time)statbuf.st_atime * std.date.TicksPerSecond; | |
1331 _lastWriteTime = cast(d_time)statbuf.st_mtime * std.date.TicksPerSecond; | |
1332 version(GNU) _st_mode = statbuf.st_mode; | |
1333 didstat = 1; | |
1334 } | |
1335 } | |
1336 | |
1337 | |
1338 /*************************************************** | |
1339 * Return contents of directory. | |
1340 */ | |
1341 | |
1342 char[][] listdir(char[] pathname) | |
1343 { | |
1344 char[][] result; | |
1345 | |
1346 bool listing(char[] filename) | |
1347 { | |
1348 result ~= filename; | |
1349 return true; // continue | |
1350 } | |
1351 | |
1352 listdir(pathname, &listing); | |
1353 return result; | |
1354 } | |
1355 | |
1356 char[][] listdir(char[] pathname, char[] pattern) | |
1357 { char[][] result; | |
1358 | |
1359 bool callback(DirEntry* de) | |
1360 { | |
1361 if (de.isdir) | |
1362 listdir(de.name, &callback); | |
1363 else | |
1364 { if (std.path.fnmatch(de.name, pattern)) | |
1365 result ~= de.name; | |
1366 } | |
1367 return true; // continue | |
1368 } | |
1369 | |
1370 listdir(pathname, &callback); | |
1371 return result; | |
1372 } | |
1373 | |
1374 char[][] listdir(char[] pathname, RegExp r) | |
1375 { char[][] result; | |
1376 | |
1377 bool callback(DirEntry* de) | |
1378 { | |
1379 if (de.isdir) | |
1380 listdir(de.name, &callback); | |
1381 else | |
1382 { if (r.test(de.name)) | |
1383 result ~= de.name; | |
1384 } | |
1385 return true; // continue | |
1386 } | |
1387 | |
1388 listdir(pathname, &callback); | |
1389 return result; | |
1390 } | |
1391 | |
1392 void listdir(char[] pathname, bool delegate(char[] filename) callback) | |
1393 { | |
1394 bool listing(DirEntry* de) | |
1395 { | |
1396 return callback(std.path.getBaseName(de.name)); | |
1397 } | |
1398 | |
1399 listdir(pathname, &listing); | |
1400 } | |
1401 | |
1402 void listdir(char[] pathname, bool delegate(DirEntry* de) callback) | |
1403 { | |
1404 DIR* h; | |
1405 dirent* fdata; | |
1406 DirEntry de; | |
1407 | |
1408 h = opendir(toStringz(pathname)); | |
1409 if (h) | |
1410 { | |
1411 try | |
1412 { | |
1413 while((fdata = readdir(h)) != null) | |
1414 { | |
1415 // Skip "." and ".." | |
1416 if (!std.string.strcmp(fdata.d_name.ptr, ".") || | |
1417 !std.string.strcmp(fdata.d_name.ptr, "..")) | |
1418 continue; | |
1419 | |
1420 de.init(pathname, fdata); | |
1421 if (!callback(&de)) | |
1422 break; | |
1423 } | |
1424 } | |
1425 finally | |
1426 { | |
1427 closedir(h); | |
1428 } | |
1429 } | |
1430 else | |
1431 { | |
1432 throw new FileException(pathname, getErrno()); | |
1433 } | |
1434 } | |
1435 | |
1436 | |
1437 /*************************************************** | |
1438 * Copy a file. File timestamps are preserved. | |
1439 */ | |
1440 | |
1441 void copy(char[] from, char[] to) | |
1442 { | |
1443 version (all) | |
1444 { | |
1445 struct_stat statbuf; | |
1446 | |
1447 char* fromz = toStringz(from); | |
1448 char* toz = toStringz(to); | |
1449 //printf("file.copy(from='%s', to='%s')\n", fromz, toz); | |
1450 | |
1451 int fd = sys.open(fromz, O_RDONLY); | |
1452 if (fd == -1) | |
1453 { | |
1454 //printf("\topen error, errno = %d\n",getErrno()); | |
1455 goto err1; | |
1456 } | |
1457 | |
1458 //printf("\tfile opened\n"); | |
1459 if (sys.fstat(fd, &statbuf)) | |
1460 { | |
1461 //printf("\tfstat error, errno = %d\n",getErrno()); | |
1462 goto err2; | |
1463 } | |
1464 | |
1465 int fdw = sys.open(toz, O_CREAT | O_WRONLY | O_TRUNC, 0660); | |
1466 if (fdw == -1) | |
1467 { | |
1468 //printf("\topen error, errno = %d\n",getErrno()); | |
1469 goto err2; | |
1470 } | |
1471 | |
1472 size_t BUFSIZ = 4096 * 16; | |
1473 void* buf = std.c.stdlib.malloc(BUFSIZ); | |
1474 if (!buf) | |
1475 { BUFSIZ = 4096; | |
1476 buf = std.c.stdlib.malloc(BUFSIZ); | |
1477 } | |
1478 if (!buf) | |
1479 { | |
1480 //printf("\topen error, errno = %d\n",getErrno()); | |
1481 goto err4; | |
1482 } | |
1483 | |
1484 for (auto size = statbuf.st_size; size; ) | |
1485 { size_t toread = (size > BUFSIZ) ? BUFSIZ : size; | |
1486 | |
1487 auto n = sys.read(fd, buf, toread); | |
1488 if (n != toread) | |
1489 { | |
1490 //printf("\tread error, errno = %d\n",getErrno()); | |
1491 goto err5; | |
1492 } | |
1493 n = sys.write(fdw, buf, toread); | |
1494 if (n != toread) | |
1495 { | |
1496 //printf("\twrite error, errno = %d\n",getErrno()); | |
1497 goto err5; | |
1498 } | |
1499 size -= toread; | |
1500 } | |
1501 | |
1502 std.c.stdlib.free(buf); | |
1503 | |
1504 if (sys.close(fdw) == -1) | |
1505 { | |
1506 //printf("\tclose error, errno = %d\n",getErrno()); | |
1507 goto err2; | |
1508 } | |
1509 | |
1510 utimbuf utim; | |
1511 utim.actime = cast(typeof(utim.actime))statbuf.st_atime; | |
1512 utim.modtime = cast(typeof(utim.modtime))statbuf.st_mtime; | |
1513 if (utime(toz, &utim) == -1) | |
1514 { | |
1515 //printf("\tutime error, errno = %d\n",getErrno()); | |
1516 goto err3; | |
1517 } | |
1518 | |
1519 if (sys.close(fd) == -1) | |
1520 { | |
1521 //printf("\tclose error, errno = %d\n",getErrno()); | |
1522 goto err1; | |
1523 } | |
1524 | |
1525 return; | |
1526 | |
1527 err5: | |
1528 std.c.stdlib.free(buf); | |
1529 err4: | |
1530 sys.close(fdw); | |
1531 err3: | |
1532 std.c.stdio.remove(toz); | |
1533 err2: | |
1534 sys.close(fd); | |
1535 err1: | |
1536 throw new FileException(from, getErrno()); | |
1537 } | |
1538 else | |
1539 { | |
1540 void[] buffer; | |
1541 | |
1542 buffer = read(from); | |
1543 write(to, buffer); | |
1544 delete buffer; | |
1545 } | |
1546 } | |
1547 | |
1548 | |
1549 | |
1550 } | |
1551 | |
1552 unittest | |
1553 { | |
1554 //printf("std.file.unittest\n"); | |
1555 void[] buf; | |
1556 | |
1557 buf = new void[10]; | |
1558 (cast(byte[])buf)[] = 3; | |
1559 write("unittest_write.tmp", buf); | |
1560 void buf2[] = read("unittest_write.tmp"); | |
1561 assert(buf == buf2); | |
1562 | |
1563 copy("unittest_write.tmp", "unittest_write2.tmp"); | |
1564 buf2 = read("unittest_write2.tmp"); | |
1565 assert(buf == buf2); | |
1566 | |
1567 remove("unittest_write.tmp"); | |
1568 if (exists("unittest_write.tmp")) | |
1569 assert(0); | |
1570 remove("unittest_write2.tmp"); | |
1571 if (exists("unittest_write2.tmp")) | |
1572 assert(0); | |
1573 } | |
1574 | |
1575 unittest | |
1576 { | |
1577 listdir (".", delegate bool (DirEntry * de) | |
1578 { | |
1579 auto s = std.string.format("%s : c %s, w %s, a %s", de.name, | |
1580 toUTCString (de.creationTime), | |
1581 toUTCString (de.lastWriteTime), | |
1582 toUTCString (de.lastAccessTime)); | |
1583 return true; | |
1584 } | |
1585 ); | |
1586 } | |
1587 | |
1588 |