Deprecated: The each() function is deprecated. This message will be suppressed on further calls in /home/zhenxiangba/zhenxiangba.com/public_html/phproxy-improved-master/index.php on line 456
/*
* esplit -- enhanced split
* (tarアーカイブを分割、出力をパイプに)
*
* revision history:
* 0.0: Dec. 23, 2006 by Dai ISHIJIMA (as psplit.c)
* 0.1: Jun. 3, 2007 (as nsplit.c)
* 0.2: Jun. 10, 2007 (as esplit.c)
*
* usage:
* esplit -bytes -d# -c# -o file/pipe
*
* options:
* -bytes 分割するバイト数を指定
* -o 出力 出力先を指定。'|' で始まる場合はパイプに食わす
* -d# 出力先の '%' が数字#桁に
* -c# 出力先の '%' がアルファベット#桁に
* -t tar形式を無視 (tarアーカイブのファイル境界で分割しない)
*
* example:
* % tar cf - . | gzip --fast | esplit -512m -c2 -o 'hoge.%.tgz'
* カレントディレクトリをtarで固めて圧縮して512Mバイト単位に分割
* (tar cf - . | gzip --fast | split -b 512m - とほぼ等価)
*
* % tar cf - . | esplit -512m -d3 -o '| gzip --fast > hoge.%.tgz'
* カレントディレクトリをtarで固めて、512Mバイト単位に分割して
* 圧縮する
*
* split(1)コマンドは、ファイルを一定のサイズに分割することはできます。
* しかし、分割後のデータをパイプに食わしたりすることはできません。
* また、tarアーカイブの構造を認識して、ファイル境界で分割することも
* できません。このプログラムは、出力をパイプに食わしたり、アーカイブ
* の構造を認識して、適当な位置でファイルを分割することができます。
*
* [1]% tar cf - . | gzip --fast | split -b 100k - foo.tgz.
*
* とすると、カレントディレクトリをtarで固めて圧縮し、foo.tgz.aa,...
* というファイルに分割することができます。しかし、分割されたアーカイブ
* が壊れてしまった場合などは、そのアーカイブ以降のデータを復元できません。
*
* [2]% tar cf - . | esplit -100k -c2 -o '| gzip --fast > foo.tgz.%'
*
* とすると、分割されたアーカイブを個別に扱うことができます。つまり、
* [1] で作成した foo.tgz.ab は foo.tgz.aa なしに抽出 (解凍) すること
* ができませんが、[2] で作成したファイルは tar tzvf foo.tgz.ab など
* で処理することが可能になります。
*/
#include
#include
#define YES 1
#define NO 0
#define EOS '\0'
#define shift --argc; ++argv
char *prog;
#define IS_PIPE '|'
#define IS_TAR 't'
#define UNKNOWN 'u'
#define NOT_TAR 0
#define SEQUENCE '%'
#define D_BASE 10
#define C_BASE 26
#define TBLKSIZ 512
#define NAMSIZ 100
#define MODSIZ 8
#define UIDSIZ 8
#define GIDSIZ 8
#define SIZSIZ 12
#define MTMSIZ 12
#define SUMSIZ 8
/* tar形式のヘッダ情報 (古い? ;^^) */
typedef union {
unsigned char buf[TBLKSIZ];
struct header {
char name[NAMSIZ];
char mode[MODSIZ];
char uid[UIDSIZ];
char gid[GIDSIZ];
char size[SIZSIZ];
char mtime[MTMSIZ];
char cksum[SUMSIZ];
char linkflag;
char linknum[NAMSIZ];
} dbuf;
} tblock_t;
/* 新しい出力先の名称 */
char *newname(int n, char *s, char *format)
{
static char t[BUFSIZ];
int nseq;
int pos, m;
int radix, start;
nseq = 2;
if (isdigit(format[1])) {
nseq = format[1] - '0';
}
pos = 0;
while ((*s != EOS) && (pos - nseq < BUFSIZ - 1)) {
if (*s == SEQUENCE) {
if (*(s + 1) != SEQUENCE) {
break;
}
else {
++s;
}
}
t[pos] = *s;
++pos;
++s;
}
m = 0;
if (*s == SEQUENCE) {
++s;
radix = D_BASE;
start = '0';
if (format[0] == 'c') {
radix = C_BASE;
start = 'a';
}
while (m < nseq) {
t[pos + nseq - m - 1] = (n % radix) + start;
n /= radix;
++m;
}
}
pos += m;
while ((*s != EOS) && (pos < BUFSIZ - 1)) {
t[pos] = *s;
++pos;
++s;
}
t[pos] = EOS;
return(t);
}
/* 新しい出力先を開いてポインタを返す */
FILE *openfp(char *name)
{
FILE *fp;
if (*name == IS_PIPE) {
++name;
while (isspace(*name)) {
++name;
}
if ((fp = popen(name, "w")) == NULL) {
fprintf(stderr, "%s: can't open pipe: %s\n", prog, name);
exit(1);
}
}
else {
if ((fp = fopen(name, "w")) == NULL) {
fprintf(stderr, "%s: can't open file: %s\n", prog, name);
exit(1);
}
}
return(fp);
}
/* 出力先を閉じる */
void closefp(FILE *fp, char *name)
{
if (name[0] == IS_PIPE) {
++name;
while (isspace(*name)) {
++name;
}
if (pclose(fp) != 0) {
fprintf(stderr, "%s: can't close pipe: %s\n", prog, name);
}
}
else {
if (fclose(fp) != 0) {
fprintf(stderr, "%s: can't close file: %s\n", prog, name);
}
}
}
/* 入力はtar形式か? */
int istar(tblock_t *tblock)
{
int i;
int cksum;
int calc;
tblock_t bufcopy;
cksum = 0;
for (i = 0; i < SUMSIZ; i++) {
if (tblock->dbuf.cksum[i] == EOS) {
break;
}
cksum = cksum * 8 + tblock->dbuf.cksum[i] - '0';
}
for (i = 0; i < TBLKSIZ; i++) {
bufcopy.buf[i] = tblock->buf[i];
}
for (i = 0; i < SUMSIZ; i++) {
bufcopy.dbuf.cksum[i] = ' ';
}
calc = 0;
for (i = 0; i < TBLKSIZ; i++) {
calc += bufcopy.buf[i];
}
#ifdef EBUG
fprintf(stderr, "%s: cksum %8o, %8o\n", prog, cksum, calc);
#endif
if (calc == cksum) {
return(IS_TAR);
}
return(NOT_TAR);
}
/* 読み込んだブロックがNULLでない */
int nonull(unsigned char *buf)
{
int i;
i = 0;
for (i = 0; i < TBLKSIZ - 1; i++) {
if (buf[i] != 0) {
return(buf[i]);
}
}
return(buf[i]);
}
/* 読み込んだブロックはNULLか */
int nullblk(unsigned char *buf)
{
int i;
i = 0;
for (i = 0; i < TBLKSIZ - 1; i++) {
if (buf[i] != 0) {
return(0);
}
}
return(1);
}
/* tar形式のファイル長さを返す */
unsigned long tarlength(tblock_t *tblock)
{
int i;
unsigned long length;
length = 0;
for (i = 0; i < SIZSIZ; i++) {
if (tblock->dbuf.size[i] == EOS) {
break;
}
length = length * 8 + tblock->dbuf.size[i] - '0';
}
return(length);
}
/* ファイルを分割する */
void split(FILE *fp, unsigned long length, char *output,
char *format, int mode, int verbose)
{
static int nfil = 0;
char *filnam;
FILE *ofp;
unsigned long osiz;
unsigned long rsiz;
unsigned long wsiz;
unsigned long tlen;
unsigned long tout;
tblock_t tblock;
nfil = 0;
ofp = NULL;
osiz = 0;
tout = 0;
rsiz = 0;
while (!feof(fp)) {
if (rsiz == 0) { /* 入力バッファが空なら読み込み */
rsiz = fread(tblock.buf, 1, TBLKSIZ, fp);
if (verbose > 3) {
fprintf(stderr, "%s: read %ld bytes\n", prog, rsiz);
}
}
if (ofp == NULL) { /* オープンされていなければ出力を開く */
filnam = newname(nfil, output, format);
ofp = openfp(filnam);
osiz = 0;
}
if ((mode != NOT_TAR) && (istar(&tblock))) {
/* tarモードならファイル一つ分を読み書き */
mode = IS_TAR;
tlen = tarlength(&tblock);
if (verbose > 2) {
fprintf(stderr, "%s: tar: %s (%ld)\n",
prog, tblock.dbuf.name, tlen);
}
/* とりあえずヘッダ部分を出力 */
if ((wsiz = fwrite(tblock.buf, 1, rsiz, ofp)) != rsiz) {
fprintf(stderr, "%s: write to %d-th output failed at %ld,\n",
prog, nfil, osiz);
fprintf(stderr, " (wrote: %ld != read: %ld)\n", wsiz, rsiz);
exit(1);
}
tout = 0;
while (tout < tlen) { /* ファイルの実体があれば読み書き */
rsiz = fread(tblock.buf, 1, TBLKSIZ, fp);
if (rsiz <= 0) {
break;
}
if (verbose > 3) {
fprintf(stderr, "%s: read %ld bytes\n", prog, rsiz);
}
if ((wsiz = fwrite(tblock.buf, 1, rsiz, ofp)) != rsiz) {
fprintf(stderr, "%s: write to %d-th output failed",
prog, nfil);
fprintf(stderr, " at %ld,\n", osiz);
fprintf(stderr, " (wrote: %ld != read: %ld)\n",
wsiz, rsiz);
exit(1);
}
osiz += wsiz;
tout += wsiz;
}
/* ファイルの後ろにNULLブロックが続いていれば読み書き */
rsiz = fread(tblock.buf, 1, TBLKSIZ, fp);
while (nullblk(tblock.buf)) {
if ((wsiz = fwrite(tblock.buf, 1, rsiz, ofp)) != rsiz) {
fprintf(stderr, "%s: write to %d-th output failed",
prog, nfil);
fprintf(stderr, " at %ld,\n", osiz);
fprintf(stderr, " (wrote: %ld != read: %ld)\n",
wsiz, rsiz);
exit(1);
}
osiz += wsiz;
tout += wsiz;
if ((rsiz = fread(tblock.buf, 1, TBLKSIZ, fp)) <= 0) {
break;
}
}
mode = UNKNOWN;
}
else { /* tarモードでないときはブロックごとに読み書き */
if ((wsiz = fwrite(tblock.buf, 1, rsiz, ofp)) != rsiz) {
fprintf(stderr, "%s: write to %d-th output failed at %ld,\n",
prog, nfil, osiz);
fprintf(stderr, " (wrote: %ld != read: %ld)\n", wsiz, rsiz);
exit(1);
}
osiz += wsiz;
rsiz = 0;
}
if (osiz >= length) {
/* 出力済みサイズが指定長さを越えていたらファイルを閉じる */
if (verbose > 0) {
fprintf(stderr, "%s: wrote %ld bytes on %s\n",
prog, osiz, filnam);
}
closefp(ofp, filnam);
ofp = NULL;
++nfil;
}
}
if (ofp != NULL) {
if (verbose > 0) {
fprintf(stderr, "%s: wrote %ld bytes on %s\n",
prog, osiz, filnam);
}
closefp(ofp, filnam);
++nfil;
}
}
/* 出力サイズを得る */
unsigned long getfilsiz(char *s)
{
char *t;
unsigned long n;
t = s;
n = 0;
while (isdigit(*s)) {
n = n * 10;
n += (*s - '0');
++s;
}
if ((*s == 'k') || (*s == 'K')) {
n *= 1024L;
}
else if ((*s == 'm') || (*s == 'M')) {
n *= (1024L * 1024L);
}
else if ((*s == 'g') || (*s == 'G')) {
n *= (1024L * 1024L * 1024L);
}
#if 0
else if ((*s == 't') || (*s == 'T')) {
n *= (1024L * 1024L * 1024L * 1024L);
}
#endif
else if (*s != EOS) {
fprintf(stderr, "%s: suffix '%c' unknown in '%s'\n", prog, *s, t);
}
return(n);
}
/* 使いかたの表示 */
void usage(void)
{
fprintf(stderr, "Usage: %s -size -o output -d# -c# -v\n", prog);
exit(1);
}
int main(int argc, char *argv[])
{
char *output;
unsigned long length;
char *format;
int verbose;
int mode;
FILE *fp;
prog = *argv;
shift;
length = 1024;
verbose = 0;
output = "| gzip --fast > %.gz";
format = "c2";
verbose = 0;
mode = UNKNOWN;
while ((argc > 0) && (argv[0][0] == '-') && (argv[0][1] != EOS)) {
if (isdigit(argv[0][1])) {
length = getfilsiz(&argv[0][1]);
if (length <= 0) {
fprintf(stderr, "%s: length must be lager than 0 (%ld)\n",
prog, length);
exit(1);
}
}
else if (argv[0][1] == 'o') {
shift;
output = *argv;
}
else if (argv[0][1] == 'v') {
if (isdigit(argv[0][2])) {
verbose = argv[0][2] - '0';
}
else {
++verbose;
}
}
else if (argv[0][1] == 't') {
mode = NOT_TAR;
}
else if (argv[0][1] == 'c') {
if (isdigit(argv[0][2])) {
format = &argv[0][1];
}
else {
format = "c2";
}
}
else if (argv[0][1] == 'd') {
if (isdigit(argv[0][2])) {
format = &argv[0][1];
}
else {
format = "d3";
}
}
else {
usage();
}
shift;
}
if (argc <= 0) {
split(stdin, length, output, format, mode, verbose);
}
else {
while (argc > 0) {
if ((fp = fopen(*argv, "r")) == NULL) {
fprintf(stderr, "%s: can't open %s\n", prog, *argv);
exit(1);
}
split(fp, length, output, format, mode, verbose);
shift;
}
}
exit(0);
}
/* Local Variables: */
/* compile-command:"gcc -Wall -o esplit esplit.c" */
/* End: */