diff options
Diffstat (limited to 'libdiskfs/io-read.c')
-rw-r--r-- | libdiskfs/io-read.c | 44 |
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; |