1 /*
2 *
3 * Copyright (c) International Business Machines Corp., 2001
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program 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
13 * the GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20 /*
21 * Test Name: ftruncate02
22 *
23 * Test Description:
24 * Verify that, ftruncate(2) succeeds to truncate a file to a certain length,
25 * but the attempt to read past the truncated length will fail.
26 *
27 * Expected Result:
28 * ftruncate(2) should return a value 0 and the attempt to read past the
29 * truncated length will fail. In case where the file before truncation was
30 * shorter, the bytes between the old and new should be all zeroes.
31 *
32 * Algorithm:
33 * Setup:
34 * Setup signal handling.
35 * Create temporary directory.
36 * Pause for SIGUSR1 if option specified.
37 *
38 * Test:
39 * Loop if the proper options are given.
40 * Execute system call
41 * Check return code, if system call failed (return=-1)
42 * Log the errno and Issue a FAIL message.
43 * Otherwise,
44 * Verify the Functionality of system call
45 * if successful,
46 * Issue Functionality-Pass message.
47 * Otherwise,
48 * Issue Functionality-Fail message.
49 * Cleanup:
50 * Print errno log and/or timing stats if options given
51 * Delete the temporary directory created.
52 *
53 * Usage: <for command-line>
54 * ftruncate02 [-c n] [-f] [-i n] [-I x] [-P x] [-t]
55 * where, -c n : Run n copies concurrently.
56 * -f : Turn off functionality Testing.
57 * -i n : Execute test n times.
58 * -I x : Execute test for x seconds.
59 * -P x : Pause for x seconds between iterations.
60 * -t : Turn on syscall timing.
61 *
62 * HISTORY
63 * 07/2001 Ported by Wayne Boyer
64 *
65 * RESTRICTIONS:
66 *
67 */
68
69 #include <stdio.h>
70 #include <sys/types.h>
71 #include <sys/stat.h>
72 #include <sys/fcntl.h>
73 #include <errno.h>
74 #include <string.h>
75 #include <signal.h>
76
77 #include "test.h"
78
79 #define TESTFILE "testfile" /* file under test */
80 #define FILE_MODE S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH
81 #define BUF_SIZE 256 /* buffer size */
82 #define FILE_SIZE 1024 /* test file size */
83 #define TRUNC_LEN1 256 /* truncation length */
84 #define TRUNC_LEN2 512 /* truncation length */
85
86 TCID_DEFINE(ftruncate02);
87 int TST_TOTAL = 1; /* Total number of test conditions */
88 int fd; /* file descriptor of testfile */
89 char tst_buff[BUF_SIZE]; /* buffer to hold testfile contents */
90
91 void setup(); /* setup function for the test */
92 void cleanup(); /* cleanup function for the test */
93
main(int ac,char ** av)94 int main(int ac, char **av)
95 {
96 struct stat stat_buf; /* stat(2) struct contents */
97 int lc;
98 off_t file_length2; /* test file length */
99 off_t file_length1; /* test file length */
100 int rbytes, i; /* bytes read from testfile */
101 int read_len = 0; /* total no. of bytes read from testfile */
102 int err_flag = 0; /* error indicator flag */
103
104 tst_parse_opts(ac, av, NULL, NULL);
105
106 setup();
107
108 for (lc = 0; TEST_LOOPING(lc); lc++) {
109
110 tst_count = 0;
111
112 /*
113 * Call ftruncate(2) to truncate a test file to a
114 * specified length (TRUNC_LEN1).
115 */
116 TEST(ftruncate(fd, TRUNC_LEN1));
117
118 if (TEST_RETURN == -1) {
119 tst_resm(TFAIL | TTERRNO,
120 "ftruncate(%s) to size %d failed", TESTFILE,
121 TRUNC_LEN1);
122 continue;
123 }
124 /*
125 * Get the testfile information using
126 * fstat(2).
127 */
128 if (fstat(fd, &stat_buf) < 0) {
129 tst_brkm(TFAIL, cleanup, "fstat(2) of %s failed"
130 " after 1st truncate, error:%d",
131 TESTFILE, errno);
132 }
133 stat_buf.st_mode &= ~S_IFREG;
134 file_length1 = stat_buf.st_size;
135
136 /*
137 * Set the file pointer of testfile to the
138 * beginning of the file.
139 */
140 if (lseek(fd, 0, SEEK_SET) < 0) {
141 tst_brkm(TFAIL, cleanup, "lseek(2) on %s failed"
142 " after 1st ftruncate, error:%d",
143 TESTFILE, errno);
144 }
145
146 /* Read the testfile from the beginning. */
147 while ((rbytes = read(fd, tst_buff,
148 sizeof(tst_buff))) > 0) {
149 read_len += rbytes;
150 }
151
152 /*
153 * Execute ftruncate(2) again to truncate
154 * testfile to a size TRUNC_LEN2.
155 */
156 TEST(ftruncate(fd, TRUNC_LEN2));
157
158 /*
159 * Get the testfile information using
160 * fstat(2)
161 */
162 if (fstat(fd, &stat_buf) < 0) {
163 tst_brkm(TFAIL, cleanup, "fstat(2) of %s failed"
164 " after 2nd truncate, error:%d",
165 TESTFILE, errno);
166 }
167 stat_buf.st_mode &= ~S_IFREG;
168 file_length2 = stat_buf.st_size;
169
170 /*
171 * Set the file pointer of testfile to the
172 * offset TRUNC_LEN1 of testfile.
173 */
174 if (lseek(fd, TRUNC_LEN1, SEEK_SET) < 0) {
175 tst_brkm(TFAIL, cleanup, "lseek(2) on %s failed"
176 " after 2nd ftruncate, error:%d",
177 TESTFILE, errno);
178 }
179
180 /* Read the testfile contents till EOF */
181 while ((rbytes = read(fd, tst_buff,
182 sizeof(tst_buff))) > 0) {
183 for (i = 0; i < rbytes; i++) {
184 if (tst_buff[i] != 0) {
185 err_flag++;
186 }
187 }
188 }
189
190 /*
191 * Check for expected size of testfile after
192 * issuing ftruncate(2) on it. If the ftruncate(2)
193 * to a smaller file passed, then check to see
194 * if file size was increased. If the ftruncate(2)
195 * to a smaller file failed, then don't check.
196 * Both results are allowed according to the SUS.
197 */
198
199 if (TEST_RETURN != -1) {
200 if ((file_length1 != TRUNC_LEN1) ||
201 (file_length2 != TRUNC_LEN2) ||
202 (read_len != TRUNC_LEN1) ||
203 (err_flag != 0)) {
204 tst_resm(TFAIL,
205 "Functionality of ftruncate(2) "
206 "on %s Failed", TESTFILE);
207 } else {
208 tst_resm(TPASS,
209 "Functionality of ftruncate(2) "
210 "on %s successful", TESTFILE);
211 }
212 }
213 if (TEST_RETURN == -1) {
214 if ((file_length1 != TRUNC_LEN1) ||
215 (read_len != TRUNC_LEN1) ||
216 (err_flag != 0)) {
217 tst_resm(TFAIL,
218 "Functionality of ftruncate(2) "
219 "on %s Failed", TESTFILE);
220 } else {
221 tst_resm(TPASS,
222 "Functionality of ftruncate(2) "
223 "on %s successful", TESTFILE);
224 }
225 }
226 }
227
228 cleanup();
229 tst_exit();
230 }
231
232 /*
233 * void
234 * setup() - performs all ONE TIME setup for this test.
235 * Create a temporary directory and change directory to it.
236 * Create a test file under temporary directory and write some
237 * data into it.
238 */
setup(void)239 void setup(void)
240 {
241 int i;
242 int wbytes; /* bytes written to testfile */
243 int write_len = 0; /* total no. of bytes written to testfile */
244
245 tst_sig(NOFORK, DEF_HANDLER, cleanup);
246
247 TEST_PAUSE;
248
249 tst_tmpdir();
250
251 /* Fill the test buffer with the known data */
252 for (i = 0; i < BUF_SIZE; i++) {
253 tst_buff[i] = 'a';
254 }
255 /* open a file for reading/writing */
256 fd = open(TESTFILE, O_RDWR | O_CREAT, FILE_MODE);
257 if (fd == -1)
258 tst_brkm(TBROK, cleanup,
259 "open(%s, O_RDWR|O_CREAT, %o) failed",
260 TESTFILE, FILE_MODE);
261
262 /* Write to the file 1k data from the buffer */
263 while (write_len < FILE_SIZE) {
264 if ((wbytes = write(fd, tst_buff, sizeof(tst_buff))) <= 0) {
265 tst_brkm(TBROK, cleanup, "write(%s) failed", TESTFILE);
266 } else {
267 write_len += wbytes;
268 }
269 }
270 }
271
272 /*
273 * void
274 * cleanup() - performs all ONE TIME cleanup for this test at
275 * completion or premature exit.
276 * Close the testfile.
277 * Remove the test directory and testfile created in the setup.
278 */
cleanup(void)279 void cleanup(void)
280 {
281
282 /* Close the testfile after writing data into it */
283 if (close(fd) == -1)
284 tst_brkm(TFAIL | TERRNO, NULL, "close(%s) failed", TESTFILE);
285
286 tst_rmdir();
287
288 }
289