/* @(#)osf.c 17.1.1.2 (ESO-DMD) 02/25/02 17:53:19 */ /*=========================================================================== Copyright (C) 1995 European Southern Observatory (ESO) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA. Correspondence concerning ESO-MIDAS should be addressed as follows: Internet e-mail: midas@eso.org Postal address: European Southern Observatory Data Management Division Karl-Schwarzschild-Strasse 2 D 85748 Garching bei Muenchen GERMANY ===========================================================================*/ /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .TYPE Module .NAME osf .LANGUAGE C .AUTHOR IPG-ESO Garching .ENVIRONMENT VAX / VMS Version .CATEGORY Host operating system interfaces. File management. .COMMENTS File management. These routines provide miscellaneous operations, on files and directories. The routines use the physical file name to access files. The routines return always a non-negative integer number on successful return. Otherwise, a value of -1 is set to indicate an error condition and the variable ``oserror'' contains the symbolic error code. .VERSION 0.0 25-Aug-1986 Definition J. D. Ponz .VERSION 2.0 13-Oct-1988 F. Ochsenbein. Removed logical translations, which do not deal only with files. Translation of logical names now as oshenv. Also, osfcreate FAILS if the file already exists!! Use osdopen with write option to rewrite / create a file... .VERSION 2.1 23-Aug-1990 F. Ochsenbein. Files are created with RAT = CR. Take care of non-sequential files... .VERSION 2.2 17-Oct-1990: Removed GNU-nonunderstandable code... .VERSION 2.3 19-Feb-1992: osfinfo: filestatus modified. CG. .VERSION 2.4 20-Aug-1992: osfinfo: filestatus modified. blocksize dropped.CG 020201 last modif -----------------------------------------------*/ #define DEBUG 0 /* Set to 1 for Debugging Option */ #define SECTOR_SIZE 512 #include #include #include #include #include /* System */ #include /* System */ #include /* System */ # define fab$l_fna name # define fab$b_fns lname # define rab$l_ctx buffer # define fab$l_ctx file_no # define TheSector(n) (n-1) # define FileSector(n) (n+1) #include /* System */ #include /* System */ #include /* System */ MID_EXTERN vmserror; /* VMS-specific error code */ MID_EXTERN int oserror; MID_EXTERN char *oserrmsg; #define FINISH goto FIN static struct FAB fay, *fap; static struct RAB *fp; static struct XABFHC *fhp; /* File Header Characteristics */ static struct XABPRO *pro; /* Protections */ static struct XABRDT *rdt; /* Revision Date & Time */ static unsigned short zero = 0; char *osmmget(); /*========================================================================== * Protection Code Changes *==========================================================================*/ /*==========================================================================*/ static int u_v (u) /*++++++++ .PURPOSE Converts protection code from Unix to VMS. .RETURNS Unix-like protection code. .METHOD The VMS protection field is made of 4 hexadecimal digits, edited as `WGOS'; each hexa digit contains bits `dewr' set to 1 to DENY access. UNIX uses 3 octal digits `OGW', with bits `rwe' set to 1 to PERMIT access. ------------------------------------------------------------*/ int u; /* IN: UNIX protection code */ { register int v, i, k; /* Process World, Group, Owner */ for (i=3, k=u, v=0; --i>=0; k >>= 3, v <<= 4) { v |= ( k & 2 ? 0 :10); /* WD permission */ v |= ( k & 4 ? 0 : 1); /* Read permission */ v |= ( k & 1 ? 0 : 4); /* Exec permission */ } /* Add System = Owner */ v |= (v >> 12); #if DEBUG printf("\nConverted prot. code %3o (Unix) to %4X (VMS)\n", u, v); #endif return(v); } /*==========================================================================*/ static int v_u (v) /*++++++++ .PURPOSE Converts protection code from VMS to Unix. .RETURNS VMS protection code. .METHOD The VMS protection field is made of 4 hexadecimal digits, edited as `WGOS'; each hexa digit contains bits `dewr' set to 1 to DENY access. UNIX uses 3 octal digits `OGW', with bits `rwe' set to 1 to PERMIT access. ------------------------------------------------------------*/ int v; /* IN: VMS protection code */ { register int u, i, k; k = v >> 4; /* Suppress system protections */ /* Process World, Group, Owner */ for (i=3, u=0; --i>=0; k >>= 4) { u <<= 3; u |= ( k & 2 ? 0 : 2); /* Write permission */ u |= ( k & 4 ? 0 : 1); /* Read permission */ u |= ( k & 1 ? 0 : 4); /* Exec permission */ } #if DEBUG printf("\nConverted prot. code %4X (VMS) to %3o (Unix)\n", v, u); #endif return(u); } /*======================================================================*/ static long vmstime(q) /*+++++++++++++ .PURPOSE Converts the VAX time to standard .RETURNS Time as seconds elapsed since Jan. 1, 1970 .REMARKS The VAX time is 64 bits; origin = Nov. 17, 1858; units = 100ns. (40587 days before Jan 1, 1970) --------------*/ unsigned long *q; /* IN: VAX time */ { register double tt; register long t; tt = q[1] * 4294967296e0; tt = tt + q[0]; tt = tt / 1.e7 - (40587.e0 * 86400.e0); t = tt; return(t); } /*======================================================================*/ static int finit (phname) /*++++++++ .PURPOSE Initializes the RMS blocks .RETURNS 0 ------------------------------------------------------------*/ char *phname; /* IN : physical filename */ { struct RAB *vmsinit(); fp = vmsinit(phname); fap = fp->rab$l_fab; fap->fab$b_fac = FAB$M_BRO|FAB$M_PUT; fhp = (struct XABFHC *)fap->fab$l_xab; /* File Header Characteristics */ pro = (struct XABPRO *)fhp->xab$l_nxt; /* Next block = protection */ rdt = (struct XABRDT *)pro->xab$l_nxt; /* Next block = date/time */ return(0); } /*========================================================================== * osf Routines *==========================================================================*/ /*==========================================================================*/ int osfcreate(phname, nobyt, protec) /*++++++++ .PURPOSE Creates a NEW file (STMLF format by default). Access is done by physical file name. Owner and group identifications of the process creating the file define the owner and group identification of the file. The argument protec gives the file protection code, in Unix form. .RETURNS 0 upon successful completion. Else , -1 is returned and the system error code is set into oserror. Note that trying to create a new file with the same name as an existing file is an error. .REMARKS The protection code may also include the NOATTR option. The protection code is made of 3 octal digits `OGW' for Owner / Group / World; each octal digit is made of 3 bits `rwe' for read / write (delete) / execute protection set to 1 to PERMIT access. As an example, 0755 allows read / execute to everybody, but rewriting the file is only allowed to the owner. The protection code of 0 converted to default 0755 protection. To create non-STMLF files, use osfop before oscfreate. ----------------------------------*/ char *phname; /* IN : physical filename */ long nobyt; /* IN : number of bytes to be allocated */ int protec; /* IN : protection code `OGW' (3 octal digits) \ and NOATTR option */ { register int i; MID_STATIC char c = '\n'; /* Character written in file*/ oserror = 0; if (nobyt < 0) nobyt = 0; if (protec == 0) protec = 0755; finit(phname); if (protec & NOATTR) ; else fap->fab$b_rat = FAB$M_CR; /* Create file With RAT */ i = (nobyt + SECTOR_SIZE - 1) / SECTOR_SIZE; /* if (fap->fab$b_org == FAB$C_SEQ)*/ fap->fab$l_alq = i; pro->xab$w_pro = u_v(protec); /* Convert Protection Code */ vmserror = SYS$CREATE(fap); /* Create the file ... */ if (vmserror != RMS$_NORMAL) FINISH; if (nobyt && (fap->fab$b_org == FAB$C_SEQ)) { /* Write if necessary */ vmserror = SYS$CONNECT(fp); if (vmserror != RMS$_NORMAL) FINISH; fp->rab$l_bkt = i; /* Last block ... */ fp->rab$w_rsz = nobyt - SECTOR_SIZE*(i-1); fp->rab$l_rbf = osmmget(fp->rab$w_rsz); LIB$MOVC5(&zero, 0, &zero, &fp->rab$w_rsz, fp->rab$l_rbf); /* Fill with zeroes */ *(fp->rab$l_rbf + fp->rab$w_rsz -1) = c; vmserror = SYS$WRITE(fp); if (vmserror != RMS$_NORMAL) FINISH; osmmfree(fp->rab$l_rbf); } vmserror = SYS$CLOSE(fap); /* Close the file ... */ if (vmserror != RMS$_NORMAL) FINISH; FIN: if (vmserror != RMS$_NORMAL) oserror = EIO; return( oserror ? -1 : 0); } /*==========================================================================*/ int osfdelete(phname) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Deletes file on disk by removing the directory entry corresponding to the physical name. The file is assumed not to be open. .RETURNS Value 0 on normal return / -1 if something wrong happened. ``oserror'' is then set to the system error code. .REMARKS ------------------------------------------------------------*/ char *phname; /* IN : physical filename */ { oserror = 0; finit(phname); vmserror = SYS$ERASE(fap); if (vmserror != RMS$_NORMAL) oserror = ENOENT; return(oserror ? -1 : 0); } /*==========================================================================*/ int osfcontrol(phname, function, value1, value2) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Change file protection and/or owner. Access to the file is by physical name. The argument function defines the operation to be done, value1 is the protection code (!! in octal) or the owner code and value2 is 0 or the actual group identification. .RETURNS Value 0 on normal return. Value -1 in case of error (sys error number is then returned to oserror). .METHOD UIC on VMS is made of (group<<16 + owner) .REMARKS ------------------------------------------------------------*/ char *phname; /* IN : physical filename */ int function; /* IN : function code */ int value1; /* IN : protection or owner code */ int value2; /* IN : 0 or group code */ { oserror = 0; finit(phname); vmserror = SYS$OPEN(fap); /* Open first the file ... */ if (vmserror != RMS$_NORMAL) FINISH; switch (function) { case CHMOD : /* change file protection */ pro->xab$w_pro = u_v(value1); /* Convert Protection Code */ vmserror = SYS$CLOSE(fap); /* and close it ... */ break; case CHOWN : /* change owner and group of the file */ pro->xab$l_uic = value1 + (value2<<16); /* Convert Owner UIC */ vmserror = SYS$CLOSE(fap); /* and close it ... */ break; default: oserror = EINVAL; break; } FIN: if (vmserror != RMS$_NORMAL) oserror = EIO; return(oserror ? -1 : 0); } int osfinfo(phname, status) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Get file status information. Access to the file is by physical name. .RETURNS Value 0 on normal return. (-1 if file does not exist). .REMARKS ------------------------------------------------------------*/ char *phname; /* IN : physical filename */ struct filestatus *status; /* OUT : output file status */ { oserror = 0; finit(phname); fap->fab$b_fac = FAB$M_BRO|FAB$M_GET; fap->fab$b_shr = FAB$M_SHRGET; vmserror = SYS$OPEN(fap); /* Open first the file ... */ if (vmserror != RMS$_NORMAL) FINISH; status->filesize = (fhp->xab$l_ebk-1)*fap->fab$w_bls + fhp->xab$w_ffb; if (status->filesize < 0) status->filesize = 0; status->date = vmstime(&rdt->xab$q_rdt); /* Convert the date/time */ status->owner = pro->xab$l_uic; status->protection = v_u(pro->xab$w_pro); /* Convert Prot. Code */ /* status->blocksize = (fap->fab$w_bls ? fap->fab$w_bls : SECTOR_SIZE); */ vmserror = SYS$CLOSE(fap); /* and close it ... */ FIN: if (vmserror != RMS$_NORMAL) oserror = ENOENT; return(oserror ? -1 : 0); } /*==========================================================================*/ long osfdate(phname) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Get the date of last modification of a file. .RETURNS Date of last modification (-1 if file does not exist). .REMARKS ------------------------------------------------------------*/ char *phname; /* IN : physical filename */ { long date; oserror = 0; finit(phname); fap->fab$b_fac = FAB$M_BRO|FAB$M_GET; fap->fab$b_shr = FAB$M_SHRGET; vmserror = SYS$OPEN(fap); /* Open first the file ... */ if (vmserror != RMS$_NORMAL) FINISH; date = vmstime(&rdt->xab$q_rdt); /* Convert the date/time */ vmserror = SYS$CLOSE(fap); /* and close it ... */ FIN: if (vmserror != RMS$_NORMAL) oserror = ENOENT; return(oserror ? -1 : date); } /*==========================================================================*/ long osfsize(phname) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Get the size of a file. .RETURNS Size of file in bytes (-1 if file does not exist). .REMARKS ------------------------------------------------------------*/ char *phname; /* IN : physical filename */ { long size; oserror = 0; finit(phname); fap->fab$b_fac = FAB$M_BRO|FAB$M_GET; fap->fab$b_shr = FAB$M_SHRGET; vmserror = SYS$OPEN(fap); /* Open first the file ... */ if (vmserror != RMS$_NORMAL) FINISH; size = (fhp->xab$l_ebk-1)*fap->fab$w_bls + fhp->xab$w_ffb; if (size < 0) size = 0; vmserror = SYS$CLOSE(fap); /* and close it ... */ FIN: if (vmserror != RMS$_NORMAL) oserror = ENOENT; return(oserror ? -1 : size); } /*==========================================================================*/ int osfrename(oldname, newname) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Renames a disk file by giving old and new physical names. .RETURNS Value 0 on normal return. (-1 on error. Oserror is then set to the actual error code). .REMARKS ------------------------------------------------------------*/ char *oldname; /* IN : old physical filename */ char *newname; /* IN : new physical filename */ { oserror = 0; finit(oldname); fay = cc$rms_fab; if (newname) /* Add name of file */ { fay.fab$b_fns = strlen(newname);/* sets length of file_name */ fay.fab$l_fna = newname; } vmserror = SYS$RENAME(fap, 0, 0, &fay); FIN: if (vmserror != RMS$_NORMAL) oserror = ENOENT; return(oserror ? -1 : 0); } int osftranslate(logname, phname) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Translate logical names into physical names. i.e. $KEYS ==> myfile.key .METHOD Searches the system variable list for the logname. .RETURNS length of physical name on normal return, -1 when logname does not exist (phname empty). .REMARKS System dependencies: --UNIX: getenv(3). ------------------------------------------------------------*/ char *logname; /* IN : logical name */ char *phname; /* OUT: translated physical filename */ { register int nr; char *getenv(); register char *t, *ptr, cc; /* Do the logical translation */ if ((t = getenv(logname)) == NULL) { *phname = '\0'; return(-1); } ptr = phname; for (nr=0; ; nr++) /* copy phys. filename */ { cc = *t++; if (cc == '\0') { *ptr = '\0'; return (nr); } *ptr++ = cc; } } int osfphname(logname, phname) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Translate logical names into physical names. i.e. $KEYS ==> myfile.key .METHOD Searches the system variable list for the logname. .RETURNS Value 0 on normal return, -1 when logname does not exist (phname empty). .REMARKS System dependencies: --UNIX: getenv(3). ------------------------------------------------------------*/ char *logname; /* IN : logical name */ char *phname; /* OUT: translated physical filename */ { char *getenv(); register char *t1; /* ** Do the logical translation */ if ((t1 = getenv(logname)) == NULL){ *phname = '\0'; return(-1); } strcpy(phname,t1); return(0); }