示例#1
0
文件: flist.c 项目: OPSF/uClinux
static void list_file_entry(struct file_struct *f)
{
	char perms[11];

	if (!f->basename) {
		/* this can happen if duplicate names were removed */
		return;
	}

	permstring(perms, f->mode);

#ifdef SUPPORT_LINKS
	if (preserve_links && S_ISLNK(f->mode)) {
		rprintf(FINFO, "%s %11.0f %s %s -> %s\n",
			perms,
			(double)f->length, timestring(f->modtime),
			safe_fname(f_name(f)), safe_fname(f->u.link));
	} else
#endif
	{
		rprintf(FINFO, "%s %11.0f %s %s\n",
			perms,
			(double)f->length, timestring(f->modtime),
			safe_fname(f_name(f)));
	}
}
示例#2
0
void generate_files(int f,struct file_list *flist,char *local_name,int f_recv)
{
	int i;
	int phase=0;

	if (verbose > 2)
		rprintf(FINFO,"generator starting pid=%d count=%d\n",
			(int)getpid(),flist->count);

	for (i = 0; i < flist->count; i++) {
		struct file_struct *file = flist->files[i];
		mode_t saved_mode = file->mode;
		if (!file->basename) continue;

		/* we need to ensure that any directories we create have writeable
		   permissions initially so that we can create the files within
		   them. This is then fixed after the files are transferred */
		if (!am_root && S_ISDIR(file->mode)) {
			file->mode |= S_IWUSR; /* user write */
		}

		recv_generator(local_name?local_name:f_name(file),
			       flist,i,f);

		file->mode = saved_mode;
	}

	phase++;
	csum_length = SUM_LENGTH;
	ignore_times=1;

	if (verbose > 2)
		rprintf(FINFO,"generate_files phase=%d\n",phase);

	write_int(f,-1);

	/* we expect to just sit around now, so don't exit on a
	   timeout. If we really get a timeout then the other process should
	   exit */
	io_timeout = 0;

	if (remote_version >= 13) {
		/* in newer versions of the protocol the files can cycle through
		   the system more than once to catch initial checksum errors */
		for (i=read_int(f_recv); i != -1; i=read_int(f_recv)) {
			struct file_struct *file = flist->files[i];
			recv_generator(local_name?local_name:f_name(file),
				       flist,i,f);    
		}

		phase++;
		if (verbose > 2)
			rprintf(FINFO,"generate_files phase=%d\n",phase);

		write_int(f,-1);
	}
}
static void handle_delayed_updates(char *local_name)
{
	char *fname, *partialptr;
	int ndx;

	for (ndx = -1; (ndx = bitbag_next_bit(delayed_bits, ndx)) >= 0; ) {
		struct file_struct *file = cur_flist->files[ndx];
		fname = local_name ? local_name : f_name(file, NULL);
		if ((partialptr = partial_dir_fname(fname)) != NULL) {
			if (make_backups > 0 && !make_backup(fname))
				continue;
			if (verbose > 2) {
				rprintf(FINFO, "renaming %s to %s\n",
					partialptr, fname);
			}
			/* We don't use robust_rename() here because the
			 * partial-dir must be on the same drive. */
			if (do_rename(partialptr, fname) < 0) {
				rsyserr(FERROR_XFER, errno,
					"rename failed for %s (from %s)",
					full_fname(fname), partialptr);
			} else {
				if (remove_source_files
				 || (preserve_hard_links && F_IS_HLINKED(file)))
					send_msg_int(MSG_SUCCESS, ndx);
				handle_partial_dir(partialptr, PDIR_DELETE);
			}
		}
	}
}
示例#4
0
文件: receiver.c 项目: OPSF/uClinux
static void handle_delayed_updates(struct file_list *flist, char *local_name)
{
	char *fname, *partialptr, numbuf[4];
	int i;

	for (i = -1; (i = next_delayed_bit(i)) >= 0; ) {
		struct file_struct *file = flist->files[i];
		fname = local_name ? local_name : f_name(file);
		if ((partialptr = partial_dir_fname(fname)) != NULL) {
			if (make_backups && !make_backup(fname))
				continue;
			if (verbose > 2) {
				rprintf(FINFO, "renaming %s to %s\n",
					safe_fname(partialptr),
					safe_fname(fname));
			}
			if (do_rename(partialptr, fname) < 0) {
				rsyserr(FERROR, errno,
					"rename failed for %s (from %s)",
					full_fname(fname),
					safe_fname(partialptr));
			} else {
				if (remove_sent_files
				    || (preserve_hard_links
				     && file->link_u.links)) {
					SIVAL(numbuf, 0, i);
					send_msg(MSG_SUCCESS,numbuf,4);
				}
				handle_partial_dir(partialptr,
						   PDIR_DELETE);
			}
		}
	}
}
/**
 * Function representing the <funct_def> productions
 */
void RecursiveDescentParser::funct_def() {
	if(errorCondition) return;
	
	if(token == TK_VOID || 
		token == TK_INT ||
		token == TK_CHAR) 
	{
#if DEBUG_PARSER
		std::cout << "<funct_def> --> <f_type><f_name>(<par_list>)<par_dec_list><comp_st>\n";
#endif
	
		Type t = f_type();
		Token name = f_name();
		
		std::string label = (name == TK_MAIN) ? mainLabel : iCode.getNextLabel();
		iCode.threeAddressCode(label);
		
		FunctionEntry* entry = new FunctionEntry();
		entry->setReturnType(t);
		entry->setLabel(label);
		
		currentReturnLabel = iCode.getNextLabel();
		
		match(TK_LEFT_PARENTHESES);
		par_list();
		match(TK_RIGHT_PARENTHESES);
		
		if(symTab.search(name)) {
			// oops a function with this name has already been declared
			std::stringstream msg;
			msg << "Duplicate function declaration '" << name.getValue() << "'";
			errorHandler(msg.str(), name);
		} else {
			symTab.insert(name, entry);
		}		
		symTab.createNewTable();
		ParamList* pList = par_dec_list();
		entry->setParameterList(pList);
		
		iCode.threeAddressCode(TAC_SAVE_RET_ADDR);
		iCode.threeAddressCode(TAC_SAVE_OLD_TOPSTK);
		iCode.threeAddressCode(TAC_SET_NEW_TOPSTK);
		
		comp_st(false); /* since we explicitely called createNewTable 
							we don't want comp_st to create another */
	
		iCode.threeAddressCode(currentReturnLabel);
		iCode.threeAddressCode(TAC_RESTORE_RET_ADDR);
		iCode.threeAddressCode(TAC_RESTORE_OLD_TOPSTK);
		iCode.threeAddressCode(TAC_GOTO_RETADDR);
	}
	else 
	{
		errorHandler();
	}
}
示例#6
0
int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        std::cerr << "Usage: a.out [file.bam | file.sam]" << std::endl;
        return 1;
    }

    std::string f_name(argv[1]);
    std::cout << "File name: " << f_name << std::endl;

    bt::BamReader reader;

    if ( ! reader.Open(f_name) )
    {
        std::cerr << "Couldn't open file: " << f_name << std::endl;
        return 1;
    }

    bt::SamHeader header = reader.GetHeader();
    if ( header.IsValid() )
        std::cout << "Header is valid" << std::endl;
    else
        std::cout << "Header is INVALID!!" << std::endl;

    bt::SamSequenceDictionary dict = header.Sequences;
    std::cout << "Header info: " << std::endl;
    for (bt::SamSequenceConstIterator seq = dict.ConstBegin();
         seq != dict.ConstEnd();
         ++seq)
    {
        if ( seq->HasName() ) 
        {
            std::cout << seq->Name << '\t';
        }

        if ( seq->HasLength() )
        {
            std::cout << seq->Length;
        }

        std::cout << std::endl;
    }
    std::cout << "****************************************" << std::endl;

    bt::RefVector refVector = reader.GetReferenceData();
    bt::BamAlignment aln;
    while ( reader.GetNextAlignment(aln) )
    {
        std::cout << "'" << aln.Name << "'\t" << aln.Position << '\t'
                  << aln.GetEndPosition() << '\t' << aln.RefID << '\t'
                  << refVector[ aln.RefID ].RefName << std::endl;
    }
    return 0;
}
static void no_batched_update(int ndx, BOOL is_redo)
{
	struct file_list *flist = flist_for_ndx(ndx, "no_batched_update");
	struct file_struct *file = flist->files[ndx - flist->ndx_start];

	rprintf(FERROR_XFER, "(No batched update for%s \"%s\")\n",
		is_redo ? " resend of" : "", f_name(file, NULL));

	if (inc_recurse)
		send_msg_int(MSG_NO_SEND, ndx);
}
示例#8
0
/* check if a file should be skipped because it is the same as an
   earlier hard link */
int check_hard_link(struct file_struct *file)
{
#if SUPPORT_HARD_LINKS
	int low = 0, high = hlink_count - 1;
	int ret = 0;

	if (!hlink_list || !S_ISREG(file->mode))
		return 0;

	while (low != high) {
		int mid = (low + high) / 2;
		ret = hlink_compare(&hlink_list[mid], file);
		if (ret == 0) {
			low = mid;
			break;
		}
		if (ret > 0)
			high = mid;
		else
			low = mid + 1;
	}

	/* XXX: To me this looks kind of dodgy -- why do we use [low]
	 * here and [low-1] below? -- mbp */
	if (hlink_compare(&hlink_list[low], file) != 0)
		return 0;

	if (low > 0 &&
	    S_ISREG(hlink_list[low - 1].mode) &&
	    file->dev == hlink_list[low - 1].dev &&
	    file->inode == hlink_list[low - 1].inode) {
		if (verbose >= 2) {
			rprintf(FINFO, "check_hard_link: \"%s\" is a hard link to file %d, \"%s\"\n",
				f_name(file), low-1, f_name(&hlink_list[low-1]));
		}
		return 1;
	}
#endif

	return 0;
}
示例#9
0
文件: receiver.c 项目: OPSF/uClinux
static int get_next_gen_i(int batch_gen_fd, int next_gen_i, int desired_i)
{
	while (next_gen_i < desired_i) {
		if (next_gen_i >= 0) {
			rprintf(FINFO,
				"(No batched update for%s \"%s\")\n",
				phase ? " resend of" : "",
				safe_fname(f_name(the_file_list->files[next_gen_i])));
		}
		next_gen_i = read_int(batch_gen_fd);
		if (next_gen_i == -1)
			next_gen_i = the_file_list->count;
	}
	return next_gen_i;
}
示例#10
0
static void hard_link_one(int i)
{
	STRUCT_STAT st1, st2;

	if (link_stat(f_name(&hlink_list[i - 1]), &st1) != 0)
		return;

	if (link_stat(f_name(&hlink_list[i]), &st2) != 0) {
		if (do_link
		    (f_name(&hlink_list[i - 1]),
		     f_name(&hlink_list[i])) != 0) {
			if (verbose > 0)
				rprintf(FINFO, "link %s => %s : %s\n",
					f_name(&hlink_list[i]),
					f_name(&hlink_list[i - 1]),
					strerror(errno));
			return;
		}
	} else {
		if (st2.st_dev == st1.st_dev && st2.st_ino == st1.st_ino)
			return;

		if (robust_unlink(f_name(&hlink_list[i])) != 0 ||
		    do_link(f_name(&hlink_list[i - 1]),
			    f_name(&hlink_list[i])) != 0) {
			if (verbose > 0)
				rprintf(FINFO, "link %s => %s : %s\n",
					f_name(&hlink_list[i]),
					f_name(&hlink_list[i - 1]),
					strerror(errno));
			return;
		}
	}
	if (verbose > 0)
		rprintf(FINFO, "%s => %s\n",
			f_name(&hlink_list[i]),
			f_name(&hlink_list[i - 1]));
}
示例#11
0
/* The directory is about to be deleted: if DEL_RECURSE is given, delete all
 * its contents, otherwise just checks for content.  Returns DR_SUCCESS or
 * DR_NOT_EMPTY.  Note that fname must point to a MAXPATHLEN buffer!  (The
 * buffer is used for recursion, but returned unchanged.)
 */
static enum delret delete_dir_contents(char *fname, uint16 flags)
{
	struct file_list *dirlist;
	enum delret ret;
	unsigned remainder;
	void *save_filters;
	int j, dlen;
	char *p;

	if (DEBUG_GTE(DEL, 3)) {
		rprintf(FINFO, "delete_dir_contents(%s) flags=%d\n",
			fname, flags);
	}

	dlen = strlen(fname);
	save_filters = push_local_filters(fname, dlen);

	non_perishable_cnt = 0;
	dirlist = get_dirlist(fname, dlen, 0);
	ret = non_perishable_cnt ? DR_NOT_EMPTY : DR_SUCCESS;

	if (!dirlist->used)
		goto done;

	if (!(flags & DEL_RECURSE)) {
		ret = DR_NOT_EMPTY;
		goto done;
	}

	p = fname + dlen;
	if (dlen != 1 || *fname != '/')
		*p++ = '/';
	remainder = MAXPATHLEN - (p - fname);

	/* We do our own recursion, so make delete_item() non-recursive. */
	flags = (flags & ~(DEL_RECURSE|DEL_MAKE_ROOM|DEL_NO_UID_WRITE))
	      | DEL_DIR_IS_EMPTY;

	for (j = dirlist->used; j--; ) {
		struct file_struct *fp = dirlist->files[j];

		if (fp->flags & FLAG_MOUNT_DIR && S_ISDIR(fp->mode)) {
			if (DEBUG_GTE(DEL, 1)) {
				rprintf(FINFO,
				    "mount point, %s, pins parent directory\n",
				    f_name(fp, NULL));
			}
			ret = DR_NOT_EMPTY;
			continue;
		}

		strlcpy(p, fp->basename, remainder);
		if (!(fp->mode & S_IWUSR) && !am_root && fp->flags & FLAG_OWNED_BY_US)
			do_chmod(fname, fp->mode | S_IWUSR);
		/* Save stack by recursing to ourself directly. */
		if (S_ISDIR(fp->mode)) {
			if (delete_dir_contents(fname, flags | DEL_RECURSE) != DR_SUCCESS)
				ret = DR_NOT_EMPTY;
		}
		if (delete_item(fname, fp->mode, flags) != DR_SUCCESS)
			ret = DR_NOT_EMPTY;
	}

	fname[dlen] = '\0';

  done:
	flist_free(dirlist);
	pop_local_filters(save_filters);

	if (ret == DR_NOT_EMPTY) {
		rprintf(FINFO, "cannot delete non-empty directory: %s\n",
			fname);
	}
	return ret;
}
示例#12
0
/**
 * main routine for receiver process.
 *
 * Receiver process runs on the same host as the generator process. */
int recv_files(int f_in, char *local_name)
{
	int fd1,fd2;
	STRUCT_STAT st;
	int iflags, xlen;
	char *fname, fbuf[MAXPATHLEN];
	char xname[MAXPATHLEN];
	char fnametmp[MAXPATHLEN];
	char *fnamecmp, *partialptr;
	char fnamecmpbuf[MAXPATHLEN];
	uchar fnamecmp_type;
	struct file_struct *file;
	struct stats initial_stats;
	int itemizing = am_server ? logfile_format_has_i : stdout_format_has_i;
	enum logcode log_code = log_before_transfer ? FLOG : FINFO;
	int max_phase = protocol_version >= 29 ? 2 : 1;
	int dflt_perms = (ACCESSPERMS & ~orig_umask);
#if 0 /* was SUPPORT_ACLS */
	const char *parent_dirname = "";
#endif
	int ndx, recv_ok;

	if (verbose > 2)
		rprintf(FINFO, "recv_files(%d) starting\n", cur_flist->used);

	if (delay_updates)
		delayed_bits = bitbag_create(cur_flist->used + 1);

	while (1) {
                struct sum_struct sum;
                int numMatchTokens = -1, nextToken = 0;
                char *nextData = NULL;
                static char file_sum[MAX_DIGEST_LEN];

		cleanup_disable();

		/* This call also sets cur_flist. */
		ndx = read_ndx_and_attrs(f_in, &iflags, &fnamecmp_type,
					 xname, &xlen);
		if (ndx == NDX_DONE) {
			if (inc_recurse && first_flist) {
				if (read_batch)
					gen_wants_ndx(first_flist->used + first_flist->ndx_start);
				flist_free(first_flist);
				if (first_flist)
					continue;
			} else if (read_batch && first_flist)
				gen_wants_ndx(first_flist->used);
			if (++phase > max_phase)
				break;
			if (verbose > 2)
				rprintf(FINFO, "recv_files phase=%d\n", phase);
			if (phase == 2 && delay_updates)
				handle_delayed_updates(local_name);
			send_msg(MSG_DONE, "", 0, 0);
			continue;
		}

		if (ndx - cur_flist->ndx_start >= 0)
			file = cur_flist->files[ndx - cur_flist->ndx_start];
		else
			file = dir_flist->files[cur_flist->parent_ndx];
		fname = local_name ? local_name : f_name(file, fbuf);

		if (verbose > 2)
			rprintf(FINFO, "recv_files(%s)\n", fname);

#ifdef SUPPORT_XATTRS
		if (preserve_xattrs && iflags & ITEM_REPORT_XATTR && do_xfers)
			recv_xattr_request(file, f_in);
#endif

		if (!(iflags & ITEM_TRANSFER)) {
			maybe_log_item(file, iflags, itemizing, xname);
#ifdef SUPPORT_XATTRS
			if (preserve_xattrs && iflags & ITEM_REPORT_XATTR && do_xfers
			 && !BITS_SET(iflags, ITEM_XNAME_FOLLOWS|ITEM_LOCAL_CHANGE))
				set_file_attrs(fname, file, NULL, fname, 0);
#endif
			continue;
		}
		if (phase == 2) {
			rprintf(FERROR,
				"got transfer request in phase 2 [%s]\n",
				who_am_i());
			exit_cleanup(RERR_PROTOCOL);
		}

		if (file->flags & FLAG_FILE_SENT) {
			if (csum_length == SHORT_SUM_LENGTH) {
				if (keep_partial && !partial_dir)
					make_backups = -make_backups; /* prevents double backup */
				if (append_mode)
					sparse_files = -sparse_files;
				append_mode = -append_mode;
				csum_length = SUM_LENGTH;
				redoing = 1;
			}
		} else {
			if (csum_length != SHORT_SUM_LENGTH) {
				if (keep_partial && !partial_dir)
					make_backups = -make_backups;
				if (append_mode)
					sparse_files = -sparse_files;
				append_mode = -append_mode;
				csum_length = SHORT_SUM_LENGTH;
				redoing = 0;
			}
		}

		if (!am_server && do_progress)
			set_current_file_index(file, ndx);
		stats.num_transferred_files++;
		stats.total_transferred_size += F_LENGTH(file);

		cleanup_got_literal = 0;

		if (daemon_filter_list.head
		    && check_filter(&daemon_filter_list, FLOG, fname, 0) < 0) {
			rprintf(FERROR, "attempt to hack rsync failed.\n");
			exit_cleanup(RERR_PROTOCOL);
		}

                read_sum_head(f_in, &sum);

		if (read_batch) {
			int wanted = redoing
				   ? we_want_redo(ndx)
				   : gen_wants_ndx(ndx);
			if (!wanted) {
				rprintf(FINFO,
					"(Skipping batched update for%s \"%s\")\n",
					redoing ? " resend of" : "",
					fname);
				discard_receive_data(f_in, F_LENGTH(file),
                                                     &sum, numMatchTokens, nextToken, nextData, file_sum);
				file->flags |= FLAG_FILE_SENT;
				continue;
			}
		}

		if (!do_xfers) { /* log the transfer */
			log_item(FCLIENT, file, &stats, iflags, NULL);
			if (read_batch)
				discard_receive_data(f_in, F_LENGTH(file),
                                                     &sum, numMatchTokens, nextToken, nextData, file_sum);
			continue;
		}
		if (write_batch < 0) {
			log_item(FCLIENT, file, &stats, iflags, NULL);
			if (!am_server)
				discard_receive_data(f_in, F_LENGTH(file),
                                                     &sum, numMatchTokens, nextToken, nextData, file_sum);
			continue;
		}

		partialptr = partial_dir ? partial_dir_fname(fname) : fname;

		if (protocol_version >= 29) {
			switch (fnamecmp_type) {
			case FNAMECMP_FNAME:
				fnamecmp = fname;
				break;
			case FNAMECMP_PARTIAL_DIR:
				fnamecmp = partialptr;
				break;
			case FNAMECMP_BACKUP:
				fnamecmp = get_backup_name(fname);
				break;
			case FNAMECMP_FUZZY:
				if (file->dirname) {
					pathjoin(fnamecmpbuf, MAXPATHLEN,
						 file->dirname, xname);
					fnamecmp = fnamecmpbuf;
				} else
					fnamecmp = xname;
				break;
			default:
				if (fnamecmp_type >= basis_dir_cnt) {
					rprintf(FERROR,
						"invalid basis_dir index: %d.\n",
						fnamecmp_type);
					exit_cleanup(RERR_PROTOCOL);
				}
				pathjoin(fnamecmpbuf, sizeof fnamecmpbuf,
					 basis_dir[fnamecmp_type], fname);
				fnamecmp = fnamecmpbuf;
				break;
			}
			if (!fnamecmp || (daemon_filter_list.head
			  && check_filter(&daemon_filter_list, FLOG, fname, 0) < 0)) {
				fnamecmp = fname;
				fnamecmp_type = FNAMECMP_FNAME;
			}
		} else {
			/* Reminder: --inplace && --partial-dir are never
			 * enabled at the same time. */
			if (inplace && make_backups > 0) {
				if (!(fnamecmp = get_backup_name(fname)))
					fnamecmp = fname;
				else
					fnamecmp_type = FNAMECMP_BACKUP;
			} else if (partial_dir && partialptr)
				fnamecmp = partialptr;
			else
				fnamecmp = fname;
		}

		initial_stats = stats;

                /*
                 * Opening/reading/writing files in BackupPC is quite expensive, given the
                 * compression.  Before we open the file and call mkstemp, we peek ahead at
                 * the delta tokens to see if the file is unchanged.  If so, we skip the file
                 * open, mkstemp and writing.  The file is unchanged if the tokens
                 * are sequential matching block numbers, which are encoded as
                 * negative integers (ie: -1, -2, -3...), with no literal data
                 * tokens (which have positive numbers).
                 *
                 * If the file has changed, at some point a matching block token
                 * will be out of order, or we will encounter a literal data token.
                 * At that point, we stop reading ahead and proceed as normal.
                 * We pass the number of matching block tokens, and the first
                 * unexpected token, to receive_data(), so it can process all
                 * the tokens back (basically playing them back).
                 *
                 * Of course, this only applies if the file exists already,
                 * and protocol_version 30 is required since older protocols
                 * use MD4 for the full-file digest, not MD5.
                 *
                 * First we need to read the sum struct, then start reading the
                 * tokens.
                 */
                recv_ok = 0;
                if ( protocol_version >= 30 ) {
                    numMatchTokens = 0;
                    while ( (nextToken = recv_token(f_in, &nextData)) != 0 ) {
                        if ( nextToken != -numMatchTokens - 1 ) break;
                        numMatchTokens++;
                    }
                    if ( nextToken == 0 ) {
                        OFF_T flength = (OFF_T)numMatchTokens * sum.blength;
                        if ( sum.remainder && numMatchTokens > 0 )
                                flength -= sum.blength - sum.remainder;
                        /*
                         * Likely exact match - read the final file digest and make
                         * sure the digest and file size match the existing file.
                         * If so, this call creates the temporary file so the
                         * attributes can be checked/set, and then renamed as
                         * before.
                         */
                        read_buf(f_in, file_sum, MD5_DIGEST_LEN);
                        if ( !bpc_sysCall_checkFileMatch(fnamecmp, fnametmp, file, file_sum, flength) ) {
                            recv_ok = 1;
                            if ( log_before_transfer ) {
                                iflags &= ~ITEM_REPORT_CHANGE;
                                log_item(FCLIENT, file, &initial_stats, iflags, NULL);
                            }
                        }
                    }
                }
                if ( !recv_ok ) {
                    /*
                     * proceed as normal, remembering to replay the tokens we read ahead above:
                     * first, numMatchTokens: -1, -2, ..., -numMatchTokens,
                     * then (nextToken,nextData).  After that we go back to reading the
                     * remaining tokens from f_in.
                     */

                    /* open the file */
                    fd1 = do_open(fnamecmp, O_RDONLY, 0);

                    if ( fd1 < 0 && protocol_version >= 30 && always_checksum ) {
                        /*
                         * For protocol_version >= 30 and if always_checksum is set, we can use the
                         * MD5 whole-file digest to check for a potential match via the pool.
                         * Use that as the basis if the file is there.  The generator does
                         * the same in recv_generator().
                         */
                        if ( S_ISREG(file->mode) && !bpc_sysCall_poolFileCheck(fnamecmp, file) ) {
                            fd1 = do_open(fnamecmp, O_RDONLY, 0);
                        }
                    }

                    if (fd1 == -1 && protocol_version < 29) {
                            if (fnamecmp != fname) {
                                    fnamecmp = fname;
                                    fd1 = do_open(fnamecmp, O_RDONLY, 0);
                            }

                            if (fd1 == -1 && basis_dir[0]) {
                                    /* pre-29 allowed only one alternate basis */
                                    pathjoin(fnamecmpbuf, sizeof fnamecmpbuf,
                                             basis_dir[0], fname);
                                    fnamecmp = fnamecmpbuf;
                                    fd1 = do_open(fnamecmp, O_RDONLY, 0);
                            }
                    }

                    updating_basis_or_equiv = inplace
                        && (fnamecmp == fname || fnamecmp_type == FNAMECMP_BACKUP);

                    if (fd1 == -1) {
                            st.st_mode = 0;
                            st.st_size = 0;
                    } else if (do_fstat(fd1,&st) != 0) {
                            rsyserr(FERROR_XFER, errno, "fstat %s failed",
                                    full_fname(fnamecmp));
                            discard_receive_data(f_in, F_LENGTH(file),
                                                 &sum, numMatchTokens, nextToken, nextData, file_sum);
                            bpc_close(fd1);
                            if (inc_recurse)
                                    send_msg_int(MSG_NO_SEND, ndx);
                            continue;
                    }

                    if (fd1 != -1 && S_ISDIR(st.st_mode) && fnamecmp == fname) {
                            /* this special handling for directories
                             * wouldn't be necessary if robust_rename()
                             * and the underlying robust_unlink could cope
                             * with directories
                             */
                            rprintf(FERROR_XFER, "recv_files: %s is a directory\n",
                                    full_fname(fnamecmp));
                            discard_receive_data(f_in, F_LENGTH(file),
                                                 &sum, numMatchTokens, nextToken, nextData, file_sum);
                            bpc_close(fd1);
                            if (inc_recurse)
                                    send_msg_int(MSG_NO_SEND, ndx);
                            continue;
                    }

                    if (fd1 != -1 && !S_ISREG(st.st_mode)) {
                            bpc_close(fd1);
                            fd1 = -1;
                    }

                    /* If we're not preserving permissions, change the file-list's
                     * mode based on the local permissions and some heuristics. */
                    if (!preserve_perms) {
                            int exists = fd1 != -1;
    #if 0 /* was SUPPORT_ACLS */
                            const char *dn = file->dirname ? file->dirname : ".";
                            if (parent_dirname != dn
                             && strcmp(parent_dirname, dn) != 0) {
                                    dflt_perms = default_perms_for_dir(dn);
                                    parent_dirname = dn;
                            }
    #endif
                            file->mode = dest_mode(file->mode, st.st_mode,
                                                   dflt_perms, exists);
                    }

                    /* We now check to see if we are writing the file "inplace" */
                    if (inplace)  {
                            fd2 = do_open(fname, O_WRONLY|O_CREAT, 0600);
                            if (fd2 == -1) {
                                    rsyserr(FERROR_XFER, errno, "open %s failed",
                                            full_fname(fname));
                            }
                    } else {
                            fd2 = open_tmpfile(fnametmp, fname, file);
                            if (fd2 != -1)
                                    cleanup_set(fnametmp, partialptr, file, fd1, fd2);
                    }

                    if (fd2 == -1) {
                            discard_receive_data(f_in, F_LENGTH(file),
                                                 &sum, numMatchTokens, nextToken, nextData, file_sum);
                            if (fd1 != -1)
                                    bpc_close(fd1);
                            if (inc_recurse)
                                    send_msg_int(MSG_NO_SEND, ndx);
                            continue;
                    }

                    /* log the transfer */
                    if (log_before_transfer)
                            log_item(FCLIENT, file, &initial_stats, iflags, NULL);
                    else if (!am_server && verbose && do_progress)
                            rprintf(FINFO, "%s\n", fname);

                    /* recv file data */
                    recv_ok = receive_data(f_in, fnamecmp, fd1, st.st_size,
                                           fname, fd2, F_LENGTH(file),
                                           &sum, numMatchTokens, nextToken, nextData, file_sum);

                    if (fd1 != -1)
                            bpc_close(fd1);
                    if (bpc_close(fd2) < 0) {
                            rsyserr(FERROR, errno, "close failed on %s",
                                    full_fname(fnametmp));
                            exit_cleanup(RERR_FILEIO);
                    }
                }

                log_item(log_code, file, &initial_stats, iflags, NULL);

		if ((recv_ok && (!delay_updates || !partialptr)) || inplace) {
			if (partialptr == fname)
				partialptr = NULL;
			if (!finish_transfer(fname, fnametmp, fnamecmp,
					     partialptr, file, recv_ok, 1))
				recv_ok = -1;
			else if (fnamecmp == partialptr) {
				do_unlink(partialptr);
				handle_partial_dir(partialptr, PDIR_DELETE);
			}
		} else if (keep_partial && partialptr) {
			if (!handle_partial_dir(partialptr, PDIR_CREATE)) {
				rprintf(FERROR,
				    "Unable to create partial-dir for %s -- discarding %s.\n",
				    local_name ? local_name : f_name(file, NULL),
				    recv_ok ? "completed file" : "partial file");
				do_unlink(fnametmp);
				recv_ok = -1;
			} else if (!finish_transfer(partialptr, fnametmp, fnamecmp, NULL,
						    file, recv_ok, !partial_dir))
				recv_ok = -1;
			else if (delay_updates && recv_ok) {
				bitbag_set_bit(delayed_bits, ndx);
				recv_ok = 2;
			} else
				partialptr = NULL;
		} else
			do_unlink(fnametmp);

		cleanup_disable();

		if (read_batch)
			file->flags |= FLAG_FILE_SENT;

		switch (recv_ok) {
		case 2:
			break;
		case 1:
			if (remove_source_files || inc_recurse
			 || (preserve_hard_links && F_IS_HLINKED(file)))
				send_msg_int(MSG_SUCCESS, ndx);
			break;
		case 0: {
			enum logcode msgtype = redoing ? FERROR_XFER : FWARNING;
			if (msgtype == FERROR_XFER || verbose) {
				char *errstr, *redostr, *keptstr;
				if (!(keep_partial && partialptr) && !inplace)
					keptstr = "discarded";
				else if (partial_dir)
					keptstr = "put into partial-dir";
				else
					keptstr = "retained";
				if (msgtype == FERROR_XFER) {
					errstr = "ERROR";
					redostr = "";
				} else {
					errstr = "WARNING";
					redostr = read_batch ? " (may try again)"
							     : " (will try again)";
				}
				rprintf(msgtype,
					"%s: %s failed verification -- update %s%s.\n",
					errstr, local_name ? f_name(file, NULL) : fname,
					keptstr, redostr);
			}
			if (!redoing) {
				if (read_batch)
					flist_ndx_push(&batch_redo_list, ndx);
				send_msg_int(MSG_REDO, ndx);
				file->flags |= FLAG_FILE_SENT;
                                bpc_sysCall_printfileStatus(fname, "retry");
			} else if (inc_recurse)
				send_msg_int(MSG_NO_SEND, ndx);
                                bpc_sysCall_printfileStatus(fname, "fail");
			break;
		    }
		case -1:
			if (inc_recurse)
				send_msg_int(MSG_NO_SEND, ndx);
			break;
		}
	}
	if (make_backups < 0)
		make_backups = -make_backups;

	if (phase == 2 && delay_updates) /* for protocol_version < 29 */
		handle_delayed_updates(local_name);

	if (verbose > 2)
		rprintf(FINFO,"recv_files finished\n");

	return 0;
}
示例#13
0
/**
 * Acts on file number @p i from @p flist, whose name is @p fname.
 *
 * First fixes up permissions, then generates checksums for the file.
 *
 * @note This comment was added later by mbp who was trying to work it
 * out.  It might be wrong.
 **/ 
int recv_generator(char *fname, struct file_list *flist, int i, int f_out)
{  
	int fd;
	STRUCT_STAT st;
	struct map_struct *buf;
	struct sum_struct *s;
	int statret;
	struct file_struct *file = flist->files[i];
	struct timeval tv_start;
	char *fnamecmp;
	char fnamecmpbuf[MAXPATHLEN];
	extern char *compare_dest;
	extern int list_only;
	extern int preserve_perms;
	extern int only_existing;
	extern int orig_umask;

	if (list_only) return 0;

	if (verbose > 2)
		rprintf(FINFO,"recv_generator(%s,%d)\n",fname,i);

	statret = link_stat(fname,&st);

	if (only_existing && statret == -1 && errno == ENOENT) {
		/* we only want to update existing files */
		if (verbose > 1) rprintf(FINFO, "not creating new file \"%s\"\n",fname);
		return 0;
	}

	if (statret == 0 && 
	    !preserve_perms && 
	    (S_ISDIR(st.st_mode) == S_ISDIR(file->mode))) {
		/* if the file exists already and we aren't perserving
                   presmissions then act as though the remote end sent
                   us the file permissions we already have */
		file->mode = (file->mode & _S_IFMT) | (st.st_mode & ~_S_IFMT);
	}

	if (S_ISDIR(file->mode)) {
                /* The file to be received is a directory, so we need
                 * to prepare appropriately.  If there is already a
                 * file of that name and it is *not* a directory, then
                 * we need to delete it.  If it doesn't exist, then
                 * recursively create it. */
          
		if (dry_run) return 0; /* XXXX -- might cause inaccuracies?? -- mbp */
		if (statret == 0 && !S_ISDIR(st.st_mode)) {
			if (robust_unlink(fname) != 0) {
				rprintf(FERROR, RSYNC_NAME
					": recv_generator: unlink \"%s\" to make room for directory: %s\n",
                                        fname,strerror(errno));
				return 0;
			}
			statret = -1;
		}
		if (statret != 0 && do_mkdir(fname,file->mode) != 0 && errno != EEXIST) {
			if (!(relative_paths && errno==ENOENT && 
			      create_directory_path(fname, orig_umask)==0 && 
			      do_mkdir(fname,file->mode)==0)) {
				rprintf(FERROR, RSYNC_NAME ": recv_generator: mkdir \"%s\": %s (2)\n",
					fname,strerror(errno));
			}
		}
		/* f_out is set to -1 when doing final directory 
		   permission and modification time repair */
		if (set_perms(fname,file,NULL,0) && verbose && (f_out != -1)) 
			rprintf(FINFO,"%s/\n",fname);
		return 0;
	}

	if (preserve_links && S_ISLNK(file->mode)) {
#if SUPPORT_LINKS
		char lnk[MAXPATHLEN];
		int l;
		extern int safe_symlinks;

		if (safe_symlinks && unsafe_symlink(file->link, fname)) {
			if (verbose) {
				rprintf(FINFO,"ignoring unsafe symlink \"%s\" -> \"%s\"\n",
					fname,file->link);
			}
			return 0;
		}
		if (statret == 0) {
			l = readlink(fname,lnk,MAXPATHLEN-1);
			if (l > 0) {
				lnk[l] = 0;
				/* A link already pointing to the
				 * right place -- no further action
				 * required. */
				if (strcmp(lnk,file->link) == 0) {
					set_perms(fname,file,&st,1);
					return 0;
				}
			}  
			/* Not a symlink, so delete whatever's
			 * already there and put a new symlink
			 * in place. */			   
			delete_file(fname);
		}
		if (do_symlink(file->link,fname) != 0) {
			rprintf(FERROR,RSYNC_NAME": symlink \"%s\" -> \"%s\": %s\n",
				fname,file->link,strerror(errno));
		} else {
			set_perms(fname,file,NULL,0);
			if (verbose) {
				rprintf(FINFO,"%s -> %s\n", fname,file->link);
			}
		}
#endif
		return 0;
	}

#ifdef HAVE_MKNOD
	if (am_root && preserve_devices && IS_DEVICE(file->mode)) {
		if (statret != 0 || 
		    st.st_mode != file->mode ||
		    st.st_rdev != file->rdev) {	
			delete_file(fname);
			if (verbose > 2)
				rprintf(FINFO,"mknod(%s,0%o,0x%x)\n",
					fname,(int)file->mode,(int)file->rdev);
			if (do_mknod(fname,file->mode,file->rdev) != 0) {
				rprintf(FERROR,"mknod %s : %s\n",fname,strerror(errno));
			} else {
				set_perms(fname,file,NULL,0);
				if (verbose)
					rprintf(FINFO,"%s\n",fname);
			}
		} else {
			set_perms(fname,file,&st,1);
		}
		return 0;
	}
#endif

	if (preserve_hard_links && check_hard_link(file)) {
		if (verbose > 1)
			rprintf(FINFO, "recv_generator: \"%s\" is a hard link\n",f_name(file));
		return 0;
	}

	if (!S_ISREG(file->mode)) {
		rprintf(FINFO, "skipping non-regular file \"%s\"\n",fname);
		return 0;
	}

	fnamecmp = fname;

	if ((statret == -1) && (compare_dest != NULL)) {
		/* try the file at compare_dest instead */
		int saveerrno = errno;
		snprintf(fnamecmpbuf,MAXPATHLEN,"%s/%s",compare_dest,fname);
		statret = link_stat(fnamecmpbuf,&st);
		if (!S_ISREG(st.st_mode))
			statret = -1;
		if (statret == -1)
			errno = saveerrno;
		else
			fnamecmp = fnamecmpbuf;
	}

	if (statret == -1) {
		if (errno == ENOENT) {
			write_int(f_out,i);
			if (!dry_run) {
			    if(do_stats){
				gettimeofday(&tv_start,0);
				rprintf(FINFO, "File start: %s time: %d %d\n",fnamecmp,
				    tv_start.tv_sec,
				    tv_start.tv_usec);
			    }
			    send_sums(NULL,f_out);
			return 1;
			}
		} else {
			if (verbose > 1)
				rprintf(FERROR, RSYNC_NAME
					": recv_generator failed to open \"%s\": %s\n",
					fname, strerror(errno));
			return 0;
		}
	}

	if (!S_ISREG(st.st_mode)) {
		if (delete_file(fname) != 0) {
			return 0;
		}
		if(do_stats){
		    gettimeofday(&tv_start,0);
		    rprintf(FINFO, "File start: %s time: %d %d\n",fnamecmp,
			tv_start.tv_sec,
			tv_start.tv_usec);
		}

		/* now pretend the file didn't exist */
		write_int(f_out,i);
		if (!dry_run) send_sums(NULL,f_out);    
		return 1;
	}

	if (opt_ignore_existing && fnamecmp == fname) { 
		if (verbose > 1)
			rprintf(FINFO,"%s exists\n",fname);
		return 0;
	} 

	if (update_only && cmp_modtime(st.st_mtime,file->modtime)>0 && fnamecmp == fname) {
		if (verbose > 1)
			rprintf(FINFO,"%s is newer\n",fname);
		return 0;
	}

	if (skip_file(fname, file, &st)) {
		if (fnamecmp == fname)
			set_perms(fname,file,&st,1);
		return 0;
	}

	if (dry_run) {
		if(do_stats){
		    gettimeofday(&tv_start,0);
		    rprintf(FINFO, "File start: %s time: %d %d\n",fnamecmp,
			tv_start.tv_sec,
			tv_start.tv_usec);
		}
		write_int(f_out,i);
		return 1;
	}

	if (disable_deltas_p()) {
		if(do_stats){
		    gettimeofday(&tv_start,0);
		    rprintf(FINFO, "File start: %s time: %d %d\n",fnamecmp,
			tv_start.tv_sec,
			tv_start.tv_usec);
		}
		write_int(f_out,i);
		send_sums(NULL,f_out);    
		return 1;
	}
	if(do_stats){
	    gettimeofday(&tv_start,0);
	    rprintf(FINFO, "File start: %s time: %d %d\n",fnamecmp,
		    tv_start.tv_sec,
		    tv_start.tv_usec);
	}
	/* open the file */  
	fd = do_open(fnamecmp, O_RDONLY, 0);

	if (fd == -1) {
		rprintf(FERROR,RSYNC_NAME": failed to open \"%s\", continuing : %s\n",fnamecmp,strerror(errno));
		/* pretend the file didn't exist */
		write_int(f_out,i);
		send_sums(NULL,f_out);
		return 1;
	}

	if (st.st_size > 0) {
		buf = map_file(fd,st.st_size);
	} else {
		buf = NULL;
	}

	if (verbose > 3)
		rprintf(FINFO,"gen mapped %s of size %.0f\n",fnamecmp,(double)st.st_size);

	if(do_stats){
	    timing(TIMING_START);
	}
	s = generate_sums(buf,st.st_size,adapt_block_size(file, block_size));

	if(do_stats){
	    rprintf(FINFO, "Generator: %s %s\n", fnamecmp,timing(TIMING_END));
	}

	if (verbose > 2)
		rprintf(FINFO,"sending sums for %d\n",i);

	write_int(f_out,i);
	if(do_stats){
	    timing(TIMING_START);
	}
	send_sums(s,f_out);

	if(do_stats){
	    rprintf(FINFO, "Send sums: %s %s\n", fnamecmp,timing(TIMING_END));
	}
	close(fd);
	if (buf) unmap_file(buf);

	free_sums(s);
	return 1;
}
示例#14
0
/* if we have a backup_dir, then we get here from make_backup().
   We will move the file to be deleted into a parallel directory tree */
static int keep_backup(char *fname)
{

	static int initialised;

	char keep_name [MAXPATHLEN];
	STRUCT_STAT st;
	struct file_struct *file;

	int kept=0;
	int ret_code;

	if (!initialised) {
		if (backup_dir[strlen(backup_dir) - 1] == '/')
			backup_dir[strlen(backup_dir) - 1] = 0;
		if (verbose > 0)
			rprintf (FINFO, "backup_dir is %s\n", backup_dir);
		initialised = 1;
	}

	/* return if no file to keep */
#if SUPPORT_LINKS
	if (do_lstat (fname, &st)) return 1;
#else
	if (do_stat (fname, &st)) return 1;
#endif

	file = make_file(-1, fname, NULL, 1);

	/* the file could have disappeared */
	if (!file) return 1;

        /* make a complete pathname for backup file */
        if (strlen(backup_dir) + strlen(fname) + 
		(suffix_specified ? strlen(backup_suffix) : 0) > (MAXPATHLEN - 1)) {
                rprintf (FERROR, "keep_backup filename too long\n");
                return 0;
        }

	if (suffix_specified) {
        	snprintf(keep_name, sizeof (keep_name), "%s/%s%s", backup_dir, fname, backup_suffix);
		} else {
        	snprintf(keep_name, sizeof (keep_name), "%s/%s", backup_dir, fname);
		}


#ifdef HAVE_MKNOD
	/* Check to see if this is a device file, or link */
        if(IS_DEVICE(file->mode)) {
                if(am_root && preserve_devices) {
                        make_bak_dir(fname,backup_dir);
                        if(do_mknod(keep_name,file->mode,file->rdev)!=0) {
                                rprintf(FERROR,"mknod %s : %s\n",keep_name,strerror(errno));
                        } else {
                                if(verbose>2)
                                        rprintf(FINFO,"make_backup : DEVICE %s successful.\n",fname);
                        };
                };
		kept=1;
                do_unlink(fname);
        };
#endif

	if(!kept && S_ISDIR(file->mode)) {
		/* make an empty directory */
                make_bak_dir(fname,backup_dir);
                do_mkdir(keep_name,file->mode);
                ret_code=do_rmdir(fname);
                if(verbose>2)
                        rprintf(FINFO,"make_backup : RMDIR %s returns %i\n",fname,ret_code);
		kept=1;
        };

#if SUPPORT_LINKS
        if(!kept && preserve_links && S_ISLNK(file->mode)) {
                extern int safe_symlinks;
                if (safe_symlinks && unsafe_symlink(file->link, keep_name)) {
                        if (verbose) {
                                rprintf(FINFO,"ignoring unsafe symlink %s -> %s\n",
                                        keep_name,file->link);
                        }
			kept=1;
                }
                make_bak_dir(fname,backup_dir);
                if(do_symlink(file->link,keep_name) != 0) {
                        rprintf(FERROR,"link %s -> %s : %s\n",keep_name,file->link,strerror(errno));
                };
                do_unlink(fname);
		kept=1;
        };
#endif
        if(!kept && preserve_hard_links && check_hard_link(file)) {
                if(verbose > 1) rprintf(FINFO,"%s is a hard link\n",f_name(file));
        };

        if(!kept && !S_ISREG(file->mode)) {
                rprintf(FINFO,"make_bak: skipping non-regular file %s\n",fname);
        }

	/* move to keep tree if a file */
	if(!kept) {
		if (!robust_move (fname, keep_name))
			rprintf(FERROR, "keep_backup failed %s -> %s : %s\n",
				fname, keep_name, strerror(errno));
	};
	set_perms (keep_name, file, NULL, 0);
	free_file (file);
	free (file);

	if (verbose > 1)
		rprintf (FINFO, "keep_backup %s -> %s\n", fname, keep_name);
	return 1;
} /* keep_backup */
示例#15
0
void recv_generator(char *fname,struct file_list *flist,int i,int f_out)
{  
	int fd;
	STRUCT_STAT st;
	struct map_struct *buf;
	struct sum_struct *s;
	int statret;
	struct file_struct *file = flist->files[i];
	char *fnamecmp;
	char fnamecmpbuf[MAXPATHLEN];
	extern char *compare_dest;
	extern int list_only;

	if (list_only) return;

	if (verbose > 2)
		rprintf(FINFO,"recv_generator(%s,%d)\n",fname,i);

	statret = link_stat(fname,&st);

	if (S_ISDIR(file->mode)) {
		if (dry_run) return;
		if (statret == 0 && !S_ISDIR(st.st_mode)) {
			if (robust_unlink(fname) != 0) {
				rprintf(FERROR,"unlink %s : %s\n",fname,strerror(errno));
				return;
			}
			statret = -1;
		}
		if (statret != 0 && do_mkdir(fname,file->mode) != 0 && errno != EEXIST) {
			if (!(relative_paths && errno==ENOENT && 
			      create_directory_path(fname)==0 && 
			      do_mkdir(fname,file->mode)==0)) {
				rprintf(FERROR,"mkdir %s : %s (2)\n",
					fname,strerror(errno));
			}
		}
		if (set_perms(fname,file,NULL,0) && verbose) 
			rprintf(FINFO,"%s/\n",fname);
		return;
	}

	if (preserve_links && S_ISLNK(file->mode)) {
#if SUPPORT_LINKS
		char lnk[MAXPATHLEN];
		int l;
		extern int safe_symlinks;

		if (safe_symlinks && unsafe_symlink(file->link, fname)) {
			if (verbose) {
				rprintf(FINFO,"ignoring unsafe symlink %s -> %s\n",
					fname,file->link);
			}
			return;
		}
		if (statret == 0) {
			l = readlink(fname,lnk,MAXPATHLEN-1);
			if (l > 0) {
				lnk[l] = 0;
				if (strcmp(lnk,file->link) == 0) {
					set_perms(fname,file,&st,1);
					return;
				}
			}
		}
		delete_file(fname);
		if (do_symlink(file->link,fname) != 0) {
			rprintf(FERROR,"link %s -> %s : %s\n",
				fname,file->link,strerror(errno));
		} else {
			set_perms(fname,file,NULL,0);
			if (verbose) {
				rprintf(FINFO,"%s -> %s\n",
					fname,file->link);
			}
		}
#endif
		return;
	}

#ifdef HAVE_MKNOD
	if (am_root && preserve_devices && IS_DEVICE(file->mode)) {
		if (statret != 0 || 
		    st.st_mode != file->mode ||
		    st.st_rdev != file->rdev) {	
			delete_file(fname);
			if (verbose > 2)
				rprintf(FINFO,"mknod(%s,0%o,0x%x)\n",
					fname,(int)file->mode,(int)file->rdev);
			if (do_mknod(fname,file->mode,file->rdev) != 0) {
				rprintf(FERROR,"mknod %s : %s\n",fname,strerror(errno));
			} else {
				set_perms(fname,file,NULL,0);
				if (verbose)
					rprintf(FINFO,"%s\n",fname);
			}
		} else {
			set_perms(fname,file,&st,1);
		}
		return;
	}
#endif

	if (preserve_hard_links && check_hard_link(file)) {
		if (verbose > 1)
			rprintf(FINFO,"%s is a hard link\n",f_name(file));
		return;
	}

	if (!S_ISREG(file->mode)) {
		rprintf(FINFO,"skipping non-regular file %s\n",fname);
		return;
	}

	fnamecmp = fname;

	if ((statret == -1) && (compare_dest != NULL)) {
		/* try the file at compare_dest instead */
		int saveerrno = errno;
		slprintf(fnamecmpbuf,MAXPATHLEN,"%s/%s",compare_dest,fname);
		statret = link_stat(fnamecmpbuf,&st);
		if (!S_ISREG(st.st_mode))
			statret = -1;
		if (statret == -1)
			errno = saveerrno;
		else
			fnamecmp = fnamecmpbuf;
	}

	if (statret == -1) {
		if (errno == ENOENT) {
			write_int(f_out,i);
			if (!dry_run) send_sums(NULL,f_out);
		} else {
			if (verbose > 1)
				rprintf(FERROR,"recv_generator failed to open %s\n",fname);
		}
		return;
	}

	if (!S_ISREG(st.st_mode)) {
		if (delete_file(fname) != 0) {
			return;
		}

		/* now pretend the file didn't exist */
		write_int(f_out,i);
		if (!dry_run) send_sums(NULL,f_out);    
		return;
	}

	if (update_only && st.st_mtime > file->modtime && fnamecmp == fname) {
		if (verbose > 1)
			rprintf(FINFO,"%s is newer\n",fname);
		return;
	}

	if (skip_file(fname, file, &st)) {
		if (fnamecmp == fname)
			set_perms(fname,file,&st,1);
		return;
	}

	if (dry_run) {
		write_int(f_out,i);
		return;
	}

	if (whole_file) {
		write_int(f_out,i);
		send_sums(NULL,f_out);    
		return;
	}

	/* open the file */  
	fd = open(fnamecmp,O_RDONLY);

	if (fd == -1) {
		rprintf(FERROR,"failed to open %s : %s\n",fnamecmp,strerror(errno));
		rprintf(FERROR,"skipping %s\n",fname);
		return;
	}

	if (st.st_size > 0) {
		buf = map_file(fd,st.st_size);
	} else {
		buf = NULL;
	}

	if (verbose > 3)
		rprintf(FINFO,"gen mapped %s of size %d\n",fnamecmp,(int)st.st_size);

	s = generate_sums(buf,st.st_size,adapt_block_size(file, block_size));

	if (verbose > 2)
		rprintf(FINFO,"sending sums for %d\n",i);

	write_int(f_out,i);
	send_sums(s,f_out);

	close(fd);
	if (buf) unmap_file(buf);

	free_sums(s);
}
示例#16
0
/**
 * main routine for receiver process.
 *
 * Receiver process runs on the same host as the generator process. */
int recv_files(int f_in, char *local_name)
{
	int fd1,fd2;
	STRUCT_STAT st;
	int iflags, xlen;
	char *fname, fbuf[MAXPATHLEN];
	char xname[MAXPATHLEN];
	char fnametmp[MAXPATHLEN];
	char *fnamecmp, *partialptr;
	char fnamecmpbuf[MAXPATHLEN];
	uchar fnamecmp_type;
	struct file_struct *file;
	struct stats initial_stats;
	int itemizing = am_server ? logfile_format_has_i : stdout_format_has_i;
	enum logcode log_code = log_before_transfer ? FLOG : FINFO;
	int max_phase = protocol_version >= 29 ? 2 : 1;
	int dflt_perms = (ACCESSPERMS & ~orig_umask);
#ifdef SUPPORT_ACLS
	const char *parent_dirname = "";
#endif
	int ndx, recv_ok;

	if (verbose > 2)
		rprintf(FINFO, "recv_files(%d) starting\n", cur_flist->used);

	if (delay_updates)
		delayed_bits = bitbag_create(cur_flist->used + 1);

	while (1) {
		cleanup_disable();

		/* This call also sets cur_flist. */
		ndx = read_ndx_and_attrs(f_in, &iflags, &fnamecmp_type,
					 xname, &xlen);
		if (ndx == NDX_DONE) {
			if (inc_recurse && first_flist) {
				if (read_batch)
					gen_wants_ndx(first_flist->used + first_flist->ndx_start);
				flist_free(first_flist);
				if (first_flist)
					continue;
			} else if (read_batch && first_flist)
				gen_wants_ndx(first_flist->used);
			if (++phase > max_phase)
				break;
			if (verbose > 2)
				rprintf(FINFO, "recv_files phase=%d\n", phase);
			if (phase == 2 && delay_updates)
				handle_delayed_updates(local_name);
			send_msg(MSG_DONE, "", 0, 0);
			continue;
		}

		if (ndx - cur_flist->ndx_start >= 0)
			file = cur_flist->files[ndx - cur_flist->ndx_start];
		else
			file = dir_flist->files[cur_flist->parent_ndx];
		fname = local_name ? local_name : f_name(file, fbuf);

		if (verbose > 2)
			rprintf(FINFO, "recv_files(%s)\n", fname);

#ifdef SUPPORT_XATTRS
		if (iflags & ITEM_REPORT_XATTR && !dry_run)
			recv_xattr_request(file, f_in);
#endif

		if (!(iflags & ITEM_TRANSFER)) {
			maybe_log_item(file, iflags, itemizing, xname);
#ifdef SUPPORT_XATTRS
			if (preserve_xattrs && iflags & ITEM_REPORT_XATTR && !dry_run)
				set_file_attrs(fname, file, NULL, fname, 0);
#endif
			continue;
		}
		if (phase == 2) {
			rprintf(FERROR,
				"got transfer request in phase 2 [%s]\n",
				who_am_i());
			exit_cleanup(RERR_PROTOCOL);
		}

		if (file->flags & FLAG_FILE_SENT) {
			if (csum_length == SHORT_SUM_LENGTH) {
				if (keep_partial && !partial_dir)
					make_backups = -make_backups; /* prevents double backup */
				if (append_mode)
					sparse_files = -sparse_files;
				append_mode = -append_mode;
				csum_length = SUM_LENGTH;
				redoing = 1;
			}
		} else {
			if (csum_length != SHORT_SUM_LENGTH) {
				if (keep_partial && !partial_dir)
					make_backups = -make_backups;
				if (append_mode)
					sparse_files = -sparse_files;
				append_mode = -append_mode;
				csum_length = SHORT_SUM_LENGTH;
				redoing = 0;
			}
		}

		if (!am_server && do_progress)
			set_current_file_index(file, ndx);
		stats.num_transferred_files++;
		stats.total_transferred_size += F_LENGTH(file);

		cleanup_got_literal = 0;

		if (daemon_filter_list.head
		    && check_filter(&daemon_filter_list, FLOG, fname, 0) < 0) {
			rprintf(FERROR, "attempt to hack rsync failed.\n");
			exit_cleanup(RERR_PROTOCOL);
		}

		if (!do_xfers) { /* log the transfer */
			log_item(FCLIENT, file, &stats, iflags, NULL);
			if (read_batch)
				discard_receive_data(f_in, F_LENGTH(file));
			continue;
		}
		if (write_batch < 0) {
			log_item(FCLIENT, file, &stats, iflags, NULL);
			if (!am_server)
				discard_receive_data(f_in, F_LENGTH(file));
			continue;
		}

		if (read_batch) {
			if (!(redoing ? we_want_redo(ndx) : gen_wants_ndx(ndx))) {
				rprintf(FINFO,
					"(Skipping batched update for%s \"%s\")\n",
					redoing ? " resend of" : "",
					fname);
				discard_receive_data(f_in, F_LENGTH(file));
				file->flags |= FLAG_FILE_SENT;
				continue;
			}
		}

		partialptr = partial_dir ? partial_dir_fname(fname) : fname;

		if (protocol_version >= 29) {
			switch (fnamecmp_type) {
			case FNAMECMP_FNAME:
				fnamecmp = fname;
				break;
			case FNAMECMP_PARTIAL_DIR:
				fnamecmp = partialptr;
				break;
			case FNAMECMP_BACKUP:
				fnamecmp = get_backup_name(fname);
				break;
			case FNAMECMP_FUZZY:
				if (file->dirname) {
					pathjoin(fnamecmpbuf, MAXPATHLEN,
						 file->dirname, xname);
					fnamecmp = fnamecmpbuf;
				} else
					fnamecmp = xname;
				break;
			default:
				if (fnamecmp_type >= basis_dir_cnt) {
					rprintf(FERROR,
						"invalid basis_dir index: %d.\n",
						fnamecmp_type);
					exit_cleanup(RERR_PROTOCOL);
				}
				pathjoin(fnamecmpbuf, sizeof fnamecmpbuf,
					 basis_dir[fnamecmp_type], fname);
				fnamecmp = fnamecmpbuf;
				break;
			}
			if (!fnamecmp || (daemon_filter_list.head
			  && check_filter(&daemon_filter_list, FLOG, fname, 0) < 0)) {
				fnamecmp = fname;
				fnamecmp_type = FNAMECMP_FNAME;
			}
		} else {
			/* Reminder: --inplace && --partial-dir are never
			 * enabled at the same time. */
			if (inplace && make_backups > 0) {
				if (!(fnamecmp = get_backup_name(fname)))
					fnamecmp = fname;
				else
					fnamecmp_type = FNAMECMP_BACKUP;
			} else if (partial_dir && partialptr)
				fnamecmp = partialptr;
			else
				fnamecmp = fname;
		}

		initial_stats = stats;

		/* open the file */
		fd1 = do_open(fnamecmp, O_RDONLY, 0);

		if (fd1 == -1 && protocol_version < 29) {
			if (fnamecmp != fname) {
				fnamecmp = fname;
				fd1 = do_open(fnamecmp, O_RDONLY, 0);
			}

			if (fd1 == -1 && basis_dir[0]) {
				/* pre-29 allowed only one alternate basis */
				pathjoin(fnamecmpbuf, sizeof fnamecmpbuf,
					 basis_dir[0], fname);
				fnamecmp = fnamecmpbuf;
				fd1 = do_open(fnamecmp, O_RDONLY, 0);
			}
		}

		updating_basis_or_equiv = inplace
		    && (fnamecmp == fname || fnamecmp_type == FNAMECMP_BACKUP);

		if (fd1 == -1) {
			st.st_mode = 0;
			st.st_size = 0;
		} else if (do_fstat(fd1,&st) != 0) {
			rsyserr(FERROR_XFER, errno, "fstat %s failed",
				full_fname(fnamecmp));
			discard_receive_data(f_in, F_LENGTH(file));
			close(fd1);
			if (inc_recurse)
				send_msg_int(MSG_NO_SEND, ndx);
			continue;
		}

		if (fd1 != -1 && S_ISDIR(st.st_mode) && fnamecmp == fname) {
			/* this special handling for directories
			 * wouldn't be necessary if robust_rename()
			 * and the underlying robust_unlink could cope
			 * with directories
			 */
			rprintf(FERROR_XFER, "recv_files: %s is a directory\n",
				full_fname(fnamecmp));
			discard_receive_data(f_in, F_LENGTH(file));
			close(fd1);
			if (inc_recurse)
				send_msg_int(MSG_NO_SEND, ndx);
			continue;
		}

		if (fd1 != -1 && !S_ISREG(st.st_mode)) {
			close(fd1);
			fd1 = -1;
		}

		/* If we're not preserving permissions, change the file-list's
		 * mode based on the local permissions and some heuristics. */
		if (!preserve_perms) {
			int exists = fd1 != -1;
#ifdef SUPPORT_ACLS
			const char *dn = file->dirname ? file->dirname : ".";
			if (parent_dirname != dn
			 && strcmp(parent_dirname, dn) != 0) {
				dflt_perms = default_perms_for_dir(dn);
				parent_dirname = dn;
			}
#endif
			file->mode = dest_mode(file->mode, st.st_mode,
					       dflt_perms, exists);
		}

		/* We now check to see if we are writing the file "inplace" */
		if (inplace)  {
			fd2 = do_open(fname, O_WRONLY|O_CREAT, 0600);
			if (fd2 == -1) {
				rsyserr(FERROR_XFER, errno, "open %s failed",
					full_fname(fname));
			}
		} else {
			fd2 = open_tmpfile(fnametmp, fname, file);
			if (fd2 != -1)
				cleanup_set(fnametmp, partialptr, file, fd1, fd2);
		}

		if (fd2 == -1) {
			discard_receive_data(f_in, F_LENGTH(file));
			if (fd1 != -1)
				close(fd1);
			if (inc_recurse)
				send_msg_int(MSG_NO_SEND, ndx);
			continue;
		}

		/* log the transfer */
		if (log_before_transfer)
			log_item(FCLIENT, file, &initial_stats, iflags, NULL);
		else if (!am_server && verbose && do_progress)
			rprintf(FINFO, "%s\n", fname);

		/* recv file data */
		recv_ok = receive_data(f_in, fnamecmp, fd1, st.st_size,
				       fname, fd2, F_LENGTH(file));

		log_item(log_code, file, &initial_stats, iflags, NULL);

		if (fd1 != -1)
			close(fd1);
		if (close(fd2) < 0) {
			rsyserr(FERROR, errno, "close failed on %s",
				full_fname(fnametmp));
			exit_cleanup(RERR_FILEIO);
		}

		if ((recv_ok && (!delay_updates || !partialptr)) || inplace) {
			if (partialptr == fname)
				partialptr = NULL;
			if (!finish_transfer(fname, fnametmp, fnamecmp,
					     partialptr, file, recv_ok, 1))
				recv_ok = -1;
			else if (fnamecmp == partialptr) {
				do_unlink(partialptr);
				handle_partial_dir(partialptr, PDIR_DELETE);
			}
		} else if (keep_partial && partialptr) {
			if (!handle_partial_dir(partialptr, PDIR_CREATE)) {
				rprintf(FERROR,
				    "Unable to create partial-dir for %s -- discarding %s.\n",
				    local_name ? local_name : f_name(file, NULL),
				    recv_ok ? "completed file" : "partial file");
				do_unlink(fnametmp);
				recv_ok = -1;
			} else if (!finish_transfer(partialptr, fnametmp, fnamecmp, NULL,
						    file, recv_ok, !partial_dir))
				recv_ok = -1;
			else if (delay_updates && recv_ok) {
				bitbag_set_bit(delayed_bits, ndx);
				recv_ok = 2;
			} else
				partialptr = NULL;
		} else
			do_unlink(fnametmp);

		cleanup_disable();

		if (read_batch)
			file->flags |= FLAG_FILE_SENT;

		switch (recv_ok) {
		case 2:
			break;
		case 1:
			if (remove_source_files || inc_recurse
			 || (preserve_hard_links && F_IS_HLINKED(file)))
				send_msg_int(MSG_SUCCESS, ndx);
			break;
		case 0: {
			enum logcode msgtype = redoing ? FERROR_XFER : FWARNING;
			if (msgtype == FERROR_XFER || verbose) {
				char *errstr, *redostr, *keptstr;
				if (!(keep_partial && partialptr) && !inplace)
					keptstr = "discarded";
				else if (partial_dir)
					keptstr = "put into partial-dir";
				else
					keptstr = "retained";
				if (msgtype == FERROR_XFER) {
					errstr = "ERROR";
					redostr = "";
				} else {
					errstr = "WARNING";
					redostr = read_batch ? " (may try again)"
							     : " (will try again)";
				}
				rprintf(msgtype,
					"%s: %s failed verification -- update %s%s.\n",
					errstr, local_name ? f_name(file, NULL) : fname,
					keptstr, redostr);
			}
			if (!redoing) {
				if (read_batch)
					flist_ndx_push(&batch_redo_list, ndx);
				send_msg_int(MSG_REDO, ndx);
				file->flags |= FLAG_FILE_SENT;
			} else if (inc_recurse)
				send_msg_int(MSG_NO_SEND, ndx);
			break;
		    }
		case -1:
			if (inc_recurse)
				send_msg_int(MSG_NO_SEND, ndx);
			break;
		}
	}
	if (make_backups < 0)
		make_backups = -make_backups;

	if (phase == 2 && delay_updates) /* for protocol_version < 29 */
		handle_delayed_updates(local_name);

	if (verbose > 2)
		rprintf(FINFO,"recv_files finished\n");

	return 0;
}
示例#17
0
/* A generic logging routine for send/recv, with parameter substitiution. */
static void log_formatted(enum logcode code, const char *format, const char *op,
			  struct file_struct *file, const char *fname, int iflags,
			  const char *hlink)
{
	char buf[MAXPATHLEN+1024], buf2[MAXPATHLEN], fmt[32];
	char *p, *s, *c;
	const char *n;
	size_t len, total;
	int64 b;

	*fmt = '%';

	/* We expand % codes one by one in place in buf.  We don't
	 * copy in the terminating null of the inserted strings, but
	 * rather keep going until we reach the null of the format. */
	total = strlcpy(buf, format, sizeof buf);
	if (total > MAXPATHLEN) {
		rprintf(FERROR, "log-format string is WAY too long!\n");
		exit_cleanup(RERR_MESSAGEIO);
	}
	buf[total++] = '\n';
	buf[total] = '\0';

	for (p = buf; (p = strchr(p, '%')) != NULL; ) {
		int humanize = 0;
		s = p++;
		c = fmt + 1;
		while (*p == '\'') {
			humanize++;
			p++;
		}
		if (*p == '-')
			*c++ = *p++;
		while (isDigit(p) && c - fmt < (int)(sizeof fmt) - 8)
			*c++ = *p++;
		while (*p == '\'') {
			humanize++;
			p++;
		}
		if (!*p)
			break;
		*c = '\0';
		n = NULL;

		/* Note for %h and %a: it doesn't matter what fd we pass to
		 * client_{name,addr} because rsync_module will already have
		 * forced the answer to be cached (assuming, of course, for %h
		 * that lp_reverse_lookup(module_id) is true). */
		switch (*p) {
		case 'h':
			if (am_daemon) {
				n = lp_reverse_lookup(module_id)
				  ? client_name(0) : undetermined_hostname;
			}
			break;
		case 'a':
			if (am_daemon)
				n = client_addr(0);
			break;
		case 'l':
			strlcat(fmt, "s", sizeof fmt);
			snprintf(buf2, sizeof buf2, fmt,
				 do_big_num(F_LENGTH(file), humanize, NULL));
			n = buf2;
			break;
		case 'U':
			strlcat(fmt, "u", sizeof fmt);
			snprintf(buf2, sizeof buf2, fmt,
				 uid_ndx ? F_OWNER(file) : 0);
			n = buf2;
			break;
		case 'G':
			if (!gid_ndx || file->flags & FLAG_SKIP_GROUP)
				n = "DEFAULT";
			else {
				strlcat(fmt, "u", sizeof fmt);
				snprintf(buf2, sizeof buf2, fmt,
					 F_GROUP(file));
				n = buf2;
			}
			break;
		case 'p':
			strlcat(fmt, "d", sizeof fmt);
			snprintf(buf2, sizeof buf2, fmt, (int)getpid());
			n = buf2;
			break;
		case 'M':
			n = c = timestring(file->modtime);
			while ((c = strchr(c, ' ')) != NULL)
				*c = '-';
			break;
		case 'B':
			c = buf2 + MAXPATHLEN - PERMSTRING_SIZE - 1;
			permstring(c, file->mode);
			n = c + 1; /* skip the type char */
			break;
		case 'o':
			n = op;
			break;
		case 'f':
			if (fname) {
				c = f_name_buf();
				strlcpy(c, fname, MAXPATHLEN);
			} else
				c = f_name(file, NULL);
			if (am_sender && F_PATHNAME(file)) {
				pathjoin(buf2, sizeof buf2,
					 F_PATHNAME(file), c);
				clean_fname(buf2, 0);
				if (fmt[1]) {
					strlcpy(c, buf2, MAXPATHLEN);
					n = c;
				} else
					n = buf2;
			} else if (am_daemon && *c != '/') {
				pathjoin(buf2, sizeof buf2,
					 curr_dir + module_dirlen, c);
				clean_fname(buf2, 0);
				if (fmt[1]) {
					strlcpy(c, buf2, MAXPATHLEN);
					n = c;
				} else
					n = buf2;
			} else {
				clean_fname(c, 0);
				n = c;
			}
			if (*n == '/')
				n++;
			break;
		case 'n':
			if (fname) {
				c = f_name_buf();
				strlcpy(c, fname, MAXPATHLEN);
			} else
				c = f_name(file, NULL);
			if (S_ISDIR(file->mode))
				strlcat(c, "/", MAXPATHLEN);
			n = c;
			break;
		case 'L':
			if (hlink && *hlink) {
				n = hlink;
				strlcpy(buf2, " => ", sizeof buf2);
			} else if (S_ISLNK(file->mode) && !fname) {
				n = F_SYMLINK(file);
				strlcpy(buf2, " -> ", sizeof buf2);
			} else {
				n = "";
				if (!fmt[1])
					break;
				strlcpy(buf2, "    ", sizeof buf2);
			}
			strlcat(fmt, "s", sizeof fmt);
			snprintf(buf2 + 4, sizeof buf2 - 4, fmt, n);
			n = buf2;
			break;
		case 'm':
			n = lp_name(module_id);
			break;
		case 't':
			n = timestring(time(NULL));
			break;
		case 'P':
			n = full_module_path;
			break;
		case 'u':
			n = auth_user;
			break;
		case 'b':
		case 'c':
			if (!(iflags & ITEM_TRANSFER))
				b = 0;
			else if ((!!am_sender) ^ (*p == 'c'))
				b = total_data_written - initial_data_written;
			else
				b = total_data_read - initial_data_read;
			strlcat(fmt, "s", sizeof fmt);
			snprintf(buf2, sizeof buf2, fmt,
				 do_big_num(b, humanize, NULL));
			n = buf2;
			break;
		case 'C':
			n = NULL;
			if (S_ISREG(file->mode)) {
				if (always_checksum && canonical_checksum(checksum_type))
					n = sum_as_hex(checksum_type, F_SUM(file));
				else if (iflags & ITEM_TRANSFER && canonical_checksum(xfersum_type))
					n = sum_as_hex(xfersum_type, sender_file_sum);
			}
			if (!n) {
				int checksum_len = csum_len_for_type(always_checksum ? checksum_type : xfersum_type);
				memset(buf2, ' ', checksum_len*2);
				buf2[checksum_len*2] = '\0';
				n = buf2;
			}
			break;
		case 'i':
			if (iflags & ITEM_DELETED) {
				n = "*deleting  ";
				break;
			}
			n  = c = buf2 + MAXPATHLEN - 32;
			c[0] = iflags & ITEM_LOCAL_CHANGE
			      ? iflags & ITEM_XNAME_FOLLOWS ? 'h' : 'c'
			     : !(iflags & ITEM_TRANSFER) ? '.'
			     : !local_server && *op == 's' ? '<' : '>';
			if (S_ISLNK(file->mode)) {
				c[1] = 'L';
				c[3] = '.';
				c[4] = !(iflags & ITEM_REPORT_TIME) ? '.'
				     : !preserve_times || !receiver_symlink_times
				    || (iflags & ITEM_REPORT_TIMEFAIL) ? 'T' : 't';
			} else {
				c[1] = S_ISDIR(file->mode) ? 'd'
				     : IS_SPECIAL(file->mode) ? 'S'
				     : IS_DEVICE(file->mode) ? 'D' : 'f';
				c[3] = !(iflags & ITEM_REPORT_SIZE) ? '.' : 's';
				c[4] = !(iflags & ITEM_REPORT_TIME) ? '.'
				     : !preserve_times ? 'T' : 't';
			}
			c[2] = !(iflags & ITEM_REPORT_CHANGE) ? '.' : 'c';
			c[5] = !(iflags & ITEM_REPORT_PERMS) ? '.' : 'p';
			c[6] = !(iflags & ITEM_REPORT_OWNER) ? '.' : 'o';
			c[7] = !(iflags & ITEM_REPORT_GROUP) ? '.' : 'g';
			c[8] = !(iflags & ITEM_REPORT_ATIME) ? '.' : 'u';
			c[9] = !(iflags & ITEM_REPORT_ACL) ? '.' : 'a';
			c[10] = !(iflags & ITEM_REPORT_XATTR) ? '.' : 'x';
			c[11] = '\0';

			if (iflags & (ITEM_IS_NEW|ITEM_MISSING_DATA)) {
				char ch = iflags & ITEM_IS_NEW ? '+' : '?';
				int i;
				for (i = 2; c[i]; i++)
					c[i] = ch;
			} else if (c[0] == '.' || c[0] == 'h' || c[0] == 'c') {
				int i;
				for (i = 2; c[i]; i++) {
					if (c[i] != '.')
						break;
				}
				if (!c[i]) {
					for (i = 2; c[i]; i++)
						c[i] = ' ';
				}
			}
			break;
		}

		/* "n" is the string to be inserted in place of this % code. */
		if (!n)
			continue;
		if (n != buf2 && fmt[1]) {
			strlcat(fmt, "s", sizeof fmt);
			snprintf(buf2, sizeof buf2, fmt, n);
			n = buf2;
		}
		len = strlen(n);

		/* Subtract the length of the escape from the string's size. */
		total -= p - s + 1;

		if (len + total >= (size_t)sizeof buf) {
			rprintf(FERROR,
				"buffer overflow expanding %%%c -- exiting\n",
				p[0]);
			exit_cleanup(RERR_MESSAGEIO);
		}

		/* Shuffle the rest of the string along to make space for n */
		if (len != (size_t)(p - s + 1))
			memmove(s + len, p + 1, total - (s - buf) + 1);
		total += len;

		/* Insert the contents of string "n", but NOT its null. */
		if (len)
			memcpy(s, n, len);

		/* Skip over inserted string; continue looking */
		p = s + len;
	}

	rwrite(code, buf, total, 0);
}
示例#18
0
文件: hardcopy.c 项目: noikiy/VICAR
FUNCTION CODE hard_help
(
    struct   SFILE	*fctx,		/* In: file context block for opened file	*/
    TEXT  		curlib[],	/* In: library name of opened file		*/
    TEXT		procname[],	/* In: proc name for LHS of help display	*/
    TEXT		outname[],	/* In: name of output file			*/
    struct  HELPBLK	*helpblk	/* out: help output control block		*/

)
{

    IMPORT  struct  VARIABLE *char_gbl;		/* system characteristics	*/

    struct DIRBLK	dirblk;		/* directive control block		*/
    struct TXTSTOR	title;		/* context for dynamically stored title text */
    struct SFILE	f;
    struct POSCTX	saved_pos;
    struct POSCTX	level2_pos;
    BOOL		has_level2;
    TEXT		str[STRINGSIZ+1];
    CODE		code;
    TEXT		field[STRINGSIZ+1];	/* text field after a directive	*/
    TEXT		name[STRINGSIZ+1];
    TEXT		key[KEYSIZ+1];
    TEXT		msg[STRINGSIZ+1];

    /* If no output name was given,	*/
    if (NULLSTR(outname))		/* use pdf or command name	*/
    {
        f_name(procname, outname);
        s_append(".MEM", outname);	/* procname.MEM for output	*/
    }

    /* note -- SAVELUN is safe because |save| qual is not allowed for this command */
    code = f_ophf(&f, SAVELUN, outname, F_WRITE);	/* open output file	*/
    if (code != SUCCESS)
    {
        sprintf(msg, "Error opening output, host code = %d", f.host_code);
        store_help_error(helpblk, msg, "TAE-OPNWRT");
        return(FAIL);
    }

    d_init(&dirblk, fctx, curlib, (TEXT **)(*char_gbl).v_cvp,
           (*char_gbl).v_count);    		/* init directive block		*/
    if ((*helpblk).compiled)			/* if PDF is compiled		*/
    {
        if ((code = prep_c_help(&dirblk, &title, msg, key)) != SUCCESS)	/* prepare*/
            goto put_error;
        str[0] = EOS;
    }
    else					/* PDF is not compiled		*/
    {
        code = d_dirctv(&dirblk, str, field);
        if (s_equal(str, ".TITLE"))
        {   /* read the title into dynamic store			*/
            if ((code = gettitle(&dirblk, &title, msg, key))!= SUCCESS)
                goto put_error;
            code = d_dirctv(&dirblk, str, field);
        }
        else				/* no title */
        {
            title.numline = 0;
        }
    }

    code = put_title(&f, &title, msg, key);  /* start filling output file */
    if (code != SUCCESS) goto put_error;

    if (title.tp != NULL) fretxt(&title); /* free the dyamically-stored title	*/

    /* str should contain .HELP directive now.  If not, find it	*/
    if (! s_equal( str, ".HELP"))
    {
        code = d_search(&dirblk, ".HELP", field);
        if (code != SUCCESS)
        {
            store_help_error(helpblk, "No help available on '%s'.", "TAE-NOHELP");
            return (FAIL);
        }
    }

    code = put_text_block(&f, &dirblk, msg, key);	/* output general help	*/
    if (code != SUCCESS) goto put_error;

    code = d_search(&dirblk, ".LEVEL1", field);
    if (code != SUCCESS)		/* if there is no level1 help then */
        goto return_success;		/* assume we are done and exit	   */

    f_movpos(CURRENT_POS, &saved_pos);		/* save position in input */
    code = d_search(&dirblk, ".LEVEL2", field); /* find detailed help */
    has_level2 = (code == SUCCESS);
    if (has_level2)				/* if detailed help exists,  */
        f_movpos(CURRENT_POS, &level2_pos);	/* save the position in file */

    f_setpos(dirblk.sfileptr, &saved_pos);	/* reset position to curr pos */
    code = d_dirctv(&dirblk, str, name);	/* gives str=".TITLE"	     */

    while (1)
    {
        code = d_dirctv(&dirblk, str, name);
        if (code != SUCCESS)			/* if no more directives, we */
            break;				/* are done		     */

        if (s_equal(str, ".END") || s_equal(str, ".LEVEL2")) /* done */
            break;

        code = put_header(&f, &dirblk, str, name, msg, key);
        if (code != SUCCESS) goto put_error;
        if (has_level2)
            code = put_level2_text(&f, &dirblk, &level2_pos,
                                   str, name, msg, key);
        if (code != SUCCESS) goto put_error;
    }

return_success:
    f_close(&f, F_KEEP);
    s_lower(outname);
    sprintf(msg, "Wrote file \"%s\".", outname);
    put_stdout(msg);
    return (SUCCESS);

put_error:
    store_help_error(helpblk, msg, key);
    return (FAIL);
}