/* @(#)osd.c 17.1.1.1 (ES0-DMD) 01/25/02 17:35:07 */ /*=========================================================================== 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 Massachusetss Ave, Cambridge, MA 02139, USA. Corresponding 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 osd .LANGUAGE C .AUTHOR IPG-ESO Garching .CATEGORY Host operating system interfaces. Data file i/o. .COMMENTS Handling of data files. These routines access data in binary format. Data files are accessed via direct i/o in a synchronous way. Files are referenced by the physical filename in the open function. A file identifier is returned by this function to be used in later i/o operations. Associated to each file there is a pointer to locate the current file position. 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. On read on end of file, the value of -1 is also returned. .VERSION 0.0 25-Aug-1986 Definition J.D. Ponz .VERSION 1.0 28-Nov-1986 Programmation B. Pirenne .VERSION 1.1 14-Apr-1987 Upgrade performance B. Pirenne .VERSION 1.2 15-Jul-1987 Include asynchronous file access B. Pirenne .VERSION 1.3 07-Dec-1987 Upgrade performance and compact the code I. Suisalu .VERSION 1.4 31-May-1988 Cosmetic changes. C. Guirao. .VERSION 1.5 04-Oct-1988 osdopen creates the file if non-existant. .VERSION 1.6 21-Jun-1989 O_TRUNC added at open in WRITE mode. and open (path, flags, -1) now. .VERSION 1.7 07-Nov-1989 Simplified osdopen .VERSION 1.8 05-Feb-1990 Default creat mode is 0644 (no executre right) .VERSION 1.9 14-Mar-1990 Removed bug is osdread (set errno to 0) .VERSION 1.10 19-Dec-1990 Not checking FNAME_LEN any more CG. .VERSION 1.11 21-Oct-1991 fsync() removed. Not portable. CG. .VERSION 2.1 29-May-1992 open creates the file with default umask 0666.CG .VERSION 3.1 09-Mar-1994 Decompressing in the fly. CG. ------------------------------------------------------------*/ /* * Define _POSIX_SOURCE to indicate * that this is a POSIX program */ #define _POSIX_SOURCE 1 #include /* ANSI-C prototyping */ #include #include #include #include #include #include #include #include #include #ifdef FASTMEM_SET #include #endif #define MAX_TABLE_ENTRY 20 static struct DECOMPRESS { int entry; int longest_suffix; char *suffix[MAX_TABLE_ENTRY+2]; char *command[MAX_TABLE_ENTRY+2]; } decompress = { 2, 2, {".Z",".z"}, {"zcat","gunzip -c"}, }; static int decomp_table_read = 0; static FILE *file_ptr[_NFILE_]; extern FILE *popen(); /* Not defined in of OSF/1 */ #ifdef O_TRUNC #define O_write (O_WRONLY | O_TRUNC | O_CREAT) #else #define O_write (O_WRONLY | O_CREAT) #endif #define OSDMASK 0666 static int readn(fd, ptr, nbytes) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Read "n" bytest from a descriptor. Use in place of read() when fd is a stream socket .RETURNS If succesful, the number of bytes actaully read is returned. Otherwise, a -1 is returned. .REMARKS System dependencies: -- UNIX: read(2) ------------------------------------------------------------*/ register int fd; register char *ptr; register int nbytes; { int nleft, nread; nleft = nbytes; while (nleft > 0) { nread = read(fd, ptr, nleft); if (nread < 0) /* error, return < 0 */ return(nread); else if (nread == 0) /* EOF */ break; nleft -= nread; ptr += nread; } return(nbytes - nleft); /* return >= 0 */ } /* * read_decomp_table() " reads the file containing this table from the * environment $DECOMPRESS_TABLE, otherwise uses $MID_INCLUDE/decompress.dat * * The syntax of this file must be followed strictly: * - Only '#' as the first character makes a line in comments. * - Separators are blanks or tabs. * - Suffixes are in the first column and without quotes. * - Commands are in the second column. Double quotes are required if the * command contains blanks. * - Commands can contain the character '*' that represents the file to be * decompressed. NOTE: only the first '*' is expanded. * - Any thing after the second column is ignored. * - Incomplete entries are ignored (i.g. only the suffix) * - Only the first MAX_TABLE_ENTRY (20) entries are read, the rest is ignored. */ static int read_decomp_table() { char *getenv(); static char *decomp_table_file = NULL; FILE *fd, *fopen(); int i, suffix_length; char *q, *mid_include; char buf[100], suffix[8], command[80]; /* check if DECOMPRESS_TABLE environment is defined */ if ((decomp_table_file = getenv("DECOMPRESS_TABLE")) == NULL) { if ((mid_include = getenv("MID_INCLUDE")) == NULL) { /* Using the built-in table */ /* printf("No DECOMPRESS_TABLE or MID_INCLUDE definition\n");*/ return; } decomp_table_file = malloc(strlen(mid_include)+strlen("/decompress.dat")+1); strcpy(decomp_table_file,mid_include); strcat(decomp_table_file,"/decompress.dat"); } if ((fd = fopen (decomp_table_file, "r")) == NULL) { /* Using the built-in table */ /* printf("Cannot open DECOMPRESS_TABLE %s\n",decomp_table_file);*/ return; } /* reads the contents of decompressed table file */ while (fgets(buf, sizeof(buf), fd) != NULL && decompress.entry < MAX_TABLE_ENTRY) { if (buf[0] == '#') continue; for (q = buf; *q && ((*q == ' ') || (*q == '\t')); q++) ; for (i=0; (*q != '\n') && (*q != ' ') && (*q != '\t'); q++) suffix[i++] = *q; if (i) suffix[i]='\0'; else continue; for (; *q && ((*q == ' ') || (*q == '\t')); q++) ; if ( *q == '"' ) { q++; for (i=0; (*q != '\n') && (*q != '"'); q++) command[i++] = *q; } else { for (i=0; (*q != '\n') && (*q != ' ') && (*q != '\t'); q++) command[i++] = *q; } if (i) command[i]='\0'; else continue; suffix_length = strlen(suffix); decompress.suffix[decompress.entry] = malloc(suffix_length+1); decompress.command[decompress.entry] = malloc(strlen(command)+1); strcpy(decompress.suffix[decompress.entry],suffix); strcpy(decompress.command[decompress.entry],command); if ( suffix_length > decompress.longest_suffix) decompress.longest_suffix = suffix_length; decompress.entry++; } } static int match_preffix(phname) char *phname; { int i; int n_suffix; for (i=decompress.entry-1; i >= 0 ; i--) { n_suffix=strlen(decompress.suffix[i]); if (!strcmp(&phname[strlen(phname)-n_suffix],decompress.suffix[i])) return(i); } return(-1); } static int match_compressed_file(phname,comp_phname) char *phname; char **comp_phname; { struct stat buf; int i; *comp_phname = malloc(strlen(phname)+decompress.longest_suffix+1); for (i=decompress.entry-1; i >= 0; i--) { strcpy(*comp_phname,phname); strcat(*comp_phname,decompress.suffix[i]); if (stat(*comp_phname,&buf) == 0 && S_ISREG(buf.st_mode)) return(i); } free(*comp_phname); return(-1); } static char *get_command(phname,match) char *phname; int match; { char *command; char *ptr_to_star; command = calloc(strlen(decompress.command[match]) + strlen(phname) + 2,1); if ((ptr_to_star = strchr(decompress.command[match],'*')) == NULL) { strcpy(command,decompress.command[match]); strcat(command," "); strcat(command,phname); } else { strncpy(command,decompress.command[match],(int)(ptr_to_star-decompress.command[match])); ptr_to_star++; strcat(command,phname); strcat(command,ptr_to_star); } return(command); } int osdopen(phname, mode) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Open EXISTING binary data file for read or write. The variable mode defines the way of opening the file as : READ, WRITE, READ_WRITE and APPEND. The file pointer is set to the beginning of the file. .RETURNS Upon successful completion a positive number with the .RETURNS file identification is returned. (-1 otherwise). .REMARKS System dependencies: -- UNIX: open(2) ------------------------------------------------------------*/ char *phname; /* physical filename */ int mode; /* open mode */ { int fid, t; int myerrno; int match; FILE *fpin; char *command; char *compressed_file; switch (mode&3) { case READ: /* open for read only */ t = O_RDONLY; /* * Read the decompression table first */ if (!decomp_table_read) { decomp_table_read++; read_decomp_table(); } /* * Check if filename contains a suffix */ if ((match=match_preffix(phname)) != -1) command=get_command(phname,match); /* * Otherwise try to open filename */ else if((fid = open(phname,t,OSDMASK)) > 0) return(fid); /* * Otherwise try to find filename + suffix */ else { myerrno = errno; if ((match=match_compressed_file(phname,&compressed_file)) != -1) { command=get_command(compressed_file,match); free(compressed_file); } /* * Otherwise return the error returned by open(phname) */ else { oserror = myerrno; return(-1); } } /* * Open decompress command as a pipe */ printf("%s\n", command); if ( (fpin = popen(command, "r")) == NULL) { free(command); oserror = errno; return(-1); } free(command); fid = fileno(fpin); if (fid >= _NFILE_) { oserror = EINVAL; return(-2); } file_ptr[fid] = fpin; return(fid); break; case WRITE: /* open for write only */ t = O_write; break; case READ_WRITE: /* open for read-write */ t = O_RDWR; break; case APPEND: /* open for append */ t = O_APPEND | O_WRONLY; break; } if((fid = open(phname,t,OSDMASK)) == -1) oserror = errno; return(fid); } int osdclose(fid) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Closes data file. The argument fid is the file identification obtained from osdopen. .RETURNS Value 0 on normal return. (-1 otherwise). .REMARKS System dependencies: -- UNIX: close(2) ------------------------------------------------------------*/ int fid; /* file identification */ { FILE *fd; if (fid < 3 ){ /* This should be impossible. fid should not be stdin, stdout, stderr */ return (-1); } if ( fid >= _NFILE_ || ((fd = file_ptr[fid]) == NULL)) { if (close(fid) == -1) { oserror = errno; return(-1); } } else { file_ptr[fid] = NULL; if (pclose(fd) == -1) { oserror = errno; return(-1); } } return(0); } int osdread(fid, pbuf, nobyt) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Synchronous read from a data file. The argument fid is the file identification obtained from osdopen. osdread reads nobyt bytes from the current file position and stores the information into the buffer pointed by pbuf. On devices capable of seeking, the read starts at the position of the file pointer associated with fid. Upon return the pointer is incremented by the number of bytes actually read. .RETURNS Number of bytes actually read. (-1 in case of failure or end of file). .REMARKS System dependencies: -- UNIX: read(2) ------------------------------------------------------------*/ int fid; /* file identification */ char *pbuf; /* pointer to input buffer */ unsigned nobyt; /* number of input bytes */ { int i; errno = 0; /* MUST BE INITIALIZED... */ if ((i = readn(fid, pbuf, nobyt)) <= 0) { oserror = errno; return(-1); } return(i); } int osdwrite(fid, pbuf, nobyt) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Synchronous write into a data file. The argument fid is the file identification obtained from osdopen. osdwrite writes nobyt bytes from the buffer pointed by pbuf. On devices capable of seeking, the write starts at the position of the file pointer associated with fid. Upon return the pointer is incremented by the number of bytes actually written. .RETURNS Number of characters actually written. (-1 in case of failure). .REMARKS System dependencies: -- UNIX: write(2) ------------------------------------------------------------*/ int fid; /* file identification */ char *pbuf; /* pointer to output buffer */ unsigned nobyt; /* number of output bytes */ { int i; if ((i = write(fid, pbuf, nobyt)) == -1) oserror = errno; return(i); } long osdseek(fid, address, mode) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE moves the file pointer. The argument fid is the file identification obtained from osdopen. The address defines the pointer position in bytes relative to: start of the file, current position or end of the file as defined by the variable mode (FILE_START, FILE_CURRENT, FILE_END). (see midas/osparms.h). (i.e. : an address=0 and OS_START set means first byte of the file). .RETURNS Upon successful completion, the resulting pointer position .RETURNS measured in bytes is returned, in case of error -1L. .REMARKS System dependencies: -- UNIX: lseek(2) ------------------------------------------------------------*/ int fid; /* file identification */ long address; /* file pointer */ int mode; /* mode of addressing */ { off_t ret; if ((ret = lseek(fid, (off_t)address, mode)) == (off_t)-1) oserror = errno; return((long)ret); } int osdputs(fid, pbuf) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Synchronous write to a file a string of characters followed by a newline (end of record). The argument fid is the file identification obtained from osdopen. .RETURNS Number of characters actually written. -1 for error (oserror provides an explanation) .REMARKS ------------------------------------------------------------*/ int fid; /* IN : file identifier */ char *pbuf; /* IN : EOS-terminated string to write */ { register char *p; register int i; i = strlen(pbuf); p = pbuf + i++; *p = '\n'; if ( (i = osdwrite(fid, pbuf, i)) == -1) oserror = errno; *p = '\0'; return(i); } int osdwait(/*fid*/) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Waits for asynchronous input/output to be completed. The argument fid is the file identification obtained from osdopen. If the process is waiting for input/output operation, the execution of the process is suspended until the transfer is complete. !!! NOT IMPLEMENTED : RETURNS ALWAYS 0 !!! .RETURNS The function returns 0 for success, and -1 if any error was detected. .REMARKS System dependencies: -- UNIX: sync(2) ------------------------------------------------------------*/ /*int fid;*/ /* file identification */ { return(0); }