/*===========================================================================
  Copyright (C) 1995-2009 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
.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 a non-negative integer on successful return.
             Otherwise, a value of -1 is set to indicate an error
             condition and the variable ``oserror'' contains the 
             system error code.
             Each file has a host independent logical filename 
             to be handled by the portable directory mechanism.
             Associated to each file there is a status structure with the
             owner, protection flags and dates of creation and modification.
.VERSION 0.0 25-Aug-1986   Definition         J. D. Ponz
.VERSION 2.0 19-Feb-1992   osfinfo uses another filestatus structure. CG.
.VERSION 2.1 29-May-1992   osfcreate set default mask when mode is 0.
.VERSION 2.2 13-Jul-1992   blocksize removed. SCO/PC does not support it. CG.

 090326		last modif
-----------------------------------------------------------*/
 
#include  <stdio.h>
#include  <stdlib.h>		/* Function definitions	*/
#include  <errno.h>
#include  <sys/types.h>
#include  <sys/stat.h>
#include  <fcntl.h>
#include  <string.h>
#include  <osparms.h>
#include  <osfile.h>
#include  <proto_os.h>		/* ANSI-C prototyping */

#define OSFMASK 0666		/* This value is also restricted by umask() */

int osfcreate(phname, nobyt, mode)
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE Creates a new file or rewrites an existing one (no version number ).
         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 mode gives the file protection code.
.RETURNS 0 if all o.k. 
	 on error -1, and the system error code is set
.REMARKS System dependencies:
 --UNIX: creat(2),write(2),close(2)
------------------------------------------------------------*/
char *phname;			/* IN : physical filename */
size_t nobyt;			/* IN : number of bytes to be allocated */
int mode;			/* IN : file mode */

{
int fid;

char c = ' '; 



if ((fid = creat(phname,(mode ? mode:OSFMASK) )) < 0) 
   {				/* create file failed */
   oserror = errno;
   return(-1);
   }

if (nobyt > 0) 
   {			/* position on last byte of the file */
   if (osdseek(fid,(nobyt-1),FILE_START) < 1)
      {
      oserror = errno;
      return(-1);
      }

   if (write(fid,&c,1) != 1) 
      {			/* write last byte */
      (void) close(fid);
      oserror = errno;
      return(-1);
      } 
   }

if (close(fid) < 0) 
   {			/* close file */
   oserror = errno;
   return(-1);
   }

return(1);		/* return number of bytes ( = 1) */
}    


int osfdelete(phname)
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE Deletes file on disk by removing the directory entry corresponding
         to the physical name. The file has to be closed.
.RETURNS Value 0 on normal return, -1 on error and oserror is set.
.REMARKS System dependencies:
 --UNIX: unlink(2)
------------------------------------------------------------*/
char *phname;			/* IN : physical filename */
{ 
	if (unlink(phname) < 0) { 
		oserror = errno;
		return(-1);
		}
	return(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 or the owner
	 code and value2 is free or the actual group identification.
.RETURNS Value 0 on normal return, -1 on error (oserror is set).
.REMARKS System dependencies:
 --UNIX: chmod(2), chown(2)
------------------------------------------------------------*/
char *phname;			/* IN : physical filename */
int function;			/* IN : function code */
int value1;			/* IN : protection or owner code */
int value2;                     /* IN : 0          or group code */
{

	switch (function) {
	case CHMOD:		/* change file protection  */
		if(chmod(phname, value1) < 0) {
			oserror = errno;
			return(-1);
			}
		break;
	case CHOWN:		/* change owner and group of the file */
		if(chown(phname, value1, value2) < 0) {
			oserror = errno;
			return(-1);
			}
		break;
	default:
		oserror = EINVAL;
		return(-1);
	}
	return(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 on error (check oserror).
.REMARKS System dependencies:
 --UNIX: stat(2)
------------------------------------------------------------*/
char *phname;  			/* IN : physical filename */
struct filestatus *status; 	/* OUT : output file status */
{
	struct stat buf;

	/*  
 	** get file status and return it to the structure ``filestatus'' 
	*/
	if (stat(phname,&buf) == -1) {
		oserror = errno;
		return(-1);
		}
	/* 
	** transfer values obtained to structure ``filestatus'' 
	*/
	status->filesize = buf.st_size;
	status->owner = buf.st_uid;
	status->date = buf.st_mtime;
	status->protection = buf.st_mode;
	return(0);
}

int osfmkdir(phname)
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE Create a new directory
.RETURNS Value 0 on normal return, -1 on error (check oserror).
.REMARKS Use system with mkdir
------------------------------------------------------------*/
char *phname;			/* IN : physical directory name */
{
	char *cmd;
  
  cmd = malloc((size_t)(8 + (int)strlen(phname)));
  strcpy(cmd, "mkdir ");
  strcat(cmd, phname);
  oserror = system(cmd);
  free(cmd);
  return(oserror ? -1 : 0);
}

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 (check oserror).
.REMARKS System dependencies:
 --UNIX: link(2), unlink(2)
------------------------------------------------------------*/
char *oldname;			/* IN : old physical filename */
char *newname;			/* IN : new physical filename */

{

unlink(newname);	/* remove newname if exist */

if (link(oldname, newname) < 0) 
   {
   char *cmd;

   cmd = (char *) malloc((size_t)(8 + (int)strlen(oldname) + (int)strlen(newname)));
   strcpy(cmd,"mv -f ");
   strcat(cmd,oldname);
   strcat(cmd," ");
   strcat(cmd,newname);
   oserror = system(cmd);
   free(cmd);
   return(oserror ? -1 : 0);
   }

if(unlink(oldname) < 0) 
   {
   oserror=errno;
   return(-1);
   }

return(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);
}
int osflgname(phname, logname)
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE Physical into logical filename translation.
         The logical filename is a structure consisting of three
         character strings to define the logical path (node, device and 
         directory), the logical name of the file and the type of file. 
.RETURNS Value 0 on normal return, -1 if structure limits are too small. 
.REMARKS System dependencies:
 --UNIX: none
------------------------------------------------------------*/
char *phname;			/* IN : input physical filename */
struct lname *logname;		/* OUT: translated logical name */
{
	char *locph, *sep;
	int len;

#ifdef NO_STRCHR	/* Some pure BSD systems */
#define strrchr rindex
#endif

#ifndef strrchr 	/* On IBM6000 strchr() is a macro */
	extern char *strrchr();
#endif

	locph=phname;
	/*
	** Look for the last occurrence of the separator "/". From the
	** the beginning of the physical name till this separator 
	** is the logical path name.
	*/
	if((sep=strrchr(locph,'/'))!=NULL) {
		if((len=sep-locph)>_LPLEN) {
			oserror = EINVAL; 
			return(-1); 
			}
		strncpy(logname->lpath,locph,len);
		locph += len+1;
		}
	/*
	** Look for the last occurrence of the separator ".". From this
	** separator till the end of the physical name
	** is the file type.
	*/
	if((sep=strrchr(locph,'.'))!=NULL) {
		if((len=strlen(sep+1))>_LTLEN) {
			oserror = EINVAL; 
			return(-1); 
			}
		strncpy(logname->ltype,sep+1,len);
		*sep = '\0';
		}
	/*
	** Between both separators "/" and "." 
	** is the logical file name.
	*/
	if((len=strlen(locph))>_LFLEN) {
		oserror = EINVAL; 
		return(-1); 
		}
	strncpy(logname->lfile,locph,len);
	return(0);
}
