summaryrefslogtreecommitdiffstats
path: root/fs/nfs/nfs2xdr.c
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1997-12-06 23:51:34 +0000
committerRalf Baechle <ralf@linux-mips.org>1997-12-06 23:51:34 +0000
commit230e5ab6a084ed50470f101934782dbf54b0d06b (patch)
tree5dd821c8d33f450470588e7a543f74bf74306e9e /fs/nfs/nfs2xdr.c
parentc9b1c8a64c6444d189856f1e26bdcb8b4cd0113a (diff)
Merge with Linux 2.1.67.
Diffstat (limited to 'fs/nfs/nfs2xdr.c')
-rw-r--r--fs/nfs/nfs2xdr.c48
1 files changed, 30 insertions, 18 deletions
diff --git a/fs/nfs/nfs2xdr.c b/fs/nfs/nfs2xdr.c
index 5eec5eb65..0311b7d0b 100644
--- a/fs/nfs/nfs2xdr.c
+++ b/fs/nfs/nfs2xdr.c
@@ -23,6 +23,7 @@
#include <linux/nfs_fs.h>
#define NFSDBG_FACILITY NFSDBG_XDR
+/* #define NFS_PARANOIA 1 */
#define QUADLEN(len) (((len) + 3) >> 2)
static int nfs_stat_to_errno(int stat);
@@ -371,17 +372,18 @@ nfs_xdr_readdirargs(struct rpc_rqst *req, u32 *p, struct nfs_readdirargs *args)
* to avoid a malloc of NFS_MAXNAMLEN+1 for each file name.
* After decoding, the layout in memory looks like this:
* entry1 entry2 ... entryN <space> stringN ... string2 string1
+ * Each entry consists of three __u32 values, the same space as NFS uses.
* Note that the strings are not null-terminated so that the entire number
* of entries returned by the server should fit into the buffer.
*/
static int
nfs_xdr_readdirres(struct rpc_rqst *req, u32 *p, struct nfs_readdirres *res)
{
- struct nfs_entry *entry;
struct iovec *iov = req->rq_rvec;
int status, nr, len;
- char *string;
+ char *string, *start;
u32 *end;
+ __u32 fileid, cookie, *entry;
if ((status = ntohl(*p++)))
return -nfs_stat_to_errno(status);
@@ -396,10 +398,11 @@ nfs_xdr_readdirres(struct rpc_rqst *req, u32 *p, struct nfs_readdirres *res)
end = (u32 *) ((u8 *) p + iov[1].iov_len);
/* Get start and end of dirent buffer */
- entry = (struct nfs_entry *) res->buffer;
+ entry = (__u32 *) res->buffer;
+ start = (char *) res->buffer;
string = (char *) res->buffer + res->bufsiz;
- for (nr = 0; *p++; nr++, entry++) {
- entry->fileid = ntohl(*p++);
+ for (nr = 0; *p++; nr++) {
+ fileid = ntohl(*p++);
len = ntohl(*p++);
if ((p + QUADLEN(len) + 3) > end) {
@@ -413,27 +416,36 @@ nfs_xdr_readdirres(struct rpc_rqst *req, u32 *p, struct nfs_readdirres *res)
return -errno_NFSERR_IO;
}
string -= len;
- if ((void *) (entry+1) > (void *) string) {
- /* This may actually happen because an nfs_entry
- * will take up more space than the XDR data. On
- * 32bit machines that's due to 8byte alignment,
- * on 64bit machines that's because the char * takes
- * up 2 longs.
- *
- * THIS IS BAD!
+ if ((void *) (entry+3) > (void *) string) {
+ /*
+ * This error is impossible as long as the temp
+ * buffer is no larger than the user buffer. The
+ * current packing algorithm uses the same amount
+ * of space in the user buffer as in the XDR data,
+ * so it's guaranteed to fit.
*/
- printk(KERN_NOTICE "NFS: should not happen in %s!\n",
+ printk("NFS: incorrect buffer size in %s!\n",
__FUNCTION__);
break;
}
- entry->name = string;
- entry->length = len;
memmove(string, p, len);
p += QUADLEN(len);
- entry->cookie = ntohl(*p++);
- entry->eof = !p[0] && p[1];
+ cookie = ntohl(*p++);
+ /*
+ * To make everything fit, we encode the length, offset,
+ * and eof flag into 32 bits. This works for filenames
+ * up to 32K and PAGE_SIZE up to 64K.
+ */
+ status = !p[0] && p[1] ? (1 << 15) : 0; /* eof flag */
+ *entry++ = fileid;
+ *entry++ = cookie;
+ *entry++ = ((string - start) << 16) | status | (len & 0x7FFF);
}
+#ifdef NFS_PARANOIA
+printk("nfs_xdr_readdirres: %d entries, ent sp=%d, str sp=%d\n",
+nr, ((char *) entry - start), (start + res->bufsiz - string));
+#endif
return nr;
}