/src/gdal/netcdf-c-4.7.4/libdispatch/dwinpath.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright 2018, University Corporation for Atmospheric Research |
3 | | * See netcdf/COPYRIGHT file for copying and redistribution conditions. |
4 | | */ |
5 | | |
6 | | #include "config.h" |
7 | | #include <stdlib.h> |
8 | | #include <stdio.h> |
9 | | #include <string.h> |
10 | | #include <assert.h> |
11 | | #include <errno.h> |
12 | | #ifdef HAVE_FCNTL_H |
13 | | #include <fcntl.h> |
14 | | #endif |
15 | | #ifdef HAVE_UNISTD_H |
16 | | #include <unistd.h> |
17 | | #endif |
18 | | #ifdef _MSC_VER |
19 | | #include <io.h> |
20 | | #endif |
21 | | |
22 | | #include "ncexternl.h" |
23 | | #include "ncwinpath.h" |
24 | | |
25 | | extern char *realpath(const char *path, char *resolved_path); |
26 | | |
27 | | #undef PATHFORMAT |
28 | | |
29 | | /* |
30 | | Code to provide some path conversion code so that |
31 | | cygwin and (some) mingw paths can be passed to open/fopen |
32 | | for Windows. Other cases will be added as needed. |
33 | | Rules: |
34 | | 1. a leading single alpha-character path element (e.g. /D/...) |
35 | | will be interpreted as a windows drive letter. |
36 | | 2. a leading '/cygdrive/X' will be converted to |
37 | | a drive letter X if X is alpha-char. |
38 | | 3. a leading D:/... is treated as a windows drive letter |
39 | | 4. a relative path will be converted to an absolute path. |
40 | | 5. If any of the above is encountered, then forward slashes |
41 | | will be converted to backslashes. |
42 | | All other cases are passed thru unchanged |
43 | | */ |
44 | | |
45 | | |
46 | | /* Define legal windows drive letters */ |
47 | | static const char* windrive = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; |
48 | | |
49 | | static const size_t cdlen = 10; /* strlen("/cygdrive/") */ |
50 | | |
51 | | static int pathdebug = -1; |
52 | | |
53 | | static char* makeabsolute(const char* relpath); |
54 | | |
55 | | EXTERNL |
56 | | char* /* caller frees */ |
57 | | NCpathcvt(const char* path) |
58 | 0 | { |
59 | 0 | char* outpath = NULL; |
60 | 0 | char* p; |
61 | 0 | char* q; |
62 | 0 | size_t pathlen; |
63 | |
|
64 | 0 | if(path == NULL) goto done; /* defensive driving */ |
65 | | |
66 | | /* Check for path debug env vars */ |
67 | 0 | if(pathdebug < 0) { |
68 | 0 | const char* s = getenv("NCPATHDEBUG"); |
69 | 0 | pathdebug = (s == NULL ? 0 : 1); |
70 | 0 | } |
71 | |
|
72 | 0 | pathlen = strlen(path); |
73 | | |
74 | | /* 1. look for MSYS path /D/... */ |
75 | 0 | if(pathlen >= 2 |
76 | 0 | && (path[0] == '/' || path[0] == '\\') |
77 | 0 | && strchr(windrive,path[1]) != NULL |
78 | 0 | && (path[2] == '/' || path[2] == '\\' || path[2] == '\0')) { |
79 | | /* Assume this is a mingw path */ |
80 | 0 | outpath = (char*)malloc(pathlen+3); /* conservative */ |
81 | 0 | if(outpath == NULL) goto done; |
82 | 0 | q = outpath; |
83 | 0 | *q++ = path[1]; |
84 | 0 | *q++ = ':'; |
85 | 0 | strncpy(q,&path[2],pathlen); |
86 | 0 | if(strlen(outpath) == 2) |
87 | 0 | strcat(outpath,"/"); |
88 | 0 | goto slashtrans; |
89 | 0 | } |
90 | | |
91 | | /* 2. Look for leading /cygdrive/D where D is a single-char drive letter */ |
92 | 0 | if(pathlen >= (cdlen+1) |
93 | 0 | && memcmp(path,"/cygdrive/",cdlen)==0 |
94 | 0 | && strchr(windrive,path[cdlen]) != NULL |
95 | 0 | && (path[cdlen+1] == '/' |
96 | 0 | || path[cdlen+1] == '\\' |
97 | 0 | || path[cdlen+1] == '\0')) { |
98 | | /* Assume this is a cygwin path */ |
99 | 0 | outpath = (char*)malloc(pathlen+1); /* conservative */ |
100 | 0 | if(outpath == NULL) goto done; |
101 | 0 | outpath[0] = path[cdlen]; /* drive letter */ |
102 | 0 | outpath[1] = ':'; |
103 | 0 | strcpy(&outpath[2],&path[cdlen+1]); |
104 | 0 | if(strlen(outpath) == 2) |
105 | 0 | strcat(outpath,"/"); |
106 | 0 | goto slashtrans; |
107 | 0 | } |
108 | | |
109 | | /* 3. Look for leading D: where D is a single-char drive letter */ |
110 | 0 | if(pathlen >= 2 |
111 | 0 | && strchr(windrive,path[0]) != NULL |
112 | 0 | && path[1] == ':' |
113 | 0 | && (path[2] == '\0' || path[2] == '/' || path[2] == '\\')) { |
114 | 0 | outpath = strdup(path); |
115 | 0 | goto slashtrans; |
116 | 0 | } |
117 | | |
118 | | /* 4. Look for relative path */ |
119 | 0 | if(pathlen > 1 && path[0] == '.') { |
120 | 0 | outpath = makeabsolute(path); |
121 | 0 | goto slashtrans; |
122 | 0 | } |
123 | | |
124 | | /* Other: just pass thru */ |
125 | 0 | outpath = strdup(path); |
126 | 0 | goto done; |
127 | | |
128 | 0 | slashtrans: |
129 | | /* In order to help debugging, and if not using MSC_VER or MINGW, |
130 | | convert back slashes to forward, else convert forward to back |
131 | | */ |
132 | 0 | p = outpath; |
133 | | /* In all #1 or #2 cases, translate '/' -> '\\' */ |
134 | 0 | for(;*p;p++) { |
135 | 0 | if(*p == '/') {*p = '\\';} |
136 | 0 | } |
137 | | #ifdef PATHFORMAT |
138 | | #ifndef _MSC_VER |
139 | | p = outpath; |
140 | | /* Convert '\' back to '/' */ |
141 | | for(;*p;p++) { |
142 | | if(*p == '\\') {*p = '/';} |
143 | | } |
144 | | } |
145 | | #endif /*!_MSC_VER*/ |
146 | | #endif /*PATHFORMAT*/ |
147 | |
|
148 | 0 | done: |
149 | 0 | if(pathdebug) { |
150 | 0 | fprintf(stderr,"XXXX: inpath=|%s| outpath=|%s|\n", |
151 | 0 | path?path:"NULL",outpath?outpath:"NULL"); |
152 | 0 | fflush(stderr); |
153 | 0 | } |
154 | 0 | return outpath; |
155 | 0 | } |
156 | | |
157 | | static char* |
158 | | makeabsolute(const char* relpath) |
159 | 0 | { |
160 | 0 | char* path = NULL; |
161 | | #ifdef _WIN32 |
162 | | path = _fullpath(NULL,relpath,8192); |
163 | | #else |
164 | 0 | path = realpath(relpath, NULL); |
165 | 0 | #endif |
166 | 0 | if(path == NULL) |
167 | 0 | path = strdup(relpath); |
168 | 0 | return path; |
169 | 0 | } |
170 | | |
171 | | #ifdef WINPATH |
172 | | |
173 | | /* |
174 | | Provide wrappers for open and fopen. |
175 | | */ |
176 | | |
177 | | EXTERNL |
178 | | FILE* |
179 | | NCfopen(const char* path, const char* flags) |
180 | | { |
181 | | FILE* f = NULL; |
182 | | char* cvtname = NCpathcvt(path); |
183 | | if(cvtname == NULL) return NULL; |
184 | | f = fopen(cvtname,flags); |
185 | | free(cvtname); |
186 | | return f; |
187 | | } |
188 | | |
189 | | EXTERNL |
190 | | int |
191 | | NCopen3(const char* path, int flags, int mode) |
192 | | { |
193 | | int fd = -1; |
194 | | char* cvtname = NCpathcvt(path); |
195 | | if(cvtname == NULL) return -1; |
196 | | fd = open(cvtname,flags,mode); |
197 | | free(cvtname); |
198 | | return fd; |
199 | | } |
200 | | |
201 | | EXTERNL |
202 | | int |
203 | | NCopen2(const char *path, int flags) |
204 | | { |
205 | | return NCopen3(path,flags,0); |
206 | | } |
207 | | |
208 | | /* |
209 | | Provide wrappers for other file system functions |
210 | | */ |
211 | | |
212 | | /* Return access applied to path+mode */ |
213 | | EXTERNL |
214 | | int |
215 | | NCaccess(const char* path, int mode) |
216 | | { |
217 | | int status = 0; |
218 | | char* cvtname = NCpathcvt(path); |
219 | | if(cvtname == NULL) return -1; |
220 | | #ifdef _MSC_VER |
221 | | status = _access(cvtname,mode); |
222 | | #else |
223 | | status = access(cvtname,mode); |
224 | | #endif |
225 | | free(cvtname); |
226 | | return status; |
227 | | } |
228 | | |
229 | | EXTERNL |
230 | | int |
231 | | NCremove(const char* path) |
232 | | { |
233 | | int status = 0; |
234 | | char* cvtname = NCpathcvt(path); |
235 | | if(cvtname == NULL) return ENOENT; |
236 | | status = remove(cvtname); |
237 | | free(cvtname); |
238 | | return status; |
239 | | } |
240 | | |
241 | | #endif /*WINPATH*/ |