Skip to content

Commit

Permalink
rangify readLink and symlink
Browse files Browse the repository at this point in the history
Removing @safe from the signatures so that attribute inference takes
care of things. There are @safe unittests already, ensuring that the
functions themselves don't do anything unsafe.

Replacing @trusted declarations with @trusted function literals. This
way it's more clear that the specific call is @trusted, not the called
function.
  • Loading branch information
aG0aep6G committed Apr 26, 2016
1 parent f6f1197 commit dce9175
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 23 deletions.
2 changes: 2 additions & 0 deletions changelog.dd
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ $(BUGSTITLE Library Changes,
of the type being iterated)
$(LI $(XREF algorithm, sorting, isStrictlyMonotonic) which doesn't allow
equal values was added.)
$(LI $(REF readLink, std,file) and $(REF symlink, std,file) have been
rangified.)
)

$(BUGSTITLE Library Changes,
Expand Down
101 changes: 78 additions & 23 deletions std/file.d
Original file line number Diff line number Diff line change
Expand Up @@ -2310,15 +2310,31 @@ unittest
$(D FileException) on error (which includes if the _symlink already
exists).
+/
version(StdDdoc) void symlink(C1, C2)(const(C1)[] original, const(C2)[] link) @safe;
else version(Posix) void symlink(C1, C2)(const(C1)[] original, const(C2)[] link) @safe
{
static auto trustedSymlink(const(C1)[] path1, const(C2)[] path2) @trusted
version(StdDdoc) void symlink(RO, RL)(RO original, RL link)
if ((isInputRange!RO && isSomeChar!(ElementType!RO) ||
isConvertibleToString!RO) &&
(isInputRange!RL && isSomeChar!(ElementType!RL) ||
isConvertibleToString!RL));
else version(Posix) void symlink(RO, RL)(RO original, RL link)
if ((isInputRange!RO && isSomeChar!(ElementType!RO) ||
isConvertibleToString!RO) &&
(isInputRange!RL && isSomeChar!(ElementType!RL) ||
isConvertibleToString!RL))
{
static if (isConvertibleToString!RO || isConvertibleToString!RL)
{
import std.meta : staticMap;
alias Types = staticMap!(convertToString, RO, RL);
symlink!Types(original, link);
}
else
{
return core.sys.posix.unistd.symlink(path1.tempCString(),
path2.tempCString());
auto oz = original.tempCString();
auto lz = link.tempCString();
alias posixSymlink = core.sys.posix.unistd.symlink;
immutable int result = () @trusted {return posixSymlink(oz, lz);} ();
cenforce(result == 0, text(link));
}
cenforce(trustedSymlink(original, link) == 0, link);
}

version(Posix) @safe unittest
Expand Down Expand Up @@ -2364,6 +2380,12 @@ version(Posix) @safe unittest
}
}

version(Posix) unittest
{
static assert(__traits(compiles,
symlink(TestAliasedString(null), TestAliasedString(null))));
}


/++
$(BLUE This function is Posix-Only.)
Expand All @@ -2376,23 +2398,22 @@ version(Posix) @safe unittest
Throws:
$(D FileException) on error.
+/
version(StdDdoc) string readLink(C)(const(C)[] link) @safe;
else version(Posix) string readLink(C)(const(C)[] link) @safe
version(StdDdoc) string readLink(R)(R link)
if (isInputRange!R && isSomeChar!(ElementEncodingType!R) &&
!isConvertibleToString!R);
else version(Posix) string readLink(R)(R link)
if (isInputRange!R && isSomeChar!(ElementEncodingType!R) &&
!isConvertibleToString!R)
{
static auto trustedReadlink(const(C)[] path, char[] buf) @trusted
{
return core.sys.posix.unistd.readlink(path.tempCString(), buf.ptr, buf.length);
}
static auto trustedAssumeUnique(ref C[] array) @trusted
{
return assumeUnique(array);
}

alias posixReadlink = core.sys.posix.unistd.readlink;
enum bufferLen = 2048;
enum maxCodeUnits = 6;
char[bufferLen] buffer;
auto size = trustedReadlink(link, buffer);
cenforce(size != -1, link);
const linkz = link.tempCString();
auto size = () @trusted {
return posixReadlink(linkz, buffer.ptr, buffer.length);
} ();
cenforce(size != -1, to!string(link));

if(size <= bufferLen - maxCodeUnits)
return to!string(buffer[0 .. size]);
Expand All @@ -2401,13 +2422,17 @@ else version(Posix) string readLink(C)(const(C)[] link) @safe

foreach(i; 0 .. 10)
{
size = trustedReadlink(link, dynamicBuffer);
cenforce(size != -1, link);
size = () @trusted {
return posixReadlink(linkz, dynamicBuffer.ptr, dynamicBuffer.length);
} ();
cenforce(size != -1, to!string(link));

if(size <= dynamicBuffer.length - maxCodeUnits)
{
dynamicBuffer.length = size;
return trustedAssumeUnique(dynamicBuffer);
return () @trusted {
return assumeUnique(dynamicBuffer);
} ();
}

dynamicBuffer.length = dynamicBuffer.length * 3 / 2;
Expand All @@ -2416,6 +2441,15 @@ else version(Posix) string readLink(C)(const(C)[] link) @safe
throw new FileException(to!string(link), "Path is too long to read.");
}

/// ditto
version(StdDdoc) string readLink(R)(R link)
if (isConvertibleToString!R);
else version(Posix) string readLink(R)(R link)
if (isConvertibleToString!R)
{
return readLink!(StringTypeOf!R)(link);
}

version(Posix) @safe unittest
{
import std.string;
Expand All @@ -2434,6 +2468,27 @@ version(Posix) @safe unittest
assertThrown!FileException(readLink("/doesnotexist"));
}

version(Posix) @safe unittest
{
static assert(__traits(compiles, readLink(TestAliasedString("foo"))));
}

version(Posix) unittest // input range of dchars
{
mkdirRecurse(deleteme);
scope(exit) if(deleteme.exists) rmdirRecurse(deleteme);
write(deleteme ~ "/f", "");
import std.range.interfaces: InputRange, inputRangeObject;
import std.utf: byChar;
immutable string link = deleteme ~ "/l";
symlink("f", link);
InputRange!dchar linkr = inputRangeObject(link);
alias R = typeof(linkr);
static assert(isInputRange!R);
static assert(!isForwardRange!R);
assert(readLink(linkr) == "f");
}


/****************************************************
* Get the current working directory.
Expand Down

0 comments on commit dce9175

Please sign in to comment.