Getdents implementation in library/vfs/mfs.
Changed readdir, etc. to use getdents
This commit is contained in:
parent
12eb228aae
commit
ca448f0b0f
@ -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 */
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
16
lib/other/_getdents.c
Executable 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);
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -44,7 +44,6 @@ DIR *opendir(const char *name)
|
||||
}
|
||||
|
||||
dp->_fd= d;
|
||||
dp->_v7= -1;
|
||||
dp->_count= 0;
|
||||
dp->_pos= 0;
|
||||
|
||||
|
@ -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 $
|
||||
*/
|
||||
|
@ -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
7
lib/syscall/getdents.s
Executable file
@ -0,0 +1,7 @@
|
||||
.sect .text
|
||||
.extern __getdents
|
||||
.define _getdents
|
||||
.align 2
|
||||
|
||||
_getdents:
|
||||
jmp __getdents
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -58,5 +58,6 @@ PUBLIC _PROTOTYPE (int (*fs_call_vec[]), (void) ) = {
|
||||
fs_new_driver, /* 37 */
|
||||
fs_breadwrite, /* 38 */
|
||||
fs_breadwrite, /* 39 */
|
||||
fs_getdents, /* 40 */
|
||||
};
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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) );
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -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 */
|
||||
|
Loading…
x
Reference in New Issue
Block a user