1 | /* Some basic tests for LFS. |
2 | Copyright (C) 2000-2022 Free Software Foundation, Inc. |
3 | This file is part of the GNU C Library. |
4 | |
5 | The GNU C Library is free software; you can redistribute it and/or |
6 | modify it under the terms of the GNU Lesser General Public |
7 | License as published by the Free Software Foundation; either |
8 | version 2.1 of the License, or (at your option) any later version. |
9 | |
10 | The GNU C Library is distributed in the hope that it will be useful, |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
13 | Lesser General Public License for more details. |
14 | |
15 | You should have received a copy of the GNU Lesser General Public |
16 | License along with the GNU C Library; if not, see |
17 | <https://www.gnu.org/licenses/>. */ |
18 | |
19 | #include <unistd.h> |
20 | #include <stdlib.h> |
21 | #include <sys/types.h> |
22 | #include <sys/stat.h> |
23 | #include <fcntl.h> |
24 | #include <error.h> |
25 | #include <errno.h> |
26 | #include <sys/resource.h> |
27 | #include <support/check.h> |
28 | |
29 | /* Prototype for our test function. */ |
30 | extern void do_prepare (int argc, char *argv[]); |
31 | extern int do_test (int argc, char *argv[]); |
32 | |
33 | /* We have a preparation function. */ |
34 | #define PREPARE do_prepare |
35 | |
36 | /* This defines the `main' function and some more. */ |
37 | #include <test-skeleton.c> |
38 | |
39 | /* These are for the temporary file we generate. */ |
40 | char *name; |
41 | int fd; |
42 | |
43 | /* 2^31 = 2GB. */ |
44 | #define TWO_GB 2147483648LL |
45 | |
46 | void |
47 | do_prepare (int argc, char *argv[]) |
48 | { |
49 | size_t name_len; |
50 | struct rlimit64 rlim; |
51 | |
52 | name_len = strlen (test_dir); |
53 | name = xmalloc (n: name_len + sizeof ("/lfsXXXXXX" )); |
54 | mempcpy (mempcpy (name, test_dir, name_len), |
55 | "/lfsXXXXXX" , sizeof ("/lfsXXXXXX" )); |
56 | |
57 | /* Open our test file. */ |
58 | fd = mkstemp64 (template: name); |
59 | if (fd == -1) |
60 | { |
61 | if (errno == ENOSYS) |
62 | { |
63 | /* Fail silently. */ |
64 | error (status: 0, errnum: 0, format: "open64 is not supported" ); |
65 | exit (EXIT_SUCCESS); |
66 | } |
67 | else |
68 | error (EXIT_FAILURE, errno, format: "cannot create temporary file" ); |
69 | } |
70 | if (!support_descriptor_supports_holes (fd)) |
71 | FAIL_UNSUPPORTED ("File %s does not support holes" , name); |
72 | add_temp_file (name); |
73 | |
74 | if (getrlimit64 (RLIMIT_FSIZE, &rlim) != 0) |
75 | { |
76 | error (status: 0, errno, format: "cannot get resource limit" ); |
77 | exit (0); |
78 | } |
79 | if (rlim.rlim_cur < TWO_GB + 200) |
80 | { |
81 | rlim.rlim_cur = TWO_GB + 200; |
82 | if (setrlimit64 (RLIMIT_FSIZE, rlimits: &rlim) != 0) |
83 | { |
84 | error (status: 0, errno, format: "cannot reset file size limits" ); |
85 | exit (0); |
86 | } |
87 | } |
88 | } |
89 | |
90 | static void |
91 | test_ftello (void) |
92 | { |
93 | FILE *f; |
94 | int ret; |
95 | off64_t pos; |
96 | |
97 | f = fopen64 (filename: name, modes: "w" ); |
98 | |
99 | ret = fseeko64 (stream: f, TWO_GB+100, SEEK_SET); |
100 | if (ret == -1 && errno == ENOSYS) |
101 | { |
102 | error (status: 0, errnum: 0, format: "fseeko64 is not supported." ); |
103 | exit (EXIT_SUCCESS); |
104 | } |
105 | if (ret == -1 && errno == EINVAL) |
106 | { |
107 | error (status: 0, errnum: 0, format: "LFS seems not to be supported" ); |
108 | exit (EXIT_SUCCESS); |
109 | } |
110 | if (ret == -1) |
111 | { |
112 | error (status: 0, errno, format: "fseeko64 failed with error" ); |
113 | exit (EXIT_FAILURE); |
114 | } |
115 | |
116 | ret = fwrite ("Hello" , 1, 5, f); |
117 | if (ret == -1 && errno == EFBIG) |
118 | { |
119 | error (status: 0, errno, format: "LFS seems not to be supported" ); |
120 | exit (EXIT_SUCCESS); |
121 | } |
122 | |
123 | if (ret == -1 && errno == ENOSPC) |
124 | { |
125 | error (status: 0, errnum: 0, format: "Not enough space to write file." ); |
126 | exit (EXIT_SUCCESS); |
127 | } |
128 | |
129 | if (ret != 5) |
130 | error (EXIT_FAILURE, errno, format: "Cannot write test string to large file" ); |
131 | |
132 | pos = ftello64 (stream: f); |
133 | |
134 | if (pos != TWO_GB+105) |
135 | { |
136 | error (status: 0, errnum: 0, format: "ftello64 gives wrong result." ); |
137 | exit (EXIT_FAILURE); |
138 | } |
139 | |
140 | fclose (f); |
141 | } |
142 | |
143 | int |
144 | do_test (int argc, char *argv[]) |
145 | { |
146 | int ret, fd2; |
147 | struct stat64 statbuf; |
148 | |
149 | ret = lseek64 (fd: fd, TWO_GB+100, SEEK_SET); |
150 | if (ret == -1 && errno == ENOSYS) |
151 | { |
152 | error (status: 0, errnum: 0, format: "lseek64 is not supported." ); |
153 | exit (EXIT_SUCCESS); |
154 | } |
155 | if (ret == -1 && errno == EINVAL) |
156 | { |
157 | error (status: 0, errnum: 0, format: "LFS seems not to be supported." ); |
158 | exit (EXIT_SUCCESS); |
159 | } |
160 | if (ret == -1) |
161 | { |
162 | error (status: 0, errno, format: "lseek64 failed with error" ); |
163 | exit (EXIT_FAILURE); |
164 | } |
165 | off64_t offset64 = lseek64 (fd: fd, offset: 0, SEEK_CUR); |
166 | if (offset64 != TWO_GB + 100) |
167 | { |
168 | error (status: 0, errnum: 0, format: "lseek64 did not return expected offset" ); |
169 | exit (EXIT_FAILURE); |
170 | } |
171 | off_t offset = lseek (fd: fd, offset: 0, SEEK_CUR); |
172 | if (sizeof (off_t) < sizeof (off64_t)) |
173 | { |
174 | if (offset != -1 || errno != EOVERFLOW) |
175 | { |
176 | error (status: 0, errnum: 0, format: "lseek did not fail with EOVERFLOW" ); |
177 | exit (EXIT_FAILURE); |
178 | } |
179 | } |
180 | else |
181 | if (offset != TWO_GB + 100) |
182 | { |
183 | error (status: 0, errnum: 0, format: "lseek did not return expected offset" ); |
184 | exit (EXIT_FAILURE); |
185 | } |
186 | |
187 | ret = write (fd, "Hello" , 5); |
188 | if (ret == -1 && errno == EFBIG) |
189 | { |
190 | error (status: 0, errnum: 0, format: "LFS seems not to be supported." ); |
191 | exit (EXIT_SUCCESS); |
192 | } |
193 | |
194 | if (ret == -1 && errno == ENOSPC) |
195 | { |
196 | error (status: 0, errnum: 0, format: "Not enough space to write file." ); |
197 | exit (EXIT_SUCCESS); |
198 | } |
199 | |
200 | if (ret != 5) |
201 | error (EXIT_FAILURE, errno, format: "cannot write test string to large file" ); |
202 | |
203 | ret = close (fd: fd); |
204 | |
205 | if (ret == -1) |
206 | error (EXIT_FAILURE, errno, format: "error closing file" ); |
207 | |
208 | ret = stat64 (file: name, buf: &statbuf); |
209 | |
210 | if (ret == -1 && (errno == ENOSYS || errno == EOVERFLOW)) |
211 | error (status: 0, errnum: 0, format: "stat64 is not supported." ); |
212 | else if (ret == -1) |
213 | error (EXIT_FAILURE, errno, format: "cannot stat file `%s'" , name); |
214 | else if (statbuf.st_size != (TWO_GB + 100 + 5)) |
215 | error (EXIT_FAILURE, errnum: 0, format: "stat reported size %lld instead of %lld." , |
216 | (long long int) statbuf.st_size, (TWO_GB + 100 + 5)); |
217 | |
218 | fd2 = openat64 (AT_FDCWD, file: name, O_RDWR); |
219 | if (fd2 == -1) |
220 | { |
221 | if (errno == ENOSYS) |
222 | { |
223 | /* Silently ignore this test. */ |
224 | error (status: 0, errnum: 0, format: "openat64 is not supported" ); |
225 | } |
226 | else |
227 | error (EXIT_FAILURE, errno, format: "openat64 failed to open big file" ); |
228 | } |
229 | else |
230 | { |
231 | ret = close (fd: fd2); |
232 | |
233 | if (ret == -1) |
234 | error (EXIT_FAILURE, errno, format: "error closing file" ); |
235 | } |
236 | |
237 | test_ftello (); |
238 | |
239 | return 0; |
240 | } |
241 | |