aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGarrett D'Amore <garrett@damore.org>2018-01-10 16:14:54 -0800
committerGarrett D'Amore <garrett@damore.org>2018-01-11 06:42:19 -0800
commit3dd4cbf8efcfd574e2244798a86edd2f10c9cb45 (patch)
treea5087862282f1ed950cf3daf3c3e45078b9e4216 /src
parent282da09430fc39d8f93d78b828d3653e95318255 (diff)
downloadnng-3dd4cbf8efcfd574e2244798a86edd2f10c9cb45.tar.gz
nng-3dd4cbf8efcfd574e2244798a86edd2f10c9cb45.tar.bz2
nng-3dd4cbf8efcfd574e2244798a86edd2f10c9cb45.zip
Refactored file API.
This refactor of the file API provides a simpler and easier to use interface for our needs (and simpler to implement) in both the ZeroTier transport and the HTTP/TLS file accesses. It also removes some restrictions present on the old one, although it is still not suitable for working with large files. (It will work, just be very inefficient as the entire file must be loaded into memory.)
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt2
-rw-r--r--src/core/file.c111
-rw-r--r--src/core/file.h79
-rw-r--r--src/core/nng_impl.h1
-rw-r--r--src/core/platform.h45
-rw-r--r--src/platform/posix/posix_file.c196
-rw-r--r--src/platform/windows/win_file.c309
-rw-r--r--src/supplemental/websocket/websocket.c2
-rw-r--r--src/transport/zerotier/zerotier.c56
9 files changed, 600 insertions, 201 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index a341a8c5..a7bf3937 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -40,6 +40,8 @@ set (NNG_SOURCES
core/device.h
core/endpt.c
core/endpt.h
+ core/file.c
+ core/file.h
core/idhash.c
core/idhash.h
core/init.c
diff --git a/src/core/file.c b/src/core/file.c
new file mode 100644
index 00000000..d7000a6a
--- /dev/null
+++ b/src/core/file.c
@@ -0,0 +1,111 @@
+//
+// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
+// Copyright 2018 Capitar IT Group BV <info@capitar.com>
+//
+// This software is supplied under the terms of the MIT License, a
+// copy of which should be located in the distribution where this
+// file was obtained (LICENSE.txt). A copy of the license may also be
+// found online at https://opensource.org/licenses/MIT.
+//
+
+#include "core/nng_impl.h"
+
+int
+nni_file_put(const char *name, const void *data, size_t sz)
+{
+ return (nni_plat_file_put(name, data, sz));
+}
+
+int
+nni_file_get(const char *name, void **datap, size_t *szp)
+{
+ return (nni_plat_file_get(name, datap, szp));
+}
+
+int
+nni_file_delete(const char *name)
+{
+ return (nni_plat_file_delete(name));
+}
+
+struct walkdata {
+ nni_file_walker fn;
+ void * arg;
+};
+
+static int
+plat_walker(const char *name, void *arg)
+{
+ struct walkdata *w = arg;
+ int rv;
+
+ rv = w->fn(name, w->arg);
+ switch (rv) {
+ case NNI_FILE_WALK_CONTINUE:
+ return (NNI_PLAT_FILE_WALK_CONTINUE);
+ case NNI_FILE_WALK_STOP:
+ return (NNI_PLAT_FILE_WALK_STOP);
+ case NNI_FILE_WALK_PRUNE_CHILD:
+ return (NNI_PLAT_FILE_WALK_PRUNE_CHILD);
+ case NNI_FILE_WALK_PRUNE_SIB:
+ return (NNI_PLAT_FILE_WALK_PRUNE_SIB);
+ }
+ // We treat any other value as a stop condition. The program
+ // is returning something invalid.
+ return (NNI_PLAT_FILE_WALK_STOP);
+}
+
+int
+nni_file_walk(const char *name, nni_file_walker walker, void *arg, int flags)
+{
+ struct walkdata w;
+ int wflags = 0;
+
+ w.fn = walker;
+ w.arg = arg;
+
+ if (flags & NNI_FILE_WALK_FILES_ONLY) {
+ wflags |= NNI_PLAT_FILE_WALK_FILES_ONLY;
+ }
+ if (flags & NNI_FILE_WALK_SHALLOW) {
+ wflags |= NNI_PLAT_FILE_WALK_SHALLOW;
+ }
+
+ return (nni_plat_file_walk(name, plat_walker, &w, wflags));
+}
+
+int
+nni_file_type(const char *name, int *ftype)
+{
+ int rv;
+ int t;
+
+ if ((rv = nni_plat_file_type(name, &t)) != 0) {
+ return (rv);
+ }
+
+ switch (t) {
+ case NNI_PLAT_FILE_TYPE_FILE:
+ *ftype = NNI_FILE_TYPE_FILE;
+ break;
+ case NNI_PLAT_FILE_TYPE_DIR:
+ *ftype = NNI_FILE_TYPE_DIR;
+ break;
+ default:
+ *ftype = NNI_FILE_TYPE_OTHER;
+ break;
+ }
+ return (0);
+}
+
+char *
+nni_file_join(const char *dir, const char *file)
+{
+ return (nni_plat_join_dir(dir, file));
+}
+
+const char *
+nni_file_basename(const char *path)
+{
+ return (nni_plat_file_basename(path));
+} \ No newline at end of file
diff --git a/src/core/file.h b/src/core/file.h
new file mode 100644
index 00000000..b45aae61
--- /dev/null
+++ b/src/core/file.h
@@ -0,0 +1,79 @@
+//
+// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
+// Copyright 2018 Capitar IT Group BV <info@capitar.com>
+//
+// This software is supplied under the terms of the MIT License, a
+// copy of which should be located in the distribution where this
+// file was obtained (LICENSE.txt). A copy of the license may also be
+// found online at https://opensource.org/licenses/MIT.
+//
+
+#ifndef CORE_FILE_H
+#define CORE_FILE_H
+
+// File/Store Support
+//
+// Some transports require a persistent storage for things like configs,
+// key material, etc. Generally, these are all going to be relatively
+// small objects (such as certificates), so we only require a synchronous
+// implementation from platforms. We provide a very limited and simple
+// file API for these purposes; basic CRUD operations only, plus a way
+// to iterate over names. These are adequate for NNG's internal uses;
+// applications should use normal platform-specific APIs or those in the
+// standard C library.
+
+// nni_file_put writes the named file, with the provided data,
+// and the given size. If the file already exists it is overwritten.
+// The permissions on the file will allow the application to read and
+// write the file, but may (should) restrict anything else beyond that
+// where they can. If the name contains platform specific directory
+// separators, then any missing parent directories will be created if
+// possible.
+extern int nni_file_put(const char *, const void *, size_t);
+
+// nni_plat_file_get reads the entire named file, allocating storage
+// to receive the data and returning the data and the size in the
+// reference arguments. The data pointer should be freed with nni_free
+// using the supplied size when no longer needed.
+extern int nni_file_get(const char *, void **, size_t *);
+
+// nni_file_delete deletes the named file.
+extern int nni_file_delete(const char *);
+
+enum nni_file_type_val {
+ NNI_FILE_TYPE_FILE,
+ NNI_FILE_TYPE_DIR,
+ NNI_FILE_TYPE_OTHER,
+};
+
+// nni_file_exists checks if the named file exists.
+extern int nni_file_type(const char *, int *);
+
+// nni_file_walk walks a list of files.
+enum nni_file_walk_result {
+ NNI_FILE_WALK_CONTINUE,
+ NNI_FILE_WALK_STOP,
+ NNI_FILE_WALK_PRUNE_SIB,
+ NNI_FILE_WALK_PRUNE_CHILD,
+};
+
+enum nni_file_walk_flags {
+ NNI_FILE_WALK_DEPTH_FIRST = 0, // get children first
+ NNI_FILE_WALK_BREADTH_FIRST = 1, // get siblings first (later)
+ NNI_FILE_WALK_SHALLOW = 2, // do not descend into subdirectories
+ NNI_FILE_WALK_FILES_ONLY = 4, // directory names are not reported
+};
+
+typedef int (*nni_file_walker)(const char *, void *);
+extern int nni_file_walk(const char *, nni_file_walker, void *, int);
+
+// nni_file_join joins two path components to make a path name.
+// For example. on UNIX systems nni_file_join("/tmp", "a") returns
+// "/tmp/a". The pathname returned should be freed with nni_strfree().
+extern char *nni_file_join(const char *, const char *);
+
+// nni_file_basename returns the "file" name, without the parent directory.
+// The returned value generally is within the supplied path name.
+extern const char *nni_file_basename(const char *);
+
+#endif // CORE_FILE_H
diff --git a/src/core/nng_impl.h b/src/core/nng_impl.h
index bee6ae41..ea8512bb 100644
--- a/src/core/nng_impl.h
+++ b/src/core/nng_impl.h
@@ -29,6 +29,7 @@
#include "core/aio.h"
#include "core/clock.h"
#include "core/device.h"
+#include "core/file.h"
#include "core/idhash.h"
#include "core/init.h"
#include "core/list.h"
diff --git a/src/core/platform.h b/src/core/platform.h
index 9e193175..73b6785b 100644
--- a/src/core/platform.h
+++ b/src/core/platform.h
@@ -1,6 +1,6 @@
//
-// Copyright 2017 Garrett D'Amore <garrett@damore.org>
-// Copyright 2017 Capitar IT Group BV <info@capitar.com>
+// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
+// Copyright 2018 Capitar IT Group BV <info@capitar.com>
//
// This software is supplied under the terms of the MIT License, a
// copy of which should be located in the distribution where this
@@ -370,7 +370,7 @@ extern void nni_plat_pipe_close(int, int);
//
// Some transports require a persistent storage for things like
// key material, etc. Generally, these are all going to be relatively
-// small objects (such as certificates), so we ony require a synchronous
+// small objects (such as certificates), so we only require a synchronous
// implementation from platforms. This Key-Value API is intended to
// to support using the Key's as filenames, and keys will consist of
// only these characters: [0-9a-zA-Z._-]. The directory used should be
@@ -393,9 +393,41 @@ extern int nni_plat_file_put(const char *, const void *, size_t);
// using the supplied size when no longer needed.
extern int nni_plat_file_get(const char *, void **, size_t *);
-// nni_plat_file_delete deletes the named file.
+// nni_plat_file_delete deletes the named file. If the name refers to
+// a directory, then that will be removed only if empty.
extern int nni_plat_file_delete(const char *);
+// nni_plat_file_check checks the file path to determine its type.
+// If the path does not exist, then NNG_ENOENT is returned.
+enum nni_plat_file_type_val {
+ NNI_PLAT_FILE_TYPE_FILE, // normal file
+ NNI_PLAT_FILE_TYPE_DIR, // normal directory
+ NNI_PLAT_FILE_TYPE_OTHER, // something else (pipe, device node, etc.)
+};
+extern int nni_plat_file_type(const char *, int *);
+
+enum nni_plat_file_walk_result {
+ NNI_PLAT_FILE_WALK_CONTINUE,
+ NNI_PLAT_FILE_WALK_STOP, // stop walking (all done)
+ NNI_PLAT_FILE_WALK_PRUNE_SIB, // skip siblings and their children
+ NNI_PLAT_FILE_WALK_PRUNE_CHILD, // skip children
+};
+
+enum nni_plat_file_walk_flags {
+ NNI_PLAT_FILE_WALK_DEPTH_FIRST = 0, // get children first
+ NNI_PLAT_FILE_WALK_BREADTH_FIRST = 1, // get siblings first (later)
+ NNI_PLAT_FILE_WALK_SHALLOW = 2, // do not descend into subdirectories
+ NNI_PLAT_FILE_WALK_FILES_ONLY = 4, // directory names are not reported
+};
+
+// nni_plat_file_walker is called for each pathname found by walking a
+// directory tree. It returns one of the nni_plat_file_walk_result values.
+typedef int (*nni_plat_file_walker)(const char *, void *);
+
+// nni_plat_file_walk walks a directory tree, calling the walker function
+// with the path name, and the supplied void * argument.
+extern int nni_plat_file_walk(const char *, nni_plat_file_walker, void *, int);
+
// nni_plat_dir_open attempts to "open a directory" for listing. The
// handle for further operations is returned in the first argument, and
// the directory name is supplied in the second.
@@ -435,6 +467,11 @@ extern char *nni_plat_home_dir(void);
// "/tmp/a". The pathname returned should be freed with nni_strfree().
extern char *nni_plat_join_dir(const char *, const char *);
+// nni_plat_file_basename returns the "file" part of the file name.
+// The returned pointer will usually reference the end of the supplied
+// string, and may not be altered.
+extern const char *nni_plat_file_basename(const char *);
+
//
// Actual platforms we support. This is included up front so that we can
// get the specific types that are supplied by the platform.
diff --git a/src/platform/posix/posix_file.c b/src/platform/posix/posix_file.c
index d7033095..23a714cd 100644
--- a/src/platform/posix/posix_file.c
+++ b/src/platform/posix/posix_file.c
@@ -1,6 +1,6 @@
//
-// Copyright 2017 Garrett D'Amore <garrett@damore.org>
-// Copyright 2017 Capitar IT Group BV <info@capitar.com>
+// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
+// Copyright 2018 Capitar IT Group BV <info@capitar.com>
//
// This software is supplied under the terms of the MIT License, a
// copy of which should be located in the distribution where this
@@ -24,6 +24,39 @@
// File support.
+static int
+nni_plat_make_parent_dirs(const char *path)
+{
+ char *dup;
+ char *p;
+ int rv;
+
+ // creates everything up until the last component.
+ if ((dup = nni_strdup(path)) == NULL) {
+ return (NNG_ENOMEM);
+ }
+ p = dup;
+ while ((p = strchr(p, '/')) != NULL) {
+ if (p != dup) {
+ *p = '\0';
+ rv = mkdir(dup, S_IRWXU);
+ *p = '/';
+ if ((rv != 0) && (errno != EEXIST)) {
+ rv = nni_plat_errno(errno);
+ nni_strfree(dup);
+ return (rv);
+ }
+ }
+
+ // collapse grouped "/" characters
+ while (*p == '/') {
+ p++;
+ }
+ }
+ nni_strfree(dup);
+ return (0);
+}
+
// nni_plat_file_put writes the named file, with the provided data,
// and the given size. If the file already exists it is overwritten.
// The permissions on the file should be limited to read and write
@@ -34,6 +67,15 @@ nni_plat_file_put(const char *name, const void *data, size_t len)
FILE *f;
int rv = 0;
+ // It is possible that the name contains a directory path
+ // that does not exist. In this case we try to create the
+ // entire tree.
+ if (strchr(name, '/') != NULL) {
+ if ((rv = nni_plat_make_parent_dirs(name)) != 0) {
+ return (rv);
+ }
+ }
+
if ((f = fopen(name, "wb")) == NULL) {
return (nni_plat_errno(errno));
}
@@ -84,66 +126,64 @@ done:
return (rv);
}
-// nni_plat_file_delete deletes the named file.
+// nni_plat_file_delete deletes the named file or directory.
int
nni_plat_file_delete(const char *name)
{
- if (unlink(name) < 0) {
- return (nni_plat_errno(errno));
+ if (rmdir(name) == 0) {
+ return (0);
}
- return (0);
+ if ((errno == ENOTDIR) && (unlink(name) == 0)) {
+ return (0);
+ }
+ if (errno == ENOENT) {
+ return (0);
+ }
+ return (nni_plat_errno(errno));
}
-// nni_plat_dir_open attempts to "open a directory" for listing. The
-// handle for further operations is returned in the first argument, and
-// the directory name is supplied in the second.
int
-nni_plat_dir_open(void **dirp, const char *name)
+nni_plat_file_type(const char *name, int *typep)
{
- DIR *dir;
+ struct stat sbuf;
+ int rv;
- if ((dir = opendir(name)) == NULL) {
+ if (stat(name, &sbuf) != 0) {
return (nni_plat_errno(errno));
}
- *dirp = dir;
- return (0);
-}
-
-int
-nni_plat_dir_create(const char *name)
-{
- if (mkdir(name, S_IRWXU) != 0) {
- if (errno == EEXIST) {
- return (0);
- }
- return (nni_plat_errno(errno));
+ switch (sbuf.st_mode & S_IFMT) {
+ case S_IFREG:
+ *typep = NNI_PLAT_FILE_TYPE_FILE;
+ break;
+ case S_IFDIR:
+ *typep = NNI_PLAT_FILE_TYPE_DIR;
+ break;
+ default:
+ *typep = NNI_PLAT_FILE_TYPE_OTHER;
+ break;
}
return (0);
}
-int
-nni_plat_dir_remove(const char *name)
+static int
+nni_plat_file_walk_inner(const char *name, nni_plat_file_walker walkfn,
+ void *arg, int flags, bool *stop)
{
- if (rmdir(name) != 0) {
- if (errno == ENOENT) {
- return (0);
- }
+ DIR *dir;
+
+ if ((dir = opendir(name)) == NULL) {
return (nni_plat_errno(errno));
}
- return (0);
-}
-
-// nni_plat_dir_next gets the next directory entry. Each call returns
-// a new entry (arbitrary order). When no more entries exist, it returns
-// NNG_ENOENT.
-int
-nni_plat_dir_next(void *dir, const char **namep)
-{
for (;;) {
+ int rv;
struct dirent *ent;
+ struct stat sbuf;
+ char * path;
+ int walkrv;
- if ((ent = readdir((DIR *) dir)) == NULL) {
- return (NNG_ENOENT);
+ if ((ent = readdir(dir)) == NULL) {
+ closedir(dir);
+ return (0);
}
// Skip "." and ".." -- we would like to skip all
// directories, but that would require checking full
@@ -152,17 +192,73 @@ nni_plat_dir_next(void *dir, const char **namep)
(strcmp(ent->d_name, "..") == 0)) {
continue;
}
- *namep = ent->d_name;
- return (0);
+ if ((rv = nni_asprintf(&path, "%s/%s", name, ent->d_name)) !=
+ 0) {
+ closedir(dir);
+ return (rv);
+ }
+ if (stat(path, &sbuf) != 0) {
+ if (errno == ENOENT) { // deleted while walking
+ continue;
+ }
+ rv = nni_plat_errno(errno);
+ nni_strfree(path);
+ closedir(dir);
+ return (rv);
+ }
+ if (flags & NNI_PLAT_FILE_WALK_FILES_ONLY) {
+ if ((sbuf.st_mode & S_IFMT) == S_IFREG) {
+ walkrv = walkfn(path, arg);
+ } else {
+ walkrv = NNI_PLAT_FILE_WALK_CONTINUE;
+ }
+ } else {
+ walkrv = walkfn(path, arg);
+ }
+
+ if (walkrv == NNI_PLAT_FILE_WALK_STOP) {
+ *stop = true;
+ }
+
+ if ((!*stop) && (rv != NNI_PLAT_FILE_WALK_PRUNE_CHILD) &&
+ ((flags & NNI_PLAT_FILE_WALK_SHALLOW) == 0) &&
+ ((sbuf.st_mode & S_IFMT) == S_IFDIR)) {
+ rv = nni_plat_file_walk_inner(
+ path, walkfn, arg, flags, stop);
+ if (rv != 0) {
+ nni_strfree(path);
+ closedir(dir);
+ return (rv);
+ }
+ }
+
+ nni_strfree(path);
+
+ if ((walkrv == NNI_PLAT_FILE_WALK_PRUNE_SIB) || (*stop)) {
+ break;
+ }
}
+ closedir(dir);
+ return (0);
}
-// nni_plat_dir_close closes the directory handle, freeing all
-// resources associated with it.
-void
-nni_plat_dir_close(void *dir)
+int
+nni_plat_file_walk(
+ const char *name, nni_plat_file_walker walkfn, void *arg, int flags)
{
- (void) closedir((DIR *) dir);
+ bool stop = false;
+
+ return (nni_plat_file_walk_inner(name, walkfn, arg, flags, &stop));
+}
+
+const char *
+nni_plat_file_basename(const char *path)
+{
+ const char *end;
+ if ((end = strrchr(path, '/')) != NULL) {
+ return (end + 1);
+ }
+ return (path);
}
char *
@@ -182,8 +278,8 @@ nni_plat_home_dir(void)
{
char *home;
- // POSIX says that $HOME is *REQUIRED*. We could look in getpwuid,
- // but realistically this is simply not required.
+ // POSIX says that $HOME is *REQUIRED*. We could look in
+ // getpwuid, but realistically this is simply not required.
if ((home = getenv("HOME")) != NULL) {
return (nni_strdup(home));
}
diff --git a/src/platform/windows/win_file.c b/src/platform/windows/win_file.c
index e10f2848..2a9504aa 100644
--- a/src/platform/windows/win_file.c
+++ b/src/platform/windows/win_file.c
@@ -1,6 +1,6 @@
//
-// Copyright 2017 Garrett D'Amore <garrett@damore.org>
-// Copyright 2017 Capitar IT Group BV <info@capitar.com>
+// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
+// Copyright 2018 Capitar IT Group BV <info@capitar.com>
//
// This software is supplied under the terms of the MIT License, a
// copy of which should be located in the distribution where this
@@ -12,11 +12,73 @@
#ifdef NNG_PLATFORM_WINDOWS
+#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
// File support.
+static char *
+nni_plat_find_pathsep(char *path)
+{
+ char *p;
+ // Legal path separators are "\\" and "/" under Windows.
+ // This is sort of a poormans strchr, but with the two specific
+ // separator characters instead.
+ for (p = path; *p != '\0'; p++) {
+ if ((*p == '/') || (*p == '\\')) {
+ return (p);
+ }
+ }
+ return (NULL);
+}
+
+static int
+nni_plat_make_parent_dirs(const char *path)
+{
+ char *dup;
+ char *p;
+
+ // creates everything up until the last component.
+ if ((dup = nni_strdup(path)) == NULL) {
+ return (NNG_ENOMEM);
+ }
+
+ // Skip past C:, C:\, \\ and \ style prefixes, because we cannot
+ // create those things as directories -- they should already exist.
+ p = dup;
+ if (isalpha(p[0]) && (p[1] == ':')) {
+ p += 2;
+ if ((p[0] == '\\') || (p[0] == '/')) {
+ p++;
+ }
+ } else if ((p[0] == '\\') && (p[1] == '\\')) {
+ p += 2;
+ } else if ((p[0] == '\\') || (p[0] == '/')) {
+ p++;
+ }
+
+ while ((p = nni_plat_find_pathsep(p)) != NULL) {
+ *p = '\0';
+
+ if (!CreateDirectory(dup, NULL)) {
+ int rv = GetLastError();
+ if (rv != ERROR_ALREADY_EXISTS) {
+ nni_strfree(dup);
+ return (nni_win_error(rv));
+ }
+ }
+ *p = '\\'; // Windows prefers this though.
+
+ // collapse grouped pathsep characters
+ while ((*p == '/') || (*p == '\\')) {
+ p++;
+ }
+ }
+ nni_strfree(dup);
+ return (0);
+}
+
// nni_plat_file_put writes the named file, with the provided data,
// and the given size. If the file already exists it is overwritten.
// The permissions on the file should be limited to read and write
@@ -28,6 +90,10 @@ nni_plat_file_put(const char *name, const void *data, size_t len)
int rv = 0;
DWORD nwrite;
+ if ((rv = nni_plat_make_parent_dirs(name)) != 0) {
+ return (rv);
+ }
+
h = CreateFile(name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL, NULL);
if (h == INVALID_HANDLE_VALUE) {
@@ -96,141 +162,104 @@ done:
int
nni_plat_file_delete(const char *name)
{
- if (!DeleteFile(name)) {
- return (nni_win_error(GetLastError()));
+ int rv;
+ if (RemoveDirectory(name)) {
+ return (0);
}
- return (0);
+ if (DeleteFile(name)) {
+ return (0);
+ }
+ if ((rv = nni_win_error(GetLastError())) == NNG_ENOENT) {
+ return (0);
+ }
+ return (rv);
}
-// nni_plat_dir_open attempts to "open a directory" for listing. The
-// handle for further operations is returned in the first argument, and
-// the directory name is supplied in the second.
-struct dirhandle {
+static int
+nni_plat_file_walk_inner(const char *name, nni_plat_file_walker walkfn,
+ void *arg, int flags, bool *stop)
+{
+ char path[MAX_PATH + 1];
+ int rv;
+ int walkrv;
HANDLE dirh;
WIN32_FIND_DATA data;
- int cont; // zero on first read, 1 thereafter.
-};
-
-int
-nni_plat_dir_open(void **dhp, const char *name)
-{
- struct dirhandle *dh;
- char fullpath[MAX_PATH + 1];
-
- if ((dh = NNI_ALLOC_STRUCT(dh)) == NULL) {
- return (NNG_ENOMEM);
- }
- // Append wildcard to directory name
- _snprintf(fullpath, sizeof(fullpath), "%s\\*", name);
-
- if ((dh->dirh = FindFirstFile(fullpath, &dh->data)) ==
- INVALID_HANDLE_VALUE) {
- int rv;
+ _snprintf(path, sizeof(path), "%s\\%s", name, "*");
+ if ((dirh = FindFirstFile(path, &data)) == INVALID_HANDLE_VALUE) {
rv = nni_win_error(GetLastError());
- NNI_FREE_STRUCT(dh);
return (rv);
}
- dh->cont = 0;
- *dhp = dh;
-
- return (0);
-}
-// nni_plat_dir_next gets the next directory entry. Each call returns
-// a new entry (arbitrary order). When no more entries exist, it returns
-// NNG_ENOENT.
-int
-nni_plat_dir_next(void *dir, const char **namep)
-{
- struct dirhandle *dh = dir;
- int rv;
+ for (;;) {
+ // We never return hidden files.
+ if ((data.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) ||
+ (strcmp(data.cFileName, ".") == 0) ||
+ (strcmp(data.cFileName, "..") == 0)) {
+ goto next_file;
+ }
+ _snprintf(path, sizeof(path), "%s\\%s", name, data.cFileName);
+ walkrv = NNI_PLAT_FILE_WALK_CONTINUE;
+ if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
+ if ((flags & NNI_PLAT_FILE_WALK_FILES_ONLY) == 0) {
+ walkrv = walkfn(path, arg);
+ }
- if (dh->dirh == INVALID_HANDLE_VALUE) {
- return (NNG_ENOENT);
- }
- if (dh->cont) {
- // We need to read another entry
- if (!FindNextFile(dh->dirh, &dh->data)) {
- rv = GetLastError();
- FindClose(dh->dirh);
- dh->dirh = INVALID_HANDLE_VALUE;
- if (rv == ERROR_NO_MORE_FILES) {
- return (NNG_ENOENT);
+ if (((flags & NNI_PLAT_FILE_WALK_SHALLOW) == 0) &&
+ (walkrv != NNI_PLAT_FILE_WALK_STOP) &&
+ (walkrv != NNI_PLAT_FILE_WALK_PRUNE_CHILD)) {
+ rv = nni_plat_file_walk_inner(
+ path, walkfn, arg, flags, stop);
+ if (rv != 0) {
+ if (rv == NNG_ENOENT) {
+ rv = 0; // File deleted.
+ }
+ FindClose(dirh);
+ return (rv);
+ }
}
- return (nni_win_error(rv));
+ } else if (data.dwFileAttributes & FILE_ATTRIBUTE_DEVICE) {
+ if ((flags & NNI_PLAT_FILE_WALK_FILES_ONLY) == 0) {
+ walkrv = walkfn(path, arg);
+ }
+ } else {
+ walkrv = walkfn(path, arg);
+ }
+
+ if (*stop) {
+ walkrv = NNI_PLAT_FILE_WALK_STOP;
+ }
+
+ switch (walkrv) {
+ case NNI_PLAT_FILE_WALK_STOP:
+ *stop = true;
+ FindClose(dirh);
+ return (0);
+ case NNI_PLAT_FILE_WALK_PRUNE_SIB:
+ FindClose(dirh);
+ return (0);
}
- }
- dh->cont = 1;
- // Skip over directories.
- while (dh->data.dwFileAttributes &
- (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_HIDDEN)) {
- if (!FindNextFile(dh->dirh, &dh->data)) {
+ next_file:
+ if (!FindNextFile(dirh, &data)) {
rv = GetLastError();
- FindClose(dh->dirh);
- dh->dirh = INVALID_HANDLE_VALUE;
+ FindClose(dirh);
if (rv == ERROR_NO_MORE_FILES) {
- return (NNG_ENOENT);
+ break;
}
return (nni_win_error(rv));
}
}
- // Got a good entry.
- *namep = dh->data.cFileName;
- return (0);
-}
-
-// nni_plat_dir_close closes the directory handle, freeing all
-// resources associated with it.
-void
-nni_plat_dir_close(void *dir)
-{
- struct dirhandle *dh = dir;
- if (dh->dirh != INVALID_HANDLE_VALUE) {
- FindClose(dh->dirh);
- }
- NNI_FREE_STRUCT(dh);
-}
-
-int
-nni_plat_dir_create(const char *name)
-{
- char parent[MAX_PATH + 1];
- size_t len;
-
- nni_strlcpy(parent, name, sizeof(parent));
- len = strlen(parent);
- while (len > 0) {
- if ((parent[len - 1] == '/') || (parent[len - 1] == '\\')) {
- parent[len - 1] = '\0';
- break;
- }
- len--;
- }
-
- if (!CreateDirectoryEx(parent, name, NULL)) {
- int rv = GetLastError();
- if (rv == ERROR_ALREADY_EXISTS) {
- return (0);
- }
- return (nni_win_error(rv));
- }
return (0);
}
int
-nni_plat_dir_remove(const char *name)
+nni_plat_file_walk(
+ const char *name, nni_plat_file_walker walkfn, void *arg, int flags)
{
- if (!RemoveDirectory(name)) {
- int rv = GetLastError();
- if (rv == ERROR_PATH_NOT_FOUND) {
- return (0);
- }
- return (nni_win_error(rv));
- }
- return (0);
+ bool stop = false;
+ return (nni_plat_file_walk_inner(name, walkfn, arg, flags, &stop));
}
char *
@@ -249,22 +278,68 @@ nni_plat_home_dir(void)
{
char *homedrv;
char *homedir;
- char stuff[MAX_PATH + 1];
+ char *result;
if (((homedrv = getenv("HOMEDRIVE")) == NULL) ||
((homedir = getenv("HOMEPATH")) == NULL)) {
return (NULL);
}
- _snprintf(stuff, sizeof(stuff), "%s%s", homedrv, homedir);
- return (nni_strdup(stuff));
+ if (nni_asprintf(&result, "%s%s", homedrv, homedir) == 0) {
+ return (result);
+ }
+ return (NULL);
+}
+
+int
+nni_plat_file_type(const char *name, int *typep)
+{
+ HANDLE dirh;
+ WIN32_FIND_DATA data;
+
+ if ((dirh = FindFirstFile(name, &data)) == INVALID_HANDLE_VALUE) {
+ return (nni_win_error(GetLastError()));
+ }
+ (void) FindClose(dirh);
+ if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
+ *typep = NNI_PLAT_FILE_TYPE_DIR;
+ } else if (data.dwFileAttributes & FILE_ATTRIBUTE_DEVICE) {
+ *typep = NNI_PLAT_FILE_TYPE_OTHER;
+ } else if (data.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) {
+ *typep = NNI_PLAT_FILE_TYPE_OTHER;
+ } else {
+ *typep = NNI_PLAT_FILE_TYPE_FILE;
+ }
+ return (0);
}
char *
nni_plat_join_dir(const char *prefix, const char *suffix)
{
- char stuff[MAX_PATH + 1];
+ char *result;
+
+ if (nni_asprintf(&result, "%s\\%s", prefix, suffix) == 0) {
+ return (result);
+ }
+ return (NULL);
+}
+
+const char *
+nni_plat_file_basename(const char *name)
+{
+ const char *s;
- _snprintf(stuff, sizeof(stuff), "%s\\%s", prefix, suffix);
- return (nni_strdup(stuff));
+ // skip over drive designator if present
+ if (isalpha(name[0]) && (name[1] == ':')) {
+ name += 2;
+ }
+ s = name + strlen(name);
+ while (s > name) {
+ if ((*s == '\\') || (*s == '/')) {
+ return (s + 1);
+ }
+ s--;
+ }
+ return (name);
}
+
#endif // NNG_PLATFORM_WINDOWS \ No newline at end of file
diff --git a/src/supplemental/websocket/websocket.c b/src/supplemental/websocket/websocket.c
index c350a3c7..aca09749 100644
--- a/src/supplemental/websocket/websocket.c
+++ b/src/supplemental/websocket/websocket.c
@@ -1807,8 +1807,6 @@ nni_ws_dialer_init(nni_ws_dialer **dp, const char *addr)
nni_ws_dialer *d;
int rv;
nni_aio * aio;
- nni_url * url;
- char * host;
char * serv;
if ((d = NNI_ALLOC_STRUCT(d)) == NULL) {
diff --git a/src/transport/zerotier/zerotier.c b/src/transport/zerotier/zerotier.c
index f6594eb3..cef31a29 100644
--- a/src/transport/zerotier/zerotier.c
+++ b/src/transport/zerotier/zerotier.c
@@ -1,6 +1,6 @@
//
-// Copyright 2017 Garrett D'Amore <garrett@damore.org>
-// Copyright 2017 Capitar IT Group BV <info@capitar.com>
+// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
+// Copyright 2018 Capitar IT Group BV <info@capitar.com>
//
// This software is supplied under the terms of the MIT License, a
// copy of which should be located in the distribution where this
@@ -1212,17 +1212,14 @@ zt_state_put(ZT_Node *node, void *userptr, void *thr,
return;
}
- if ((path = nni_plat_join_dir(ztn->zn_path, fname)) == NULL) {
+ if ((path = nni_file_join(ztn->zn_path, fname)) == NULL) {
return;
}
if (len < 0) {
- (void) nni_plat_file_delete(path);
+ (void) nni_file_delete(path);
} else {
- if (strlen(ztn->zn_path) > 0) {
- (void) nni_plat_dir_create(ztn->zn_path);
- }
- (void) nni_plat_file_put(path, data, len);
+ (void) nni_file_put(path, data, len);
}
nni_strfree(path);
}
@@ -1260,11 +1257,11 @@ zt_state_get(ZT_Node *node, void *userptr, void *thr,
return (len);
}
- if ((path = nni_plat_join_dir(ztn->zn_path, fname)) == NULL) {
+ if ((path = nni_file_join(ztn->zn_path, fname)) == NULL) {
return (-1);
}
- if (nni_plat_file_get(path, &buf, &sz) != 0) {
+ if (nni_file_get(path, &buf, &sz) != 0) {
nni_strfree(path);
return (-1);
}
@@ -1475,9 +1472,6 @@ zt_node_create(zt_node **ztnp, const char *path)
(nni_random() % (zt_max_port - zt_ephemeral)) + zt_ephemeral);
nni_strlcpy(ztn->zn_path, path, sizeof(ztn->zn_path));
- if (strlen(ztn->zn_path) > 0) {
- (void) nni_plat_dir_create(ztn->zn_path);
- }
zrv = ZT_Node_new(&ztn->zn_znode, ztn, NULL, &zt_callbacks, zt_now());
if (zrv != ZT_RESULT_OK) {
zt_node_destroy(ztn);
@@ -1513,13 +1507,30 @@ zt_node_create(zt_node **ztnp, const char *path)
}
static int
+zt_walk_moons(const char *path, void *arg)
+{
+ zt_node * ztn = arg;
+ const char *bn = nni_file_basename(path);
+ char * ep;
+ uint64_t moonid;
+
+ if (strncmp(bn, "moon.", 5) != 0) {
+ return (NNI_FILE_WALK_CONTINUE);
+ }
+ moonid = strtoull(bn + 5, &ep, 16);
+ if (*ep == '\0') {
+ ZT_Node_orbit(ztn->zn_znode, NULL, moonid, 0);
+ }
+ return (NNI_FILE_WALK_CONTINUE);
+}
+
+static int
zt_node_find(zt_ep *ep)
{
zt_node * ztn;
int rv;
nng_sockaddr sa;
ZT_VirtualNetworkConfig *cf;
- void * dir;
NNI_LIST_FOREACH (&zt_nodes, ztn) {
if (strcmp(ep->ze_home, ztn->zn_path) == 0) {
@@ -1534,20 +1545,9 @@ zt_node_find(zt_ep *ep)
}
// Load moons
- if (nni_plat_dir_open(&dir, ep->ze_home) == 0) {
- uint64_t moonid;
- const char *fname;
- char * ep;
- while (nni_plat_dir_next(dir, &fname) == 0) {
- if (strncmp(fname, "moon.", 5) != 0) {
- continue;
- }
- moonid = strtoull(fname + 5, &ep, 16);
- if (*ep == '\0') {
- ZT_Node_orbit(ztn->zn_znode, NULL, moonid, 0);
- }
- }
- nni_plat_dir_close(dir);
+ if (strlen(ep->ze_home) != 0) {
+ (void) nni_file_walk(ep->ze_home, zt_walk_moons, ztn,
+ NNI_FILE_WALK_FILES_ONLY | NNI_FILE_WALK_SHALLOW);
}
done: