/* copy-file.c:
 *
 ****************************************************************
 * Copyright (C) 2003 Tom Lord
 *
 * See the file "COPYING" for further information about
 * the copyright and warranty status of this work.
 */


#include "hackerlab/fs/file-names.h"
#include "hackerlab/vu/safe.h"
#include "tla/libfsutils/link-target.h"
#include "tla/libfsutils/ensure-dir.h"
#include "tla/libfsutils/copy-file.h"



void
copy_fd (int in_fd, int out_fd)
{
  static t_uchar buf[8192];
  long amt;

  while (1)
    {
      amt = safe_read_retry (in_fd, buf, sizeof (buf));
      if (!amt)
        break;
      safe_write_retry (out_fd, buf, amt);
    }
}

void
copy_file (const char * from, const char * to)
{
  int in_fd;
  int out_fd;

  in_fd = safe_open (from, O_RDONLY, 0);
  out_fd = safe_open (to, O_WRONLY | O_EXCL | O_CREAT, 0666);

  copy_fd (in_fd, out_fd);

  safe_close (in_fd);
  safe_close (out_fd);
}

void
copy_symlink (const char * from, const char * to)
{
  t_uchar * target;

  target = link_target (from);
  safe_symlink (target, to);
  lim_free (0, target);
}

void
copy_file_or_symlink (const char * from, const char * to)
{
  struct stat stat_buf;

  safe_lstat (from, &stat_buf);
  if (S_ISLNK (stat_buf.st_mode))
    copy_symlink (from, to);
  else
    copy_file (from, to);
}

void
copy_permissions (const char * from,
                  const char * to,
                  int full_meta)
{
  struct stat from_stat_buf;
  struct stat to_stat_buf;
  mode_t mode;

  safe_lstat (from, &from_stat_buf);
  safe_lstat (to, &to_stat_buf);

  if (full_meta)
    {
      mode = from_stat_buf.st_mode & 07777;
    }
  else
    {
      mode = from_stat_buf.st_mode & 0777;
    }

  if (!S_ISLNK (from_stat_buf.st_mode) && !S_ISLNK (to_stat_buf.st_mode))
    {
      safe_chmod (to, mode);
      if (full_meta)
        safe_chown (to, from_stat_buf.st_uid, from_stat_buf.st_gid);
    }
}

void
copy_file_list (const t_uchar * dest_dir,
                const t_uchar * src_dir,
                rel_table index,
                int full_meta)
{
  int x;

  for (x = 0; x < rel_n_records (index); ++x)
    {
      t_uchar * src_path = 0;
      t_uchar * dest_path = 0;
      t_uchar * dest_path_dir = 0;
      struct stat stat_buf;
      mode_t src_mode;

      src_path = file_name_in_vicinity (0, src_dir, rel_peek_str (index, x, 0));
      dest_path = file_name_in_vicinity (0, dest_dir, rel_peek_str (index, x, 0));
      dest_path_dir = file_name_directory_file (0, dest_path);

      ensure_directory_exists (dest_path_dir);
      safe_lstat (src_path, &stat_buf);

      if (full_meta)
        {
          src_mode = stat_buf.st_mode & 07777;
        }
      else
        {
          src_mode = stat_buf.st_mode & 0777;
        }

      if (S_ISLNK (stat_buf.st_mode))
        {
          copy_symlink (src_path, dest_path);
        }
      else if (S_ISDIR (stat_buf.st_mode))
        {
          ensure_directory_exists (dest_path);
          safe_chmod (dest_path, src_mode);
          if (full_meta)
            safe_chown (dest_path, stat_buf.st_uid, stat_buf.st_gid);
        }
      else
        {
          int in_fd;
          int out_fd;

          in_fd = safe_open (src_path, O_RDONLY, 0);
          out_fd = safe_open (dest_path, O_WRONLY | O_EXCL | O_CREAT, src_mode);
          safe_fchmod (out_fd, src_mode);
          if (full_meta)
            safe_fchown (out_fd, stat_buf.st_uid, stat_buf.st_gid);

          copy_fd (in_fd, out_fd);

          safe_close (in_fd);
          safe_close (out_fd);
        }

      lim_free (0, src_path);
      lim_free (0, dest_path);
      lim_free (0, dest_path_dir);
    }
}

/* tag: Tom Lord Wed May 14 18:34:05 2003 (copy-file.c)
 */
