⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 gather.c

📁 操作系统源代码
💻 C
字号:
/* gather - collect files for mailing	Author: Andy Tanenbaum *//* It sometimes happens that one needs to mail a large directory full of * files to someone.  This program can be used to collect these files into * shar archives, compress and uuencode them. The interesting property that * it has is that it makes sure that none of the archives are too big, and * that no files are split over two archives. * * Syntax: gather [-s source_dir] [-d dest_dir] [-b max_arch_size] [-f file] * *	-s source directory	(where are the files to be sent) *	-d destination dir	(where should the archives be put) *	-b bytes		(maximum size of the archives; default 60K) *	-f file			(use file_00.uue etc as archive names) * * Examples: *	gather				# make 60K archives in this dir *	gather  -d mailings -b 50000	# make 50K archives in mailings * * Note: *	The maximum size given by -b (default 60000 bytes) is only an *	approximation, since it is hard to tell how big the final file *	will be after shar'ing, compressing, and uue'ing.  A heuristic *	is used. */#include <sys/types.h>#include <sys/stat.h>#include <dirent.h>#include <fcntl.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <stdio.h>#define DEFAULT        60000	/* default archive size */#define MAX_DIR_ENT      512	/* how many directory entries allowed */#define HEAP_SIZE      20000	/* storage size for all file names */#define NAME_SIZE       4096	/* storage size for current command */#define BASE_SIZE          7	/* max number of chars in basename */#define PATH_MAX         512	/* largest path name */#define NUMERATOR       138L	/* heuristic parameter */#define DENOMINATOR     100L	/* heuristic parameter */char heap[HEAP_SIZE + 2];	/* dir entries stored here */char names[NAME_SIZE];		/* file name lists constructed here */char work[NAME_SIZE];		/* scratch buffer */char base_name[BASE_SIZE + 1];	/* base name to use for the archives */char target[PATH_MAX];		/* storage for target file names */struct dir_ent {  char *file_name;  long file_size;} dir_ent[MAX_DIR_ENT];_PROTOTYPE(int main, (int argc, char **argv));_PROTOTYPE(int collect, (int first, int limit, long cutoff));_PROTOTYPE(long heuristic, (long m));_PROTOTYPE(void sort_dir, (int limit));_PROTOTYPE(void swap, (struct dir_ent *p, struct dir_ent *q));_PROTOTYPE(void fudge, (struct dir_ent *p, struct dir_ent *endp, long size));_PROTOTYPE(void get_basename, (char *s, char *file));_PROTOTYPE(void usage, (void));int main(argc, argv)int argc;char *argv[];{/* Parse the command and get ready. */  int i, counter, l, s, nonlocal;  char *p, num[3];  struct dirent *d;  DIR *dirp;  struct stat stbuf;  int first;			/* first entry not used yet */  int limit;			/* number of files in src_dir */  char *src_dir = ".";		/* pointer to source directory */  char *dst_dir = ".";		/* pointer to destination directory */  char *file = "";		/* name to use */  long max_bytes = DEFAULT;	/* max archive size (approx.) */  long cutoff;			/* max cumulative input size */  if (argc > 9) usage();  i = 1;  while (i < argc) {	/* Examine the i-th argument. */	p = argv[i];	if (*p != '-') usage();	switch (*(p + 1)) {	    case 's':	src_dir = argv[i + 1];	break;	    case 'd':	dst_dir = argv[i + 1];	break;	    case 'f':	file = argv[i + 1];	break;	    case 'b':		max_bytes = atol(argv[i + 1]);		if (max_bytes <= 0) {			fprintf(stderr, "gather: bad -b value\n");			exit(1);		}		break;	    default:		fprintf(stderr, "gather: unknown flag %s\n", p);		exit(1);	}	i += 2;  }  /* Determine the basename. */  get_basename(src_dir, file);  /* Open the source directory. */  i = 0;  p = heap;  if ((dirp = opendir(src_dir)) == NULL) {	fprintf(stderr, "gather: cannot open %s\n", src_dir);	exit(2);  }  /* Read in all the file names. */  while (1) {	d = readdir(dirp);	if (d == NULL) break;	l = strlen(d->d_name);	if (p + l >= &heap[HEAP_SIZE] || i >= MAX_DIR_ENT) {		fprintf(stderr, "gather: %s is too large\n", src_dir);		exit(2);	}	strcpy(work, src_dir);	strcat(work, "/");	strcat(work, d->d_name);	stat(work, &stbuf);	if ((stbuf.st_mode & S_IFMT) == S_IFDIR) continue;	dir_ent[i].file_name = p;	strcpy(p, d->d_name);	dir_ent[i].file_size = stbuf.st_size;	p += l + 1;	i++;  }  limit = i;  closedir(dirp);  /* Sort the names. */  sort_dir(limit);  /* Figure out when to stop reading files. */  cutoff = heuristic(max_bytes);  /* Collect files into archives. */  first = 0;  counter = 0;  while (first < limit) {	first = collect(first, limit, cutoff);	num[0] = '0' + (counter / 10);	num[1] = '0' + (counter % 10);	num[2] = 0;	/* Construct full path of compressed target. */	target[0] = 0;	if (strcmp(dst_dir, ".") != 0) {		strcpy(target, dst_dir);		strcat(target, "/");	}	strcat(target, base_name);	strcat(target, "_");	strcat(target, num);	strcat(target, ".Z");	/* (cd src; shar file ... | compress -fc) >dir/base.00.Z */	nonlocal = strcmp(src_dir, ".");	work[0] = 0;	if (nonlocal) {		strcat(work, "(cd ");		strcat(work, src_dir);		strcat(work, "; ");	}	strcat(work, "shar ");	strcat(work, names);	strcat(work, " | compress -fc ");	if (nonlocal) strcat(work, ")");	strcat(work, " >");	strcat(work, target);	s = system(work);	if (s < 0) {		fprintf(stderr, "gather: shar command failed\n");		exit(2);	}	/* Uue dir/base.00.Z */	strcpy(work, "uue ");	strcat(work, target);	strcat(work, "\n");	s = system(work);	if (s < 0) {		fprintf(stderr, "gather: uue command failed\n");		exit(2);	}	/* Unlink dir/base.00.Z */	unlink(target);	counter++;  }  return(0);}int collect(first, limit, cutoff)int first;int limit;long cutoff;{/* See how many files will fit in an archive. */  int nr_files;  long cum_size, size;  struct dir_ent *p, *endp;  names[0] = 0;  p = &dir_ent[first];  endp = &dir_ent[limit];  nr_files = 0;  cum_size = 0;  while (p < endp) {	size = p->file_size;	if (size > cutoff) {		fprintf(stderr, "gather: %s is too big\n", p->file_name);		exit(2);	}	/* First peek to see if next file fits.  If not, maybe some	 * other file can be used instead.  Swap them. */	if (cum_size + size > cutoff) fudge(p, endp, cutoff - cum_size);	/* If it fails now, there is no file that will fit. */	size = p->file_size;	if (cum_size + size > cutoff) return(p - dir_ent);	strcat(names, p->file_name);	strcat(names, " ");	cum_size += size;	p++;  }  return(p - dir_ent);}long heuristic(m)long m;{  /* The basic algorithm is to collect files up to some limit, and put   * them in an archive.  It is tricky to determine how many files to   * collect, because they will be shar'ed, compressed and uue'ed.   * Thus we need a heuristic for guessing how to relate the total size   * of the input files to the size of the final uue archive.  This   * heuristic is contained in this procedure.  It takes the desired   * final size as input and produces the file cutoff as output. */  return((NUMERATOR * m) / DENOMINATOR);}void sort_dir(limit)int limit;			/* how many entries in dir_ent */{/* Sort the directory using bubble sort. */  struct dir_ent *p, *q;  for (p = &dir_ent[0]; p < &dir_ent[limit - 1]; p++) {	for (q = p + 1; q < &dir_ent[limit]; q++) {		if (strcmp(p->file_name, q->file_name) > 0) swap(p, q);	}  }}void swap(p, q)struct dir_ent *p, *q;{  /* Exchange two entries. */  char *cp;  long l;  cp = p->file_name;  l = p->file_size;  p->file_name = q->file_name;  p->file_size = q->file_size;  q->file_name = cp;  q->file_size = l;}void fudge(p, endp, size)struct dir_ent *p, *endp;long size;{/* Look for a file that will fit (i.e., <= size). This fudging gives a more * uniform distribution, and reduces the number of files needed. */  register struct dir_ent *q;  for (q = p + 1; q < endp; q++) {	if (q->file_size <= size) {		swap(p, q);		return;	}  }}void get_basename(s, file)char *s;char *file;{/* Determine the basename and copy it to base_name. */  char *p, *q;  if (*file != 0) p = file;  else if (strcmp(s, ".") == 0) {	if (getcwd(work, NAME_SIZE) == NULL) {		fprintf(stderr, "gather: could not get name of working dir\n");		exit(2);	}	p = work;  } else {	p = s;  }  q = p + strlen(p) - 1;  if (*q == '\n') {	*q = 0;	q--;  }  while (1) {	if (q < p || *q == '/') break;	q--;  }  strncpy(base_name, q + 1, (size_t)BASE_SIZE);}void usage(){  fprintf(stderr, "Usage: gather [-b bytes] [-s src_dir] [-d dst_dir] [-f file]\n");  exit(1);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -