rather than allocating a PATH_MAX-sized buffer when the caller does not provide an output buffer, work first with a PATH_MAX-sized temp buffer with automatic storage, and either copy it to the caller's buffer or strdup it on success. this not only avoids massive memory waste, but also avoids pulling in free (and thus the full malloc implementation) unnecessarily in static programs.
45 lines
841 B
C
45 lines
841 B
C
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <limits.h>
|
|
#include <sys/stat.h>
|
|
#include <fcntl.h>
|
|
#include <errno.h>
|
|
#include <unistd.h>
|
|
#include <string.h>
|
|
|
|
void __procfdname(char *, unsigned);
|
|
|
|
char *realpath(const char *restrict filename, char *restrict resolved)
|
|
{
|
|
int fd;
|
|
ssize_t r;
|
|
struct stat st1, st2;
|
|
char buf[15+3*sizeof(int)];
|
|
char tmp[PATH_MAX];
|
|
|
|
if (!filename) {
|
|
errno = EINVAL;
|
|
return 0;
|
|
}
|
|
|
|
fd = open(filename, O_PATH|O_NONBLOCK|O_CLOEXEC);
|
|
if (fd < 0) return 0;
|
|
__procfdname(buf, fd);
|
|
|
|
r = readlink(buf, tmp, sizeof tmp - 1);
|
|
if (r < 0) goto err;
|
|
tmp[r] = 0;
|
|
|
|
fstat(fd, &st1);
|
|
r = stat(tmp, &st2);
|
|
if (r<0 || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino) {
|
|
if (!r) errno = ELOOP;
|
|
goto err;
|
|
}
|
|
|
|
close(fd);
|
|
return resolved ? strcpy(resolved, tmp) : strdup(tmp);
|
|
err:
|
|
close(fd);
|
|
return 0;
|
|
}
|