mescc: Mes C Library: Add closedir, opendir, readdir.
authorJan Nieuwenhuizen <janneke@gnu.org>
Sun, 26 Aug 2018 16:34:53 +0000 (18:34 +0200)
committerJan Nieuwenhuizen <janneke@gnu.org>
Sun, 26 Aug 2018 16:34:53 +0000 (18:34 +0200)
* include/dirent.h: New file.  Import from glibc-2.2.5.
* include/dirstream.h: Likewise.
* lib/dirent/__getdirentries.c: Likewise.
* lib/dirent/closedir.c: Likewise.
* lib/dirent/readdir.c (readdir): Likewise.
* lib/libc+gnu.c: Include them.
* include/linux/x86/syscall.h (SYS_getdents): New macro.
* include/linux/x86_64/syscall.h (SYS_getdents): Likewise.
* lib/linux/gnu.c (getdents): New function.
* include/limits.h (NAME_MAX): New macro.
* include/fcntl.h (O_DIRECTORY): New macro.
* scaffold/tests/readdir.dir: New directory.
* scaffold/tests/99-readdir.c: New file, use it.
* build-aux/check-mescc.sh (tests): Run it.

18 files changed:
build-aux/check-mescc.sh
include/dirent.h [new file with mode: 0644]
include/dirstream.h [new file with mode: 0644]
include/fcntl.h
include/limits.h
include/linux/x86/syscall.h
include/linux/x86_64/syscall.h
include/sys/types.h
lib/dirent/__getdirentries.c [new file with mode: 0644]
lib/dirent/closedir.c [new file with mode: 0644]
lib/dirent/opendir.c [new file with mode: 0644]
lib/dirent/readdir.c [new file with mode: 0644]
lib/libc+gnu.c
lib/linux/gnu.c
scaffold/tests/99-readdir.c [new file with mode: 0644]
scaffold/tests/readdir.dir/dir/.keep [new file with mode: 0644]
scaffold/tests/readdir.dir/file [new file with mode: 0644]
scaffold/tests/readdir.dir/link [new symlink]

index 43142fafd7f5a810eff988cd36dad15cea7712dc..26fbcdcb16171d45d1770f7e9189fe204878299b 100755 (executable)
@@ -141,6 +141,7 @@ t
 96-strto
 97-fopen
 98-fopen
+99-readdir
 "
 
 # 90: needs GNU, fails for mescc, passes for tcc
diff --git a/include/dirent.h b/include/dirent.h
new file mode 100644 (file)
index 0000000..cc8be20
--- /dev/null
@@ -0,0 +1,76 @@
+/* -*-comment-start: "//";comment-end:""-*-
+ * GNU Mes --- Maxwell Equations of Software
+ * Copyright (C) 1991, 1992 Free Software Foundation, Inc.
+ * Copyright © 2018 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
+ *
+ * This file is part of GNU Mes.
+ *
+ * GNU Mes is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * GNU Mes is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Mes.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __MES_DIRENT_H
+#define __MES_DIRENT_H 1
+
+#if WITH_GLIBC
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+#undef __MES_DIRENT_H
+#include_next <dirent.h>
+
+#else // ! WITH_GLIBC
+
+#include <dirstream.h>
+
+// Taken from GNU C Library 1.06.4, 2.2.5
+
+/*
+ *     POSIX Standard: 5.1.2 Directory Operations      <dirent.h>
+ */
+
+#include <stddef.h>
+
+int __getdirentries (int filedes, char *buffer, size_t nbytes, off_t *basep);
+
+struct dirent
+  {
+    ino_t d_ino;
+    off_t d_off;
+    unsigned short int d_reclen;
+#if 0
+    unsigned char d_type;
+#endif
+    char d_name[256];          /* We must not include limits.h! */
+  };
+
+/* Open a directory stream on NAME.
+   Return a DIR stream on the directory, or NULL if it could not be opened.  */
+DIR *opendir (char const *name);
+
+/* Close the directory stream DIRP.
+   Return 0 if successful, -1 if not.  */
+int closedir (DIR *dirp);
+
+/* Read a directory entry from DIRP.
+   Return a pointer to a `struct dirent' describing the entry,
+   or NULL for EOF or error.  The storage returned may be overwritten
+   by a later readdir call on the same DIR stream.  */
+struct dirent *readdir (DIR *dirp);
+
+/* Rewind DIRP to the beginning of the directory.  */
+extern void rewinddir (DIR *dirp);
+
+#endif // ! WITH_GLIBC
+
+#endif // __MES_DIRENT_H
diff --git a/include/dirstream.h b/include/dirstream.h
new file mode 100644 (file)
index 0000000..d4c4343
--- /dev/null
@@ -0,0 +1,55 @@
+/* -*-comment-start: "//";comment-end:""-*-
+ * GNU Mes --- Maxwell Equations of Software
+ *Copyright (C) 1993, 1995, 1996 Free Software Foundation, Inc.
+ * Copyright © 2018 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
+ *
+ * This file is part of GNU Mes.
+ *
+ * GNU Mes is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * GNU Mes is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Mes.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __MES_DIRSTREAM_H
+#define __MES_DIRSTREAM_H 1
+
+#if WITH_GLIBC
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+#undef __MES_DIRSTREAM_H
+#include_next <dirstream.h>
+
+#else // ! WITH_GLIBC
+
+#include <sys/types.h>
+
+// Taken from GNU C Library 2.2.5
+
+/* Directory stream type.  */
+struct __dirstream
+  {
+    int fd;                    /* File descriptor.  */
+
+    char *data;                        /* Directory block.  */
+    size_t allocation;         /* Space allocated for the block.  */
+    size_t size;               /* Total valid data in the block.  */
+    size_t offset;             /* Current offset into the block.  */
+
+    off_t filepos;             /* Position of next entry to read.  */
+  };
+
+typedef struct __dirstream DIR;
+
+#endif // ! WITH_GLIBC
+
+#endif // __MES_DIRSTREAM_H
index 2126cc77038853eaabca967502c03d7465d307d4..2980d47b92b5465db002194bbf80907568a7253f 100644 (file)
 
 #else // ! WITH_GLIBC
 
-#define O_RDONLY 0
-#define O_WRONLY 1
-#define O_RDWR 2
-#define O_CREAT 64
-#define O_EXCL 128
-#define O_TRUNC 512
-#define O_APPEND 1024
+#define O_RDONLY          0
+#define O_WRONLY          1
+#define O_RDWR            2
+#define O_CREAT        0x40
+#define O_EXCL         0x80
+#define O_TRUNC       0x200
+#define O_APPEND      0x400
+#define O_DIRECTORY 0x10000
 
 #define FD_CLOEXEC 1
 
index b31007daff42acebcf6259d4784ab67633f85962..c4075606e16afc4a9dbdc3dca9b54673639fdf1f 100644 (file)
@@ -38,6 +38,8 @@
 #define LONG_MIN -2147483648
 #define LONG_MAX 2147483647
 #define _POSIX_OPEN_MAX 16
+#define PATH_MAX 512
+#define NAME_MAX 255
 
 #endif // ! WITH_GLIBC
 
index 1b5639a43c0c353dc24a200e0502503095c282d5..e9fc52dc338477a0abcda01380fa5ff400289a81 100644 (file)
@@ -66,5 +66,6 @@
 #define SYS_setitimer 0x68
 #define SYS_fstat     0x6c
 #define SYS_nanosleep 0xa2
+#define SYS_getdents  0x8d
 
 #endif // __MES_LINUX_X86_SYSCALL_H
index c5b33c338517c3f7ad8bd677aaebb1417652a0f3..be5f23a9734357990d53a10fc63d747ac35ca980 100644 (file)
@@ -63,5 +63,6 @@
 #define SYS_setitimer 0x26
 #define SYS_fstat     0x05
 #define SYS_nanosleep 0x33
+#define SYS_getdents  0x4e
 
 #endif // __MES_LINUX_X86_64_SYSCALL_H
index c4b9ede78d7ffdc19bacfe4deb1a5a7be52c9c2e..1e2f29a62e5da61a32b6f04af534402fcad0be31 100644 (file)
@@ -69,6 +69,12 @@ typedef int gid_t;
 typedef unsigned ino_t;
 #endif
 
+#ifndef __MES_INO64_T
+#define __MES_INO64_T
+#undef ino64_t
+typedef unsigned long long ino64_t;
+#endif
+
 #ifndef __MES_INTPTR_T
 #define __MES_INTPTR_T
 #undef intptr_t
@@ -81,6 +87,12 @@ typedef long intptr_t;
 typedef unsigned long off_t;
 #endif
 
+#ifndef __MES_OFF64_T
+#define __MES_OFF64_T
+#undef off64_t
+typedef unsigned long long off64_t;
+#endif
+
 #ifndef __MES_PID_T
 #define __MES_PID_T
 #undef pid_t
diff --git a/lib/dirent/__getdirentries.c b/lib/dirent/__getdirentries.c
new file mode 100644 (file)
index 0000000..923eedc
--- /dev/null
@@ -0,0 +1,35 @@
+/* -*-comment-start: "//";comment-end:""-*-
+ * GNU Mes --- Maxwell Equations of Software
+ * Copyright (C) 1993 Free Software Foundation, Inc.
+ * Copyright © 2018 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
+ *
+ * This file is part of GNU Mes.
+ *
+ * GNU Mes is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * GNU Mes is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Mes.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+// Taken from GNU C Library 1.06.4
+
+#include <dirent.h>
+#include <stdio.h>
+#include <unistd.h>
+
+int
+__getdirentries (int filedes, char *buffer, size_t nbytes, off_t *basep)
+{
+  if (basep)
+    *basep = lseek (filedes, (off_t) 0, SEEK_CUR);
+
+  return read (filedes, buf, nbytes);
+}
diff --git a/lib/dirent/closedir.c b/lib/dirent/closedir.c
new file mode 100644 (file)
index 0000000..743778e
--- /dev/null
@@ -0,0 +1,54 @@
+/* -*-comment-start: "//";comment-end:""-*-
+ * GNU Mes --- Maxwell Equations of Software
+ * Copyright (C) 1991, 1993, 1995, 1996, 1998 Free Software Foundation, Inc.
+ * Copyright © 2018 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
+ *
+ * This file is part of GNU Mes.
+ *
+ * GNU Mes is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * GNU Mes is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Mes.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+// Taken from GNU C Library 2.2.5
+
+#include <errno.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <dirent.h>
+#include <unistd.h>
+
+#include <errno.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <dirstream.h>
+
+/* Close the directory stream DIRP.
+   Return 0 if successful, -1 if not.  */
+int
+closedir (DIR *dirp)
+{
+  int filedes;
+
+  if (dirp == NULL)
+    {
+      errno = EINVAL;
+      return -1;
+    }
+
+  filedes = dirp->fd;
+  free (dirp);
+
+  return close (filedes);
+}
diff --git a/lib/dirent/opendir.c b/lib/dirent/opendir.c
new file mode 100644 (file)
index 0000000..c0a75c5
--- /dev/null
@@ -0,0 +1,81 @@
+/* -*-comment-start: "//";comment-end:""-*-
+ * GNU Mes --- Maxwell Equations of Software
+ * Copyright (C) 1991-1996,98,2000,2001 Free Software Foundation, Inc.
+ * Copyright © 2018 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
+ *
+ * This file is part of GNU Mes.
+ *
+ * GNU Mes is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * GNU Mes is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Mes.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+// Taken from GNU C Library 2.2.5
+
+#include <errno.h>
+#include <limits.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <stdio.h>
+
+#include <dirstream.h>
+
+/* Open a directory stream on NAME.  */
+DIR *
+opendir (char const *name)
+{
+  DIR *dirp;
+  struct stat statbuf;
+  int fd;
+  size_t allocation;
+  int save_errno;
+
+  if (name[0] == '\0')
+    {
+      /* POSIX.1-1990 says an empty name gets ENOENT;
+        but `open' might like it fine.  */
+      errno = ENOENT;
+      return 0;
+    }
+
+  fd = open (name, O_RDONLY|O_DIRECTORY);
+  if (fd < 0)
+    return 0;
+
+  if (fstat (fd, &statbuf) < 0)
+    goto lose;
+
+  if (fcntl (fd, F_SETFD, FD_CLOEXEC) < 0)
+    goto lose;
+
+  allocation = statbuf.st_blksize;
+
+  dirp = (DIR *) calloc (1, sizeof (DIR) + allocation);
+  if (!dirp)
+  lose:
+    {
+      save_errno = errno;
+      close (fd);
+      errno = save_errno;
+      return 0;
+    }
+  dirp->data = (char *) (dirp + 1);
+  dirp->allocation = allocation;
+  dirp->fd = fd;
+
+  return dirp;
+}
diff --git a/lib/dirent/readdir.c b/lib/dirent/readdir.c
new file mode 100644 (file)
index 0000000..b878397
--- /dev/null
@@ -0,0 +1,85 @@
+/* -*-comment-start: "//";comment-end:""-*-
+ * GNU Mes --- Maxwell Equations of Software
+ * Copyright (C) 1991,92,93,94,95,96,97,99,2000 Free Software Foundation, Inc.
+ * Copyright © 2018 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
+ *
+ * This file is part of GNU Mes.
+ *
+ * GNU Mes is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * GNU Mes is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Mes.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+// Taken from GNU C Library 2.2.5
+
+#include <errno.h>
+#include <limits.h>
+#include <stddef.h>
+#include <string.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <assert.h>
+
+#include <dirstream.h>
+
+/* Read a directory entry from DIRP.  */
+struct dirent *
+readdir (DIR *dirp)
+{
+  struct dirent *dp;
+  int saved_errno = errno;
+
+  do
+    {
+      size_t reclen;
+
+      if (dirp->offset >= dirp->size)
+       {
+         /* We've emptied out our buffer.  Refill it.  */
+
+         size_t maxread;
+         ssize_t bytes;
+
+         maxread = dirp->allocation;
+
+#if 0
+         off_t base;
+         bytes = __getdirentries (dirp->fd, dirp->data, maxread, &base);
+#else
+          bytes = getdents (dirp->fd, dirp->data, maxread);
+#endif
+         if (bytes <= 0)
+           {
+             /* Don't modifiy errno when reaching EOF.  */
+             if (bytes == 0)
+                errno = saved_errno;
+             dp = 0;
+             break;
+           }
+         dirp->size = (size_t) bytes;
+
+         /* Reset the offset into the buffer.  */
+         dirp->offset = 0;
+       }
+
+      dp = (struct dirent *) &dirp->data[dirp->offset];
+
+      reclen = dp->d_reclen;
+      dirp->offset += reclen;
+      dirp->filepos = dp->d_off;
+
+      /* Skip deleted files.  */
+    } while (dp->d_ino == 0);
+
+  return dp;
+}
index 8974e87e15715bf046332fb901f7c5df4d6cfc64..b8096adb8ff106deba63a3763b9e2713a1b81fd4 100644 (file)
@@ -98,3 +98,8 @@
 
 #include <stdlib/__exit.c>
 #include <stub/__cleanup.c>
+
+#include <dirent/__getdirentries.c>
+#include <dirent/closedir.c>
+#include <dirent/opendir.c>
+#include <dirent/readdir.c>
index e756b0605f85788436c867955d3affbb0ce787a5..5fc30f9661c81bfb15d4369ea8e5dc8df57bf9b9 100644 (file)
@@ -145,3 +145,9 @@ fstat (int fd, struct stat *statbuf)
 {
   return _sys_call2 (SYS_fstat, (long)fd, (long)statbuf);
 }
+
+int
+getdents (long filedes, char *buffer, size_t nbytes)
+{
+  return _sys_call3 (SYS_getdents, (long)filedes, (long)buffer, (long)nbytes);
+}
diff --git a/scaffold/tests/99-readdir.c b/scaffold/tests/99-readdir.c
new file mode 100644 (file)
index 0000000..c76fdf9
--- /dev/null
@@ -0,0 +1,110 @@
+/* -*-comment-start: "//";comment-end:""-*-
+ * GNU Mes --- Maxwell Equations of Software
+ * Copyright © 2018 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
+ *
+ * This file is part of GNU Mes.
+ *
+ * GNU Mes is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * GNU Mes is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Mes.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libmes.h>
+#include <string.h>
+#include <dirent.h>
+#include <errno.h>
+
+int
+qsort_strcmp (void const* a, void const* b)
+{
+  return strcmp (*((char**) a), *((char**) b));
+}
+
+int
+main ()
+{
+  DIR *d = opendir ("scaffold/tests/readdir-fu");
+  if (d)
+    return 1;
+  if (errno != ENOENT)
+    return 2;
+
+  d = opendir ("scaffold/tests/99-readdir.c");
+  if (d)
+    return 3;
+  if (errno != ENOTDIR)
+    return 4;
+
+  errno = 0;
+  d = opendir ("scaffold/tests/readdir.dir");
+  if (!d)
+    return 5;
+
+  if (errno)
+    return 6;
+
+  int i = 0;
+  char* list[6] = {0};
+  struct dirent *entry = readdir (d);
+  if (!entry)
+    return 7;
+  oputs (entry->d_name);
+  oputs ("\n");
+  list[i++] = entry->d_name;
+
+  entry = readdir (d);
+  if (!entry)
+    return 8;
+  oputs (entry->d_name);
+  oputs ("\n");
+  list[i++] = entry->d_name;
+
+  entry = readdir (d);
+  if (!entry)
+    return 9;
+  oputs (entry->d_name);
+  oputs ("\n");
+  list[i++] = entry->d_name;
+
+  entry = readdir (d);
+  if (!entry)
+    return 10;
+  oputs (entry->d_name);
+  oputs ("\n");
+  list[i++] = entry->d_name;
+
+  entry = readdir (d);
+  if (!entry)
+    return 11;
+  oputs (entry->d_name);
+  oputs ("\n");
+  list[i++] = entry->d_name;
+
+  entry = readdir (d);
+  if (entry)
+    return 12;
+
+  oputs ("\nls:\n");
+  qsort (list, 5, sizeof (char*), qsort_strcmp);
+  for (int i = 0; i < 5; i++)
+    {
+      oputs (list[i]); oputs ("\n");
+    }
+
+  if (strcmp (list[0], "."))
+    return 13;
+
+  if (strcmp (list[4], "link"))
+    return 14;
+
+  return 0;
+}
diff --git a/scaffold/tests/readdir.dir/dir/.keep b/scaffold/tests/readdir.dir/dir/.keep
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/scaffold/tests/readdir.dir/file b/scaffold/tests/readdir.dir/file
new file mode 100644 (file)
index 0000000..f73f309
--- /dev/null
@@ -0,0 +1 @@
+file
diff --git a/scaffold/tests/readdir.dir/link b/scaffold/tests/readdir.dir/link
new file mode 120000 (symlink)
index 0000000..1a010b1
--- /dev/null
@@ -0,0 +1 @@
+file
\ No newline at end of file