Getdents implementation in library/vfs/mfs.

Changed readdir, etc. to use getdents
This commit is contained in:
Philip Homburg 2006-11-09 16:22:54 +00:00
parent 12eb228aae
commit ca448f0b0f
19 changed files with 303 additions and 59 deletions

View File

@ -59,20 +59,23 @@ struct _v7_direct {
/* Definitions for the directory(3) routines: */
typedef struct {
char _fd; /* Filedescriptor of open directory */
char _v7; /* Directory is Version 7 */
short _count; /* This many objects in buf */
off_t _pos; /* Position in directory file */
struct _fl_direct *_ptr; /* Next slot in buf */
struct _fl_direct _buf[_FLEX_PER_BLOCK]; /* One block of a directory file */
struct _fl_direct _v7f[_FLEX_PER_V7]; /* V7 entry transformed to flex */
unsigned _count; /* This many bytes in _buf */
unsigned _pos; /* Position in _buf */
char _buf[_MAX_BLOCK_SIZE]; /* The size does not really
* matter as long as the
* buffer is big enough
* to contain at least one
* entry.
*/
} DIR;
#define _DIRENT_NAME_LEN 61
struct dirent { /* Largest entry (8 slots) */
ino_t d_ino; /* I-node number */
unsigned char d_extent; /* Extended with this many slots */
char d_name[_DIRENT_NAME_LEN]; /* Null terminated name */
off_t d_off; /* Offset in directory */
unsigned short d_reclen; /* Length of this record */
char d_name[1]; /* Null terminated name */
};
/* Function Prototypes. */
@ -87,6 +90,9 @@ _PROTOTYPE( off_t telldir, (DIR *_dirp) );
#define dirfd(dirp) ((dirp)->_fd)
_PROTOTYPE( int getdents, (int _fildes, struct dirent *_buf,
size_t _nbyte) );
#endif
#endif /* _DIRENT_H */

View File

@ -64,6 +64,7 @@
#define SVRCTL 77
#define SYSUNAME 78
#define GETSYSINFO 79 /* to PM or FS */
#define GETDENTS 80 /* to FS */
#define FSTATFS 82 /* to FS */
#define SELECT 85 /* to FS */
#define FCHDIR 86 /* to FS */

View File

@ -128,7 +128,9 @@
#define REQ_BREAD 38
#define REQ_BWRITE 39
#define NREQS 40
#define REQ_GETDENTS 40
#define NREQS 41
#define FS_READY 57

View File

@ -10,6 +10,7 @@ libc_FILES=" \
_cprofile.c \
_devctl.c \
__pm_findproc.c \
_getdents.c \
_getnpid.c \
_getsigset.c \
_getnprocnr.c \

16
lib/other/_getdents.c Executable file
View File

@ -0,0 +1,16 @@
#include <lib.h>
#define getdents _getdents
#include <dirent.h>
PUBLIC ssize_t getdents(fd, buffer, nbytes)
int fd;
struct dirent *buffer;
size_t nbytes;
{
message m;
m.m1_i1 = fd;
m.m1_i2 = nbytes;
m.m1_p1 = (char *) buffer;
return _syscall(FS, GETDENTS, &m);
}

View File

@ -19,14 +19,8 @@ int seekdir(DIR *dp, off_t pos)
if (dp == nil) { errno= EBADF; return -1; }
dp->_count= 0;
dp->_ptr= dp->_buf;
off= pos & (sizeof(dp->_buf) - 1);
dp->_pos= pos - off;
if (lseek(dp->_fd, dp->_pos, SEEK_SET) == -1) return -1;
while (dp->_pos < pos && readdir(dp) != nil) {}
if (lseek(dp->_fd, pos, SEEK_SET) == -1) return -1;
return 0;
}

View File

@ -6,11 +6,22 @@
#include <sys/types.h>
#include <dirent.h>
#include <errno.h>
#include <unistd.h>
off_t telldir(DIR *dp)
/* Return the current read position in a directory. */
{
struct dirent *dep;
if (dp == nil) { errno= EBADF; return -1; }
return dp->_pos;
if (dp->_pos < dp->_count)
{
/* Use position in next entry */
dep= (struct dirent *)&dp->_buf[dp->_pos];
return dep->d_off;
}
/* Get current offset in directory */
return lseek(dp->_fd, 0, SEEK_CUR);
}

View File

@ -44,7 +44,6 @@ DIR *opendir(const char *name)
}
dp->_fd= d;
dp->_v7= -1;
dp->_count= 0;
dp->_pos= 0;

View File

@ -2,58 +2,44 @@
* 24 Apr 1989
*/
#define nil 0
#include <lib.h>
#define read _read
#define readdir _readdir
#define readdir _readdir
#define getdents _getdents
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <unistd.h>
#include <stddef.h>
#include <stdlib.h>
#include <fcntl.h>
#include <limits.h>
#include <errno.h>
#include <string.h>
#define v7ent(p) ((struct _v7_direct *) (p))
#define V7_EXTENT (sizeof(struct _v7_direct) / sizeof(struct _fl_direct) - 1)
struct dirent *readdir(DIR *dp)
/* Return the next entry in a directory. Handle V7 and FLEX format dirs. */
/* Return the next entry in a directory. */
{
struct dirent *e;
struct dirent *entp;
int count, pos, reclen;
if (dp == nil) { errno= EBADF; return nil; }
do {
if (dp->_count <= 0) {
/* Read the next directory block. */
dp->_count= read(dp->_fd, dp->_buf, sizeof(dp->_buf));
if (dp->_count <= 0) return nil;
count= dp->_count;
pos= dp->_pos;
if (count == 0 || pos >= count)
{
count= getdents(dp->_fd, (struct dirent *)dp->_buf,
sizeof(dp->_buf));
if (count <= 0) return nil;
dp->_count= count;
dp->_pos= pos= 0;
}
entp= (struct dirent *)&((char *)dp->_buf)[pos];
reclen= entp->d_reclen;
dp->_pos= pos+reclen;
dp->_count/= sizeof(dp->_buf[0]);
dp->_ptr= dp->_buf;
/* Extent is zero of the first flex entry. */
if (dp->_v7 == (char)-1) dp->_v7= dp->_buf[0].d_extent;
}
if (!dp->_v7) {
/* FLEX. */
e= (struct dirent *) dp->_ptr;
} else {
/* V7: transform to FLEX. */
e= (struct dirent *) dp->_v7f;
e->d_ino= v7ent(dp->_ptr)->d_ino;
e->d_extent= V7_EXTENT;
memcpy(e->d_name, v7ent(dp->_ptr)->d_name, DIRSIZ);
e->d_name[DIRSIZ]= 0;
}
dp->_ptr+= 1 + e->d_extent;
dp->_count-= 1 + e->d_extent;
dp->_pos+= (1 + e->d_extent) * sizeof(*dp->_ptr);
} while (e->d_ino == 0);
return e;
return entp;
}
/*
* $PchId: _readdir.c,v 1.6 2005/01/27 21:46:42 philip Exp $
*/

View File

@ -37,6 +37,7 @@ libc_FILES=" \
fstat.s \
fstatfs.s \
getcwd.s \
getdents.s \
getegid.s \
geteuid.s \
getgid.s \

7
lib/syscall/getdents.s Executable file
View File

@ -0,0 +1,7 @@
.sect .text
.extern __getdents
.define _getdents
.align 2
_getdents:
jmp __getdents

View File

@ -46,6 +46,7 @@ int lookup(void);
int fs_slink(void);
int fs_rdlink(void);
int fs_breadwrite(void);
int fs_getdents(void);
void init_inode_cache(void);

View File

@ -2,6 +2,8 @@
#include "fs.h"
#include <fcntl.h>
#include <stddef.h>
#include <string.h>
#include <unistd.h>
#include <minix/com.h>
#include "buf.h"
@ -556,3 +558,155 @@ unsigned bytes_ahead; /* bytes beyond position for immediate use */
return(get_block(dev, baseblock, NORMAL));
}
#define GETDENTS_BUFSIZ 257
PRIVATE char getdents_buf[GETDENTS_BUFSIZ];
/*===========================================================================*
* fs_getdents *
*===========================================================================*/
PUBLIC int fs_getdents(void)
{
register struct inode *rip;
int o, r, block_size, len, reclen, done;
ino_t ino;
block_t b;
cp_grant_id_t gid;
size_t size, tmpbuf_off, userbuf_off;
off_t pos, off, block_pos, new_pos, ent_pos;
struct buf *bp;
struct direct *dp;
struct dirent *dep;
char *cp;
ino= fs_m_in.REQ_GDE_INODE;
gid= fs_m_in.REQ_GDE_GRANT;
size= fs_m_in.REQ_GDE_SIZE;
pos= fs_m_in.REQ_GDE_POS;
/* Check whether the position is properly aligned */
if (pos % DIR_ENTRY_SIZE)
return ENOENT;
if ( (rip = get_inode(fs_dev, ino)) == NIL_INODE) {
printf("MFS(%d) get_inode by fs_getdents() failed\n", SELF_E);
return(EINVAL);
}
block_size= rip->i_sp->s_block_size;
off= (pos % block_size); /* Offset in block */
block_pos= pos-off;
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 */
userbuf_off= 0; /* Offset in the user's buffer */
/* The default position for the next request is EOF. If the user's buffer
* fills up before EOF, new_pos will be modified.
*/
new_pos= rip->i_size;
for (; block_pos < rip->i_size; block_pos += block_size) {
b = read_map(rip, block_pos); /* get block number */
/* Since directories don't have holes, 'b' cannot be NO_BLOCK. */
bp = get_block(rip->i_dev, b, NORMAL); /* get a dir block */
if (bp == NO_BLOCK)
panic(__FILE__,"get_block returned NO_BLOCK", NO_NUM);
/* Search a directory block. */
if (block_pos < pos)
dp = &bp->b_dir[off / DIR_ENTRY_SIZE];
else
dp = &bp->b_dir[0];
for (; dp < &bp->b_dir[NR_DIR_ENTRIES(block_size)]; dp++) {
if (dp->d_ino == 0)
continue; /* Entry is not in use */
/* Compute the length of the name */
cp= memchr(dp->d_name, '\0', NAME_MAX);
if (cp == NULL)
len= NAME_MAX;
else
len= cp-dp->d_name;
/* Compute record length */
reclen= offsetof(struct dirent, d_name) + len + 1;
o= (reclen % sizeof(long));
if (o != 0)
reclen += sizeof(long)-o;
/* Need the postition of this entry in the directory */
ent_pos= block_pos + ((char *)dp - bp->b_data);
if (tmpbuf_off + reclen > GETDENTS_BUFSIZ)
{
r= sys_safecopyto(FS_PROC_NR, gid, userbuf_off,
(vir_bytes)getdents_buf, tmpbuf_off, D);
if (r != OK)
{
panic(__FILE__,
"fs_getdents: sys_safecopyto failed\n",
r);
}
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 postion 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->d_ino;
dep->d_off= ent_pos;
dep->d_reclen= reclen;
memcpy(dep->d_name, dp->d_name, len);
dep->d_name[len]= '\0';
tmpbuf_off += reclen;
}
put_block(bp, DIRECTORY_BLOCK);
if (done)
break;
}
if (tmpbuf_off != 0)
{
r= sys_safecopyto(FS_PROC_NR, gid, userbuf_off,
(vir_bytes)getdents_buf, tmpbuf_off, D);
if (r != OK)
panic(__FILE__, "fs_getdents: sys_safecopyto failed\n", r);
userbuf_off += tmpbuf_off;
}
r= ENOSYS;
fs_m_out.RES_GDE_POS_CHANGE= 0; /* No change in case of an error */
if (done && userbuf_off == 0)
r= EINVAL; /* The user's buffer is too small */
else
{
r= userbuf_off;
if (new_pos >= pos)
fs_m_out.RES_GDE_POS_CHANGE= new_pos-pos;
}
put_inode(rip); /* release the inode */
return(r);
}

View File

@ -58,5 +58,6 @@ PUBLIC _PROTOTYPE (int (*fs_call_vec[]), (void) ) = {
fs_new_driver, /* 37 */
fs_breadwrite, /* 38 */
fs_breadwrite, /* 39 */
fs_getdents, /* 40 */
};

View File

@ -95,7 +95,7 @@ _PROTOTYPE (int (*call_vec[NCALLS]), (void) ) = {
do_svrctl, /* 77 = svrctl */
do_sysuname, /* 78 = sysuname */
do_getsysinfo, /* 79 = getsysinfo */
no_sys, /* 80 = unused */
no_sys, /* 80 = (getdents) */
no_sys, /* 81 = unused */
no_sys, /* 82 = (fstatfs) */
no_sys, /* 83 = unused */

View File

@ -122,6 +122,7 @@ _PROTOTYPE( int do_umask, (void) );
/* read.c */
_PROTOTYPE( int do_read, (void) );
_PROTOTYPE( int do_getdents, (void) );
_PROTOTYPE( int read_write, (int rw_flag) );
/* request.c */
@ -165,6 +166,8 @@ _PROTOTYPE( int req_newdriver, (endpoint_t fs_e, Dev_t dev,
endpoint_t driver_e) );
_PROTOTYPE( int req_breadwrite, (breadwrite_req_t *req,
readwrite_res_t *res) );
_PROTOTYPE( int req_getdents, (endpoint_t fs_e, ino_t inode_nr,
off_t pos, cp_grant_id_t gid, size_t size, off_t *pos_change) );
/* stadir.c */
_PROTOTYPE( int do_chdir, (void) );

View File

@ -5,6 +5,7 @@
*
* The entry points into this file are
* do_read: perform the READ system call by calling read_write
* do_getdents: read entries from a directory (GETDENTS)
* read_write: actually do the work of READ and WRITE
*
* Changes for VFS:
@ -290,3 +291,43 @@ int rw_flag; /* READING or WRITING */
}
#endif
/*===========================================================================*
* do_getdents *
*===========================================================================*/
PUBLIC int do_getdents()
{
/* Perform the getdents(fd, buf, size) system call. */
int r;
off_t pos_change;
cp_grant_id_t gid;
register struct filp *rfilp;
/* Is the file descriptor valid? */
if ( (rfilp = get_filp(m_in.fd)) == NIL_FILP) {
return(err_code);
}
if (!(rfilp->filp_mode & R_BIT))
return EBADF;
if ((rfilp->filp_vno->v_mode & I_TYPE) != I_DIRECTORY)
return EBADF;
gid=cpf_grant_magic(rfilp->filp_vno->v_fs_e, who_e, (vir_bytes) m_in.buffer,
m_in.nbytes, CPF_WRITE);
if (gid < 0) panic(__FILE__, "cpf_grant_magic failed", gid);
/* Issue request */
r= req_getdents(rfilp->filp_vno->v_fs_e, rfilp->filp_vno->v_inode_nr,
rfilp->filp_pos, gid, m_in.nbytes, &pos_change);
cpf_revoke(gid);
if (r > 0)
rfilp->filp_pos += pos_change;
return r;
}

View File

@ -831,6 +831,27 @@ readwrite_res_t *res;
}
PUBLIC int req_getdents(fs_e, inode_nr, pos, gid, size, pos_change)
endpoint_t fs_e;
ino_t inode_nr;
off_t pos;
cp_grant_id_t gid;
size_t size;
off_t *pos_change;
{
int r;
message m;
m.m_type= REQ_GETDENTS;
m.REQ_GDE_INODE= inode_nr;
m.REQ_GDE_GRANT= gid;
m.REQ_GDE_SIZE= size;
m.REQ_GDE_POS= pos;
r = fs_sendrec(fs_e, &m);
*pos_change= m.RES_GDE_POS_CHANGE;
return r;
}
#if 0
@ -951,4 +972,3 @@ PUBLIC int fs_sendrec(endpoint_t fs_e, message *reqm)
}

View File

@ -98,7 +98,7 @@ PUBLIC _PROTOTYPE (int (*call_vec[]), (void) ) = {
no_sys, /* 78 = (sysuname) */
do_getsysinfo, /* 79 = getsysinfo */
no_sys, /* 80 = unused */
do_getdents, /* 80 = getdents */
no_sys, /* 81 = unused */
do_fstatfs, /* 82 = fstatfs */
no_sys, /* 83 = unused */