diff options
| author | Garrett D'Amore <garrett@damore.org> | 2018-01-10 16:14:54 -0800 |
|---|---|---|
| committer | Garrett D'Amore <garrett@damore.org> | 2018-01-11 06:42:19 -0800 |
| commit | 3dd4cbf8efcfd574e2244798a86edd2f10c9cb45 (patch) | |
| tree | a5087862282f1ed950cf3daf3c3e45078b9e4216 /src/platform/windows/win_file.c | |
| parent | 282da09430fc39d8f93d78b828d3653e95318255 (diff) | |
| download | nng-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/platform/windows/win_file.c')
| -rw-r--r-- | src/platform/windows/win_file.c | 309 |
1 files changed, 192 insertions, 117 deletions
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 |
