/* 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. */
#define dirfd(dirp) ((dirp)->_fd)
+_PROTOTYPE( int getdents, (int _fildes, struct dirent *_buf,
+ size_t _nbyte) );
+
#endif
#endif /* _DIRENT_H */
#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 */
#define REQ_BREAD 38
#define REQ_BWRITE 39
-#define NREQS 40
+#define REQ_GETDENTS 40
+
+#define NREQS 41
#define FS_READY 57
_cprofile.c \
_devctl.c \
__pm_findproc.c \
+ _getdents.c \
_getnpid.c \
_getsigset.c \
_getnprocnr.c \
--- /dev/null
+#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);
+}
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;
}
#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);
}
}
dp->_fd= d;
- dp->_v7= -1;
dp->_count= 0;
dp->_pos= 0;
* 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;
-
- 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;
+ 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;
+
+ return entp;
}
+
+/*
+ * $PchId: _readdir.c,v 1.6 2005/01/27 21:46:42 philip Exp $
+ */
fstat.s \
fstatfs.s \
getcwd.s \
+ getdents.s \
getegid.s \
geteuid.s \
getgid.s \
--- /dev/null
+.sect .text
+.extern __getdents
+.define _getdents
+.align 2
+
+_getdents:
+ jmp __getdents
int fs_slink(void);
int fs_rdlink(void);
int fs_breadwrite(void);
+int fs_getdents(void);
void init_inode_cache(void);
#include "fs.h"
#include <fcntl.h>
+#include <stddef.h>
+#include <string.h>
#include <unistd.h>
#include <minix/com.h>
#include "buf.h"
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);
+}
fs_new_driver, /* 37 */
fs_breadwrite, /* 38 */
fs_breadwrite, /* 39 */
+ fs_getdents, /* 40 */
};
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 */
/* read.c */
_PROTOTYPE( int do_read, (void) );
+_PROTOTYPE( int do_getdents, (void) );
_PROTOTYPE( int read_write, (int rw_flag) );
/* request.c */
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) );
*
* 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:
}
#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;
+}
+
+
+
}
+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
}
-
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 */