aboutsummaryrefslogtreecommitdiff
path: root/libdiskfs/io-read.c
diff options
context:
space:
mode:
Diffstat (limited to 'libdiskfs/io-read.c')
-rw-r--r--libdiskfs/io-read.c44
1 files changed, 37 insertions, 7 deletions
diff --git a/libdiskfs/io-read.c b/libdiskfs/io-read.c
index a5dd148a..787c0eae 100644
--- a/libdiskfs/io-read.c
+++ b/libdiskfs/io-read.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1994, 1995, 1996 Free Software Foundation
+ Copyright (C) 1994,95,96,97,99,2001 Free Software Foundation
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -29,7 +29,7 @@ diskfs_S_io_read (struct protid *cred,
{
struct node *np;
int err;
- int off = offset;
+ off_t off = offset;
char *buf;
int ourbuf = 0;
@@ -46,6 +46,11 @@ diskfs_S_io_read (struct protid *cred,
if (off == -1)
off = cred->po->filepointer;
+ if (off < 0)
+ {
+ mutex_unlock (&np->lock);
+ return EINVAL;
+ }
if (off > np->dn_stat.st_size)
maxread = 0;
@@ -55,24 +60,49 @@ diskfs_S_io_read (struct protid *cred,
if (maxread > *datalen)
{
ourbuf = 1;
- vm_allocate (mach_task_self (), (u_int *) &buf, maxread, 1);
+ buf = mmap (0, maxread, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
*data = buf;
}
else
buf = *data;
*datalen = maxread;
- if (maxread)
+
+ if (maxread == 0)
+ err = 0;
+ else if (S_ISLNK (np->dn_stat.st_mode))
+ {
+ /* Read from a symlink. */
+ if (! diskfs_read_symlink_hook)
+ err = EINVAL;
+ else
+ {
+ if (off == 0 && maxread == np->dn_stat.st_size)
+ err = (*diskfs_read_symlink_hook)(np, buf);
+ else
+ {
+ char *whole_link = alloca (np->dn_stat.st_size);
+ err = (*diskfs_read_symlink_hook)(np, whole_link);
+ if (! err)
+ memcpy (buf, whole_link + off, maxread);
+ }
+ }
+ }
+ else
+ err = EINVAL; /* Use read below. */
+
+ if (err == EINVAL)
err = _diskfs_rdwr_internal (np, buf, off, datalen, 0,
cred->po->openstat & O_NOATIME);
- else
- err = 0;
+
if (diskfs_synchronous)
diskfs_node_update (np, 1); /* atime! */
+
if (offset == -1 && !err)
cred->po->filepointer += *datalen;
+
if (err && ourbuf)
- vm_deallocate (mach_task_self (), (u_int) buf, maxread);
+ munmap (buf, maxread);
mutex_unlock (&np->lock);
return err;