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