/*
* Copyright (c) 2000-2001 Silicon Graphics, Inc. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it would be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* Further, this software is distributed without any warranty that it is
* free of the rightful claim of any third person regarding infringement
* or the like. Any license provided herein, whether implied or
* otherwise, applies only to this software file. Patent licenses, if
* any, provided herein do not apply to combinations of this program with
* other software, or any other product whatsoever.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write the Free Software Foundation, Inc., 59
* Temple Place - Suite 330, Boston MA 02111-1307, USA.
*
* Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
* Mountain View, CA 94043, or:
*
* http://www.sgi.com
*
* For further information regarding this notice, see:
*
* http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <lib/hsm.h>
#include <lib/errtest.h>
#include <getopt.h>
#include <string.h>
/*---------------------------------------------------------------------------
Test program used to test the DMAPI function dm_punch_hole(). The
command line is:
test_hole [-v] [-s sid] pathname
where
ls_path
is the path to a specific copy of ls, important only for its size
pathname
is the path to the test filesystem
sid
is the session ID whose events you you are interested in.
----------------------------------------------------------------------------*/
#ifndef linux
extern char *sys_errlist[];
#endif
extern int optind;
extern char *optarg;
char *Progname;
static void
usage(void)
{
fprintf(stderr, "usage:\t%s [-v] [-s sid] ls_path directoryname\n",
Progname);
exit(1);
}
int
main(
int argc,
char **argv)
{
dm_sessid_t sid = DM_NO_SESSION;
char *pathname = NULL;
char *ls_path = NULL;
dm_off_t offset = 0;
dm_off_t ex_off = 0;
dm_extent_t extent[20];
u_int nelem;
dm_size_t length = 0;
void *hanp;
size_t hlen;
dm_token_t test_token;
char *name;
int opt;
int Vflag = 0;
char filename[128];
char command[128];
dm_off_t roff;
dm_size_t rlen;
dm_off_t blocksize = 5;
void *test_vp;
struct stat buf;
struct stat checkbuf;
if (Progname = strrchr(argv[0], '/')) {
Progname++;
} else {
Progname = argv[0];
}
/* Crack and validate the command line options. */
while ((opt = getopt(argc, argv, "vs:")) != EOF) {
switch (opt) {
case 'v':
Vflag++;
break;
case 's':
sid = atol(optarg);
break;
case '?':
usage();
}
}
if (optind + 2 != argc)
usage();
ls_path = argv[optind];
pathname = argv[optind+1];
if (dm_init_service(&name) == -1) {
fprintf(stdout, "Can't initialize the DMAPI\n");
exit(1);
}
if (sid == DM_NO_SESSION)
find_test_session(&sid);
/* Get the directory handle. */
if (dm_path_to_handle(pathname, &hanp, &hlen)) {
fprintf(stdout,
"ERROR: can't get handle for directory %s\n", pathname);
exit(1);
}
printf("Hole test beginning...\n");
sprintf(filename, "%s/VeryLongUnlikelyFilename.HOLETEST", pathname);
sprintf(command, "cp %s %s \n", ls_path, filename);
system(command);
if (dm_path_to_handle(filename, &hanp, &hlen)) {
fprintf(stdout, "can't get handle for %s\n; aborting test",
filename);
sprintf(command, "rm %s \n", filename);
system(command);
fprintf(stdout, "\tHole test aborted.\n");
dm_handle_free(hanp, hlen);
exit(1);
}
/* ## Get the block size using a length-1 probe. ## */
dm_probe_hole(sid, hanp, hlen, DM_NO_TOKEN, 1, 0,
&blocksize, &rlen);
if (blocksize==0) {
fprintf(stdout, "Error: block size appears to be 0!\n");
sprintf(command, "rm %s \n", filename);
system(command);
fprintf(stdout, "\tHole test aborted.\n");
dm_handle_free(hanp, hlen);
exit(1);
}
/* Check that dm_probe_hole returns an extent from the next
* highest multiple of the block size, to the end of the file
*/
for (offset = 0; offset < 29604; offset++) {
if (dm_probe_hole(sid, hanp, hlen, DM_NO_TOKEN, offset, length,
&roff, &rlen)) {
fprintf(stdout, "dm_probe_hole failed on pass %lld (%s)\n",
(long long)offset, ERR_NAME);
}
else {
if (rlen != 0) {
fprintf(stdout,
"Error: hole did not extend to end of file!\n");
}
if (blocksize*(roff/blocksize) != roff) {
fprintf(stdout,
"Error: offset not a multiple of block size!\n");
}
}
}
/* Be sure dm_punch_hole doesn't change the time stamp,
* and verify that dm_get_allocinfo shows a hole
* followed by an extent to the end of the file.
*/
for(offset = 28672; offset > 0; offset-=blocksize) {
if (stat(filename, &buf)){
fprintf(stdout,
"Error: unable to stat the test file; %s (1st)\n",
filename);
continue;
}
if (dm_probe_hole(sid, hanp, hlen, DM_NO_TOKEN, offset, length,
&roff, &rlen)) {
fprintf(stdout, "dm_probe_hole failed, %s\n",
ERR_NAME);
continue;
}
if (roff != offset) {
fprintf(stdout,
"Error: presumed offset was not %lld.\n",
(long long)(roff));
}
if (dm_punch_hole(sid, hanp, hlen, DM_NO_TOKEN,
roff, length)) {
fprintf(stdout, "dm_punch_hole failed, %s\n",
ERR_NAME);
continue;
}
if (stat(filename, &checkbuf)){
fprintf(stdout,
"Error: unable to stat the test file. (2nd)\n");
continue;
}
else {
/* COMPARE BUF AND CHECKBUF! */
#ifdef linux
if ((buf.st_atime == checkbuf.st_atime) &&
(buf.st_mtime == checkbuf.st_mtime) &&
(buf.st_ctime == checkbuf.st_ctime))
#else
if ((buf.st_atim.tv_sec == checkbuf.st_atim.tv_sec) &&
(buf.st_atim.tv_nsec == checkbuf.st_atim.tv_nsec) &&
(buf.st_mtim.tv_sec == checkbuf.st_mtim.tv_sec) &&
(buf.st_mtim.tv_nsec == checkbuf.st_mtim.tv_nsec) &&
(buf.st_ctim.tv_sec == checkbuf.st_ctim.tv_sec) &&
(buf.st_ctim.tv_nsec == checkbuf.st_ctim.tv_nsec))
#endif
{
if (Vflag) {
fprintf(stdout,
"\tTime stamp unchanged by hole from offset %lld.\n",
(long long)(offset));
}
}
else {
fprintf(stdout,
"Error: punch_hole changed file's time stamp.\n");
}
ex_off=0;
if ((dm_get_allocinfo(sid, hanp, hlen, DM_NO_TOKEN,
&ex_off, 1, extent, &nelem) == 1) &&
(extent->ex_type == DM_EXTENT_RES) &&
(dm_get_allocinfo(sid, hanp, hlen, DM_NO_TOKEN,
&ex_off, 1, extent, &nelem) == 0) &&
(extent->ex_type == DM_EXTENT_HOLE)) {
if (extent->ex_offset == roff){
if (Vflag) {
fprintf(stdout, "\tVerified hole at %lld\n",
(long long)(extent->ex_offset));
}
}
else {
fprintf(stdout, "\tError: get_allocinfo found hole at %lld\n",
(long long)(extent->ex_offset));
}
}
else {
fprintf(stdout, "\tError: get_allocinfo did not find an "
"extent followed by a hole!\n");
}
}
}
/*------------------------*\
|* ## Errno subtests ## *|
\*------------------------*/
fprintf(stdout, "\t(beginning errno subtests...)\n");
/*---------------------------------------------------------*/
ERRTEST(E2BIG,
"probe (from past EOF)",
dm_probe_hole(sid, hanp, hlen, DM_NO_TOKEN, 30000, length,
&roff, &rlen))
/*---------------------------------------------------------*/
#if 0
PROBLEM: No error is produced.
off+len >= filesize should produce E2BIG...
ERRTEST(E2BIG,
"probe (to past EOF)",
dm_probe_hole(sid, hanp, hlen, DM_NO_TOKEN, 15000, 150000,
&roff, &rlen))
#endif
/*---------------------------------------------------------*/
SHAREDTEST("probe", hanp, hlen, test_token,
dm_probe_hole(sid, hanp, hlen, test_token,
0, 0, &roff, &rlen))
/*---------------------------------------------------------*/
EXCLTEST("punch", hanp, hlen, test_token,
dm_punch_hole(sid, hanp, hlen, test_token, 0, 0))
/*---------------------------------------------------------*/
ERRTEST(EAGAIN,
"punch",
dm_punch_hole(sid, hanp, hlen, DM_NO_TOKEN,
1, length))
/*---------------------------------------------------------*/
if ((test_vp = handle_clone(hanp, hlen)) == NULL) {
fprintf(stderr,
"Cannot create a test handle (%s); skipping EBADF test\n",
ERR_NAME);
}
else {
((char *) test_vp)[hlen/2]++;
ERRTEST(EBADF,
"probe",
dm_probe_hole(sid, test_vp, hlen, DM_NO_TOKEN,
offset, length,
&roff, &rlen))
ERRTEST(EBADF,
"punch",
dm_punch_hole(sid, test_vp, hlen, DM_NO_TOKEN,
offset, length))
}
dm_handle_free(test_vp, hlen);
/*---------------------------------------------------------*/
ERRTEST(EFAULT,
"probe (null handle)",
dm_probe_hole(sid, 0, hlen, DM_NO_TOKEN, offset, length,
&roff, &rlen))
ERRTEST(EFAULT,
"probe (bad rlen)",
dm_probe_hole(sid, 0, hlen, DM_NO_TOKEN, offset, length,
&roff, (dm_size_t*)(-1000)))
ERRTEST(EFAULT,
"probe (bad roff)",
dm_probe_hole(sid, hanp, hlen, DM_NO_TOKEN, offset, length,
(dm_off_t*)(-1000), &rlen))
/*---------------------------------------------------------*/
ERRTEST(EFAULT,
"punch",
dm_punch_hole(sid, 0, hlen, DM_NO_TOKEN, offset, length))
/*---------------------------------------------------------*/
ERRTEST(EINVAL,
"probe (bad session)",
dm_probe_hole(-100, hanp, hlen, DM_NO_TOKEN, offset, length,
&roff, &rlen))
/*---------------------------------------------------------*/
ERRTEST(EINVAL,
"probe (bad token)",
dm_probe_hole(sid, hanp, hlen, 0, offset, length,
&roff, &rlen))
/*---------------------------------------------------------*/
ERRTEST(EINVAL,
"probe (bad token 2)",
dm_probe_hole(sid, hanp, hlen, 0, offset, length,
&roff, &rlen))
/*---------------------------------------------------------*/
fprintf(stdout, "\t(errno subtests complete)\n");
sprintf(command, "rm %s \n", filename);
system(command);
printf("Hole test complete.\n");
dm_handle_free(hanp, hlen);
exit(0);
}