blob: f8bfe1399992a9b09270b4b9e631b122d99e0dff [file] [log] [blame]
bigbiff bigbiffe60683a2013-02-22 20:55:50 -05001/*
2 * Portable xxxat() functions.
3 *
4 * No copyright is claimed. This code is in the public domain; do with
5 * it what you wish.
6 *
7 * Written by Karel Zak <kzak@redhat.com>
8 */
9#include <stdio.h>
10#include <stdlib.h>
11#include <fcntl.h>
12#include <sys/stat.h>
13
14#include "at.h"
15#include "c.h"
16
17#ifdef HAVE_FSTATAT
18int fstat_at(int dir, const char *dirname __attribute__ ((__unused__)),
19 const char *filename, struct stat *st, int nofollow)
20{
21 return fstatat(dir, filename, st,
22 nofollow ? AT_SYMLINK_NOFOLLOW : 0);
23}
24#else
25int fstat_at(int dir, const char *dirname, const char *filename,
26 struct stat *st, int nofollow)
27{
28
29 if (*filename != '/') {
30 char path[PATH_MAX];
31 int len;
32
33 len = snprintf(path, sizeof(path), "%s/%s", dirname, filename);
34 if (len < 0 || len + 1 > sizeof(path))
35 return -1;
36
37 return nofollow ? lstat(path, st) : stat(path, st);
38 }
39
40 return nofollow ? lstat(filename, st) : stat(filename, st);
41}
42#endif
43
44#ifdef HAVE_FSTATAT
45int open_at(int dir, const char *dirname __attribute__ ((__unused__)),
46 const char *filename, int flags)
47{
48 return openat(dir, filename, flags);
49}
50#else
51int open_at(int dir, const char *dirname, const char *filename, int flags)
52{
53 if (*filename != '/') {
54 char path[PATH_MAX];
55 int len;
56
57 len = snprintf(path, sizeof(path), "%s/%s", dirname, filename);
58 if (len < 0 || len + 1 > sizeof(path))
59 return -1;
60
61 return open(path, flags);
62 }
63 return open(filename, flags);
64}
65#endif
66
67FILE *fopen_at(int dir, const char *dirname, const char *filename, int flags,
68 const char *mode)
69{
70 int fd = open_at(dir, dirname, filename, flags);
71
72 if (fd < 0)
73 return NULL;
74
75 return fdopen(fd, mode);
76}
77
78#ifdef HAVE_FSTATAT
79ssize_t readlink_at(int dir, const char *dirname __attribute__ ((__unused__)),
80 const char *pathname, char *buf, size_t bufsiz)
81{
82 return readlinkat(dir, pathname, buf, bufsiz);
83}
84#else
85ssize_t readlink_at(int dir, const char *dirname, const char *pathname,
86 char *buf, size_t bufsiz)
87{
88 if (*pathname != '/') {
89 char path[PATH_MAX];
90 int len;
91
92 len = snprintf(path, sizeof(path), "%s/%s", dirname, pathname);
93 if (len < 0 || len + 1 > sizeof(path))
94 return -1;
95
96 return readlink(path, buf, bufsiz);
97 }
98 return readlink(pathname, buf, bufsiz);
99}
100#endif
101
102#ifdef TEST_PROGRAM_AT
103#include <errno.h>
104#include <sys/types.h>
105#include <dirent.h>
106#include <string.h>
107
108int main(int argc, char *argv[])
109{
110 DIR *dir;
111 struct dirent *d;
112 char *dirname;
113
114 if (argc != 2) {
115 fprintf(stderr, "usage: %s <directory>\n", argv[0]);
116 exit(EXIT_FAILURE);
117 }
118 dirname = argv[1];
119
120 dir = opendir(dirname);
121 if (!dir)
122 err(EXIT_FAILURE, "cannot open %s", dirname);
123
124 while ((d = readdir(dir))) {
125 struct stat st;
126 FILE *f;
127
128 printf("%32s ", d->d_name);
129
130 if (fstat_at(dirfd(dir), dirname, d->d_name, &st, 0) == 0)
131 printf("%16jd bytes ", st.st_size);
132 else
133 printf("%16s bytes ", "???");
134
135 f = fopen_at(dirfd(dir), dirname, d->d_name, O_RDONLY, "r");
136 printf(" %s\n", f ? "OK" : strerror(errno));
137 if (f)
138 fclose(f);
139 }
140 closedir(dir);
141 return EXIT_SUCCESS;
142}
143#endif