Coverage Report

Created: 2023-05-28 06:42

/src/netcdf-c/libnczarr/zdim.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright 2003-2019, University Corporation for Atmospheric
2
 * Research. See the COPYRIGHT file for copying and redistribution
3
 * conditions. */
4
5
/**
6
 * @file @internal This file is part of netcdf-4, a netCDF-like
7
 * interface for NCZ, or a ZARR backend for netCDF, depending on your
8
 * point of view.
9
 *
10
 * This file includes the ZARR code to deal with dimensions.
11
 *
12
 * @author Dennis Heimbigner, Ed Hartnett
13
 */
14
15
#include "zincludes.h"
16
17
/**
18
 * @internal Dimensions are defined in attributes attached to the
19
 * appropriate group in the data file.
20
 *
21
 * @param ncid File and group ID.
22
 * @param name Name of the new dimension.
23
 * @param len Length of the new dimension.
24
 * @param idp Pointer that gets the ID of the new dimension. Ignored
25
 * if NULL.
26
 *
27
 * @return ::NC_NOERR No error.
28
 * @return ::NC_EBADID Bad ncid.
29
 * @return ::NC_EMAXNAME Name is too long.
30
 * @return ::NC_EBADNAME Name breaks netCDF name rules.
31
 * @return ::NC_EINVAL Invalid input.
32
 * @return ::NC_EPERM Read-only file.
33
 * @return ::NC_EUNLIMIT Only one unlimited dim for classic model.
34
 * @return ::NC_ENOTINDEFINE Not in define mode.
35
 * @return ::NC_EDIMSIZE Dim length too large.
36
 * @return ::NC_ENAMEINUSE Name already in use in group.
37
 * @return ::NC_ENOMEM Out of memory.
38
 * @author Dennis Heimbigner, Ed Hartnett
39
 */
40
int
41
NCZ_def_dim(int ncid, const char *name, size_t len, int *idp)
42
0
{
43
0
    NC *nc;
44
0
    NC_GRP_INFO_T *grp;
45
0
    NC_FILE_INFO_T *h5;
46
0
    NC_DIM_INFO_T *dim;
47
0
    char norm_name[NC_MAX_NAME + 1];
48
0
    int stat = NC_NOERR;
49
50
0
    LOG((2, "%s: ncid 0x%x name %s len %d", __func__, ncid, name,
51
0
         (int)len));
52
53
    /* Find our global metadata structure. */
54
0
    if ((stat = nc4_find_nc_grp_h5(ncid, &nc, &grp, &h5)))
55
0
        return stat;
56
0
    assert(h5 && nc && grp);
57
58
    /* If the file is read-only, return an error. */
59
0
    if (h5->no_write)
60
0
        return NC_EPERM;
61
62
    /* Check some stuff if strict nc3 rules are in effect. */
63
0
    if (h5->cmode & NC_CLASSIC_MODEL)
64
0
    {
65
#ifdef LOOK
66
        /* Only one limited dimenson for strict nc3. */
67
        if (len == NC_UNLIMITED) {
68
      int i;
69
            for(i=0;i<ncindexsize(grp->dim);i++) {
70
                dim = (NC_DIM_INFO_T*)ncindexith(grp->dim,i);
71
                if(dim == NULL) continue;
72
                if (dim->unlimited)
73
                    return NC_EUNLIMIT;
74
            }
75
        }
76
        /* Must be in define mode for stict nc3. */
77
        if (!(h5->flags & NC_INDEF))
78
            return NC_ENOTINDEFINE;
79
#endif
80
0
    }
81
82
    /* Make sure this is a valid netcdf name. */
83
0
    if ((stat = nc4_check_name(name, norm_name)))
84
0
        return stat;
85
86
    /* Since unlimited is not supported, len > 0 */
87
0
    if(len <= 0)
88
0
        return NC_EDIMSIZE;
89
90
    /* For classic model: dim length has to fit in a 32-bit unsigned
91
     * int, as permitted for 64-bit offset format. */
92
0
    if (h5->cmode & NC_CLASSIC_MODEL)
93
0
        if(len > X_UINT_MAX) /* Backward compat */
94
0
            return NC_EDIMSIZE;
95
96
    /* Make sure the name is not already in use. */
97
0
    dim = (NC_DIM_INFO_T*)ncindexlookup(grp->dim,norm_name);
98
0
    if(dim != NULL)
99
0
        return NC_ENAMEINUSE;
100
101
    /* If it's not in define mode, enter define mode. Do this only
102
     * after checking all input data, so we only enter define mode if
103
     * input is good. */
104
0
    if (!(h5->flags & NC_INDEF))
105
0
        if ((stat = NCZ_redef(ncid)))
106
0
            return stat;
107
108
    /* Add a dimension to the list. The ID must come from the file
109
     * information, since dimids are visible in more than one group. */
110
0
    if ((stat = nc4_dim_list_add(grp, norm_name, len, -1, &dim)))
111
0
        return stat;
112
113
    /* Create struct for NCZ-specific dim info. */
114
0
    if (!(dim->format_dim_info = calloc(1, sizeof(NCZ_DIM_INFO_T))))
115
0
        return NC_ENOMEM;
116
0
    ((NCZ_DIM_INFO_T*)dim->format_dim_info)->common.file = h5;
117
118
    /* Pass back the dimid. */
119
0
    if (idp)
120
0
        *idp = dim->hdr.id;
121
122
0
    return stat;
123
0
}
124
125
/**
126
 * @internal Find out name and len of a dim. For an unlimited
127
 * dimension, the length is the largest length so far written. If the
128
 * name of lenp pointers are NULL, they will be ignored.
129
 *
130
 * @param ncid File and group ID.
131
 * @param dimid Dimension ID.
132
 * @param name Pointer that gets name of the dimension.
133
 * @param lenp Pointer that gets length of dimension.
134
 *
135
 * @return ::NC_NOERR No error.
136
 * @return ::NC_EBADID Bad ncid.
137
 * @return ::NC_EDIMSIZE Dimension length too large.
138
 * @return ::NC_EBADDIM Dimension not found.
139
 * @author Dennis Heimbigner, Ed Hartnett
140
 */
141
int
142
NCZ_inq_dim(int ncid, int dimid, char *name, size_t *lenp)
143
0
{
144
0
    NC *nc;
145
0
    NC_FILE_INFO_T *h5;
146
0
    NC_GRP_INFO_T *grp, *dim_grp;
147
0
    NC_DIM_INFO_T *dim;
148
0
    int stat = NC_NOERR;
149
150
0
    LOG((2, "%s: ncid 0x%x dimid %d", __func__, ncid, dimid));
151
152
    /* Find our global metadata structure. */
153
0
    if ((stat = nc4_find_nc_grp_h5(ncid, &nc, &grp, &h5)))
154
0
        return stat;
155
0
    assert(h5 && nc && grp);
156
157
    /* Find the dimension and its home group. */
158
0
    if ((stat = nc4_find_dim(grp, dimid, &dim, &dim_grp)))
159
0
        return stat;
160
0
    assert(dim);
161
162
    /* Return the dimension name, if the caller wants it. */
163
0
    if (name && dim->hdr.name)
164
0
        strcpy(name, dim->hdr.name);
165
166
    /* Return the dimension length, if the caller wants it. */
167
0
    if (lenp)
168
0
    {
169
#ifdef LOOK
170
        if (dim->unlimited)
171
        {
172
            /* Since this is an unlimited dimension, go to the file
173
               and see how many records there are. Take the max number
174
               of records from all the vars that share this
175
               dimension. */
176
            *lenp = 0;
177
            if ((stat = ncz_find_dim_len(dim_grp, dimid, &lenp)))
178
                return stat;
179
        }
180
        else
181
#endif
182
0
        {
183
0
            if (dim->too_long)
184
0
            {
185
0
                stat = NC_EDIMSIZE;
186
0
                *lenp = NC_MAX_UINT;
187
0
            }
188
0
            else
189
0
                *lenp = dim->len;
190
0
        }
191
0
    }
192
193
0
    return stat;
194
0
}
195
196
/**
197
 * @internal Rename a dimension, for those who like to prevaricate.
198
 *
199
 * @note If we're not in define mode, new name must be of equal or
200
 * less size, if strict nc3 rules are in effect for this file. But we
201
 * don't check this because reproducing the exact classic behavior
202
 * would be too difficult. See github issue #1340.
203
 *
204
 * @param ncid File and group ID.
205
 * @param dimid Dimension ID.
206
 * @param name New dimension name.
207
 *
208
 * @return ::NC_NOERR No error.
209
 * @return ::NC_EBADID Bad ncid.
210
 * @return ::NC_EHDFERR ZARR returned error.
211
 * @return ::NC_ENOMEM Out of memory.
212
 * @return ::NC_EINVAL Name must be provided.
213
 * @return ::NC_ENAMEINUSE Name is already in use in group.
214
 * @return ::NC_EMAXNAME Name is too long.
215
 * @return ::NC_EBADDIM Dimension not found.
216
 * @return ::NC_EBADNAME Name breaks netCDF name rules.
217
 * @return ::NC_EDIMMETA Unable to delete ZARR dataset.
218
 * @author Dennis Heimbigner, Ed Hartnett
219
 */
220
int
221
NCZ_rename_dim(int ncid, int dimid, const char *name)
222
0
{
223
0
    NC_GRP_INFO_T *grp;
224
0
    NC_DIM_INFO_T *dim;
225
0
    NC_FILE_INFO_T *h5;
226
0
    char norm_name[NC_MAX_NAME + 1];
227
0
    int stat;
228
229
    /* Note: name is new name */
230
0
    if (!name)
231
0
        return NC_EINVAL;
232
233
0
    LOG((2, "%s: ncid 0x%x dimid %d name %s", __func__, ncid,
234
0
         dimid, name));
235
236
    /* Find info for this file and group, and set pointer to each. */
237
0
    if ((stat = nc4_find_grp_h5(ncid, &grp, &h5)))
238
0
        return stat;
239
0
    assert(h5 && grp);
240
241
    /* Trying to write to a read-only file? No way, Jose! */
242
0
    if (h5->no_write)
243
0
        return NC_EPERM;
244
245
    /* Make sure this is a valid netcdf name. */
246
0
    if ((stat = nc4_check_name(name, norm_name)))
247
0
        return stat;
248
249
    /* Get the original dim. */
250
0
    if ((stat = nc4_find_dim(grp, dimid, &dim, NULL)))
251
0
        return stat;
252
0
    assert(dim && dim->format_dim_info);
253
254
    /* Check if new name is in use. */
255
0
    if (ncindexlookup(grp->dim, norm_name))
256
0
        return NC_ENAMEINUSE;
257
258
    /* Give the dimension its new name in metadata. UTF8 normalization
259
     * has been done. */
260
0
    assert(dim->hdr.name);
261
0
    free(dim->hdr.name);
262
0
    if (!(dim->hdr.name = strdup(norm_name)))
263
0
        return NC_ENOMEM;
264
0
    LOG((3, "dim is now named %s", dim->hdr.name));
265
266
    /* rebuild index. */
267
0
    if (!ncindexrebuild(grp->dim))
268
0
        return NC_EINTERNAL;
269
270
0
    return NC_NOERR;
271
0
}
272
273
int
274
NCZ_inq_unlimdims(int ncid, int *ndimsp, int *unlimdimidsp)
275
0
{
276
0
    if(ndimsp) *ndimsp = 0;
277
0
    return NC_NOERR;
278
0
}