0e938665c51a6c14edaac42e106baf4d3cc4d90d
[xfstests-dev.git] / dmapi / src / suite2 / src / test_hole.c
1 /*
2  * Copyright (c) 2000 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 #ifdef linux
40 #include <string.h>
41 #endif
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         int     i;
73
74         fprintf(stderr, "usage:\t%s [-v] [-s sid] ls_path directoryname\n",
75                 Progname);
76         exit(1);
77 }
78
79
80 int
81 main(
82         int     argc, 
83         char    **argv)
84 {
85         dm_sessid_t     sid = DM_NO_SESSION;
86         char            *pathname = NULL;
87         char            *ls_path = NULL;
88         dm_off_t        offset = 0;
89         dm_off_t        ex_off = 0;
90         dm_extent_t     extent[20];
91         u_int           nelem;
92         dm_size_t       length = 0;
93         void            *hanp;
94         size_t          hlen;
95         dm_token_t      test_token;
96         char            *name;
97         int             opt;
98         int             i;
99         int             Vflag = 0;
100         char            filename[128];
101         char            command[128];
102         dm_off_t        roff;
103         dm_size_t       rlen;
104         dm_off_t        blocksize = 5; 
105         void            *test_vp;
106         struct stat    buf;
107         struct stat    checkbuf;
108
109
110         if (Progname = strrchr(argv[0], '/')) {
111                 Progname++;
112         } else {
113                 Progname = argv[0];
114         }
115
116         /* Crack and validate the command line options. */
117
118         while ((opt = getopt(argc, argv, "vs:")) != EOF) {
119                 switch (opt) {
120                 case 'v':
121                         Vflag++;
122                         break;
123                 case 's':
124                         sid = atol(optarg);
125                         break;
126                 case '?':
127                         usage();
128                 }
129         }
130         if (optind + 2 != argc)
131                 usage();
132         ls_path = argv[optind];
133         pathname = argv[optind+1];
134
135         if (dm_init_service(&name) == -1)  {
136                 fprintf(stdout, "Can't inititalize the DMAPI\n");
137                 exit(1);
138         }
139         if (sid == DM_NO_SESSION)
140                 find_test_session(&sid);
141
142         /* Get the directory handle. */
143
144         if (dm_path_to_handle(pathname, &hanp, &hlen)) {
145                 fprintf(stdout, 
146                      "ERROR: can't get handle for directory %s\n", pathname);
147                 exit(1);
148         }
149         
150         printf("Hole test beginning...\n");
151         sprintf(filename, "%s/VeryLongUnlikelyFilename.HOLETEST", pathname);
152         sprintf(command, "cp %s %s \n", ls_path, filename); 
153         system(command);
154
155         if (dm_path_to_handle(filename, &hanp, &hlen)) {
156           fprintf(stdout, "can't get handle for %s\n; aborting test",
157                   filename);
158           
159           sprintf(command, "rm %s \n", filename); 
160           system(command);
161           fprintf(stdout, "\tHole test aborted.\n");
162           
163           dm_handle_free(hanp, hlen);
164           exit(1);
165         }
166    
167         /*   ## Get the block size using a length-1 probe. ##   */
168         dm_probe_hole(sid, hanp, hlen, DM_NO_TOKEN, 1, 0,
169                       &blocksize, &rlen);
170         
171         if (blocksize==0) {
172           fprintf(stdout, "Error: block size appears to be 0!\n");
173           
174           sprintf(command, "rm %s \n", filename); 
175           system(command);
176           fprintf(stdout, "\tHole test aborted.\n");
177           
178           dm_handle_free(hanp, hlen);
179           exit(1);
180         }
181
182         /* Check that dm_probe_hole returns an extent from the next
183          * highest multiple of the block size, to the end of the file
184          */
185         i = 0;
186         for (offset = 0; offset < 29604; offset++) { 
187           if (dm_probe_hole(sid, hanp, hlen, DM_NO_TOKEN, offset, length,
188                             &roff, &rlen)) {
189             fprintf(stdout, "dm_probe_hole failed on pass %lld (%s)\n",
190                     (long long)offset, ERR_NAME);
191           }
192           else {
193             if (rlen != 0) {
194                 fprintf(stdout, 
195                         "Error: hole did not extend to end of file!\n");
196             }
197             if (blocksize*(roff/blocksize) != roff) {
198                 fprintf(stdout,
199                         "Error: offset not a multiple of block size!\n");
200             }
201           }
202         }
203         
204         /* Be sure dm_punch_hole doesn't change the time stamp, 
205          * and verify that dm_get_allocinfo shows a hole
206          * followed by an extent to the end of the file.
207          */
208         for(offset = 28672; offset > 0; offset-=blocksize) {
209           if (stat(filename, &buf)){
210             fprintf(stdout, 
211                     "Error: unable to stat the test file; %s (1st)\n", 
212                     filename);
213             continue;
214           }
215           if (dm_probe_hole(sid, hanp, hlen, DM_NO_TOKEN, offset, length,
216                             &roff, &rlen)) {
217             fprintf(stdout, "dm_probe_hole failed, %s\n",
218                     ERR_NAME);
219             continue;
220           }
221           if (roff != offset) {
222             fprintf(stdout, 
223                     "Error: presumed offset was not %lld.\n",
224                     (long long)(roff));
225           }
226           if (dm_punch_hole(sid, hanp, hlen, DM_NO_TOKEN,
227                             roff, length)) {
228             fprintf(stdout, "dm_punch_hole failed, %s\n",
229                     ERR_NAME);
230             continue;
231           }
232           if (stat(filename, &checkbuf)){
233             fprintf(stdout, 
234                     "Error: unable to stat the test file. (2nd)\n");
235             continue;
236           }
237           else {
238             /* COMPARE BUF AND CHECKBUF! */
239 #ifdef linux
240             if ((buf.st_atime == checkbuf.st_atime) &&
241                 (buf.st_mtime == checkbuf.st_mtime) &&
242                 (buf.st_ctime == checkbuf.st_ctime))
243 #else
244             if ((buf.st_atim.tv_sec == checkbuf.st_atim.tv_sec) &&
245                 (buf.st_atim.tv_nsec == checkbuf.st_atim.tv_nsec) &&
246                 (buf.st_mtim.tv_sec == checkbuf.st_mtim.tv_sec) &&
247                 (buf.st_mtim.tv_nsec == checkbuf.st_mtim.tv_nsec) &&
248                 (buf.st_ctim.tv_sec == checkbuf.st_ctim.tv_sec) &&
249                 (buf.st_ctim.tv_nsec == checkbuf.st_ctim.tv_nsec))
250 #endif
251            {
252               if (Vflag) {
253                 fprintf(stdout, 
254                         "\tTime stamp unchanged by hole from offset %lld.\n",
255                         (long long)(offset));
256               }
257             }
258             else {
259               fprintf(stdout,
260                       "Error: punch_hole changed file's time stamp.\n");
261             }
262             ex_off=0;
263             if ((dm_get_allocinfo(sid, hanp, hlen, DM_NO_TOKEN, 
264                                   &ex_off, 1, extent, &nelem) == 1) &&
265                 (extent->ex_type == DM_EXTENT_RES) &&
266                 (dm_get_allocinfo(sid, hanp, hlen, DM_NO_TOKEN,
267                                   &ex_off, 1, extent, &nelem) == 0) &&
268                 (extent->ex_type == DM_EXTENT_HOLE)) {
269               if (extent->ex_offset == roff){
270                 if (Vflag) {
271                   fprintf(stdout, "\tVerified hole at %lld\n", 
272                           (long long)(extent->ex_offset));
273                 }
274               }
275               else {
276                 fprintf(stdout, "\tError: get_allocinfo found hole at %lld\n",
277                         (long long)(extent->ex_offset));
278               }
279             }
280             else {
281                 fprintf(stdout, "\tError: get_allocinfo did not find an "
282                         "extent followed by a hole!\n");
283             }
284           }
285         }
286         /*------------------------*\
287         |*  ## Errno subtests ##  *|
288         \*------------------------*/
289         fprintf(stdout, "\t(beginning errno subtests...)\n");
290         /*---------------------------------------------------------*/
291         ERRTEST(E2BIG,
292                 "probe (from past EOF)",
293                 dm_probe_hole(sid, hanp, hlen, DM_NO_TOKEN, 30000, length,
294                               &roff, &rlen))
295         /*---------------------------------------------------------*/
296 #if 0
297         PROBLEM: No error is produced.  
298         off+len >= filesize should produce E2BIG...
299
300         ERRTEST(E2BIG,
301                 "probe (to past EOF)",
302                 dm_probe_hole(sid, hanp, hlen, DM_NO_TOKEN, 15000, 150000,
303                               &roff, &rlen))
304 #endif
305         /*---------------------------------------------------------*/
306         SHAREDTEST("probe", hanp, hlen, test_token, 
307                  dm_probe_hole(sid, hanp, hlen, test_token, 
308                                0, 0, &roff, &rlen)) 
309         /*---------------------------------------------------------*/
310         EXCLTEST("punch", hanp, hlen, test_token, 
311                    dm_punch_hole(sid, hanp, hlen, test_token, 0, 0)) 
312         /*---------------------------------------------------------*/
313         ERRTEST(EAGAIN,
314                 "punch",
315                 dm_punch_hole(sid, hanp, hlen, DM_NO_TOKEN,
316                               1, length))       
317         /*---------------------------------------------------------*/
318         if ((test_vp = handle_clone(hanp, hlen)) == NULL) {
319           fprintf(stderr, 
320                   "Cannot create a test handle (%s); skipping EBADF test\n",
321                   ERR_NAME);
322         }
323         else {
324          ((char *) test_vp)[hlen/2]++;
325           ERRTEST(EBADF,
326                   "probe",
327                   dm_probe_hole(sid, test_vp, hlen, DM_NO_TOKEN,
328                                 offset, length,
329                                 &roff, &rlen))
330           ERRTEST(EBADF,
331                   "punch",
332                   dm_punch_hole(sid, test_vp, hlen, DM_NO_TOKEN,
333                                 offset, length))
334         }
335         dm_handle_free(test_vp, hlen);
336         /*---------------------------------------------------------*/
337         ERRTEST(EFAULT,
338                 "probe (null handle)",
339                 dm_probe_hole(sid, 0, hlen, DM_NO_TOKEN, offset, length,
340                                 &roff, &rlen))
341         ERRTEST(EFAULT,
342                 "probe (bad rlen)",
343                 dm_probe_hole(sid, 0, hlen, DM_NO_TOKEN, offset, length,
344                                 &roff, (dm_size_t*)(-1000)))
345         ERRTEST(EFAULT,
346                 "probe (bad roff)",
347                 dm_probe_hole(sid, hanp, hlen, DM_NO_TOKEN, offset, length,
348                                 (dm_off_t*)(-1000), &rlen))
349         /*---------------------------------------------------------*/
350         ERRTEST(EFAULT,
351                 "punch",
352                 dm_punch_hole(sid, 0, hlen, DM_NO_TOKEN, offset, length))
353         /*---------------------------------------------------------*/
354         ERRTEST(EINVAL,
355                 "probe (bad session)",
356                 dm_probe_hole(-100, hanp, hlen, DM_NO_TOKEN, offset, length,
357                                 &roff, &rlen))
358         /*---------------------------------------------------------*/
359         ERRTEST(EINVAL, 
360                 "probe (bad token)",
361                 dm_probe_hole(sid, hanp, hlen, 0, offset, length,
362                                 &roff, &rlen))
363         /*---------------------------------------------------------*/
364         ERRTEST(EINVAL, 
365                 "probe (bad token 2)",
366                 dm_probe_hole(sid, hanp, hlen, 0, offset, length,
367                                 &roff, &rlen))
368         /*---------------------------------------------------------*/
369         fprintf(stdout, "\t(errno subtests complete)\n");
370                 
371
372         sprintf(command, "rm %s \n", filename); 
373         system(command);
374         printf("Hole test complete.\n");
375
376         dm_handle_free(hanp, hlen);
377         exit(0);
378 }
379