]> Zhao Yanbai Git Server - minix.git/commitdiff
Getdents implementation in library/vfs/mfs.
authorPhilip Homburg <philip@cs.vu.nl>
Thu, 9 Nov 2006 16:22:54 +0000 (16:22 +0000)
committerPhilip Homburg <philip@cs.vu.nl>
Thu, 9 Nov 2006 16:22:54 +0000 (16:22 +0000)
Changed readdir, etc. to use getdents

19 files changed:
include/dirent.h
include/minix/callnr.h
include/minix/vfsif.h
lib/other/Makefile.in
lib/other/_getdents.c [new file with mode: 0755]
lib/other/_seekdir.c
lib/other/telldir.c
lib/posix/_opendir.c
lib/posix/_readdir.c
lib/syscall/Makefile.in
lib/syscall/getdents.s [new file with mode: 0755]
servers/mfs/proto.h
servers/mfs/read.c
servers/mfs/table.c
servers/pm/table.c
servers/vfs/proto.h
servers/vfs/read.c
servers/vfs/request.c
servers/vfs/table.c

index 097456035ca799b87bf92cb653d5e3b6f74f3c03..81c03181238e2e2a9b7852ff053049444449d1f7 100755 (executable)
@@ -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 */
index c2c62f67cea3d2b8af47d32226b062bb27578a04..b776a46bfabf66e99a3ee02bee13d53b13d2ec83 100755 (executable)
@@ -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 */
index c20e2066bb113a5197da35c4d2eaad9ef255f5dd..dfacacb44d37210ca1866ca8d32513b7abc08168 100644 (file)
 #define REQ_BREAD                38
 #define REQ_BWRITE               39
 
-#define NREQS                    40
+#define REQ_GETDENTS            40
+
+#define NREQS                    41
 
 #define FS_READY                 57
 
index 675661ac4d68aa795caa62e9d5ef8769e4d6f4e8..2a16f371cb6dce80ace540def80105cb3be3e3ad 100644 (file)
@@ -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 (executable)
index 0000000..698ec2b
--- /dev/null
@@ -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);
+}
index 5e9746428bd6c23b74883d6d38b116c5743cac94..a341f9dc746fda504b30f48f07bc438a641ec559 100755 (executable)
@@ -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;
 }
index f13ee0135fb5acaaa4adf264de1a6f6f53112555..c6e7c3f636cf5e9054a5e6f6d4896bc78c1bac1b 100755 (executable)
@@ -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);
 }
index 5f174aa958be70561994e7c98f3cc46ac1158ec6..8ede6e60dc71bb842150b5072cb4b539db0e6277 100755 (executable)
@@ -44,7 +44,6 @@ DIR *opendir(const char *name)
        }
 
        dp->_fd= d;
-       dp->_v7= -1;
        dp->_count= 0;
        dp->_pos= 0;
 
index 4187ed5737926ebcf79bf6b5d0a3f1e61d899f2b..fa5ef9cf01576b79597cf9168ad236d2958de0e0 100755 (executable)
@@ -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;
-
-                       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 $
+ */
index 82094ba48f7a663dee81b4d115fb8ec03d8a0a96..306e03e6b4cba5fa22a0069b1d668a7f3d2d9e4d 100644 (file)
@@ -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 (executable)
index 0000000..38405e1
--- /dev/null
@@ -0,0 +1,7 @@
+.sect .text
+.extern        __getdents
+.define        _getdents
+.align 2
+
+_getdents:
+       jmp     __getdents
index 2ed4d75b951009973d2badf0cffa2152821c08cb..dd3fbb1ca7c1b721bb3b713ccf7acb6d1641d65b 100644 (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);
 
index 44b1724ec83a4d8a944c4df4ca0467b598547499..920c22c1bf6b85cf49ac347320d8fa734a15efe9 100644 (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);
+}
index cc7fae361b6571d000900feb001eb98acf4c8c27..1db0b907d0a325e0e7d4b3ae2a36222bf6dae1b3 100644 (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  */
 };
 
index d1aaecf3e29ea7b029820d6b94c6922dae58ae93..35e0d1c9c2fb2f9c999169704e8d972f5a68e8fd 100644 (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 */
index 9928e9731ee80fc6314c5fd3702272cfb6c38ce4..f117a2470eb7d005080a556964da809fb074bafb 100644 (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)                                       );
index 84e3618efff3be3913a627ebc70f9ed05f362273..d860f6ac0f42245cc4176f454b91bc61bd214e13 100644 (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;
+}
+
+
+
index 6849fdb45457430afa95213383f0be2ef66b3e18..cb7bc69a8d22a47c17e809165057f8294eeb13de 100644 (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)
 }
 
 
-
index aada1f9520c9f85c76b2d5afc7bf26d526ccf87b..09d96bfa0d56a9802b74fd68db25612ecc0288bd 100644 (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 */