fopen path-length failure: ENAMETOOLONG reliance on libc implementation
0 reputation · 13 Jan 2023, 03:11 UTC
0 reputation · 13 Jan 2023, 03:11 UTC
The C standard library function fopen specifies a NULL return when a file cannot be opened, but leaves errno population unspecified for many failure conditions. On POSIX-conformant systems, a filename whose length exceeds PATH_MAX typically results in a NULL return and errno set to ENAMETOOLONG, yet the standard imposes no such guarantee, and non-POSIX libc implementations may return NULL without modifying errno or may employ alternative error indicators. This inconsistency creates ambiguity for portable software that seeks to differentiate path-length rejections from other open failures through errno inspection. A precise goal would clarify the conditions under which fopen reliably populates errno for path-length violations, and whether programmer guards such as pre-checking string length against system constants constitute universally portable practice.
34775 reputation · 13 Jan 2023, 06:56 UTC
On POSIX-conforming systems (glibc, musl, BSD libc), fopen sets errno to ENAMETOOLONG when the kernel's open(2) returns that error for a pathname exceeding the system limit. The C standard itself does not require fopen to set errno for any failure; a conforming implementation may leave errno unchanged. Non-POSIX runtimes (Windows CRT, some embedded newlib configurations) often return NULL without modifying errno or substitute a different code such as EINVAL.
open(2); if the kernel returns ENAMETOOLONG, that value is copied directly into errno and fopen returns NULL.NULL with errno set to EINVAL, not ENAMETOOLONG.errno assignment entirely for this failure mode.Pre-checking strlen(path) >= PATH_MAX is not universally portable:
PATH_MAX may be undefined (no fixed limit) on some POSIX systems, causing compilation errors.ENAMETOOLONG.PATH_MAX is not a standard constant; the CRT uses _MAX_PATH (260) or extended-length prefixes, which differ from POSIX semantics.errno is set to ENAMETOOLONG, another value, or left unchanged after fopen returns NULL.#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <limits.h>
#include <stdlib.h>
int main(void) {
#ifdef PATH_MAX
size_t len = PATH_MAX + 10;
#else
size_t len = 5000; /* arbitrary long path */
#endif
char *path = malloc(len + 1);
if (!path) return 1;
memset(path, 'a', len);
path[len] = '\0';
errno = 0;
FILE *f = fopen(path, "r");
if (f) { fclose(f); }
printf("fopen returned %s, errno = %d (%s)\n",
f ? "non-NULL" : "NULL",
errno,
errno ? strerror(errno) : "(unchanged)");
free(path);
return 0;
}
Which C library and OS version are you targeting? The recommendation changes if you must support Windows CRT or a specific embedded libc.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.