Logo Search packages:      
Sourcecode: tardy version File versions  Download package

tardy.cc

//
//    tardy - a tar post-processor
//    Copyright (C) 1993, 1995, 1996, 1998, 1999, 2001-2004 Peter Miller;
//    All rights reserved.
//
//    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., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
//
// MANIFEST: functions to manipulate tar archives
//

#include <vector>
#include <ac/grp.h>
#include <ac/pwd.h>

#include <error.h>
#include <file/input/normal.h>
#include <file/input/stdin.h>
#include <file/output/buffer.h>
#include <file/output/normal.h>
#include <file/output/stdout.h>
#include <ifmt.h>
#include <ofmt.h>
#include <tar/input/filter/clean.h>
#include <tar/input/filter/group_name.h>
#include <tar/input/filter/group_numbr.h>
#include <tar/input/filter/gunzip.h>
#include <tar/input/filter/mode_clear.h>
#include <tar/input/filter/mode_set.h>
#include <tar/input/filter/now.h>
#include <tar/input/filter/prefix.h>
#include <tar/input/filter/remov_prefi.h>
#include <tar/input/filter/remove_prefix_count.h>
#include <tar/input/filter/suppr_direc.h>
#include <tar/input/filter/user_name.h>
#include <tar/input/filter/user_number.h>
#include <tar/output/list.h>
#include <tar/output/filter/gzip.h>
#include <tardy.h>

using std::vector;

#define NOT_SET (-32767)

static long uid = NOT_SET;
static long gid = NOT_SET;
static int mode_set = NOT_SET;
static int mode_clear = NOT_SET;
static int list;
static char *prefix;
static int no_directories;
static vector<rcstring> remove_prefix_list;
static long remove_prefix_count;
static int clean;
static int now_flag;
static rcstring uname;
static rcstring gname;
static input_opener_ty input_opener;
static output_opener_ty output_opener;
static bool compress_flag;
static bool decompress_flag;
static int blocksize;


void
tardy_user_name_by_string(char *s)
{
    if (uname != "")
      fatal("duplicate -User_NAme option");
    uname = s;
}


void
tardy_user_name_by_number(long n)
{
    if (uname != "")
      fatal("duplicate -User_NAme option");
    if (n < 0 || n >= (1L << 16))
      fatal("uid %ld out of range", n);
    struct passwd *pw = getpwuid(n);
    if (!pw)
      fatal("uid %ld unknown", n);
    uname = pw->pw_name;
}


void
tardy_user_number_by_string(char *s)
{
    if (uid != NOT_SET)
      fatal("duplicate -User_NUmber option");
    struct passwd *pw = getpwnam(s);
    if (!pw)
      fatal("user \"%s\" unknown", s);
    uid = pw->pw_uid;
}


void
tardy_user_number_by_number(long n)
{
    if (n < 0 || n >= (1L << 16))
      fatal("user number %ld out of range", n);
    if (uid != NOT_SET)
      fatal("duplicate -User_NUmber option");
    uid = n;
}


void
tardy_group_number_by_string(char *s)
{
    if (gid != NOT_SET)
      fatal("duplicate -Group_NUmber option");
    struct group *gr = getgrnam(s);
    if (!gr)
      fatal("group \"%s\" unknown", s);
    gid = gr->gr_gid;
}


void
tardy_group_name_by_string(char *s)
{
    if (gname != "")
      fatal("duplicate -Group_NAme option");
    gname = s;
}


void
tardy_group_name_by_number(long n)
{
    if (gname != "")
      fatal("duplicate -Group_NAme option");
    if (n < 0 || n >= (1L << 16))
      fatal("gid %ld out of range", n);
    struct group *gr = getgrgid(n);
    if (!gr)
      fatal("gid %ld unknown", n);
    gname = gr->gr_name;
}


void
tardy_group_number_by_number(long n)
{
    if (n < 0 || n >= (1L << 16))
      fatal("group number %ld out of range", n);
    if (gid != NOT_SET)
      fatal("duplicate -Group_NUmber option");
    gid = n;
}


void
tardy_no_fix_type(void)
{
    tardy_format_output("tar-v7");
}


void
tardy_format_input(const char *name)
{
    if (input_opener)
      fatal("duplicate -Input_ForMaT option");
    input_opener = input_opener_by_name(name);
}


void
tardy_format_output(const char *name)
{
    if (output_opener)
      fatal("duplicate -Output_ForMaT option");
    output_opener = output_opener_by_name(name);
}


void
tardy(char *ifn, char *ofn)
{
    //
    // open the input file
    //
    file_input *ifpx =
      (
          ifn ?
          (file_input *)new file_input_normal(ifn) :
          (file_input *)new file_input_stdin()
      );
    if (!input_opener)
      input_opener = input_opener_by_name("tar");
    tar_input *ifp = input_opener(ifpx);

    if (decompress_flag)
      ifp = new tar_input_filter_gunzip(ifp);

    //
    // open the output file
    //
    file_output *ofpx =
      (
          ofn ?
          (file_output *)new file_output_normal(ofn) :
          (file_output *)new file_output_stdout()
      );
    if (!output_opener)
      output_opener = output_opener_by_name("ustar");
    ofpx = new file_output_buffer(ofpx, blocksize);
    tar_output *ofp = output_opener(ofpx);
    ofp->set_block_size(blocksize);

    if (compress_flag)
      ofp = new tar_output_filter_gzip(ofp);

    //
    // Filter the input, if requested.
    //
    if (no_directories)
      ifp = new tar_input_filter_suppress_directories(ifp);
    if (uid != NOT_SET)
      ifp = new tar_input_filter_user_number(ifp, uid);
    if (uname != "")
      ifp = new tar_input_filter_user_name(ifp, uname);
    if (gid != NOT_SET)
      ifp = new tar_input_filter_group_number(ifp, gid);
    if (gname != "")
      ifp = new tar_input_filter_group_name(ifp, gname);
    if (mode_set != NOT_SET)
      ifp = new tar_input_filter_mode_set(ifp, mode_set);
    if (mode_clear != NOT_SET)
      ifp = new tar_input_filter_mode_clear(ifp, mode_clear);
    if (remove_prefix_count > 0)
      ifp = new tar_input_filter_remove_prefix_count(ifp, remove_prefix_count);
    for
    (
      vector<rcstring>::iterator it = remove_prefix_list.begin();
      it != remove_prefix_list.end();
      ++it
    )
      ifp = new tar_input_filter_remove_prefix(ifp, *it);
    if (prefix)
      ifp = new tar_input_filter_prefix(ifp, prefix);
    if (clean)
      ifp = new tar_input_filter_clean(ifp, clean);
    if (now_flag)
      ifp = new tar_input_filter_now(ifp);

    //
    // Filter the output, if requested.
    //
    if (list)
      ofp = new tar_output_list(ofp);

    //
    // Allocate a large chunk of memory to play with.
    //
    long buffer_size = 1L << 16;
    char *buffer = new char[buffer_size];

    ofp->write_archive_begin();
    for (;;)
    {
      tar_header h;
      if (!ifp->read_header(h))
          break;
      ifp->read_header_padding();
      ofp->write_header(h);
      ofp->write_header_padding();
      
      int nbytes = 0;
      while (nbytes < h.size)
      {
          long chunk_max = h.size - nbytes;
          if (chunk_max > buffer_size)
            chunk_max = buffer_size;
          int chunk = ifp->read_data(buffer, chunk_max);
          if (chunk == 0)
            ifp->fatal("premature end of file");
          ofp->write_data(buffer, chunk);
          nbytes += chunk;
      }
      ifp->read_data_padding();
      ofp->write_data_padding();
    }
    ofp->write_archive_end();

    delete buffer;
    delete ifp;
    delete ofp;
}


void
tardy_prefix(char *s)
{
    if (prefix)
      fatal("duplicate -Prefix option");
    prefix = s;
}


void
tardy_remove_prefix(char *s)
{
    remove_prefix_list.push_back(rcstring(s));
}


void
tardy_remove_prefix(long n)
{
    remove_prefix_count = n;
}


void
tardy_mode_set(int n)
{
    if (mode_set != NOT_SET)
      fatal("duplicate -Mode_Set option");
    mode_set = (n & 0777);
}


void
tardy_mode_clear(int n)
{
    if (mode_clear != NOT_SET)
      fatal("duplicate -Mode_Clear option");
    mode_clear = (n & 07777);
}


void
tardy_list()
{
    if (list)
      fatal("duplicate -List option");
    list = 1;
}


void
tardy_now()
{
    if (now_flag)
      fatal("duplicate -Now option");
    now_flag = 1;
}


void
tardy_no_directories()
{
    if (no_directories)
      fatal("duplicate -No_Directories option");
    no_directories = 1;
}


void
tardy_clean_space()
{
    if (clean & tar_input_filter_clean::flag_space)
      fatal("duplicate -Clean_Space option");
    clean |= tar_input_filter_clean::flag_space;
}


void
tardy_clean_print()
{
    if (clean & tar_input_filter_clean::flag_print)
      fatal("duplicate -Clean_Print option");
    clean |= tar_input_filter_clean::flag_print;
}


void
tardy_clean_meta()
{
    if (clean & tar_input_filter_clean::flag_shell)
      fatal("duplicate -Clean_Meta option");
    clean |= tar_input_filter_clean::flag_shell;
}


static void
check_case(void)
{
    if
    (
      (clean & tar_input_filter_clean::flag_up)
    &&
      (clean & tar_input_filter_clean::flag_down)
    )
      fatal("the -DownCase and -UpCase options are mutually exclusive");
}


void
tardy_downcase()
{
    if (clean & tar_input_filter_clean::flag_down)
      fatal("duplicate -DownCase option");
    clean |= tar_input_filter_clean::flag_down;
    check_case();
}


void
tardy_upcase()
{
    if (clean & tar_input_filter_clean::flag_up)
      fatal("duplicate -UpCase option");
    clean |= tar_input_filter_clean::flag_up;
    check_case();
}


void
tardy_gzip()
{
    compress_flag = true;
}


void
tardy_gunzip()
{
    decompress_flag = true;
}


void
tardy_blocksize(int n)
{
    blocksize = (n > 0 ? (n << 9) : 0);
}

Generated by  Doxygen 1.6.0   Back to index