/*
		                  LCRZO
                             Network library
             Copyright(c) 1999,2000,2001,2002 Laurent Constantin
                                  -----

  Main server    : http://www.laurentconstantin.com/
  Backup servers : http://go.to/laurentconstantin/
                   http://laurentconstantin.est-la.com/
                   http://laurentconstantin.free.fr/
                   http://lauconstantin.multimania.com/
  [my current email address is on the web servers]

                                  -----
  This file is part of Lcrzo.

  Lcrzo is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  Lcrzo 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
  Lesser General Public License for more details (http://www.gnu.org).

------------------------------------------------------------------------
*/

/* -- Note about comments and variable names --
   In versions 1.00 up to 2.08, lcrzo was only written in French (my
   mother tongue). Since version 3.00, lcrzo is written in English, but
   most of comments and variable names are still in French.
   In future versions, I'll try to translate everything into English,
   but as you may guess, that's a quite big work...
   So, for the moment, here are some word translation, if you want to
   be able to understand what's going on in the functions :
     afficher - print     ;  ajouter - add         ;  copie - copy
     dernier - last       ;  donnee - data         ;  ecrire - write
     entete - header      ;  envoye - sent         ;  ferme - close
     fichier - file       ;  lire - read           ;  masque - mask 
     nboct - byte number  ;  ouvre, ouvrir - open  ;  paq, paquet - packet
     plage - range        ;  premier - first       ;  recu - received
     reseau - network     ;  retour - return       ;  taille - size
     tunnel - pipe

*/

#include "lcrzo_incl.h"

/*-------------------------------------------------------------*/
void lcrzo_priv_stat_print(struct stat st);
void lcrzo_priv_stat_print(struct stat st)
{ lcrzo_uint32_print("dev=", st.st_dev, "%u", " ");
  lcrzo_uint32_print("ino=", st.st_ino, "%u", " ");
  lcrzo_uint32_print("mode=", st.st_mode, "%u", " ");
  lcrzo_uint32_print("nlink=", st.st_nlink, "%u", " ");
  lcrzo_uint32_print("uid=", st.st_uid, "%u", " ");
  lcrzo_uint32_print("gid=", st.st_gid, "%u", " ");
  lcrzo_uint32_print("size=", st.st_size, "%u", "\n");
}

/*-------------------------------------------------------------*/
#include "sysdep/lcrzo_priv_filename_stat_get.c"

/*-------------------------------------------------------------*/
#include "sysdep/lcrzo_priv_fd_stat_get.c"

/*-------------------------------------------------------------*/
#include "sysdep/lcrzo_priv_stat_forbidschange.c"

/*-------------------------------------------------------------*/
#include "sysdep/lcrzo_priv_stat_forbidslink.c"

/*-------------------------------------------------------------*/
#include "sysdep/lcrzo_priv_stat_forbidsnotreg.c"

/*-------------------------------------------------------------*/
#include "sysdep/lcrzo_priv_stat_type.c"

/*-------------------------------------------------------------*/
int lcrzo_priv_stat_size(struct stat st, 
			 lcrzo_int32 *psize);
int lcrzo_priv_stat_size(struct stat st, 
			 lcrzo_int32 *psize)
{
  if (st.st_size>0x7FFFFFFF)
    return(LCRZO_ERR_SPFILE2G);

  /*set the correct value*/
  if (psize!=NULL)
  { *psize=(lcrzo_int32)st.st_size;
  }  
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
#include "sysdep/lcrzo_priv_wait_file_wait.c"

/*-------------------------------------------------------------*/
#include "sysdep/lcrzo_priv_wait_file_read.c"

/*-------------------------------------------------------------*/
int lcrzo_priv_dir_eventually_create_parent(const char *dirname);
int lcrzo_priv_dir_eventually_create_parent(const char *dirname)
{ int ret;
  lcrzo_string parent;
  lcrzo_bool yes;

  /* check if parent directory exists. Otherwise, create it */
  ret=lcrzo_filename_parentdir(dirname, &parent);
  if ( ret==LCRZO_ERR_OK )
  { ret=lcrzo_dir_exist(parent, &yes);
    if ( ret==LCRZO_ERR_OK && !yes )
    { ret=lcrzo_dir_create(parent); 
    }
    lcrzo_string_free(parent);
  }
 
  return(ret);
}

/*-------------------------------------------------------------*/
#if ! defined O_BINARY
 /* should only be useful on Windows, so set 0 if not defined */
 #define O_BINARY 0
#endif

/*-------------------------------------------------------------*/
int lcrzo_file_open_read(const char *filename,
			    lcrzo_file *pfile)
{ int ret, fd;
  struct stat st1, st2;

  /*parameters verification*/
  if (filename==NULL) return(LCRZO_ERR_PANULLPTR);

  /*before opening, we verify if the file seems OK*/
  lcrzo_er(lcrzo_priv_filename_stat_get(filename, &st1));
  lcrzo_er(lcrzo_priv_stat_forbidslink(st1));
  lcrzo_er(lcrzo_priv_stat_forbidsnotreg(st1));

  /*open*/
  fd=LAURENT_open(filename, O_RDONLY | O_BINARY);
  if (fd==-1) return(LCRZO_ERR_FUOPEN);

  /*verify if the characteristics are the same*/
  lcrzo_efr(lcrzo_priv_fd_stat_get(fd, &st2), LAURENT_close(fd));
  lcrzo_efr(lcrzo_priv_stat_forbidschange(st1, st2), LAURENT_close(fd));

  /*eventually close the file descriptor*/
  if (pfile==NULL)
  { ret=LAURENT_close(fd);
    if ( ret == -1 ) return(LCRZO_ERR_FUCLOSE);
  }
  else
  { pfile->fd=fd;
    pfile->canclosefd=LCRZO_TRUE;
    pfile->openforreading=LCRZO_TRUE;
    pfile->openforwriting=LCRZO_FALSE;
    pfile->dataend=LCRZO_FALSE;
    pfile->storeddata=NULL;
    pfile->storeddatasize=0;
  }

  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
#include "sysdep/lcrzo_file_open_write.c"

/*-------------------------------------------------------------*/
int lcrzo_file_open_append(const char *filename,
			 lcrzo_bool mustbeanexistentfile,
			 lcrzo_file *pfile)
{ int ret, fd;
  lcrzo_int16 language;
  struct stat st1, st2;
  lcrzo_bool fileexists;

  /*parameters verification*/
  if (filename==NULL) return(LCRZO_ERR_PANULLPTR);
  lcrzo_bool_verifbof(mustbeanexistentfile);

  /*before opening, we verify if the file seems OK*/
  ret=lcrzo_priv_filename_stat_get(filename, &st1);
  if (ret!=LCRZO_ERR_OK)
  { /*unknown error*/
    if (errno!=ENOENT) return(ret);
    errno=0;
    fileexists=0;
  }
  else
  { fileexists=1;
    lcrzo_er(lcrzo_priv_stat_forbidslink(st1));
    lcrzo_er(lcrzo_priv_stat_forbidsnotreg(st1));
  }

  /*error cases*/
  if ( mustbeanexistentfile && !fileexists )
  { lcrzo_er(lcrzo_global_get_language(&language));
    if (language==LCRZO_GLOBAL_LANG_FR)
    { lcrzo_er(lcrzo_priv_global_set_errmsglcrzo("Fichier existant voulu, mais il n'existe pas"));
    }
    else
    { lcrzo_er(lcrzo_priv_global_set_errmsglcrzo("We want an existent file, but file doesn't exists"));
    }
    return(LCRZO_ERR_SPFILESECURITY);
  }
  
  /*open*/
  if (fileexists)
  { fd=LAURENT_open(filename, O_WRONLY|O_APPEND|O_BINARY);
    if (fd==-1) return(LCRZO_ERR_FUOPEN);
    /*verify if the characteristics are the same*/
    lcrzo_efr(lcrzo_priv_fd_stat_get(fd, &st2), LAURENT_close(fd));
    lcrzo_efr(lcrzo_priv_stat_forbidschange(st1, st2), LAURENT_close(fd));
  }
  else
  { fd=LAURENT_open3(filename, O_WRONLY|O_CREAT|O_EXCL|O_BINARY, 0600);
    if (fd==-1) return(LCRZO_ERR_FUOPEN);
  }

  /*eventually close the file descriptor*/
  if (pfile==NULL)
  { ret=LAURENT_close(fd);
    if ( ret == -1 ) return(LCRZO_ERR_FUCLOSE);
  }
  else
  { pfile->fd=fd;
    pfile->canclosefd=LCRZO_TRUE;
    pfile->openforreading=LCRZO_FALSE;
    pfile->openforwriting=LCRZO_TRUE;
    pfile->dataend=LCRZO_FALSE;
    pfile->storeddata=NULL;
    pfile->storeddatasize=0;
  }

  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_file_close(lcrzo_file *pfile)
{ int ret;

  if (pfile==NULL) return(LCRZO_ERR_OK);

  /* eventually close the file descriptor */
  if (pfile->canclosefd)
  { ret=LAURENT_close(pfile->fd);
    if ( ret == -1 ) return(LCRZO_ERR_FUCLOSE);
    pfile->canclosefd=LCRZO_FALSE;
  }

  /* file can not be used */
  pfile->dataend=LCRZO_TRUE;
  pfile->openforreading=LCRZO_FALSE;
  pfile->openforwriting=LCRZO_FALSE;
  
  /* free data */
  if (pfile->storeddata==NULL && pfile->storeddatasize) return(LCRZO_ERR_PANULLPTRSIZE);
  if (pfile->storeddatasize)
  { lcrzo_er(lcrzo_data_free(pfile->storeddata));
    pfile->storeddata=NULL;
    pfile->storeddatasize=0;
  }
 
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_fd_close(int fd)
{ int ret;

  ret=LAURENT_close(fd);
  if ( ret == -1 ) return(LCRZO_ERR_FUCLOSE);

  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_stream_close(LCRZOFILE *pstream)
{ int ret;

  ret=fclose(pstream);
  if ( ret == -1 ) return(LCRZO_ERR_FUFCLOSE);

  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_file_init_fd(int fd,
                       lcrzo_file *pfile)
{
  if (pfile!=NULL)
  { pfile->fd=fd;
    pfile->canclosefd=LCRZO_FALSE;
    pfile->openforreading=LCRZO_TRUE;
    pfile->openforwriting=LCRZO_TRUE;
    pfile->dataend=LCRZO_FALSE;
    pfile->storeddata=NULL;
    pfile->storeddatasize=0;
  }

  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_file_init_stream(LCRZOFILE *pstream,
                           lcrzo_file *pfile)
{
  if (pfile!=NULL)
  { pfile->fd=LAURENT_fileno((FILE *)pstream);
    pfile->canclosefd=LCRZO_FALSE;
    pfile->openforreading=LCRZO_TRUE;
    pfile->openforwriting=LCRZO_TRUE;
    pfile->dataend=LCRZO_FALSE;
    pfile->storeddata=NULL;
    pfile->storeddatasize=0;
  }

  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_fd_init_file(lcrzo_file *pfile, 
                       int *pfd)
{
  /* parameter verification */
  if (pfile==NULL) return(LCRZO_ERR_PANULLPTR);

  if (pfd!=NULL)
  { *pfd=pfile->fd;
    pfile->canclosefd=LCRZO_FALSE; /* because it must be externally closed */
  }
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_stream_init_file(lcrzo_file *pfile, 
                           LCRZOFILE **ppstream)
{
  /* parameter verification */
  if (pfile==NULL) return(LCRZO_ERR_PANULLPTR);

  if (ppstream!=NULL)
  { if ( pfile->openforreading && !pfile->openforwriting )
    { *ppstream=LAURENT_fdopen(pfile->fd, "rb");
    }
    else if ( !pfile->openforreading && pfile->openforwriting )
    { *ppstream=LAURENT_fdopen(pfile->fd, "wb");
    }
    else
    { /* don't know so try both */
      *ppstream=LAURENT_fdopen(pfile->fd, "r+wb");
      if (*ppstream==NULL)
      { *ppstream=LAURENT_fdopen(pfile->fd, "rb");
      }
      if (*ppstream==NULL)
      { *ppstream=LAURENT_fdopen(pfile->fd, "wb");
      }
    }
    if (*ppstream==NULL) return(LCRZO_ERR_FUFDOPEN);
    pfile->canclosefd=LCRZO_FALSE; /* because it must be externally closed */
  }
  return(LCRZO_ERR_OK);
}


/*-------------------------------------------------------------*/
int lcrzo_file_write(lcrzo_file *pfile,
		   lcrzo_constdata data,
		   lcrzo_int32 datasize)
{ 
  /*parameters verification*/
  if (pfile==NULL) return(LCRZO_ERR_PANULLPTR);

  if (!pfile->openforwriting) return(LCRZO_ERR_LONOTOPENFORWRITING);

  lcrzo_er(lcrzo_priv_fd_write(pfile->fd, data, datasize));

  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_file_write_msg(lcrzo_file *pfile,
		       lcrzo_constdata data,
		       lcrzo_int32 datasize)
{   
  /*parameters verification*/
  if (pfile==NULL) return(LCRZO_ERR_PANULLPTR);

  if (!pfile->openforwriting) return(LCRZO_ERR_LONOTOPENFORWRITING);

  lcrzo_er(lcrzo_priv_fd_write_msg(pfile->fd, data, datasize));
  
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_file_readm(lcrzo_file *pfile,
		   lcrzo_time *pmaxwaitingtime, 
		   lcrzo_data *pdataout,
		   lcrzo_int32 *pdataoutsize)
{ lcrzo_wait waitread;
  lcrzo_bool mayread;

  /* parameter verification */
  if (pfile==NULL) return(LCRZO_ERR_PANULLPTR);

  lcrzo_er(lcrzo_wait_init_file_read(pfile, &waitread));
  lcrzo_er(lcrzo_wait_wait1(&waitread, pmaxwaitingtime, &mayread));
  lcrzo_er(lcrzo_wait_close(&waitread));
  if (!mayread) return(LCRZO_ERR_OKTEMPDATAEND);

  /* exit with data */
  lcrzo_er(lcrzo_priv_storeddata_extract(&(pfile->storeddata), &(pfile->storeddatasize),
                                         pfile->dataend, pdataout, pdataoutsize));

  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_file_readm_fixed(lcrzo_file *pfile,
		   lcrzo_time *pmaxwaitingtime, 
			 lcrzo_int32 datasizetoread,
			 lcrzo_data *pdataout)
{ lcrzo_wait waitread;
  lcrzo_bool mayread;

  /* parameter verification */
  if (pfile==NULL) return(LCRZO_ERR_PANULLPTR);

  lcrzo_er(lcrzo_wait_init_file_read_fixed(pfile, datasizetoread, &waitread));
  lcrzo_er(lcrzo_wait_wait1(&waitread, pmaxwaitingtime, &mayread));
  lcrzo_er(lcrzo_wait_close(&waitread));
  if (!mayread) return(LCRZO_ERR_OKTEMPDATAEND);

  /* exit with data */
  lcrzo_er(lcrzo_priv_storeddata_extract_fixed(&(pfile->storeddata), 
					       &(pfile->storeddatasize),
                                               pfile->dataend, datasizetoread,
					       pdataout));

  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_file_readm_line(lcrzo_file *pfile,
		   lcrzo_time *pmaxwaitingtime, 
			lcrzo_data *pdataout,
			lcrzo_int32 *pdataoutsize)
{ lcrzo_wait waitread;
  lcrzo_bool mayread;

  /* parameter verification */
  if (pfile==NULL) return(LCRZO_ERR_PANULLPTR);

  lcrzo_er(lcrzo_wait_init_file_read_line(pfile, &waitread));
  lcrzo_er(lcrzo_wait_wait1(&waitread, pmaxwaitingtime, &mayread));
  lcrzo_er(lcrzo_wait_close(&waitread));
  if (!mayread) return(LCRZO_ERR_OKTEMPDATAEND);
 
  /* exit with data */
  lcrzo_er(lcrzo_priv_storeddata_extract_line(&(pfile->storeddata),
					      &(pfile->storeddatasize),
                                              pfile->dataend, pdataout,
					      pdataoutsize));

  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_filename_type(const char *filename, 
			lcrzo_int16 *ptype)
{ struct stat st;

  /*get the stat*/
  lcrzo_er(lcrzo_priv_filename_stat_get(filename, &st));
  lcrzo_er(lcrzo_priv_stat_type(st, ptype));
 
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_file_type(lcrzo_file *pfile, 
		    lcrzo_int16 *ptype)
{ struct stat st;

  /*get the stat*/
  if (pfile==NULL) return(LCRZO_ERR_PANULLPTR);
  lcrzo_er(lcrzo_priv_fd_stat_get(pfile->fd, &st));
  lcrzo_er(lcrzo_priv_stat_type(st, ptype));
  
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
#include "sysdep/lcrzo_file_flush.c"

/*-------------------------------------------------------------*/
int lcrzo_file_offset_set(lcrzo_file *pfile, 
			lcrzo_int32 offset)
{ int ret;

  if (offset<0) return(LCRZO_ERR_PATOOLOW);
  if (pfile==NULL) return(LCRZO_ERR_PANULLPTR);

  ret=LAURENT_lseek(pfile->fd, offset, SEEK_SET);
  if (ret<0) return(LCRZO_ERR_FULSEEK);
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_file_offset_get(lcrzo_file *pfile, 
			  lcrzo_int32 *poffset)
{ lcrzo_intmax off;

  if (pfile==NULL) return(LCRZO_ERR_PANULLPTR);

  off=LAURENT_lseek(pfile->fd, 0, SEEK_CUR);
  if (off==-1) return(LCRZO_ERR_FULSEEK);
  if (off>0x7FFFFFFF) return(LCRZO_ERR_SPFILE2G);

  if (poffset!=NULL) *poffset=(lcrzo_int32)off;
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_filename_size(const char *filename, 
		    lcrzo_int32 *psize)
{ struct stat st;

  /*get the stat*/
  lcrzo_er(lcrzo_priv_filename_stat_get(filename, &st));
  lcrzo_er(lcrzo_priv_stat_size(st, psize));
  
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_file_size(lcrzo_file *pfile, 
		  lcrzo_int32 *psize)
{ struct stat st;

  if (pfile==NULL) return(LCRZO_ERR_PANULLPTR);

  /*get the stat*/
  lcrzo_er(lcrzo_priv_fd_stat_get(pfile->fd, &st));
  lcrzo_er(lcrzo_priv_stat_size(st, psize));
  
  return(LCRZO_ERR_OK);
}


/*-------------------------------------------------------------*/
int lcrzo_filename_exist(const char *filename,
		     lcrzo_bool *pyes)
{ int ret;
  struct stat st;
  lcrzo_bool fileexists;

  fileexists=LCRZO_FALSE;
  ret=lcrzo_priv_filename_stat_get(filename, &st);
  if (ret==LCRZO_ERR_OK)
  { fileexists=LCRZO_TRUE;
  }
  else if ( ret==LCRZO_ERR_OKFILENOTFOUND)
  { fileexists=LCRZO_FALSE;
  }
  else
  { return(ret);
  }
  lcrzo_err_purge();

  if (pyes!=NULL)
  { *pyes=fileexists;
  }

  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_filename_create(const char *filename)
{ return(lcrzo_file_open_write(filename, LCRZO_FALSE, LCRZO_TRUE, NULL));
}

/*-------------------------------------------------------------*/
int lcrzo_filename_remove(const char *filename)
{ int ret;
  struct stat st1;

  /*parameters verification*/
  if (filename==NULL) return(LCRZO_ERR_PANULLPTR);

  /*before removing, we verify if the file seems OK*/
  lcrzo_er(lcrzo_priv_filename_stat_get(filename, &st1));
  lcrzo_er(lcrzo_priv_stat_forbidslink(st1));
  lcrzo_er(lcrzo_priv_stat_forbidsnotreg(st1));

  /* unlink the file */
  ret=LAURENT_unlink(filename);
  if ( ret == -1 ) return(LCRZO_ERR_FUUNLINK);
  
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_filename_rename(const char *oldfilename, 
		      const char *newfilename)
{ lcrzo_er(lcrzo_filename_copy(oldfilename, newfilename));
  return(lcrzo_filename_remove(oldfilename));
}

/*-------------------------------------------------------------*/
int lcrzo_filename_copy(const char *oldfilename, 
		    const char *newfilename)
{ int ret;
  lcrzo_file filein, fileout;
  lcrzo_data data;
  lcrzo_int32 datasize;

  /*open files*/
  lcrzo_er(lcrzo_file_open_read(oldfilename, &filein));
  lcrzo_efr(lcrzo_file_open_write(newfilename, LCRZO_FALSE, LCRZO_TRUE, &fileout),
	    lcrzo_file_close(&filein));

  while(LCRZO_TRUE)
  { ret=lcrzo_file_readm(&filein, LCRZO_WAIT_INFINITE, &data, &datasize);
    if (ret==LCRZO_ERR_OKDATAEND)
    { break;
    }
    else if (ret==LCRZO_ERR_OK)
    { lcrzo_efr(lcrzo_file_write(&fileout, data, datasize), 
		lcrzo_file_close(&filein);lcrzo_file_close(&fileout));
      lcrzo_data_free(data);
    }
    else
    { lcrzo_file_close(&filein);lcrzo_file_close(&fileout); return(ret);
    }
  }
  lcrzo_file_close(&filein);
  lcrzo_file_close(&fileout);

  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_file_copy(lcrzo_file *pfile, 
		  const char *newfilename)
{ int ret;
  lcrzo_file fileout;
  lcrzo_data data;
  lcrzo_int32 datasize;

  /*open files*/
  lcrzo_er(lcrzo_file_offset_set(pfile, 0));
  lcrzo_er(lcrzo_file_open_write(newfilename, LCRZO_FALSE, LCRZO_TRUE, &fileout));

  while(LCRZO_TRUE)
  { ret=lcrzo_file_readm(pfile, LCRZO_WAIT_INFINITE, &data, &datasize);
    if (ret==LCRZO_ERR_OKDATAEND)
    { break;
    }
    else if (ret==LCRZO_ERR_OK)
    { lcrzo_efr(lcrzo_file_write(&fileout, data, datasize), lcrzo_file_close(&fileout));
      lcrzo_data_free(data);
    }
    else
    { lcrzo_file_close(&fileout); return(ret);
    }
  }
  lcrzo_er(lcrzo_file_close(&fileout));

  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
#include "sysdep/lcrzo_filename_truncate.c"

/*-------------------------------------------------------------*/
#include "sysdep/lcrzo_file_truncate.c"

/*-------------------------------------------------------------*/
int lcrzo_filename_read(const char *filename,
		    lcrzo_data *pdata,
		    lcrzo_int32 *pdatasize)
{ int ret;
  lcrzo_file file;
  lcrzo_data data, tmpdata;
  lcrzo_int32 datasize, tmpdatasize;

  /* to check if size < 2G */
  lcrzo_er(lcrzo_filename_size(filename, NULL));

  datasize=0;
  lcrzo_er(lcrzo_data_alloc(datasize, &data));

  /*open file*/
  lcrzo_er(lcrzo_file_open_read(filename, &file));

  while(LCRZO_TRUE)
  { ret=lcrzo_file_readm(&file, LCRZO_WAIT_INFINITE, &tmpdata, &tmpdatasize);
    if (ret==LCRZO_ERR_OKDATAEND)
    { break;
    }
    else if (ret==LCRZO_ERR_OK)
    { ret=lcrzo_data_appendm_data(tmpdata, tmpdatasize,
				  datasize, &data, &datasize);
      lcrzo_data_free(tmpdata);
      if (ret!=LCRZO_ERR_OK) 
      { lcrzo_file_close(&file);
        lcrzo_data_free(data);
        return(ret);
      }
    }
    else
    { lcrzo_file_close(&file);
      lcrzo_data_free(data);
      return(ret);
    }
  }
  lcrzo_er(lcrzo_file_close(&file));

  if (pdatasize!=NULL) *pdatasize=datasize;
  if (pdata!=NULL)
  { *pdata=data; 
  }
  else
  { lcrzo_data_free(data);
  }
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_filename_write(const char *filename,
		     lcrzo_bool mustbeanexistentfile,
		     lcrzo_bool mustbeanewfile,
		     lcrzo_constdata data,
		     lcrzo_int32 datasize)
{ int ret, ret2;
  lcrzo_file file;
  
  /*open file*/
  lcrzo_er(lcrzo_file_open_write(filename, mustbeanexistentfile, 
				 mustbeanewfile,
				 &file));
  ret=lcrzo_file_write(&file, data, datasize);
  ret2=lcrzo_file_close(&file);
  if ( ret==LCRZO_ERR_OK && ret2!=LCRZO_ERR_OK) return(ret2); 
  return(ret);
}

/*-------------------------------------------------------------*/
int lcrzo_filename_append(const char *filename,
			  lcrzo_bool mustbeanexistentfile,
			  lcrzo_constdata data,
			  lcrzo_int32 datasize)
{ int ret, ret2;
  lcrzo_file file;

  /*open file*/
  lcrzo_er(lcrzo_file_open_append(filename, mustbeanexistentfile, &file));
  ret=lcrzo_file_write(&file, data, datasize);
  ret2=lcrzo_file_close(&file);
  if ( ret==LCRZO_ERR_OK && ret2!=LCRZO_ERR_OK) return(ret2); 
  return(ret);
}

/*-------------------------------------------------------------*/
int lcrzo_priv_dirname_removelastslash(lcrzo_conststring indirname,
				       lcrzo_string *poutdirname);
int lcrzo_priv_dirname_removelastslash(lcrzo_conststring indirname,
				       lcrzo_string *poutdirname)
{ 
  lcrzo_er(lcrzo_filename_clean(indirname, poutdirname));

  if (poutdirname!=NULL)
  { if ( strlen(*poutdirname)>1 && 
		 (*poutdirname)[strlen(*poutdirname)-1]=='/' )
  { (*poutdirname)[strlen(*poutdirname)-1]='\0';
  }
  }
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
#include "sysdep/lcrzo_dir_exist.c"

/*-------------------------------------------------------------*/
#include "sysdep/lcrzo_dir_create.c"

/*-------------------------------------------------------------*/
int lcrzo_dir_remove(const char *dirname)
{ int ret;
  lcrzo_string cleandirname;

  lcrzo_er(lcrzo_priv_dirname_removelastslash(dirname, &cleandirname));
  ret=LAURENT_rmdir(cleandirname);
  lcrzo_string_free(cleandirname);
  if (ret==-1)
  { if (errno==ENOENT) return(LCRZO_ERR_OKFILENOTFOUND); 
    return(LCRZO_ERR_FURMDIR);
  }
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_dir_rename(const char *olddirname, 
		     const char *newdirname)
{ int ret, err;
  lcrzo_string cleanolddirname, cleannewdirname;

  err=0;
  ret=lcrzo_priv_dirname_removelastslash(olddirname, &cleanolddirname);
  if ( ret==LCRZO_ERR_OK )
  { ret=lcrzo_priv_dirname_removelastslash(newdirname, &cleannewdirname);
    if ( ret==LCRZO_ERR_OK )
    { err=rename(cleanolddirname, cleannewdirname);
      lcrzo_string_free(cleannewdirname);
    }
    lcrzo_string_free(cleanolddirname);
  }
  if ( ret!=LCRZO_ERR_OK ) return(ret);
  
  if (err==-1)
  { if (errno==ENOENT) return(LCRZO_ERR_OKFILENOTFOUND); 
    return(LCRZO_ERR_FURENAME);
  }

  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
#include "sysdep/lcrzo_dir_count.c"

/*-------------------------------------------------------------*/
#include "sysdep/lcrzo_dir_value_pos.c"

/*-------------------------------------------------------------*/
int lcrzo_filename_clean(lcrzo_conststring filename,
			 lcrzo_string *pcleanedfilename)
{ lcrzo_string tmp, root; 
  lcrzo_uint8 c, c_1;
  lcrzo_bool lastcharwasslash;
  int i, j, size, lastdirsize;
  char *pc;

  /* return empty filenames */
  if (strlen(filename)==0)
  { lcrzo_er(lcrzo_string_initm_text("", pcleanedfilename));
    return(LCRZO_ERR_OK);
  }

  /* eventually add "./", or replace "x:\"by"/", or replace "\\comp\"by"/" */
  if (filename[0]=='/')
  { lcrzo_er(lcrzo_string_initm_text("/", &root));
    lcrzo_er(lcrzo_string_initm_text(filename, &tmp));
  }
  else
  { /* search "x:\" */
    if ( strlen(filename)>=3 && isalpha((int)filename[0]) && 
	 filename[1]==':' && filename[2]=='\\' )
    { lcrzo_er(lcrzo_string_initm_data((lcrzo_constdata)filename, 3, &root));
      root[3]='\0';
      lcrzo_er(lcrzo_string_initm_text(filename+2, &tmp)); /* \ will be replaced by / */
    }
    /* search "x:" */
    else if ( strlen(filename)>=2 && isalpha((int)filename[0]) && 
	      filename[1]==':' )
    { lcrzo_er(lcrzo_string_initm_data((lcrzo_constdata)filename, 2, &root));
      root[2]='\0';
      lcrzo_er(lcrzo_string_initm_text("./", &tmp));
      lcrzo_er(lcrzo_string_appendm_text(filename+2, &tmp));
    }
    /* search "\\comp\" */
    else if ( strlen(filename)>=2 && filename[0]=='\\' && 
	      filename[1]=='\\' )
    { pc=strchr(filename+2, '\\');
      if (pc==NULL) pc=strchr(filename+2, '/');
      if (pc==NULL)
      { /* file is only "\\comp", so there is nothing to clean */
        lcrzo_er(lcrzo_string_initm_text(filename, pcleanedfilename));
        return(LCRZO_ERR_OK);
      }
      size=(pc-filename);
      lcrzo_er(lcrzo_string_initm_data((lcrzo_constdata)filename, size, &root));
      root[size]='\0';
      lcrzo_er(lcrzo_string_appendm_text("\\", &root));
      lcrzo_er(lcrzo_string_initm_text(pc, &tmp)); /* \ will be replaced by / */
    }
    /* search "\rep" */
    else if ( strlen(filename)>=1 && filename[0]=='\\' )
    { lcrzo_er(lcrzo_string_initm_text("/", &root));
      lcrzo_er(lcrzo_string_initm_text(filename, &tmp)); /* \ will be replaced by / */
    }
    else
    { /* add "./" */
      lcrzo_er(lcrzo_string_initm_text("", &root));
      lcrzo_er(lcrzo_string_initm_text("./", &tmp));
      lcrzo_er(lcrzo_string_appendm_text(filename, &tmp));
    }
  }
  /*printf("==%s ==%s\n", root, tmp);*/

  /* convert "\" to "/" */
  size=strlen(tmp);
  for ( i=0 ; i<size ; i++ )
  { if ( tmp[i]=='\\' ) 
      tmp[i]='/';
  }

  /* convert "/.$" to "/" */
  size=strlen(tmp);
  if (size>=2)
  { if ( tmp[size-2]=='/' && tmp[size-1]=='.' )
    { tmp[size-1]='\0';
    }
  }

  /* convert "/..$" to "/../" */
  size=strlen(tmp);
  if (size>=3)
  { if ( tmp[size-3]=='/' && tmp[size-2]=='.' && tmp[size-1]=='.' )
    { lcrzo_er(lcrzo_string_appendm_char('/', 1, &tmp));
    }
  }

  /* convert "/./" to "//" */
  size=strlen(tmp);
  i=0;
  j=0;
  for ( ; i<size-2 ; i++ )
  { c=tmp[i];
    tmp[j++]=c;
    if ( c=='/' && tmp[i+1]=='.' && tmp[i+2]=='/' )
    { i++;
    }
  }
  if (i<size-1) tmp[j++]=tmp[i++];
  if (i<size) tmp[j++]=tmp[i];
  tmp[j]='\0';

  /* convert "//" to "/" */
  size=strlen(tmp);
  j=0;
  c_1='_';
  for ( i=0 ; i<size ; i++ )
  { c=tmp[i];
    if ( ! ( c_1=='/' && c=='/' ) ) 
    { tmp[j++]=c;
    }
    c_1=c;
  }
  tmp[j]='\0';

  /* convert /aa/bb/../ to /aa/ */
  size=strlen(tmp);
  i=0;
  j=0;
  lastcharwasslash=LCRZO_TRUE;
  for ( ; i<size-2 ; i++ )
  { c=tmp[i];
    if ( lastcharwasslash && c=='.' && tmp[i+1]=='.' && tmp[i+2]=='/' )
    { /* go back to the last '/' */
      if (j>0)
      { c_1=tmp[j-1]; tmp[j-1]='\0'; /* just for strrchr*/
        pc=strrchr(tmp, '/');
        tmp[j-1]=c_1;
      }
      else
	pc=NULL;
      if ( pc==NULL )
      { /* no '/' found */
        if ( tmp[0]=='/' )
	{ /* can not have /.. because / is root */
          lcrzo_string_free(tmp);
          return(LCRZO_ERR_SPPATHROOTDOTDOT);
	}
        else
	{ /* start with ./../, so add ../ */
          tmp[j++]='.'; tmp[j++]='.'; tmp[j++]='/';
	}
      }
      else
      { /* './' found */
        c_1=tmp[j-1]; tmp[j-1]='\0'; /* just for strlen*/
        lastdirsize=strlen(tmp)-(pc-tmp);
        tmp[j-1]=c_1;
        if ( lastdirsize==3 && pc[1]=='.' && pc[2]=='.' )
	{ /* tmp actually end with /../ (between the found character (pc)
             and the strlen of tmp */
          tmp[j++]='.'; tmp[j++]='.'; tmp[j++]='/';
	}
	else
	{ /* go back to the last '/' */
          j=pc-tmp+1;
	}
      }
      i+=2; /* we skip two characters */
      lastcharwasslash=LCRZO_TRUE;
    }
    else
    { tmp[j++]=c;
      lastcharwasslash=(lcrzo_bool)((c=='/') ? LCRZO_TRUE : LCRZO_FALSE);
    }
  }
  if (i<size-1) tmp[j++]=tmp[i++];
  if (i<size) tmp[j++]=tmp[i];
  tmp[j]='\0';

  /* set output value */
  /*printf("==%s ==%s\n", root, tmp);*/
  if (pcleanedfilename!=NULL)
  { if ( tmp[0]=='/' )
    { lcrzo_er(lcrzo_string_initm_text(root, pcleanedfilename));
      lcrzo_er(lcrzo_string_appendm_text(tmp+1, pcleanedfilename));
    }
    else
    { lcrzo_er(lcrzo_string_initm_text(root, pcleanedfilename));
      if ( strlen(root) || !strncmp(tmp, "./../", 5) )
      { /* because tmp always start with "./" */
        lcrzo_er(lcrzo_string_appendm_text(tmp+2, pcleanedfilename));
      }
      else
      { lcrzo_er(lcrzo_string_appendm_text(tmp, pcleanedfilename));
      }
    }
  }
  lcrzo_er(lcrzo_string_free(root));
  lcrzo_er(lcrzo_string_free(tmp));
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_filename_parentdir(lcrzo_conststring filename,
			     lcrzo_string *pparentdir)
{ lcrzo_string tmp;

  /* special case for empty filenames */
  if (strlen(filename)==0)
  { lcrzo_er(lcrzo_string_initm_text("./", pparentdir));
    return(LCRZO_ERR_OK);
  }

  lcrzo_er(lcrzo_string_initm_text(filename, &tmp));
  lcrzo_er(lcrzo_string_appendm_text("/../", &tmp));
  lcrzo_er(lcrzo_filename_clean(tmp, pparentdir));
  lcrzo_er(lcrzo_string_free(tmp));
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_filename_lastfile(lcrzo_conststring filename,
			    lcrzo_string *plastfile)
{ lcrzo_string tmp;
  char *pc;
  int size, ret;

  lcrzo_er(lcrzo_filename_clean(filename, &tmp));
  /* special case of root : try to go up */
  ret=lcrzo_filename_parentdir(tmp, NULL);
  if (ret==LCRZO_ERR_SPPATHROOTDOTDOT)
  { lcrzo_er(lcrzo_string_initm_text(tmp, plastfile));
    lcrzo_er(lcrzo_string_free(tmp));
    return(LCRZO_ERR_OK);
  }
  else if (ret!=LCRZO_ERR_OK)
  { return(ret);
  }

  /* suppress the ending '/' */
  size=strlen(tmp);
  if ( size>0 )
  { if ( tmp[size-1]=='/' )
    { tmp[size-1]='\0';
    }
  }

  /* find the last '/' */
  pc=strrchr(tmp, '/');
  if (pc==NULL) pc=strrchr(tmp, '\\');
  if (pc==NULL)
  { lcrzo_er(lcrzo_string_initm_text(tmp, plastfile));
  }
  else
  { lcrzo_er(lcrzo_string_initm_text(pc+1, plastfile));
  }
  lcrzo_er(lcrzo_string_free(tmp));
  return(LCRZO_ERR_OK);
}

