#include "realpath.h"
#include "fcntl.h"
static inline char *flexible_realpath_at(pid_t pid, int dirfd, const char *path,
rw_status *h,
enum last_symlink_handling lasth) {
if (!path) return NULL;
char *rawpath = NULL;
do {
const char *procself = "/proc/self/";
const int procselflen = strlen(procself);
if (strlen(path) > procselflen &&
!memcmp(path, procself, procselflen)) {
char *out = malloc(PATH_MAX);
snprintf(out, PATH_MAX, "/proc/%d/%s", pid, path + procselflen);
rawpath = out;
break;
}
if (path[0] == '/') {
rawpath = strdup(path);
break;
}
char *proc_fd = malloc(PATH_MAX);
if (dirfd >= 0 && dirfd != AT_FDCWD) snprintf(proc_fd, PATH_MAX, "/proc/%d/fd/%d", pid, dirfd);
else snprintf(proc_fd, PATH_MAX, "/proc/%d/cwd", pid);
char *cwd = malloc(PATH_MAX);
int linklen = readlink(proc_fd, cwd, PATH_MAX);
if (linklen < 0) {
fprintf(stderr, "unable to determine cwd from %s i.e. fd %d!!! (%s)\n",
proc_fd, dirfd, strerror(errno));
return NULL;
}
cwd[linklen] = 0;
int total_len = strlen(cwd) + strlen(path) + 4;
if (total_len > PATH_MAX) cwd = realloc(cwd, total_len);
strcat(cwd, "/");
strcat(cwd, path);
free(proc_fd);
rawpath = cwd;
break;
} while (0);
char *rp = flexible_realpath(rawpath, h, lasth);
free(rawpath);
return rp;
}
static inline void read_dir_fd(pid_t pid, int dirfd, rw_status *h) {
char *abspath = flexible_realpath_at(pid, dirfd, ".", h, look_for_file_or_directory);
if (!lookup_in_hash(&h->mkdir, abspath)) {
insert_hashset(&h->readdir, abspath);
}
free(abspath);
}
static inline void read_something_at(pid_t pid, int dirfd, const char *path,
rw_status *h, enum last_symlink_handling lh) {
char *abspath = flexible_realpath_at(pid, dirfd, path, h, lh);
if (!abspath) return;
struct stat st;
if (!lookup_in_hash(&h->written, abspath) && !stat(abspath, &st) && S_ISREG(st.st_mode)) {
insert_hashset(&h->read, abspath);
}
free(abspath);
}
static inline void write_something_at(pid_t pid, int dirfd, const char *path,
rw_status *h, enum last_symlink_handling lh) {
char *abspath = flexible_realpath_at(pid, dirfd, path, h, lh);
insert_hashset(&h->written, abspath);
delete_from_hashset(&h->read, abspath);
free(abspath);
}
static inline void read_file_at(pid_t pid, int dirfd, const char *path,
rw_status *h) {
read_something_at(pid, dirfd, path, h, look_for_file_or_directory);
}
static inline void maybe_read_file_at(pid_t pid, int dirfd, const char *path,
rw_status *h) {
read_something_at(pid, dirfd, path, h, look_for_file_or_directory);
}
static inline void write_file_at(pid_t pid, int dirfd, const char *path,
rw_status *h) {
write_something_at(pid, dirfd, path, h, look_for_file_or_directory);
}
static inline void read_link_at(pid_t pid, int dirfd, const char *path,
rw_status *h) {
read_something_at(pid, dirfd, path, h, look_for_symlink);
}
static inline void write_link_at(pid_t pid, int dirfd, const char *path,
rw_status *h) {
write_something_at(pid, dirfd, path, h, look_for_symlink);
}