return rmdir(path);
 }
 
-static int slow_copyfile(const char *from, const char *to, mode_t mode)
+static int slow_copyfile(const char *from, const char *to)
 {
        int err = -1;
        char *line = NULL;
        size_t n;
        FILE *from_fp = fopen(from, "r"), *to_fp;
-       mode_t old_umask;
 
        if (from_fp == NULL)
                goto out;
 
-       old_umask = umask(mode ^ 0777);
        to_fp = fopen(to, "w");
-       umask(old_umask);
        if (to_fp == NULL)
                goto out_fclose_from;
 
        int fromfd, tofd;
        struct stat st;
        int err = -1;
+       char *tmp = NULL, *ptr = NULL;
 
        if (stat(from, &st))
                goto out;
 
-       if (st.st_size == 0) /* /proc? do it slowly... */
-               return slow_copyfile(from, to, mode);
-
-       fromfd = open(from, O_RDONLY);
-       if (fromfd < 0)
+       /* extra 'x' at the end is to reserve space for '.' */
+       if (asprintf(&tmp, "%s.XXXXXXx", to) < 0) {
+               tmp = NULL;
                goto out;
+       }
+       ptr = strrchr(tmp, '/');
+       if (!ptr)
+               goto out;
+       ptr = memmove(ptr + 1, ptr, strlen(ptr) - 1);
+       *ptr = '.';
 
-       tofd = creat(to, mode);
+       tofd = mkstemp(tmp);
        if (tofd < 0)
-               goto out_close_from;
+               goto out;
+
+       if (fchmod(tofd, mode))
+               goto out_close_to;
+
+       if (st.st_size == 0) { /* /proc? do it slowly... */
+               err = slow_copyfile(from, tmp);
+               goto out_close_to;
+       }
+
+       fromfd = open(from, O_RDONLY);
+       if (fromfd < 0)
+               goto out_close_to;
 
        err = copyfile_offset(fromfd, 0, tofd, 0, st.st_size);
 
-       close(tofd);
-       if (err)
-               unlink(to);
-out_close_from:
        close(fromfd);
+out_close_to:
+       close(tofd);
+       if (!err)
+               err = link(tmp, to);
+       unlink(tmp);
 out:
+       free(tmp);
        return err;
 }