Added and implemented Silc DIR API.
[runtime.git] / lib / silcutil / unix / silcunixdir.c
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;
+}