]> Zhao Yanbai Git Server - minix.git/commitdiff
MFS: getdents fixes
authorThomas Veerman <thomas@minix3.org>
Thu, 26 Jul 2012 12:42:55 +0000 (12:42 +0000)
committerThomas Veerman <thomas@minix3.org>
Mon, 30 Jul 2012 09:44:57 +0000 (09:44 +0000)
.Use a bigger buffer to hold results
.Do not try to store more data than user buffer can hold

servers/mfs/const.h
servers/mfs/read.c

index d651a10cb6cab25ae205644c78765c956ea761da..286ed902170f026d513c6d120fdb2f94fd0a85f2 100644 (file)
@@ -11,7 +11,6 @@
                                 * should be more or less the same as
                                 * NR_VNODES in vfs
                                 */
-#define GETDENTS_BUFSIZ  257
 
 #define INODE_HASH_LOG2   7     /* 2 based logarithm of the inode hash size */
 #define INODE_HASH_SIZE   ((unsigned long)1<<INODE_HASH_LOG2)
index dc2ebd2b259bb90d89840b35398c939dd55ccca7..eccd44f69f7d6207419dce6e33f709b74592b88e 100644 (file)
@@ -17,7 +17,6 @@ static int rw_chunk(struct inode *rip, u64_t position, unsigned off,
        size_t chunk, unsigned left, int rw_flag, cp_grant_id_t gid, unsigned
        buf_off, unsigned int block_size, int *completed);
 
-static char getdents_buf[GETDENTS_BUFSIZ];
 
 /*===========================================================================*
  *                             fs_readwrite                                 *
@@ -538,6 +537,9 @@ unsigned bytes_ahead;               /* bytes beyond position for immediate use */
  *===========================================================================*/
 int fs_getdents(void)
 {
+#define GETDENTS_BUFSIZE       (sizeof(struct dirent) + MFS_NAME_MAX + 1)
+#define GETDENTS_ENTRIES       8
+  static char getdents_buf[GETDENTS_BUFSIZE * GETDENTS_ENTRIES];
   register struct inode *rip;
   int o, r, done;
   unsigned int block_size, len, reclen;
@@ -569,7 +571,7 @@ int fs_getdents(void)
   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 */
+  memset(getdents_buf, '\0', sizeof(getdents_buf));    /* 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
@@ -609,7 +611,19 @@ int fs_getdents(void)
                  /* Need the position of this entry in the directory */
                  ent_pos = block_pos + ((char *) dp - (bp->b_data));
 
-                 if(tmpbuf_off + reclen > GETDENTS_BUFSIZ) {
+               if (userbuf_off + tmpbuf_off + reclen >= size) {
+                         /* The user has no space for one more record */
+                         done = TRUE;
+
+                         /* Record the position of this entry, it is the
+                          * starting point of the next request (unless the
+                          * postion is modified with lseek).
+                          */
+                         new_pos = ent_pos;
+                         break;
+               }
+
+               if (tmpbuf_off + reclen >= GETDENTS_BUFSIZE*GETDENTS_ENTRIES) {
                          r = sys_safecopyto(VFS_PROC_NR, gid,
                                             (vir_bytes) userbuf_off, 
                                             (vir_bytes) getdents_buf,
@@ -621,46 +635,34 @@ int fs_getdents(void)
 
                          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 position 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->mfs_d_ino;
-                 dep->d_off = ent_pos;
-                 dep->d_reclen = (unsigned short) reclen;
-                 memcpy(dep->d_name, dp->mfs_d_name, len);
-                 dep->d_name[len] = '\0';
-                 tmpbuf_off += reclen;
-         }
+               }
+
+               dep = (struct dirent *) &getdents_buf[tmpbuf_off];
+               dep->d_ino = dp->mfs_d_ino;
+               dep->d_off = ent_pos;
+               dep->d_reclen = (unsigned short) reclen;
+               memcpy(dep->d_name, dp->mfs_d_name, len);
+               dep->d_name[len] = '\0';
+               tmpbuf_off += reclen;
+       }
 
-         put_block(bp, DIRECTORY_BLOCK);
-         if(done)
-                 break;
+       put_block(bp, DIRECTORY_BLOCK);
+       if (done)
+               break;
   }
 
-  if(tmpbuf_off != 0) {
-         r = sys_safecopyto(VFS_PROC_NR, gid, (vir_bytes) userbuf_off,
+  if (tmpbuf_off != 0) {
+       r = sys_safecopyto(VFS_PROC_NR, gid, (vir_bytes) userbuf_off,
                             (vir_bytes) getdents_buf, (size_t) tmpbuf_off);
-         if (r != OK) {
-               put_inode(rip);
-               return(r);
-         }
+       if (r != OK) {
+               put_inode(rip);
+               return(r);
+       }
 
-         userbuf_off += tmpbuf_off;
+       userbuf_off += tmpbuf_off;
   }
 
-  if(done && userbuf_off == 0)
+  if (done && userbuf_off == 0)
          r = EINVAL;           /* The user's buffer is too small */
   else {
          fs_m_out.RES_NBYTES = userbuf_off;