Changeset 683

Show
Ignore:
Timestamp:
05/02/08 15:08:11 (2 months ago)
Author:
andrei
Message:

* Made atoi work with all string types, but also scheduled it for deprecation in favor of to!(int) and parse!(int).

* Made atof work with all string types, but also scheduled it for deprecation in favor of to!(double) and parse!(double) (or real).

* Made cmp and icmp work with strings of all widths

* Changed signature of toStringz to return const(char)*

* Fixed signature of join so it works with immutable arrays

* Added tolowerInPlace, toupperInPlace (these may be changed or removed).

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/phobos/std/file.d

    r589 r683  
    4646private import std.c.string; 
    4747private import std.traits; 
    48 import std.conv; 
    49 private import std.stdio; // for testing only 
     48private import std.conv; 
     49private import std.contracts; 
     50private import std.utf; 
     51version (unittest) { 
     52    private import std.stdio; // for testing only 
     53
    5054 
    5155/* =========================== Win32 ======================= */ 
     
    6064private import std.date; 
    6165 
    62 int useWfuncs = 1
     66enum useWfuncs = true
    6367 
    6468static this() 
     
    7478class FileException : Exception 
    7579{ 
    76  
    7780    uint errno;         // operating system error code 
    7881 
     
    99102 
    100103/******************************************** 
    101  * Read file name[], return array of bytes read. 
    102  * Throws: 
    103  * FileException on error. 
     104 * Read file $(D name), return array of bytes read. 
     105 * 
     106 * Throws: $(D FileException) on error. 
    104107 */ 
    105108 
     
    154157/********************************************* 
    155158 * Write buffer[] to file name[]. 
    156  * Throws: FileException on error. 
     159 * Throws: $(D FileException) on error. 
    157160 */ 
    158161 
     
    196199/********************************************* 
    197200 * Append buffer[] to file name[]. 
    198  * Throws: FileException on error. 
     201 * Throws: $(D FileException) on error. 
    199202 */ 
    200203 
     
    240243/*************************************************** 
    241244 * Rename file from[] to to[]. 
    242  * Throws: FileException on error. 
     245 * Throws: $(D FileException) on error. 
    243246 */ 
    244247 
    245248void rename(in string from, in string to) 
    246249{ 
    247     BOOL result
     250    BOOL result = void
    248251 
    249252    if (useWfuncs) 
     
    258261/*************************************************** 
    259262 * Delete file name[]. 
    260  * Throws: FileException on error. 
     263 * Throws: $(D FileException) on error. 
    261264 */ 
    262265 
    263266void remove(in string name) 
    264267{ 
    265     BOOL result
     268    BOOL result = void
    266269 
    267270    if (useWfuncs) 
     
    276279/*************************************************** 
    277280 * Get size of file name[]. 
    278  * Throws: FileException on error. 
     281 * Throws: $(D FileException) on error. 
    279282 */ 
    280283 
     
    311314 
    312315/************************* 
    313  * Get creation/access/modified times of file name[]
    314  * Throws: FileException on error. 
     316 * Get creation/access/modified times of file $(D name)
     317 * Throws: $(D FileException) on error. 
    315318 */ 
    316319 
     
    351354 */ 
    352355 
    353 int exists(string name) 
     356bool exists(in string name) 
    354357{ 
    355358    uint result; 
     
    361364    result = GetFileAttributesA(toMBSz(name)); 
    362365 
    363     return (result == 0xFFFFFFFF) ? 0 : 1
     366    return result == 0xFFFFFFFF
    364367} 
    365368 
    366369/*************************************************** 
    367370 * Get file name[] attributes. 
    368  * Throws: FileException on error. 
     371 * Throws: $(D FileException) on error. 
    369372 */ 
    370373 
     
    386389/**************************************************** 
    387390 * Is name[] a file? 
    388  * Throws: FileException if name[] doesn't exist. 
    389  */ 
    390  
    391 int isfile(in string name) 
     391 * Throws: $(D FileException) if name[] doesn't exist. 
     392 */ 
     393 
     394bool isfile(in string name) 
    392395{ 
    393396    return (getAttributes(name) & FILE_ATTRIBUTE_DIRECTORY) == 0; 
     
    396399/**************************************************** 
    397400 * Is name[] a directory? 
    398  * Throws: FileException if name[] doesn't exist. 
    399  */ 
    400  
    401 int isdir(in string name) 
     401 * Throws: $(D FileException) if name[] doesn't exist. 
     402 */ 
     403 
     404bool isdir(in string name) 
    402405{ 
    403406    return (getAttributes(name) & FILE_ATTRIBUTE_DIRECTORY) != 0; 
     
    406409/**************************************************** 
    407410 * Change directory to pathname[]. 
    408  * Throws: FileException on error. 
     411 * Throws: $(D FileException) on error. 
    409412 */ 
    410413 
     
    425428/**************************************************** 
    426429 * Make directory pathname[]. 
    427  * Throws: FileException on error. 
     430 * Throws: $(D FileException) on error. 
    428431 */ 
    429432 
    430433void mkdir(in string pathname) 
    431 {   BOOL result
     434{   BOOL result = void
    432435 
    433436    if (useWfuncs) 
     
    444447/**************************************************** 
    445448 * Remove directory pathname[]. 
    446  * Throws: FileException on error. 
     449 * Throws: $(D FileException) on error. 
    447450 */ 
    448451 
    449452void rmdir(in string pathname) 
    450 {   BOOL result
     453{   BOOL result = void
    451454 
    452455    if (useWfuncs) 
     
    463466/**************************************************** 
    464467 * Get current directory. 
    465  * Throws: FileException on error. 
     468 * Throws: $(D FileException) on error. 
    466469 */ 
    467470 
     
    569572 * Return contents of directory pathname[]. 
    570573 * The names in the contents do not include the pathname. 
    571  * Throws: FileException on error 
     574 * Throws: $(D FileException) on error 
    572575 * Example: 
    573576 *  This program lists all the files and subdirectories in its 
     
    850853void copy(in string from, in string to) 
    851854{ 
    852     BOOL result; 
    853  
    854     if (useWfuncs) 
    855     result = CopyFileW(std.utf.toUTF16z(from), std.utf.toUTF16z(to), false); 
    856     else 
    857     result = CopyFileA(toMBSz(from), toMBSz(to), false); 
     855    invariant result = useWfuncs 
     856    ? CopyFileW(std.utf.toUTF16z(from), std.utf.toUTF16z(to), false) 
     857        : CopyFileA(toMBSz(from), toMBSz(to), false); 
    858858    if (!result) 
    859          throw new FileException(to, GetLastError()); 
     859         throw new FileException(to, GetLastError); 
    860860} 
    861861 
     
    876876class FileException : Exception 
    877877{ 
    878  
    879878    uint errno;         // operating system error code 
    880879 
     
    890889 
    891890    this(string name, uint errno) 
    892     {   char[80] buf = void; 
     891    { 
     892        char[1024] buf = void; 
    893893    auto s = strerror_r(errno, buf.ptr, buf.length); 
    894     this(name, std.string.toString(s).idup); 
     894    this(name, std.string.toString(s)); 
    895895    this.errno = errno; 
    896896    } 
    897897} 
     898 
     899private T cenforce(T)(T condition, lazy string name) 
     900{ 
     901    if (!condition) throw new FileException(name, getErrno); 
     902    return condition; 
     903} 
     904 
    898905 
    899906/******************************************** 
     
    903910 */ 
    904911 
    905 void[] read(in string name) 
    906 
    907     uint numread; 
    908     struct_stat statbuf; 
    909  
    910     auto namez = toStringz(name); 
    911     //printf("file.read('%s')\n",namez); 
    912     auto fd = std.c.linux.linux.open(namez, O_RDONLY); 
    913     if (fd == -1) 
    914     { 
    915         //printf("\topen error, errno = %d\n",getErrno()); 
    916         goto err1; 
    917     } 
    918  
    919     //printf("\tfile opened\n"); 
    920     if (std.c.linux.linux.fstat(fd, &statbuf)) 
    921     { 
    922         //printf("\tfstat error, errno = %d\n",getErrno()); 
    923         goto err2; 
    924     } 
    925     auto size = statbuf.st_size; 
     912void[] read(string name) 
     913
     914    invariant fd = std.c.linux.linux.open(toStringz(name), O_RDONLY); 
     915    cenforce(fd != -1, name); 
     916    scope(exit) std.c.linux.linux.close(fd); 
     917 
     918    struct_stat statbuf = void; 
     919    cenforce(std.c.linux.linux.fstat(fd, &statbuf) == 0, name); 
     920    invariant size = statbuf.st_size; 
     921    if (!size) return null; 
    926922    auto buf = std.gc.malloc(size); 
    927     if (buf.ptr) 
    928     std.gc.hasNoPointers(buf.ptr); 
    929  
    930     numread = std.c.linux.linux.read(fd, buf.ptr, size); 
    931     if (numread != size) 
    932     { 
    933         //printf("\tread error, errno = %d\n",getErrno()); 
    934         goto err2; 
    935     } 
    936  
    937     if (std.c.linux.linux.close(fd) == -1) 
    938     { 
    939     //printf("\tclose error, errno = %d\n",getErrno()); 
    940         goto err; 
    941     } 
     923    enforce(buf, "Out of memory"); 
     924    scope(failure) delete buf; 
     925    std.gc.hasNoPointers(buf.ptr); 
     926 
     927    cenforce(std.c.linux.linux.read(fd, buf.ptr, size) == size, name); 
    942928 
    943929    return buf[0 .. size]; 
    944  
    945 err2: 
    946     std.c.linux.linux.close(fd); 
    947 err: 
    948     delete buf; 
    949  
    950 err1: 
    951     throw new FileException(name.idup, getErrno()); 
    952 
     930
     931 
     932/******************************************** 
     933 * Read and validates (using $(XREF utf, validate)) a text file. $(D 
     934 * S) can be a type of array of characters of any width and constancy. 
     935 * 
     936 * Returns: array of characters read 
     937 * 
     938 * Throws: $(D FileException) on file error, $(D UtfException) on UTF 
     939 * decoding error. 
     940 *       
     941 */ 
     942 
     943S readText(S)(in string name) 
     944
     945    auto result = cast(S) read(name); 
     946    std.utf.validate(result); 
     947    return result; 
     948
     949 
     950// Implementation helper for write and append 
     951 
     952private void writeImpl(in string name, in void[] buffer, in uint mode) 
     953
     954    invariant fd = std.c.linux.linux.open(toStringz(name), 
     955            mode, 0660); 
     956    cenforce(fd != -1, name); 
     957    { 
     958        scope(failure) std.c.linux.linux.close(fd); 
     959        invariant size = buffer.length; 
     960        cenforce(std.c.linux.linux.write(fd, buffer.ptr, size) == size, name); 
     961    } 
     962    cenforce(std.c.linux.linux.close(fd) == 0, name); 
     963
     964 
    953965 
    954966/********************************************* 
    955967 * Write a file. 
    956  * Returns: 
    957  *  0   success 
    958968 */ 
    959969 
    960970void write(in string name, in void[] buffer) 
    961971{ 
    962     int fd; 
    963     int numwritten; 
    964  
    965     auto namez = toStringz(name); 
    966     fd = std.c.linux.linux.open(namez, O_CREAT | O_WRONLY | O_TRUNC, 0660); 
    967     if (fd == -1) 
    968         goto err; 
    969  
    970     numwritten = std.c.linux.linux.write(fd, buffer.ptr, buffer.length); 
    971     if (buffer.length != numwritten) 
    972         goto err2; 
    973  
    974     if (std.c.linux.linux.close(fd) == -1) 
    975         goto err; 
    976  
    977     return; 
    978  
    979 err2: 
    980     std.c.linux.linux.close(fd); 
    981 err: 
    982     throw new FileException(name.idup, getErrno()); 
    983 
    984  
     972    return writeImpl(name, buffer, O_CREAT | O_WRONLY | O_TRUNC); 
     973
    985974 
    986975/********************************************* 
     
    990979void append(in string name, in void[] buffer) 
    991980{ 
    992     int fd; 
    993     int numwritten; 
    994     char *namez; 
    995  
    996     namez = toStringz(name); 
    997     fd = std.c.linux.linux.open(namez, O_APPEND | O_WRONLY | O_CREAT, 0660); 
    998     if (fd == -1) 
    999         goto err; 
    1000  
    1001     numwritten = std.c.linux.linux.write(fd, buffer.ptr, buffer.length); 
    1002     if (buffer.length != numwritten) 
    1003         goto err2; 
    1004  
    1005     if (std.c.linux.linux.close(fd) == -1) 
    1006         goto err; 
    1007  
    1008     return; 
    1009  
    1010 err2: 
    1011     std.c.linux.linux.close(fd); 
    1012 err: 
    1013     throw new FileException(name.idup, getErrno()); 
    1014 
    1015  
     981    return writeImpl(name, buffer, O_APPEND | O_WRONLY | O_CREAT); 
     982
    1016983 
    1017984/*************************************************** 
     
    1021988void rename(in string from, in string to) 
    1022989{ 
    1023     char *fromz = toStringz(from); 
    1024     char *toz = toStringz(to); 
    1025  
    1026     if (std.c.stdio.rename(fromz, toz) == -1) 
    1027     throw new FileException(to.idup, getErrno()); 
    1028 
    1029  
     990    cenforce(std.c.stdio.rename(toStringz(from), toStringz(to)) == -1, to); 
     991
    1030992 
    1031993/*************************************************** 
     
    1035997void remove(in string name) 
    1036998{ 
    1037     if (std.c.stdio.remove(toStringz(name)) == -1) 
    1038     throw new FileException(name.idup, getErrno()); 
     999    cenforce(std.c.stdio.remove(toStringz(name)) != -1, name); 
    10391000} 
    10401001 
     
    10461007ulong getSize(in string name) 
    10471008{ 
    1048     struct_stat statbuf; 
    1049     if (std.c.linux.linux.stat(toStringz(name), &statbuf)) 
    1050     { 
    1051         throw new FileException(name, getErrno()); 
    1052     } 
     1009    struct_stat statbuf = void; 
     1010    cenforce(std.c.linux.linux.stat(toStringz(name), &statbuf) == 0, name); 
    10531011    return statbuf.st_size; 
    10541012} 
     
    10711029uint getAttributes(in string name) 
    10721030{ 
    1073     struct_stat statbuf; 
    1074  
    1075     auto namez = toStringz(name); 
    1076     if (std.c.linux.linux.stat(namez, &statbuf)) 
    1077     { 
    1078     throw new FileException(name.idup, getErrno()); 
    1079     } 
    1080  
     1031    struct_stat statbuf = void; 
     1032    cenforce(std.c.linux.linux.stat(toStringz(name), &statbuf) == 0, name); 
    10811033    return statbuf.st_mode; 
    10821034} 
    10831035 
    10841036/************************* 
    1085  * Get creation/access/modified times of file name[]
    1086  * Throws: FileException on error. 
     1037 * Get creation/access/modified times of file $(D name)
     1038 * Throws: $(D FileException) on error. 
    10871039 */ 
    10881040 
    10891041void getTimes(in string name, out d_time ftc, out d_time fta, out d_time ftm) 
    10901042{ 
    1091     struct_stat statbuf; 
    1092     char *namez; 
    1093  
    1094     namez = toStringz(name); 
    1095     if (std.c.linux.linux.stat(namez, &statbuf)) 
    1096     { 
    1097     throw new FileException(name.idup, getErrno()); 
    1098     } 
    1099  
    1100     ftc = cast(d_time)statbuf.st_ctime * std.date.TicksPerSecond; 
    1101     fta = cast(d_time)statbuf.st_atime * std.date.TicksPerSecond; 
    1102     ftm = cast(d_time)statbuf.st_mtime * std.date.TicksPerSecond; 
    1103 
    1104  
     1043    struct_stat statbuf = void; 
     1044    cenforce(std.c.linux.linux.stat(toStringz(name), &statbuf) == 0, name); 
     1045    ftc = cast(d_time) statbuf.st_ctime * std.date.TicksPerSecond; 
     1046    fta = cast(d_time) statbuf.st_atime * std.date.TicksPerSecond; 
     1047    ftm = cast(d_time) statbuf.st_mtime * std.date.TicksPerSecond; 
     1048
     1049 
     1050/************************* 
     1051 * Set access/modified times of file $(D name). 
     1052 * Throws: $(D FileException) on error. 
     1053 */ 
     1054 
     1055void setTimes(in string name, d_time fta, d_time ftm) 
     1056
     1057    version (linux) 
     1058    { 
     1059        // utimbuf times = { 
     1060        //     cast(__time_t) (fta / std.date.TicksPerSecond), 
     1061        //     cast(__time_t) (ftm / std.date.TicksPerSecond) }; 
     1062        // enforce(utime(toStringz(name), &times) == 0); 
     1063        timeval[2] t = void; 
     1064        t[0].tv_sec = fta / std.date.TicksPerSecond; 
     1065        t[0].tv_usec = cast(long) ((cast(double) fta / std.date.TicksPerSecond) 
     1066                * 1_000_000) % 1_000_000; 
     1067        t[1].tv_sec = ftm / std.date.TicksPerSecond; 
     1068        t[1].tv_usec = cast(long) ((cast(double) ftm / std.date.TicksPerSecond) 
     1069                * 1_000_000) % 1_000_000; 
     1070        enforce(utimes(toStringz(name), t.ptr) == 0); 
     1071    } 
     1072    else 
     1073    { 
     1074        if (true) enforce(false, "Not implemented"); 
     1075    } 
     1076
     1077 
     1078unittest 
     1079
     1080    system("touch deleteme") == 0 || assert(false); 
     1081    scope(exit) remove("deleteme"); 
     1082    d_time ftc1, fta1, ftm1; 
     1083    getTimes("deleteme", ftc1, fta1, ftm1); 
     1084    setTimes("deleteme", fta1 + 1000, ftm1 + 1000); 
     1085    d_time ftc2, fta2, ftm2; 
     1086    getTimes("deleteme", ftc2, fta2, ftm2); 
     1087    assert(fta1 + 1000 == fta2); 
     1088    assert(ftm1 + 1000 == ftm2); 
     1089
     1090 
     1091/** 
     1092   Returns the time of the last modification of file $(D name). If the 
     1093   file does not exist, throws a $(D FileException). 
     1094*/ 
     1095 
     1096d_time lastModified(in string name) 
     1097
     1098    struct_stat statbuf = void; 
     1099    cenforce(std.c.linux.linux.stat(toStringz(name), &statbuf) == 0, name); 
     1100    return cast(d_time) statbuf.st_mtime * std.date.TicksPerSecond; 
     1101
     1102 
     1103/** 
     1104Returns the time of the last modification of file $(D name). If the 
     1105file does not exist, returns $(D returnIfMissing). 
     1106 
     1107A frequent usage pattern occurs in build automation tools such as 
     1108$(WEB www.gnu.org/software/make, make) or $(WEB 
     1109en.wikipedia.org/wiki/Apache_Ant, ant). To check whether file $(D 
     1110target) must be rebuilt from file $(D source) (i.e., $(D target) is 
     1111older than $(D source) or does not exist), use the comparison below. 
     1112 
     1113---------------------------- 
     1114if (lastModified(source) >= lastModified(target, d_time.min)) 
     1115
     1116    ... must (re)build ... 
     1117
     1118else 
     1119
     1120    ... target's up-to-date ... 
     1121
     1122---------------------------- 
     1123 
     1124The code above throws a $(D FileException) if $(D source) does not 
     1125exist (as it should). On the other hand, the $(D d_time.min) default 
     1126makes a non-existing $(D target) seem infinitely old so the test 
     1127correctly prompts building it. 
     1128 
     1129*/ 
     1130 
     1131d_time lastModified(string name, d_time returnIfMissing) 
     1132
     1133    struct_stat statbuf = void; 
     1134    return std.c.linux.linux.stat(toStringz(name), &statbuf) != 0 
     1135        ? returnIfMissing 
     1136        : cast(d_time) statbuf.st_mtime * std.date.TicksPerSecond; 
     1137
     1138 
     1139unittest 
     1140
     1141    system("touch deleteme") == 0 || assert(false); 
     1142    scope(exit) remove("deleteme"); 
     1143    assert(lastModified("deleteme") >  
     1144        lastModified("this file does not exist", d_time.min)); 
     1145    assert(lastModified("deleteme") > lastModified(__FILE__)); 
     1146
    11051147 
    11061148/**************************************************** 
     
    11081150 */ 
    11091151 
    1110 int exists(in string name) 
    1111 
    1112     return access(toStringz(name),0) == 0; 
    1113  
    1114 /+ 
    1115     struct_stat statbuf; 
    1116     char *namez; 
    1117  
    1118     namez = toStringz(name); 
    1119     if (std.c.linux.linux.stat(namez, &statbuf)) 
    1120     { 
    1121     return 0; 
    1122     } 
    1123     return 1; 
    1124 +/ 
     1152bool exists(in string name) 
     1153
     1154    return access(toStringz(name), 0) == 0; 
    11251155} 
    11261156 
     
    11281158{ 
    11291159    assert(exists(".")); 
     1160    assert(!exists("this file does not exist")); 
     1161    system("touch deleteme") == 0 || assert(false); 
     1162    scope(exit) remove("deleteme"); 
     1163    assert(exists("deleteme")); 
    11301164} 
    11311165 
     
    11341168 */ 
    11351169 
    1136 int isfile(in string name) 
     1170bool isfile(in string name) 
    11371171{ 
    11381172    return (getAttributes(name) & S_IFMT) == S_IFREG;   // regular file 
     
    11431177 */ 
    11441178 
    1145 int isdir(string name) 
     1179bool isdir(in string name) 
    11461180{ 
    11471181    return (getAttributes(name) & S_IFMT) == S_IFDIR; 
     
    11541188void chdir(string pathname) 
    11551189{ 
    1156     if (std.c.linux.linux.chdir(toStringz(pathname))) 
    1157     { 
    1158     throw new FileException(pathname, getErrno()); 
    1159     } 
     1190    cenforce(std.c.linux.linux.chdir(toStringz(pathname)) == 0, pathname); 
    11601191} 
    11611192 
     
    11661197void mkdir(string pathname) 
    11671198{ 
    1168     if (std.c.linux.linux.mkdir(toStringz(pathname), 0777)) 
    1169     { 
    1170     throw new FileException(pathname, getErrno()); 
    1171     } 
     1199    cenforce(std.c.linux.linux.mkdir(toStringz(pathname), 0777) == 0, pathname); 
    11721200} 
    11731201 
     
    11781206void rmdir(string pathname) 
    11791207{ 
    1180     if (std.c.linux.linux.rmdir(toStringz(pathname))) 
    1181     { 
    1182     throw new FileException(pathname, getErrno()); 
    1183     } 
     1208    cenforce(std.c.linux.linux.rmdir(toStringz(pathname)) == 0, pathname); 
    11841209} 
    11851210 
     
    11901215string getcwd() 
    11911216{ 
    1192     auto p = std.c.linux.linux.getcwd(null, 0); 
    1193     if (!p) 
    1194     { 
    1195     throw new FileException("cannot get cwd", getErrno()); 
    1196     } 
     1217    auto p = cenforce(std.c.linux.linux.getcwd(null, 0), 
     1218            "cannot get cwd"); 
    11971219    scope(exit) std.c.stdlib.free(p); 
    1198     auto len = std.string.strlen(p); 
    1199     return p[0 .. len].idup; 
     1220    return p[0 .. std.string.strlen(p)].idup; 
    12001221} 
    12011222 
     
    12121233    d_time _lastWriteTime = d_time_nan; // time file was last written to 
    12131234    ubyte d_type; 
    1214     ubyte didstat;          // done lazy evaluation of stat() 
     1235    struct_stat statbuf; 
     1236    bool didstat;           // done lazy evaluation of stat() 
    12151237 
    12161238    void init(string path, dirent *fd) 
    1217     {   size_t len = std.string.strlen(fd.d_name.ptr); 
     1239    { 
     1240        invariant len = std.string.strlen(fd.d_name.ptr); 
    12181241    name = std.path.join(path, fd.d_name[0 .. len].idup); 
    12191242    d_type = fd.d_type; 
    1220     didstat = 0
    1221     } 
    1222  
    1223     int isdir() 
    1224     { 
    1225     return d_type & DT_DIR
    1226     } 
    1227  
    1228     int isfile() 
    1229     { 
    1230     return d_type & DT_REG
     1243    didstat = false
     1244    } 
     1245 
     1246    bool isdir() 
     1247    { 
     1248    return (d_type & DT_DIR) != 0
     1249    } 
     1250 
     1251    bool isfile() 
     1252    { 
     1253    return (d_type & DT_REG) != 0
    12311254    } 
    12321255 
    12331256    ulong size() 
    12341257    { 
    1235     if (!didstat) 
    1236         doStat(); 
     1258    ensureStatDone; 
    12371259    return _size; 
    12381260    } 
     
    12401262    d_time creationTime() 
    12411263    { 
    1242     if (!didstat) 
    1243         doStat(); 
     1264    ensureStatDone; 
    12441265    return _creationTime; 
    12451266    } 
     
    12471268    d_time lastAccessTime() 
    12481269    { 
    1249     if (!didstat) 
    1250         doStat(); 
     1270    ensureStatDone; 
    12511271    return _lastAccessTime; 
    12521272    } 
     
    12541274    d_time lastWriteTime() 
    12551275    { 
    1256     if (!didstat) 
    1257         doStat(); 
     1276    ensureStatDone; 
    12581277    return _lastWriteTime; 
    12591278    } 
     
    12631282     */ 
    12641283 
    1265     void doStat() 
    1266     { 
    1267     int fd; 
    1268     struct_stat statbuf; 
    1269  
    1270     auto namez = toStringz(name); 
    1271     if (std.c.linux.linux.stat(namez, &statbuf)) 
    1272     { 
    1273         //printf("\tstat error, errno = %d\n",getErrno()); 
    1274         return; 
    1275     } 
     1284    void ensureStatDone() 
     1285    { 
     1286        if (didstat) return; 
     1287    enforce(std.c.linux.linux.stat(toStringz(name), &statbuf) == 0, 
     1288                "Failed to stat file `"~name~"'"); 
    12761289    _size = statbuf.st_size; 
    12771290    _creationTime = cast(d_time)statbuf.st_ctime * std.date.TicksPerSecond; 
    12781291    _lastAccessTime = cast(d_time)statbuf.st_atime * std.date.TicksPerSecond; 
    12791292    _lastWriteTime = cast(d_time)statbuf.st_mtime * std.date.TicksPerSecond; 
    1280  
    1281     didstat = 1; 
     1293    didstat = true; 
    12821294    } 
    12831295} 
     
    13501362void listdir(string pathname, bool delegate(DirEntry* de) callback) 
    13511363{ 
    1352     DIR* h
    1353     dirent* fdata
     1364    auto h = cenforce(opendir(toStringz(pathname)), pathname)
     1365    scope(exit) closedir(h)
    13541366    DirEntry de; 
    1355  
    1356     h = opendir(toStringz(pathname)); 
    1357     if (h) 
    1358     { 
    1359     try 
    1360     { 
    1361         while((fdata = readdir(h)) != null) 
    1362         { 
    1363         // Skip "." and ".." 
    1364         if (!std.string.strcmp(fdata.d_name.ptr, ".") || 
    1365             !std.string.strcmp(fdata.d_name.ptr, "..")) 
    1366             continue; 
    1367  
    1368         de.init(pathname, fdata); 
    1369         if (!callback(&de))      
    1370             break; 
    1371         } 
    1372     } 
    1373     finally 
    1374     { 
    1375         closedir(h); 
    1376     } 
    1377     } 
    1378     else 
    1379     { 
    1380         throw new FileException(pathname, getErrno()); 
    1381     } 
    1382 
    1383  
     1367    for (dirent* fdata; (fdata = readdir(h)) != null; ) 
     1368    { 
     1369        // Skip "." and ".." 
     1370        if (!std.string.strcmp(fdata.d_name.ptr, ".") || 
     1371                !std.string.strcmp(fdata.d_name.ptr, "..")) 
     1372            continue; 
     1373        de.init(pathname, fdata); 
     1374        if (!callback(&de))      
     1375            break; 
     1376    } 
     1377
    13841378 
    13851379/*************************************************** 
     
    13891383void copy(in string from, in string to) 
    13901384{ 
    1391   version (all) 
    1392   { 
    1393     struct_stat statbuf; 
    1394  
    1395     char* fromz = toStringz(from); 
    1396     char* toz = toStringz(to); 
    1397     //printf("file.copy(from='%s', to='%s')\n", fromz, toz); 
    1398  
    1399     int fd = std.c.linux.linux.open(fromz, O_RDONLY); 
    1400     if (fd == -1) 
    1401     { 
    1402         //printf("\topen error, errno = %d\n",getErrno()); 
    1403         goto err1; 
    1404     } 
    1405  
    1406     //printf("\tfile opened\n"); 
    1407     if (std.c.linux.linux.fstat(fd, &statbuf)) 
    1408     { 
    1409         //printf("\tfstat error, errno = %d\n",getErrno()); 
    1410         goto err2; 
    1411     } 
    1412  
    1413     int fdw = std.c.linux.linux.open(toz, O_CREAT | O_WRONLY | O_TRUNC, 0660); 
    1414     if (fdw == -1) 
    1415     { 
    1416         //printf("\topen error, errno = %d\n",getErrno()); 
    1417         goto err2; 
    1418     } 
    1419  
    1420     size_t BUFSIZ = 4096 * 16; 
    1421     void* buf = std.c.stdlib.malloc(BUFSIZ); 
    1422     if (!buf) 
    1423     {   BUFSIZ = 4096; 
    1424     buf = std.c.stdlib.malloc(BUFSIZ); 
    1425     } 
    1426     if (!buf) 
    1427     { 
    1428         //printf("\topen error, errno = %d\n",getErrno()); 
    1429         goto err4; 
    1430     } 
    1431  
    1432     for (size_t size = statbuf.st_size; size; ) 
    1433     {   size_t toread = (size > BUFSIZ) ? BUFSIZ : size; 
    1434  
    1435     auto n = std.c.linux.linux.read(fd, buf, toread); 
    1436     if (n != toread) 
    1437     { 
    1438         //printf("\tread error, errno = %d\n",getErrno()); 
    1439         goto err5; 
    1440     } 
    1441     n = std.c.linux.linux.write(fdw, buf, toread); 
    1442     if (n != toread) 
    1443     { 
    1444         //printf("\twrite error, errno = %d\n",getErrno()); 
    1445         goto err5; 
    1446     } 
    1447     size -= toread; 
    1448     } 
    1449  
    1450     std.c.stdlib.free(buf); 
    1451  
    1452     if (std.c.linux.linux.close(fdw) == -1) 
    1453     { 
    1454     //printf("\tclose error, errno = %d\n",getErrno()); 
    1455         goto err2; 
    1456     } 
    1457  
    1458     utimbuf utim; 
    1459     utim.actime = cast(__time_t)statbuf.st_atime; 
    1460     utim.modtime = cast(__time_t)statbuf.st_mtime; 
    1461     if (utime(toz, &utim) == -1) 
    1462     { 
    1463     //printf("\tutime error, errno = %d\n",getErrno()); 
    1464     goto err3; 
    1465     } 
    1466  
    1467     if (std.c.linux.linux.close(fd) == -1) 
    1468     { 
    1469     //printf("\tclose error, errno = %d\n",getErrno()); 
    1470         goto err1; 
    1471     } 
    1472  
    1473     return; 
    1474  
    1475 err5: 
    1476     std.c.stdlib.free(buf); 
    1477 err4: 
    1478     std.c.linux.linux.close(fdw); 
    1479 err3: 
    1480     std.c.stdio.remove(toz); 
    1481 err2: 
    1482     std.c.linux.linux.close(fd); 
    1483 err1: 
    1484     throw new FileException(from.idup, getErrno()); 
    1485   } 
    1486   else 
    1487   { 
    1488     void[] buffer; 
    1489  
    1490     buffer = read(from); 
    1491     write(to, buffer); 
    1492     delete buffer; 
    1493   } 
     1385    version (all) 
     1386    { 
     1387        invariant fd = std.c.linux.linux.open(toStringz(from), O_RDONLY); 
     1388        cenforce(fd != -1, from); 
     1389        scope(exit) std.c.linux.linux.close(fd); 
     1390 
     1391        struct_stat statbuf = void; 
     1392        cenforce(std.c.linux.linux.fstat(fd, &statbuf) == 0, from); 
     1393 
     1394        auto toz = toStringz(to); 
     1395        invariant fdw = std.c.linux.linux.open(toz, 
     1396                O_CREAT | O_WRONLY | O_TRUNC, 0660); 
     1397        cenforce(fdw != -1, from); 
     1398        scope(failure) std.c.stdio.remove(toz); 
     1399        { 
     1400            scope(failure) std.c.linux.linux.close(fdw); 
     1401            auto BUFSIZ = 4096u * 16; 
     1402            auto buf = std.c.stdlib.malloc(BUFSIZ); 
     1403            if (!buf) 
     1404            { 
     1405                BUFSIZ = 4096; 
     1406                buf = enforce(std.c.stdlib.malloc(BUFSIZ), "Out of memory"); 
     1407            } 
     1408            scope(exit) std.c.stdlib.free(buf); 
     1409             
     1410            for (size_t size = statbuf.st_size; size; ) 
     1411            { 
     1412                invariant toxfer = (size > BUFSIZ) ? BUFSIZ : size; 
     1413                cenforce(std.c.linux.linux.read(fd, buf, toxfer) == toxfer 
     1414                        && std.c.linux.linux.write(fdw, buf, toxfer) == toxfer, 
     1415                        from); 
     1416                assert(size >= toxfer); 
     1417                size -= toxfer; 
     1418            } 
     1419        } 
     1420         
     1421        cenforce(std.c.linux.linux.close(fdw) != -1, from); 
     1422         
     1423        utimbuf utim = void; 
     1424        utim.actime = cast(__time_t) statbuf.st_atime; 
     1425        utim.modtime = cast(__time_t) statbuf.st_mtime; 
     1426        cenforce(utime(toz, &utim) != -1, from); 
     1427    } 
     1428    else 
     1429    { 
     1430        void[] buffer; 
     1431         
     1432        buffer = read(from); 
     1433        write(to, buffer); 
     1434        delete buffer; 
     1435    } 
    14941436} 
    14951437