Skip to content

Commit

Permalink
New platform API for storage methods.
Browse files Browse the repository at this point in the history
This includes converting the ZeroTier transport to use these.

The new API supports file creation, retrieval, and deletion. It
also supports directory methods for traversal, creation, and
deletion.  It also has a few methods to obtain well-known directories
like $TMPDIR and $HOME.

A rich test suite for this functionality is added as well.
  • Loading branch information
gdamore committed Oct 10, 2017
1 parent 52d3785 commit f14cdb7
Show file tree
Hide file tree
Showing 9 changed files with 734 additions and 48 deletions.
2 changes: 2 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ if (NNG_PLATFORM_POSIX)
platform/posix/posix_clock.c
platform/posix/posix_debug.c
platform/posix/posix_epdesc.c
platform/posix/posix_file.c
platform/posix/posix_ipc.c
platform/posix/posix_pipe.c
platform/posix/posix_pipedesc.c
Expand All @@ -131,6 +132,7 @@ if (NNG_PLATFORM_WINDOWS)
platform/windows/win_impl.h
platform/windows/win_clock.c
platform/windows/win_debug.c
platform/windows/win_file.c
platform/windows/win_iocp.c
platform/windows/win_ipc.c
platform/windows/win_pipe.c
Expand Down
50 changes: 47 additions & 3 deletions src/core/platform.h
Original file line number Diff line number Diff line change
Expand Up @@ -368,21 +368,65 @@ extern void nni_plat_pipe_close(int, int);
// determined by using an environment variable (NNG_STATE_DIR), or
// using some other application-specific method.
//
// We also support listing keys, for the case where a key must be looked
// up -- for example to get a list of certificates, or some such.
//

// 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.
extern int nni_plat_file_put(const char *, const void *, int);
extern int nni_plat_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.
extern int nni_plat_file_get(const char *, void **, int *);
// reference arguments. The data pointer should be freed with nni_free
// 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.
extern int nni_plat_file_delete(const char *);

// 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.
extern int nni_plat_dir_open(void **, const char *);

// 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. The returned name is valid until the next call to this
// function, or until the directory is closed. Only files are returned,
// subdirectories are not reported.
extern int nni_plat_dir_next(void *, const char **);

// nni_plat_dir_close closes the directory handle, freeing all
// resources associated with it.
extern void nni_plat_dir_close(void *);

// nni_plat_dir_create creates a directory. Any parent directories must
// already exist. If the directory already exists, 0 is returned.
extern int nni_plat_dir_create(const char *);

// nni_plat_dir_remove removes a directory, which must already be empty.
// If it does not exist, 0 is returned.
extern int nni_plat_dir_remove(const char *);

// nni_plat_temp_dir returns a temporary/scratch directory for the platform
// The result should be freed with nni_strfree().
extern char *nni_plat_temp_dir(void);

// nni_plat_home_dir returns the "home" directory for the user running the
// application. This is a convenient place to store preferences, etc.
// Applications should append an application specific directory name.
// The result should be freed with nni_strfree().
extern char *nni_plat_home_dir(void);

// nni_plat_join_dir joins to path components to make a path name.
// For example. on UNIX systems nni_plat_join_dir("/tmp", "a") returns
// "/tmp/a". The pathname returned should be freed with nni_strfree().
extern char *nni_plat_join_dir(const char *, 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.
#if defined(NNG_PLATFORM_POSIX)
Expand Down
207 changes: 207 additions & 0 deletions src/platform/posix/posix_file.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
//
// Copyright 2017 Garrett D'Amore <[email protected]>
// Copyright 2017 Capitar IT Group BV <[email protected]>
//
// 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
1 change: 1 addition & 0 deletions src/platform/windows/win_debug.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 },
Expand Down
Loading

0 comments on commit f14cdb7

Please sign in to comment.