|
@@ -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
|
|
|
|
|
|
}
|