+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
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.
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
#
# 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
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
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
#include <sys/types.h>
#include <sys/stat.h>
#include <time.h>
+#include <dirent.h>
#ifdef HAVE_SIGNAL_H
#include <signal.h>
#include "silcthread.h"
#include "silcschedule.h"
#include "silclog.h"
+#include "silcdir.h"
#include "silcfileutil.h"
#include "silcbuffer.h"
#include "silcbuffmt.h"
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
#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
--- /dev/null
+/*
+
+ 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 */
* // 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);
* }
*
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
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
--- /dev/null
+/* 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;
+}
#
# 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
silcunixnet.c \
silcunixutil.c \
silcunixsocketstream.c \
- silcunixthread.c
+ silcunixthread.c \
+ silcunixdir.c
include $(top_srcdir)/Makefile.defines.in
--- /dev/null
+/*
+
+ 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;
+}