/* * Portable xxxat() functions. * * Copyright (C) 2010 Karel Zak */ #include #include #include #include #include "at.h" #include "c.h" int fstat_at(int dir, const char *dirname, const char *filename, struct stat *st, int nofollow) { #ifdef HAVE_FSTATAT return fstatat(dir, filename, st, nofollow ? AT_SYMLINK_NOFOLLOW : 0); #else if (*filename != '/') { char path[PATH_MAX]; int len; len = snprintf(path, sizeof(path), "%s/%s", dirname, filename); if (len < 0 || len + 1 > sizeof(path)) return -1; return nofollow ? lstat(path, st) : stat(path, st); } return nofollow ? lstat(filename, st) : stat(filename, st); #endif } int open_at(int dir, const char *dirname, const char *filename, int flags) { #ifdef HAVE_FSTATAT return openat(dir, filename, flags); #else if (*filename != '/') { char path[PATH_MAX]; int len; len = snprintf(path, sizeof(path), "%s/%s", dirname, filename); if (len < 0 || len + 1 > sizeof(path)) return -1; return open(path, flags); } return open(filename, flags); #endif } FILE *fopen_at(int dir, const char *dirname, const char *filename, int flags, const char *mode) { int fd = open_at(dir, dirname, filename, flags); if (fd < 0) return NULL; return fdopen(fd, mode); } ssize_t readlink_at(int dir, const char *dirname, const char *pathname, char *buf, size_t bufsiz) { #ifdef HAVE_FSTATAT return readlinkat(dir, pathname, buf, bufsiz); #else if (*pathname != '/') { char path[PATH_MAX]; int len; len = snprintf(path, sizeof(path), "%s/%s", dirname, pathname); if (len < 0 || len + 1 > sizeof(path)) return -1; return readlink(path, buf, bufsiz); } return readlink(pathname, buf, bufsiz); #endif } #ifdef TEST_PROGRAM_AT #include #include #include #include int main(int argc, char *argv[]) { DIR *dir; struct dirent *d; char *dirname; if (argc != 2) { fprintf(stderr, "usage: %s \n", argv[0]); exit(EXIT_FAILURE); } dirname = argv[1]; dir = opendir(dirname); if (!dir) err(EXIT_FAILURE, "%s: open failed", dirname); while ((d = readdir(dir))) { struct stat st; FILE *f; printf("%32s ", d->d_name); if (fstat_at(dirfd(dir), dirname, d->d_name, &st, 0) == 0) printf("%16jd bytes ", st.st_size); else printf("%16s bytes ", "???"); f = fopen_at(dirfd(dir), dirname, d->d_name, O_RDONLY, "r"); printf(" %s\n", f ? "OK" : strerror(errno)); if (f) fclose(f); } closedir(dir); return EXIT_SUCCESS; } #endif