[OpenVMS] Example-C How To Create And Record To File Using QIO's
PRODUCTS: DEC C, Version 5.6 OpenVMS VAX OpenVMS Alpha
SOURCE: Philippe Vouters Fontainebleau/France
HIGH QUALITY MOBILES+TABLETS: http://android-land.fr
OVERVIEW: This sample program does direct disk driver QIOs to create a file, record into it using a large buffer, truncate the file to the end of the recording block and reread it. This bypasses RMS for Realtime performance considera- tions.
*** CAUTION *** This sample program has been tested using DEC C V5.6 on OpenVMS ALPHA V7.1. However, we cannot guarantee its effectiveness because of the possibility of error in transmitting or implementing it. It is meant to be used as a template for writing your own program, and may require modification for use on your system.
PROGRAM NOTES: This program requires the PSWAPM priviledge and PHY_IO if writing LOGICAL blocks. Compile the program using the following commands: $ CC[/DEFINE=(logical[,byte=n])] Direct_disk_qio +- ALPHA$LIBRARY:SYS$LIB_C/LIBRARY $ LINK Direct_disk_qio $ iodisk :== $disk:[directory]Direct_disk_qio.exe $! Activation: $! iodisk <filename> $ exit
PROGRAM: /* * COPYRIGHT (C) 1997,1999 BY * DIGITAL EQUIPMENT CORPORATION, MAYNARD * MASSACHUSETTS. ALL RIGHTS RESERVED. * * THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED AND COPIED * ONLY IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE AND WITH THE INCLUSION * OF THE ABOVE COPYRIGHT NOTICE. THIS SOFTWARE OR ANY OTHER COPIES * THEREOF MAY NOT BE PROVIDED OR OTHERWISE MADE AVAILABLE TO ANY OTHER * PERSON. NO TITLE TO AND OWNERSHIP OF THE SOFTWARE IS HEREBY TRANSFERRED. * * THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE WITHOUT NOTICE AND * SHOULD NOT BE CONSTRUED AS A COMMITMENT BY DIGITAL EQUIPMENT CORPORATION. * * DIGITAL ASSUMES NO RESPONSIBILITY FOR THE USE OR RELIABILITY OF ITS * SOFTWARE ON EQUIPMENT THAT IS NOT SUPPLIED BY DIGITAL. * * NO RESPONSIBILITY IS ASSUMED FOR THE USE OR RELIABILITY OF SOFTWARE * ON EQUIPMENT THAT IS NOT SUPPLIED BY DIGITAL EQUIPMENT CORPORATION. * * SUPPORT FOR THIS SOFTWARE IS NOT COVERED UNDER ANY DIGITAL SOFTWARE * PRODUCT SUPPORT CONTRACT, BUT MAY BE PROVIDED UNDER THE TERMS OF THE * CONSULTING AGREEMENT UNDER WHICH THIS SOFTWARE WAS DEVELOPED. */ #ifdef __VAXC #module DISK_DRIVER "V1.0-003" #endif #ifdef __DECC #pragma module DISK_DRIVER "V1.0-003" #endif /* * Modification history * V1.0-003, Philippe Vouters, 27, August 1999 * - rewrite to use no static variables for better modularity. * Use freesub to see if there is enough disk space. * V1.0-002, Philippe Vouters, 19, November 1997 * - Compute the startlbn correctly according to ODS file struture * so that IO$_WRITELBLK writes to correct block. * - Suppress the NOSPAN record attribute which prevented a DUMP/RECORD * or a COPY when BYTE > 512 bytes. */ #include <stdio.h> #include <stdlib.h> #include <time.h> #include <errno.h> #include <string.h> #include time #pragma extern_prefix save #pragma extern_prefix "decc$" #include <unistd.h> #include <unixio.h> #pragma extern_prefix restore #include <descrip.h> /* Descriptor Structure and Constant Definitions */ #include <fibdef.h> /* File Information Block Definitions */ #include <fiddef.h> /* File identification Definitions */ #include <fatdef.h> #include <iodef.h> /* I/O function code Definitions */ #include <lib$routines.h> /* Library (LIB$) routine definitions */ #include <rms.h> /* All RMS Structure & Return Status Definitions */ #include <ssdef.h> /* System Service Return Status Value Definitions */ #include <starlet.h> /* System routine definitions*/ #include <psldef.h> #include <atrdef.h> #include <fh2def.h> #include <fm2def.h> #include <syidef.h> #include <secdef.h> #include <jpidef.h> #ifdef LOGICAL /* * Write Logical Block requires PHY_IO priviledge. */ #define IOWRT IO$_WRITELBLK #else #define IOWRT IO$_WRITEVBLK #endif /* ** ** MACRO DEFINITIONS ** */ /* ** The following macro defines a status check which ** occurs numerous times throughout the program. */ #define check_s(status) \ if ( ! (status & 1) ) lib$signal (status) #define BLOCKSIZE 512 #define nboucle 1000 #define nb 40 #ifndef BYTE #define byte BLOCKSIZE #else #define byte (BYTE/BLOCKSIZE)*BLOCKSIZE # if (byte > 32767) # error "BYTE cannot have a value greater than 32,767 bytes" # endif #endif #define sizbuf nb*byte /* Storage control block offsets, in *WORDS* */ #define CLEVOFF 0 /* Offset to structure level */ #define CLSFOFF 1 /* Offset to cluster factor */ #define CVSZOFF 2 /* Offset to volume size longword */ #define BITS 8 /* Number of bits per byte */ /* * The allocation size is setup arbitrarily to the maximum size + * 1,000 blocks. This is to show the effect of the truncate option * used at the end of the file writing. For an actual data collection * and file recording, without knowing either the number of Realtime * I/O collection or the size of each I/O recording, do a $getdvi for * this device, and setup the allocation_size to the number of free * blocks. Note that for getting the maximum disk space, while doing * logical blocks I/Os, initialize the disk with the /INDEX=BEGINNING * qualifier option. */ #define allocation_size (nboucle * sizbuf)/BLOCKSIZE + 1000 /* ** Declare counters etc. */ unsigned int device_channel; /* Channel Number */ #ifdef __DECC #pragma member_alignment save #pragma nomember_alignment word #endif typedef struct { unsigned short status; unsigned int bytes_count; unsigned short unused; } iosb_t; /* I/O status block */ typedef struct { unsigned short buflen; unsigned short code; void *buffer; int *retlen; } item_t; #ifdef __DECC #pragma member_alignment restore #endif /* Define references to FIB fields, for VAX only */ #ifdef __VAXC /* use full structure/union names on VAX */ #define f_i_b_outerl f_i_b.fib$r_fid_overlay.fibSr_fid_fields #define f_i_b_outer2 f_i_b_outerl.fib$r_fid_rvn_overlay #define f_i_b$w_fid_num f_i_b_outerl.fib$w_fid_num #define f_i_bSw_fid_seq f_i_b_outerl.fib$w_fid_seq #define f_i_bSw_fid_rvn f_i_b_outer2.fib$w_fid_rvn #define f_i_b$l_acctl f_i_b.fib$r_acctl_overlay.fib$l_acctl #endif typedef struct { char *buffer; /* The buffer that holds the data */ int para1; /* Loops indicator for filling buffer */ int startlbn; /* File starting logical block number */ unsigned long recnum; /* Total size of information recorded */ iosb_t io_status; /* $QIO I/O Status Block */ unsigned short device_channel; } ast_param_t; int AST_PROC(ast_param_t *ast_param) { int status,i; check_s (ast_param->io_status.status); ast_param->para1++; for(i=0 ; i <sizbuf ; i++) ast_param->buffer[i] = (i + ast_param->para1) % 256; ast_param->recnum += sizbuf; if(ast_param->para1 == nboucle) { if(((status = sys$wake(0, NULL)) & 1) != 1) lib$stop(status); } else status = sys$qio ( /* Write new record */ 0, /* no EFN */ ast_param->device_channel, /* Channel */ IOWRT, /* func = write virtual block */ &ast_param->io_status, /* IOSB */ AST_PROC, /* AST completion routine */ ast_param, /* parameters */ ast_param->buffer, /* P1 = address of buffer */ sizbuf, /* P2 = length of buffer */ ast_param->startlbn + (ast_param->para1*sizbuf)/BLOCKSIZE,/*P3 = Record number*/ 0, /* No P4-P6 */ 0,0); return(status); } int freesub(devptr,freptr,totptr,clsfac,contig) /* Output: 0 == success, <0 == error */ char *devptr; /* Input: device name, including colon */ long int *freptr; /* Output: free block count */ long int *totptr; /* Output: total block count */ short int *clsfac; /* Output: cluster factor */ long int *contig; { long int frecnt; /* 32 bit integers */ long int contigfrecnt=0; char previousfree = 0; unsigned short int n; /* 16 bit unsigned, for logical shift */ int i, j, k, ifil; /* Assorted integers */ short int buf[256]; /* bitmap data buffer */ char filspec[100]; /* temp buffer for creating filespec */ strcpy (filspec,devptr); /* Copy device spec into name buffer */ strcat (filspec,"[000000]BITMAP.SYS;1"); /* Append dir, filename */ *contig = 0; if ((ifil=open(filspec,0)) < 0) /* Open bitmap file */ return(ifil); /* Open failed, return error */ /* The first block of the bitmap file is a control block containing general * information about the volume. The remaining blocks are the actual bitmap, * one bit set for each cluster of blocks allocated. */ i= read(ifil,buf,512); /* Read the storage control block */ if (i < 1) return(i); /* Read failed, return error */ /* The storage bitmap level word should have a 2 in the high byte, and * a 1 in the low byte. That is the only structure level we understand, * so return an error if something else is there. */ if (buf[CLEVOFF] != 0x201) /* Verify ODS-2, bitmap format 1 */ return(-1); /* Allocation of blocks on an ODS-2 volume is done in bunches called * clusters. The cluster factor (number of 512 byte blocks in a cluster) * is needed to calculate the number of free blocks. */ *clsfac = buf[CLSFOFF]; /* Stash the cluster factor */ /* "Buf" is an array of 16-bit integers. The volume's total block size * is a longword, present in words CVSZOFF and CVSZOFF+1. Take the longword * starting at buf[CVSZOFF] and move it to the address in totptr. */ *totptr = *((long int *) &buf[CVSZOFF]); /* Invoke compiler magic */ /* Read the remaining bitmap blocks, counting bits by shifting each bit off. */ frecnt = 0; /* Nothing counted yet */ i= read(ifil,buf,512); /* Read first bitmap block */ while (i > 0) { /* While not EOF... */ for (j=0;j<256;j++) { /* Examine each word in the block */ n = buf[j]; /* Get unsigned data word */ for (k=0; k< sizeof(n)*BITS; k++) { /* Count free bits until zero */ if (n & 01){ /* If low bit is set... */ frecnt++; /* ...count a cluster free. */ contigfrecnt++; /* Keep track contiguous */ if (!previousfree) previousfree++; } else { /* Store maximum of contiguous bits set to 1 */ if (*contig < contigfrecnt) *contig = contigfrecnt; contigfrecnt = 0; /* Reset contiguous flag */ previousfree = 0; } n >>= 1; /* Shift off low bit of n */ } } i= read(ifil,buf,512); /* Read next block */ } /* The read failed: was it an error (i<0) or end-of-file (i==0)? */ if (i < 0) return(i); /* Read failed, return error */ /* Multiply the count of bits set in the bitmap by the cluster factor, * yielding the count of free blocks on the volume. */ *freptr = frecnt * *clsfac; /* Consider custer factor */ /* Store maximum of contiguous bits set to 1 */ if (*contig < contigfrecnt) *contig = contigfrecnt; *contig = *contig * *clsfac; /* Compute contiguous free blocks */ return(close(ifil)); /* All done */ } main(int argc, char **argv) { double io; int j, i; struct tm *date; char esa[NAM$C_MAXRSS]; char rsa[NAM$C_MAXRSS]; char device[NAM$C_MAXRSS]; char filename[NAM$C_MAXRSS]; int block_non_ok = -1; int block_ok = 0; int bad_record = 0; unsigned int uic; long int freeblocks,contiguous_freeblocks; unsigned int item_code = JPI$_UIC; char *inadr[2]; char *cp; char *defaultspec = "*.BID;*"; struct dsc$descriptor_s dummydsc; FAT fatbuf; FH2 file_hdr; FM2 *fm1; FM2 *map_area; FM2_1 *retrieval_pointer; struct atrdef *atr; struct tm datedeb; struct tm *datefin; ast_param_t *ast_param; unsigned long date_valdeb; unsigned long date_valfin; /* Declare RMS control blocks */ struct FAB f_a_b; /* File Access Block */ struct fibdef f_i_b; /* File Information Block */ struct RAB r_a_b; /* Record Access BLock */ struct NAM n_b; /* Name Block */ /* Declare Bits and Pieces for File Access */ unsigned long int status; /* Status Return */ unsigned long int record_match = SS$_NORMAL; /* Record Number Match */ struct dsc$descriptor_s device_descr = {0,DSC$K_DTYPE_T,DSC$K_CLASS_S,0}; /* Device descriptor */ #ifdef __DECC #pragma member_alignment save #pragma nomember_alignment word #endif struct { /* File Information Block Descriptor */ unsigned short intlength, pad; struct fibdef * addr; } fib_descr = { FIB$K_LENGTH,0,NULL}; #ifdef __DECC #pragma member_alignment restore #endif if(argc != 2){ printf("Usage $disq file_name\n"); exit(1); } fib_descr.addr = &f_i_b; memset(&f_i_b,0,sizeof(f_i_b)); memset(&fatbuf,0,sizeof(FAT)); /* * Set swapping mode to no swap. * Require PSWAPM priviledge. */ status = sys$setswm(1); check_s (status); ast_param = calloc(1,sizeof(ast_param_t)); ast_param->buffer = malloc(sizbuf); /* * Lock the buffer pages into working set to improve performances. * Require PSWAPM priviledge. */ inadr[0] = ast_param->buffer; inadr[1] = ast_param->buffer + sizbuf; status = sys$lckpag(inadr,NULL,PSL$C_USER); check_s(status); status = lib$getjpi (&item_code,0,NULL,&uic,NULL,NULL); check_s(status); printf("Stay tuned !!! Don't worry : it will work\n"); /* ** In the first part of the program, we start off by building the file ** using RMS functions. */ /* ** Begin by creating and opening the file using a FAB and NAM block. */ /* ** First, fill the necessary fields in the FAB. */ f_a_b = cc$rms_fab; /* Begin by using the initialized */ /* template provided by the system */ f_a_b.fab$l_fop = FAB$M_NAM | FAB$M_OFP; /* Use NAM Block inputs */ f_a_b.fab$l_fna = argv[1]; /* File name string address */ f_a_b.fab$b_fns = strlen(argv[1]); /* File name string size */ f_a_b.fab$l_dna = defaultspec; /* File name string address */ f_a_b.fab$b_dns = strlen(defaultspec); /* File name string size */ f_a_b.fab$l_nam = &n_b; /* File name block address */ /* ** Initialize the name block using the initialized template ** provided by the system. */ n_b = cc$rms_nam; n_b.nam$l_esa = esa; n_b.nam$b_ess = NAM$C_MAXRSS; n_b.nam$l_rsa = rsa; n_b.nam$b_rss = NAM$C_MAXRSS; n_b.nam$b_nop = NAM$M_NOCONCEAL; n_b.nam$b_ess = NAM$C_MAXRSS; status = sys$parse(&f_a_b,0,0); check_s (status); /* * Check if enough blocks free for operations. It must be greater than * allocation size. If LOGICAL I/O check contiguous free space otherwise * check free blocks. */ strncpy(device,n_b.nam$l_dev,n_b.nam$b_dev); device[n_b.nam$b_dev] = '\0'; if (freesub(device,&freeblocks,(long int *)&i,(short int*)&j, &contiguous_freeblocks) < 0){ printf ("Erreur getting free blocks information\n"); exit(0); } #ifdef LOGICAL if (allocation_size > contiguous_freeblocks){ printf ("Not enough contiguous free blocks on %s.\ Requested %d, contiguous %d\n", device,allocation_size,contiguous_freeblocks); #else if (allocation_size > freeblocks){ printf ("Not enough free blocks on %s. Requested %d, free %d\n", device,allocation_size,freeblocks); #endif exit(0); } printf("Disk free space checked. Continuing...\n"); /* * Get filename and type from the parse, appending a null version for * which is necessary to refer to last file's version. */ memset (filename,0,sizeof(filename)); strncpy(filename,n_b.nam$l_name,n_b.nam$b_name); strncat(filename,n_b.nam$l_type,n_b.nam$b_type); strcat (filename,";0"); /* ** We begin by using $ASSIGN to assign a channel to the file ** device. */ device_descr.dsc$w_length = n_b.nam$b_esl; device_descr.dsc$a_pointer = esa; status = sys$assign (&device_descr, /* Device descriptor */ &ast_param->device_channel, /* Channel number */ 0, /* Default access mode */ 0); /* No mailbox */ check_s(status); /* Exit if error */ /* ** To create the file, we use $QIO, specifying the IO$_CREATE ** function, with modifier IO$M_CREATE to create a directory entry. ** We pass the directory ID information from the sys$parse. */ dummydsc.dsc$w_length = strlen(filename); dummydsc.dsc$a_pointer = filename; dummydsc.dsc$b_class = DSC$K_CLASS_S; dummydsc.dsc$b_dtype = DSC$K_DTYPE_T; /* ** Because we parsed the device without specifying the nam$v_synchk bit ** set to one, we have in the name block a valid nam$w_did that we can ** use for further file creation in that directory. Also setup missing ** fib fields and set RMS file attributes in fatbuf. */ for (i=0;i<sizeof(f_i_b.fib$w_did)/sizeof (f_i_b.fib$w_did[0]);i++) f_i_b.fib$w_did[i] = n_b.nam$w_did[i]; f_i_b.fib$v_newver = 1; f_i_b.fib$v_writethru = 1; f_i_b.fib$v_extend = 1; f_i_b.fib$v_aldef = 1; /* * File allocation size. */ f_i_b.fib$l_exsz = allocation_size; #ifdef LOGICAL f_i_b.fib$v_alcon = 1; f_i_b.fib$v_filcon = 1; #endif /* * To speed up file access when using Virtual Access, map the the entire * window. */ f_i_b.fib$b_wsize = -1; fatbuf.fat$v_rtype = FAT$C_FIXED; fatbuf.fat$v_fileorg = FAT$C_SEQUENTIAL; fatbuf.fat$w_rsize = byte; fatbuf.fat$w_maxrec = byte; fatbuf.fat$w_efblkh = 0; fatbuf.fat$w_efblkl = 1; fatbuf.fat$w_ffbyte = 0; atr = calloc(3,sizeof(struct atrdef)); /* * Also Set Record Attributes and file's owner UIC. */ atr[0].atr$w_size = ATR$S_RECATTR; atr[0].atr$w_type = ATR$C_RECATTR; atr[0].atr$l_addr = &fatbuf; atr[1].atr$w_size = ATR$S_UIC; atr[1].atr$w_type = ATR$C_UIC; atr[1].atr$l_addr = &uic; status = sys$qiow (0, /* No event flag number */ ast_param->device_channel, /* Channel */ IO$_CREATE | IO$M_CREATE ,/* Create the file */ &ast_param->io_status, /* IO status block */ 0, /* No AST completion routine */ 0, /* So no AST routine parameters */ &fib_descr, /* P1 = address of FIB descriptor*/ &dummydsc, /* P2 = filename */ 0, /* No P3 */ 0, /* No P4 */ atr, /* P5 = ATR record */ 0); check_s(status); /* Close and exit if error */ check_s(ast_param->io_status.status); /* Close and exit if error */ f_i_b.fib$v_write = 1; f_i_b.fib$v_noread = 1; f_i_b.fib$v_nowrite = 1; f_i_b.fib$v_seqonly = 1; atr[1].atr$w_size = ATR$S_HEADER; atr[1].atr$w_type = ATR$C_HEADER; atr[1].atr$l_addr = &file_hdr; status = sys$qiow (0, /* No event flag number */ ast_param->device_channel, /* Channel */ IO$_ACCESS | IO$M_ACCESS ,/* Create the file */ &ast_param->io_status, /* IO status block */ 0, /* No AST completion routine */ 0, /* So no AST routine parameters */ &fib_descr, /* P1 = address of FIB descriptor*/ &dummydsc, 0, /* No P3 */ 0, /* no P4 */ atr, /* P5 = ATR record */ 0); check_s(status); /* Close and exit if error */ check_s(ast_param->io_status.status); /* Close and exit if error */ fm1 = map_area = (FM2 *)((short *)&file_hdr + file_hdr.fh2$b_mpoffset); #ifdef LOGICAL /* * Get file's stating logical block number (LBN). */ while (fm1<(FM2 *)((short *)map_area + file_hdr.fh2$b_map_inuse)){ if (fm1->fm2$v_format == FM2$C_PLACEMENT) fm1 = (FM2 *)((char *)fm1 + 2); else { switch (fm1->fm2$v_format){ case FM2$C_FORMAT1: ast_param->startlbn = fm1->fm2$w_lowlbn; ast_param->startlbn += fm1->fm2$v_highlbn << 16; fm1 = (FM2 *)((char *)fm1 + 4); break; case FM2$C_FORMAT2: ast_param->startlbn = ((FM2_1 *)fm1)->fm2$l_lbn2; fm1 = (FM2 *)((char *)fm1 + 6); break; case FM2$C_FORMAT3: ast_param->startlbn = ((FM2_2 *)fm1)->fm2$l_lbn3; fm1 = (FM2 *)((char *)fm1 + 8); } }/* end else */ } /* end while */ #else /* * For Virtual I/Os the startlbn is equal to the first file's VBN (1). */ ast_param->startlbn = 1; #endif /* * Get time of start of collection. */ time(&date_valdeb); date = localtime(&date_valdeb); memcpy(&datedeb,date,sizeof(struct tm)); /* * Initialize number of I/Os counter. */ ast_param->recnum = 0; ast_param->para1 = 0; /* * Setup the initial buffer content. */ for(i=0 ; i <sizbuf ; i++) ast_param->buffer[i] = (i + ast_param->para1) % 256; /* * Startup the first I/O with AST on the device channel. * WRITELBLK requires PHY_IO priviledge. */ status = sys$qio ( /* Write new record */ 0, /* no EFN */ ast_param->device_channel, /* Channel */ IOWRT, /* func = write virtual block */ &ast_param->io_status, /* IOSB */ AST_PROC, /* AST completion routine */ ast_param, /* parameters */ ast_param->buffer, /* P1 = address of buffer */ sizbuf, /* P2 = length of buffer */ ast_param->startlbn+ (ast_param->para1*sizbuf)/BLOCKSIZE,/* P3 = Record number */ 0, /* No P4-P6 */ 0, 0); check_s(status); /* make sure write OK */ /* * Hibernate. We will be awakened by the AST at the end of the collection. */ if(((status = sys$hiber()) &1) != 1) lib$stop(status); time(&date_valfin); /* ** All records have now been swapped pairwise. Close file ** using $QIO with IO$_DEACCESS and deassign the channel. ** Note that in this case we don't save the status return ** code. */ /* * Compute the number of BLOCKS that have been written. * Set file's EOF marker at the beginning of next block. * And, finally, truncate the file freeing used space. */ ast_param->recnum = (ast_param->recnum + BLOCKSIZE-1)/BLOCKSIZE + 1; /* * Set file's last VBN in high and low worrd. These words are * inverted for compatibilty reasons with PDP-11. */ fatbuf.fat$w_efblkh = (ast_param->recnum & ~0xFFFF) >> 16; fatbuf.fat$w_efblkl = ast_param->recnum & 0xFFFF; f_i_b.fib$v_writethru = 1; f_i_b.fib$v_extend = 0; f_i_b.fib$v_trunc = 1; f_i_b.fib$l_exsz = 0; f_i_b.fib$l_exvbn = ast_param->recnum; atr[1].atr$w_size = 0; atr[1].atr$w_type = 0; atr[1].atr$l_addr = 0; status = sys$qiow (0, /* No EFN */ ast_param->device_channel, IO$_DEACCESS, /* Function is deaccess file */ 0, /* No IOSB, AST, P2-P6 */ 0, 0, &fib_descr, /* P1 = address of FIB descriptor*/ 0,0,0, atr, 0); check_s(status); sys$dassgn (ast_param->device_channel); /* Deassign the device channel */ /* * Get end of collection time. */ datefin = localtime(&date_valfin); printf("end time = %d h %d m %d s\n",datefin->tm_hour,datefin->tm_min, datefin->tm_sec); printf("start time = %d h %d m %d s\n",datedeb.tm_hour,datedeb.tm_min, datedeb.tm_sec); /* * Compute the disk performance (number of bytes/seconds). */ io = ((double)(((datefin->tm_hour*60)+datefin->tm_min)*60+datefin->tm_sec)- (double)(((datedeb.tm_hour*60)+datedeb.tm_min)*60+datedeb.tm_sec)); if (io != 0.0){ io = (double) (sizbuf * nboucle)/io; printf("computed i/o rate = %.2lf bytes/sec with sizbuf = %d bytes\n", io,sizbuf); } else printf("computed i/o rate = +Infinity\n"); printf ("Checking file's content. Please wait ...\n"); /* ** We begin by using $ASSIGN to assign a channel to the file ** device to read the file using this time virtual blocks. */ status = sys$assign (&device_descr, /* Device descriptor */ &ast_param->device_channel, /* Channel number */ 0, /* Default access mode */ 0); /* No mailbox */ check_s(status); /* Exit if error */ /* ** To open the file, we use $QIO, specifying the io$access ** function, with read & write access specified. We use the ** file ID information from the first part of the program to ** get access to the file we want. */ /* * Reset the fib's access intention to READ. */ f_i_b.fib$v_write = 0; status = sys$qiow (0, /* No event flag number */ ast_param->device_channel, /* Channel */ IO$_ACCESS|IO$M_ACCESS, /* Access the file */ &ast_param->io_status, /* IO status block */ 0, /* No AST completion routine */ 0, /* So no AST routine parameters */ &fib_descr, /* P1 = address of FIB descriptor*/ &dummydsc, 0,0,0,0); /* No P3-P6 */ check_s(status); /* Close and exit if error */ check_s(ast_param->io_status.status); /* Close and exit if error */ /* * Reread the file using read Virtual Block. */ for(j = 0; j < nboucle; j++) { memset(ast_param->buffer,0,sizbuf); status = sys$qiow( /* Read record */ 0, /* no EFN */ ast_param->device_channel, /* Channel */ IO$_READVBLK, /* func = read virtual block */ &ast_param->io_status, /* IOSB */ 0, /* No AST completion routine */ 0, /* or parameters */ ast_param->buffer, /* P1 = address of buffer */ sizbuf, /* P2 = length of buffer */ (j*sizbuf)/BLOCKSIZE+1, /* P3 = Record number */ 0, /* No P4-P6 */ 0,0); check_s(status); /* make sure write OK */ /* * Check if records have been correctly written to the disk. */ for(i=0 ; i <sizbuf ; i++) if(ast_param->buffer[i] != (char)((i + j) % 256)){ printf("\nUncorrect record #%d, buffer[%d] = %2x, expected = %2x\n", j,i,ast_param->buffer[i],(i + j) % 256); block_non_ok = j; bad_record = 1; if (j!=0) printf ("Correct records range #%d to #%d\n", block_ok,block_non_ok -1); break; } if ((i == sizbuf) && (bad_record)){ block_ok = j; bad_record = 0; } } printf ("Correct records range #%d to #%d\n", block_non_ok+1,nboucle); /* ** All records have now been swapped pairwise. Close file ** using $QIO with IO$_DEACCESS and deassign the channel. ** Note that in this case we don't save the status return ** code. */ sys$qiow (0, /* No EFN */ ast_param->device_channel, IO$_DEACCESS, /* Function is deaccess file */ 0, /* No IOSB, AST, P1-P6 */ 0,0,0,0,0,0,0,0); sys$dassgn (ast_param->device_channel); /* Deassign the device channel */ /* * Set swapping mode to swap. * Require PSWAPM priviledge. */ status = sys$setswm(0); check_s (status); }
REFERENCE: "OpenVMS I/O User's Reference Manual", (AA-PV6SB-TK)