From: Philip Homburg Date: Thu, 9 Nov 2006 16:22:54 +0000 (+0000) Subject: Getdents implementation in library/vfs/mfs. X-Git-Tag: v3.1.3~146 X-Git-Url: http://zhaoyanbai.com/repos/named-checkzone.html?a=commitdiff_plain;h=ca448f0b0fee530262d92a2497db8c6ea4f5a551;p=minix.git Getdents implementation in library/vfs/mfs. Changed readdir, etc. to use getdents --- diff --git a/include/dirent.h b/include/dirent.h index 097456035..81c031812 100755 --- a/include/dirent.h +++ b/include/dirent.h @@ -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 */ diff --git a/include/minix/callnr.h b/include/minix/callnr.h index c2c62f67c..b776a46bf 100755 --- a/include/minix/callnr.h +++ b/include/minix/callnr.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 */ diff --git a/include/minix/vfsif.h b/include/minix/vfsif.h index c20e2066b..dfacacb44 100644 --- a/include/minix/vfsif.h +++ b/include/minix/vfsif.h @@ -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 diff --git a/lib/other/Makefile.in b/lib/other/Makefile.in index 675661ac4..2a16f371c 100644 --- a/lib/other/Makefile.in +++ b/lib/other/Makefile.in @@ -10,6 +10,7 @@ libc_FILES=" \ _cprofile.c \ _devctl.c \ __pm_findproc.c \ + _getdents.c \ _getnpid.c \ _getsigset.c \ _getnprocnr.c \ diff --git a/lib/other/_getdents.c b/lib/other/_getdents.c new file mode 100755 index 000000000..698ec2b09 --- /dev/null +++ b/lib/other/_getdents.c @@ -0,0 +1,16 @@ +#include +#define getdents _getdents +#include + +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); +} diff --git a/lib/other/_seekdir.c b/lib/other/_seekdir.c index 5e9746428..a341f9dc7 100755 --- a/lib/other/_seekdir.c +++ b/lib/other/_seekdir.c @@ -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; } diff --git a/lib/other/telldir.c b/lib/other/telldir.c index f13ee0135..c6e7c3f63 100755 --- a/lib/other/telldir.c +++ b/lib/other/telldir.c @@ -6,11 +6,22 @@ #include #include #include +#include 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); } diff --git a/lib/posix/_opendir.c b/lib/posix/_opendir.c index 5f174aa95..8ede6e60d 100755 --- a/lib/posix/_opendir.c +++ b/lib/posix/_opendir.c @@ -44,7 +44,6 @@ DIR *opendir(const char *name) } dp->_fd= d; - dp->_v7= -1; dp->_count= 0; dp->_pos= 0; diff --git a/lib/posix/_readdir.c b/lib/posix/_readdir.c index 4187ed573..fa5ef9cf0 100755 --- a/lib/posix/_readdir.c +++ b/lib/posix/_readdir.c @@ -2,58 +2,44 @@ * 24 Apr 1989 */ #define nil 0 -#include -#define read _read -#define readdir _readdir +#define readdir _readdir +#define getdents _getdents #include #include #include #include +#include #include #include #include #include #include -#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 $ + */ diff --git a/lib/syscall/Makefile.in b/lib/syscall/Makefile.in index 82094ba48..306e03e6b 100644 --- a/lib/syscall/Makefile.in +++ b/lib/syscall/Makefile.in @@ -37,6 +37,7 @@ libc_FILES=" \ fstat.s \ fstatfs.s \ getcwd.s \ + getdents.s \ getegid.s \ geteuid.s \ getgid.s \ diff --git a/lib/syscall/getdents.s b/lib/syscall/getdents.s new file mode 100755 index 000000000..38405e167 --- /dev/null +++ b/lib/syscall/getdents.s @@ -0,0 +1,7 @@ +.sect .text +.extern __getdents +.define _getdents +.align 2 + +_getdents: + jmp __getdents diff --git a/servers/mfs/proto.h b/servers/mfs/proto.h index 2ed4d75b9..dd3fbb1ca 100644 --- a/servers/mfs/proto.h +++ b/servers/mfs/proto.h @@ -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); diff --git a/servers/mfs/read.c b/servers/mfs/read.c index 44b1724ec..920c22c1b 100644 --- a/servers/mfs/read.c +++ b/servers/mfs/read.c @@ -2,6 +2,8 @@ #include "fs.h" #include +#include +#include #include #include #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); +} diff --git a/servers/mfs/table.c b/servers/mfs/table.c index cc7fae361..1db0b907d 100644 --- a/servers/mfs/table.c +++ b/servers/mfs/table.c @@ -58,5 +58,6 @@ PUBLIC _PROTOTYPE (int (*fs_call_vec[]), (void) ) = { fs_new_driver, /* 37 */ fs_breadwrite, /* 38 */ fs_breadwrite, /* 39 */ + fs_getdents, /* 40 */ }; diff --git a/servers/pm/table.c b/servers/pm/table.c index d1aaecf3e..35e0d1c9c 100644 --- a/servers/pm/table.c +++ b/servers/pm/table.c @@ -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 */ diff --git a/servers/vfs/proto.h b/servers/vfs/proto.h index 9928e9731..f117a2470 100644 --- a/servers/vfs/proto.h +++ b/servers/vfs/proto.h @@ -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) ); diff --git a/servers/vfs/read.c b/servers/vfs/read.c index 84e3618ef..d860f6ac0 100644 --- a/servers/vfs/read.c +++ b/servers/vfs/read.c @@ -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; +} + + + diff --git a/servers/vfs/request.c b/servers/vfs/request.c index 6849fdb45..cb7bc69a8 100644 --- a/servers/vfs/request.c +++ b/servers/vfs/request.c @@ -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) } - diff --git a/servers/vfs/table.c b/servers/vfs/table.c index aada1f952..09d96bfa0 100644 --- a/servers/vfs/table.c +++ b/servers/vfs/table.c @@ -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 */