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

📄 remsync.c

📁 操作系统源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/*	remsync 1.5 - remotely synchronize file trees	Author: Kees J. Bot *								10 Jun 1994 */#define nil 0#include <sys/types.h>#include <sys/stat.h>#include <stdio.h>#include <stdlib.h>#include <stdarg.h>#include <string.h>#include <dirent.h>#include <unistd.h>#include <fcntl.h>#include <errno.h>#include <limits.h>#include <time.h>#include <utime.h>#define arraysize(a)	(sizeof(a) / sizeof((a)[0]))#define arraylimit(a)	((a) + arraysize(a))#ifndef major#define major(dev)	((int) ((dev) >> 8))#define minor(dev)	((int) ((dev) & 0xFF))#endif#ifndef S_ISLNK/* There were no symlinks in medieval times. */#define S_ISLNK(mode)			(0)#define lstat				stat#define symlink(path1, path2)		(errno= ENOSYS, -1)#define readlink(path, buf, len)	(errno= ENOSYS, -1)#endifint sflag;		/* Make state file. */int dflag;		/* Make list of differences. */int uflag;		/* Only update files with newer versions. */int xflag;		/* Do not cross device boundaries. */int Dflag;		/* Debug: Readable differences, no file contents. */int vflag;		/* Verbose. */#define NO_DEVICE	(-1)dev_t xdev= NO_DEVICE;	/* The device that you should stay within. */int excode= 0;		/* Exit(excode); */#define BASE_INDENT	2	/* State file basic indent. */void report(const char *label){	fprintf(stderr, "remsync: %s: %s\n", label, strerror(errno));	excode= 1;}void fatal(const char *label){	report(label);	exit(1);}void *allocate(void *mem, size_t size){	if ((mem= mem == nil ? malloc(size) : realloc(mem, size)) == nil) {		fprintf(stderr, "remsync: Out of memory: %s\n",			strerror(errno));		exit(1);	}	return mem;}void deallocate(void *mem){	if (mem != nil) free(mem);}/* One needs to slowly forget two sets of objects: for the code that reads * the state file, and for the code that traverses trees. */int keep;#define KEEP_STATE	0#define KEEP_TRAVERSE	1void forget(void *mem)/* Some objects must be deleted in time, but not just yet. */{	static void *death_row[2][50];	static void **dp[2]= { death_row[0], death_row[1] };	deallocate(*dp[keep]);	*dp[keep]++= mem;	if (dp[keep] == arraylimit(death_row[keep])) dp[keep]= death_row[keep];}char *copystr(const char *s){	char *c= allocate(nil, (strlen(s) + 1) * sizeof(c[0]));	strcpy(c, s);	return c;}typedef struct pathname {	char		*path;	/* The actual pathname. */	size_t		idx;	/* Index for the terminating null byte. */	size_t		lim;	/* Actual length of the path array. */} pathname_t;void path_init(pathname_t *pp)/* Initialize a pathname to the null string. */{	pp->path= allocate(nil, (pp->lim= 16) * sizeof(pp->path[0]));	pp->path[pp->idx= 0]= 0;}void path_add(pathname_t *pp, const char *name)/* Add a component to a pathname. */{	size_t lim;	char *p;	int slash;	lim= pp->idx + strlen(name) + 2;	if (lim > pp->lim) {		pp->lim= lim + lim/2;	/* add an extra 50% growing space. */		pp->path= allocate(pp->path, pp->lim * sizeof(pp->path[0]));	}	p= pp->path + pp->idx;	slash= (pp->idx > 0);	if (pp->idx == 1 && p[-1] == '/') p--;	while (*name != 0) {		if (*name == '/') {			slash= 1;		} else {			if (slash) { *p++ = '/'; slash= 0; }			*p++= *name;		}		name++;	}	if (slash && p == pp->path) *p++= '/';	*p = 0;	pp->idx= p - pp->path;}void path_trunc(pathname_t *pp, size_t didx)/* Delete part of a pathname to a remembered length. */{	pp->path[pp->idx= didx]= 0;}#if kept_for_comments_onlyconst char *path_name(const pathname_t *pp)/* Return the actual name as a char array. */{	return pp->path;}size_t path_length(const pathname_t *pp)/* The length of the pathname. */{	return pp->idx;}void path_drop(pathname_t *pp)/* Release the storage occupied by the pathname. */{	free(pp->path);}#endif#define path_name(pp)		((const char *) (pp)->path)#define path_length(pp)		((pp)->idx)#define path_drop(pp)		free((void *) (pp)->path)typedef struct namelist {	/* Obviously a list of names. */	struct namelist	*next;	char		*name;} namelist_t;char *rdlink(const char *link, off_t size)/* Look where "link" points. */{	static char *path= nil;	static size_t len= 0;	size_t n;	if (len <= size) {		path= allocate(path, (len= size * 2) * sizeof(path[0]));	}	if ((n= readlink(link, path, len)) == -1) return nil;	path[n]= 0;	return path;}void sort(namelist_t **anl)/* A stable mergesort disguised as line noise.  Must be called like this: *	if (L!=nil && L->next!=nil) sort(&L); */{	/* static */ namelist_t *nl1, **mid;  /* Need not be local */	namelist_t *nl2;	nl1= *(mid= &(*anl)->next);	do {		if ((nl1= nl1->next) == nil) break;		mid= &(*mid)->next;	} while ((nl1= nl1->next) != nil);	nl2= *mid;	*mid= nil;	if ((*anl)->next != nil) sort(anl);	if (nl2->next != nil) sort(&nl2);	nl1= *anl;	for (;;) {		if (strcmp(nl1->name, nl2->name)<=0) {			if ((nl1= *(anl= &nl1->next)) == nil) {				*anl= nl2;				break;			}		} else {			*anl= nl2;			nl2= *(anl= &nl2->next);			*anl= nl1;			if (nl2 == nil) break;		}	}}namelist_t *collect(const char *dir)/* Return a sorted list of directory entries.  Returns null with errno != 0 * on error. */{	namelist_t *names, **pn= &names;	DIR *dp;	struct dirent *entry;	if ((dp= opendir(dir)) == nil) return nil;	while ((entry= readdir(dp)) != nil) {		if (entry->d_name[0] == '.'			&& (entry->d_name[1] == 0				|| (entry->d_name[1] == '.'					&& entry->d_name[2] == 0))) {			continue;		}		*pn= allocate(nil, sizeof(**pn));		(*pn)->name= copystr(entry->d_name);		pn= &(*pn)->next;	}	closedir(dp);	*pn= nil;	errno= 0;	if (names != nil && names->next != nil) sort(&names);	return names;}char *pop_name(namelist_t **names)/* Return one name of a name list. */{	char *name;	namelist_t *junk;	junk= *names;	*names= junk->next;	name= junk->name;	deallocate(junk);	forget(name);	return name;}typedef enum filetype {		/* The files we know about. */	F_DIR,	F_FILE,	F_BLK,	F_CHR,	F_PIPE,	F_LINK} filetype_t;typedef struct entry {		/* One file. */	int		depth;		/* Depth in directory tree. */	const char	*name;		/* Name of entry. */	const char	*path;		/* Path name. */	int		ignore;		/* Ignore this entry (errno number.) */	unsigned long	fake_ino;	/* Fake inode number for hard links. */	int		linked;		/* Is the file hard linked? */	int		lastlink;	/* Is it the last link? */	char		*link;		/* Where a (sym)link points to. */	filetype_t	type;	mode_t		mode;		/* Not unlike those in struct stat. */	uid_t		uid;	gid_t		gid;	off_t		size;	time_t		mtime;	dev_t		rdev;} entry_t;void linked(entry_t *entry, struct stat *stp)/* Return an "inode number" if a file could have links (link count > 1). * Also return a path to the first link if you see the file again. */{	static unsigned long new_fake_ino= 0;	static struct links {		struct links	*next;		char		*path;		ino_t		ino;		dev_t		dev;		nlink_t		nlink;		unsigned long	fake_ino;	} *links[1024];	struct links **plp, *lp;	entry->linked= entry->lastlink= 0;	entry->fake_ino= 0;	entry->link= nil;	if (S_ISDIR(stp->st_mode) || stp->st_nlink < 2) return;	plp= &links[stp->st_ino % arraysize(links)];	while ((lp= *plp) != nil && (lp->ino != stp->st_ino				|| lp->dev != stp->st_dev)) plp= &lp->next;	if (lp == nil) {		/* New file, store it with a new fake inode number. */		*plp= lp= allocate(nil, sizeof(*lp));		lp->next= nil;		lp->path= copystr(entry->path);		lp->ino= stp->st_ino;		lp->dev= stp->st_dev;		lp->nlink= stp->st_nlink;		lp->fake_ino= ++new_fake_ino;	} else {		entry->link= lp->path;		entry->linked= 1;	}	entry->fake_ino= lp->fake_ino;	if (--lp->nlink == 0) {		/* No need to remember this one, no more links coming. */		*plp= lp->next;		forget(lp->path);		deallocate(lp);		entry->lastlink= 1;	}}char *tree;		/* Tree to work on. */FILE *statefp;		/* State file. */char *state_file;FILE *difffp;		/* File of differences. */char *diff_file;entry_t *traverse(void)/* Get one name from the directory tree. */{	static int depth;	static pathname_t path;	static entry_t entry;	static namelist_t **entries;	static size_t *trunc;	static size_t deep;	static namelist_t *newentries;	struct stat st;recurse:	keep= KEEP_TRAVERSE;	if (deep == 0) {		/* Initialize for the root of the tree. */		path_init(&path);		path_add(&path, tree);		entries= allocate(nil, 1 * sizeof(entries[0]));		entries[0]= allocate(nil, sizeof(*entries[0]));		entries[0]->next= nil;		entries[0]->name= copystr("/");		trunc= allocate(nil, 1 * sizeof(trunc[0]));		trunc[0]= path_length(&path);		deep= 1;	} else	if (newentries != nil) {		/* Last entry was a directory, need to go down. */		if (entry.ignore) {			/* Ouch, it is to be ignored! */			while (newentries != nil) (void) pop_name(&newentries);			goto recurse;		}		if (++depth == deep) {			deep++;			entries= allocate(entries, deep * sizeof(entries[0]));			trunc= allocate(trunc, deep * sizeof(trunc[0]));		}		entries[depth]= newentries;		newentries= nil;		trunc[depth]= path_length(&path);	} else {		/* Pop up out of emptied directories. */		while (entries[depth] == nil) {			if (depth == 0) return nil;	/* Back at the root. */			/* Go up one level. */			depth--;		}	}	entry.name= pop_name(&entries[depth]);	path_trunc(&path, trunc[depth]);	path_add(&path, entry.name);	if (depth == 0) {		entry.path= "/";	} else {		entry.path= path_name(&path) + trunc[0];		if (entry.path[0] == '/') entry.path++;	}	entry.depth= depth;	entry.ignore= 0;	if (lstat(path_name(&path), &st) < 0) {		if (depth == 0 || errno != ENOENT) {			/* Something wrong with this entry, complain about			 * it and ignore it further.			 */			entry.ignore= errno;			report(path_name(&path));			return &entry;		} else {			/* Entry strangely nonexistent; simply continue. */			goto recurse;		}	}	/* Don't cross mountpoints if -x is set. */	if (xflag) {		if (xdev == NO_DEVICE) xdev= st.st_dev;		if (st.st_dev != xdev) {			/* Ignore the mountpoint. */			entry.ignore= EXDEV;			return &entry;		}	}	entry.mode= st.st_mode & 07777;	entry.uid= st.st_uid;	entry.gid= st.st_gid;	entry.size= st.st_size;	entry.mtime= st.st_mtime;	entry.rdev= st.st_rdev;	linked(&entry, &st);	if (S_ISDIR(st.st_mode)) {		/* A directory. */		entry.type= F_DIR;		/* Gather directory entries for the next traverse. */		if ((newentries= collect(path_name(&path))) == nil							&& errno != 0) {			entry.ignore= errno;			report(path_name(&path));		}	} else	if (S_ISREG(st.st_mode)) {		/* A plain file. */		entry.type= F_FILE;	} else	if (S_ISBLK(st.st_mode)) {		/* A block special file. */		entry.type= F_BLK;	} else	if (S_ISCHR(st.st_mode)) {		/* A character special file. */		entry.type= F_CHR;	} else	if (S_ISFIFO(st.st_mode)) {		/* A named pipe. */		entry.type= F_PIPE;	} else	if (S_ISLNK(st.st_mode)) {		/* A symbolic link. */		entry.type= F_LINK;		if ((entry.link= rdlink(path_name(&path), st.st_size)) == nil) {			entry.ignore= errno;			report(path_name(&path));		}	} else {		/* Unknown type of file. */		entry.ignore= EINVAL;	}	return &entry;}void checkstate(void){	if (ferror(statefp)) fatal(state_file);}void indent(int depth)/* Provide indentation to show directory depth. */{	int n= BASE_INDENT * (depth - 1);	while (n >= 8) {		if (putc('\t', statefp) == EOF) checkstate();		n-= 8;	}	while (n > 0) {		if (putc(' ', statefp) == EOF) checkstate();		n--;	}}int print_name(FILE *fp, const char *name)/* Encode a name. */{

⌨️ 快捷键说明

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