Wolfgang Thallergcc16 merge934c3885 months agoHistory
5524 lines · 155.6 KB · D
RawDownload
// Written in the D programming language. /**Utilities for manipulating files and scanning directories. Functionsin this module handle files as a unit, e.g., read or write one fileat a time. For opening files and manipulating them via handles referto module $(MREF std, stdio). $(SCRIPT inhibitQuickIndex = 1;)$(DIVC quickindex,$(BOOKTABLE,$(TR $(TH Category) $(TH Functions))$(TR $(TD General) $(TD          $(LREF exists)          $(LREF isDir)          $(LREF isFile)          $(LREF isSymlink)          $(LREF rename)          $(LREF thisExePath)))$(TR $(TD Directories) $(TD          $(LREF chdir)          $(LREF dirEntries)          $(LREF getcwd)          $(LREF mkdir)          $(LREF mkdirRecurse)          $(LREF rmdir)          $(LREF rmdirRecurse)          $(LREF tempDir)))$(TR $(TD Files) $(TD          $(LREF append)          $(LREF copy)          $(LREF read)          $(LREF readText)          $(LREF remove)          $(LREF slurp)          $(LREF write)))$(TR $(TD Symlinks) $(TD          $(LREF symlink)          $(LREF readLink)))$(TR $(TD Attributes) $(TD          $(LREF attrIsDir)          $(LREF attrIsFile)          $(LREF attrIsSymlink)          $(LREF getAttributes)          $(LREF getLinkAttributes)          $(LREF getSize)          $(LREF setAttributes)))$(TR $(TD Timestamp) $(TD          $(LREF getTimes)          $(LREF getTimesWin)          $(LREF setTimes)          $(LREF timeLastModified)          $(LREF timeLastAccessed)          $(LREF timeStatusChanged)))$(TR $(TD Other) $(TD          $(LREF DirEntry)          $(LREF FileException)          $(LREF PreserveAttributes)          $(LREF SpanMode)          $(LREF getAvailableDiskSpace)))))  Copyright: Copyright The D Language Foundation 2007 - 2011.See_Also:  The $(HTTP ddili.org/ders/d.en/files.html, official tutorial) for anintroduction to working with files in D, module$(MREF std, stdio) for opening files and manipulating them via handles,and module $(MREF std, path) for manipulating path strings. License:   $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0).Authors:   $(HTTP digitalmars.com, Walter Bright),           $(HTTP erdani.org, Andrei Alexandrescu),           $(HTTP jmdavisprog.com, Jonathan M Davis)Source:    $(PHOBOSSRC std/file.d) */module std.file; import core.stdc.errno, core.stdc.stdlib, core.stdc.string;import core.time : abs, dur, hnsecs, seconds; import std.datetime.date : DateTime;import std.datetime.systime : Clock, SysTime, unixTimeToStdTime;import std.internal.cstring;import std.meta;import std.range;import std.traits;import std.typecons; version (OSX)    version = Darwin;else version (iOS)    version = Darwin;else version (TVOS)    version = Darwin;else version (WatchOS)    version = Darwin; version (Windows){    import core.sys.windows.winbase, core.sys.windows.winnt, std.windows.syserror;}else version (Posix){    import core.sys.posix.dirent, core.sys.posix.fcntl, core.sys.posix.sys.stat,        core.sys.posix.sys.time, core.sys.posix.unistd, core.sys.posix.utime;}else    static assert(false, "Module " ~ .stringof ~ " not implemented for this OS."); // Character type used for operating system filesystem APIsversion (Windows){    private alias FSChar = WCHAR;       // WCHAR can be aliased to wchar or wchar_t}else version (Posix){    private alias FSChar = char;}else    static assert(0); // Purposefully not documented. Use at your own risk@property string deleteme() @safe{    import std.conv : text;    import std.path : buildPath;    import std.process : thisProcessID;     enum base = "deleteme.dmd.unittest.pid";    static string fileName;     if (!fileName)        fileName = text(buildPath(tempDir(), base), thisProcessID);    return fileName;} version (StdUnittest) private struct TestAliasedString{    string get() @safe @nogc pure nothrow return scope { return _s; }    alias get this;    @disable this(this);    string _s;} version (Android){    package enum system_directory = "/system/etc";    package enum system_file      = "/system/etc/hosts";}else version (Posix){    package enum system_directory = "/usr/include";    package enum system_file      = "/usr/include/assert.h";}  /++    Exception thrown for file I/O errors. +/class FileException : Exception{    import std.conv : text, to;     /++        OS error code.     +/    immutable uint errno;     private this(scope const(char)[] name, scope const(char)[] msg, string file, size_t line, uint errno) @safe pure    {        if (msg.empty)            super(name is null ? "(null)" : name.idup, file, line);        else            super(text(name is null ? "(null)" : name, ": ", msg), file, line);         this.errno = errno;    }     /++        Constructor which takes an error message.         Params:            name = Name of file for which the error occurred.            msg  = Message describing the error.            file = The file where the error occurred.            line = The _line where the error occurred.     +/    this(scope const(char)[] name, scope const(char)[] msg, string file = __FILE__, size_t line = __LINE__) @safe pure    {        this(name, msg, file, line, 0);    }     /++        Constructor which takes the error number ($(LUCKY GetLastError)        in Windows, $(D_PARAM errno) in POSIX).         Params:            name  = Name of file for which the error occurred.            errno = The error number.            file  = The file where the error occurred.                    Defaults to `__FILE__`.            line  = The _line where the error occurred.                    Defaults to `__LINE__`.     +/    version (Windows) this(scope const(char)[] name,                          uint errno = .GetLastError(),                          string file = __FILE__,                          size_t line = __LINE__) @safe    {        this(name, generateSysErrorMsg(errno), file, line, errno);    }    else version (Posix) this(scope const(char)[] name,                             uint errno = .errno,                             string file = __FILE__,                             size_t line = __LINE__) @trusted    {        import std.exception : errnoString;        this(name, errnoString(errno), file, line, errno);    }} ///@safe unittest{    import std.exception : assertThrown;     assertThrown!FileException("non.existing.file.".readText);} private T cenforce(T)(T condition, lazy scope const(char)[] name, string file = __FILE__, size_t line = __LINE__){    if (condition)        return condition;    version (Windows)    {        throw new FileException(name, .GetLastError(), file, line);    }    else version (Posix)    {        throw new FileException(name, .errno, file, line);    }} version (Windows)@trustedprivate T cenforce(T)(T condition, scope const(char)[] name, scope const(FSChar)* namez,    string file = __FILE__, size_t line = __LINE__){    if (condition)        return condition;    if (!name)    {        import core.stdc.wchar_ : wcslen;        import std.conv : to;         auto len = namez ? wcslen(namez) : 0;        name = to!string(namez[0 .. len]);    }    throw new FileException(name, .GetLastError(), file, line);} version (Posix)@trustedprivate T cenforce(T)(T condition, scope const(char)[] name, scope const(FSChar)* namez,    string file = __FILE__, size_t line = __LINE__){    if (condition)        return condition;    if (!name)    {        import core.stdc.string : strlen;         auto len = namez ? strlen(namez) : 0;        name = namez[0 .. len].idup;    }    throw new FileException(name, .errno, file, line);} // https://issues.dlang.org/show_bug.cgi?id=17102@safe unittest{    try    {        cenforce(false, null, null,                __FILE__, __LINE__);    }    catch (FileException) {}} /* ********************************** * Basic File operations. */ /********************************************Read entire contents of file `name` and returns it as an untypedarray. If the file size is larger than `upTo`, only `upTo`bytes are _read. Params:    name = string or range of characters representing the file _name    upTo = if present, the maximum number of bytes to _read Returns: Untyped array of bytes _read. Throws: $(LREF FileException) on error. See_Also: $(REF readText, std,file) for reading and validating a text file. */ void[] read(R)(R name, size_t upTo = size_t.max)if (isSomeFiniteCharInputRange!R && !isConvertibleToString!R){    static if (isNarrowString!R && is(immutable ElementEncodingType!R == immutable char))        return readImpl(name, name.tempCString!FSChar(), upTo);    else        return readImpl(null, name.tempCString!FSChar(), upTo);} ///@safe unittest{    import std.utf : byChar;    scope(exit)    {        assert(exists(deleteme));        remove(deleteme);    }     std.file.write(deleteme, "1234"); // deleteme is the name of a temporary file    assert(read(deleteme, 2) == "12");    assert(read(deleteme.byChar) == "1234");    assert((cast(const(ubyte)[])read(deleteme)).length == 4);} /// dittovoid[] read(R)(auto ref R name, size_t upTo = size_t.max)if (isConvertibleToString!R){    return read!(StringTypeOf!R)(name, upTo);} @safe unittest{    static assert(__traits(compiles, read(TestAliasedString(null))));} version (Posix) private void[] readImpl(scope const(char)[] name, scope const(FSChar)* namez,                                        size_t upTo = size_t.max) @trusted{    import core.memory : GC;    import std.algorithm.comparison : min;    import std.conv : to;    import std.checkedint : checked;     // A few internal configuration parameters {    enum size_t        minInitialAlloc = 1024 * 4,        maxInitialAlloc = size_t.max / 2,        sizeIncrement = 1024 * 16,        maxSlackMemoryAllowed = 1024;    // }     immutable fd = core.sys.posix.fcntl.open(namez,            core.sys.posix.fcntl.O_RDONLY);    cenforce(fd != -1, name);    scope(exit) core.sys.posix.unistd.close(fd);     stat_t statbuf = void;    cenforce(fstat(fd, &statbuf) == 0, name, namez);     immutable initialAlloc = min(upTo, to!size_t(statbuf.st_size        ? min(statbuf.st_size + 1, maxInitialAlloc)        : minInitialAlloc));    void[] result = GC.malloc(initialAlloc, GC.BlkAttr.NO_SCAN)[0 .. initialAlloc];    scope(failure) GC.free(result.ptr);     auto size = checked(size_t(0));     for (;;)    {        immutable actual = core.sys.posix.unistd.read(fd, result.ptr + size.get,                (min(result.length, upTo) - size).get);        cenforce(actual != -1, name, namez);        if (actual == 0) break;        size += actual;        if (size >= upTo) break;        if (size < result.length) continue;        immutable newAlloc = size + sizeIncrement;        result = GC.realloc(result.ptr, newAlloc.get, GC.BlkAttr.NO_SCAN)[0 .. newAlloc.get];    }     return result.length - size >= maxSlackMemoryAllowed        ? GC.realloc(result.ptr, size.get, GC.BlkAttr.NO_SCAN)[0 .. size.get]        : result[0 .. size.get];} version (Windows)private extern (Windows) @nogc nothrow{    pragma(mangle, CreateFileW.mangleof)    HANDLE trustedCreateFileW(scope const(wchar)* namez, DWORD dwDesiredAccess,        DWORD dwShareMode, SECURITY_ATTRIBUTES* lpSecurityAttributes,        DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes,        HANDLE hTemplateFile)  @trusted;     pragma(mangle, CloseHandle.mangleof) BOOL trustedCloseHandle(HANDLE) @trusted;} version (Windows) private void[] readImpl(scope const(char)[] name, scope const(FSChar)* namez,                                          size_t upTo = size_t.max) @trusted{    import core.memory : GC;    import std.algorithm.comparison : min;    static trustedGetFileSize(HANDLE hFile, out ulong fileSize)    {        DWORD sizeHigh;        DWORD sizeLow = GetFileSize(hFile, &sizeHigh);        const bool result = sizeLow != INVALID_FILE_SIZE;        if (result)            fileSize = makeUlong(sizeLow, sizeHigh);        return result;    }    static trustedReadFile(HANDLE hFile, void *lpBuffer, size_t nNumberOfBytesToRead)    {        // Read by chunks of size < 4GB (Windows API limit)        size_t totalNumRead = 0;        while (totalNumRead != nNumberOfBytesToRead)        {            const uint chunkSize = min(nNumberOfBytesToRead - totalNumRead, 0xffff_0000);            DWORD numRead = void;            const result = ReadFile(hFile, lpBuffer + totalNumRead, chunkSize, &numRead, null);            if (result == 0 || numRead != chunkSize)                return false;            totalNumRead += chunkSize;        }        return true;    }     alias defaults =        AliasSeq!(GENERIC_READ,            FILE_SHARE_READ | FILE_SHARE_WRITE, (SECURITY_ATTRIBUTES*).init,            OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,            HANDLE.init);    auto h = trustedCreateFileW(namez, defaults);     cenforce(h != INVALID_HANDLE_VALUE, name, namez);    scope(exit) cenforce(trustedCloseHandle(h), name, namez);    ulong fileSize = void;    cenforce(trustedGetFileSize(h, fileSize), name, namez);    size_t size = min(upTo, fileSize);    auto buf = () { return GC.malloc(size, GC.BlkAttr.NO_SCAN)[0 .. size]; } ();     scope(failure)    {        () { GC.free(buf.ptr); } ();    }     if (size)        cenforce(trustedReadFile(h, &buf[0], size), name, namez);    return buf[0 .. size];} version (linux) @safe unittest{    // A file with "zero" length that doesn't have 0 length at all    auto s = std.file.readText("/proc/cpuinfo");    assert(s.length > 0);    //writefln("'%s'", s);} @safe unittest{    scope(exit) if (exists(deleteme)) remove(deleteme);    import std.stdio;    auto f = File(deleteme, "w");    f.write("abcd"); f.flush();    assert(read(deleteme) == "abcd");} /++    Reads and validates (using $(REF validate, std, utf)) a text file. S can be    an array of any character type. However, no width or endian conversions are    performed. So, if the width or endianness of the characters in the given    file differ from the width or endianness of the element type of S, then    validation will fail.     Params:        S = the string type of the file        name = string or range of characters representing the file _name     Returns: Array of characters read.     Throws: $(LREF FileException) if there is an error reading the file,

Lines 1–500 of 5524.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t