/src/gdal/netcdf-c-4.7.4/libdispatch/dutil.c
Line | Count | Source |
1 | | /********************************************************************* |
2 | | * Copyright 2018, UCAR/Unidata |
3 | | * See netcdf/COPYRIGHT file for copying and redistribution conditions. |
4 | | *********************************************************************/ |
5 | | |
6 | | #include "config.h" |
7 | | #include <stdlib.h> |
8 | | #include <string.h> |
9 | | #include <stdio.h> |
10 | | #ifdef HAVE_UNISTD_H |
11 | | #include <unistd.h> |
12 | | #endif |
13 | | #ifdef HAVE_SYS_STAT_H |
14 | | #include <sys/stat.h> |
15 | | #endif |
16 | | #ifdef HAVE_FCNTL_H |
17 | | #include <fcntl.h> |
18 | | #endif |
19 | | #ifdef _MSC_VER |
20 | | #include <io.h> |
21 | | #endif |
22 | | #include "netcdf.h" |
23 | | #include "ncuri.h" |
24 | | #include "ncbytes.h" |
25 | | #include "nclist.h" |
26 | | #include "nclog.h" |
27 | | #include "ncwinpath.h" |
28 | | |
29 | | extern int mkstemp(char *template); |
30 | | |
31 | | #define NC_MAX_PATH 4096 |
32 | | |
33 | | #define LBRACKET '[' |
34 | | #define RBRACKET ']' |
35 | | |
36 | | /**************************************************/ |
37 | | /** |
38 | | * Provide a hidden interface to allow utilities |
39 | | * to check if a given path name is really an ncdap4 url. |
40 | | * If no, return null, else return basename of the url |
41 | | * minus any extension. |
42 | | */ |
43 | | |
44 | | int |
45 | | NC__testurl(const char* path, char** basenamep) |
46 | 0 | { |
47 | 0 | NCURI* uri; |
48 | 0 | int ok = NC_NOERR; |
49 | 0 | if(ncuriparse(path,&uri)) |
50 | 0 | ok = NC_EURL; |
51 | 0 | else { |
52 | 0 | char* slash = (uri->path == NULL ? NULL : strrchr(uri->path, '/')); |
53 | 0 | char* dot; |
54 | 0 | if(slash == NULL) slash = (char*)path; else slash++; |
55 | 0 | slash = nulldup(slash); |
56 | 0 | if(slash == NULL) |
57 | 0 | dot = NULL; |
58 | 0 | else |
59 | 0 | dot = strrchr(slash, '.'); |
60 | 0 | if(dot != NULL && dot != slash) *dot = '\0'; |
61 | 0 | if(basenamep) |
62 | 0 | *basenamep=slash; |
63 | 0 | else if(slash) |
64 | 0 | free(slash); |
65 | 0 | } |
66 | 0 | ncurifree(uri); |
67 | 0 | return ok; |
68 | 0 | } |
69 | | |
70 | | /* Return 1 if this machine is little endian */ |
71 | | int |
72 | | NC_isLittleEndian(void) |
73 | 0 | { |
74 | 0 | union { |
75 | 0 | unsigned char bytes[SIZEOF_INT]; |
76 | 0 | int i; |
77 | 0 | } u; |
78 | 0 | u.i = 1; |
79 | 0 | return (u.bytes[0] == 1 ? 1 : 0); |
80 | 0 | } |
81 | | |
82 | | char* |
83 | | NC_backslashEscape(const char* s) |
84 | 0 | { |
85 | 0 | const char* p; |
86 | 0 | char* q; |
87 | 0 | size_t len; |
88 | 0 | char* escaped = NULL; |
89 | |
|
90 | 0 | len = strlen(s); |
91 | 0 | escaped = (char*)malloc(1+(2*len)); /* max is everychar is escaped */ |
92 | 0 | if(escaped == NULL) return NULL; |
93 | 0 | for(p=s,q=escaped;*p;p++) { |
94 | 0 | char c = *p; |
95 | 0 | switch (c) { |
96 | 0 | case '\\': |
97 | 0 | case '/': |
98 | 0 | case '.': |
99 | 0 | case '@': |
100 | 0 | *q++ = '\\'; *q++ = '\\'; |
101 | 0 | break; |
102 | 0 | default: *q++ = c; break; |
103 | 0 | } |
104 | 0 | } |
105 | 0 | *q = '\0'; |
106 | 0 | return escaped; |
107 | 0 | } |
108 | | |
109 | | char* |
110 | | NC_backslashUnescape(const char* esc) |
111 | 0 | { |
112 | 0 | size_t len; |
113 | 0 | char* s; |
114 | 0 | const char* p; |
115 | 0 | char* q; |
116 | |
|
117 | 0 | if(esc == NULL) return NULL; |
118 | 0 | len = strlen(esc); |
119 | 0 | s = (char*)malloc(len+1); |
120 | 0 | if(s == NULL) return NULL; |
121 | 0 | for(p=esc,q=s;*p;) { |
122 | 0 | switch (*p) { |
123 | 0 | case '\\': |
124 | 0 | p++; |
125 | | /* fall thru */ |
126 | 0 | default: *q++ = *p++; break; |
127 | 0 | } |
128 | 0 | } |
129 | 0 | *q = '\0'; |
130 | 0 | return s; |
131 | 0 | } |
132 | | |
133 | | char* |
134 | | NC_entityescape(const char* s) |
135 | 0 | { |
136 | 0 | const char* p; |
137 | 0 | char* q; |
138 | 0 | size_t len; |
139 | 0 | char* escaped = NULL; |
140 | 0 | const char* entity; |
141 | |
|
142 | 0 | len = strlen(s); |
143 | 0 | escaped = (char*)malloc(1+(6*len)); /* 6 = |'| */ |
144 | 0 | if(escaped == NULL) return NULL; |
145 | 0 | for(p=s,q=escaped;*p;p++) { |
146 | 0 | char c = *p; |
147 | 0 | switch (c) { |
148 | 0 | case '&': entity = "&"; break; |
149 | 0 | case '<': entity = "<"; break; |
150 | 0 | case '>': entity = ">"; break; |
151 | 0 | case '"': entity = """; break; |
152 | 0 | case '\'': entity = "'"; break; |
153 | 0 | default : entity = NULL; break; |
154 | 0 | } |
155 | 0 | if(entity == NULL) |
156 | 0 | *q++ = c; |
157 | 0 | else { |
158 | 0 | len = strlen(entity); |
159 | 0 | memcpy(q,entity,len); |
160 | 0 | q+=len; |
161 | 0 | } |
162 | 0 | } |
163 | 0 | *q = '\0'; |
164 | 0 | return escaped; |
165 | 0 | } |
166 | | |
167 | | /** |
168 | | Wrap mktmp and return the generated path, |
169 | | or null if failed. |
170 | | Base is the base file path. XXXXX is appended |
171 | | to allow mktmp add its unique id. |
172 | | Return the generated path. |
173 | | */ |
174 | | |
175 | | char* |
176 | | NC_mktmp(const char* base) |
177 | 0 | { |
178 | 0 | int fd; |
179 | 0 | char* cvtpath = NULL; |
180 | 0 | char tmp[NC_MAX_PATH]; |
181 | 0 | #ifdef HAVE_MKSTEMP |
182 | 0 | mode_t mask; |
183 | 0 | #endif |
184 | | |
185 | | /* Make sure that this path conversion has been applied */ |
186 | 0 | cvtpath = NCpathcvt(base); |
187 | 0 | strncpy(tmp,cvtpath,sizeof(tmp)); |
188 | 0 | nullfree(cvtpath); |
189 | 0 | strncat(tmp, "XXXXXX", sizeof(tmp) - strlen(tmp) - 1); |
190 | |
|
191 | 0 | #ifdef HAVE_MKSTEMP |
192 | | /* Note Potential problem: old versions of this function |
193 | | leave the file in mode 0666 instead of 0600 */ |
194 | 0 | mask=umask(0077); |
195 | 0 | fd = mkstemp(tmp); |
196 | 0 | (void)umask(mask); |
197 | | #else /* !HAVE_MKSTEMP */ |
198 | | { |
199 | | #ifdef HAVE_MKTEMP |
200 | | #ifdef _MSC_VER |
201 | | /* Use _mktemp_s */ |
202 | | _mktemp_s(tmp,sizeof(tmp)-1); |
203 | | #else /*!_MSC_VER*/ |
204 | | mktemp(tmp); |
205 | | tmo[sizeof[tmp]-1] = '\0'; |
206 | | #endif |
207 | | #else /* !HAVE_MKTEMP */ |
208 | | /* Need to simulate by using some kind of pseudo-random number */ |
209 | | { |
210 | | int rno = rand(); |
211 | | char spid[7]; |
212 | | if(rno < 0) rno = -rno; |
213 | | snprintf(spid,sizeof(spid),"%06d",rno); |
214 | | strncat(tmp,spid,sizeof(tmp) - strlen(tmp) - 1); |
215 | | } |
216 | | #endif /* HAVE_MKTEMP */ |
217 | | #ifdef _MSC_VER |
218 | | fd=NCopen3(tmp,O_RDWR|O_BINARY|O_CREAT, _S_IREAD|_S_IWRITE); |
219 | | #else |
220 | | fd=NCopen3(tmp,O_RDWR|O_CREAT|O_EXCL, S_IRWXU); |
221 | | #endif |
222 | | } |
223 | | #endif /* !HAVE_MKSTEMP */ |
224 | 0 | if(fd < 0) { |
225 | 0 | nclog(NCLOGERR, "Could not create temp file: %s",tmp); |
226 | 0 | return NULL; |
227 | 0 | } else |
228 | 0 | close(fd); |
229 | 0 | return strdup(tmp); |
230 | 0 | } |
231 | | |
232 | | int |
233 | | NC_readfile(const char* filename, NCbytes* content) |
234 | 0 | { |
235 | 0 | int ret = NC_NOERR; |
236 | 0 | FILE* stream = NULL; |
237 | 0 | char part[1024]; |
238 | |
|
239 | | #ifdef _WIN32 |
240 | | stream = NCfopen(filename,"rb"); |
241 | | #else |
242 | 0 | stream = NCfopen(filename,"r"); |
243 | 0 | #endif |
244 | 0 | if(stream == NULL) {ret=errno; goto done;} |
245 | 0 | for(;;) { |
246 | 0 | size_t count = fread(part, 1, sizeof(part), stream); |
247 | 0 | if(count <= 0) break; |
248 | 0 | ncbytesappendn(content,part,count); |
249 | 0 | if(ferror(stream)) {ret = NC_EIO; goto done;} |
250 | 0 | if(feof(stream)) break; |
251 | 0 | } |
252 | 0 | ncbytesnull(content); |
253 | 0 | done: |
254 | 0 | if(stream) fclose(stream); |
255 | 0 | return ret; |
256 | 0 | } |
257 | | |
258 | | int |
259 | | NC_writefile(const char* filename, size_t size, void* content) |
260 | 0 | { |
261 | 0 | int ret = NC_NOERR; |
262 | 0 | FILE* stream = NULL; |
263 | 0 | void* p; |
264 | 0 | size_t remain; |
265 | |
|
266 | | #ifdef _WIN32 |
267 | | stream = NCfopen(filename,"wb"); |
268 | | #else |
269 | 0 | stream = NCfopen(filename,"w"); |
270 | 0 | #endif |
271 | 0 | if(stream == NULL) {ret=errno; goto done;} |
272 | 0 | p = content; |
273 | 0 | remain = size; |
274 | 0 | while(remain > 0) { |
275 | 0 | size_t written = fwrite(p, 1, remain, stream); |
276 | 0 | if(ferror(stream)) {ret = NC_EIO; goto done;} |
277 | 0 | if(feof(stream)) break; |
278 | 0 | remain -= written; |
279 | 0 | } |
280 | 0 | done: |
281 | 0 | if(stream) fclose(stream); |
282 | 0 | return ret; |
283 | 0 | } |
284 | | |
285 | | /* |
286 | | Parse a path as a url and extract the modelist. |
287 | | If the path is not a URL, then return a NULL list. |
288 | | If a URL, but modelist is empty or does not exist, |
289 | | then return empty list. |
290 | | */ |
291 | | int |
292 | | NC_getmodelist(const char* path, NClist** modelistp) |
293 | 0 | { |
294 | 0 | int stat=NC_NOERR; |
295 | 0 | NClist* modelist = NULL; |
296 | 0 | NCURI* uri = NULL; |
297 | 0 | const char* modestr = NULL; |
298 | 0 | const char* p = NULL; |
299 | 0 | const char* endp = NULL; |
300 | |
|
301 | 0 | ncuriparse(path,&uri); |
302 | 0 | if(uri == NULL) goto done; /* not a uri */ |
303 | | |
304 | | /* Get the mode= arg from the fragment */ |
305 | 0 | modelist = nclistnew(); |
306 | 0 | modestr = ncurilookup(uri,"mode"); |
307 | 0 | if(modestr == NULL || strlen(modestr) == 0) goto done; |
308 | | /* Parse the mode string at the commas or EOL */ |
309 | 0 | p = modestr; |
310 | 0 | for(;;) { |
311 | 0 | char* s; |
312 | 0 | ptrdiff_t slen; |
313 | 0 | endp = strchr(p,','); |
314 | 0 | if(endp == NULL) endp = p + strlen(p); |
315 | 0 | slen = (endp - p); |
316 | 0 | if((s = malloc(slen+1)) == NULL) {stat = NC_ENOMEM; goto done;} |
317 | 0 | memcpy(s,p,slen); |
318 | 0 | s[slen] = '\0'; |
319 | 0 | nclistpush(modelist,s); |
320 | 0 | if(*endp == '\0') break; |
321 | 0 | p = endp+1; |
322 | 0 | } |
323 | | |
324 | 0 | done: |
325 | 0 | if(stat == NC_NOERR) { |
326 | 0 | if(modelistp) {*modelistp = modelist; modelist = NULL;} |
327 | 0 | } |
328 | 0 | ncurifree(uri); |
329 | 0 | nclistfree(modelist); |
330 | 0 | return stat; |
331 | 0 | } |
332 | | |
333 | | /* |
334 | | Check "mode=" list for a path and return 1 if present, 0 otherwise. |
335 | | */ |
336 | | int |
337 | | NC_testmode(const char* path, const char* tag) |
338 | 0 | { |
339 | 0 | int stat = NC_NOERR; |
340 | 0 | int found = 0; |
341 | 0 | int i; |
342 | 0 | NClist* modelist = NULL; |
343 | |
|
344 | 0 | if((stat = NC_getmodelist(path, &modelist))) goto done; |
345 | 0 | for(i=0;i<nclistlength(modelist);i++) { |
346 | 0 | const char* value = nclistget(modelist,i); |
347 | 0 | if(strcasecmp(tag,value)==0) {found = 1; break;} |
348 | 0 | } |
349 | | |
350 | 0 | done: |
351 | 0 | nclistfreeall(modelist); |
352 | 0 | return found; |
353 | 0 | } |