1 | /* Test for fchmodat function. */ |
2 | |
3 | #include <dirent.h> |
4 | #include <fcntl.h> |
5 | #include <stdio.h> |
6 | #include <stdlib.h> |
7 | #include <string.h> |
8 | #include <unistd.h> |
9 | #include <sys/stat.h> |
10 | |
11 | #include <support/xunistd.h> |
12 | |
13 | static void prepare (void); |
14 | #define PREPARE(argc, argv) prepare () |
15 | |
16 | static int do_test (void); |
17 | #define TEST_FUNCTION do_test () |
18 | |
19 | #include "../test-skeleton.c" |
20 | |
21 | static int dir_fd; |
22 | |
23 | static void |
24 | prepare (void) |
25 | { |
26 | size_t test_dir_len = strlen (test_dir); |
27 | static const char dir_name[] = "/tst-fchmodat.XXXXXX" ; |
28 | |
29 | size_t dirbuflen = test_dir_len + sizeof (dir_name); |
30 | char *dirbuf = malloc (size: dirbuflen); |
31 | if (dirbuf == NULL) |
32 | { |
33 | puts (s: "out of memory" ); |
34 | exit (1); |
35 | } |
36 | |
37 | snprintf (s: dirbuf, maxlen: dirbuflen, format: "%s%s" , test_dir, dir_name); |
38 | if (mkdtemp (template: dirbuf) == NULL) |
39 | { |
40 | puts (s: "cannot create temporary directory" ); |
41 | exit (1); |
42 | } |
43 | |
44 | add_temp_file (name: dirbuf); |
45 | |
46 | dir_fd = open (file: dirbuf, O_RDONLY | O_DIRECTORY); |
47 | if (dir_fd == -1) |
48 | { |
49 | puts (s: "cannot open directory" ); |
50 | exit (1); |
51 | } |
52 | } |
53 | |
54 | |
55 | static int |
56 | do_test (void) |
57 | { |
58 | /* fdopendir takes over the descriptor, make a copy. */ |
59 | int dupfd = dup (fd: dir_fd); |
60 | if (dupfd == -1) |
61 | { |
62 | puts (s: "dup failed" ); |
63 | return 1; |
64 | } |
65 | if (lseek (fd: dupfd, offset: 0, SEEK_SET) != 0) |
66 | { |
67 | puts (s: "1st lseek failed" ); |
68 | return 1; |
69 | } |
70 | |
71 | /* The directory should be empty save the . and .. files. */ |
72 | DIR *dir = fdopendir (fd: dupfd); |
73 | if (dir == NULL) |
74 | { |
75 | puts (s: "fdopendir failed" ); |
76 | return 1; |
77 | } |
78 | struct dirent64 *d; |
79 | while ((d = readdir64 (dirp: dir)) != NULL) |
80 | if (strcmp (d->d_name, "." ) != 0 && strcmp (d->d_name, ".." ) != 0) |
81 | { |
82 | printf (format: "temp directory contains file \"%s\"\n" , d->d_name); |
83 | return 1; |
84 | } |
85 | closedir (dirp: dir); |
86 | |
87 | umask (mask: 022); |
88 | |
89 | /* Try to create a file. */ |
90 | int fd = openat (fd: dir_fd, file: "some-file" , O_CREAT|O_RDWR|O_EXCL, 0666); |
91 | if (fd == -1) |
92 | { |
93 | if (errno == ENOSYS) |
94 | { |
95 | puts (s: "*at functions not supported" ); |
96 | return 0; |
97 | } |
98 | |
99 | puts (s: "file creation failed" ); |
100 | return 1; |
101 | } |
102 | xwrite (fd, "hello" , 5); |
103 | puts (s: "file created" ); |
104 | |
105 | struct stat64 st1; |
106 | if (fstat64 (fd: fd, buf: &st1) != 0) |
107 | { |
108 | puts (s: "fstat64 failed" ); |
109 | return 1; |
110 | } |
111 | |
112 | /* Before closing the file, try using this file descriptor to open |
113 | another file. This must fail. */ |
114 | if (fchmodat (fd, "some-file" , 0400, 0) != -1) |
115 | { |
116 | puts (s: "fchmodat using descriptor for normal file worked" ); |
117 | return 1; |
118 | } |
119 | if (errno != ENOTDIR) |
120 | { |
121 | puts (s: "\ |
122 | error for fchmodat using descriptor for normal file not ENOTDIR " ); |
123 | return 1; |
124 | } |
125 | |
126 | close (fd: fd); |
127 | |
128 | if ((st1.st_mode & 0777) != 0644) |
129 | { |
130 | printf (format: "openat created mode %04o, not 0644\n" , (st1.st_mode & 0777)); |
131 | return 1; |
132 | } |
133 | |
134 | if (fchmodat (dir_fd, "some-file" , 0400, 0) != 0) |
135 | { |
136 | puts (s: "fchownat failed" ); |
137 | return 1; |
138 | } |
139 | |
140 | struct stat64 st2; |
141 | if (fstatat64 (fd: dir_fd, file: "some-file" , buf: &st2, flag: 0) != 0) |
142 | { |
143 | puts (s: "fstatat64 failed" ); |
144 | return 1; |
145 | } |
146 | |
147 | if ((st2.st_mode & 0777) != 0400) |
148 | { |
149 | puts (s: "mode change failed" ); |
150 | return 1; |
151 | } |
152 | |
153 | if (unlinkat (fd: dir_fd, name: "some-file" , flag: 0) != 0) |
154 | { |
155 | puts (s: "unlinkat failed" ); |
156 | return 1; |
157 | } |
158 | |
159 | /* Create a file descriptor which is closed again right away. */ |
160 | int dir_fd2 = dup (fd: dir_fd); |
161 | if (dir_fd2 == -1) |
162 | { |
163 | puts (s: "dup failed" ); |
164 | return 1; |
165 | } |
166 | close (fd: dir_fd2); |
167 | |
168 | if (fchmodat (dir_fd2, "some-file" , 0400, 0) != -1) |
169 | { |
170 | puts (s: "fchmodat using closed descriptor worked" ); |
171 | return 1; |
172 | } |
173 | if (errno != EBADF) |
174 | { |
175 | puts (s: "error for fchmodat using closed descriptor not EBADF " ); |
176 | return 1; |
177 | } |
178 | |
179 | close (fd: dir_fd); |
180 | |
181 | if (fchmodat (-1, "some-file" , 0400, 0) != -1) |
182 | { |
183 | puts (s: "fchmodat using invalid descriptor worked" ); |
184 | return 1; |
185 | } |
186 | if (errno != EBADF) |
187 | { |
188 | puts (s: "error for fchmodat using invalid descriptor not EBADF " ); |
189 | return 1; |
190 | } |
191 | |
192 | return 0; |
193 | } |
194 | |