root/trunk/bevutils/file.d

Revision 20, 33.7 kB (checked in by teales, 5 years ago)

Bevutils files initial check-in.

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