mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-01-23 01:32:14 -05:00
LibCore: Add File::read_link() :^)
This is a convenient wrapper around readlink() that hides away the details of buffers and buffer sizes, and simply returns a String. The best part is it doesn't rely on PATH_MAX :D It comes in two versions, for Serenity, where we can pass non-null-terminated strings to syscalls, and where sys$readlink() returns the total link size, and for other systems, where we have to copy out the string, and always have to do two syscalls.
This commit is contained in:
parent
47d83800e1
commit
d89843f96f
Notes:
sideshowbarker
2024-07-19 05:36:53 +09:00
Author: https://github.com/bugaevc Commit: https://github.com/SerenityOS/serenity/commit/d89843f96fa Pull-request: https://github.com/SerenityOS/serenity/pull/2564 Reviewed-by: https://github.com/alimpfard Reviewed-by: https://github.com/awesomekling
2 changed files with 74 additions and 0 deletions
|
@ -24,6 +24,9 @@
|
|||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifdef __serenity__
|
||||
# include <Kernel/Syscall.h>
|
||||
#endif
|
||||
#include <LibCore/File.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
|
@ -129,5 +132,75 @@ String File::real_path_for(const String& filename)
|
|||
return real_path;
|
||||
}
|
||||
|
||||
#ifdef __serenity__
|
||||
|
||||
String File::read_link(const StringView& link_path)
|
||||
{
|
||||
// First, try using a 64-byte buffer, that ought to be enough for anybody.
|
||||
char small_buffer[64];
|
||||
Syscall::SC_readlink_params small_params {
|
||||
{ link_path.characters_without_null_termination(), link_path.length() },
|
||||
{ small_buffer, sizeof(small_buffer) }
|
||||
};
|
||||
int rc = syscall(SC_readlink, &small_params);
|
||||
if (rc < 0) {
|
||||
errno = -rc;
|
||||
return {};
|
||||
}
|
||||
size_t size = rc;
|
||||
// If the call was successful, the syscall (unlike the LibC wrapper)
|
||||
// returns the full size of the link. Let's see if our small buffer
|
||||
// was enough to read the whole link.
|
||||
if (size <= sizeof(small_buffer))
|
||||
return { small_buffer, size };
|
||||
// Nope, but at least now we know the right size.
|
||||
char* large_buffer_ptr;
|
||||
auto large_buffer = StringImpl::create_uninitialized(size, large_buffer_ptr);
|
||||
Syscall::SC_readlink_params large_params {
|
||||
{ link_path.characters_without_null_termination(), link_path.length() },
|
||||
{ large_buffer_ptr, (size_t)size }
|
||||
};
|
||||
rc = syscall(SC_readlink, &large_params);
|
||||
if (rc < 0) {
|
||||
errno = -rc;
|
||||
return {};
|
||||
}
|
||||
size_t new_size = rc;
|
||||
if (new_size == size)
|
||||
return { *large_buffer };
|
||||
|
||||
// If we're here, the symlink has changed while we were looking at it.
|
||||
// If it became shorter, our buffer is valid, we just have to trim it a bit.
|
||||
if (new_size < size)
|
||||
return { large_buffer_ptr, new_size };
|
||||
// Otherwise, here's not much we can do, unless we want to loop endlessly
|
||||
// in this case. Let's leave it up to the caller whether to loop.
|
||||
errno = -EAGAIN;
|
||||
return {};
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
// This is a sad version for other systems. It has to always make a copy of the
|
||||
// link path, and to always make two syscalls to get the right size first.
|
||||
String File::read_link(const StringView& link_path)
|
||||
{
|
||||
String link_path_str = link_path;
|
||||
struct stat statbuf;
|
||||
int rc = lstat(link_path_str.characters(), &statbuf);
|
||||
if (rc < 0)
|
||||
return {};
|
||||
char* buffer_ptr;
|
||||
auto buffer = StringImpl::create_uninitialized(statbuf.st_size, buffer_ptr);
|
||||
rc = readlink(link_path_str.characters(), buffer_ptr, statbuf.st_size);
|
||||
if (rc < 0)
|
||||
return {};
|
||||
// (See above.)
|
||||
if (rc == statbuf.st_size)
|
||||
return { *buffer };
|
||||
return { buffer_ptr, (size_t)rc };
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
|
|
@ -47,6 +47,7 @@ public:
|
|||
|
||||
static bool exists(const String& filename);
|
||||
static String real_path_for(const String& filename);
|
||||
static String read_link(const StringView& link_path);
|
||||
|
||||
virtual bool open(IODevice::OpenMode) override;
|
||||
|
||||
|
|
Loading…
Reference in a new issue