netcdf-c/include/ncpathmgr.h
Dennis Heimbigner 9380790ea8 Support MSYS2/Mingw platform
re:

The current netcdf-c release has some problems with the mingw platform
on windows. Mostly they are path issues.

Changes to support mingw+msys2:
-------------------------------
* Enable option of looking into the windows registry to find
  the mingw root path. In aid of proper path handling.
* Add mingw+msys as a specific platform in configure.ac and move testing
  of the platform to the front so it is available early.
* Handle mingw X libncpoco (dynamic loader) properly even though
  mingw does not yet support it.
* Handle mingw X plugins properly even though mingw does not yet support it.
* Alias pwd='pwd -W' to better handle paths in shell scripts.
* Plus a number of other minor compile irritations.
* Disallow the use of multiple nc_open's on the same file for windows
  (and mingw) because windows does not seem to handle these properly.
  Not sure why we did not catch this earlier.
* Add mountpoint info to dpathmgr.c to help support mingw.
* Cleanup dpathmgr conversions.

Known problems:
---------------
* I have not been able to get shared libraries to work, so
  plugins/filters must be disabled.
* There is some kind of problem with libcurl that I have not solved,
  so all uses of libcurl (currently DAP+Byterange) must be disabled.

Misc. other fixes:
------------------
* Cleanup the relationship between ENABLE_PLUGINS and various other flags
  in CMakeLists.txt and configure.ac.
* Re-arrange the TESTDIRS order in Makefile.am.
* Add pseudo-breakpoint to nclog.[ch] for debugging.
* Improve the documentation of the path manager code in ncpathmgr.h
* Add better support for relative paths in dpathmgr.c
* Default the mode args to NCfopen to include "b" (binary) for windows.
* Add optional debugging output in various places.
* Make sure that everything builds with plugins disabled.
* Fix numerous (s)printf inconsistencies betweenb the format spec
  and the arguments.
2021-12-23 22:18:56 -07:00

243 lines
8.1 KiB
C

/*
* Copyright 2018, University Corporation for Atmospheric Research
* See netcdf/COPYRIGHT file for copying and redistribution conditions.
*/
#ifndef _NCPATHMGR_H_
#define _NCPATHMGR_H_
#include "config.h"
#include <stdlib.h>
#include <stdio.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_DIRENT_H
#include <dirent.h>
#endif
#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
#include "ncexternl.h"
/*
The path management code attempts to take an arbitrary path and convert
it to a form acceptable to the current platform.
Assumptions about Input path:
1. It is not a URL
2. It conforms to the format expected by one of the following:
Linux (/x/y/...),
Cygwin (/cygdrive/D/...),
Windows|MINGW (D:\...),
Windows network path (\\mathworks\...)
MSYS (/D/...),
4. It is encoded in the local platform character set. Note that
for most systems, this is utf-8. But for Windows, the
encoding is most likely some form of ANSI code page, probably
the windows 1252 encoding. Note that in any case, the path
must be representable in the local Code Page.
Note that all input paths first have all back slashes (\)
converted to forward (/), so following rules are in terms of /.
Parsing Rules:
1. A relative path is left as is with no drive letter.
2. A leading '/cygdrive/D' will be converted to
drive letter D if D is alpha-char.
3. A leading D:/... is treated as a windows drive letter
4. A leading /d/... is treated as a windows drive letter
if the platform is MSYS2.
5. A leading // is a windows network path and is converted
to a drive letter using the fake drive letter "/".
So '//svc/x/y' translates to '/:/svc/x/y'.
6. All other cases are assumed to be Unix variants with no drive letter.
After parsing, the following pieces of information are kept in a struct.
a. kind: The inferred path type (e.g. cygwin, unix, etc)
b. drive: The drive letter if any
c. path: The path is everything after the drive letter
For output, NCpathcvt produces a re-written path that is acceptable
to the current platform (the one on which the code is running).
Additional root mount point information is obtained for Cygwin and MSYS.
The root mount point is found as follows (in order of precedence):
1. Registry: get the value of the key named "HKEY_LOCAL_MACHINE/SOFTWARE/Cygwin/setup".
2. Environment: get the value of MSYS2_PREFIX
The re-write rules (unparsing) are given the above three pieces
of info + the current platform + the root mount point (if any).
The conversion rules are as follows.
Platform | No Input Driv | Input Drive
----------------------------------------------------
NCPD_NIX | <path> | /<drive>/path
NCPD_CYGWIN | /<path> | /cygdrive/<drive>/<path>
NCPD_WIN | <mountpoint>/<path> | <drive>:<path>
NCPD_MSYS | <mountpoint>/<path> | <drive>:<path>
Notes:
1. MINGW without MSYS is treated like WIN.
2. The reason msys and win prefix the mount point is because
the IO functions are handled directly by Windows, hence
the conversion must look like a true windows path with a drive.
*/
#ifndef WINPATH
#if defined _WIN32 || defined __MINGW32__
#define WINPATH 1
#endif
#endif
/* Define wrapper constants for use with NCaccess */
/* Define wrapper constants for use with NCaccess */
#ifdef _WIN32
#define ACCESS_MODE_EXISTS 0
#define ACCESS_MODE_R 4
#define ACCESS_MODE_W 2
#define ACCESS_MODE_RW 6
#ifndef O_RDONLY
#define O_RDONLY _O_RDONLY
#define O_RDWR _O_RDWR
#define O_APPEND _O_APPEND
#define O_BINARY _O_BINARY
#define O_CREAT _O_CREAT
#define O_EXCL _O_EXCL
#endif
#else
#define ACCESS_MODE_EXISTS (F_OK)
#define ACCESS_MODE_R (R_OK)
#define ACCESS_MODE_W (W_OK)
#define ACCESS_MODE_RW (R_OK|W_OK)
#endif
#ifdef _WIN32
#ifndef S_IFDIR
#define S_IFDIR _S_IFDIR
#define S_IFREG _S_IFREG
#endif
#ifndef S_ISDIR
#define S_ISDIR(mode) ((mode) & _S_IFDIR)
#define S_ISREG(mode) ((mode) & _S_IFREG)
#endif
#endif /*_WIN32*/
/*
WARNING: you should never need to explictly call this function;
rather it is invoked as part of the wrappers for e.g. NCfopen, etc.
This function is intended to be Idempotent: f(f(x) == f(x).
This means it is ok to call it repeatedly with no harm.
Unless, of course, an error occurs.
*/
EXTERNL char* NCpathcvt(const char* path);
/**
It is often convenient to convert a path to some canonical format
that has some desirable properties:
1. All backslashes have been converted to forward slash
2. It can be suffixed or prefixed by simple concatenation
with a '/' separator. The exception being if the base part
may be absolute, in which case, suffixing only is allowed;
the user is responsible for getting this right.
To this end we choose the cygwin format as our standard canonical form.
If the path has a windows drive letter, then it is represented
in the cygwin "/cygdrive/<drive-letter>" form.
If it is a windows network path, then it starts with "//".
If it is on *nix* platform, then this sequence will never appear
and the canonical path will look like a standard *nix* path.
*/
EXTERNL int NCpathcanonical(const char* srcpath, char** canonp);
EXTERNL int NChasdriveletter(const char* path);
EXTERNL int NCisnetworkpath(const char* path);
/* Canonicalize and make absolute by prefixing the current working directory */
EXTERNL char* NCpathabsolute(const char* name);
/* Check if this path appears to start with a windows drive letter */
EXTERNL int NChasdriveletter(const char* path);
/* Convert from the local coding (e.g. ANSI) to utf-8;
note that this can produce unexpected results for Windows
because it first converts to wide character and then to utf8. */
EXTERNL int NCpath2utf8(const char* path, char** u8p);
/* Wrap various stdio and unistd IO functions.
It is especially important to use for windows so that
NCpathcvt (above) is invoked on the path.
*/
#if defined(WINPATH)
/* path converter wrappers*/
EXTERNL FILE* NCfopen(const char* path, const char* flags);
EXTERNL int NCopen3(const char* path, int flags, int mode);
EXTERNL int NCopen2(const char* path, int flags);
EXTERNL int NCaccess(const char* path, int mode);
EXTERNL int NCremove(const char* path);
EXTERNL int NCmkdir(const char* path, int mode);
EXTERNL int NCrmdir(const char* path);
EXTERNL char* NCgetcwd(char* cwdbuf, size_t len);
EXTERNL int NCmkstemp(char* buf);
#ifdef HAVE_SYS_STAT_H
EXTERNL int NCstat(const char* path, struct stat* buf);
#endif
#ifdef HAVE_DIRENT_H
EXTERNL DIR* NCopendir(const char* path);
EXTERNL int NCclosedir(DIR* ent);
#endif
#else /*!WINPATH*/
#define NCfopen(path,flags) fopen((path),(flags))
#define NCopen3(path,flags,mode) open((path),(flags),(mode))
#define NCopen2(path,flags) open((path),(flags))
#define NCremove(path) remove(path)
#define NCaccess(path,mode) access(path,mode)
#define NCmkdir(path,mode) mkdir(path,mode)
#define NCgetcwd(buf,len) getcwd(buf,len)
#define NCmkstemp(buf) mkstemp(buf);
#define NCcwd(buf, len) getcwd(buf,len)
#define NCrmdir(path) rmdir(path)
#define NCunlink(path) unlink(path)
#ifdef HAVE_SYS_STAT_H
#define NCstat(path,buf) stat(path,buf)
#endif
#ifdef HAVE_DIRENT_H
#define NCopendir(path) opendir(path)
#define NCclosedir(ent) closedir(ent)
#endif
#endif /*!WINPATH*/
/* Platform independent */
#define NCclose(fd) close(fd)
#define NCfstat(fd,buf) fstat(fd,buf)
/**************************************************/
/* Following definitions are for testing only */
/* Possible Kinds Of Output */
#define NCPD_UNKNOWN 0
#define NCPD_NIX 1
#define NCPD_MSYS 2
#define NCPD_CYGWIN 3
#define NCPD_WIN 4
/* #define NCPD_MINGW NCPD_WIN *alias*/
#define NCPD_REL 6 /* actual kind is unknown */
EXTERNL char* NCpathcvt_test(const char* path, int ukind, int udrive);
EXTERNL int NCgetlocalpathkind(void);
EXTERNL int NCgetinputpathkind(const char* inpath);
EXTERNL const char* NCgetkindname(int kind);
EXTERNL void printutf8hex(const char* s, char* sx);
EXTERNL int getmountpoint(char*, size_t);
/**************************************************/
/* From dutil.c */
EXTERNL char* NC_backslashEscape(const char* s);
EXTERNL char* NC_backslashUnescape(const char* esc);
EXTERNL char* NC_shellUnescape(const char* esc);
#endif /* _NCPATHMGR_H_ */