fix XFSQA 145 / test_hole
[xfstests-dev.git] / dmapi / src / suite2 / src / test_hole.c
1 /*
2  * Copyright (c) 2000-2001 Silicon Graphics, Inc.
3  * All Rights Reserved.
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License as
7  * published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it would be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write the Free Software Foundation,
16  * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17  */
18
19 #include <sys/types.h>
20 #include <sys/stat.h>
21
22 #include <lib/hsm.h>
23 #include <lib/errtest.h>
24
25 #include <getopt.h>
26 #include <string.h>
27
28
29 /*---------------------------------------------------------------------------
30
31 Test program used to test the DMAPI function dm_punch_hole().  The
32 command line is:
33
34         test_hole [-v] [-s sid] pathname
35
36 where 
37    ls_path
38       is the path to a specific copy of ls, important only for its size
39    pathname 
40       is the path to the test filesystem
41    sid
42       is the session ID whose events you you are interested in.
43
44 ----------------------------------------------------------------------------*/
45
46 #ifndef linux
47 extern  char    *sys_errlist[];
48 #endif
49 extern  int     optind;
50 extern  char    *optarg;
51
52 char    *Progname;
53
54
55 static void
56 usage(void)
57 {
58         fprintf(stderr, "usage:\t%s [-v] [-s sid] ls_path directoryname\n",
59                 Progname);
60         exit(1);
61 }
62
63
64 int
65 main(
66         int     argc, 
67         char    **argv)
68 {
69         dm_sessid_t     sid = DM_NO_SESSION;
70         char            *pathname = NULL;
71         char            *ls_path = NULL;
72         dm_off_t        offset = 0, end;
73         dm_off_t        ex_off = 0;
74         dm_extent_t     extent[20];
75         u_int           nelem;
76         dm_size_t       length = 0;
77         void            *hanp;
78         size_t          hlen;
79         dm_token_t      test_token;
80         char            *name;
81         int             opt;
82         int             Vflag = 0;
83         char            filename[128];
84         char            command[128];
85         dm_off_t        roff;
86         dm_size_t       rlen;
87         dm_off_t        blocksize = 5; 
88         void            *test_vp;
89         struct stat    buf;
90         struct stat    checkbuf;
91
92
93         if (Progname = strrchr(argv[0], '/')) {
94                 Progname++;
95         } else {
96                 Progname = argv[0];
97         }
98
99         /* Crack and validate the command line options. */
100
101         while ((opt = getopt(argc, argv, "vs:")) != EOF) {
102                 switch (opt) {
103                 case 'v':
104                         Vflag++;
105                         break;
106                 case 's':
107                         sid = atol(optarg);
108                         break;
109                 case '?':
110                         usage();
111                 }
112         }
113         if (optind + 2 != argc)
114                 usage();
115         ls_path = argv[optind];
116         pathname = argv[optind+1];
117
118         if (dm_init_service(&name) == -1)  {
119                 fprintf(stdout, "Can't initialize the DMAPI\n");
120                 exit(1);
121         }
122         if (sid == DM_NO_SESSION)
123                 find_test_session(&sid);
124
125         /* Get the directory handle. */
126
127         if (dm_path_to_handle(pathname, &hanp, &hlen)) {
128                 fprintf(stdout, 
129                      "ERROR: can't get handle for directory %s\n", pathname);
130                 exit(1);
131         }
132         
133         printf("Hole test beginning...\n");
134         sprintf(filename, "%s/VeryLongUnlikelyFilename.HOLETEST", pathname);
135         sprintf(command, "cp %s %s \n", ls_path, filename); 
136         system(command);
137
138         if (dm_path_to_handle(filename, &hanp, &hlen)) {
139           fprintf(stdout, "can't get handle for %s\n; aborting test",
140                   filename);
141           
142           sprintf(command, "rm %s \n", filename); 
143           system(command);
144           fprintf(stdout, "\tHole test aborted.\n");
145           
146           dm_handle_free(hanp, hlen);
147           exit(1);
148         }
149    
150         /*   ## Get the block size using a length-1 probe. ##   */
151         dm_probe_hole(sid, hanp, hlen, DM_NO_TOKEN, 1, 0,
152                       &blocksize, &rlen);
153         
154         if (blocksize==0) {
155           fprintf(stdout, "Error: block size appears to be 0!\n");
156           
157           sprintf(command, "rm %s \n", filename); 
158           system(command);
159           fprintf(stdout, "\tHole test aborted.\n");
160           
161           dm_handle_free(hanp, hlen);
162           exit(1);
163         }
164
165         /*
166          * The kernel always rounds the offset up to the next block
167          * size, so we can only probes up to the previous to last block.
168          */
169         end = (29604 / blocksize) * blocksize;
170
171         /* Check that dm_probe_hole returns an extent from the next
172          * highest multiple of the block size, to the end of the file
173          */
174         for (offset = 0; offset < end; offset++) { 
175           if (dm_probe_hole(sid, hanp, hlen, DM_NO_TOKEN, offset, length,
176                             &roff, &rlen)) {
177             fprintf(stdout, "dm_probe_hole failed on pass %lld (%s)\n",
178                     (long long)offset, ERR_NAME);
179           }
180           else {
181             if (rlen != 0) {
182                 fprintf(stdout, 
183                         "Error: hole did not extend to end of file!\n");
184             }
185             if (blocksize*(roff/blocksize) != roff) {
186                 fprintf(stdout,
187                         "Error: offset not a multiple of block size!\n");
188             }
189           }
190         }
191         
192         /* Be sure dm_punch_hole doesn't change the time stamp, 
193          * and verify that dm_get_allocinfo shows a hole
194          * followed by an extent to the end of the file.
195          */
196         for(offset = 28672; offset > 0; offset-=blocksize) {
197           if (stat(filename, &buf)){
198             fprintf(stdout, 
199                     "Error: unable to stat the test file; %s (1st)\n", 
200                     filename);
201             continue;
202           }
203           if (dm_probe_hole(sid, hanp, hlen, DM_NO_TOKEN, offset, length,
204                             &roff, &rlen)) {
205             fprintf(stdout, "dm_probe_hole failed, %s\n",
206                     ERR_NAME);
207             continue;
208           }
209           if (roff != offset) {
210             fprintf(stdout, 
211                     "Error: presumed offset was not %lld.\n",
212                     (long long)(roff));
213           }
214           if (dm_punch_hole(sid, hanp, hlen, DM_NO_TOKEN,
215                             roff, length)) {
216             fprintf(stdout, "dm_punch_hole failed, %s\n",
217                     ERR_NAME);
218             continue;
219           }
220           if (stat(filename, &checkbuf)){
221             fprintf(stdout, 
222                     "Error: unable to stat the test file. (2nd)\n");
223             continue;
224           }
225           else {
226             /* COMPARE BUF AND CHECKBUF! */
227 #ifdef linux
228             if ((buf.st_atime == checkbuf.st_atime) &&
229                 (buf.st_mtime == checkbuf.st_mtime) &&
230                 (buf.st_ctime == checkbuf.st_ctime))
231 #else
232             if ((buf.st_atim.tv_sec == checkbuf.st_atim.tv_sec) &&
233                 (buf.st_atim.tv_nsec == checkbuf.st_atim.tv_nsec) &&
234                 (buf.st_mtim.tv_sec == checkbuf.st_mtim.tv_sec) &&
235                 (buf.st_mtim.tv_nsec == checkbuf.st_mtim.tv_nsec) &&
236                 (buf.st_ctim.tv_sec == checkbuf.st_ctim.tv_sec) &&
237                 (buf.st_ctim.tv_nsec == checkbuf.st_ctim.tv_nsec))
238 #endif
239            {
240               if (Vflag) {
241                 fprintf(stdout, 
242                         "\tTime stamp unchanged by hole from offset %lld.\n",
243                         (long long)(offset));
244               }
245             }
246             else {
247               fprintf(stdout,
248                       "Error: punch_hole changed file's time stamp.\n");
249             }
250             ex_off=0;
251             if ((dm_get_allocinfo(sid, hanp, hlen, DM_NO_TOKEN, 
252                                   &ex_off, 1, extent, &nelem) == 1) &&
253                 (extent->ex_type == DM_EXTENT_RES) &&
254                 (dm_get_allocinfo(sid, hanp, hlen, DM_NO_TOKEN,
255                                   &ex_off, 1, extent, &nelem) == 0) &&
256                 (extent->ex_type == DM_EXTENT_HOLE)) {
257               if (extent->ex_offset == roff){
258                 if (Vflag) {
259                   fprintf(stdout, "\tVerified hole at %lld\n", 
260                           (long long)(extent->ex_offset));
261                 }
262               }
263               else {
264                 fprintf(stdout, "\tError: get_allocinfo found hole at %lld\n",
265                         (long long)(extent->ex_offset));
266               }
267             }
268             else {
269                 fprintf(stdout, "\tError: get_allocinfo did not find an "
270                         "extent followed by a hole!\n");
271             }
272           }
273         }
274         /*------------------------*\
275         |*  ## Errno subtests ##  *|
276         \*------------------------*/
277         fprintf(stdout, "\t(beginning errno subtests...)\n");
278         /*---------------------------------------------------------*/
279         ERRTEST(E2BIG,
280                 "probe (from past EOF)",
281                 dm_probe_hole(sid, hanp, hlen, DM_NO_TOKEN, 30000, length,
282                               &roff, &rlen))
283         /*---------------------------------------------------------*/
284         ERRTEST(E2BIG,
285                 "probe (to past EOF)",
286                 dm_probe_hole(sid, hanp, hlen, DM_NO_TOKEN, 15000, 150000,
287                               &roff, &rlen))
288         /*---------------------------------------------------------*/
289         SHAREDTEST("probe", hanp, hlen, test_token, 
290                  dm_probe_hole(sid, hanp, hlen, test_token, 
291                                0, 0, &roff, &rlen)) 
292         /*---------------------------------------------------------*/
293         EXCLTEST("punch", hanp, hlen, test_token, 
294                    dm_punch_hole(sid, hanp, hlen, test_token, 0, 0)) 
295         /*---------------------------------------------------------*/
296         /*
297          * No idea where that EAGAIN should come from, it's never
298          * returned from the kernel.
299          *
300          *              -- hch
301          */
302 #if 0
303         ERRTEST(EAGAIN,
304                 "punch",
305                 dm_punch_hole(sid, hanp, hlen, DM_NO_TOKEN,
306                               1, length))       
307 #endif
308         /*---------------------------------------------------------*/
309         if ((test_vp = handle_clone(hanp, hlen)) == NULL) {
310           fprintf(stderr, 
311                   "Cannot create a test handle (%s); skipping EBADF test\n",
312                   ERR_NAME);
313         }
314         else {
315          ((char *) test_vp)[hlen/2]++;
316           ERRTEST(EBADF,
317                   "probe",
318                   dm_probe_hole(sid, test_vp, hlen, DM_NO_TOKEN,
319                                 offset, length,
320                                 &roff, &rlen))
321           ERRTEST(EBADF,
322                   "punch",
323                   dm_punch_hole(sid, test_vp, hlen, DM_NO_TOKEN,
324                                 offset, length))
325         }
326         dm_handle_free(test_vp, hlen);
327         /*---------------------------------------------------------*/
328         ERRTEST(EFAULT,
329                 "probe (null handle)",
330                 dm_probe_hole(sid, 0, hlen, DM_NO_TOKEN, offset, length,
331                                 &roff, &rlen))
332         ERRTEST(EFAULT,
333                 "probe (bad rlen)",
334                 dm_probe_hole(sid, 0, hlen, DM_NO_TOKEN, offset, length,
335                                 &roff, (dm_size_t*)(-1000)))
336         ERRTEST(EFAULT,
337                 "probe (bad roff)",
338                 dm_probe_hole(sid, hanp, hlen, DM_NO_TOKEN, offset, length,
339                                 (dm_off_t*)(-1000), &rlen))
340         /*---------------------------------------------------------*/
341         ERRTEST(EFAULT,
342                 "punch",
343                 dm_punch_hole(sid, 0, hlen, DM_NO_TOKEN, offset, length))
344         /*---------------------------------------------------------*/
345         ERRTEST(EINVAL,
346                 "probe (bad session)",
347                 dm_probe_hole(-100, hanp, hlen, DM_NO_TOKEN, offset, length,
348                                 &roff, &rlen))
349         /*---------------------------------------------------------*/
350         ERRTEST(EINVAL, 
351                 "probe (bad token)",
352                 dm_probe_hole(sid, hanp, hlen, 0, offset, length,
353                                 &roff, &rlen))
354         /*---------------------------------------------------------*/
355         ERRTEST(EINVAL, 
356                 "probe (bad token 2)",
357                 dm_probe_hole(sid, hanp, hlen, 0, offset, length,
358                                 &roff, &rlen))
359         /*---------------------------------------------------------*/
360         fprintf(stdout, "\t(errno subtests complete)\n");
361                 
362
363         sprintf(command, "rm %s \n", filename); 
364         system(command);
365         printf("Hole test complete.\n");
366
367         dm_handle_free(hanp, hlen);
368         exit(0);
369 }
370