mirror of
https://github.com/RGBCube/serenity
synced 2025-05-20 02:55:07 +00: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
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.
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#ifdef __serenity__
|
||||||
|
# include <Kernel/Syscall.h>
|
||||||
|
#endif
|
||||||
#include <LibCore/File.h>
|
#include <LibCore/File.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
@ -129,5 +132,75 @@ String File::real_path_for(const String& filename)
|
||||||
return real_path;
|
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 bool exists(const String& filename);
|
||||||
static String real_path_for(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;
|
virtual bool open(IODevice::OpenMode) override;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue