fix aliasing-based undefined behavior in mbsrtowcs
[musl] / src / misc / realpath.c
index ef156fc..d2708e5 100644 (file)
@@ -1,49 +1,43 @@
 #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>
+#include "syscall.h"
 
-char *realpath(const char *filename, char *resolved)
+char *realpath(const char *restrict filename, char *restrict resolved)
 {
        int fd;
        ssize_t r;
        struct stat st1, st2;
        char buf[15+3*sizeof(int)];
-       int alloc = 0;
+       char tmp[PATH_MAX];
 
        if (!filename) {
                errno = EINVAL;
                return 0;
        }
 
-       fd = open(filename, O_RDONLY|O_NONBLOCK);
+       fd = sys_open(filename, O_PATH|O_NONBLOCK|O_CLOEXEC);
        if (fd < 0) return 0;
-       snprintf(buf, sizeof buf, "/proc/self/fd/%d", fd);
+       __procfdname(buf, fd);
 
-       if (!resolved) {
-               alloc = 1;
-               resolved = malloc(PATH_MAX);
-               if (!resolved) return 0;
-       }
-
-       r = readlink(buf, resolved, PATH_MAX-1);
+       r = readlink(buf, tmp, sizeof tmp - 1);
        if (r < 0) goto err;
-       resolved[r] = 0;
+       tmp[r] = 0;
 
        fstat(fd, &st1);
-       r = stat(resolved, &st2);
+       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;
+       __syscall(SYS_close, fd);
+       return resolved ? strcpy(resolved, tmp) : strdup(tmp);
 err:
-       if (alloc) free(resolved);
-       close(fd);
+       __syscall(SYS_close, fd);
        return 0;
 }