/* pristines.c:
 *
 * vim:smartindent ts=8:sts=2:sta:et:ai:shiftwidth=2
 ****************************************************************
 * Copyright (C) 2003 Tom Lord
 *
 * See the file "COPYING" for further information about
 * the copyright and warranty status of this work.
 */


#include "hackerlab/bugs/panic.h"
#include "hackerlab/bugs/exception.h"
#include "hackerlab/char/char-class.h"
#include "hackerlab/char/str.h"
#include "hackerlab/fs/file-names.h"
#include "hackerlab/vu/safe.h"
#include "libfsutils/dir-listing.h"
#include "libfsutils/ensure-dir.h"
#include "libfsutils/tmp-files.h"
#include "libfsutils/rmrf.h"
#include "libfsutils/copy-file.h"
#include "libarch/invent.h"
#include "libarch/build-revision.h"
#include "libarch/inode-sig.h"
#include "libarch/namespace.h"
#include "libarch/pristines.h"
#include "libarch/project-tree.h"

static t_uchar * arch_pristine_loc (t_uchar * archive, t_uchar * revision);


void
arch_make_pristine (arch_project_tree_t * tree, t_uchar * archive, t_uchar * revision)
{
  rel_table inventory = 0;
  t_uchar * tmp_pristine = 0;
  t_uchar * version = arch_parse_package_name (arch_ret_package_version, 0, revision);
  t_uchar * fqversion = arch_fully_qualify (archive, version);
  arch_patch_id * patch_id = arch_patch_id_new_archive (archive, revision);
  lim_free (0, version);

  inventory = arch_source_inventory (tree, 1, 0, 0);
  tmp_pristine = talloc_tmp_file_name (talloc_context, tree->root, ",,pristine");
  rmrf_file (tmp_pristine);
  safe_mkdir (tmp_pristine, 0777);
  copy_file_list (tmp_pristine, tree->root, inventory);
  arch_set_tree_version (tmp_pristine, patch_id);

  arch_install_pristine (tree, archive, revision, tmp_pristine);

  rel_free_table (inventory);
  talloc_free (tmp_pristine);
  lim_free (0, fqversion);
  talloc_free (patch_id);
}


void
arch_add_pristine (int chatter_fd, arch_project_tree_t * tree, struct arch_archive * arch, t_uchar * archive, t_uchar * revision)
{
  t_uchar * tmp_path = 0;

  tmp_path = talloc_tmp_file_name (talloc_context, tree->root, ",,new-pristine");
  safe_mkdir (tmp_path, 0777);

  arch_build_revision (tmp_path, arch, archive, revision, tree);
  arch_install_pristine (tree, archive, revision, tmp_path);

  talloc_free (tmp_path);
}


t_uchar *
arch_pristine_loc (t_uchar * archive, t_uchar * revision)
{
  t_uchar * category = 0;
  t_uchar * branch = 0;
  t_uchar * version = 0;
  t_uchar * answer = 0;

  invariant (arch_valid_package_name (revision, arch_no_archive, arch_req_patch_level, 0));
  invariant (arch_valid_archive_name (archive));

  category = arch_parse_package_name (arch_ret_category, 0, revision);
  branch = arch_parse_package_name (arch_ret_package, 0, revision);
  version = arch_parse_package_name (arch_ret_package_version, 0, revision);

  answer = str_alloc_cat_many (0, "{arch}/++pristine-trees/", "unlocked", "/", category, "/", branch, "/", version, "/", archive, "/", revision, str_end);

  lim_free (0, category);
  lim_free (0, branch);
  lim_free (0, version);

  return answer;
}

void
arch_install_pristine (arch_project_tree_t * tree, t_uchar * archive, t_uchar * revision, t_uchar * source)
{
  t_uchar * loc = 0;
  t_uchar * path = 0;
  arch_project_tree_t * source_tree;
  arch_patch_id * patch_id = arch_patch_id_new_archive (archive, revision);

  source_tree = arch_project_tree_new (talloc_context, source);

  arch_snap_inode_sig (source_tree, patch_id);

  loc = arch_pristine_loc (archive, revision);
  path = file_name_in_vicinity (0, tree->root, loc);

  ensure_directory_exists (path);
  rmrf_file (path);
  safe_rename (source, path);

  arch_project_tree_delete (source_tree);
  lim_free (0, loc);
  lim_free (0, path);
  talloc_free (patch_id);
}


rel_table
arch_pristines (t_uchar * tree_root,
                t_uchar * archive_limit,
                t_uchar * limit)
{
  int here_fd;
  int errn;
  struct stat statb;
  t_uchar * category = 0;
  t_uchar * branch = 0;
  t_uchar * version = 0;
  t_uchar * revision = 0;
  t_uchar * unlocked_in_this_tree_path = 0;
  rel_table answer = 0;
  int x;

  here_fd = safe_open (".", O_RDONLY, 0);

  if (archive_limit)
    invariant (arch_valid_archive_name (archive_limit));

  if (limit)
    {
      invariant (arch_valid_package_name (limit, arch_no_archive, arch_req_category, 1));

      category = arch_parse_package_name (arch_ret_category, 0, limit);

      if (arch_valid_package_name (limit, arch_no_archive, arch_req_package, 1))
        {
          branch = arch_parse_package_name (arch_ret_package, 0, limit);

          if (arch_valid_package_name (limit, arch_no_archive, arch_req_version, 1))
            {
              version = arch_parse_package_name (arch_ret_package_version, 0, limit);

              if (arch_valid_package_name (limit, arch_no_archive, arch_req_patch_level, 0))
                {
                  revision = limit;
                }
            }
        }
    }

  unlocked_in_this_tree_path = file_name_in_vicinity (0, tree_root, "{arch}/++pristine-trees/unlocked");

  for (x=0; x!=1; x=1)
    {
      if (vu_chdir (&errn, unlocked_in_this_tree_path))
          continue;

        {
          rel_table maybe_categories = 0;
          int c;

          if (category)
            {
              rel_add_records (&maybe_categories, rel_make_record (category, 0), 0);
            }
          else
            {
              maybe_categories = directory_files (".");
            }


          for (c = 0; c < rel_n_records (maybe_categories); ++c)
            {

              if (arch_valid_package_name (maybe_categories[c][0], arch_no_archive, arch_req_category, 0)
                  && (!vu_lstat (&errn, maybe_categories[c][0], &statb) && S_ISDIR (statb.st_mode)))
                {
                  rel_table maybe_branches = 0;
                  int b;

                  safe_chdir (maybe_categories[c][0]);

                  if (branch)
                    {
                      rel_add_records (&maybe_branches, rel_make_record (branch, 0), 0);
                    }
                  else
                    {
                      maybe_branches = directory_files (".");
                    }

                  for (b = 0; b < rel_n_records (maybe_branches); ++b)
                    {

                      if (arch_valid_package_name (maybe_branches[b][0], arch_no_archive, arch_req_package, 0)
                          && (!vu_lstat (&errn, maybe_branches[b][0], &statb) && S_ISDIR (statb.st_mode)))
                        {
                          rel_table maybe_versions = 0;
                          int v;

                          safe_chdir (maybe_branches[b][0]);

                          if (version)
                            {
                              rel_add_records (&maybe_versions, rel_make_record (version, 0), 0);
                            }
                          else
                            {
                              maybe_versions = directory_files (".");
                            }

                          for (v = 0; v < rel_n_records (maybe_versions); ++v)
                            {
                              if (arch_valid_package_name (maybe_versions[v][0], arch_no_archive, arch_req_version, 0)
                                  && (!vu_lstat (&errn, maybe_versions[v][0], &statb) && S_ISDIR (statb.st_mode)))
                                {
                                  rel_table maybe_archives = 0;
                                  int a;

                                  safe_chdir (maybe_versions[v][0]);

                                  if (archive_limit)
                                    {
                                      rel_add_records (&maybe_archives, rel_make_record (archive_limit, 0), 0);
                                    }
                                  else
                                    {
                                      maybe_archives = directory_files (".");
                                    }

                                  for (a = 0; a < rel_n_records (maybe_archives); ++a)
                                    {
                                      if (arch_valid_archive_name (maybe_archives[a][0]) && (!vu_lstat (&errn, maybe_archives[a][0], &statb) && S_ISDIR (statb.st_mode)))
                                        {
                                          rel_table maybe_revisions = 0;
                                          int r;

                                          safe_chdir (maybe_archives[a][0]);

                                          if (revision)
                                            {
                                              rel_add_records (&maybe_revisions, rel_make_record (revision, 0), 0);
                                            }
                                          else
                                            {
                                              maybe_revisions = directory_files (".");
                                            }

                                          for (r = 0; r < rel_n_records (maybe_revisions); ++r)
                                            {
                                              if (arch_valid_package_name (maybe_revisions[r][0], arch_no_archive, arch_req_patch_level, 0)
                                                  && (!vu_lstat (&errn, maybe_revisions[r][0], &statb) && S_ISDIR (statb.st_mode)))
                                                {
                                                  t_uchar * fqr = 0;

                                                  fqr = arch_fully_qualify (maybe_archives[a][0], maybe_revisions[r][0]);
                                                  rel_add_records (&answer, rel_make_record (fqr, 0), 0);
                                                  lim_free (0, fqr);
                                                }
                                            }

                                          safe_chdir ("..");
                                          rel_free_table (maybe_revisions);
                                        }
                                    }

                                  safe_chdir ("..");
                                  rel_free_table (maybe_archives);
                                }
                            }

                          safe_chdir ("..");
                          rel_free_table (maybe_versions);
                        }
                    }

                  safe_chdir ("..");
                  rel_free_table (maybe_branches);
                }
            }

          safe_fchdir (here_fd);
          rel_free_table (maybe_categories);
        }
    }

  arch_sort_table_by_name_field (0, answer, 0);

  safe_close (here_fd);

  lim_free (0, category);
  lim_free (0, branch);
  lim_free (0, version);
  lim_free (0, revision);
  lim_free (0, unlocked_in_this_tree_path);

  return answer;
}


arch_project_tree_t *
arch_find_pristine (arch_project_tree_t * tree,
                    arch_patch_id * revision,
                    enum arch_pristine_search_scope scope)
{
  const t_uchar * unlocked_pristine_stem = "{arch}/++pristine-trees/unlocked";
  t_uchar * category = 0;
  t_uchar * branch = 0;
  t_uchar * unlocked_relpath = 0;
  t_uchar * unlocked_in_this_tree_path = 0;
  arch_project_tree_t * answer = NULL;

  invariant (arch_valid_package_name (arch_patch_id_patch_id (revision), arch_req_archive, arch_req_patch_level, 0));

  category = arch_parse_package_name (arch_ret_category, 0, arch_patch_id_patch_id (revision));
  branch = arch_parse_package_name (arch_ret_package, 0, arch_patch_id_patch_id (revision));

  unlocked_relpath = str_alloc_cat_many (0, unlocked_pristine_stem, "/", category, "/", branch, "/", arch_patch_id_version (revision), "/", arch_patch_id_patch_id (revision), str_end);

  unlocked_in_this_tree_path = file_name_in_vicinity (0, tree->root, unlocked_relpath);

  if ((scope == arch_tree_pristine_search)
      && !safe_access (unlocked_in_this_tree_path, F_OK))
    {
      answer = arch_project_tree_new_exact (talloc_context, unlocked_in_this_tree_path);
    }
  else
    {
      t_uchar * tree_root_dir = 0;
      rel_table sibling_files = 0;
      rel_table sibling_paths = 0;
      int x;

      if (scope == arch_cache_dir_pristine_search)
        tree_root_dir = str_save (0, tree->root);
      else
        {
          tree_root_dir = file_name_directory_file (0, tree->root);
          if (!tree_root_dir)
            tree_root_dir = str_save (0, ".");
        }
      sibling_files = directory_files (tree_root_dir);

      if (scope != arch_tree_pristine_search)
        {
          for (x = 0; x < rel_n_records (sibling_files); ++x)
            {
              if (char_is_alnum (sibling_files[x][0][0]))
                {
                  int ign;
                  struct stat stat_buf;
                  t_uchar * path = 0;

                  path = file_name_in_vicinity (0, tree_root_dir, sibling_files[x][0]);

                  if (!vu_lstat (&ign, path, &stat_buf) && S_ISDIR (stat_buf.st_mode))
                    {
                      rel_add_records (&sibling_paths, rel_make_record (path, 0), 0);
                    }
                  lim_free (0, path);
                }
            }

          for (x = 0; !answer && (x < rel_n_records (sibling_paths)); ++x)
            {
              t_uchar * unlocked_sibling_path = 0;
              int errno = 0;

              unlocked_sibling_path = file_name_in_vicinity (0, sibling_paths[x][0], unlocked_relpath);

              if (!vu_access (&errno, unlocked_sibling_path, F_OK))
                {
                  answer = arch_project_tree_new_exact (talloc_context, unlocked_sibling_path);
                }

              lim_free (0, unlocked_sibling_path);
            }
        }

      lim_free (0, tree_root_dir);
      rel_free_table (sibling_files);
      rel_free_table (sibling_paths);
    }

  lim_free (0, category);
  lim_free (0, branch);
  lim_free (0, unlocked_relpath);
  lim_free (0, unlocked_in_this_tree_path);


  if (answer)
    {
      if (!arch_valid_inode_sig (answer, arch_patch_id_archive (revision), arch_patch_id_revision (revision)))
	{
	  safe_printfmt (2, "corrupt pristine (failed inode signature validation)\n    revision: %s\n    directory %s\n. Removing this pristine.\n",
			 arch_patch_id_patch_id (revision), answer->root);
	  rmrf_file (answer->root);
	  arch_project_tree_delete (answer);
	  answer = NULL;
	}
    }

  return answer;
}




/* tag: Tom Lord Wed May 21 18:53:22 2003 (pristines.c)
 */


syntax highlighted by Code2HTML, v. 0.9.1