[PATCH v2 10/12] mini-os: add struct file_ops for file type socket

Juergen Gross posted 12 patches 4 months, 1 week ago
[PATCH v2 10/12] mini-os: add struct file_ops for file type socket
Posted by Juergen Gross 4 months, 1 week ago
Even with some special handling needed in select_poll(), add a struct
file_ops for FTYPE_SOCKET. Due to the need of the special handling it
isn't possible to use a dynamically allocated file type.

Most functions calling the file_ops methods can be simplified a lot now
that no file type specific handling is left. Same applies to the file
type name printing in debug/verbose mode.

Signed-off-by: Juergen Gross <jgross@suse.com>
---
 lib/sys.c | 153 +++++++++++++++++++++++++-----------------------------
 1 file changed, 70 insertions(+), 83 deletions(-)

diff --git a/lib/sys.c b/lib/sys.c
index 3a8aa68..12deaed 100644
--- a/lib/sys.c
+++ b/lib/sys.c
@@ -99,11 +99,70 @@ static struct file_ops file_ops_none = {
     .name = "none",
 };
 
+#ifdef HAVE_LWIP
+static int socket_read(int fd, void *buf, size_t nbytes)
+{
+    return lwip_read(fd, buf, nbytes);
+}
+
+static int socket_write(int fd, const void *buf, size_t nbytes)
+{
+    return lwip_write(fd, (void *)buf, nbytes);
+}
+
+static int close_socket_fd(int fd)
+{
+    struct file *file = get_file_from_fd(fd);
+
+    return lwip_close(file->fd);
+}
+
+static int socket_fstat(int fd, struct stat *buf)
+{
+    buf->st_mode = S_IFSOCK | S_IRUSR | S_IWUSR;
+    buf->st_atime = buf->st_mtime = buf->st_ctime = time(NULL);
+
+    return 0;
+}
+
+static int socket_fcntl(int fd, int cmd, va_list args)
+{
+    long arg;
+    struct file *file = get_file_from_fd(fd);
+
+    arg = va_arg(args, long);
+
+    if ( cmd == F_SETFL && !(arg & ~O_NONBLOCK) )
+    {
+        /* Only flag supported: non-blocking mode */
+        uint32_t nblock = !!(arg & O_NONBLOCK);
+
+        return lwip_ioctl(file->fd, FIONBIO, &nblock);
+    }
+
+    printk("fcntl(%d, %d, %lx/%lo)\n", fd, cmd, arg, arg);
+    errno = ENOSYS;
+    return -1;
+}
+
+static struct file_ops socket_ops = {
+    .name = "socket",
+    .read = socket_read,
+    .write = socket_write,
+    .close = close_socket_fd,
+    .fstat = socket_fstat,
+    .fcntl = socket_fcntl,
+};
+#endif
+
 static struct file_ops *file_ops[FTYPE_N + FTYPE_SPARE] = {
     [FTYPE_NONE] = &file_ops_none,
 #ifdef CONFIG_CONSFRONT
     [FTYPE_CONSOLE] = &console_ops,
 #endif
+#ifdef HAVE_LWIP
+    [FTYPE_SOCKET] = &socket_ops,
+#endif
 };
 
 unsigned int alloc_file_type(struct file_ops *ops)
@@ -282,14 +341,6 @@ int read(int fd, void *buf, size_t nbytes)
     if ( ops->read )
         return ops->read(fd, buf, nbytes);
 
-    switch (files[fd].type) {
-#ifdef HAVE_LWIP
-	case FTYPE_SOCKET:
-	    return lwip_read(files[fd].fd, buf, nbytes);
-#endif
-	default:
-	    break;
-    }
     printk("read(%d): Bad descriptor\n", fd);
     errno = EBADF;
     return -1;
@@ -302,14 +353,6 @@ int write(int fd, const void *buf, size_t nbytes)
     if ( ops->write )
         return ops->write(fd, buf, nbytes);
 
-    switch (files[fd].type) {
-#ifdef HAVE_LWIP
-	case FTYPE_SOCKET:
-	    return lwip_write(files[fd].fd, (void*) buf, nbytes);
-#endif
-	default:
-	    break;
-    }
     printk("write(%d): Bad descriptor\n", fd);
     errno = EBADF;
     return -1;
@@ -378,26 +421,14 @@ int close(int fd)
 
     printk("close(%d)\n", fd);
     if ( ops->close )
-    {
         res = ops->close(fd);
-        goto out;
-    }
-
-    switch (files[fd].type) {
-        default:
-            break;
-#ifdef HAVE_LWIP
-	case FTYPE_SOCKET:
-	    res = lwip_close(files[fd].fd);
-            break;
-#endif
-	case FTYPE_NONE:
-            printk("close(%d): Bad descriptor\n", fd);
-            errno = EBADF;
-            return -1;
+    else if ( files[fd].type == FTYPE_NONE )
+    {
+        printk("close(%d): Bad descriptor\n", fd);
+        errno = EBADF;
+        return -1;
     }
 
- out:
     memset(files + fd, 0, sizeof(struct file));
     files[fd].type = FTYPE_NONE;
     return res;
@@ -429,21 +460,6 @@ int fstat(int fd, struct stat *buf)
     if ( ops->fstat )
         return ops->fstat(fd, buf);
 
-    switch (files[fd].type) {
-	case FTYPE_SOCKET: {
-            buf->st_mode = S_IFSOCK|S_IRUSR|S_IWUSR;
-	    buf->st_uid = 0;
-	    buf->st_gid = 0;
-	    buf->st_size = 0;
-	    buf->st_atime = 
-	    buf->st_mtime = 
-	    buf->st_ctime = time(NULL);
-	    return 0;
-	}
-	default:
-	    break;
-    }
-
     printk("statf(%d): Bad descriptor\n", fd);
     errno = EBADF;
     return -1;
@@ -491,21 +507,9 @@ int fcntl(int fd, int cmd, ...)
     arg = va_arg(ap, long);
     va_end(ap);
 
-    switch (cmd) {
-#ifdef HAVE_LWIP
-	case F_SETFL:
-	    if (files[fd].type == FTYPE_SOCKET && !(arg & ~O_NONBLOCK)) {
-		/* Only flag supported: non-blocking mode */
-		uint32_t nblock = !!(arg & O_NONBLOCK);
-		return lwip_ioctl(files[fd].fd, FIONBIO, &nblock);
-	    }
-	    /* Fallthrough */
-#endif
-	default:
-	    printk("fcntl(%d, %d, %lx/%lo)\n", fd, cmd, arg, arg);
-	    errno = ENOSYS;
-	    return -1;
-    }
+    printk("fcntl(%d, %d, %lx/%lo)\n", fd, cmd, arg, arg);
+    errno = ENOSYS;
+    return -1;
 }
 
 DIR *opendir(const char *name)
@@ -539,23 +543,6 @@ int closedir(DIR *dir)
 
 /* We assume that only the main thread calls select(). */
 
-#if defined(LIBC_DEBUG) || defined(LIBC_VERBOSE)
-static const char *file_types[] = {
-    [FTYPE_NONE]    = "none",
-    [FTYPE_SOCKET]  = "socket",
-};
-
-static char *get_type_name(unsigned int type)
-{
-    if ( type < ARRAY_SIZE(file_ops) && file_ops[type] )
-        return file_ops[type]->name;
-
-    if ( type < ARRAY_SIZE(file_types) && file_types[type] )
-        return file_types[type];
-
-    return "none";
-}
-#endif
 #ifdef LIBC_DEBUG
 static void dump_set(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout)
 {
@@ -566,7 +553,7 @@ static void dump_set(int nfds, fd_set *readfds, fd_set *writefds, fd_set *except
 	if (FD_ISSET(i, set)) { \
 	    if (comma) \
 		printk(", "); \
-	    printk("%d(%s)", i, get_type_name(files[i].type)); \
+	    printk("%d(%s)", i, get_file_ops(files[i].type)->name); \
 	    comma = 1; \
 	} \
     } \
@@ -600,7 +587,7 @@ static void dump_pollfds(struct pollfd *pfd, int nfds, int timeout)
         fd = pfd[i].fd;
         if (comma)
             printk(", ");
-        printk("%d(%s)/%02x", fd, get_type_name(files[fd].type),
+        printk("%d(%s)/%02x", fd, get_file_ops(files[fd].type)->name,
             pfd[i].events);
             comma = 1;
     }
@@ -754,7 +741,7 @@ static int select_poll(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exce
 	printk("%d(%d): ", nb, sock_n);
 	for (i = 0; i < nfds; i++) {
 	    if (nbread[i] || nbwrite[i] || nbexcept[i])
-		printk(" %d(%c):", i, get_type_name(files[i].type));
+		printk(" %d(%c):", i, get_file_ops(files[i].type)->name);
 	    if (nbread[i])
 	    	printk(" %dR", nbread[i]);
 	    if (nbwrite[i])
-- 
2.26.2


Re: [PATCH v2 10/12] mini-os: add struct file_ops for file type socket
Posted by Samuel Thibault 4 months, 1 week ago
Juergen Gross, le mar. 11 janv. 2022 16:12:13 +0100, a ecrit:
> Even with some special handling needed in select_poll(), add a struct
> file_ops for FTYPE_SOCKET. Due to the need of the special handling it
> isn't possible to use a dynamically allocated file type.
> 
> Most functions calling the file_ops methods can be simplified a lot now
> that no file type specific handling is left. Same applies to the file
> type name printing in debug/verbose mode.
> 
> Signed-off-by: Juergen Gross <jgross@suse.com>

modulo the int fd / file * thing,

Reviewed-by: Samuel Thibault <samuel.thibault@ens-lyon.org>

> ---
>  lib/sys.c | 153 +++++++++++++++++++++++++-----------------------------
>  1 file changed, 70 insertions(+), 83 deletions(-)
> 
> diff --git a/lib/sys.c b/lib/sys.c
> index 3a8aa68..12deaed 100644
> --- a/lib/sys.c
> +++ b/lib/sys.c
> @@ -99,11 +99,70 @@ static struct file_ops file_ops_none = {
>      .name = "none",
>  };
>  
> +#ifdef HAVE_LWIP
> +static int socket_read(int fd, void *buf, size_t nbytes)
> +{
> +    return lwip_read(fd, buf, nbytes);
> +}
> +
> +static int socket_write(int fd, const void *buf, size_t nbytes)
> +{
> +    return lwip_write(fd, (void *)buf, nbytes);
> +}
> +
> +static int close_socket_fd(int fd)
> +{
> +    struct file *file = get_file_from_fd(fd);
> +
> +    return lwip_close(file->fd);
> +}
> +
> +static int socket_fstat(int fd, struct stat *buf)
> +{
> +    buf->st_mode = S_IFSOCK | S_IRUSR | S_IWUSR;
> +    buf->st_atime = buf->st_mtime = buf->st_ctime = time(NULL);
> +
> +    return 0;
> +}
> +
> +static int socket_fcntl(int fd, int cmd, va_list args)
> +{
> +    long arg;
> +    struct file *file = get_file_from_fd(fd);
> +
> +    arg = va_arg(args, long);
> +
> +    if ( cmd == F_SETFL && !(arg & ~O_NONBLOCK) )
> +    {
> +        /* Only flag supported: non-blocking mode */
> +        uint32_t nblock = !!(arg & O_NONBLOCK);
> +
> +        return lwip_ioctl(file->fd, FIONBIO, &nblock);
> +    }
> +
> +    printk("fcntl(%d, %d, %lx/%lo)\n", fd, cmd, arg, arg);
> +    errno = ENOSYS;
> +    return -1;
> +}
> +
> +static struct file_ops socket_ops = {
> +    .name = "socket",
> +    .read = socket_read,
> +    .write = socket_write,
> +    .close = close_socket_fd,
> +    .fstat = socket_fstat,
> +    .fcntl = socket_fcntl,
> +};
> +#endif
> +
>  static struct file_ops *file_ops[FTYPE_N + FTYPE_SPARE] = {
>      [FTYPE_NONE] = &file_ops_none,
>  #ifdef CONFIG_CONSFRONT
>      [FTYPE_CONSOLE] = &console_ops,
>  #endif
> +#ifdef HAVE_LWIP
> +    [FTYPE_SOCKET] = &socket_ops,
> +#endif
>  };
>  
>  unsigned int alloc_file_type(struct file_ops *ops)
> @@ -282,14 +341,6 @@ int read(int fd, void *buf, size_t nbytes)
>      if ( ops->read )
>          return ops->read(fd, buf, nbytes);
>  
> -    switch (files[fd].type) {
> -#ifdef HAVE_LWIP
> -	case FTYPE_SOCKET:
> -	    return lwip_read(files[fd].fd, buf, nbytes);
> -#endif
> -	default:
> -	    break;
> -    }
>      printk("read(%d): Bad descriptor\n", fd);
>      errno = EBADF;
>      return -1;
> @@ -302,14 +353,6 @@ int write(int fd, const void *buf, size_t nbytes)
>      if ( ops->write )
>          return ops->write(fd, buf, nbytes);
>  
> -    switch (files[fd].type) {
> -#ifdef HAVE_LWIP
> -	case FTYPE_SOCKET:
> -	    return lwip_write(files[fd].fd, (void*) buf, nbytes);
> -#endif
> -	default:
> -	    break;
> -    }
>      printk("write(%d): Bad descriptor\n", fd);
>      errno = EBADF;
>      return -1;
> @@ -378,26 +421,14 @@ int close(int fd)
>  
>      printk("close(%d)\n", fd);
>      if ( ops->close )
> -    {
>          res = ops->close(fd);
> -        goto out;
> -    }
> -
> -    switch (files[fd].type) {
> -        default:
> -            break;
> -#ifdef HAVE_LWIP
> -	case FTYPE_SOCKET:
> -	    res = lwip_close(files[fd].fd);
> -            break;
> -#endif
> -	case FTYPE_NONE:
> -            printk("close(%d): Bad descriptor\n", fd);
> -            errno = EBADF;
> -            return -1;
> +    else if ( files[fd].type == FTYPE_NONE )
> +    {
> +        printk("close(%d): Bad descriptor\n", fd);
> +        errno = EBADF;
> +        return -1;
>      }
>  
> - out:
>      memset(files + fd, 0, sizeof(struct file));
>      files[fd].type = FTYPE_NONE;
>      return res;
> @@ -429,21 +460,6 @@ int fstat(int fd, struct stat *buf)
>      if ( ops->fstat )
>          return ops->fstat(fd, buf);
>  
> -    switch (files[fd].type) {
> -	case FTYPE_SOCKET: {
> -            buf->st_mode = S_IFSOCK|S_IRUSR|S_IWUSR;
> -	    buf->st_uid = 0;
> -	    buf->st_gid = 0;
> -	    buf->st_size = 0;
> -	    buf->st_atime = 
> -	    buf->st_mtime = 
> -	    buf->st_ctime = time(NULL);
> -	    return 0;
> -	}
> -	default:
> -	    break;
> -    }
> -
>      printk("statf(%d): Bad descriptor\n", fd);
>      errno = EBADF;
>      return -1;
> @@ -491,21 +507,9 @@ int fcntl(int fd, int cmd, ...)
>      arg = va_arg(ap, long);
>      va_end(ap);
>  
> -    switch (cmd) {
> -#ifdef HAVE_LWIP
> -	case F_SETFL:
> -	    if (files[fd].type == FTYPE_SOCKET && !(arg & ~O_NONBLOCK)) {
> -		/* Only flag supported: non-blocking mode */
> -		uint32_t nblock = !!(arg & O_NONBLOCK);
> -		return lwip_ioctl(files[fd].fd, FIONBIO, &nblock);
> -	    }
> -	    /* Fallthrough */
> -#endif
> -	default:
> -	    printk("fcntl(%d, %d, %lx/%lo)\n", fd, cmd, arg, arg);
> -	    errno = ENOSYS;
> -	    return -1;
> -    }
> +    printk("fcntl(%d, %d, %lx/%lo)\n", fd, cmd, arg, arg);
> +    errno = ENOSYS;
> +    return -1;
>  }
>  
>  DIR *opendir(const char *name)
> @@ -539,23 +543,6 @@ int closedir(DIR *dir)
>  
>  /* We assume that only the main thread calls select(). */
>  
> -#if defined(LIBC_DEBUG) || defined(LIBC_VERBOSE)
> -static const char *file_types[] = {
> -    [FTYPE_NONE]    = "none",
> -    [FTYPE_SOCKET]  = "socket",
> -};
> -
> -static char *get_type_name(unsigned int type)
> -{
> -    if ( type < ARRAY_SIZE(file_ops) && file_ops[type] )
> -        return file_ops[type]->name;
> -
> -    if ( type < ARRAY_SIZE(file_types) && file_types[type] )
> -        return file_types[type];
> -
> -    return "none";
> -}
> -#endif
>  #ifdef LIBC_DEBUG
>  static void dump_set(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout)
>  {
> @@ -566,7 +553,7 @@ static void dump_set(int nfds, fd_set *readfds, fd_set *writefds, fd_set *except
>  	if (FD_ISSET(i, set)) { \
>  	    if (comma) \
>  		printk(", "); \
> -	    printk("%d(%s)", i, get_type_name(files[i].type)); \
> +	    printk("%d(%s)", i, get_file_ops(files[i].type)->name); \
>  	    comma = 1; \
>  	} \
>      } \
> @@ -600,7 +587,7 @@ static void dump_pollfds(struct pollfd *pfd, int nfds, int timeout)
>          fd = pfd[i].fd;
>          if (comma)
>              printk(", ");
> -        printk("%d(%s)/%02x", fd, get_type_name(files[fd].type),
> +        printk("%d(%s)/%02x", fd, get_file_ops(files[fd].type)->name,
>              pfd[i].events);
>              comma = 1;
>      }
> @@ -754,7 +741,7 @@ static int select_poll(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exce
>  	printk("%d(%d): ", nb, sock_n);
>  	for (i = 0; i < nfds; i++) {
>  	    if (nbread[i] || nbwrite[i] || nbexcept[i])
> -		printk(" %d(%c):", i, get_type_name(files[i].type));
> +		printk(" %d(%c):", i, get_file_ops(files[i].type)->name);
>  	    if (nbread[i])
>  	    	printk(" %dR", nbread[i]);
>  	    if (nbwrite[i])
> -- 
> 2.26.2
> 

-- 
Samuel
Running Windows on a Pentium is like having a brand new Porsche but only
be able to drive backwards with the handbrake on.
(Unknown source)

Re: [PATCH v2 10/12] mini-os: add struct file_ops for file type socket
Posted by Andrew Cooper 4 months, 1 week ago
On 11/01/2022 15:12, Juergen Gross wrote:
> +static int socket_write(int fd, const void *buf, size_t nbytes)
> +{
> +    return lwip_write(fd, (void *)buf, nbytes);

This void cast was bogus before, and can be dropped.  lwip_write()
already takes a const pointer.

~Andrew

Re: [PATCH v2 10/12] mini-os: add struct file_ops for file type socket
Posted by Juergen Gross 4 months, 1 week ago
On 12.01.22 12:25, Andrew Cooper wrote:
> On 11/01/2022 15:12, Juergen Gross wrote:
>> +static int socket_write(int fd, const void *buf, size_t nbytes)
>> +{
>> +    return lwip_write(fd, (void *)buf, nbytes);
> 
> This void cast was bogus before, and can be dropped.  lwip_write()
> already takes a const pointer.

Okay.


Juergen

Re: [PATCH v2 10/12] mini-os: add struct file_ops for file type socket
Posted by Andrew Cooper 4 months, 1 week ago
On 11/01/2022 15:12, Juergen Gross wrote:
> diff --git a/lib/sys.c b/lib/sys.c
> index 3a8aa68..12deaed 100644
> --- a/lib/sys.c
> +++ b/lib/sys.c
> @@ -99,11 +99,70 @@ static struct file_ops file_ops_none = {
>      .name = "none",
>  };
>  
> +#ifdef HAVE_LWIP
> +static int socket_read(int fd, void *buf, size_t nbytes)
> +{
> +    return lwip_read(fd, buf, nbytes);
> +}
> +
> +static int socket_write(int fd, const void *buf, size_t nbytes)
> +{
> +    return lwip_write(fd, (void *)buf, nbytes);
> +}
> +
> +static int close_socket_fd(int fd)
> +{
> +    struct file *file = get_file_from_fd(fd);
> +
> +    return lwip_close(file->fd);
> +}

Actually, on further thoughts...

> +static struct file_ops socket_ops = {
> +    .name = "socket",
> +    .read = socket_read,
> +    .write = socket_write,
> +    .close = close_socket_fd,
> +    .fstat = socket_fstat,
> +    .fcntl = socket_fcntl,
> +};

read, write and close should dispatch directly to lwip_* and not bounce
through a no-op local function.

~Andrew

Re: [PATCH v2 10/12] mini-os: add struct file_ops for file type socket
Posted by Juergen Gross 4 months, 1 week ago
On 12.01.22 12:28, Andrew Cooper wrote:
> On 11/01/2022 15:12, Juergen Gross wrote:
>> diff --git a/lib/sys.c b/lib/sys.c
>> index 3a8aa68..12deaed 100644
>> --- a/lib/sys.c
>> +++ b/lib/sys.c
>> @@ -99,11 +99,70 @@ static struct file_ops file_ops_none = {
>>       .name = "none",
>>   };
>>   
>> +#ifdef HAVE_LWIP
>> +static int socket_read(int fd, void *buf, size_t nbytes)
>> +{
>> +    return lwip_read(fd, buf, nbytes);
>> +}
>> +
>> +static int socket_write(int fd, const void *buf, size_t nbytes)
>> +{
>> +    return lwip_write(fd, (void *)buf, nbytes);
>> +}
>> +
>> +static int close_socket_fd(int fd)
>> +{
>> +    struct file *file = get_file_from_fd(fd);
>> +
>> +    return lwip_close(file->fd);
>> +}
> 
> Actually, on further thoughts...
> 
>> +static struct file_ops socket_ops = {
>> +    .name = "socket",
>> +    .read = socket_read,
>> +    .write = socket_write,
>> +    .close = close_socket_fd,
>> +    .fstat = socket_fstat,
>> +    .fcntl = socket_fcntl,
>> +};
> 
> read, write and close should dispatch directly to lwip_* and not bounce
> through a no-op local function.

Not with changing the first parameter to struct file *.

BTW, this patch had a bug, as the calls need to use file->fd instead of
fd.


Juergen
Re: [PATCH v2 10/12] mini-os: add struct file_ops for file type socket
Posted by Andrew Cooper 4 months, 1 week ago
On 12/01/2022 11:32, Juergen Gross wrote:
> On 12.01.22 12:28, Andrew Cooper wrote:
>> On 11/01/2022 15:12, Juergen Gross wrote:
>>> diff --git a/lib/sys.c b/lib/sys.c
>>> index 3a8aa68..12deaed 100644
>>> --- a/lib/sys.c
>>> +++ b/lib/sys.c
>>> @@ -99,11 +99,70 @@ static struct file_ops file_ops_none = {
>>>       .name = "none",
>>>   };
>>>   +#ifdef HAVE_LWIP
>>> +static int socket_read(int fd, void *buf, size_t nbytes)
>>> +{
>>> +    return lwip_read(fd, buf, nbytes);
>>> +}
>>> +
>>> +static int socket_write(int fd, const void *buf, size_t nbytes)
>>> +{
>>> +    return lwip_write(fd, (void *)buf, nbytes);
>>> +}
>>> +
>>> +static int close_socket_fd(int fd)
>>> +{
>>> +    struct file *file = get_file_from_fd(fd);
>>> +
>>> +    return lwip_close(file->fd);
>>> +}
>>
>> Actually, on further thoughts...
>>
>>> +static struct file_ops socket_ops = {
>>> +    .name = "socket",
>>> +    .read = socket_read,
>>> +    .write = socket_write,
>>> +    .close = close_socket_fd,
>>> +    .fstat = socket_fstat,
>>> +    .fcntl = socket_fcntl,
>>> +};
>>
>> read, write and close should dispatch directly to lwip_* and not bounce
>> through a no-op local function.
>
> Not with changing the first parameter to struct file *.

Oh, good point.

>
> BTW, this patch had a bug, as the calls need to use file->fd instead of
> fd.

Yay for multiple fd spaces.

~Andrew

Re: [PATCH v2 10/12] mini-os: add struct file_ops for file type socket
Posted by Samuel Thibault 4 months, 1 week ago
Juergen Gross, le mar. 11 janv. 2022 16:12:13 +0100, a ecrit:
> +static int socket_fstat(int fd, struct stat *buf)
> +{
> +    buf->st_mode = S_IFSOCK | S_IRUSR | S_IWUSR;
> +    buf->st_atime = buf->st_mtime = buf->st_ctime = time(NULL);
> +
> +    return 0;
> +}

Similarly, this seems to be missing setting st_uid, st_gid, st_size?

Samuel