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