Coverage Report

Created: 2023-05-28 06:42

/src/netcdf-c/libnczarr/zmap.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 "zincludes.h"
7
#include <stdarg.h>
8
#include "ncpathmgr.h"
9
10
/**************************************************/
11
/* Import the current implementations */
12
13
14
/**************************************************/
15
16
NCZM_FEATURES
17
nczmap_features(NCZM_IMPL impl)
18
0
{
19
0
    switch (impl) {
20
0
    case NCZM_FILE: return zmap_file.features;
21
#ifdef ENABLE_NCZARR_ZIP
22
    case NCZM_ZIP: return zmap_zip.features;
23
#endif
24
#ifdef ENABLE_S3
25
    case NCZM_S3: return zmap_s3sdk.features;
26
#endif
27
0
    default: break;
28
0
    }
29
0
    return NCZM_UNIMPLEMENTED;
30
0
}
31
32
int
33
nczmap_create(NCZM_IMPL impl, const char *path, int mode, size64_t flags, void* parameters, NCZMAP** mapp)
34
0
{
35
0
    int stat = NC_NOERR;
36
0
    NCZMAP* map = NULL;
37
0
    NCURI* uri = NULL;
38
    
39
0
    if(path == NULL || strlen(path) == 0)
40
0
  {stat = NC_EINVAL; goto done;}
41
42
0
    if(mapp) *mapp = NULL;
43
44
0
    switch (impl) {
45
0
    case NCZM_FILE:
46
0
        stat = zmap_file.create(path, mode, flags, parameters, &map);
47
0
  if(stat) goto done;
48
0
  break;
49
#ifdef ENABLE_NCZARR_ZIP
50
    case NCZM_ZIP:
51
        stat = zmap_zip.create(path, mode, flags, parameters, &map);
52
  if(stat) goto done;
53
  break;
54
#endif
55
#ifdef ENABLE_S3
56
    case NCZM_S3:
57
        stat = zmap_s3sdk.create(path, mode, flags, parameters, &map);
58
  if(stat) goto done;
59
  break;
60
#endif
61
0
    default:
62
0
  {stat = REPORT(NC_ENOTBUILT,"nczmap_create"); goto done;}
63
0
    }
64
0
    if(mapp) *mapp = map;
65
0
done:
66
0
    ncurifree(uri);
67
0
    return THROW(stat);
68
0
}
69
70
int
71
nczmap_open(NCZM_IMPL impl, const char *path, int mode, size64_t flags, void* parameters, NCZMAP** mapp)
72
0
{
73
0
    int stat = NC_NOERR;
74
0
    NCZMAP* map = NULL;
75
0
    NCURI* uri = NULL;
76
77
0
    if(path == NULL || strlen(path) == 0)
78
0
  {stat = NC_EINVAL; goto done;}
79
80
0
    if(mapp) *mapp = NULL;
81
82
0
    switch (impl) {
83
0
    case NCZM_FILE:
84
0
        stat = zmap_file.open(path, mode, flags, parameters, &map);
85
0
  if(stat) goto done;
86
0
  break;
87
#ifdef ENABLE_NCZARR_ZIP
88
    case NCZM_ZIP:
89
        stat = zmap_zip.open(path, mode, flags, parameters, &map);
90
  if(stat) goto done;
91
  break;
92
#endif
93
#ifdef ENABLE_S3
94
    case NCZM_S3:
95
        stat = zmap_s3sdk.open(path, mode, flags, parameters, &map);
96
  if(stat) goto done;
97
  break;
98
#endif
99
0
    default:
100
0
  {stat = REPORT(NC_ENOTBUILT,"nczmap_open"); goto done;}
101
0
    }
102
103
0
done:
104
0
    ncurifree(uri);
105
0
    if(!stat) {
106
0
        if(mapp) *mapp = map;
107
0
    }
108
0
    return THROW(stat);
109
0
}
110
111
/**************************************************/
112
/* API Wrapper */
113
114
int
115
nczmap_close(NCZMAP* map, int delete)
116
0
{
117
0
    int stat = NC_NOERR;
118
0
    if(map && map->api)
119
0
        stat = map->api->close(map,delete);
120
0
    return THROW(stat);
121
0
}
122
123
int
124
nczmap_exists(NCZMAP* map, const char* key)
125
0
{
126
0
    return map->api->exists(map, key);
127
0
}
128
129
int
130
nczmap_len(NCZMAP* map, const char* key, size64_t* lenp)
131
0
{
132
0
    return map->api->len(map, key, lenp);
133
0
}
134
135
int
136
nczmap_read(NCZMAP* map, const char* key, size64_t start, size64_t count, void* content)
137
0
{
138
0
    return map->api->read(map, key, start, count, content);
139
0
}
140
141
int
142
nczmap_write(NCZMAP* map, const char* key, size64_t start, size64_t count, const void* content)
143
0
{
144
0
    return map->api->write(map, key, start, count, content);
145
0
}
146
147
/* Define a static qsort comparator for strings for use with qsort */
148
static int
149
cmp_strings(const void* a1, const void* a2)
150
0
{
151
0
    const char** s1 = (const char**)a1;
152
0
    const char** s2 = (const char**)a2;
153
0
    return strcmp(*s1,*s2);
154
0
}
155
156
int
157
nczmap_search(NCZMAP* map, const char* prefix, NClist* matches)
158
0
{
159
0
    int stat = NC_NOERR;
160
0
    if((stat = map->api->search(map, prefix, matches)) == NC_NOERR) {
161
        /* sort the list */
162
0
        if(nclistlength(matches) > 1) {
163
0
      void* base = nclistcontents(matches);
164
0
            qsort(base, nclistlength(matches), sizeof(char*), cmp_strings);
165
0
  }
166
0
    }
167
0
    return stat;
168
0
}
169
170
/**************************************************/
171
/* Utilities */
172
173
int
174
nczm_split(const char* path, NClist* segments)
175
0
{
176
0
    return nczm_split_delim(path,NCZM_SEP[0],segments);
177
0
}
178
179
int
180
nczm_split_delim(const char* path, char delim, NClist* segments)
181
0
{
182
0
    return NC_split_delim(path,delim,segments);
183
0
}
184
185
/* concat the the segments with each segment preceded by '/' */
186
int
187
nczm_join(NClist* segments, char** pathp)
188
0
{
189
0
    int stat = NC_NOERR;
190
0
    int i;
191
0
    NCbytes* buf = NULL;
192
193
0
    if(segments == NULL)
194
0
  {stat = NC_EINVAL; goto done;}
195
0
    if((buf = ncbytesnew())==NULL)
196
0
  {stat = NC_ENOMEM; goto done;}
197
0
    if(nclistlength(segments) == 0)
198
0
        ncbytescat(buf,"/");
199
0
    else for(i=0;i<nclistlength(segments);i++) {
200
0
  const char* seg = nclistget(segments,i);
201
0
  if(seg[0] != '/')
202
0
      ncbytescat(buf,"/");
203
0
  ncbytescat(buf,seg);    
204
0
    }
205
206
0
done:
207
0
    if(!stat) {
208
0
  if(pathp) *pathp = ncbytesextract(buf);
209
0
    }
210
0
    ncbytesfree(buf);
211
0
    return THROW(stat);
212
0
}
213
214
int
215
nczm_concat(const char* prefix, const char* suffix, char** pathp)
216
0
{
217
0
    NCbytes* buf = ncbytesnew();
218
219
0
    if(prefix == NULL || strlen(prefix)==0) prefix = NCZM_SEP;
220
0
    if(suffix == NULL) suffix = "";
221
0
    ncbytescat(buf,prefix);
222
0
    if(ncbytesget(buf,ncbyteslength(buf)-1) == NCZM_SEP[0])
223
0
  ncbytessetlength(buf,ncbyteslength(buf)-1);
224
0
    if(strlen(suffix) > 0 && suffix[0] != NCZM_SEP[0])
225
0
  ncbytescat(buf,NCZM_SEP);
226
0
    ncbytescat(buf,suffix);
227
0
    if(pathp) *pathp = ncbytesextract(buf);
228
0
    ncbytesfree(buf);
229
0
    return NC_NOERR;
230
0
}
231
232
/* Concat multiple strings, but with no intervening separators */
233
int
234
nczm_appendn(char** resultp, int n, ...)
235
0
{
236
0
    va_list args;
237
0
    NCbytes* buf = ncbytesnew();
238
0
    int i;
239
240
0
    va_start(args, n);
241
0
    for(i=0;i<n;i++) {
242
0
  char* s = va_arg(args,char*);
243
0
  if(s != NULL) ncbytescat(buf,s);
244
0
    }
245
0
    ncbytesnull(buf);
246
0
    va_end(args);
247
0
    if(resultp) {*resultp = ncbytesextract(buf);}
248
0
    ncbytesfree(buf);
249
0
    return NC_NOERR;
250
0
}
251
252
/* A segment is defined as a '/' plus characters following up
253
   to the end or upto the next '/'
254
*/
255
int
256
nczm_divide_at(const char* key, int nsegs, char** prefixp, char** suffixp)
257
0
{
258
0
    int stat = NC_NOERR;
259
0
    char* prefix = NULL;
260
0
    char* suffix = NULL;
261
0
    size_t len, i;
262
0
    ptrdiff_t delta;
263
0
    const char* p;
264
0
    int abssegs = (nsegs >= 0 ?nsegs: -nsegs);
265
0
    int presegs = 0;
266
 
267
    /* Special case */
268
0
    if(key == NULL || strlen(key) == 0) goto done;
269
270
0
    p = (key[0] == '/' ? key+1 : key);
271
    /* Count number of segments */
272
0
    for(len=0;;) {
273
0
        const char* q = strchr(p,'/');    
274
0
  len++;
275
0
  if(q == NULL) break;
276
0
  p = q+1; /* start past leading '/' of next segment */
277
0
    }
278
0
    if(abssegs > len)
279
0
  {stat = NC_EINVAL; goto done;}
280
    /* find split point */
281
0
    if(nsegs >= 0)
282
0
  {presegs = abssegs;}
283
0
    else
284
0
  {presegs = (len - abssegs);}
285
286
    /* skip past the first presegs segments */
287
0
    for(p=key,i=0;i<presegs;i++) {
288
0
        const char* q = strchr(p+1,'/'); 
289
0
  if(q == NULL) {p = (p + strlen(p)); break;}
290
0
  else p = q;
291
0
    }
292
    /* p should point at the presegs+1 start point */
293
0
    delta = (p-key);    
294
0
    if(prefixp) {
295
0
        prefix = malloc(delta+1);
296
0
        memcpy(prefix,key,delta);
297
0
        prefix[delta] = '\0';
298
0
        *prefixp = prefix;
299
0
    } 
300
0
    if(suffixp) {
301
0
        suffix = strdup(p);
302
0
        *suffixp = suffix;
303
0
    }
304
0
done:
305
0
    return stat;
306
0
}
307
308
int
309
nczm_clear(NCZMAP* map)
310
0
{
311
0
    if(map) 
312
0
  nullfree(map->url);
313
0
    return NC_NOERR;
314
0
}
315
316
int
317
nczm_isabsolutepath(const char* path)
318
0
{
319
0
    if(path == NULL) return 0;
320
0
    switch (path[0]) {
321
0
    case '\\': return 1;
322
0
    case '/': return 1;
323
0
    case '\0': break;
324
0
    default:
325
  /* Check for windows drive letter */
326
0
  if(NChasdriveletter(path)) return 1;
327
0
        break;
328
0
    }
329
0
    return 0;
330
0
}
331
332
/* Convert forward slash to backslash ( !localize) or vice-versa (localize)*/
333
int
334
nczm_localize(const char* path, char** localpathp, int localize)
335
0
{
336
0
    int stat = NC_NOERR;
337
0
    char* localpath = NULL;
338
0
    char* p;
339
0
    int forward = 1;
340
0
    int offset = 0;
341
0
    static const char* windrive = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
342
343
#ifdef _MSC_VER
344
    forward = (localize?0:1);
345
#endif
346
    /* If path comes from a url, then it may start with: /x:/...
347
       where x is a drive letter. If so, then remove leading / */
348
0
    if(strlen(path) >= 4
349
0
       && path[0] == '/' && strchr(windrive,path[1]) != NULL
350
0
       && path[2] == ':' && path[3] == '/')
351
0
  offset = 1;
352
0
    if((localpath = strdup(path+offset))==NULL) return NC_ENOMEM;
353
354
0
    for(p=localpath;*p;p++) {
355
0
  if(forward && *p == '\\') *p = '/';
356
0
  else if(!forward && *p == '/') *p = '\\';
357
0
    }
358
0
    if(localpathp) {*localpathp = localpath; localpath = NULL;}
359
0
    nullfree(localpath);
360
0
    return stat;
361
0
}
362
363
/* Convert path0 to be:
364
1. absolute -- including drive letters
365
2. forward slashed -- we will convert back to back slash in nczm_fixpath
366
*/
367
368
int
369
nczm_canonicalpath(const char* path, char** cpathp)
370
0
{
371
0
    int ret = NC_NOERR;
372
0
    char* cpath = NULL;
373
0
    char* tmp1 = NULL;
374
375
0
    if(path == NULL) 
376
0
  {cpath = NULL; goto done;}
377
378
    /* Process path to make it be absolute*/
379
0
    if((tmp1 = NCpathabsolute(path))==NULL) {ret = NC_ENOMEM; goto done;}
380
381
    /* Fix slashes to be forward for now */
382
0
    if((ret = nczm_localize(tmp1,&cpath,!LOCALIZE))) goto done;
383
384
0
    if(cpathp) {*cpathp = cpath; cpath = NULL;}
385
0
done:
386
0
    nullfree(tmp1);
387
0
    nullfree(cpath);
388
0
    return THROW(ret);    
389
0
}
390
391
/* extract the first segment of a path */
392
int
393
nczm_segment1(const char* path, char** seg1p)
394
0
{
395
0
    int ret = NC_NOERR;
396
0
    char* seg1 = NULL;
397
0
    const char* p = NULL;
398
0
    const char* q = NULL;
399
0
    ptrdiff_t delta;
400
401
0
    if(path == NULL) 
402
0
  {seg1 = NULL; goto done;}
403
404
0
    p = path;
405
0
    if(*p == '/') p++; /* skip any leading '/' */
406
0
    q = strchr(p,'/');
407
0
    if(q == NULL) q = p+strlen(p); /* point to stop character */
408
0
    delta = (q-p);
409
0
    if((seg1 = (char*)malloc(delta+1))==NULL)
410
0
        {ret = NC_ENOMEM; goto done;}
411
0
    memcpy(seg1,p,delta);
412
0
    seg1[delta] = '\0';
413
414
0
    if(seg1p) {*seg1p = seg1; seg1 = NULL;}
415
0
done:
416
0
    nullfree(seg1);
417
0
    return THROW(ret);    
418
0
}
419
420
/*
421
Extract the last segment from path.
422
*/
423
424
int
425
nczm_lastsegment(const char* path, char** lastp)
426
0
{
427
0
    int ret = NC_NOERR;
428
0
    const char* last = NULL;
429
430
0
    if(path == NULL)
431
0
  {if(lastp) *lastp = NULL; goto done;}
432
433
0
    last = strrchr(path,'/');
434
0
    if(last == NULL) last = path; else last++;
435
436
0
    if(lastp) *lastp = strdup(last);
437
438
0
done:
439
0
    return THROW(ret);    
440
0
}
441
442
/*
443
Extract the basename from a path.
444
Basename is last segment minus one extension.
445
*/
446
447
int
448
nczm_basename(const char* path, char** basep)
449
0
{
450
0
    int stat = NC_NOERR;
451
0
    char* base = NULL;
452
0
    char* last = NULL;
453
0
    const char* p = NULL;
454
0
    ptrdiff_t delta;
455
456
0
    if((stat=nczm_lastsegment(path,&last))) goto done;
457
458
0
    if(last == NULL) goto done;
459
0
    p = strrchr(last,'.');
460
0
    if(p == NULL) p = last+strlen(last);
461
0
    delta = (p - last);
462
0
    if((base = (char*)malloc(delta+1))==NULL)
463
0
        {stat = NC_ENOMEM; goto done;}
464
0
    memcpy(base,last,delta);
465
0
    base[delta] = '\0';
466
0
    if(basep) {*basep = base; base = NULL;}
467
0
done:
468
0
    nullfree(last);
469
0
    nullfree(base);
470
0
    return THROW(stat);    
471
0
}
472
473
/* bubble sort a list of strings */
474
void
475
nczm_sortlist(NClist* l)
476
0
{
477
0
    nczm_sortenvv(nclistlength(l),(char**)nclistcontents(l));
478
0
}
479
480
static int
481
nczm_compare(const void* arg1, const void* arg2)
482
0
{
483
0
    char* n1 = *((char**)arg1);
484
0
    char* n2 = *((char**)arg2);
485
0
    return strcmp(n1,n2);
486
0
}
487
488
/* quick sort a list of strings */
489
void
490
nczm_sortenvv(int n, char** envv)
491
0
{
492
0
    if(n <= 1) return;
493
0
    qsort(envv, n, sizeof(char*), nczm_compare);
494
#if 0
495
{int i;
496
for(i=0;i<n;i++)
497
fprintf(stderr,">>> sorted: [%d] %s\n",i,(const char*)envv[i]);
498
}
499
#endif
500
0
}
501
502
void
503
NCZ_freeenvv(int n, char** envv)
504
0
{
505
0
    int i;
506
0
    char** p;
507
0
    if(envv == NULL) return;
508
0
    if(n < 0)
509
0
       {for(n=0, p = envv; *p; n++); /* count number of strings */}
510
0
    for(i=0;i<n;i++) {
511
0
        if(envv[i]) {
512
0
      free(envv[i]);
513
0
  }
514
0
    }
515
0
    free(envv);    
516
0
}