aboutsummaryrefslogtreecommitdiff
path: root/src/platform
diff options
context:
space:
mode:
Diffstat (limited to 'src/platform')
-rw-r--r--src/platform/posix/posix_file.c207
-rw-r--r--src/platform/windows/win_debug.c1
-rw-r--r--src/platform/windows/win_file.c270
3 files changed, 478 insertions, 0 deletions
diff --git a/src/platform/posix/posix_file.c b/src/platform/posix/posix_file.c
new file mode 100644
index 00000000..d7033095
--- /dev/null
+++ b/src/platform/posix/posix_file.c
@@ -0,0 +1,207 @@
+//
+// Copyright 2017 Garrett D'Amore <garrett@damore.org>
+// Copyright 2017 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"
+
+#ifdef NNG_PLATFORM_POSIX
+
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+// File support.
+
+// 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
+// access by the entity running the application only.
+int
+nni_plat_file_put(const char *name, const void *data, size_t len)
+{
+ FILE *f;
+ int rv = 0;
+
+ if ((f = fopen(name, "wb")) == NULL) {
+ return (nni_plat_errno(errno));
+ }
+ if (fwrite(data, 1, len, f) != len) {
+ rv = nni_plat_errno(errno);
+ (void) unlink(name);
+ }
+ (void) fclose(f);
+ return (rv);
+}
+
+// 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.
+int
+nni_plat_file_get(const char *name, void **datap, size_t *lenp)
+{
+ FILE * f;
+ struct stat st;
+ int rv = 0;
+ int len;
+ void * data;
+
+ if ((f = fopen(name, "rb")) == NULL) {
+ return (nni_plat_errno(errno));
+ }
+
+ if (stat(name, &st) != 0) {
+ rv = nni_plat_errno(errno);
+ (void) fclose(f);
+ return (rv);
+ }
+
+ len = st.st_size;
+ if ((data = nni_alloc(len)) == NULL) {
+ rv = NNG_ENOMEM;
+ goto done;
+ }
+ if (fread(data, 1, len, f) != len) {
+ rv = nni_plat_errno(errno);
+ nni_free(data, len);
+ goto done;
+ }
+ *datap = data;
+ *lenp = len;
+done:
+ (void) fclose(f);
+ return (rv);
+}
+
+// nni_plat_file_delete deletes the named file.
+int
+nni_plat_file_delete(const char *name)
+{
+ if (unlink(name) < 0) {
+ return (nni_plat_errno(errno));
+ }
+ return (0);
+}
+
+// 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)
+{
+ DIR *dir;
+
+ if ((dir = opendir(name)) == NULL) {
+ 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));
+ }
+ return (0);
+}
+
+int
+nni_plat_dir_remove(const char *name)
+{
+ if (rmdir(name) != 0) {
+ if (errno == ENOENT) {
+ return (0);
+ }
+ 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 (;;) {
+ struct dirent *ent;
+
+ if ((ent = readdir((DIR *) dir)) == NULL) {
+ return (NNG_ENOENT);
+ }
+ // Skip "." and ".." -- we would like to skip all
+ // directories, but that would require checking full
+ // paths.
+ if ((strcmp(ent->d_name, ".") == 0) ||
+ (strcmp(ent->d_name, "..") == 0)) {
+ continue;
+ }
+ *namep = ent->d_name;
+ return (0);
+ }
+}
+
+// nni_plat_dir_close closes the directory handle, freeing all
+// resources associated with it.
+void
+nni_plat_dir_close(void *dir)
+{
+ (void) closedir((DIR *) dir);
+}
+
+char *
+nni_plat_temp_dir(void)
+{
+ char *temp;
+
+ // POSIX says $TMPDIR is required.
+ if ((temp = getenv("TMPDIR")) != NULL) {
+ return (nni_strdup(temp));
+ }
+ return (nni_strdup("/tmp"));
+}
+
+char *
+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.
+ if ((home = getenv("HOME")) != NULL) {
+ return (nni_strdup(home));
+ }
+ return (NULL);
+}
+
+char *
+nni_plat_join_dir(const char *prefix, const char *suffix)
+{
+ char * newdir;
+ size_t len;
+
+ len = strlen(prefix) + strlen(suffix) + 2;
+ newdir = nni_alloc(strlen(prefix) + strlen(suffix) + 2);
+ if (newdir != NULL) {
+ (void) snprintf(newdir, len, "%s/%s", prefix, suffix);
+ }
+ return (newdir);
+}
+
+#endif // NNG_PLATFORM_POSIX
diff --git a/src/platform/windows/win_debug.c b/src/platform/windows/win_debug.c
index 0113af58..00e327db 100644
--- a/src/platform/windows/win_debug.c
+++ b/src/platform/windows/win_debug.c
@@ -87,6 +87,7 @@ static struct {
{
// clang-format off
{ ERROR_FILE_NOT_FOUND, NNG_ENOENT },
+ { ERROR_PATH_NOT_FOUND, NNG_ENOENT },
{ ERROR_ACCESS_DENIED, NNG_EPERM },
{ ERROR_INVALID_HANDLE, NNG_ECLOSED },
{ ERROR_NOT_ENOUGH_MEMORY, NNG_ENOMEM },
diff --git a/src/platform/windows/win_file.c b/src/platform/windows/win_file.c
new file mode 100644
index 00000000..adb57a75
--- /dev/null
+++ b/src/platform/windows/win_file.c
@@ -0,0 +1,270 @@
+//
+// Copyright 2017 Garrett D'Amore <garrett@damore.org>
+// Copyright 2017 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"
+
+#ifdef NNG_PLATFORM_WINDOWS
+
+#include <stdio.h>
+#include <stdlib.h>
+
+// File support.
+
+// 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
+// access by the entity running the application only.
+int
+nni_plat_file_put(const char *name, const void *data, size_t len)
+{
+ HANDLE h;
+ int rv = 0;
+ DWORD nwrite;
+
+ h = CreateFile(name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL, NULL);
+ if (h == INVALID_HANDLE_VALUE) {
+ return (nni_win_error(GetLastError()));
+ }
+
+ if (!WriteFile(h, data, (DWORD) len, &nwrite, NULL)) {
+ rv = nni_win_error(GetLastError());
+ (void) DeleteFile(name);
+ goto done;
+ }
+ // These are regular files, synchronous operations. If we got a
+ // short write, then we should have gotten an error!
+ NNI_ASSERT(nwrite == len);
+
+done:
+ (void) CloseHandle(h);
+ return (rv);
+}
+
+// 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.
+int
+nni_plat_file_get(const char *name, void **datap, size_t *lenp)
+{
+ int rv = 0;
+ void * data;
+ DWORD sz;
+ DWORD nread;
+ HANDLE h;
+
+ h = CreateFile(name, GENERIC_READ, 0, NULL, OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL, NULL);
+ if (h == INVALID_HANDLE_VALUE) {
+ return (nni_win_error(GetLastError()));
+ }
+ // We choose not to support extraordinarily large files (>4GB)
+ if ((sz = GetFileSize(h, NULL)) == INVALID_FILE_SIZE) {
+ rv = nni_win_error(GetLastError());
+ goto done;
+ }
+ if ((data = nni_alloc((size_t) sz)) == NULL) {
+ rv = NNG_ENOMEM;
+ goto done;
+ }
+ if (!ReadFile(h, data, sz, &nread, NULL)) {
+ rv = nni_win_error(GetLastError());
+ nni_free(data, sz);
+ goto done;
+ }
+
+ // We can get a short read, indicating end of file. We return
+ // the actual number of bytes read. The fact that the data buffer
+ // is larger than this is ok, because our nni_free() routine just
+ // uses HeapFree(), which doesn't need a matching size.
+
+ *datap = data;
+ *lenp = (size_t) nread;
+done:
+ (void) CloseHandle(h);
+ return (rv);
+}
+
+// nni_plat_file_delete deletes the named file.
+int
+nni_plat_file_delete(const char *name)
+{
+ if (!DeleteFile(name)) {
+ return (nni_win_error(GetLastError()));
+ }
+ return (0);
+}
+
+// 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 {
+ 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;
+ 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;
+
+ 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);
+ }
+ return (nni_win_error(rv));
+ }
+ }
+ dh->cont = 1;
+
+ // Skip over directories.
+ while (dh->data.dwFileAttributes &
+ (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_HIDDEN)) {
+ 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);
+ }
+ 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];
+ int 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)
+{
+ if (!RemoveDirectory(name)) {
+ int rv = GetLastError();
+ if (rv == ERROR_PATH_NOT_FOUND) {
+ return (0);
+ }
+ return (nni_win_error(rv));
+ }
+ return (0);
+}
+
+char *
+nni_plat_temp_dir(void)
+{
+ char path[MAX_PATH + 1];
+
+ if (!GetTempPath(MAX_PATH + 1, path)) {
+ return (NULL);
+ }
+ return (nni_strdup(path));
+}
+
+char *
+nni_plat_home_dir(void)
+{
+ char *homedrv;
+ char *homedir;
+ char stuff[MAX_PATH + 1];
+
+ if (((homedrv = getenv("HOMEDRIVE")) == NULL) ||
+ ((homedir = getenv("HOMEPATH")) == NULL)) {
+ return (NULL);
+ }
+ _snprintf(stuff, sizeof(stuff), "%s%s", homedrv, homedir);
+ return (nni_strdup(stuff));
+}
+
+char *
+nni_plat_join_dir(const char *prefix, const char *suffix)
+{
+ char stuff[MAX_PATH + 1];
+
+ _snprintf(stuff, sizeof(stuff), "%s\\%s", prefix, suffix);
+ return (nni_strdup(stuff));
+}
+#endif // NNG_PLATFORM_WINDOWS \ No newline at end of file