Skip to content

libhdf5: nc_create reports every H5Fcreate failure as EACCES ("Permission denied") #3430

Description

@hyoklee

Summary

NC4_create_file reports every H5Fcreate failure as the POSIX errno EACCES (13), so nc_strerror renders any netCDF-4 create failure as "Permission denied" — whatever actually went wrong. Two consequences:

  • The diagnosis is usually wrong, and it points users at file permissions, which are usually fine.
  • A positive POSIX errno is returned where the API documents netCDF status codes (NC_NOERR or negative NC_E*). nc_strerror only produces a sensible string here by falling through to strerror.

libhdf5/hdf5create.c on main (db5a7f9), both call sites:

            if ((hdf5_info->hdfid = nc4_H5Fcreate(path, flags, fcpl_id, fapl_id)) < 0)
                BAIL(EACCES);                       /* line 244, diskless */
        }
        else /* Normal file */
        {
            /* Create the HDF5 file. */
            if ((hdf5_info->hdfid = nc4_H5Fcreate(path, flags, fcpl_id, fapl_id)) < 0)
                BAIL(EACCES);                       /* line 250, normal */
        }

The line immediately above the first one already does the conventional thing — if (H5Pset_fapl_core(...) < 0) BAIL(NC_EHDFERR); — so this looks like an oversight rather than a deliberate mapping.

Reproducer

Stock netCDF-C and HDF5, no plugins or drivers involved. The path's directory does not exist, so the real error is ENOENT:

#include <netcdf.h>
#include <stdio.h>
static void try_create(const char *p, int cmode, const char *label) {
    int ncid, stat = nc_create(p, cmode, &ncid);
    printf("%-10s nc_create(\"%s\") -> %d (%s)\n", label, p, stat, nc_strerror(stat));
    if (!stat) nc_close(ncid);
}
int main(void) {
    try_create("no_such_dir/x.nc", NC_NETCDF4, "netcdf-4");
    try_create("no_such_dir/x.nc", 0,          "classic");
    return 0;
}
netcdf-4   nc_create("no_such_dir/x.nc") -> 13 (Permission denied)
classic    nc_create("no_such_dir/x.nc") -> 2 (No such file or directory)

The classic dispatcher gets it right for the same path; only the netCDF-4 path claims a permission problem. And a genuine permission failure (creating in a chmod 555 directory) also returns 13, so the two are indistinguishable from the API.

How this cost real time

We hit it through a VFD, where nothing about the failure was permission-related: a CLIO VFD build rejected an HDF5_DRIVER_CONFIG string whose grammar had changed upstream, H5Fcreate failed, and the application reported

Sorry! Unexpected result, .../nc_perf/tst_chunks3.c, line: 314 - Permission denied

Only strace settled it — no syscall in the process ever returned EACCES, and the file was never even opened for writing. Any FAPL, VFD, VOL, or plugin-loading failure lands on these two lines, and HDF5 2.x makes it harder still: driver callbacks now run inside H5_BEFORE_USER_CB, so a driver's own pushed error does not reach the caller's stack and all the user sees is H5FD_open(): can't open file. With BAIL(EACCES) on top, netCDF-4 users get "Permission denied" for a config-string typo.

Suggested fix

Return NC_EHDFERR at both sites, matching the surrounding code — or map the HDF5 error stack to a netCDF status if a finer answer is wanted, but in any case not a bare positive errno. Happy to send a PR if you'd like it in this shape.

If the intent was to keep reporting a real EACCES distinctly, that could be done deliberately (e.g. access()/errno check on the parent directory) rather than by assuming every create failure is one.

Environment

  • netCDF-C main (tested at 984d9758, a local branch whose only delta is an unrelated MSVC build fix under nc_perf/; libhdf5/hdf5create.c is identical to main @ db5a7f93)
  • HDF5 develop @ 562e6028 (2.3.0), shared, thread-safety off, zlib on
  • x86-64 Linux (WSL2, glibc 2.39), gcc 13

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions