MFS: getdents fixes

.Use a bigger buffer to hold results
.Do not try to store more data than user buffer can hold
This commit is contained in:
Thomas Veerman 2012-07-26 12:42:55 +00:00
parent b6ea15115c
commit fa9199e049
2 changed files with 37 additions and 36 deletions

View File

@ -11,7 +11,6 @@
* should be more or less the same as
* NR_VNODES in vfs
*/
#define GETDENTS_BUFSIZ 257
#define INODE_HASH_LOG2 7 /* 2 based logarithm of the inode hash size */
#define INODE_HASH_SIZE ((unsigned long)1<<INODE_HASH_LOG2)

View File

@ -17,7 +17,6 @@ static int rw_chunk(struct inode *rip, u64_t position, unsigned off,
size_t chunk, unsigned left, int rw_flag, cp_grant_id_t gid, unsigned
buf_off, unsigned int block_size, int *completed);
static char getdents_buf[GETDENTS_BUFSIZ];
/*===========================================================================*
* fs_readwrite *
@ -538,6 +537,9 @@ unsigned bytes_ahead; /* bytes beyond position for immediate use */
*===========================================================================*/
int fs_getdents(void)
{
#define GETDENTS_BUFSIZE (sizeof(struct dirent) + MFS_NAME_MAX + 1)
#define GETDENTS_ENTRIES 8
static char getdents_buf[GETDENTS_BUFSIZE * GETDENTS_ENTRIES];
register struct inode *rip;
int o, r, done;
unsigned int block_size, len, reclen;
@ -569,7 +571,7 @@ int fs_getdents(void)
done = FALSE; /* Stop processing directory blocks when done is set */
tmpbuf_off = 0; /* Offset in getdents_buf */
memset(getdents_buf, '\0', GETDENTS_BUFSIZ); /* Avoid leaking any data */
memset(getdents_buf, '\0', sizeof(getdents_buf)); /* Avoid leaking any data */
userbuf_off = 0; /* Offset in the user's buffer */
/* The default position for the next request is EOF. If the user's buffer
@ -609,7 +611,19 @@ int fs_getdents(void)
/* Need the position of this entry in the directory */
ent_pos = block_pos + ((char *) dp - (bp->b_data));
if(tmpbuf_off + reclen > GETDENTS_BUFSIZ) {
if (userbuf_off + tmpbuf_off + reclen >= size) {
/* The user has no space for one more record */
done = TRUE;
/* Record the position of this entry, it is the
* starting point of the next request (unless the
* postion is modified with lseek).
*/
new_pos = ent_pos;
break;
}
if (tmpbuf_off + reclen >= GETDENTS_BUFSIZE*GETDENTS_ENTRIES) {
r = sys_safecopyto(VFS_PROC_NR, gid,
(vir_bytes) userbuf_off,
(vir_bytes) getdents_buf,
@ -621,46 +635,34 @@ int fs_getdents(void)
userbuf_off += tmpbuf_off;
tmpbuf_off = 0;
}
if(userbuf_off + tmpbuf_off + reclen > size) {
/* The user has no space for one more record */
done = TRUE;
/* Record the position of this entry, it is the
* starting point of the next request (unless the
* postion is modified with lseek).
*/
new_pos = ent_pos;
break;
}
}
dep = (struct dirent *) &getdents_buf[tmpbuf_off];
dep->d_ino = dp->mfs_d_ino;
dep->d_off = ent_pos;
dep->d_reclen = (unsigned short) reclen;
memcpy(dep->d_name, dp->mfs_d_name, len);
dep->d_name[len] = '\0';
tmpbuf_off += reclen;
}
dep = (struct dirent *) &getdents_buf[tmpbuf_off];
dep->d_ino = dp->mfs_d_ino;
dep->d_off = ent_pos;
dep->d_reclen = (unsigned short) reclen;
memcpy(dep->d_name, dp->mfs_d_name, len);
dep->d_name[len] = '\0';
tmpbuf_off += reclen;
}
put_block(bp, DIRECTORY_BLOCK);
if(done)
break;
put_block(bp, DIRECTORY_BLOCK);
if (done)
break;
}
if(tmpbuf_off != 0) {
r = sys_safecopyto(VFS_PROC_NR, gid, (vir_bytes) userbuf_off,
if (tmpbuf_off != 0) {
r = sys_safecopyto(VFS_PROC_NR, gid, (vir_bytes) userbuf_off,
(vir_bytes) getdents_buf, (size_t) tmpbuf_off);
if (r != OK) {
put_inode(rip);
return(r);
}
if (r != OK) {
put_inode(rip);
return(r);
}
userbuf_off += tmpbuf_off;
userbuf_off += tmpbuf_off;
}
if(done && userbuf_off == 0)
if (done && userbuf_off == 0)
r = EINVAL; /* The user's buffer is too small */
else {
fs_m_out.RES_NBYTES = userbuf_off;