Move struct _uzistat into its own structure, shared between the kernel and
authorDavid Given <dg@cowlark.com>
Thu, 21 Jan 2016 20:37:35 +0000 (21:37 +0100)
committerDavid Given <dg@cowlark.com>
Thu, 21 Jan 2016 20:37:35 +0000 (21:37 +0100)
userspace. stcpy() now copies this safely (avoiding compiler packing gotchas).

Kernel/include/kernel.h
Kernel/include/userstructs.h [new file with mode: 0644]
Kernel/syscall_fs.c
Library/include/syscalls.h

index 84af6d4..7804828 100644 (file)
@@ -174,21 +174,6 @@ typedef struct dinode {
     blkno_t  i_addr[20];
 } dinode;               /* Exactly 64 bytes long! */
 
-struct  stat    /* Really only used by libc */
-{
-       int16_t   st_dev;
-       uint16_t  st_ino;
-       uint16_t  st_mode;
-       uint16_t  st_nlink;
-       uint16_t  st_uid;
-       uint16_t  st_gid;
-       uint16_t  st_rdev;
-       off_t   st_size;
-       uint32_t  st_atime;     /* Break in 2038 */
-       uint32_t  st_mtime;
-       uint32_t  st_ctime;
-};
-
 /* We use the Linux one for compatibility. There's no real Unix 'standard'
    for such things */
 
diff --git a/Kernel/include/userstructs.h b/Kernel/include/userstructs.h
new file mode 100644 (file)
index 0000000..6401de9
--- /dev/null
@@ -0,0 +1,29 @@
+#ifndef _USERSTRUCTURES_H
+#define _USERSTRUCTURES_H
+
+/* Structures shared between kernel and user space.
+ *
+ * Only use explicitly sized types here --- otherwise differing compiler
+ * flags between kernel code and user code can pack them differently.
+ */
+
+struct _uzistat
+{
+       /* Do not change this without also changing stcpy() in syscall_fs.c. */
+
+       int16_t  st_dev;
+       uint16_t st_ino;
+       uint16_t st_mode;
+       uint16_t st_nlink;
+       uint16_t st_uid;
+       uint16_t st_gid;
+       uint16_t st_rdev;
+       uint32_t st_size;
+       uint32_t st_atime;  /* Breaks in 2038 */
+       uint32_t st_mtime;
+       uint32_t st_ctime;
+       uint32_t st_timeh;      /* Time high bytes */
+};
+
+#endif
+
index 2c8056a..c4dd91a 100644 (file)
@@ -2,6 +2,7 @@
 #include <version.h>
 #include <kdata.h>
 #include <printf.h>
+#include <userstructs.h>
 
 void updoff(void)
 {
@@ -134,9 +135,17 @@ arg_t _fstat(void)
 /* Utility for stat and fstat */
 int stcpy(inoptr ino, char *buf)
 {
-       int err = uput((char *) &(ino->c_dev), buf, 12);
-       err |= uput((char *) &(ino->c_node.i_addr[0]), buf + 12, 2);
-       err |= uput((char *) &(ino->c_node.i_size), buf + 14, 16);
+       /* Copying the structure a member at a time is too expensive.  Instead we
+        * copy sequential runs of identical types (the only members which the
+        * compiler guarantees are next to each other). */
+
+       uint32_t zero = 0;
+       struct _uzistat* st = (struct _uzistat*) buf;
+       int err = uput(&ino->c_dev,            &st->st_dev,   2 * sizeof(uint16_t));
+       err |=    uput(&ino->c_node.i_mode,    &st->st_mode,  4 * sizeof(uint16_t));
+       err |=    uput(&ino->c_node.i_addr[0], &st->st_rdev,  1 * sizeof(uint16_t));
+       err |=    uput(&ino->c_node.i_size,    &st->st_size,  4 * sizeof(uint32_t));
+       err |=    uput(&zero,                  &st->st_timeh, 1 * sizeof(uint32_t));
        return err;
 }
 
index 3adde78..96f56a8 100644 (file)
 #endif
 #include <sys/stat.h>
 
+/* TODO: make this less nasty. */
+#include "../../Kernel/include/userstructs.h"
+
 extern int errno;
 extern int syscall(int callno, ...);
 
-struct  _uzistat
-{
-       int16_t    st_dev;
-       uint16_t   st_ino;
-       uint16_t   st_mode;
-       uint16_t   st_nlink;
-       uint16_t   st_uid;
-       uint16_t   st_gid;
-       uint16_t   st_rdev;
-       uint32_t   st_size;
-       uint32_t   st_atime;
-       uint32_t   st_mtime;
-       uint32_t   st_ctime;
-       uint32_t   st_timeh;    /* Time high bytes */
-};
-
 struct _uzisysinfoblk {
   uint8_t infosize;            /* For expandability */
   uint8_t banks;               /* Banks in our 64K (and thus pagesize) */