/*

  silcfileutil.c

  Author: Pekka Riikonen <priikone@silcnet.org>

  Copyright (C) 1997 - 2003 Pekka Riikonen

  The contents of this file are subject to one of the Licenses specified 
  in the COPYING file;  You may not use this file except in compliance 
  with the License.

  The software distributed under the License is distributed on an "AS IS"
  basis, in the hope that it will be useful, but WITHOUT WARRANTY OF ANY
  KIND, either expressed or implied.  See the COPYING file for more
  information.

*/
/* $Id: silcfileutil.c,v 1.4.2.3 2003/11/09 15:37:47 priikone Exp $ */

#include "silcincludes.h"

/* Opens a file indicated by the filename `filename' with flags indicated
   by the `flags'. */

int silc_file_open(const char *filename, int flags)
{
  int fd = open(filename, flags, 0600);
  return fd;
}

/* Opens a file indicated by the filename `filename' with flags indicated
   by the `flags', and with the specified `mode'. */

int silc_file_open_mode(const char *filename, int flags, int mode)
{
  int fd = open(filename, flags, mode);
  return fd;
}

/* Reads data from file descriptor `fd' to `buf'. */

int silc_file_read(int fd, unsigned char *buf, SilcUInt32 buf_len)
{
  return read(fd, (void *)buf, buf_len);
}

/* Writes `buffer' of length of `len' to file descriptor `fd'. */

int silc_file_write(int fd, const char *buffer, SilcUInt32 len)
{
  return write(fd, (const void *)buffer, len);
}

/* Closes file descriptor */

int silc_file_close(int fd)
{
  return close(fd);
}

/* Writes a buffer to the file. */

int silc_file_writefile(const char *filename, const char *buffer,
			SilcUInt32 len)
{
  int fd;
  int flags = O_CREAT | O_WRONLY | O_TRUNC;

#if defined(O_BINARY)
  flags |= O_BINARY;
#endif /* O_BINARY */

  if ((fd = open(filename, flags, 0644)) == -1) {
    SILC_LOG_ERROR(("Cannot open file %s for writing: %s", filename,
		    strerror(errno)));
    return -1;
  }

  if (silc_file_write(fd, buffer, len) == -1) {
    SILC_LOG_ERROR(("Cannot write to file %s: %s", filename, strerror(errno)));
    silc_file_close(fd);
    return -1;
  }

  silc_file_close(fd);

  return 0;
}

/* Writes a buffer to the file.  If the file is created specific mode is
   set to the file. */

int silc_file_writefile_mode(const char *filename, const char *buffer,
			     SilcUInt32 len, int mode)
{
  int fd;
  int flags = O_CREAT | O_WRONLY | O_TRUNC;

#if defined(O_BINARY)
  flags |= O_BINARY;
#endif /* O_BINARY */

  if ((fd = open(filename, flags, mode)) == -1) {
    SILC_LOG_ERROR(("Cannot open file %s for writing: %s", filename,
		    strerror(errno)));
    return -1;
  }

  if ((silc_file_write(fd, buffer, len)) == -1) {
    SILC_LOG_ERROR(("Cannot write to file %s: %s", filename, strerror(errno)));
    silc_file_close(fd);
    return -1;
  }

  silc_file_close(fd);

  return 0;
}

/* Reads a file to a buffer. The allocated buffer is returned. Length of
   the file read is returned to the return_len argument. */

char *silc_file_readfile(const char *filename, SilcUInt32 *return_len)
{
  int fd;
  char *buffer;
  int filelen;

  fd = silc_file_open(filename, O_RDONLY);
  if (fd < 0) {
    if (errno == ENOENT)
      return NULL;
    SILC_LOG_ERROR(("Cannot open file %s: %s", filename, strerror(errno)));
    return NULL;
  }

  filelen = lseek(fd, (off_t)0L, SEEK_END);
  if (filelen < 0) {
    silc_file_close(fd);
    return NULL;
  }
  if (lseek(fd, (off_t)0L, SEEK_SET) < 0) {
    silc_file_close(fd);
    return NULL;
  }

  if (filelen < 0) {
    SILC_LOG_ERROR(("Cannot open file %s: %s", filename, strerror(errno)));
    silc_file_close(fd);
    return NULL;
  }

  buffer = silc_calloc(filelen + 1, sizeof(char));

  if ((silc_file_read(fd, buffer, filelen)) == -1) {
    memset(buffer, 0, sizeof(buffer));
    silc_file_close(fd);
    SILC_LOG_ERROR(("Cannot read from file %s: %s", filename,
                    strerror(errno)));
    return NULL;
  }

  silc_file_close(fd);
  buffer[filelen] = EOF;

  if (return_len)
    *return_len = filelen;

  return buffer;
}

/* Returns the size of `filename'. Returns 0 on error. */

SilcUInt64 silc_file_size(const char *filename)
{
  int ret;
  struct stat stats;

#ifndef SILC_WIN32
  ret = lstat(filename, &stats);
#else
  ret = stat(filename, &stats);
#endif
  if (ret < 0)
    return 0;

  return (SilcUInt64)stats.st_size;
}
