/* C-Kermit C RTL replacement functions for VMS systems. */ /*---------------------------------------------------------------------- * * utime() * * VMS C RTL before V7.3 lacks utime(). In V7.3, utime() sets only * the modified (revised) date, not the created date of a file. * * UNIX "ls -l" reports the modified time. VMS "DIRECTORY /DATE" * reports the creation time. Reconciling these in FTP DIR reports * is non-trivial. * * UNIX utime() sets revision and access times. VMS does not always * maintain access times, so this utime() replacement sets the * creation and revision times to the specified revision (or * creation?) time. Any access time is ignored. * *---------------------------------------------------------------------- */ #if __CRTL_VER >= 70300000 /* Avoid "%CC-W-EMPTYFILE, Source file does not contain any declarations." */ int dummy_function(void); #else /* __CRTL_VER < 70300000 */ #include <errno.h> #include <string.h> #include <time.h> #include <unixlib.h> #include <atrdef.h> #include <descrip.h> #include <fibdef.h> #include <iodef.h> #include <lib$routines.h> #include <rms.h> #include <starlet.h> #include <stsdef.h> #include "ckvrtl.h" /* Use <iosbdef.h> if available. Otherwise declare IOSB here. */ #if !defined( __VAX) && (__CRTL_VER >= 70000000) #include <iosbdef.h> #else /* __CRTL_VER >= 70000000 */ typedef struct _iosb { unsigned short int iosb$w_status; /* Final I/O status */ unsigned short int iosb$w_bcnt; /* 16-bit byte count */ unsigned int iosb$l_dev_depend; /* 32-bit dev dependent */ } IOSB; #endif /* !defined( __VAX) && (__CRTL_VER >= 70000000) */ /* Ugly work-around for bad type in VAX <atrdef.h>. */ #ifdef __VAX #define UWA (unsigned int) #else /* def __VAX */ #define UWA #endif /* def __VAX */ /* Private utime() code. */ /* Use long name (NAML) structure only where available. (This should be non-VAX with __CRTL_VER >= 70200000.) */ #ifdef NAML$C_BID /* Use long name (NAML) structure. */ #define FAB$L_NAMX fab$l_naml #define NAMX NAML #define NAMX$C_MAXRSS NAML$C_MAXRSS #define NAMX$B_DEV naml$l_long_dev_size #define NAMX$L_DEV naml$l_long_dev #define NAMX$L_ESA naml$l_long_expand #define NAMX$B_ESL naml$l_long_expand_size #define NAMX$B_ESS naml$l_long_expand_alloc #define NAMX$W_FID naml$w_fid #define NAMX$L_RSA naml$l_long_result #define NAMX$B_RSL naml$l_long_result_size #define NAMX$B_RSS naml$l_long_result_alloc #define CC$RMS_NAMX cc$rms_naml #else /* def NAML$C_BID */ /* Use short name (NAM) structure. */ #define FAB$L_NAMX fab$l_nam #define NAMX NAM #define NAMX$C_MAXRSS NAM$C_MAXRSS #define NAMX$B_DEV nam$b_dev #define NAMX$L_DEV nam$l_dev #define NAMX$L_ESA nam$l_esa #define NAMX$B_ESL nam$b_esl #define NAMX$B_ESS nam$b_ess #define NAMX$W_FID nam$w_fid #define NAMX$L_RSA nam$l_rsa #define NAMX$B_RSL nam$b_rsl #define NAMX$B_RSS nam$b_rss #define CC$RMS_NAMX cc$rms_nam #endif /* def NAML$C_BID */ /*--------------------------------------------------------------------*/ /* Private utime() code. */ /* Action routine for decc$to_vms(), in utime(). */ char vms_path[ NAMX$C_MAXRSS+ 1]; int set_vms_name( char *name, int type) { strncpy( vms_path, name, NAMX$C_MAXRSS); vms_path[ NAMX$C_MAXRSS] = '\0'; return 1; } /*--------------------------------------------------------------------*/ /* utime() replacement. */ int vms_utime( const char *path, const struct utimbuf *times) { time_t utc_unsigned; int chan, i; int sts, sts2; unsigned short int vms_num_vec_time[ 7]; unsigned int vms_abs_time[ 2]; struct tm *tms; struct _iosb iosb_q; /* QIOW item list used to set creation and revision dates. */ struct atrdef ut_atr[ 3] = { {sizeof( vms_abs_time), ATR$C_CREDATE, UWA vms_abs_time}, {sizeof( vms_abs_time), ATR$C_REVDATE, UWA vms_abs_time}, {0,0,0}}; /* Various RMS structures used for file access. */ struct FAB ut_fab = cc$rms_fab; struct RAB ut_rab = cc$rms_rab; struct NAMX ut_namx = CC$RMS_NAMX; static struct fibdef ut_fib; /* Device and file name buffers and their descriptors. */ static char dev_namx[ NAMX$C_MAXRSS+ 1]; char esa_namx[ NAMX$C_MAXRSS+ 1]; char rsa_namx[ NAMX$C_MAXRSS+ 1]; struct dsc$descriptor dev_dsc = {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, dev_namx}; struct dsc$descriptor fib_dsc = {sizeof( ut_fib), DSC$K_DTYPE_T, DSC$K_CLASS_S, (char *) &ut_fib}; /* We will accept either a UNIX-like path name or a VMS-like path name. If a slash is found in the name, assume that it's UNIX-like, and convert it to VMS form. Otherwise, use it as-is. */ if (strchr( path, '/') != NULL) { sts = decc$to_vms( path, set_vms_name, 0, 0); path = vms_path; } /* Install the VMS file specification into the FAB. */ ut_fab.fab$l_fna = (char *) path; ut_fab.fab$b_fns = (unsigned char) strlen( path); ut_fab.fab$l_dna = ""; ut_fab.fab$b_dns = 0; /* Point the FAB to the NAMX. */ ut_fab.FAB$L_NAMX = &ut_namx; /* Install the name buffers into the NAM. */ ut_namx.NAMX$L_ESA = esa_namx; ut_namx.NAMX$B_ESL = 0; ut_namx.NAMX$B_ESS = sizeof( esa_namx)- 1; ut_namx.NAMX$L_RSA = rsa_namx; ut_namx.NAMX$B_RSL = 0; ut_namx.NAMX$B_RSS = sizeof( rsa_namx)- 1; /* Convert the modification time (UTC time_t) to local "tm" time. */ tms = localtime( &(times-> modtime)); /* Move (translate) "tm" structure local time to VMS vector time. */ if (tms != NULL) { vms_num_vec_time[ 0] = tms-> tm_year+ 1900; vms_num_vec_time[ 1] = tms-> tm_mon+ 1; vms_num_vec_time[ 2] = tms-> tm_mday; vms_num_vec_time[ 3] = tms-> tm_hour; vms_num_vec_time[ 4] = tms-> tm_min; vms_num_vec_time[ 5] = tms-> tm_sec; vms_num_vec_time[ 6] = 0; /* centiseconds */ /* Convert VMS vector time to VMS absolute time (quadword). */ sts = lib$cvt_vectim( vms_num_vec_time, vms_abs_time); if ((sts& STS$M_SEVERITY) == STS$K_SUCCESS) { /* Parse the file specification. */ sts = sys$parse( &ut_fab, 0, 0); if ((sts& STS$M_SEVERITY) == STS$K_SUCCESS) { /* Locate the file. (Gets the FID.) */ sts = sys$search( &ut_fab, 0, 0); if ((sts& STS$M_SEVERITY) == STS$K_SUCCESS) { /* Form the device name descriptor. */ dev_dsc.dsc$w_length = ut_namx.NAMX$B_DEV; dev_dsc.dsc$a_pointer = (char *) ut_namx.NAMX$L_DEV; /* Assign a channel to the disk device. */ sts = sys$assign( &dev_dsc, &chan, 0, 0); if ((sts& STS$M_SEVERITY) == STS$K_SUCCESS) { /* Move the FID (and not the DID) into the FIB. */ memset( (void *) &ut_fib, 0, sizeof( ut_fib)); for (i = 0; i < 3; i++) { ut_fib.fib$w_fid[ i] = ut_namx.NAMX$W_FID[ i]; ut_fib.fib$w_did[ i] = 0; } /* Prevent this QIOW from setting the revision time to now. */ ut_fib.fib$l_acctl = FIB$M_NORECORD; /* Set the file dates. */ sts = sys$qiow( 0, chan, IO$_MODIFY, &iosb_q, 0, 0, &fib_dsc, 0, 0, 0, ut_atr, 0); if ((sts& STS$M_SEVERITY) == STS$K_SUCCESS) { sts = iosb_q.iosb$w_status; } sts2 = sys$dassgn( chan); if ((sts& STS$M_SEVERITY) == STS$K_SUCCESS) { sts = sts2; } } } } } } /* Convert successful VMS status to zero = success status. If failure, set errno and vaxc$errno, and return -1 = failure status. */ if ((sts& STS$M_SEVERITY) == STS$K_SUCCESS) { sts = 0; } else { errno = EVMSERR; vaxc$errno = sts; sts = -1; } return sts; } #endif /* __CRTL_VER >= 70300000 [else] */ /**********************************************************************/ #if !defined( __VAX) && (__CRTL_VER >= 70301000) #include <stdio.h> #include <unixlib.h> /* Flag to sense if vms_init() was called. (Handy for debug.) */ int vms_init_done = -1; /* vms_init() Uses LIB$INITIALIZE to set a collection of C RTL features without requiring the user to define the corresponding logical names. */ /* Structure to hold a DECC$* feature name and its desired value. */ typedef struct { char *name; int value; } decc_feat_t; /* Array of DECC$* feature names and their desired values. */ decc_feat_t decc_feat_array[] = { /* Preserve command-line case with SET PROCESS/PARSE_STYLE=EXTENDED */ { "DECC$ARGV_PARSE_STYLE", 1 }, /* Preserve case for file names on ODS5 disks. */ { "DECC$EFS_CASE_PRESERVE", 1 }, /* Enable multiple dots (and most characters) in ODS5 file names, while preserving VMS-ness of ";version". */ { "DECC$EFS_CHARSET", 1 }, /* List terminator. */ { (char *)NULL, 0 } }; /* LIB$INITIALIZE initialization function. */ static void vms_init( void) { int feat_index; int feat_value; int feat_value_max; int feat_value_min; int i; int sts; /* Set the global flag to indicate that LIB$INITIALIZE worked. */ vms_init_done = 1; /* Loop through all items in the decc_feat_array[]. */ for (i = 0; decc_feat_array[ i].name != NULL; i++) { /* Get the feature index. */ feat_index = decc$feature_get_index( decc_feat_array[ i].name); if (feat_index >= 0) { /* Valid item. Collect its properties. */ feat_value = decc$feature_get_value( feat_index, 1); feat_value_min = decc$feature_get_value( feat_index, 2); feat_value_max = decc$feature_get_value( feat_index, 3); if ((decc_feat_array[ i].value >= feat_value_min) && (decc_feat_array[ i].value <= feat_value_max)) { /* Valid value. Set it if necessary. */ if (feat_value != decc_feat_array[ i].value) { sts = decc$feature_set_value( feat_index, 1, decc_feat_array[ i].value); } } else { /* Invalid DECC feature value. */ printf( " INVALID DECC FEATURE VALUE, %d: %d <= %s <= %d.\n", feat_value, feat_value_min, decc_feat_array[ i].name, feat_value_max); } } else { /* Invalid DECC feature name. */ printf( " UNKNOWN DECC FEATURE: %s.\n", decc_feat_array[ i].name); } } } /* Get "vms_init()" into a valid, loaded LIB$INITIALIZE PSECT. */ #pragma nostandard /* Establish the LIB$INITIALIZE PSECTs, with proper alignment and other attributes. Note that "nopic" is significant only on VAX. */ #pragma extern_model save #pragma extern_model strict_refdef "LIB$INITIALIZE" 2, nopic, nowrt void (*const x_vms_init)() = vms_init; #pragma extern_model strict_refdef "LIB$INITIALIZ" 2, nopic, nowrt const int spare[ 8] = { 0 }; #pragma extern_model restore /* Fake reference to ensure loading the LIB$INITIALIZE PSECT. */ #pragma extern_model save int LIB$INITIALIZE(void); #pragma extern_model strict_refdef int dmy_lib$initialize = (int) LIB$INITIALIZE; #pragma extern_model restore #pragma standard #endif /* !defined( __VAX) && (__CRTL_VER >= 70301000) */