-
-
Notifications
You must be signed in to change notification settings - Fork 753
rangify readLink and symlink #3967
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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!(ElementEncodingType!RO) || | ||
| isConvertibleToString!RO) && | ||
| (isInputRange!RL && isSomeChar!(ElementEncodingType!RL) || | ||
| isConvertibleToString!RL)); | ||
| else version(Posix) void symlink(RO, RL)(RO original, RL link) | ||
| if ((isInputRange!RO && isSomeChar!(ElementEncodingType!RO) || | ||
| isConvertibleToString!RO) && | ||
| (isInputRange!RL && isSomeChar!(ElementEncodingType!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 | ||
|
|
@@ -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.) | ||
|
|
@@ -2376,44 +2398,55 @@ 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 | ||
| { | ||
| static auto trustedReadlink(const(C)[] path, char[] buf) @trusted | ||
| 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 if (isConvertibleToString!R) | ||
| { | ||
| return core.sys.posix.unistd.readlink(path.tempCString(), buf.ptr, buf.length); | ||
| return readLink!(convertToString!R)(link); | ||
| } | ||
| static auto trustedAssumeUnique(ref C[] array) @trusted | ||
| else | ||
| { | ||
| return assumeUnique(array); | ||
| } | ||
|
|
||
| enum bufferLen = 2048; | ||
| enum maxCodeUnits = 6; | ||
| char[bufferLen] buffer; | ||
| auto size = trustedReadlink(link, buffer); | ||
| cenforce(size != -1, link); | ||
|
|
||
| if(size <= bufferLen - maxCodeUnits) | ||
| return to!string(buffer[0 .. size]); | ||
|
|
||
| auto dynamicBuffer = new char[](bufferLen * 3 / 2); | ||
| alias posixReadlink = core.sys.posix.unistd.readlink; | ||
| enum bufferLen = 2048; | ||
| enum maxCodeUnits = 6; | ||
| char[bufferLen] buffer; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How about a test to cover at least > 2048 path case?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I didn't write this, just indented it. Let's fix pre-existing issues separately. |
||
| 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]); | ||
|
|
||
| auto dynamicBuffer = new char[](bufferLen * 3 / 2); | ||
|
|
||
| foreach(i; 0 .. 10) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why 10 ? And then what? At least a comment could help a bit
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ditto. I just indented this. |
||
| { | ||
| size = () @trusted { | ||
| return posixReadlink(linkz, dynamicBuffer.ptr, | ||
| dynamicBuffer.length); | ||
| } (); | ||
| cenforce(size != -1, to!string(link)); | ||
|
|
||
| foreach(i; 0 .. 10) | ||
| { | ||
| size = trustedReadlink(link, dynamicBuffer); | ||
| cenforce(size != -1, link); | ||
| if(size <= dynamicBuffer.length - maxCodeUnits) | ||
| { | ||
| dynamicBuffer.length = size; | ||
| return () @trusted { | ||
| return assumeUnique(dynamicBuffer); | ||
| } (); | ||
| } | ||
|
|
||
| if(size <= dynamicBuffer.length - maxCodeUnits) | ||
| { | ||
| dynamicBuffer.length = size; | ||
| return trustedAssumeUnique(dynamicBuffer); | ||
| dynamicBuffer.length = dynamicBuffer.length * 3 / 2; | ||
| } | ||
|
|
||
| dynamicBuffer.length = dynamicBuffer.length * 3 / 2; | ||
| throw new FileException(to!string(link), "Path is too long to read."); | ||
| } | ||
|
|
||
| throw new FileException(to!string(link), "Path is too long to read."); | ||
| } | ||
|
|
||
| version(Posix) @safe unittest | ||
|
|
@@ -2434,6 +2467,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. | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It made sense that the calls to
tempCStringwere within the@trustedblock before, despitetempCStringitself being mistakenly@trusted. But I guess the unit tests would ensure that this is properly rectified if we decide to fixtempCString.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The
tempCStringcalls must not be@trusted. The types on whichtempCStringis called were more restricted before: only arrays, i.e. no user code. Now it's called on unverified, user-supplied ranges. Calling it in an@trustedblock would make unverified code@trusted.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, of course.