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

📄 synctree.c

📁 操作系统源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/*	synctree 4.15 - Synchronise file tree.		Author: Kees J. Bot *								5 Apr 1989 * SYNOPSYS *	synctree [-iuf] [[user1@machine1:]dir1 [[user2@]machine2:]dir2 * * Dir2 will then be synchronized to dir1 with respect to the flags. * The flags mean: *	-i  Be interactive on files other than directories too. *	-u  Only install files that are newer, i.e. that need an update. *	-f  Force.  Don't ask for confirmation, all answers are 'yes'. * * Hitting return lets synctree use its proposed answer.  Hitting CTRL-D is * like typing return to all questions that follow. * * If either of the directories to be synchronized contains the file ".backup" * then it is a backup directory.  The file ".backup" in this directory is * an array of mode information indexed on inode number. * * Copyright 1989 Kees J. Bot, All rights reserved. * This program may only be used with Minix, unless permission has been * granted by me.  Any other use is a violation of my copyright. * * 89/04/05, Kees J. Bot - Birth of tree synchronizing program. * 92/02/02		 - General overhaul, rcp(1) like syntax. */#define nil 0#include <sys/types.h>#include <stdio.h>#include <sys/stat.h>#include <utime.h>#include <string.h>#include <signal.h>#include <dirent.h>#include <errno.h>#include <fcntl.h>#include <stdlib.h>#include <unistd.h>#include <time.h>#include <sys/wait.h>#if _MINIX#include "limits.h"#include "minix/config.h"#define BLOCK_SIZE	1024#define LITTLE_ENDIAN	(CHIP == INTEL)#define USE_SHADOWING	(CHIP == M68000)#else#define LITTLE_ENDIAN	0#define USE_SHADOWING	0#endif#ifndef PATH_MAX#define PATH_MAX	1024#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)#endif#define NUMBYTES     4	/* Any number fits in this many bytes. */#define CHUNK     4096	/* Transfer files in this size chunks. */static int install= 0;	/* Install files, do not delete, update if newer. */static int interact= 0;	/* Ask permission to install too. */static int force= 0;	/* Force trees to be completely equal. */static int backup= 0;	/* This tree is for backup. */static char SYNCNAME[]	= "synctree";static char SLAVENAME[]	= "==SLAVE==";static char MASTERNAME[]= "==MASTER==";static char BACKUP[] = ".backup";	/* Backup filemodes. */static int filemodes;			/* Filemodes fildes. */static int chan[2]= { 0, 1 };	/* In and output channel to opposite side. */#define BUCKSIZE (1+NUMBYTES+CHUNK)static char bucket[BUCKSIZE];	/* Put a lot of things here before sending. */static char *buckp= bucket;	/* Fill pointer. */static int buckn= 0;		/* # bytes in bucket. */enum orders {	/* What back breaking labour should the slave perform? */	ENTER= 128,	/* Make ready to process contents of directory. */	ADVANCE,	/* Determine next pathname and report it back. */	CAT,		/* Send contents of file. */	MORE,		/* Send more file contents. */	CANCEL,		/* Current pathname is not installed, remove as link. */	DIE,		/* Die with exit(0); */	DIE_BAD,	/* exit(1); */	POSITIVE,	/* Ask a yes/no question expecting yes. */	NEGATIVE,	/* Same expecting no. */	PASS_YES,	/* Pass this to the master will you. */	PASS_NO		/* Same here. */};#ifdef DEBUGchar *ORDERS[]= {	"ENTER", "ADVANCE", "CAT", "MORE", "CANCEL", "DIE", "DIE_BAD",	"POSITIVE", "NEGATIVE", "PASS_YES", "PASS_NO"};#endifenum answers {	PATH= 128,	/* Report pathname, and stat(2) info. */	LINK,		/* Report linkname, pathname, and stat(2) info. */	DATA,		/* Contents of file follow. */	NODATA,		/* Can't read file. */	DONE,		/* Nothing more to advance to. */	SYMLINK,	/* Report symlinkname, pathname, and stat(2) info. */	YES, NO		/* Result of an ASK. */};#ifdef DEBUGchar *ANSWERS[]= {	"PATH", "LINK", "DATA", "NODATA", "DONE", "SYMLINK", "YES", "NO"};#define DPRINTF(format, arg)	fprintf(stderr, format, arg0, arg)#else#define DPRINTF(format, arg)#endifstruct mode {	unsigned short	md_mode;	unsigned short	md_uid;	unsigned short	md_gid;	unsigned short	md_rdev;	unsigned short	md_devsiz;};static char *arg0;	/* basename(argv[0]) */static int ex= 0;	/* exit status. */static void because(){	fprintf(stderr, ": %s\n", strerror(errno));	ex= 1;}static void perr(label) char *label;{	fprintf(stderr, "%s: %s: %s\n", arg0, label, strerror(errno));	ex= 1;}static void perrx(label) char *label;{	perr(label);	exit(1);}#if S_HIDDEN/* Support for per achitecture hidden files. */static int transparent= 0;static void isvisible(name) char *name;{	char *p= name + strlen(name);	while (p > name && *--p == '/') {}	if (p > name && *p == '@' && p[-1] != '/') transparent= 1;}#else#define transparent	0#define isvisible(name)	((void) 0)#endifstatic void isbackup(slave) int slave;{	if ((filemodes= open(BACKUP, slave ? O_RDONLY : O_RDWR)) >= 0)		backup= 1;	else {		if (errno != ENOENT) perrx(BACKUP);	}}static char path[PATH_MAX+1];	/* Holds pathname of file being worked on. */static char lnkpth[PATH_MAX+1];	/* (Sym)link to path. */static char *linkpath;		/* What path is, or should be linked to. */static struct stat st;		/* Corresponding stat(2) info. */static char Spath[PATH_MAX+1];	/* Slave is looking at this. */static char Slnkpth[PATH_MAX+1];/* (Sym)link to Spath. */static char *Slinkpath=nil;	/* Either nil or Slnkpth. */static struct stat Sst;		/* Slave's stat(2). */static char *addpath(p, n) char *p, *n;/* Add a name to the path, return pointer to end. */{	if (p - path + 1 + strlen(n) > PATH_MAX) {		*p= 0;		fprintf(stderr, "%s: %s/%s is too long.\n", arg0, path, n);		fprintf(stderr, "%s: Unable to continue.\n", arg0);		exit(1);	}	if (p == path+1 && path[0] == '.') p= path;	if (p > path) *p++ = '/';	while (*n != 0) *p++ = *n++;	*p= 0;	return p;}struct entry {	/* A directory entry. */	struct entry	*next;	/* Next entry in same directory */	struct entry	*dir;	/* It is part of this directory */	struct entry	*con;	/* If a dir, its contents */	char		*name;	/* Name of this dir entry */};static struct entry *E= nil;		/* File being processed. */static void setpath(e) struct entry *e;/* Set path leading to e. */{	static char *pend;	if (e == nil)		pend= path;	else {		setpath(e->dir);		pend= addpath(pend, e->name);	}}static void sort(ae) struct entry **ae;/* This is either a stable mergesort, or thermal noise, I'm no longer sure. * It must be called like this: if (L!=nil && L->next!=nil) sort(&L); */{	/* static */ struct entry *e1, **mid;  /* Need not be local */	struct entry *e2;	e1= *(mid= &(*ae)->next);	do {		if ((e1= e1->next) == nil) break;		mid= &(*mid)->next;	} while ((e1= e1->next) != nil);	e2= *mid;	*mid= nil;	if ((*ae)->next != nil) sort(ae);	if (e2->next != nil) sort(&e2);	e1= *ae;	for (;;) {		if (strcmp(e1->name, e2->name)<=0) {			if ((e1= *(ae= &e1->next)) == nil) {				*ae= e2;				break;			}		} else {			*ae= e2;			e2= *(ae= &e2->next);			*ae= e1;			if (e2 == nil) break;		}	}}static void enter()/* Collect directory entries of E. */{	struct entry **last= &E->con, *new;	struct dirent *e;	DIR *d;	if ((d= opendir(path)) == nil) {		fprintf(stderr, "%s: Can't read dir %s\n", arg0, path);		return;	}	while ((e= readdir(d)) != nil) {		if (e->d_name[0] == '.' && (e->d_name[1] == 0			|| (e->d_name[1] == '.' && e->d_name[2] == 0)		)) continue;		new= (struct entry *) malloc(sizeof(*new));		new->next= nil;		new->dir= E;		new->con= nil;		new->name= (char *) malloc(strlen(e->d_name) + 1);		strcpy(new->name, e->d_name);		*last= new;		last= &new->next;	}	closedir(d);	if (E->con != nil && E->con->next != nil) sort(&E->con);}#define cancellink()	((void) islink())	/* Delete link by calling for it twice. (Gross hack) */static char *islink()/* Returns the name of the file path is linked to.  If no such link can be * found, then path is added to the list and nil is returned.  If all the * links of a file have been seen, then it is removed from the list. * Directories are not seen as linkable. */{	struct links {		struct links	*next;	/* They form a simple list. */		char		*name;	/* Full name of the link. */		dev_t		dev;	/* Identification. */		ino_t		ino;		int		count;	/* This many links are not seen yet. */	};	static struct links *lnktop=nil, **lnk= nil;	struct links *new;	if (!S_ISDIR(st.st_mode) && st.st_nlink > 1) {		lnk= &lnktop;		while (*lnk != nil			&& !((*lnk)->dev == st.st_dev			&& (*lnk)->ino == st.st_ino)		) lnk= &(*lnk)->next;		if (*lnk != nil) {	/* Link found, return its name. */			new= *lnk;			strcpy(lnkpth, new->name);			if (--new->count == 0 || strcmp(path, new->name) == 0) {						/* ^^ check for cancellink. */				*lnk= new->next;				free(new->name);				free(new);			}			return lnkpth;		}			/* No link found, add this one. */		*lnk= new= (struct links *) malloc(sizeof(*new));		new->next= nil;		new->name= (char *) malloc(strlen(path) + 1);		strcpy(new->name, path);		new->dev= st.st_dev;		new->ino= st.st_ino;		new->count= st.st_nlink - 1;	}	lnk= nil;	return nil;}static void setstat(ino, stp) ino_t ino; struct stat *stp;/* Set backup status info, we know that backup is true. */{	struct mode md;	md.md_mode = stp->st_mode;	md.md_uid = stp->st_uid;	md.md_gid = stp->st_gid;	md.md_rdev = stp->st_rdev;	md.md_devsiz = stp->st_size / 1024;	if (lseek(filemodes, (off_t) sizeof(md) * (off_t) ino, 0) == -1		|| write(filemodes, (char *) &md, sizeof(md)) != sizeof(md)	) perrx(BACKUP);}static int getstat(name, stp) char *name; struct stat *stp;/* Get status information of file name, skipping some files.  Backup info * is inserted as needed. */{	errno= 0;	if (strcmp(name, BACKUP) == 0) return -1;	if (lstat(name, stp) < 0) return -1;	if (stp->st_mode == S_IFREG && stp->st_mtime == 0) return -1;	if (backup) {		struct mode md;		if (lseek(filemodes,			(off_t) sizeof(md) * (off_t) stp->st_ino, 0) == -1		    || read(filemodes, (char *) &md, sizeof(md)) != sizeof(md)		    || md.md_mode == 0		) {			errno= 0;			setstat(stp->st_ino, stp);		} else {			stp->st_mode = md.md_mode;			stp->st_uid = md.md_uid;			stp->st_gid = md.md_gid;			stp->st_rdev = md.md_rdev;			if (S_ISBLK(stp->st_mode))				stp->st_size= (off_t) md.md_devsiz * 1024;		}	}	return 0;}static int advance()/* Determine next pathname, return true on success. */{	for (;;) {		if (E==nil) {	/* First call, enter root dir. */			E= (struct entry *) malloc(sizeof(*E));			E->dir= nil;			E->con= nil;			E->next= nil;			E->name= (char *) malloc(3);			strcpy(E->name, transparent ? ".@" : ".");		} else		if (E->con != nil)	/* Dir's files must be processed. */			E= E->con;		else {			for (;;) {				/* Remove E from it's parents list, then				 * try next entry, if none, go to parent dir.				 */				struct entry *junk= E, *parent= E->dir;				if (parent != nil) parent->con= E->next;				E= E->next;				free(junk->name);				free(junk);				if (E != nil) break;				if ((E= parent) == nil) return 0;			}		}		setpath(E);		if (getstat(path, &st) == 0) {			if (S_ISLNK(st.st_mode)) {				int n;				if ((n= readlink(path, lnkpth, PATH_MAX)) >= 0)				{					lnkpth[n]= 0;					break;				}			} else {				break;			}		}		if (errno != 0 && errno != ENOENT) perr(path);	}	linkpath= islink();	DPRINTF("%s: path = %s\n", path);	return 1;}static enum orders request()/* Slave reads command sent by master. */{	static char buf[64], *bp;	static int n= 0;	int req;	for (;;) {		if (n == 0) {			if ((n= read(chan[0], buf, (int) sizeof(buf))) <= 0) {				if (n < 0) perrx("request()");				/* Master died, try to report it then follow. */				fprintf(stderr,

⌨️ 快捷键说明

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