openat2-resolve-flags.dhover×197all
#!/usr/bin/env dub
/+ dub.sdl:
    name "openat2_resolve_flags"
    platforms "linux"
    targetPath "build"
    buildType "checked" {
        buildOptions "optimize" "inline" "debugInfo"
    }
+/
/**
 * `openat2(2)` — what each `RESOLVE_*` flag accepts and refuses (Linux 5.6+).
 *
 * Builds a scratch tree, then opens nine paths relative to its root with
 * different `resolve` masks and prints the outcome of each. The point is the
 * table this produces: a relative symlink that stays inside the root is fine
 * under `RESOLVE_BENEATH` but refused under `RESOLVE_NO_SYMLINKS`; a `..` that
 * stays beneath is fine in the kernel even though a portable component check
 * must refuse it; an absolute symlink, an absolute path and a `..` climb are
 * all `EXDEV`; a procfs magic link is `ELOOP` under `RESOLVE_NO_MAGICLINKS`.
 *
 * Companion to docs/research/safe-path-traversal/linux-openat2.md
 * § "Dimension 3 — symlink and `..` policy".
 *
 * Run with: `dub run --single openat2-resolve-flags.d`
 *
 * Portability: on a kernel without `openat2` (pre-5.6, or a seccomp policy
 * that returns `ENOSYS`), prints a `SKIP:` line and exits 0.
 */
module 
(module) openat2_resolve_flags

openat2(2) — what each RESOLVE_* flag accepts and refuses (Linux 5.6+).

Builds a scratch tree, then opens nine paths relative to its root with different resolve masks and prints the outcome of each. The point is the table this produces: a relative symlink that stays inside the root is fine under RESOLVE_BENEATH but refused under RESOLVE_NO_SYMLINKS; a .. that stays beneath is fine in the kernel even though a portable component check must refuse it; an absolute symlink, an absolute path and a .. climb are all EXDEV; a procfs magic link is ELOOP under RESOLVE_NO_MAGICLINKS.

Companion to docs/research/safe-path-traversal/linux-openat2.md § "Dimension 3 — symlink and .. policy".

Run with: dub run --single openat2-resolve-flags.d

Portability

on a kernel without openat2 (pre-5.6, or a seccomp policy that returns ENOSYS), prints a SKIP: line and exits 0.

openat2_resolve_flags
;
import
(package) core
core
.
(package) core.stdc
stdc
.
(module) core.stdc.errno

D header file for C99.

pubs.opengroup.org/onlinepubs/009695399/basedefs/errno.h.html, errno.h

Source

core/stdc/errno.d

@copyrightCopyright Sean Kelly 2005 - 2009.@licenseDistributed under the Boost Software License 1.0. (See accompanying file LICENSE)@authorsSean Kelly, Alex Rønne Petersen@standardsISO/IEC 9899:1999 (E)
errno
:
(alias) openat2_resolve_flags.errno = int core.stdc.errno.__errno_location() nothrow @nogc ref @trusted
errno
,
(alias constant) openat2_resolve_flags.EXDEV = int core.stdc.errno.EXDEV = 18
EXDEV
,
(alias constant) openat2_resolve_flags.ELOOP = int core.stdc.errno.ELOOP = 40
ELOOP
,
(alias constant) openat2_resolve_flags.ENOSYS = int core.stdc.errno.ENOSYS = 38
ENOSYS
,
(alias constant) openat2_resolve_flags.ENOENT = int core.stdc.errno.ENOENT = 2
ENOENT
;
import
(package) core
core
.
(package) core.sys
sys
.
(package) core.sys.linux
linux
.
(module) core.sys.linux.unistd
unistd
:
(alias) openat2_resolve_flags.syscall = long core.sys.linux.unistd.syscall(long sysno, ...) nothrow @nogc

Invoke system call number sysno, passing it the remaining arguments.

syscall
;
import
(package) core
core
.
(package) core.sys
sys
.
(package) core.sys.posix
posix
.
(module) core.sys.posix.fcntl

D header file for POSIX.

@copyrightCopyright Sean Kelly 2005 - 2009.@licenseBoost License 1.0.@authorsSean Kelly, Alex Rønne Petersen@standardsThe Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition
fcntl
:
(alias constant) openat2_resolve_flags.O_RDONLY = int core.sys.posix.fcntl.O_RDONLY = 0
O_RDONLY
,
(alias constant) openat2_resolve_flags.O_DIRECTORY = int core.sys.posix.fcntl.O_DIRECTORY = 65536
O_DIRECTORY
,
(alias constant) openat2_resolve_flags.O_CLOEXEC = int core.sys.posix.fcntl.O_CLOEXEC = 524288
O_CLOEXEC
, open;
import
(package) core
core
.
(package) core.sys
sys
.
(package) core.sys.posix
posix
.
(module) core.sys.posix.unistd

D header file for POSIX.

@copyrightCopyright Sean Kelly 2005 - 2009.@licenseBoost License 1.0.@authorsSean Kelly@standardsThe Open Group Base Specifications Issue 8, IEEE Std 1003.1, 2024 Edition
unistd
:
(alias) openat2_resolve_flags.close = int core.sys.posix.unistd.close(int) nothrow @nogc @trusted
close
;
import
(package) std
std
.
(module) std.conv

A one-stop shop for converting values from one type to another.

Category Functions
Generic asOriginalType castFrom parse to toChars bitCast
Strings text wtext dtext writeText writeWText writeDText hexString
Numeric octal roundTo signed unsigned
Exceptions ConvException ConvOverflowException

Source

std/conv.d

@copyrightCopyright The D Language Foundation 2007-.@licenseBoost License 1.0.@authorsWalter Bright, Andrei Alexandrescu, Shin Fujishiro, Adam D. Ruppe, Kenji Hara
conv
:
(alias template) openat2_resolve_flags.text = std.conv.text(T...)(T args) if (T.length > 0)

Convenience functions for converting one or more arguments of any type into text (the three character widths).

text
;
import
(package) std
std
.
(module) std.file

Utilities for manipulating files and scanning directories. Functions in this module handle files as a unit, e.g., read or write one file at a time. For opening files and manipulating them via handles refer to module std.stdio.

Category Functions
General exists isDir isFile isSymlink rename thisExePath
Directories chdir dirEntries getcwd mkdir mkdirRecurse rmdir rmdirRecurse tempDir
Files append copy read readText remove slurp write
Symlinks symlink readLink
Attributes attrIsDir attrIsFile attrIsSymlink getAttributes getLinkAttributes getSize setAttributes
Timestamp getTimes getTimesWin setTimes timeLastModified timeLastAccessed timeStatusChanged
Other DirEntry FileException PreserveAttributes SpanMode getAvailableDiskSpace

Source

std/file.d

@copyrightCopyright The D Language Foundation 2007 - 2011.@seeThe official tutorial for an introduction to working with files in D, module std.stdio for opening files and manipulating them via handles, and module std.path for manipulating path strings.@licenseBoost License 1.0.@authorsWalter Bright, Andrei Alexandrescu, Jonathan M Davis
file
:
(alias template) openat2_resolve_flags.exists = std.file.exists(R)(R name) if (isSomeFiniteCharInputRange!R && !isConvertibleToString!R)

Determine whether the given file (or directory) exists.

@paramname string or range of characters representing the file name@returnstrue if the file name specified as input exists
exists
,
(alias) openat2_resolve_flags.mkdirRecurse = void std.file.mkdirRecurse(scope const(char)[] pathname) @safe

Make directory and all parent directories as needed.

Does nothing if the directory specified by pathname already exists.

@parampathname the full path of the directory to create@throwsFileException on error.
mkdirRecurse
,
(alias) openat2_resolve_flags.rmdirRecurse = void std.file.rmdirRecurse(scope const(char)[] pathname) @safe

Remove directory and all of its content and subdirectories, recursively.

@parampathname the path of the directory to completely remove@paramde The DirEntry to remove@throwsFileException if there is an error (including if the given file is not a directory).
rmdirRecurse
,
(alias template) openat2_resolve_flags.symlink = std.file.symlink(RO, RL)(RO original, RL link) if ((isSomeFiniteCharInputRange!RO || isConvertibleToString!RO) && (isSomeFiniteCharInputRange!RL || isConvertibleToString!RL))

This function is POSIX-Only.

Creates a symbolic link (symlink).

@paramoriginal The file that is being linked. This is the target path that's stored in the symlink. A relative path is relative to the created symlink.@paramlink The symlink to create. A relative path is relative to the current working directory.@throwsFileException on error (which includes if the symlink already exists).
symlink
,
(alias) openat2_resolve_flags.tempDir = string std.file.tempDir() @trusted

Returns the path to a directory for temporary files. On POSIX platforms, it searches through the following list of directories and returns the first one which is found to exist:

  1. The directory given by the TMPDIR environment variable.

  2. The directory given by the TEMP environment variable.

  3. The directory given by the TMP environment variable.

  4. /tmp/

  5. /var/tmp/

  6. /usr/tmp/

On all platforms, tempDir returns the current working directory on failure.

The return value of the function is cached, so the procedures described below will only be performed the first time the function is called. All subsequent runs will return the same string, regardless of whether environment variables and directory structures have changed in the meantime.

The POSIX tempDir algorithm is inspired by Python's tempfile.tempdir.

@returns

On Windows, this function returns the result of calling the Windows API function GetTempPath.

On POSIX platforms, it searches through the following list of directories and returns the first one which is found to exist:

  1. The directory given by the TMPDIR environment variable.

  2. The directory given by the TEMP environment variable.

  3. The directory given by the TMP environment variable.

  4. /tmp

  5. /var/tmp

  6. /usr/tmp

On all platforms, tempDir returns "." on failure, representing the current working directory.

tempDir
,
(alias template) openat2_resolve_flags.write = std.file.write(R)(R name, const void[] buffer) if ((isSomeFiniteCharInputRange!R || isSomeString!R) && !isConvertibleToString!R)

Write buffer to file name.

Creates the file if it does not already exist.

@paramname string or range of characters representing the file name@parambuffer data to be written to file@throwsFileException on error.@seetoFile
write
;
import
(package) std
std
.
(module) std.path

This module is used to manipulate path strings.

All functions, with the exception of expandTilde (and in some cases absolutePath and relativePath), are pure string manipulation functions; they don't depend on any state outside the program, nor do they perform any actual file system actions. This has the consequence that the module does not make any distinction between a path that points to a directory and a path that points to a file, and it does not know whether or not the object pointed to by the path actually exists in the file system. To differentiate between these cases, use isDir and exists.

Note that on Windows, both the backslash (\) and the slash (/) are in principle valid directory separators. This module treats them both on equal footing, but in cases where a new separator is added, a backslash will be used. Furthermore, the buildNormalizedPath function will replace all slashes with backslashes on that platform.

In general, the functions in this module assume that the input paths are well-formed. (That is, they should not contain invalid characters, they should follow the file system's path format, etc.) The result of calling a function on an ill-formed path is undefined. When there is a chance that a path or a file name is invalid (for instance, when it has been input by the user), it may sometimes be desirable to use the isValidFilename and isValidPath functions to check this.

Most functions do not perform any memory allocations, and if a string is returned, it is usually a slice of an input string. If a function allocates, this is explicitly mentioned in the documentation.

Category Functions
Normalization absolutePath asAbsolutePath asNormalizedPath asRelativePath buildNormalizedPath buildPath chainPath expandTilde
Partitioning baseName dirName dirSeparator driveName pathSeparator pathSplitter relativePath rootName stripDrive
Validation isAbsolute isDirSeparator isRooted isValidFilename isValidPath
Extension defaultExtension extension setExtension stripExtension withDefaultExtension withExtension
Other filenameCharCmp filenameCmp globMatch CaseSensitive

Source

std/path.d

@authorsLars Tandle Kyllingstad, Walter Bright, Grzegorz Adam Hankiewicz, Thomas Khne, Andrei Alexandrescu@copyrightCopyright (c) 2000-2014, the authors. All rights reserved.@licenseBoost License 1.0
path
:
(alias template) openat2_resolve_flags.buildPath = std.path.buildPath(Range)(scope Range segments) if (isInputRange!Range && !isInfinite!Range && isSomeString!(ElementType!Range))

Combines one or more path segments.

This function takes a set of path segments, given as an input range of string elements or as a set of string arguments, and concatenates them with each other. Directory separators are inserted between segments if necessary. If any of the path segments are absolute (as defined by isAbsolute), the preceding segments will be dropped.

On Windows, if one of the path segments are rooted, but not absolute (e.g. \foo), all preceding path segments down to the previous root will be dropped. (See below for an example.)

This function always allocates memory to hold the resulting path. The variadic overload is guaranteed to only perform a single allocation, as is the range version if paths is a forward range.

@paramsegments An input range of segments to assemble the path from.@returnsThe assembled path.
buildPath
;
import
(package) std
std
.
(module) std.stdio
Category Symbols
File handles _popen File isFileHandle openNetwork stderr stdin stdout
Reading chunks lines readf readfln readln
Writing toFile write writef writefln writeln
Misc KeepTerminator LockType StdioException

Standard I/O functions that extend core.stdc.stdio. core.stdc.stdio is publically imported when importing std.stdio.

There are three layers of I/O:

  1. The lowest layer is the operating system layer. The two main schemes are Windows and Posix.

  2. C's stdio.h which unifies the two operating system schemes.

  3. std.stdio, this module, unifies the various stdio.h implementations into a high level package for D programs.

Source

std/stdio.d

@copyrightCopyright The D Language Foundation 2007-.@licenseBoost License 1.0.@authorsWalter Bright, Andrei Alexandrescu, Alex Rønne Petersen
stdio
:
(alias template) openat2_resolve_flags.writefln = std.stdio.writefln(alias fmt, A...)(A args) if (isSomeString!(typeof(fmt)))

Equivalent to writef(fmt, args, '\n').

writefln
,
(alias template) openat2_resolve_flags.writeln = std.stdio.writeln(T...)(T args)

Equivalent to write(args, '\n'). Calling writeln without arguments is valid and just prints a newline to the standard output.

Example

Reads stdin and writes it to stdout with an argument counter.

import std.stdio;

void main()
{
    string line;

    for (size_t count = 0; (line = readln) !is null; count++)
    {
         writeln("Input ", count, ": ", line);
    }
}
@paramargs the items to write to stdout@throwsIn case of an I/O error, throws an StdioException.
writeln
;
import
(package) std
std
.
(module) std.string

String handling functions.

Category Functions
Searching
column
indexOf
indexOfAny
indexOfNeither
lastIndexOf
lastIndexOfAny
lastIndexOfNeither
Comparison
isNumeric
Mutation
capitalize
Pruning and Filling
center
chomp
chompPrefix
chop
detabber
detab
entab
entabber
leftJustify
outdent
rightJustify
strip
stripLeft
stripRight
wrap
Substitution
abbrev
soundex
soundexer
succ
tr
translate
Miscellaneous
assumeUTF
fromStringz
lineSplitter
representation
splitLines
toStringz
Objects of types string, wstring, and dstring are value types
and cannot be mutated element-by-element. For using mutation during building
strings, use char[], wchar[], or dchar[]. The xxxstring
types are preferable because they don't exhibit undesired aliasing, thus
making code more robust.

The following functions are publicly imported:

Module Functions
Publicly imported functions
std.algorithm
cmp, std,algorithm,comparison
count, std,algorithm,searching
endsWith, std,algorithm,searching
startsWith, std,algorithm,searching
std.array
join, std,array
replace, std,array
replaceInPlace, std,array
split, std,array
empty, std,array
std.format
format, std,format
sformat, std,format
std.uni
icmp, std,uni
toLower, std,uni
toLowerInPlace, std,uni
toUpper, std,uni
toUpperInPlace, std,uni
There is a rich set of functions for string handling defined in other modules.
Functions related to Unicode and ASCII are found in std.uni
and std.ascii, respectively. Other functions that have a
wider generality than just strings can be found in std.algorithm
and std.range.

Source

std/string.d

@seestd.algorithm and std.range for generic range algorithms , std.ascii for functions that work with ASCII strings , std.uni for functions that work with unicode strings@copyrightCopyright The D Language Foundation 2007-.@licenseBoost License 1.0.@authorsWalter Bright, Andrei Alexandrescu, Jonathan M Davis, and David L. 'SpottedTiger' Davis
string
:
(alias) openat2_resolve_flags.toStringz = immutable(char)* std.string.toStringz(scope const(char)[] s) pure nothrow @trusted
@params A D-style string.@returns

A C-style null-terminated string equivalent to s. s must not contain embedded '\0''s as any C function will treat the first '\0' that it sees as the end of the string. If s.empty is true, then a string containing only '\0' is returned.

Important Note: When passing a char* to a C function, and the C function keeps it around for any reason, make sure that you keep a reference to it in your D code. Otherwise, it may become invalid during a garbage collection cycle and cause a nasty bug when the C code tries to use it.

toStringz
;
// From <linux/openat2.h>. Not in druntime as of LDC 1.42. enum
(constant) int openat2_resolve_flags.RESOLVE_NO_XDEV = 1
RESOLVE_NO_XDEV
= 0x01;
enum
(constant) int openat2_resolve_flags.RESOLVE_NO_MAGICLINKS = 2
RESOLVE_NO_MAGICLINKS
= 0x02;
enum
(constant) int openat2_resolve_flags.RESOLVE_NO_SYMLINKS = 4
RESOLVE_NO_SYMLINKS
= 0x04;
enum
(constant) int openat2_resolve_flags.RESOLVE_BENEATH = 8
RESOLVE_BENEATH
= 0x08;
enum
(constant) int openat2_resolve_flags.RESOLVE_IN_ROOT = 16
RESOLVE_IN_ROOT
= 0x10;
// From <sys/syscall.h>: 437 on every architecture that has openat2 (it was // added after the syscall tables were unified). enum
(constant) int openat2_resolve_flags.SYS_openat2 = 437
SYS_openat2
= 437;
// `struct open_how` — extensible: the size argument lets the kernel tell an // old struct from a new one (`E2BIG` if we pass trailing non-zero bytes it // does not know about). struct
(struct) openat2_resolve_flags.open_how
open_how
{ ulong
(field) ulong openat2_resolve_flags.open_how.flags
flags
;
ulong
(field) ulong openat2_resolve_flags.open_how.mode
mode
;
ulong
(field) ulong openat2_resolve_flags.open_how.resolve
resolve
;
} /// Returns the fd, or `-errno`. int
int openat2_resolve_flags.openat2(int dirfd, string path, ulong flags, ulong resolve)

Returns the fd, or -errno.

openat2
(int
(parameter) int dirfd
dirfd
,
(alias) object.string = string
string
(parameter) string path
path
, ulong
(parameter) ulong flags
flags
, ulong
(parameter) ulong resolve
resolve
)
{ auto
(local variable) openat2_resolve_flags.open_how how
how
=
(struct) openat2_resolve_flags.open_how
open_how
(
(parameter) ulong flags
flags
, 0,
(parameter) ulong resolve
resolve
);
const
(local variable) const(long) r
r
=
long core.sys.linux.unistd.syscall(long sysno, ...) nothrow @nogc

Invoke system call number sysno, passing it the remaining arguments.

syscall
(
(constant) int openat2_resolve_flags.SYS_openat2 = 437
SYS_openat2
,
(parameter) int dirfd
dirfd
,
(parameter) string path
path
.
immutable(char)* std.string.toStringz(scope const(char)[] s) pure nothrow @trusted

Examples

import core.stdc.string : strlen;
import std.conv : to;

auto p = toStringz("foo");
assert(strlen(p) == 3);
const(char)[] foo = "abbzxyzzy";
p = toStringz(foo[3 .. 5]);
assert(strlen(p) == 2);

string test = "";
p = toStringz(test);
assert(*p == 0);

test = "\0";
p = toStringz(test);
assert(*p == 0);

test = "foo\0";
p = toStringz(test);
assert(p[0] == 'f' && p[1] == 'o' && p[2] == 'o' && p[3] == 0);

const string test2 = "";
p = toStringz(test2);
assert(*p == 0);

assert(toStringz([]) is toStringz(""));
@params A D-style string.@returns

A C-style null-terminated string equivalent to s. s must not contain embedded '\0''s as any C function will treat the first '\0' that it sees as the end of the string. If ``s.empty is true, then a string containing only '\0' is returned.

Important Note: When passing a char* to a C function, and the C function keeps it around for any reason, make sure that you keep a reference to it in your D code. Otherwise, it may become invalid during a garbage collection cycle and cause a nasty bug when the C code tries to use it.

toStringz
, &
(local variable) openat2_resolve_flags.open_how how
how
,
(local variable) openat2_resolve_flags.open_how how
how
.
(constant) ulong openat2_resolve_flags.open_how.sizeof = 24LU
sizeof
);
return
(local variable) const(long) r
r
< 0 ? -
int core.stdc.errno.__errno_location() nothrow @nogc ref @trusted
errno
: cast(int)
(local variable) const(long) r
r
;
}
(alias) object.string = string
string
string openat2_resolve_flags.errName(int e)
errName
(int
(parameter) int e
e
)
{ switch (
(parameter) int e
e
)
{ case
(constant) int core.stdc.errno.EXDEV = 18
EXDEV
: return "EXDEV";
case
(constant) int core.stdc.errno.ELOOP = 40
ELOOP
: return "ELOOP";
case
(constant) int core.stdc.errno.ENOENT = 2
ENOENT
: return "ENOENT";
case
(constant) int core.stdc.errno.ENOSYS = 38
ENOSYS
: return "ENOSYS";
default: return
string std.conv.text!(string, int)(string __param_0, int __param_1) pure nothrow @safe

Convenience functions for converting one or more arguments of any type into text (the three character widths).

text
("errno ",
(parameter) int e
e
);
} } void
void openat2_resolve_flags.report(string label, int dirfd, string path, ulong resolve)
report
(
(alias) object.string = string
string
(parameter) string label
label
, int
(parameter) int dirfd
dirfd
,
(alias) object.string = string
string
(parameter) string path
path
, ulong
(parameter) ulong resolve
resolve
)
{ const
(local variable) const(int) fd
fd
=
int openat2_resolve_flags.openat2(int dirfd, string path, ulong flags, ulong resolve)

Returns the fd, or -errno.

openat2
(
(parameter) int dirfd
dirfd
,
(parameter) string path
path
,
(constant) int core.sys.posix.fcntl.O_RDONLY = 0
O_RDONLY
|
(constant) int core.sys.posix.fcntl.O_CLOEXEC = 524288
O_CLOEXEC
,
(parameter) ulong resolve
resolve
);
if (
(local variable) const(int) fd
fd
>= 0)
{
int core.sys.posix.unistd.close(int) nothrow @nogc @trusted
close
(
(local variable) const(int) fd
fd
);
void std.stdio.writefln!(char, string, string)(in char[] fmt, string __param_1, string __param_2) @safe

Equivalent to writef(fmt, args, '\n').

writefln
(" %-42s %-30s ok",
(parameter) string path
path
,
(parameter) string label
label
);
} else
void std.stdio.writefln!(char, string, string, string)(in char[] fmt, string __param_1, string __param_2, string __param_3) @safe

Equivalent to writef(fmt, args, '\n').

writefln
(" %-42s %-30s %s",
(parameter) string path
path
,
(parameter) string label
label
,
string openat2_resolve_flags.errName(int e)
errName
(-
(local variable) const(int) fd
fd
));
} int
int D main()
main
()
{ // Probe first: an `ENOSYS` here means no openat2 at all. { const
(local variable) const(int) fd
fd
=
int openat2_resolve_flags.openat2(int dirfd, string path, ulong flags, ulong resolve)

Returns the fd, or -errno.

openat2
(-100 /* AT_FDCWD */, ".",
(constant) int core.sys.posix.fcntl.O_RDONLY = 0
O_RDONLY
|
(constant) int core.sys.posix.fcntl.O_DIRECTORY = 65536
O_DIRECTORY
, 0);
if (
(local variable) const(int) fd
fd
== -
(constant) int core.stdc.errno.ENOSYS = 38
ENOSYS
)
{
void std.stdio.writeln!string(string __param_0) @safe

Equivalent to write(args, '\n'). Calling writeln without arguments is valid and just prints a newline to the standard output.

Example

Reads stdin and writes it to stdout with an argument counter.

import std.stdio;

void main()
{
    string line;

    for (size_t count = 0; (line = readln) !is null; count++)
    {
         writeln("Input ", count, ": ", line);
    }
}
@paramargs the items to write to stdout@throwsIn case of an I/O error, throws an StdioException.
writeln
("SKIP: openat2 unavailable on this kernel (ENOSYS)");
return 0; } if (
(local variable) const(int) fd
fd
>= 0)
int core.sys.posix.unistd.close(int) nothrow @nogc @trusted
close
(
(local variable) const(int) fd
fd
);
} const
(local variable) const(string) root
root
=
string std.path.buildPath!char(const(char)[][] paths...) pure nothrow @safe

Combines one or more path segments.

This function takes a set of path segments, given as an input range of string elements or as a set of string arguments, and concatenates them with each other. Directory separators are inserted between segments if necessary. If any of the path segments are absolute (as defined by isAbsolute), the preceding segments will be dropped.

On Windows, if one of the path segments are rooted, but not absolute (e.g. \foo), all preceding path segments down to the previous root will be dropped. (See below for an example.)

This function always allocates memory to hold the resulting path. The variadic overload is guaranteed to only perform a single allocation, as is the range version if paths is a forward range.

Examples

version (Posix)
{
    assert(buildPath("foo", "bar", "baz") == "foo/bar/baz");
    assert(buildPath("/foo/", "bar/baz")  == "/foo/bar/baz");
    assert(buildPath("/foo", "/bar")      == "/bar");
}

version (Windows)
{
    assert(buildPath("foo", "bar", "baz") == `foo\bar\baz`);
    assert(buildPath(`c:\foo`, `bar\baz`) == `c:\foo\bar\baz`);
    assert(buildPath("foo", `d:\bar`)     == `d:\bar`);
    assert(buildPath("foo", `\bar`)       == `\bar`);
    assert(buildPath(`c:\foo`, `\bar`)    == `c:\bar`);
}
@paramsegments An input range of segments to assemble the path from.@returnsThe assembled path.
buildPath
(
string std.file.tempDir() @trusted

Returns the path to a directory for temporary files. On POSIX platforms, it searches through the following list of directories and returns the first one which is found to exist:

  1. The directory given by the TMPDIR environment variable.

  2. The directory given by the TEMP environment variable.

  3. The directory given by the TMP environment variable.

  4. /tmp/

  5. /var/tmp/

  6. /usr/tmp/

On all platforms, tempDir returns the current working directory on failure.

The return value of the function is cached, so the procedures described below will only be performed the first time the function is called. All subsequent runs will return the same string, regardless of whether environment variables and directory structures have changed in the meantime.

The POSIX tempDir algorithm is inspired by Python's tempfile.tempdir.

Examples

import std.ascii : letters;
import std.conv : to;
import std.path : buildPath;
import std.random : randomSample;
import std.utf : byCodeUnit;

// random id with 20 letters
auto id = letters.byCodeUnit.randomSample(20).to!string;
auto myFile = tempDir.buildPath(id ~ "my_tmp_file");
scope(exit) myFile.remove;

myFile.write("hello");
assert(myFile.readText == "hello");
@returns

On Windows, this function returns the result of calling the Windows API function GetTempPath.

On POSIX platforms, it searches through the following list of directories and returns the first one which is found to exist:

  1. The directory given by the TMPDIR environment variable.

  2. The directory given by the TEMP environment variable.

  3. The directory given by the TMP environment variable.

  4. /tmp

  5. /var/tmp

  6. /usr/tmp

On all platforms, tempDir returns "." on failure, representing the current working directory.

tempDir
, "openat2-resolve-flags-demo");
if (
(local variable) const(string) root
root
.
bool std.file.exists!string(string name) nothrow @nogc @safe

Determine whether the given file (or directory) exists.

@paramname string or range of characters representing the file name@returnstrue if the file name specified as input exists
exists
)
void std.file.rmdirRecurse(scope const(char)[] pathname) @safe

Remove directory and all of its content and subdirectories, recursively.

@parampathname the path of the directory to completely remove@paramde The DirEntry to remove@throwsFileException if there is an error (including if the given file is not a directory).
rmdirRecurse
(
(local variable) const(string) root
root
);
scope (exit)
void std.file.rmdirRecurse(scope const(char)[] pathname) @safe

Remove directory and all of its content and subdirectories, recursively.

@parampathname the path of the directory to completely remove@paramde The DirEntry to remove@throwsFileException if there is an error (including if the given file is not a directory).
rmdirRecurse
(
(local variable) const(string) root
root
);
void std.file.mkdirRecurse(scope const(char)[] pathname) @safe

Make directory and all parent directories as needed.

Does nothing if the directory specified by pathname already exists.

Examples

import std.path : buildPath;

auto dir = deleteme ~ "dir";
scope(exit) dir.rmdirRecurse;

dir.mkdir;
assert(dir.exists);
dir.mkdirRecurse; // does nothing

// creates all parent directories as needed
auto nested = dir.buildPath("a", "b", "c");
nested.mkdirRecurse;
assert(nested.exists);
import std.exception : assertThrown;

scope(exit) deleteme.remove;
deleteme.write("a");

// cannot make directory as it's already a file
assertThrown!FileException(deleteme.mkdirRecurse);
@parampathname the full path of the directory to create@throwsFileException on error.
mkdirRecurse
(
string std.path.buildPath!char(const(char)[][] paths...) pure nothrow @safe

Combines one or more path segments.

This function takes a set of path segments, given as an input range of string elements or as a set of string arguments, and concatenates them with each other. Directory separators are inserted between segments if necessary. If any of the path segments are absolute (as defined by isAbsolute), the preceding segments will be dropped.

On Windows, if one of the path segments are rooted, but not absolute (e.g. \foo), all preceding path segments down to the previous root will be dropped. (See below for an example.)

This function always allocates memory to hold the resulting path. The variadic overload is guaranteed to only perform a single allocation, as is the range version if paths is a forward range.

Examples

version (Posix)
{
    assert(buildPath("foo", "bar", "baz") == "foo/bar/baz");
    assert(buildPath("/foo/", "bar/baz")  == "/foo/bar/baz");
    assert(buildPath("/foo", "/bar")      == "/bar");
}

version (Windows)
{
    assert(buildPath("foo", "bar", "baz") == `foo\bar\baz`);
    assert(buildPath(`c:\foo`, `bar\baz`) == `c:\foo\bar\baz`);
    assert(buildPath("foo", `d:\bar`)     == `d:\bar`);
    assert(buildPath("foo", `\bar`)       == `\bar`);
    assert(buildPath(`c:\foo`, `\bar`)    == `c:\bar`);
}
@paramsegments An input range of segments to assemble the path from.@returnsThe assembled path.
buildPath
(
(local variable) const(string) root
root
, "inside"));
void std.file.write!string(string name, const(void[]) buffer) @safe

Write buffer to file name.

Creates the file if it does not already exist.

Examples

scope(exit)
{
    assert(exists(deleteme));
    remove(deleteme);
}

int[] a = [ 0, 1, 1, 2, 3, 5, 8 ];
write(deleteme, a); // deleteme is the name of a temporary file
const bytes = read(deleteme);
const fileInts = () @trusted { return cast(int[]) bytes; }();
assert(fileInts == a);
@paramname string or range of characters representing the file name@parambuffer data to be written to file@throwsFileException on error.@seetoFile
write
(
string std.path.buildPath!char(const(char)[][] paths...) pure nothrow @safe

Combines one or more path segments.

This function takes a set of path segments, given as an input range of string elements or as a set of string arguments, and concatenates them with each other. Directory separators are inserted between segments if necessary. If any of the path segments are absolute (as defined by isAbsolute), the preceding segments will be dropped.

On Windows, if one of the path segments are rooted, but not absolute (e.g. \foo), all preceding path segments down to the previous root will be dropped. (See below for an example.)

This function always allocates memory to hold the resulting path. The variadic overload is guaranteed to only perform a single allocation, as is the range version if paths is a forward range.

Examples

version (Posix)
{
    assert(buildPath("foo", "bar", "baz") == "foo/bar/baz");
    assert(buildPath("/foo/", "bar/baz")  == "/foo/bar/baz");
    assert(buildPath("/foo", "/bar")      == "/bar");
}

version (Windows)
{
    assert(buildPath("foo", "bar", "baz") == `foo\bar\baz`);
    assert(buildPath(`c:\foo`, `bar\baz`) == `c:\foo\bar\baz`);
    assert(buildPath("foo", `d:\bar`)     == `d:\bar`);
    assert(buildPath("foo", `\bar`)       == `\bar`);
    assert(buildPath(`c:\foo`, `\bar`)    == `c:\bar`);
}
@paramsegments An input range of segments to assemble the path from.@returnsThe assembled path.
buildPath
(
(local variable) const(string) root
root
, "inside", "file.txt"), "x");
void std.file.symlink!(string, string)(string original, string link) @safe

This function is POSIX-Only.

Creates a symbolic link (symlink).

@paramoriginal The file that is being linked. This is the target path that's stored in the symlink. A relative path is relative to the created symlink.@paramlink The symlink to create. A relative path is relative to the current working directory.@throwsFileException on error (which includes if the symlink already exists).
symlink
("inside",
string std.path.buildPath!char(const(char)[][] paths...) pure nothrow @safe

Combines one or more path segments.

This function takes a set of path segments, given as an input range of string elements or as a set of string arguments, and concatenates them with each other. Directory separators are inserted between segments if necessary. If any of the path segments are absolute (as defined by isAbsolute), the preceding segments will be dropped.

On Windows, if one of the path segments are rooted, but not absolute (e.g. \foo), all preceding path segments down to the previous root will be dropped. (See below for an example.)

This function always allocates memory to hold the resulting path. The variadic overload is guaranteed to only perform a single allocation, as is the range version if paths is a forward range.

Examples

version (Posix)
{
    assert(buildPath("foo", "bar", "baz") == "foo/bar/baz");
    assert(buildPath("/foo/", "bar/baz")  == "/foo/bar/baz");
    assert(buildPath("/foo", "/bar")      == "/bar");
}

version (Windows)
{
    assert(buildPath("foo", "bar", "baz") == `foo\bar\baz`);
    assert(buildPath(`c:\foo`, `bar\baz`) == `c:\foo\bar\baz`);
    assert(buildPath("foo", `d:\bar`)     == `d:\bar`);
    assert(buildPath("foo", `\bar`)       == `\bar`);
    assert(buildPath(`c:\foo`, `\bar`)    == `c:\bar`);
}
@paramsegments An input range of segments to assemble the path from.@returnsThe assembled path.
buildPath
(
(local variable) const(string) root
root
, "link-in")); // relative, stays beneath
void std.file.symlink!(string, string)(string original, string link) @safe

This function is POSIX-Only.

Creates a symbolic link (symlink).

@paramoriginal The file that is being linked. This is the target path that's stored in the symlink. A relative path is relative to the created symlink.@paramlink The symlink to create. A relative path is relative to the current working directory.@throwsFileException on error (which includes if the symlink already exists).
symlink
("/",
string std.path.buildPath!char(const(char)[][] paths...) pure nothrow @safe

Combines one or more path segments.

This function takes a set of path segments, given as an input range of string elements or as a set of string arguments, and concatenates them with each other. Directory separators are inserted between segments if necessary. If any of the path segments are absolute (as defined by isAbsolute), the preceding segments will be dropped.

On Windows, if one of the path segments are rooted, but not absolute (e.g. \foo), all preceding path segments down to the previous root will be dropped. (See below for an example.)

This function always allocates memory to hold the resulting path. The variadic overload is guaranteed to only perform a single allocation, as is the range version if paths is a forward range.

Examples

version (Posix)
{
    assert(buildPath("foo", "bar", "baz") == "foo/bar/baz");
    assert(buildPath("/foo/", "bar/baz")  == "/foo/bar/baz");
    assert(buildPath("/foo", "/bar")      == "/bar");
}

version (Windows)
{
    assert(buildPath("foo", "bar", "baz") == `foo\bar\baz`);
    assert(buildPath(`c:\foo`, `bar\baz`) == `c:\foo\bar\baz`);
    assert(buildPath("foo", `d:\bar`)     == `d:\bar`);
    assert(buildPath("foo", `\bar`)       == `\bar`);
    assert(buildPath(`c:\foo`, `\bar`)    == `c:\bar`);
}
@paramsegments An input range of segments to assemble the path from.@returnsThe assembled path.
buildPath
(
(local variable) const(string) root
root
, "link-out")); // absolute: leaves the root
const
(local variable) const(int) dirfd
dirfd
= open(
int core.sys.posix.fcntl.open64(scope const(char*), int, ...) nothrow @nogc
root
.
immutable(char)* std.string.toStringz(scope const(char)[] s) pure nothrow @trusted

Examples

import core.stdc.string : strlen;
import std.conv : to;

auto p = toStringz("foo");
assert(strlen(p) == 3);
const(char)[] foo = "abbzxyzzy";
p = toStringz(foo[3 .. 5]);
assert(strlen(p) == 2);

string test = "";
p = toStringz(test);
assert(*p == 0);

test = "\0";
p = toStringz(test);
assert(*p == 0);

test = "foo\0";
p = toStringz(test);
assert(p[0] == 'f' && p[1] == 'o' && p[2] == 'o' && p[3] == 0);

const string test2 = "";
p = toStringz(test2);
assert(*p == 0);

assert(toStringz([]) is toStringz(""));
@params A D-style string.@returns

A C-style null-terminated string equivalent to s. s must not contain embedded '\0''s as any C function will treat the first '\0' that it sees as the end of the string. If ``s.empty is true, then a string containing only '\0' is returned.

Important Note: When passing a char* to a C function, and the C function keeps it around for any reason, make sure that you keep a reference to it in your D code. Otherwise, it may become invalid during a garbage collection cycle and cause a nasty bug when the C code tries to use it.

toStringz
,
(constant) int core.sys.posix.fcntl.O_RDONLY = 0
O_RDONLY
|
(constant) int core.sys.posix.fcntl.O_DIRECTORY = 65536
O_DIRECTORY
|
(constant) int core.sys.posix.fcntl.O_CLOEXEC = 524288
O_CLOEXEC
);
assert(
(local variable) const(int) dirfd
dirfd
>= 0);
scope (exit)
int core.sys.posix.unistd.close(int) nothrow @nogc @trusted
close
(
(local variable) const(int) dirfd
dirfd
);
void std.stdio.writeln!string(string __param_0) @safe

Equivalent to write(args, '\n'). Calling writeln without arguments is valid and just prints a newline to the standard output.

Example

Reads stdin and writes it to stdout with an argument counter.

import std.stdio;

void main()
{
    string line;

    for (size_t count = 0; (line = readln) !is null; count++)
    {
         writeln("Input ", count, ": ", line);
    }
}
@paramargs the items to write to stdout@throwsIn case of an I/O error, throws an StdioException.
writeln
("relative to the scratch root:");
void openat2_resolve_flags.report(string label, int dirfd, string path, ulong resolve)
report
("BENEATH",
(local variable) const(int) dirfd
dirfd
, "inside/file.txt",
(constant) int openat2_resolve_flags.RESOLVE_BENEATH = 8
RESOLVE_BENEATH
);
void openat2_resolve_flags.report(string label, int dirfd, string path, ulong resolve)
report
("BENEATH",
(local variable) const(int) dirfd
dirfd
, "inside/../inside/file.txt",
(constant) int openat2_resolve_flags.RESOLVE_BENEATH = 8
RESOLVE_BENEATH
);
void openat2_resolve_flags.report(string label, int dirfd, string path, ulong resolve)
report
("BENEATH",
(local variable) const(int) dirfd
dirfd
, "../",
(constant) int openat2_resolve_flags.RESOLVE_BENEATH = 8
RESOLVE_BENEATH
);
void openat2_resolve_flags.report(string label, int dirfd, string path, ulong resolve)
report
("BENEATH",
(local variable) const(int) dirfd
dirfd
, "/etc",
(constant) int openat2_resolve_flags.RESOLVE_BENEATH = 8
RESOLVE_BENEATH
);
void openat2_resolve_flags.report(string label, int dirfd, string path, ulong resolve)
report
("BENEATH",
(local variable) const(int) dirfd
dirfd
, "link-out/etc",
(constant) int openat2_resolve_flags.RESOLVE_BENEATH = 8
RESOLVE_BENEATH
);
void openat2_resolve_flags.report(string label, int dirfd, string path, ulong resolve)
report
("BENEATH",
(local variable) const(int) dirfd
dirfd
, "link-in/file.txt",
(constant) int openat2_resolve_flags.RESOLVE_BENEATH = 8
RESOLVE_BENEATH
);
void openat2_resolve_flags.report(string label, int dirfd, string path, ulong resolve)
report
("BENEATH|NO_SYMLINKS",
(local variable) const(int) dirfd
dirfd
, "link-in/file.txt",
(constant) int openat2_resolve_flags.RESOLVE_BENEATH = 8
RESOLVE_BENEATH
|
(constant) int openat2_resolve_flags.RESOLVE_NO_SYMLINKS = 4
RESOLVE_NO_SYMLINKS
);
void openat2_resolve_flags.report(string label, int dirfd, string path, ulong resolve)
report
("IN_ROOT",
(local variable) const(int) dirfd
dirfd
, "link-out/inside/file.txt",
(constant) int openat2_resolve_flags.RESOLVE_IN_ROOT = 16
RESOLVE_IN_ROOT
);
// A magic link: `/proc/self/cwd` is not a symlink to a path but a jump to // a kernel object, which is what `RESOLVE_NO_MAGICLINKS` refuses. const
(local variable) const(int) procfd
procfd
= open("/proc/self",
(constant) int core.sys.posix.fcntl.O_RDONLY = 0
O_RDONLY
|
(constant) int core.sys.posix.fcntl.O_DIRECTORY = 65536
O_DIRECTORY
|
(constant) int core.sys.posix.fcntl.O_CLOEXEC = 524288
O_CLOEXEC
);
if (
(local variable) const(int) procfd
procfd
>= 0)
{ scope (exit)
int core.sys.posix.unistd.close(int) nothrow @nogc @trusted
close
(
(local variable) const(int) procfd
procfd
);
void std.stdio.writeln!string(string __param_0) @safe

Equivalent to write(args, '\n'). Calling writeln without arguments is valid and just prints a newline to the standard output.

Example

Reads stdin and writes it to stdout with an argument counter.

import std.stdio;

void main()
{
    string line;

    for (size_t count = 0; (line = readln) !is null; count++)
    {
         writeln("Input ", count, ": ", line);
    }
}
@paramargs the items to write to stdout@throwsIn case of an I/O error, throws an StdioException.
writeln
("relative to /proc/self:");
void openat2_resolve_flags.report(string label, int dirfd, string path, ulong resolve)
report
("(none)",
(local variable) const(int) procfd
procfd
, "cwd", 0);
void openat2_resolve_flags.report(string label, int dirfd, string path, ulong resolve)
report
("NO_MAGICLINKS",
(local variable) const(int) procfd
procfd
, "cwd",
(constant) int openat2_resolve_flags.RESOLVE_NO_MAGICLINKS = 2
RESOLVE_NO_MAGICLINKS
);
void openat2_resolve_flags.report(string label, int dirfd, string path, ulong resolve)
report
("BENEATH",
(local variable) const(int) procfd
procfd
, "cwd",
(constant) int openat2_resolve_flags.RESOLVE_BENEATH = 8
RESOLVE_BENEATH
);
} return 0; }