aboutsummaryrefslogtreecommitdiff
path: root/libnetfs/io-read.c
diff options
context:
space:
mode:
Diffstat (limited to 'libnetfs/io-read.c')
-rw-r--r--libnetfs/io-read.c65
1 files changed, 52 insertions, 13 deletions
diff --git a/libnetfs/io-read.c b/libnetfs/io-read.c
index 54914935..ff8fbcff 100644
--- a/libnetfs/io-read.c
+++ b/libnetfs/io-read.c
@@ -1,5 +1,5 @@
-/*
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+/*
+ Copyright (C) 1995, 1996, 1997, 1999 Free Software Foundation, Inc.
Written by Michael I. Bushnell, p/BSG.
This file is part of the GNU Hurd.
@@ -21,6 +21,7 @@
#include "netfs.h"
#include "io_S.h"
#include <fcntl.h>
+#include <sys/mman.h>
error_t
netfs_S_io_read (struct protid *user,
@@ -30,41 +31,79 @@ netfs_S_io_read (struct protid *user,
mach_msg_type_number_t amount)
{
error_t err;
+ off_t start;
+ struct node *node;
int alloced = 0;
if (!user)
return EOPNOTSUPP;
+ node = user->po->np;
mutex_lock (&user->po->np->lock);
if ((user->po->openstat & O_READ) == 0)
{
- mutex_unlock (&user->po->np->lock);
+ mutex_unlock (&node->lock);
return EBADF;
}
if (amount > *datalen)
{
alloced = 1;
- vm_allocate (mach_task_self (), (vm_address_t *) data, amount, 1);
+ *data = mmap (0, amount, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
}
*datalen = amount;
- err = netfs_attempt_read (user->credential, user->po->np,
- offset == -1 ? user->po->filepointer : offset,
- datalen, *data);
+ start = (offset == -1 ? user->po->filepointer : offset);
+
+ if (start < 0)
+ err = EINVAL;
+ else if (S_ISLNK (node->nn_stat.st_mode))
+ /* Read from a symlink. */
+ {
+ off_t size = node->nn_stat.st_size;
+
+ if (start + amount > size)
+ amount = size - start;
+ if (amount > size)
+ amount = size;
+
+ if (start >= size)
+ {
+ *datalen = 0;
+ err = 0;
+ }
+ else if (amount < size || start > 0)
+ {
+ char *whole_link = alloca (size);
+ err = netfs_attempt_readlink (user->user, node, whole_link);
+ if (! err)
+ {
+ memcpy (*data, whole_link + start, amount);
+ *datalen = amount;
+ }
+ }
+ else
+ {
+ err = netfs_attempt_readlink (user->user, node, *data);
+ *datalen = amount;
+ }
+ }
+ else
+ /* Read from a normal file. */
+ err = netfs_attempt_read (user->user, node, start, datalen, *data);
+
if (offset == -1 && !err)
user->po->filepointer += *datalen;
- mutex_unlock (&user->po->np->lock);
+
+ mutex_unlock (&node->lock);
if (err && alloced)
- vm_deallocate (mach_task_self (), (vm_address_t) *data, amount);
+ munmap (*data, amount);
if (!err && alloced && (round_page (*datalen) < round_page (amount)))
- vm_deallocate (mach_task_self (),
- (vm_address_t) *data + round_page (*datalen),
- round_page (amount) - round_page (*datalen));
+ munmap (*data + round_page (*datalen),
+ round_page (amount) - round_page (*datalen));
return err;
}
-