Added and implemented Silc DIR API.
authorPekka Riikonen <priikone@silcnet.org>
Tue, 15 Jan 2008 17:52:24 +0000 (17:52 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Tue, 15 Jan 2008 17:52:24 +0000 (17:52 +0000)
CHANGES.RUNTIME
TODO
configure.ad
includes/silc.h.in
includes/silcwin32.h
lib/silcutil/silcdir.h [new file with mode: 0644]
lib/silcutil/silcerrno.h
lib/silcutil/tests/Makefile.am
lib/silcutil/tests/test_silcdir.c [new file with mode: 0644]
lib/silcutil/unix/Makefile.am
lib/silcutil/unix/silcunixdir.c [new file with mode: 0644]

index 400f6eb34de6874246ab97ecba4ea932932c945e..e916899844116e371b79547e70b01106981df8d8 100644 (file)
@@ -1,3 +1,9 @@
+Tue Jan 15 19:44:36 EET 2008  Pekka Riikonen <priikone@silcnet.org>
+
+       * Added SILC Dir API to lib/silcutil/silcdir.h.  Implemented it
+         for Unix (POSIX).  Affected files are lib/silcutil/silcdir.h,
+         lib/silcutil/unix/silcunixdir.c.
+
 Sun Jan 13 17:11:26 EET 2008  Pekka Riikonen <priikone@silcnet.org>
 
        * Added silc_buffer_memcmp and silc_buffer_tail.  Fixed SilcBuffer
diff --git a/TODO b/TODO
index 569d4dd8232edb4f9502f29b375c49de5dece085..9ae2702568d95075169fb8a366e0b8448ea3fefe 100644 (file)
--- a/TODO
+++ b/TODO
@@ -97,10 +97,6 @@ Runtime library, lib/silcutil/
 
  o Fix universal time decoding (doesn't accept all formats) in silctime.c.
 
- o Add directory opening/traversing functions
-
- o regex from /lib/contrib to lib/silcutil, define SILC Regex API. (***DONE)
-
  o Additional scheduler changes: optimize silc_schedule_wakeup.  Wakeup
    only if the scheduler is actually waiting something.  If it is
    delivering tasks wakeup is not needed.
@@ -111,6 +107,10 @@ Runtime library, lib/silcutil/
    SILC currently supports SOCKS4 and SOCKS5 but it needs to be compiled
    in separately.
 
+ o Add directory opening/traversing functions (***DONE, TODO Windows & Symbian)
+
+ o regex from /lib/contrib to lib/silcutil, define SILC Regex API. (***DONE)
+
  o Add functions to manipulate environment variables. (***DONE)
 
  o Add functions to loading shared/dynamic object symbols (replaces the
index 7467c0c32bd0dff107c1160aae33bcee52036806..a162625abcec1e1d736b10ac98c1d637e88310d4 100644 (file)
@@ -3,7 +3,7 @@
 #
 #  Author: Pekka Riikonen <priikone@silcnet.org>
 #
-#  Copyright (C) 2000 - 2007 Pekka Riikonen
+#  Copyright (C) 2000 - 2008 Pekka Riikonen
 #
 #  This program is free software; you can redistribute it and/or modify
 #  it under the terms of the GNU General Public License as published by
@@ -228,7 +228,7 @@ AC_CHECK_HEADERS(unistd.h string.h errno.h fcntl.h assert.h)
 AC_CHECK_HEADERS(sys/types.h sys/stat.h sys/time.h stddef.h)
 AC_CHECK_HEADERS(netinet/in.h netinet/tcp.h xti.h netdb.h sys/resource.h)
 AC_CHECK_HEADERS(pwd.h grp.h termcap.h paths.h)
-AC_CHECK_HEADERS(ncurses.h signal.h ctype.h utime.h)
+AC_CHECK_HEADERS(ncurses.h signal.h ctype.h utime.h dirent.h)
 AC_CHECK_HEADERS(arpa/inet.h sys/mman.h limits.h termios.h locale.h langinfo.h)
 
 # Data type checking
index 669c1343c375d0bcdc4352a20f12be5acfb4f528..c64d33b8a9e483b767703723d764e0e767666e22 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2007 Pekka Riikonen
+  Copyright (C) 1997 - 2008 Pekka Riikonen
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
@@ -130,6 +130,7 @@ extern "C" {
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <time.h>
+#include <dirent.h>
 
 #ifdef HAVE_SIGNAL_H
 #include <signal.h>
@@ -255,6 +256,7 @@ extern "C" {
 #include "silcthread.h"
 #include "silcschedule.h"
 #include "silclog.h"
+#include "silcdir.h"
 #include "silcfileutil.h"
 #include "silcbuffer.h"
 #include "silcbuffmt.h"
index 41af979413ff5efae53f5d38b2e5e5743e751fee..79430bd990cd8a0b0b06403f58b8baa55e281c3d 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 2001 - 2003 Pekka Riikonen
+  Copyright (C) 2001 - 2008 Pekka Riikonen
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
@@ -31,8 +31,8 @@
 #include "regexpr.h"
 #endif /* HAVE_SILCDEFS_H */
 
-#define snprintf _snprintf
-#define vsnprintf _vsnprintf
+#define snprintf silc_snprintf
+#define vsnprintf silc_vsnprintf
 
 #ifdef WIN32
 #define strcasecmp stricmp
diff --git a/lib/silcutil/silcdir.h b/lib/silcutil/silcdir.h
new file mode 100644 (file)
index 0000000..25fb314
--- /dev/null
@@ -0,0 +1,240 @@
+/*
+
+  silcdir.h
+
+  Author: Pekka Riikonen <priikone@silcnet.org>
+
+  Copyright (C) 2008 Pekka Riikonen
+
+  This program 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; version 2 of the License.
+
+  This program 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.
+
+*/
+
+/****h* silcutil/SILC Directory Interface
+ *
+ * DESCRIPTION
+ *
+ * The SILC Directory API provides portable way to open and read directories
+ * and their content.
+ *
+ * EXAMPLE
+ *
+ * SilcDir dir;
+ * SilcDirEntry entry;
+ *
+ * dir = silc_dir_open("foodir");
+ *
+ * while ((entry = silc_dir_read(dir, NULL)))
+ *   printf("File name: %s", silc_dir_entry_name(entry));
+ *
+ * silc_dir_close(dir);
+ *
+ ***/
+
+#ifndef SILCDIR_H
+#define SILCDIR_H
+
+/****s* silcutil/SilcDirAPI/SilcDir
+ *
+ * NAME
+ *
+ *    typedef struct SilcDirStruct *SilcDir;
+ *
+ * DESCRIPTION
+ *
+ *    The directory context.  This is allocated by silc_dir_open and
+ *    freed by calling silc_dir_close.
+ *
+ ***/
+typedef struct SilcDirStruct *SilcDir;
+
+/****s* silcutil/SilcDirAPI/SilcDirEntry
+ *
+ * NAME
+ *
+ *    typedef struct SilcDirEntryStruct *SilcDirEntry;
+ *
+ * DESCRIPTION
+ *
+ *    The directory entry context.  The entry is usually a file in the
+ *    directory.
+ *
+ ***/
+typedef struct SilcDirEntryStruct *SilcDirEntry;
+
+/****d* silcutil/SilcDirAPI/SilcDirEntryModen
+ *
+ * NAME
+ *
+ *    typedef enum { ... } SilcDirEntryMode;
+ *
+ * DESCRIPTION
+ *
+ *    The directory entry mode bits.  These bits specify the entry mode,
+ *    type and protection.
+ *
+ ***/
+typedef enum {
+  /* Type */
+  SILC_DIR_ENTRY_IFDIR     = 0x00000001,  /* Entry is directory */
+  SILC_DIR_ENTRY_IFCHR     = 0x00000002,  /* Entry is character device */
+  SILC_DIR_ENTRY_IFBLK     = 0x00000004,  /* Entry is block device */
+  SILC_DIR_ENTRY_IFREG     = 0x00000008,  /* Entry is regular file */
+  SILC_DIR_ENTRY_IFIFO     = 0x00000010,  /* Entry is FIFO */
+  SILC_DIR_ENTRY_IFLNK     = 0x00000020,  /* Entry is symbolic link */
+  SILC_DIR_ENTRY_IFSOCK    = 0x00000040,  /* Entry is socket */
+
+  /* Protection */
+  SILC_DIR_ENTRY_IRUSR     = 0x00000080,  /* Owner has read permission */
+  SILC_DIR_ENTRY_IWUSR     = 0x00000100,  /* Owner has write permission */
+  SILC_DIR_ENTRY_IXUSR     = 0x00000200,  /* Owner has execute permission */
+  SILC_DIR_ENTRY_IRGRP     = 0x00000400,  /* Group has read permission */
+  SILC_DIR_ENTRY_IWGRP     = 0x00000800,  /* Group has write permission */
+  SILC_DIR_ENTRY_IXGRP     = 0x00001000,  /* Group has execute permission */
+  SILC_DIR_ENTRY_IROTH     = 0x00002000,  /* Others have read permission */
+  SILC_DIR_ENTRY_IWOTH     = 0x00004000,  /* Others have write permission */
+  SILC_DIR_ENTRY_IXOTH     = 0x00008000,  /* Others have execute permission */
+} SilcDirEntryMode;
+
+/****s* silcutil/SilcDirAPI/SilcDirEntryStat
+ *
+ * NAME
+ *
+ *    typedef struct SilcDirEntryObject { ... } *SilcDirEntryStat,
+ *                                               SilcDirEntryStatStruct;
+ *
+ * DESCRIPTION
+ *
+ *    The directory entry status information structure.  The structure
+ *    contains various information about the entry in the directory.
+ *    This context is returned by silc_dir_read or silc_dir_entry_stat.
+ *
+ ***/
+typedef struct SilcDirEntryStatObject {
+  SilcTimeStruct last_access;          /* Time of last access */
+  SilcTimeStruct last_mod;             /* Time of last modification */
+  SilcTimeStruct last_change;          /* Time of last status change */
+  SilcUInt64 size;                     /* Entry size in bytes */
+  SilcUInt32 uid;                      /* Owner ID of the entry */
+  SilcUInt32 gid;                      /* Group owner ID of the entry */
+  SilcUInt32 dev;                      /* Entry device number */
+  SilcUInt32 nlink;                    /* Number of hard links */
+  SilcDirEntryMode mode;               /* Entry mode */
+} *SilcDirEntryStat, SilcDirEntryStatStruct;
+
+/****f* silcutil/SilcDirAPI/silc_dir_open
+ *
+ * SYNOPSIS
+ *
+ *    SilcDir silc_dir_open(const char *name);
+ *
+ * DESCRIPTION
+ *
+ *    Opens the directory named `name' and returns its context.  Returns NULL
+ *    on error and sets the silc_errno.  This function must be called before
+ *    being able to read the directory and its contents.
+ *
+ ***/
+SilcDir silc_dir_open(const char *name);
+
+/****f* silcutil/SilcDirAPI/silc_dir_close
+ *
+ * SYNOPSIS
+ *
+ *    void silc_dir_close(SilcDir dir);
+ *
+ * DESCRIPTION
+ *
+ *    Closes the directory `dir'.
+ *
+ ***/
+void silc_dir_close(SilcDir dir);
+
+/****f* silcutil/SilcDirAPI/silc_dir_read
+ *
+ * SYNOPSIS
+ *
+ *    SilcDirEntry silc_dir_read(SilcDir dir, SilcDirEntryStat *status);
+ *
+ * DESCRIPTION
+ *
+ *    Reads next entry (file) from the directory `dir'.  The silc_dir_open
+ *    must be called first before reading from the directory.  Returns the
+ *    next entry context or NULL if there are no more entries or error occurs.
+ *    In case of error the silc_errno is also set.
+ *
+ *    If the `status' is non-NULL this will also call silc_dir_entry_stat
+ *    and returns the status into the `status' pointer.
+ *
+ *    The returned context remains valid until the silc_dir_read is called
+ *    again.
+ *
+ ***/
+SilcDirEntry silc_dir_read(SilcDir dir, SilcDirEntryStat *status);
+
+/****f* silcutil/SilcDirAPI/silc_dir_rewind
+ *
+ * SYNOPSIS
+ *
+ *    void silc_dir_rewind(SilcDir dir);
+ *
+ * DESCRIPTION
+ *
+ *    Rewinds the directory `dir' to the beginning of the directory.  Calling
+ *    silc_dir_read after this will return the first entry in the directory.
+ *
+ ***/
+void silc_dir_rewind(SilcDir dir);
+
+/****f* silcutil/SilcDirAPI/silc_dir_name
+ *
+ * SYNOPSIS
+ *
+ *    const char *silc_dir_name(SilcDir dir);
+ *
+ * DESCRIPTION
+ *
+ *    Returns the name of the directory from `dir' context.
+ *
+ ***/
+const char *silc_dir_name(SilcDir dir);
+
+/****f* silcutil/SilcDirAPI/silc_dir_entry_name
+ *
+ * SYNOPSIS
+ *
+ *    const char *silc_dir_entry_name(SilcDirEntry entry);
+ *
+ * DESCRIPTION
+ *
+ *    Returns the name of the entry (file) `entry'.  The returned pointer
+ *    remains valid until the silc_dir_read is called again.
+ *
+ ***/
+const char *silc_dir_entry_name(SilcDirEntry entry);
+
+/****f* silcutil/SilcDirAPI/silc_dir_entry_stat
+ *
+ * SYNOPSIS
+ *
+ *    SilcDirEntryStat silc_dir_entry_stat(SilcDir dir, SilcDirEntry entry);
+ *
+ * DESCRIPTION
+ *
+ *    Returns the status of the entry.  The status context contains details
+ *    of the entry (file) in the directory.  Returns NULL on error and sets
+ *    the silc_errno.
+ *
+ *    The returned contest is valid until the silc_dir_read is called again.
+ *
+ ***/
+SilcDirEntryStat silc_dir_entry_stat(SilcDir dir, SilcDirEntry entry);
+
+#endif /* SILCDIR_H */
index ebf329285fba82bd89e4872e2dfbe93f1869882d..f4760d8a861b2a146aa69371bd6faa4b8a411987 100644 (file)
@@ -44,7 +44,7 @@
  * // Get the detailed reason for the error too
  * if (silc_some_routine() == FALSE) {
  *   fprintf(stderr, "%s (%d) (%s)", silc_errno_string(silc_errno),
- *          silc_errno, silc_errno_reason);
+ *          silc_errno, silc_errno_reason());
  *   exit(1);
  * }
  *
index a08a086337ae5c9c47941fca96631e3d3f068e1d..94f01274a7d7c5fc8191e9bc64e57fc6041cddc1 100644 (file)
@@ -22,7 +22,7 @@ bin_PROGRAMS =        test_silcstrutil test_silcstringprep test_silchashtable \
        test_silcnet test_silcstack test_silcmime test_silcfdstream \
        test_silcatomic test_silcmutex test_silctime test_silcthread \
        test_silcdll test_silcenv test_silctimer test_silcbitops \
-       test_silcregex test_silcbuffmt
+       test_silcregex test_silcbuffmt test_silcdir
 
 test_silcstrutil_SOURCES = test_silcstrutil.c
 test_silcstringprep_SOURCES = test_silcstringprep.c
@@ -45,6 +45,7 @@ test_silctimer_SOURCES = test_silctimer.c
 test_silcbitops_SOURCES = test_silcbitops.c
 test_silcregex_SOURCES = test_silcregex.c
 test_silcbuffmt_SOURCES = test_silcbuffmt.c
+test_silcdir_SOURCES = test_silcdir.c
 
 LIBS = $(SILC_COMMON_LIBS)
 LDADD = -L.. -L../.. -lsilc
diff --git a/lib/silcutil/tests/test_silcdir.c b/lib/silcutil/tests/test_silcdir.c
new file mode 100644 (file)
index 0000000..e9e3694
--- /dev/null
@@ -0,0 +1,53 @@
+/* SilcDir tests */
+
+#include "silc.h"
+
+int main(int argc, char **argv)
+{
+  SilcBool success = FALSE;
+  SilcDir dir;
+  SilcDirEntry entry;
+  SilcDirEntryStat status;
+
+  if (argc > 1 && !strcmp(argv[1], "-d")) {
+    silc_log_debug(TRUE);
+    silc_log_quick(TRUE);
+    silc_log_debug_hexdump(TRUE);
+    silc_log_set_debug_string("*dir*,*errno*");
+  }
+
+  dir = silc_dir_open("/etc/");
+  if (!dir)
+    goto err;
+
+  printf("%s:\n", silc_dir_name(dir));
+  while ((entry = silc_dir_read(dir, &status)))
+    printf(
+     "%c%c%c%c%c%c%c%c%c%c %3d %4d %4d %8lu %04d-%02d-%02d %02d:%02d %s\n",
+       status->mode & SILC_DIR_ENTRY_IFDIR ? 'd' : '-',
+       status->mode & SILC_DIR_ENTRY_IRUSR ? 'r' : '-',
+       status->mode & SILC_DIR_ENTRY_IWUSR ? 'w' : '-',
+       status->mode & SILC_DIR_ENTRY_IXUSR ? 'x' : '-',
+       status->mode & SILC_DIR_ENTRY_IRGRP ? 'r' : '-',
+       status->mode & SILC_DIR_ENTRY_IWGRP ? 'w' : '-',
+       status->mode & SILC_DIR_ENTRY_IXGRP ? 'x' : '-',
+       status->mode & SILC_DIR_ENTRY_IROTH ? 'r' : '-',
+       status->mode & SILC_DIR_ENTRY_IWOTH ? 'w' : '-',
+       status->mode & SILC_DIR_ENTRY_IXOTH ? 'x' : '-',
+       status->nlink, status->uid, status->gid, status->size,
+       status->last_mod.year, status->last_mod.month, status->last_mod.day,
+       status->last_mod.hour, status->last_mod.minute,
+       silc_dir_entry_name(entry));
+
+  fflush(stdout);
+
+  silc_dir_close(dir);
+
+  success = TRUE;
+
+ err:
+  SILC_LOG_DEBUG(("Testing was %s", success ? "SUCCESS" : "FAILURE"));
+  fprintf(stderr, "Testing was %s\n", success ? "SUCCESS" : "FAILURE");
+
+  return success;
+}
index bb9719e1fc99dded7b12e465d2644f2897b01f2c..1a1c7c312f4336d2aa445f50681a3efbd08bc817 100644 (file)
@@ -3,7 +3,7 @@
 #
 #  Author: Pekka Riikonen <priikone@silcnet.org>
 #
-#  Copyright (C) 2001 - 2006 Pekka Riikonen
+#  Copyright (C) 2001 - 2008 Pekka Riikonen
 #
 #  This program is free software; you can redistribute it and/or modify
 #  it under the terms of the GNU General Public License as published by
@@ -25,6 +25,7 @@ libsilcunixutil_la_SOURCES =  \
        silcunixnet.c           \
        silcunixutil.c          \
        silcunixsocketstream.c  \
-       silcunixthread.c
+       silcunixthread.c        \
+       silcunixdir.c
 
 include $(top_srcdir)/Makefile.defines.in
diff --git a/lib/silcutil/unix/silcunixdir.c b/lib/silcutil/unix/silcunixdir.c
new file mode 100644 (file)
index 0000000..e2fa08d
--- /dev/null
@@ -0,0 +1,249 @@
+/*
+
+  silcunixdir.c
+
+  Author: Pekka Riikonen <priikone@silcnet.org>
+
+  Copyright (C) 2008 Pekka Riikonen
+
+  This program 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; version 2 of the License.
+
+  This program 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.
+
+*/
+
+#include "silc.h"
+
+/************************** Types and definitions ***************************/
+
+/* Directory entry context */
+struct SilcDirEntryStruct {
+  struct dirent *entry;                          /* Entry */
+  SilcDirEntryStatStruct status;         /* Status */
+};
+
+/* The directory context */
+struct SilcDirStruct {
+  DIR *dir;                              /* Directory */
+  char *name;                            /* Directory name */
+  struct SilcDirEntryStruct entry;       /* Current entry */
+};
+
+/****************************** SILC Dir API ********************************/
+
+/* Open directory */
+
+SilcDir silc_dir_open(const char *name)
+{
+  SilcDir dir;
+
+  SILC_LOG_DEBUG(("Open directory '%s'", name));
+
+  dir = silc_calloc(1, sizeof(*dir));
+  if (!dir)
+    return NULL;
+
+  dir->name = silc_strdup(name);
+  if (!dir->name) {
+    silc_free(dir);
+    return NULL;
+  }
+
+  if (dir->name[strlen(dir->name) - 1] == '/')
+    dir->name[strlen(dir->name) - 1] = '\0';
+
+  dir->dir = opendir(name);
+  if (!dir->dir) {
+    silc_set_errno_posix(errno);
+    silc_free(dir->name);
+    silc_free(dir);
+    return NULL;
+  }
+
+  return dir;
+}
+
+/* Close directory */
+
+void silc_dir_close(SilcDir dir)
+{
+  if (!dir)
+    return;
+
+  SILC_LOG_DEBUG(("Close directory '%s'", dir->name));
+
+  closedir(dir->dir);
+  silc_free(dir->name);
+  silc_free(dir);
+}
+
+/* Read next entry in the directory */
+
+SilcDirEntry silc_dir_read(SilcDir dir, SilcDirEntryStat *status)
+{
+  if (!dir) {
+    silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
+    return NULL;
+  }
+
+  SILC_LOG_DEBUG(("Read directory '%s'", dir->name));
+
+  dir->entry.entry = readdir(dir->dir);
+  if (!dir->entry.entry) {
+    if (errno)
+      silc_set_errno_posix(errno);
+    return NULL;
+  }
+
+  if (status)
+    *status = silc_dir_entry_stat(dir, &dir->entry);
+
+  return (SilcDirEntry)&dir->entry;
+}
+
+/* Rewind directory */
+
+void silc_dir_rewind(SilcDir dir)
+{
+  if (!dir)
+    return;
+
+  SILC_LOG_DEBUG(("Rewind directory '%s'", dir->name));
+
+  rewinddir(dir->dir);
+}
+
+/* Return directory name */
+
+const char *silc_dir_name(SilcDir dir)
+{
+  if (!dir) {
+    silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
+    return NULL;
+  }
+
+  return dir->name;
+}
+
+/* Return entry name */
+
+const char *silc_dir_entry_name(SilcDirEntry entry)
+{
+  if (!entry) {
+    silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
+    return NULL;
+  }
+
+  return (const char *)entry->entry->d_name;
+}
+
+/* Return entry status information */
+
+SilcDirEntryStat silc_dir_entry_stat(SilcDir dir, SilcDirEntry entry)
+{
+  struct stat status;
+  char *name = NULL;
+
+  if (!dir || !entry) {
+    silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
+    return NULL;
+  }
+
+  silc_asprintf(&name, "%s/%s", dir->name, entry->entry->d_name);
+  if (!name)
+    return NULL;
+
+  SILC_LOG_DEBUG(("Get status for entry '%s'", name));
+
+  if (lstat(name, &status) != 0) {
+    silc_set_errno_posix(errno);
+    silc_free(name);
+    return NULL;
+  }
+
+  silc_free(name);
+
+  memset(&entry->status, 0, sizeof(entry->status));
+
+  silc_time_value(status.st_atime * 1000, &entry->status.last_access);
+  silc_time_value(status.st_mtime * 1000, &entry->status.last_mod);
+  silc_time_value(status.st_ctime * 1000, &entry->status.last_change);
+
+  entry->status.dev = status.st_dev;
+  entry->status.nlink = status.st_nlink;
+  entry->status.gid = status.st_gid;
+  entry->status.uid = status.st_uid;
+  entry->status.size = status.st_size;
+
+#if defined(S_IFSOCK)
+  if (status.st_mode & S_IFSOCK)
+    entry->status.mode |= SILC_DIR_ENTRY_IFSOCK;
+#endif /* S_IFSOCK */
+#if defined(S_IFLNK)
+  if (status.st_mode & S_IFLNK)
+    entry->status.mode |= SILC_DIR_ENTRY_IFLNK;
+#endif /* S_IFLNK */
+#if defined(S_IFREG)
+  if (status.st_mode & S_IFREG)
+    entry->status.mode |= SILC_DIR_ENTRY_IFREG;
+#endif /* S_IFREG */
+#if defined(S_IFBLK)
+  if (status.st_mode & S_IFBLK)
+    entry->status.mode |= SILC_DIR_ENTRY_IFBLK;
+#endif /* S_IFBLK */
+#if defined(S_IFDIR)
+  if (status.st_mode & S_IFDIR)
+    entry->status.mode |= SILC_DIR_ENTRY_IFDIR;
+#endif /* S_IFDIR */
+#if defined(S_IFCHR)
+  if (status.st_mode & S_IFCHR)
+    entry->status.mode |= SILC_DIR_ENTRY_IFCHR;
+#endif /* S_IFCHR */
+#if defined(S_IFIFO)
+  if (status.st_mode & S_IFIFO)
+    entry->status.mode |= SILC_DIR_ENTRY_IFIFO;
+#endif /* S_IFIFO */
+#if defined(S_IRUSR)
+  if (status.st_mode & S_IRUSR)
+    entry->status.mode |= SILC_DIR_ENTRY_IRUSR;
+#endif /* S_IRUSR */
+#if defined(S_IWUSR)
+  if (status.st_mode & S_IWUSR)
+    entry->status.mode |= SILC_DIR_ENTRY_IWUSR;
+#endif /* S_IWUSR */
+#if defined(S_IXUSR)
+  if (status.st_mode & S_IXUSR)
+    entry->status.mode |= SILC_DIR_ENTRY_IXUSR;
+#endif /* S_IXUSR */
+#if defined(S_IRGRP)
+  if (status.st_mode & S_IRGRP)
+    entry->status.mode |= SILC_DIR_ENTRY_IRGRP;
+#endif /* S_IRGRP */
+#if defined(S_IWGRP)
+  if (status.st_mode & S_IWGRP)
+    entry->status.mode |= SILC_DIR_ENTRY_IWGRP;
+#endif /* S_IWGRP */
+#if defined(S_IXGRP)
+  if (status.st_mode & S_IXGRP)
+    entry->status.mode |= SILC_DIR_ENTRY_IXGRP;
+#endif /* S_IXGRP */
+#if defined(S_IROTH)
+  if (status.st_mode & S_IROTH)
+    entry->status.mode |= SILC_DIR_ENTRY_IROTH;
+#endif /* S_IROTH */
+#if defined(S_IWOTH)
+  if (status.st_mode & S_IWOTH)
+    entry->status.mode |= SILC_DIR_ENTRY_IWOTH;
+#endif /* S_IWOTH */
+#if defined(S_IXOTH)
+  if (status.st_mode & S_IXOTH)
+    entry->status.mode |= SILC_DIR_ENTRY_IXOTH;
+#endif /* S_IXOTH */
+
+  return (SilcDirEntryStat)&entry->status;
+}