Пример #1
0
static
#endif
int real_main(int argc, char *argv[])
{
	int ret=1;
	int option=0;
	int daemon=1;
	int forking=1;
	int strip=0;
	int randomise=0;
	struct lock *lock=NULL;
	struct conf **confs=NULL;
	int forceoverwrite=0;
	enum action act=ACTION_LIST;
	const char *backup=NULL;
	const char *backup2=NULL;
	char *restoreprefix=NULL;
	char *stripfrompath=NULL;
	const char *regex=NULL;
	const char *browsefile=NULL;
	char *browsedir=NULL;
	const char *conffile=get_conf_path();
	const char *orig_client=NULL;
	const char *logfile=NULL;
	// The orig_client is the original client that the normal client
	// would like to restore from.
#ifndef HAVE_WIN32
	int generate_ca_only=0;
#endif
	int vss_restore=1;
	int test_confs=0;
	enum burp_mode mode;

	log_init(argv[0]);
#ifndef HAVE_WIN32
	if(!strcmp(prog, "bedup"))
		return run_bedup(argc, argv);
	if(!strcmp(prog, "bsigs"))
		return run_bsigs(argc, argv);
#endif

	while((option=getopt(argc, argv, "a:b:c:C:d:fFghil:nq:Qr:s:tvxjz:?"))!=-1)
	{
		switch(option)
		{
			case 'a':
				if(parse_action(&act, optarg)) goto end;
				break;
			case 'b':
				// The diff command may have two backups
				// specified.
				if(!backup2 && backup) backup2=optarg;
				if(!backup) backup=optarg;
				break;
			case 'c':
				conffile=optarg;
				break;
			case 'C':
				orig_client=optarg;
				break;
			case 'd':
				restoreprefix=optarg; // for restores
				browsedir=optarg; // for lists
				break;
			case 'f':
				forceoverwrite=1;
				break;
			case 'F':
				daemon=0;
				break;
			case 'g':
#ifndef HAVE_WIN32
				generate_ca_only=1;
#endif
				break;
			case 'i':
				cmd_print_all();
				ret=0;
				goto end;
			case 'l':
				logfile=optarg;
				break;
			case 'n':
				forking=0;
				break;
			case 'q':
				randomise=atoi(optarg);
				break;
			case 'Q':
				log_force_quiet();
				break;
			case 'r':
				regex=optarg;
				break;
			case 's':
				strip=atoi(optarg);
				break;
			case 'v':
				printf("%s-%s\n", progname(), VERSION);
				ret=0;
				goto end;
			case 'x':
				vss_restore=0;
				break;
			case 't':
				test_confs=1;
				break;
			case 'z':
				browsefile=optarg;
				break;
			case 'h':
			case '?':
			default:
				usage();
				goto end;
		}
	}
	if(optind<argc)
	{
		usage();
		goto end;
	}

	if(act==ACTION_MONITOR)
	{
		// Try to output everything in JSON.
		log_set_json(1);
#ifndef HAVE_WIN32
		// Need to do this so that processes reading stdout get the
		// result of the printfs of logp straight away.
		setlinebuf(stdout);
#endif
	}

	if(!(confs=confs_alloc()))
		goto end;

	if(reload(confs, conffile, 1))
		goto end;

	// Dry run to test config file syntax.
	if(test_confs)
	{
		ret=run_test_confs(confs, orig_client);
		goto end;
	}

	if(!backup) switch(act)
	{
		case ACTION_DELETE:
			logp("No backup specified for deletion.\n");
			goto end;
		case ACTION_RESTORE:
		case ACTION_VERIFY:
		case ACTION_DIFF:
		case ACTION_DIFF_LONG:
			logp("No backup specified. Using the most recent.\n");
			backup="0";
		default:
			break;
	}
	if(!backup2) switch(act)
	{
		case ACTION_DIFF:
		case ACTION_DIFF_LONG:
			logp("No second backup specified. Using file system scan.\n");
			backup2="n"; // For 'next'.
		default:
			break;
	}

	// The logfile option is only used for the status client stuff.
	if(logfile
	  && (act!=ACTION_STATUS
		&& act!=ACTION_STATUS_SNAPSHOT))
			logp("-l <logfile> option obsoleted\n");

	if(orig_client
	  && *orig_client
	  && set_string(confs[OPT_ORIG_CLIENT], orig_client))
		goto end;

	// The random delay needs to happen before the lock is got, otherwise
	// you would never be able to use burp by hand.
	if(randomise) set_int(confs[OPT_RANDOMISE], randomise);
	mode=get_e_burp_mode(confs[OPT_BURP_MODE]);
	if(mode==BURP_MODE_CLIENT
	  && (act==ACTION_BACKUP_TIMED || act==ACTION_TIMER_CHECK))
		random_delay(confs);

	if(mode==BURP_MODE_SERVER
	  && act==ACTION_CHAMP_CHOOSER)
	{
		// These server modes need to run without getting the lock.
	}
	else if(mode==BURP_MODE_CLIENT
	  && (act==ACTION_LIST
		|| act==ACTION_LIST_LONG
		|| act==ACTION_DIFF
		|| act==ACTION_DIFF_LONG
		|| act==ACTION_STATUS
		|| act==ACTION_STATUS_SNAPSHOT
		|| act==ACTION_MONITOR))
	{
		// These client modes need to run without getting the lock.
	}
	else
	{
		const char *lockfile=confs_get_lockfile(confs);
		if(!(lock=lock_alloc_and_init(lockfile)))
			goto end;
		lock_get(lock);
		switch(lock->status)
		{
			case GET_LOCK_GOT: break;
			case GET_LOCK_NOT_GOT:
				logp("Could not get lockfile.\n");
				logp("Another process is probably running,\n");
				goto end;
			case GET_LOCK_ERROR:
			default:
				logp("Could not get lockfile.\n");
				logp("Maybe you do not have permissions to write to %s.\n", lockfile);
				goto end;
		}
	}

	set_int(confs[OPT_OVERWRITE], forceoverwrite);
	set_int(confs[OPT_STRIP], strip);
	set_int(confs[OPT_FORK], forking);
	set_int(confs[OPT_DAEMON], daemon);

	strip_trailing_slashes(&restoreprefix);
	strip_trailing_slashes(&browsedir);
	if(replace_conf_str(confs[OPT_BACKUP], backup)
	  || replace_conf_str(confs[OPT_BACKUP2], backup2)
	  || replace_conf_str(confs[OPT_RESTOREPREFIX], restoreprefix)
	  || replace_conf_str(confs[OPT_STRIP_FROM_PATH], stripfrompath)
	  || replace_conf_str(confs[OPT_REGEX], regex)
	  || replace_conf_str(confs[OPT_BROWSEFILE], browsefile)
	  || replace_conf_str(confs[OPT_BROWSEDIR], browsedir)
	  || replace_conf_str(confs[OPT_MONITOR_LOGFILE], logfile))
		goto end;

	base64_init();
	hexmap_init();

	if(mode==BURP_MODE_SERVER)
	{
#ifdef HAVE_WIN32
		logp("Sorry, server mode is not implemented for Windows.\n");
#else
		ret=server_modes(act,
			conffile, lock, generate_ca_only, confs);
#endif
	}
	else
	{
		ret=client(confs, act, vss_restore);
	}

end:
	lock_release(lock);
	lock_free(&lock);
	confs_free(&confs);
	return ret;
}
Пример #2
0
int cmd_clone(int argc, const char **argv, const char *prefix)
{
	int is_bundle = 0, is_local;
	struct stat buf;
	const char *repo_name, *repo, *work_tree, *git_dir;
	char *path, *dir;
	int dest_exists;
	const struct ref *refs, *remote_head;
	const struct ref *remote_head_points_at;
	const struct ref *our_head_points_at;
	struct ref *mapped_refs;
	const struct ref *ref;
	struct strbuf key = STRBUF_INIT, value = STRBUF_INIT;
	struct strbuf branch_top = STRBUF_INIT, reflog_msg = STRBUF_INIT;
	struct transport *transport = NULL;
	const char *src_ref_prefix = "refs/heads/";
	struct remote *remote;
	int err = 0, complete_refs_before_fetch = 1;
	int submodule_progress;

	struct refspec *refspec;
	const char *fetch_pattern;

	packet_trace_identity("clone");
	argc = parse_options(argc, argv, prefix, builtin_clone_options,
			     builtin_clone_usage, 0);

	if (argc > 2)
		usage_msg_opt(_("Too many arguments."),
			builtin_clone_usage, builtin_clone_options);

	if (argc == 0)
		usage_msg_opt(_("You must specify a repository to clone."),
			builtin_clone_usage, builtin_clone_options);

	if (option_depth || option_since || option_not.nr)
		deepen = 1;
	if (option_single_branch == -1)
		option_single_branch = deepen ? 1 : 0;

	if (option_mirror)
		option_bare = 1;

	if (option_bare) {
		if (option_origin)
			die(_("--bare and --origin %s options are incompatible."),
			    option_origin);
		if (real_git_dir)
			die(_("--bare and --separate-git-dir are incompatible."));
		option_no_checkout = 1;
	}

	if (!option_origin)
		option_origin = "origin";

	repo_name = argv[0];

	path = get_repo_path(repo_name, &is_bundle);
	if (path)
		repo = xstrdup(absolute_path(repo_name));
	else if (!strchr(repo_name, ':'))
		die(_("repository '%s' does not exist"), repo_name);
	else
		repo = repo_name;

	/* no need to be strict, transport_set_option() will validate it again */
	if (option_depth && atoi(option_depth) < 1)
		die(_("depth %s is not a positive number"), option_depth);

	if (argc == 2)
		dir = xstrdup(argv[1]);
	else
		dir = guess_dir_name(repo_name, is_bundle, option_bare);
	strip_trailing_slashes(dir);

	dest_exists = !stat(dir, &buf);
	if (dest_exists && !is_empty_dir(dir))
		die(_("destination path '%s' already exists and is not "
			"an empty directory."), dir);

	strbuf_addf(&reflog_msg, "clone: from %s", repo);

	if (option_bare)
		work_tree = NULL;
	else {
		work_tree = getenv("GIT_WORK_TREE");
		if (work_tree && !stat(work_tree, &buf))
			die(_("working tree '%s' already exists."), work_tree);
	}

	if (option_bare || work_tree)
		git_dir = xstrdup(dir);
	else {
		work_tree = dir;
		git_dir = mkpathdup("%s/.git", dir);
	}

	atexit(remove_junk);
	sigchain_push_common(remove_junk_on_signal);

	if (!option_bare) {
		if (safe_create_leading_directories_const(work_tree) < 0)
			die_errno(_("could not create leading directories of '%s'"),
				  work_tree);
		if (!dest_exists && mkdir(work_tree, 0777))
			die_errno(_("could not create work tree dir '%s'"),
				  work_tree);
		junk_work_tree = work_tree;
		set_git_work_tree(work_tree);
	}

	junk_git_dir = real_git_dir ? real_git_dir : git_dir;
	if (safe_create_leading_directories_const(git_dir) < 0)
		die(_("could not create leading directories of '%s'"), git_dir);

	if (0 <= option_verbosity) {
		if (option_bare)
			fprintf(stderr, _("Cloning into bare repository '%s'...\n"), dir);
		else
			fprintf(stderr, _("Cloning into '%s'...\n"), dir);
	}

	if (option_recursive) {
		if (option_required_reference.nr &&
		    option_optional_reference.nr)
			die(_("clone --recursive is not compatible with "
			      "both --reference and --reference-if-able"));
		else if (option_required_reference.nr) {
			string_list_append(&option_config,
				"submodule.alternateLocation=superproject");
			string_list_append(&option_config,
				"submodule.alternateErrorStrategy=die");
		} else if (option_optional_reference.nr) {
			string_list_append(&option_config,
				"submodule.alternateLocation=superproject");
			string_list_append(&option_config,
				"submodule.alternateErrorStrategy=info");
		}
	}

	init_db(git_dir, real_git_dir, option_template, INIT_DB_QUIET);

	if (real_git_dir)
		git_dir = real_git_dir;

	write_config(&option_config);

	git_config(git_default_config, NULL);

	if (option_bare) {
		if (option_mirror)
			src_ref_prefix = "refs/";
		strbuf_addstr(&branch_top, src_ref_prefix);

		git_config_set("core.bare", "true");
	} else {
		strbuf_addf(&branch_top, "refs/remotes/%s/", option_origin);
	}

	strbuf_addf(&value, "+%s*:%s*", src_ref_prefix, branch_top.buf);
	strbuf_addf(&key, "remote.%s.url", option_origin);
	git_config_set(key.buf, repo);
	strbuf_reset(&key);

	if (option_required_reference.nr || option_optional_reference.nr)
		setup_reference();

	fetch_pattern = value.buf;
	refspec = parse_fetch_refspec(1, &fetch_pattern);

	strbuf_reset(&value);

	remote = remote_get(option_origin);
	transport = transport_get(remote, remote->url[0]);
	transport_set_verbosity(transport, option_verbosity, option_progress);
	transport->family = family;

	path = get_repo_path(remote->url[0], &is_bundle);
	is_local = option_local != 0 && path && !is_bundle;
	if (is_local) {
		if (option_depth)
			warning(_("--depth is ignored in local clones; use file:// instead."));
		if (option_since)
			warning(_("--shallow-since is ignored in local clones; use file:// instead."));
		if (option_not.nr)
			warning(_("--shallow-exclude is ignored in local clones; use file:// instead."));
		if (!access(mkpath("%s/shallow", path), F_OK)) {
			if (option_local > 0)
				warning(_("source repository is shallow, ignoring --local"));
			is_local = 0;
		}
	}
	if (option_local > 0 && !is_local)
		warning(_("--local is ignored"));
	transport->cloning = 1;

	if (!transport->get_refs_list || (!is_local && !transport->fetch))
		die(_("Don't know how to clone %s"), transport->url);

	transport_set_option(transport, TRANS_OPT_KEEP, "yes");

	if (option_depth)
		transport_set_option(transport, TRANS_OPT_DEPTH,
				     option_depth);
	if (option_since)
		transport_set_option(transport, TRANS_OPT_DEEPEN_SINCE,
				     option_since);
	if (option_not.nr)
		transport_set_option(transport, TRANS_OPT_DEEPEN_NOT,
				     (const char *)&option_not);
	if (option_single_branch)
		transport_set_option(transport, TRANS_OPT_FOLLOWTAGS, "1");

	if (option_upload_pack)
		transport_set_option(transport, TRANS_OPT_UPLOADPACK,
				     option_upload_pack);

	if (transport->smart_options && !deepen)
		transport->smart_options->check_self_contained_and_connected = 1;

	refs = transport_get_remote_refs(transport);

	if (refs) {
		mapped_refs = wanted_peer_refs(refs, refspec);
		/*
		 * transport_get_remote_refs() may return refs with null sha-1
		 * in mapped_refs (see struct transport->get_refs_list
		 * comment). In that case we need fetch it early because
		 * remote_head code below relies on it.
		 *
		 * for normal clones, transport_get_remote_refs() should
		 * return reliable ref set, we can delay cloning until after
		 * remote HEAD check.
		 */
		for (ref = refs; ref; ref = ref->next)
			if (is_null_oid(&ref->old_oid)) {
				complete_refs_before_fetch = 0;
				break;
			}

		if (!is_local && !complete_refs_before_fetch)
			transport_fetch_refs(transport, mapped_refs);

		remote_head = find_ref_by_name(refs, "HEAD");
		remote_head_points_at =
			guess_remote_head(remote_head, mapped_refs, 0);

		if (option_branch) {
			our_head_points_at =
				find_remote_branch(mapped_refs, option_branch);

			if (!our_head_points_at)
				die(_("Remote branch %s not found in upstream %s"),
				    option_branch, option_origin);
		}
		else
			our_head_points_at = remote_head_points_at;
	}
	else {
		if (option_branch)
			die(_("Remote branch %s not found in upstream %s"),
					option_branch, option_origin);

		warning(_("You appear to have cloned an empty repository."));
		mapped_refs = NULL;
		our_head_points_at = NULL;
		remote_head_points_at = NULL;
		remote_head = NULL;
		option_no_checkout = 1;
		if (!option_bare)
			install_branch_config(0, "master", option_origin,
					      "refs/heads/master");
	}

	write_refspec_config(src_ref_prefix, our_head_points_at,
			remote_head_points_at, &branch_top);

	if (is_local)
		clone_local(path, git_dir);
	else if (refs && complete_refs_before_fetch)
		transport_fetch_refs(transport, mapped_refs);

	update_remote_refs(refs, mapped_refs, remote_head_points_at,
			   branch_top.buf, reflog_msg.buf, transport, !is_local);

	update_head(our_head_points_at, remote_head, reflog_msg.buf);

	/*
	 * We want to show progress for recursive submodule clones iff
	 * we did so for the main clone. But only the transport knows
	 * the final decision for this flag, so we need to rescue the value
	 * before we free the transport.
	 */
	submodule_progress = transport->progress;

	transport_unlock_pack(transport);
	transport_disconnect(transport);

	if (option_dissociate) {
		close_all_packs();
		dissociate_from_references();
	}

	junk_mode = JUNK_LEAVE_REPO;
	err = checkout(submodule_progress);

	strbuf_release(&reflog_msg);
	strbuf_release(&branch_top);
	strbuf_release(&key);
	strbuf_release(&value);
	junk_mode = JUNK_LEAVE_ALL;

	free(refspec);
	return err;
}
Пример #3
0
int cmd_clone(int argc, const char **argv, const char *prefix)
{
	int is_bundle = 0, is_local;
	struct stat buf;
	const char *repo_name, *repo, *work_tree, *git_dir;
	char *path, *dir;
	int dest_exists;
	const struct ref *refs, *remote_head;
	const struct ref *remote_head_points_at;
	const struct ref *our_head_points_at;
	struct ref *mapped_refs;
	const struct ref *ref;
	struct strbuf key = STRBUF_INIT, value = STRBUF_INIT;
	struct strbuf branch_top = STRBUF_INIT, reflog_msg = STRBUF_INIT;
	struct transport *transport = NULL;
	const char *src_ref_prefix = "refs/heads/";
	struct remote *remote;
	int err = 0, complete_refs_before_fetch = 1;

	struct refspec *refspec;
	const char *fetch_pattern;

	junk_pid = getpid();

	packet_trace_identity("clone");
	argc = parse_options(argc, argv, prefix, builtin_clone_options,
			     builtin_clone_usage, 0);

	if (argc > 2)
		usage_msg_opt(_("Too many arguments."),
			builtin_clone_usage, builtin_clone_options);

	if (argc == 0)
		usage_msg_opt(_("You must specify a repository to clone."),
			builtin_clone_usage, builtin_clone_options);

	if (option_single_branch == -1)
		option_single_branch = option_depth ? 1 : 0;

	if (option_mirror)
		option_bare = 1;

	if (option_bare) {
		if (option_origin)
			die(_("--bare and --origin %s options are incompatible."),
			    option_origin);
		if (real_git_dir)
			die(_("--bare and --separate-git-dir are incompatible."));
		option_no_checkout = 1;
	}

	if (!option_origin)
		option_origin = "origin";

	repo_name = argv[0];

	path = get_repo_path(repo_name, &is_bundle);
	if (path)
		repo = xstrdup(absolute_path(repo_name));
	else if (!strchr(repo_name, ':'))
		die(_("repository '%s' does not exist"), repo_name);
	else
		repo = repo_name;
	is_local = option_local != 0 && path && !is_bundle;
	if (is_local && option_depth)
		warning(_("--depth is ignored in local clones; use file:// instead."));
	if (option_local > 0 && !is_local)
		warning(_("--local is ignored"));

	if (argc == 2)
		dir = xstrdup(argv[1]);
	else
		dir = guess_dir_name(repo_name, is_bundle, option_bare);
	strip_trailing_slashes(dir);

	dest_exists = !stat(dir, &buf);
	if (dest_exists && !is_empty_dir(dir))
		die(_("destination path '%s' already exists and is not "
			"an empty directory."), dir);

	strbuf_addf(&reflog_msg, "clone: from %s", repo);

	if (option_bare)
		work_tree = NULL;
	else {
		work_tree = getenv("GIT_WORK_TREE");
		if (work_tree && !stat(work_tree, &buf))
			die(_("working tree '%s' already exists."), work_tree);
	}

	if (option_bare || work_tree)
		git_dir = xstrdup(dir);
	else {
		work_tree = dir;
		git_dir = mkpathdup("%s/.git", dir);
	}

	if (!option_bare) {
		junk_work_tree = work_tree;
		if (safe_create_leading_directories_const(work_tree) < 0)
			die_errno(_("could not create leading directories of '%s'"),
				  work_tree);
		if (!dest_exists && mkdir(work_tree, 0777))
			die_errno(_("could not create work tree dir '%s'."),
				  work_tree);
		set_git_work_tree(work_tree);
	}
	junk_git_dir = git_dir;
	atexit(remove_junk);
	sigchain_push_common(remove_junk_on_signal);

	if (safe_create_leading_directories_const(git_dir) < 0)
		die(_("could not create leading directories of '%s'"), git_dir);

	set_git_dir_init(git_dir, real_git_dir, 0);
	if (real_git_dir) {
		git_dir = real_git_dir;
		junk_git_dir = real_git_dir;
	}

	if (0 <= option_verbosity) {
		if (option_bare)
			printf(_("Cloning into bare repository '%s'...\n"), dir);
		else
			printf(_("Cloning into '%s'...\n"), dir);
	}
	init_db(option_template, INIT_DB_QUIET);
	write_config(&option_config);

	git_config(git_default_config, NULL);

	if (option_bare) {
		if (option_mirror)
			src_ref_prefix = "refs/";
		strbuf_addstr(&branch_top, src_ref_prefix);

		git_config_set("core.bare", "true");
	} else {
		strbuf_addf(&branch_top, "refs/remotes/%s/", option_origin);
	}

	strbuf_addf(&value, "+%s*:%s*", src_ref_prefix, branch_top.buf);
	strbuf_addf(&key, "remote.%s.url", option_origin);
	git_config_set(key.buf, repo);
	strbuf_reset(&key);

	if (option_reference.nr)
		setup_reference();

	fetch_pattern = value.buf;
	refspec = parse_fetch_refspec(1, &fetch_pattern);

	strbuf_reset(&value);

	remote = remote_get(option_origin);
	transport = transport_get(remote, remote->url[0]);

	if (!is_local) {
		if (!transport->get_refs_list || !transport->fetch)
			die(_("Don't know how to clone %s"), transport->url);

		transport_set_option(transport, TRANS_OPT_KEEP, "yes");

		if (option_depth)
			transport_set_option(transport, TRANS_OPT_DEPTH,
					     option_depth);
		if (option_single_branch)
			transport_set_option(transport, TRANS_OPT_FOLLOWTAGS, "1");

		transport_set_verbosity(transport, option_verbosity, option_progress);

		if (option_upload_pack)
			transport_set_option(transport, TRANS_OPT_UPLOADPACK,
					     option_upload_pack);

		if (transport->smart_options && !option_depth)
			transport->smart_options->check_self_contained_and_connected = 1;
	}

	refs = transport_get_remote_refs(transport);

	if (refs) {
		mapped_refs = wanted_peer_refs(refs, refspec);
		/*
		 * transport_get_remote_refs() may return refs with null sha-1
		 * in mapped_refs (see struct transport->get_refs_list
		 * comment). In that case we need fetch it early because
		 * remote_head code below relies on it.
		 *
		 * for normal clones, transport_get_remote_refs() should
		 * return reliable ref set, we can delay cloning until after
		 * remote HEAD check.
		 */
		for (ref = refs; ref; ref = ref->next)
			if (is_null_sha1(ref->old_sha1)) {
				complete_refs_before_fetch = 0;
				break;
			}

		if (!is_local && !complete_refs_before_fetch)
			transport_fetch_refs(transport, mapped_refs);

		remote_head = find_ref_by_name(refs, "HEAD");
		remote_head_points_at =
			guess_remote_head(remote_head, mapped_refs, 0);

		if (option_branch) {
			our_head_points_at =
				find_remote_branch(mapped_refs, option_branch);

			if (!our_head_points_at)
				die(_("Remote branch %s not found in upstream %s"),
				    option_branch, option_origin);
		}
		else
			our_head_points_at = remote_head_points_at;
	}
	else {
		warning(_("You appear to have cloned an empty repository."));
		mapped_refs = NULL;
		our_head_points_at = NULL;
		remote_head_points_at = NULL;
		remote_head = NULL;
		option_no_checkout = 1;
		if (!option_bare)
			install_branch_config(0, "master", option_origin,
					      "refs/heads/master");
	}

	write_refspec_config(src_ref_prefix, our_head_points_at,
			remote_head_points_at, &branch_top);

	if (is_local)
		clone_local(path, git_dir);
	else if (refs && complete_refs_before_fetch)
		transport_fetch_refs(transport, mapped_refs);

	update_remote_refs(refs, mapped_refs, remote_head_points_at,
			   branch_top.buf, reflog_msg.buf, transport);

	update_head(our_head_points_at, remote_head, reflog_msg.buf);

	transport_unlock_pack(transport);
	transport_disconnect(transport);

	junk_mode = JUNK_LEAVE_REPO;
	err = checkout();

	strbuf_release(&reflog_msg);
	strbuf_release(&branch_top);
	strbuf_release(&key);
	strbuf_release(&value);
	junk_mode = JUNK_LEAVE_ALL;
	return err;
}
Пример #4
0
/* This function is called once for every file system object that fts
   encounters.  fts performs a depth-first traversal.
   A directory is usually processed twice, first with fts_info == FTS_D,
   and later, after all of its entries have been processed, with FTS_DP.
   Return RM_ERROR upon error, RM_USER_DECLINED for a negative response
   to an interactive prompt, and otherwise, RM_OK.  */
static enum RM_status
rm_fts (FTS *fts, FTSENT *ent, struct rm_options const *x)
{
  switch (ent->fts_info)
    {
    case FTS_D:			/* preorder directory */
      if (! x->recursive)
        {
          /* This is the first (pre-order) encounter with a directory.
             Not recursive, so arrange to skip contents.  */
          error (0, EISDIR, _("cannot remove %s"), quote (ent->fts_path));
          mark_ancestor_dirs (ent);
          fts_skip_tree (fts, ent);
          return RM_ERROR;
        }

      /* Perform checks that can apply only for command-line arguments.  */
      if (ent->fts_level == FTS_ROOTLEVEL)
        {
          if (strip_trailing_slashes (ent->fts_path))
            ent->fts_pathlen = strlen (ent->fts_path);

          /* If the basename of a command line argument is "." or "..",
             diagnose it and do nothing more with that argument.  */
          if (dot_or_dotdot (last_component (ent->fts_accpath)))
            {
              error (0, 0, _("cannot remove directory: %s"),
                     quote (ent->fts_path));
              fts_skip_tree (fts, ent);
              return RM_ERROR;
            }

          /* If a command line argument resolves to "/" (and --preserve-root
             is in effect -- default) diagnose and skip it.  */
          if (ROOT_DEV_INO_CHECK (x->root_dev_ino, ent->fts_statp))
            {
              ROOT_DEV_INO_WARN (ent->fts_path);
              fts_skip_tree (fts, ent);
              return RM_ERROR;
            }
        }

      {
        Ternary is_empty_directory;
        enum RM_status s = prompt (fts, ent, true /*is_dir*/, x,
                                   PA_DESCEND_INTO_DIR, &is_empty_directory);

        if (s == RM_OK && is_empty_directory == T_YES)
          {
            /* When we know (from prompt when in interactive mode)
               that this is an empty directory, don't prompt twice.  */
            s = excise (fts, ent, x, true);
            fts_skip_tree (fts, ent);
          }

        if (s != RM_OK)
          {
            mark_ancestor_dirs (ent);
            fts_skip_tree (fts, ent);
          }

        return s;
      }

    case FTS_F:			/* regular file */
    case FTS_NS:		/* stat(2) failed */
    case FTS_SL:		/* symbolic link */
    case FTS_SLNONE:		/* symbolic link without target */
    case FTS_DP:		/* postorder directory */
    case FTS_DNR:		/* unreadable directory */
    case FTS_NSOK:		/* e.g., dangling symlink */
    case FTS_DEFAULT:		/* none of the above */
      {
        /* With --one-file-system, do not attempt to remove a mount point.
           fts' FTS_XDEV ensures that we don't process any entries under
           the mount point.  */
        if (ent->fts_info == FTS_DP
            && x->one_file_system
            && FTS_ROOTLEVEL < ent->fts_level
            && ent->fts_statp->st_dev != fts->fts_dev)
          {
            mark_ancestor_dirs (ent);
            error (0, 0, _("skipping %s, since it's on a different device"),
                   quote (ent->fts_path));
            return RM_ERROR;
          }

        bool is_dir = ent->fts_info == FTS_DP || ent->fts_info == FTS_DNR;
        enum RM_status s = prompt (fts, ent, is_dir, x, PA_REMOVE_DIR, NULL);
        if (s != RM_OK)
          return s;
        return excise (fts, ent, x, is_dir);
      }

    case FTS_DC:		/* directory that causes cycles */
      emit_cycle_warning (ent->fts_path);
      fts_skip_tree (fts, ent);
      return RM_ERROR;

    case FTS_ERR:
      /* Various failures, from opendir to ENOMEM, to failure to "return"
         to preceding directory, can provoke this.  */
      error (0, ent->fts_errno, _("traversal failed: %s"),
             quote (ent->fts_path));
      fts_skip_tree (fts, ent);
      return RM_ERROR;

    default:
      error (0, 0, _("unexpected failure: fts_info=%d: %s\n"
                     "please report to %s"),
             ent->fts_info,
             quote (ent->fts_path),
             PACKAGE_BUGREPORT);
      abort ();
    }
}
Пример #5
0
int cmd_clone(int argc, const char **argv, const char *prefix)
{
	int is_bundle = 0;
	struct stat buf;
	const char *repo_name, *repo, *work_tree, *git_dir;
	char *path, *dir;
	int dest_exists;
	const struct ref *refs, *remote_head;
	const struct ref *remote_head_points_at;
	const struct ref *our_head_points_at;
	struct ref *mapped_refs;
	struct strbuf key = STRBUF_INIT, value = STRBUF_INIT;
	struct strbuf branch_top = STRBUF_INIT, reflog_msg = STRBUF_INIT;
	struct transport *transport = NULL;
	char *src_ref_prefix = "refs/heads/";
	int err = 0;

	struct refspec *refspec;
	const char *fetch_pattern;

	junk_pid = getpid();

	argc = parse_options(argc, argv, prefix, builtin_clone_options,
			     builtin_clone_usage, 0);

	if (argc > 2)
		usage_msg_opt("Too many arguments.",
			builtin_clone_usage, builtin_clone_options);

	if (argc == 0)
		usage_msg_opt("You must specify a repository to clone.",
			builtin_clone_usage, builtin_clone_options);

	if (option_mirror)
		option_bare = 1;

	if (option_bare) {
		if (option_origin)
			die("--bare and --origin %s options are incompatible.",
			    option_origin);
		option_no_checkout = 1;
	}

	if (!option_origin)
		option_origin = "origin";

	repo_name = argv[0];

	path = get_repo_path(repo_name, &is_bundle);
	if (path)
		repo = xstrdup(make_nonrelative_path(repo_name));
	else if (!strchr(repo_name, ':'))
		repo = xstrdup(make_absolute_path(repo_name));
	else
		repo = repo_name;

	if (argc == 2)
		dir = xstrdup(argv[1]);
	else
		dir = guess_dir_name(repo_name, is_bundle, option_bare);
	strip_trailing_slashes(dir);

	dest_exists = !stat(dir, &buf);
	if (dest_exists && !is_empty_dir(dir))
		die("destination path '%s' already exists and is not "
			"an empty directory.", dir);

	strbuf_addf(&reflog_msg, "clone: from %s", repo);

	if (option_bare)
		work_tree = NULL;
	else {
		work_tree = getenv("GIT_WORK_TREE");
		if (work_tree && !stat(work_tree, &buf))
			die("working tree '%s' already exists.", work_tree);
	}

	if (option_bare || work_tree)
		git_dir = xstrdup(dir);
	else {
		work_tree = dir;
		git_dir = xstrdup(mkpath("%s/.git", dir));
	}

	if (!option_bare) {
		junk_work_tree = work_tree;
		if (safe_create_leading_directories_const(work_tree) < 0)
			die_errno("could not create leading directories of '%s'",
				  work_tree);
		if (!dest_exists && mkdir(work_tree, 0755))
			die_errno("could not create work tree dir '%s'.",
				  work_tree);
		set_git_work_tree(work_tree);
	}
	junk_git_dir = git_dir;
	atexit(remove_junk);
	sigchain_push_common(remove_junk_on_signal);

	setenv(CONFIG_ENVIRONMENT, mkpath("%s/config", git_dir), 1);

	if (safe_create_leading_directories_const(git_dir) < 0)
		die("could not create leading directories of '%s'", git_dir);
	set_git_dir(make_absolute_path(git_dir));

	init_db(option_template, option_quiet ? INIT_DB_QUIET : 0);

	/*
	 * At this point, the config exists, so we do not need the
	 * environment variable.  We actually need to unset it, too, to
	 * re-enable parsing of the global configs.
	 */
	unsetenv(CONFIG_ENVIRONMENT);

	if (option_reference)
		setup_reference(git_dir);

	git_config(git_default_config, NULL);

	if (option_bare) {
		if (option_mirror)
			src_ref_prefix = "refs/";
		strbuf_addstr(&branch_top, src_ref_prefix);

		git_config_set("core.bare", "true");
	} else {
		strbuf_addf(&branch_top, "refs/remotes/%s/", option_origin);
	}

	strbuf_addf(&value, "+%s*:%s*", src_ref_prefix, branch_top.buf);

	if (option_mirror || !option_bare) {
		/* Configure the remote */
		strbuf_addf(&key, "remote.%s.fetch", option_origin);
		git_config_set_multivar(key.buf, value.buf, "^$", 0);
		strbuf_reset(&key);

		if (option_mirror) {
			strbuf_addf(&key, "remote.%s.mirror", option_origin);
			git_config_set(key.buf, "true");
			strbuf_reset(&key);
		}

		strbuf_addf(&key, "remote.%s.url", option_origin);
		git_config_set(key.buf, repo);
		strbuf_reset(&key);
	}

	fetch_pattern = value.buf;
	refspec = parse_fetch_refspec(1, &fetch_pattern);

	strbuf_reset(&value);

	if (path && !is_bundle) {
		refs = clone_local(path, git_dir);
		mapped_refs = wanted_peer_refs(refs, refspec);
	} else {
		struct remote *remote = remote_get(argv[0]);
		transport = transport_get(remote, remote->url[0]);

		if (!transport->get_refs_list || !transport->fetch)
			die("Don't know how to clone %s", transport->url);

		transport_set_option(transport, TRANS_OPT_KEEP, "yes");

		if (option_depth)
			transport_set_option(transport, TRANS_OPT_DEPTH,
					     option_depth);

		if (option_quiet)
			transport->verbose = -1;
		else if (option_verbose)
			transport->verbose = 1;

		if (option_progress)
			transport->progress = 1;

		if (option_upload_pack)
			transport_set_option(transport, TRANS_OPT_UPLOADPACK,
					     option_upload_pack);

		refs = transport_get_remote_refs(transport);
		if (refs) {
			mapped_refs = wanted_peer_refs(refs, refspec);
			transport_fetch_refs(transport, mapped_refs);
		}
	}

	if (refs) {
		clear_extra_refs();

		write_remote_refs(mapped_refs);

		remote_head = find_ref_by_name(refs, "HEAD");
		remote_head_points_at =
			guess_remote_head(remote_head, mapped_refs, 0);

		if (option_branch) {
			struct strbuf head = STRBUF_INIT;
			strbuf_addstr(&head, src_ref_prefix);
			strbuf_addstr(&head, option_branch);
			our_head_points_at =
				find_ref_by_name(mapped_refs, head.buf);
			strbuf_release(&head);

			if (!our_head_points_at) {
				warning("Remote branch %s not found in "
					"upstream %s, using HEAD instead",
					option_branch, option_origin);
				our_head_points_at = remote_head_points_at;
			}
		}
		else
			our_head_points_at = remote_head_points_at;
	}
	else {
		warning("You appear to have cloned an empty repository.");
		our_head_points_at = NULL;
		remote_head_points_at = NULL;
		remote_head = NULL;
		option_no_checkout = 1;
		if (!option_bare)
			install_branch_config(0, "master", option_origin,
					      "refs/heads/master");
	}

	if (remote_head_points_at && !option_bare) {
		struct strbuf head_ref = STRBUF_INIT;
		strbuf_addstr(&head_ref, branch_top.buf);
		strbuf_addstr(&head_ref, "HEAD");
		create_symref(head_ref.buf,
			      remote_head_points_at->peer_ref->name,
			      reflog_msg.buf);
	}

	if (our_head_points_at) {
		/* Local default branch link */
		create_symref("HEAD", our_head_points_at->name, NULL);
		if (!option_bare) {
			const char *head = skip_prefix(our_head_points_at->name,
						       "refs/heads/");
			update_ref(reflog_msg.buf, "HEAD",
				   our_head_points_at->old_sha1,
				   NULL, 0, DIE_ON_ERR);
			install_branch_config(0, head, option_origin,
					      our_head_points_at->name);
		}
	} else if (remote_head) {
		/* Source had detached HEAD pointing somewhere. */
		if (!option_bare) {
			update_ref(reflog_msg.buf, "HEAD",
				   remote_head->old_sha1,
				   NULL, REF_NODEREF, DIE_ON_ERR);
			our_head_points_at = remote_head;
		}
	} else {
		/* Nothing to checkout out */
		if (!option_no_checkout)
			warning("remote HEAD refers to nonexistent ref, "
				"unable to checkout.\n");
		option_no_checkout = 1;
	}

	if (transport) {
		transport_unlock_pack(transport);
		transport_disconnect(transport);
	}

	if (!option_no_checkout) {
		struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file));
		struct unpack_trees_options opts;
		struct tree *tree;
		struct tree_desc t;
		int fd;

		/* We need to be in the new work tree for the checkout */
		setup_work_tree();

		fd = hold_locked_index(lock_file, 1);

		memset(&opts, 0, sizeof opts);
		opts.update = 1;
		opts.merge = 1;
		opts.fn = oneway_merge;
		opts.verbose_update = !option_quiet;
		opts.src_index = &the_index;
		opts.dst_index = &the_index;

		tree = parse_tree_indirect(our_head_points_at->old_sha1);
		parse_tree(tree);
		init_tree_desc(&t, tree->buffer, tree->size);
		unpack_trees(1, &t, &opts);

		if (write_cache(fd, active_cache, active_nr) ||
		    commit_locked_index(lock_file))
			die("unable to write new index file");

		err |= run_hook(NULL, "post-checkout", sha1_to_hex(null_sha1),
				sha1_to_hex(our_head_points_at->old_sha1), "1",
				NULL);

		if (!err && option_recursive)
			err = run_command_v_opt(argv_submodule, RUN_GIT_CMD);
	}

	strbuf_release(&reflog_msg);
	strbuf_release(&branch_top);
	strbuf_release(&key);
	strbuf_release(&value);
	junk_pid = 0;
	return err;
}
Пример #6
0
static int parse_client_data(struct asfd *srfd,
	struct cstat *clist, struct conf **confs)
{
	int ret=0;
	char *command=NULL;
	char *client=NULL;
	char *backup=NULL;
	char *logfile=NULL;
	char *browse=NULL;
	const char *cp=NULL;
	struct cstat *cstat=NULL;
        struct bu *bu=NULL;
//printf("got client data: '%s'\n", srfd->rbuf->buf);

	cp=srfd->rbuf->buf;

	// The client monitor will send an initial blank line to kick things
	// off. Until it is sent, we will not even have entered the code
	// in this file. So, without it, data from the parent will not have
	// been read, and the monitor client will be given incomplete
	// information for its first response.
	// Just ignore the new line at this point, it has served its purpose.
	if(srfd->rbuf->len==1
	  && !strcmp(cp, "\n"))
	{
		ret=0;
		goto end;
	}
	command=get_str(&cp, "j:", 0);
	client=get_str(&cp, "c:", 0);
	backup=get_str(&cp, "b:", 0);
	logfile=get_str(&cp, "l:", 0);
	browse=get_str(&cp, "p:", 1);

	if(command)
	{
		if(!strcmp(command, "pretty-print-on"))
		{
			json_set_pretty_print(1);
			if(json_send_warn(srfd, "Pretty print on"))
				goto error;
		}
		else if(!strcmp(command, "pretty-print-off"))
		{
			json_set_pretty_print(0);
			if(json_send_warn(srfd, "Pretty print off"))
				goto error;
		}
		else
		{
			if(json_send_warn(srfd, "Unknown command"))
				goto error;
		}
		goto end;
	}

	if(browse)
	{
		free_w(&logfile);
		if(!(logfile=strdup_w("manifest", __func__)))
			goto error;
		strip_trailing_slashes(&browse);
	}

//dump_cbno(clist, "pcd");

	if(client && *client)
	{
		if(!(cstat=cstat_get_by_name(clist, client)))
		{
			if(json_send_warn(srfd, "Could not find client"))
				goto error;
			goto end;
		}

		if(cstat_set_backup_list(cstat))
		{
			if(json_send_warn(srfd, "Could not get backup list"))
				goto error;
			goto end;
			
		}
	}
	if(cstat && backup)
	{
		unsigned long bno=0;
		if(!(bno=strtoul(backup, NULL, 10)))
		{
			if(json_send_warn(srfd, "Could not get backup number"))
				goto error;
			goto end;
		}
		for(bu=cstat->bu; bu; bu=bu->prev)
			if(bu->bno==bno) break;

		if(!bu)
		{
			if(json_send_warn(srfd, "Backup not found"))
				goto error;
			goto end;
		}
	}
	if(logfile)
	{
		if(strcmp(logfile, "manifest")
		  && strcmp(logfile, "backup")
		  && strcmp(logfile, "restore")
		  && strcmp(logfile, "verify")
		  && strcmp(logfile, "backup_stats")
		  && strcmp(logfile, "restore_stats")
		  && strcmp(logfile, "verify_stats"))
		{
			if(json_send_warn(srfd, "File not supported"))
				goto error;
			goto end;
		}
	}
/*
	printf("client: %s\n", client?:"");
	printf("backup: %s\n", backup?:"");
	printf("logfile: %s\n", logfile?:"");
*/

	if(cstat)
	{
		if(!cstat->run_status)
			cstat_set_run_status(cstat);
	}
	else for(cstat=clist; cstat; cstat=cstat->next)
	{
		if(!cstat->run_status)
			cstat_set_run_status(cstat);
	}

	if(json_send(srfd, clist, cstat, bu, logfile, browse,
		get_int(confs[OPT_MONITOR_BROWSE_CACHE])))
			goto error;

	goto end;
error:
	ret=-1;
end:
	free_w(&client);
	free_w(&backup);
	free_w(&logfile);
	free_w(&browse);
	return ret;
}
Пример #7
0
int
main (void)
{
  struct test *t;
  bool ok = true;

  for (t = tests; t->name; t++)
    {
      char *dir = dir_name (t->name);
      int dirlen = dir_len (t->name);
      char *last = last_component (t->name);
      char *base = base_name (t->name);
      int baselen = base_len (base);
      char *stripped = strdup (t->name);
      bool modified = strip_trailing_slashes (stripped);
      bool absolute = IS_ABSOLUTE_FILE_NAME (t->name);
      if (! (strcmp (dir, t->dir) == 0
             && (dirlen == strlen (dir)
                 || (dirlen + 1 == strlen (dir) && dir[dirlen] == '.'))))
        {
          ok = false;
          printf ("dir_name '%s': got '%s' len %d,"
                  " expected '%s' len %ld\n",
                  t->name, dir, dirlen,
                  t->dir, (unsigned long) strlen (t->dir));
        }
      if (strcmp (last, t->last))
        {
          ok = false;
          printf ("last_component '%s': got '%s', expected '%s'\n",
                  t->name, last, t->last);
        }
      if (! (strcmp (base, t->base) == 0
             && (baselen == strlen (base)
                 || (baselen + 1 == strlen (base)
                     && ISSLASH (base[baselen])))))
        {
          ok = false;
          printf ("base_name '%s': got '%s' len %d,"
                  " expected '%s' len %ld\n",
                  t->name, base, baselen,
                  t->base, (unsigned long) strlen (t->base));
        }
      if (strcmp (stripped, t->stripped) || modified != t->modified)
        {
          ok = false;
          printf ("strip_trailing_slashes '%s': got %s %s, expected %s %s\n",
                  t->name, stripped, modified ? "changed" : "unchanged",
                  t->stripped, t->modified ? "changed" : "unchanged");
        }
      if (t->absolute != absolute)
        {
          ok = false;
          printf ("'%s': got %s, expected %s\n", t->name,
                  absolute ? "absolute" : "relative",
                  t->absolute ? "absolute" : "relative");
        }
      free (dir);
      free (base);
      free (stripped);
    }
  return ok ? 0 : 1;
}
Пример #8
0
/*
 * mode is the mode bits to use in creating a new directory
 *
 * parent_mode are the parent's modes if we need to create parent
 *    directories.
 *
 * owner and group are to set on any created dirs
 *
 * keep_dir_modes if set means don't change mode bits if dir exists
 */
bool makepath(ATTR *attr, const char *apath, mode_t mode, mode_t parent_mode,
            uid_t owner, gid_t group, int keep_dir_modes)
{
   struct stat statp;
   mode_t omask, tmode;
   char *path = (char *)apath;
   char *p;
   int len;
   bool ok = false;
   int created;
   char new_dir[5000];
   int ndir = 0;
   int i = 0;
   int max_dirs = (int)sizeof(new_dir);
   JCR *jcr = attr->jcr;

   if (stat(path, &statp) == 0) {     /* Does dir exist? */
      if (!S_ISDIR(statp.st_mode)) {
         Jmsg1(jcr, M_ERROR, 0, _("%s exists but is not a directory.\n"), path);
         return false;
      }
      /* Full path exists */
      if (keep_dir_modes) {
         return true;
      }
      set_own_mod(attr, path, owner, group, mode);
      return true;
   }
   omask = umask(0);
   umask(omask);
   len = strlen(apath);
   path = (char *)alloca(len+1);
   bstrncpy(path, apath, len+1);
   strip_trailing_slashes(path);
   /*
    * Now for one of the complexities. If we are not running as root,
    *  then if the parent_mode does not have wx user perms, or we are
    *  setting the userid or group, and the parent_mode has setuid, setgid,
    *  or sticky bits, we must create the dir with open permissions, then
    *  go back and patch all the dirs up with the correct perms.
    * Solution, set everything to 0777, then go back and reset them at the
    *  end.
    */
   tmode = 0777;

#if defined(HAVE_WIN32)
   /* Validate drive letter */
   if (path[1] == ':') {
      char drive[4] = "X:\\";

      drive[0] = path[0];

      UINT drive_type = GetDriveType(drive);

      if (drive_type == DRIVE_UNKNOWN || drive_type == DRIVE_NO_ROOT_DIR) {
         Jmsg1(jcr, M_ERROR, 0, _("%c: is not a valid drive.\n"), path[0]);
         goto bail_out;
      }

      if (path[2] == '\0') {          /* attempt to create a drive */
         ok = true;
         goto bail_out;               /* OK, it is already there */
      }

      p = &path[3];
   } else {
      p = path;
   }
#else
   p = path;
#endif

   /* Skip leading slash(es) */
   while (IsPathSeparator(*p)) {
      p++;
   }
   while ((p = first_path_separator(p))) {
      char save_p;
      save_p = *p;
      *p = 0;
      if (!makedir(jcr, path, tmode, &created)) {
         goto bail_out;
      }
      if (ndir < max_dirs) {
         new_dir[ndir++] = created;
      }
      *p = save_p;
      while (IsPathSeparator(*p)) {
         p++;
      }
   }
   /* Create final component */
   if (!makedir(jcr, path, tmode, &created)) {
      goto bail_out;
   }
   if (ndir < max_dirs) {
      new_dir[ndir++] = created;
   }
   if (ndir >= max_dirs) {
      Jmsg0(jcr, M_WARNING, 0, _("Too many subdirectories. Some permissions not reset.\n"));
   }

   /* Now set the proper owner and modes */
#if defined(HAVE_WIN32)

   /* Don't propagate the hidden or encrypted attributes to parent directories */
   parent_mode &= ~S_ISVTX;
   parent_mode &= ~S_ISGID;

   if (path[1] == ':') {
      p = &path[3];
   } else {
      p = path;
   }
#else
   p = path;
#endif
   /* Skip leading slash(es) */
   while (IsPathSeparator(*p)) {
      p++;
   }
   while ((p = first_path_separator(p))) {
      char save_p;
      save_p = *p;
      *p = 0;
      if (i < ndir && new_dir[i++] && !keep_dir_modes) {
         set_own_mod(attr, path, owner, group, parent_mode);
      }
      *p = save_p;
      while (IsPathSeparator(*p)) {
         p++;
      }
   }

   /* Set for final component */
   if (i < ndir && new_dir[i++]) {
      set_own_mod(attr, path, owner, group, mode);
   }

   ok = true;
bail_out:
   umask(omask);
   return ok;
}
Пример #9
0
/*
 * Add this directory to the list of data to be printed for a directory and
 * decide whether to tell the recursion processor whether to continue
 * recursing or not.
 */
static Dtype
ls_direntproc (void *callerdat, const char *dir, const char *repos,
               const char *update_dir, List *entries)
{
    Dtype retval;
    Node *p;

    /* Due to the way we called start_recursion() from ls_proc() with a single
     * argument at a time, we can assume that if we don't yet have a parent
     * directory in DIRS then this directory should be processed.
     */

    if (strcmp (dir, "."))
    {
        /* Search for our parent directory.  */
	char *parent;
        parent = xmalloc (strlen (update_dir) - strlen (dir) + 1);
        strncpy (parent, update_dir, strlen (update_dir) - strlen (dir));
        parent[strlen (update_dir) - strlen (dir)] = '\0';
        strip_trailing_slashes (parent);
        p = findnode (callerdat, parent);
    }
    else
        p = NULL;

    if (p)
    {
	/* Push this dir onto our parent directory's listing.  */
	Node *n = getnode();

	if (entries_format)
	    n->data = Xasprintf ("D/%s////\n", dir);
	else if (long_format)
	{
	    struct long_format_data *out =
		    xmalloc (sizeof (struct long_format_data));
	    out->header = xstrdup ("d--- ");
	    out->time = gmformat_time_t (unix_time_stamp (repos));
	    out->footer = Xasprintf ("%12s%s%s", "",
                                     show_dead_revs ? "     " : "", dir);
	    n->data = out;
	    n->delproc = long_format_data_delproc;
	}
	else
	    n->data = Xasprintf ("%s\n", dir);

	addnode (p->data, n);
    }

    if (!p || recurse)
    {
	/* Create a new list for this directory.  */
	p = getnode ();
	p->key = xstrdup (strcmp (update_dir, ".") ? update_dir : "");
	p->data = getlist ();
        p->delproc = ls_delproc;
	addnode (callerdat, p);

	/* Create a local directory and mark it as needing deletion.  This is
         * the behavior the recursion processor relies upon, a la update &
         * checkout.
         */
	if (!isdir (dir))
        {
	    int nonbranch;
	    if (show_tag == NULL && show_date == NULL)
	    {
		ParseTag (&show_tag, &show_date, &nonbranch);
		set_tag = true;
	    }

	    if (!created_dir)
		created_dir = xstrdup (update_dir);

	    make_directory (dir);
	    Create_Admin (dir, update_dir, repos, show_tag, show_date,
			  nonbranch, 0, 0);
	    Subdir_Register (entries, NULL, dir);
	}

	/* Tell do_recursion to keep going.  */
	retval = R_PROCESS;
    }
    else
        retval = R_SKIP_ALL;

    return retval;
}
Пример #10
0
int bbftp_retrlistdir(char *pattern,char **filelist,int *filelistlen,char *logmessage,int *errcode)
{
    int     lastslash ;
    char    *pointer ;
    char    *dirpath ;
    DIR     *curdir ;
#ifdef STANDART_FILE_CALL
    struct dirent *dp ;
    struct stat statbuf;
#else
#ifdef STANDART_READDIR_CALL
    struct dirent *dp ;
#else
    struct dirent64 *dp ;
#endif
    struct stat64 statbuf ;
#endif
    int     lengthtosend;
    int     numberoffile ;
    /*
    ** Structure to keep the filenames
    */
    struct keepfile {
        char    *filename ;
        char    filechar[3] ;
        struct  keepfile *next ;
    } ;
    struct keepfile *first_item ;
    struct keepfile *current_item ;
    struct keepfile *used_item ;
    char    *filepos ;
    int     i ;
    /*
    ** Check if it is a rfio creation
    */
#if defined(WITH_RFIO) || defined(WITH_RFIO64)    
    if ( (transferoption & TROPT_RFIO_O) == TROPT_RFIO_O ) {
        return bbftp_retrlistdir_rfio(pattern,filelist,filelistlen,logmessage,errcode) ;
    }
#endif
    if ( (dirpath = (char *) malloc ( strlen(pattern) + 1 + 3 )) == NULL ) {
        sprintf(logmessage,"Error allocating memory for dirpath %s",strerror(errno)) ;
        *errcode = 35 ;
        return -1 ;
    } 
    pointer = pattern ;
    lastslash = strlen(pointer) - 1 ;
    while ( lastslash >= 0 && pointer[lastslash] != '/') lastslash-- ;
    if ( lastslash == -1 ) {
        /*
        ** No slash in the path, so this is a pattern and we have
        ** to opendir .
        */
        if ( (curdir = opendir(".")) == NULL ) {
            sprintf(logmessage,"opendir . failed : %s ",strerror(errno)) ;
            *errcode = 86 ;
            free(dirpath) ;
            return -1 ;
        }
        strcpy(dirpath,"./") ;
    } else if ( lastslash == 0 ) {
        /*
        ** A slash in first position so we are going to open the
        ** / directory
        */
        if ( (curdir = opendir("/")) == NULL ) {
            sprintf(logmessage,"opendir / failed : %s ",strerror(errno)) ;
            *errcode = 86 ;
            free(dirpath) ;
            return -1 ;
        }
        strcpy(dirpath,"/") ;
        pointer++ ;
    } else if ( lastslash == strlen(pointer) - 1 ) {
        /*
        ** The filename end with a slash ..... error
        */
        sprintf(logmessage,"Pattern %s ends with a /",pattern) ;
        *errcode = 87 ;
        free(dirpath) ;
        return -1;
    } else {
        pointer[lastslash] = '\0';
        /*
        ** Srip unnecessary / at the end of dirpath and reset 
        ** only one
        */
        strcpy(dirpath,pointer) ;
        strip_trailing_slashes(dirpath) ;
        dirpath[strlen(dirpath)+1] = '\0';
        dirpath[strlen(dirpath)] = '/';
        if ( (curdir = opendir(dirpath)) == NULL ) {
            sprintf(logmessage,"opendir %s failed : %s ",dirpath,strerror(errno)) ;
            *errcode = 86 ;
            free(dirpath) ;
            return -1 ;
        }
        for ( i = 0 ; i <= lastslash ; i++ ) pointer++ ;
    }
    /*
    ** At this stage pointer point to the pattern and curdir
    ** is the opened directory and dirpath contain the
    ** directory name
    */
    /*
    ** As we are using the fnmatch routine we are obliged to
    ** first count the number of bytes we are sending.
    */
    lengthtosend = 0 ;
    numberoffile = 0 ;
    errno = 0 ;
    first_item = NULL ;
#ifdef STANDART_FILE_CALL
    while ( (dp = readdir(curdir) ) != NULL) {
#else
#ifdef STANDART_READDIR_CALL 
    while ( (dp = readdir(curdir) ) != NULL) {
#else
    while ( (dp = readdir64(curdir) ) != NULL) {
#endif
#endif
        if ( fnmatch(pointer, dp->d_name,0) == 0) {
            numberoffile++ ;
            lengthtosend = lengthtosend +  strlen(dirpath) + strlen(dp->d_name) + 1 + 3 ;
            if ( ( current_item = (struct keepfile *) malloc( sizeof(struct keepfile)) ) == NULL ) {
                sprintf(logmessage,"Error getting memory for structure : %s",strerror(errno)) ;
                *errcode = 35 ;
                current_item = first_item ;
                while ( current_item != NULL ) {
                    free(current_item->filename) ;
                    used_item = current_item->next ;
                    free(current_item) ;
                    current_item = used_item ;
                }
                closedir(curdir) ;
                free(dirpath) ;
                return -1 ;
            }
            if ( ( current_item->filename = (char *) malloc( strlen(dirpath) + strlen(dp->d_name) + 1) ) == NULL ) {
                sprintf(logmessage,"Error getting memory for filename : %s",strerror(errno)) ;
                *errcode = 35 ;
                /*
                ** Clean memory
                */
                free(current_item) ;
                current_item = first_item ;
                while ( current_item != NULL ) {
                    free(current_item->filename) ;
                    used_item = current_item->next ;
                    free(current_item) ;
                    current_item = used_item ;
                }
                closedir(curdir) ;
                free(dirpath) ;
                return -1 ;
            }
            current_item->next = NULL ;
            if ( first_item == NULL ) {
                first_item = current_item ;
                used_item = first_item ;
            } else {
                used_item = first_item ;
                while ( used_item->next != NULL ) used_item = used_item->next ;
                used_item->next = current_item ;
            }
            sprintf(current_item->filename,"%s%s",dirpath,dp->d_name) ;
#ifdef STANDART_FILE_CALL
            if ( lstat(current_item->filename,&statbuf) < 0 ) {
#else
            if ( lstat64(current_item->filename,&statbuf) < 0 ) {
#endif
                sprintf(logmessage,"Error lstating file %s",current_item->filename) ;
                *errcode = 89 ;
                current_item = first_item ;
                while ( current_item != NULL ) {
                    free(current_item->filename) ;
                    used_item = current_item->next ;
                    free(current_item) ;
                    current_item = used_item ;
                }
                closedir(curdir) ;
                free(dirpath) ;
                return -1 ;
            }
            if ( (statbuf.st_mode & S_IFLNK) == S_IFLNK) {
                current_item->filechar[0] = 'l' ;
#ifdef STANDART_FILE_CALL
                if ( stat(current_item->filename,&statbuf) < 0 ) {
#else
                if ( stat64(current_item->filename,&statbuf) < 0 ) {
#endif
                    /*
                    ** That means that the link refer to an unexisting file
                    */
                    current_item->filechar[1] = 'u' ;
                } else {
                    if ( (statbuf.st_mode & S_IFDIR) == S_IFDIR) {
                        current_item->filechar[1] = 'd' ;
                    } else {
                        current_item->filechar[1] = 'f' ;
                    }
                }
            } else {
                current_item->filechar[0] = ' ' ;
                if ( (statbuf.st_mode & S_IFDIR) == S_IFDIR) {
                    current_item->filechar[1] = 'd' ;
                } else {
                    current_item->filechar[1] = 'f' ;
                }
            }
            current_item->filechar[2] = '\0' ;
        }
        errno = 0 ;
    }
    /*
    ** Check errno in case of error during readdir
    ** for the following readir we are not going to check
    ** so that may be a cause of problem
    */
    if ( errno != 0 ) {
        sprintf(logmessage,"Error on readdir %s : %s ",dirpath,strerror(errno)) ;
        *errcode = 88 ;
        closedir(curdir) ;
        current_item = first_item ;
        while ( current_item != NULL ) {
            free(current_item->filename) ;
            used_item = current_item->next ;
            free(current_item) ;
            current_item = used_item ;
        }
        free(dirpath) ;
        return -1 ;
    }

    /*
    ** Check if numberoffile is zero and reply now in this
    ** case 
    */
    if ( numberoffile == 0 ) {
        *filelistlen = 0 ;
        closedir(curdir) ;
        current_item = first_item ;
        while ( current_item != NULL ) {
            free(current_item->filename) ;
            used_item = current_item->next ;
            free(current_item) ;
            current_item = used_item ;
        }
        free(dirpath) ;
        return 0 ;
    }
    /*
    ** Now everything is ready so prepare the answer
    */
    if ( ( *filelist = (char *) malloc (lengthtosend) ) == NULL ) {
        sprintf(logmessage,"Error allocating memory for filelist %s",strerror(errno)) ;
        *errcode = 35 ;
        closedir(curdir) ;
        current_item = first_item ;
        while ( current_item != NULL ) {
            free(current_item->filename) ;
            used_item = current_item->next ;
            free(current_item) ;
            current_item = used_item ;
        }
        free(dirpath) ;
        return -1 ;
    }
    current_item = first_item ;
    filepos = *filelist ;
    while ( current_item != NULL ) {
        sprintf(filepos,"%s",current_item->filename) ;
        filepos = filepos + strlen(filepos) + 1 ;
        sprintf(filepos,"%s",current_item->filechar) ;
        filepos = filepos + strlen(filepos) + 1 ;
        current_item = current_item->next ;
    }
    *filelistlen = lengthtosend ;
    closedir(curdir) ;
    current_item = first_item ;
    while ( current_item != NULL ) {
        free(current_item->filename) ;
        used_item = current_item->next ;
        free(current_item) ;
        current_item = used_item ;
    }
    free(dirpath) ;
    return 0 ;   
}

/*******************************************************************************
** bbftp_retrcheckdir :                                                        *
**                                                                             *
**      Routine to check a directory                                           *
**                                                                             *
**      OUPUT variable :                                                       *
**          logmessage :  to write the error message in case of error          *
**                                                                             *
**      GLOBAL VARIABLE USED :                                                 *                                                                      *
**                                                                             *
**      RETURN:                                                                *
**          -1  Unrecoverable error                                            *
**           0  OK                                                             *
**           1  recoverable error                                              *
**                                                                             *
*******************************************************************************/

int bbftp_retrcheckdir(char *filename,char *logmessage,int *errcode)
{
#ifdef STANDART_FILE_CALL
    struct stat statbuf;
#else
    struct stat64 statbuf ;
#endif
    int     savederrno ;
    /*
    ** Check if it is a rfio creation
    */
#if defined(WITH_RFIO) || defined(WITH_RFIO64)    
    if ( (transferoption & TROPT_RFIO_O) == TROPT_RFIO_O ) {
        return bbftp_retrcheckdir_rfio(filename,logmessage,errcode) ;
    }
#endif

#ifdef STANDART_FILE_CALL
    if ( stat(filename,&statbuf) < 0 ) {
#else
    if ( stat64(filename,&statbuf) < 0 ) {
#endif
        /*
        ** It may be normal to get an error if the dir
        ** does not exist but some error code must lead
        ** to the interruption of the transfer:
        **        EACCES         : Search permission denied
        **        ELOOP          : To many symbolic links on path
        **        ENAMETOOLONG   : Path argument too long
        **        ENOTDIR        : A component in path is not a directory
        */
        savederrno = errno ;
        if ( savederrno == EACCES ||
            savederrno == ELOOP ||
            savederrno == ENAMETOOLONG ||
            savederrno == ENOTDIR ) {
            sprintf(logmessage,"Error stating file %s : %s",filename,strerror(savederrno)) ;
            *errcode = 72 ;
            return -1 ;
        } else {
            return 0 ;
        }
    } else {
        /*
        ** The file exists so check if it is a directory
        */
        if ( (statbuf.st_mode & S_IFDIR) != S_IFDIR) {
            sprintf(logmessage,"File %s is not a directory",filename) ;
            *errcode = 76 ;
            return -1 ;
        }
    }
    return 0 ;   
}

/*******************************************************************************
** bbftp_retrcheckfile :                                                       *
**                                                                             *
**      Routine to check a file and set the global parameters                  *
**                                                                             *
**      OUPUT variable :                                                       *
**          logmessage :  to write the error message in case of error          *
**                                                                             *
**      GLOBAL VARIABLE USED :                                                 *                                                                      *
**          transferoption                      NOT MODIFIED                   * 
**          filemode                            MODIFIED                       *
**          lastaccess                          MODIFIED                       *
**          lastmodif                           MODIFIED                       *
**          filesize                            MODIFIED                       *
**          requestedstreamnumber               POSSIBLY MODIFIED              *
**                                                                             *
**      RETURN:                                                                *
**          -1  Unrecoverable error                                            *
**           0  OK                                                             *
**           1  recoverable error                                              *
**                                                                             *
*******************************************************************************/

int bbftp_retrcheckfile(char *filename,char *logmessage,int *errcode)
{
#ifdef STANDART_FILE_CALL
    struct stat statbuf;
#else
    struct stat64 statbuf ;
#endif
    int     tmpnbport ;
    int     savederrno ;
    /*
    ** Check if it is a rfio creation
    */
#if defined(WITH_RFIO) || defined(WITH_RFIO64)    
    if ( (transferoption & TROPT_RFIO_O) == TROPT_RFIO_O ) {
        return bbftp_retrcheckfile_rfio(filename,logmessage,errcode) ;
    }
#endif

#ifdef STANDART_FILE_CALL
    if ( stat(filename,&statbuf) < 0 ) {
#else
    if ( stat64(filename,&statbuf) < 0 ) {
#endif
        /*
        ** It may be normal to get an error if the file
        ** does not exist but some error code must lead
        ** to the interruption of the transfer:
        **        EACCES        : Search permission denied
        **        ELOOP         : To many symbolic links on path
        **        ENAMETOOLONG  : Path argument too long
        **        ENOENT        : The file does not exists
        **        ENOTDIR       : A component in path is not a directory
        */
        savederrno = errno ;
        sprintf(logmessage,"Error stating file %s : %s ",filename,strerror(savederrno)) ;
        *errcode = 72 ;
        if ( savederrno == EACCES ||
            savederrno == ELOOP ||
            savederrno == ENAMETOOLONG ||
            savederrno == ENOENT ||
            savederrno == ENOTDIR ) {
            return -1 ;
        } else {
            return 1 ;
        }
    } else {
        /*
        ** The file exists so check if it is a directory
        */
        if ( (statbuf.st_mode & S_IFDIR) == S_IFDIR) {
            sprintf(logmessage,"File %s is a directory",filename) ;
            *errcode = 73 ;
            return -1 ;
        }
    }
    if (S_ISREG(statbuf.st_mode)) {
        filemode = statbuf.st_mode & ~S_IFREG;
    } else {
        filemode = statbuf.st_mode;
    }
    sprintf(lastaccess,"%08x",statbuf.st_atime) ;
    sprintf(lastmodif,"%08x",statbuf.st_mtime) ;
    lastaccess[8] = '\0' ;
    lastmodif[8]  = '\0' ;
    filesize = statbuf.st_size ;
    tmpnbport = filesize/(buffersizeperstream*1024) ;
    if ( tmpnbport == 0 ) {
        requestedstreamnumber = 1 ;
    } else if ( tmpnbport < nbport ) {
        requestedstreamnumber = tmpnbport ;
    } else {
        requestedstreamnumber = nbport ;
    }
    return 0 ;   
}
/*******************************************************************************
** bbftp_retrtransferfile :                                                    *
**                                                                             *
**      Routine to transfer a file                                             *
**                                                                             *
**      INPUT variable :                                                       *
**          filename    :  file to send    NOT MODIFIED                        *
**                                                                             *
**      OUTPUT variable :                                                      *
**          logmessage :  to write the error message in case of error          *
**                                                                             *
**      GLOBAL VARIABLE USED :                                                 *                                                                      *
**                                                                             *
**      RETURN:                                                                *
**          -1  transfer failed unrecoverable error                            *
**           0  Keep the connection open (does not mean that the file has been *
**              successfully transfered)                                       *
**          >0  Recoverable error but calling has the cleaning to do           *
**                                                                             *
*******************************************************************************/
 
int bbftp_retrtransferfile(char *filename,char *logmessage,int *errcode) 
{
#ifdef STANDART_FILE_CALL
    off_t       nbperchild ;
    off_t       nbtosend;
    off_t       startpoint ;
    off_t       nbread ;
    off_t       numberread ;
    off_t       nbsent ;
    off_t       realnbtosend ;
#else
    off64_t     nbperchild ;
    off64_t     nbtosend;
    off64_t     startpoint ;
    off64_t     nbread ;
    off64_t     numberread ;
    off64_t     nbsent ;
    off64_t     realnbtosend ;
#endif
#ifdef WITH_GZIP
    uLong   buflen ;
    uLong   bufcomplen ;
#endif
    int     lentosend ;
    int     retcode ;

    int     *pidfree ;
    int     *socknumber ;
    int     i ;

    int     nfds ; 
    fd_set  selectmask ;
    struct timeval    wait_timer;
    int     fd ;

    struct mess_compress *msg_compress ;
    struct message *msg ;
    int     compressionon ;
    int     sendsock ;
    int     *portnumber ;
    extern  int     simulation_mode ;

    /*
    ** Check if it is a rfio transfer
    */
#if defined(WITH_RFIO) || defined(WITH_RFIO64)    
    if ( (transferoption & TROPT_RFIO_O) == TROPT_RFIO_O ) {
        return bbftp_retrtransferfile_rfio(filename,logmessage,errcode) ;
    }
#endif
    if (protocol == 2) { /* Active mode */
      socknumber = mysockets ;
	} else { /* Passive mode */
	  portnumber = myports ;
	}
    nbperchild = filesize/requestedstreamnumber ;
    pidfree = mychildren ;

    /*
    ** Now start all our children
    */
    for (i = 1 ; i <= requestedstreamnumber ; i++) {
        if ( i == requestedstreamnumber ) {
            startpoint = (i-1)*nbperchild;
            nbtosend = filesize-(nbperchild*(requestedstreamnumber-1)) ;
        } else {
            startpoint = (i-1)*nbperchild;
            nbtosend = nbperchild ;
        }
        if (protocol == 2) {
		  sendsock = *socknumber ;
		  socknumber++ ;
		} else { /* Passive mode */
          /*
          ** Now create the socket to send
          */
          sendsock = 0 ;
          while (sendsock == 0 ) {
            sendsock = bbftp_createdatasock(*portnumber/*,logmessage*/) ;
          }
          if ( sendsock < 0 ) {
            /*
            ** We set childendinerror to 1 in order to prevent the father
            ** to send a BAD message which can desynchronize the client and the
            ** server (We need only one error message)
            ** Bug discovered by amlutz on 2000/03/11
            */
		  /*            if ( childendinerror == 0 ) {
                childendinerror = 1 ;
                reply(MSG_BAD,logmessage) ;
				}
				clean_child() ;*/
            return 1 ;
          }
          portnumber++ ;
          /*
          ** Set flagsighup to zero in order to be able in child
          ** not to wait STARTCHILDTO if signal was sent before 
          ** entering select. (Seen on Linux with one child)
          */
          /*flagsighup = 0 ;*/
		}
        if ( (retcode = fork()) == 0 ) {
            int     ns ;
            blockallsignals() ;
            /*
            ** We are in child
            */
            /* 
            ** In child the first thing to do is to 
            ** close the control socket, and all the 
            ** socket not concerning itself
            */
            close(STDIN_FILENO) ;
            close(STDOUT_FILENO) ;
            close(STDERR_FILENO) ;
            close(incontrolsock) ;
            close(outcontrolsock) ; 
			if (protocol == 2) { /* Active mode */
              int     *socktoclose ;
              socktoclose = mysockets ;
              for ( i=0 ; i< requestedstreamnumber ; i++ ) {
                if ( *socktoclose !=  sendsock) close(*socktoclose) ;
                socktoclose++ ;
              }
			}
            /*
            ** And open the file 
            */
#ifdef STANDART_FILE_CALL
            if ( (fd = open(filename,O_RDONLY|O_BINARY)) < 0 ) {
#else
            if ( (fd = open64(filename,O_RDONLY|O_BINARY)) < 0 ) {
#endif
                /*
                ** An error on openning the local file is considered
                ** as fatal. Maybe this need to be improved depending
                ** on errno
                */
                i = errno ;
                _exit(i) ;
            }
#ifdef STANDART_FILE_CALL
            if ( lseek(fd,startpoint,SEEK_SET) < 0 ) {
#else
            if ( lseek64(fd,startpoint,SEEK_SET) < 0 ) {
#endif
                i = errno ;
                close(fd) ;
                _exit(i)  ;
            }
            /*
            ** We are now just going to select on our 
            ** socket
            **/
            nfds = sysconf(_SC_OPEN_MAX) ;
            FD_ZERO(&selectmask) ;
            FD_SET(sendsock,&selectmask) ;
            /*
            ** Set the timer for the connection
            */
            wait_timer.tv_sec  = CHILDWAITTIME ;
            wait_timer.tv_usec = 0 ;
            if (protocol == 2) {
                retcode = select(FD_SETSIZE,&selectmask,0,0,&wait_timer) ;
            } else {
                retcode = select(FD_SETSIZE,0,&selectmask,0,&wait_timer) ;
            }
            if ( retcode < 0 ) {
                /*
                ** select return in error 
                ** Let us sleep a while in order to let
                ** the father fork all its children
                */
                i = errno ;
                close(fd) ;
                sleep(CHILDWAITTIME) ;
                _exit(i) ;
            }
            if ( retcode == 0 ) {
                /*
                ** That is a time out let us exit 
                ** with the time out error
                */
                close(fd) ;
                _exit(ETIMEDOUT) ;
            }
            /*
            ** At this point as we only set one bit we have 
            ** got a connection
            */
			if (protocol == 2) { /* Active mode */
              if ( (ns = accept(sendsock,0,0) ) < 0 ) {
                i = errno ;
                close(fd) ;
                _exit(i) ;
              }
              /*
              ** Close the listening socket
              */
              close(sendsock) ;
			} else {
			  ns = sendsock ;
			  /*close(sendsock) ;*/
			}
            /*
            ** Start the sending loop
            ** In simulation mode, simulate the transfer
            */
            if (!simulation_mode) {
              nbread = 0 ;
              while ( nbread < nbtosend ) {
                if ( (numberread = read ( fd, readbuffer, ( (buffersizeperstream*1024) <= nbtosend - nbread) ?  (buffersizeperstream*1024) : nbtosend-nbread) ) > 0 ) {
                    nbread = nbread+numberread ;
#ifdef WITH_GZIP                    
                    if ( (transferoption & TROPT_GZIP ) == TROPT_GZIP ) {
                        /*
                        ** In case of compression we are going to use
                        ** a temporary buffer
                        */
                        bufcomplen = buffersizeperstream*1024 ;
                        buflen = numberread ;
                        retcode = compress((Bytef *)compbuffer,&bufcomplen,(Bytef *)readbuffer,buflen) ;
                        if ( retcode != 0 ) {
                            msg_compress = ( struct mess_compress *) compbuffer;
                            /*
                            ** Compress error, in this cas we are sending the
                            ** date uncompressed
                            */
                            msg_compress->code = DATA_NOCOMPRESS ;
                            lentosend = numberread ;
#ifndef WORDS_BIGENDIAN
                            msg_compress->datalen = ntohl(lentosend) ;
#else
                            msg_compress->datalen = lentosend ;
#endif
                            realnbtosend = numberread ;
                        } else {
                            memcpy(readbuffer,compbuffer,buffersizeperstream*1024) ;
                            msg_compress = ( struct mess_compress *) compbuffer;
                            msg_compress->code = DATA_COMPRESS ;
                            lentosend = bufcomplen ;
#ifndef WORDS_BIGENDIAN
                            msg_compress->datalen = ntohl(lentosend) ;
#else
                            msg_compress->datalen = lentosend ;
#endif
                            realnbtosend =  bufcomplen ;
                        }
                        /*
                        ** Send the header
                        */
                        if ( writemessage(ns,compbuffer,COMPMESSLEN,datato,1) < 0 ) {
                            i = ETIMEDOUT ;
                            _exit(i) ;
                        }
                    } else {
                        realnbtosend = numberread ;
                    }
#else
                    realnbtosend = numberread ;
#endif                    
                    /*
                    ** Send the data
                    */
                    nbsent = 0 ;
                    while ( nbsent < realnbtosend ) {
                        lentosend = realnbtosend-nbsent ;
                        nfds = sysconf(_SC_OPEN_MAX) ;
                        FD_ZERO(&selectmask) ;
                        FD_SET(ns,&selectmask) ;
                        wait_timer.tv_sec  = datato  ;
                        wait_timer.tv_usec = 0 ;
                        if ( (retcode = select(FD_SETSIZE,0,&selectmask,0,&wait_timer) ) == -1 ) {
                            /*
                            ** Select error
                            */
                            i = errno ;
                            close(fd) ;
                            close(ns) ;
                            _exit(i) ;
                        } else if ( retcode == 0 ) {
                            close(fd) ;
                            i=ETIMEDOUT ;
                            close(ns) ;
                            _exit(i) ;
                        } else {
                            retcode = send(ns,&readbuffer[nbsent],lentosend,0) ;
                            if ( retcode < 0 ) {
                                i = errno ;
                                close(fd) ;
                                close(ns) ;
                                _exit(i) ;
                            } else if ( retcode == 0 ) {
                                i = ECONNRESET ;
                                close(fd) ;
                                close(ns) ;
                                _exit(i) ;
                            } else {
                                nbsent = nbsent+retcode ;
                            }
                        }
                    }
                } else {
                    i = errno ;
                    close(ns) ;
                    close(fd) ;
                    _exit(i) ;
                }
              }
              close(fd) ;
              /*
              ** All data has been sent so wait for the acknoledge
              */
              if ( readmessage(ns,readbuffer,MINMESSLEN,ackto,1) < 0 ) {
                close(ns) ;
                _exit(ETIMEDOUT) ;
              }
              msg = (struct message *) readbuffer ;
              if ( msg->code != MSG_ACK) {
                close(ns) ;
                _exit(1) ;
              }
			}
            close(ns) ;
            _exit(0) ;
        } else {
            /*
            ** We are in father
            */
            if ( retcode == -1 ) {
                /*
                ** Fork failed ...
                */
                sprintf(logmessage,"Fork failed : %s\n",strerror(errno)) ;
                *errcode = 36 ;
                sprintf(logmessage,"fork failed : %s ",strerror(errno)) ;
                bbftp_clean_child() ;
                return -1 ;
            } else {
                *pidfree++ = retcode ;
		close(sendsock) ;
                /*socknumber++ ;*/
            }
        }
    }
    return 0 ;
}
Пример #11
0
/* Start a recursive command.

   Command line arguments (ARGC, ARGV) dictate the directories and
   files on which we operate.  In the special case of no arguments, we
   default to ".".  */
int start_recursion (FILEPROC fileproc, FILESDONEPROC filesdoneproc,
    PREDIRENTPROC predirentproc, DIRENTPROC direntproc, DIRLEAVEPROC dirleaveproc,
    void *callerdat,

    int argc,
    char **argv,
    int local,

    /* This specifies the kind of recursion.  There are several cases:

       1.  W_LOCAL is not set but W_REPOS is.  The current
       directory when we are called must be the repository and
       recursion proceeds according to what exists in the repository.

       2a.  W_LOCAL is set but W_REPOS is not.  The
       current directory when we are called must be the working
       directory.  Recursion proceeds according to what exists in the
       working directory, never (I think) consulting any part of the
       repository which does not correspond to the working directory
       ("correspond" == Name_Repository).

       2b.  W_LOCAL is set and so is W_REPOS.  This is the
       weird one.  The current directory when we are called must be
       the working directory.  We recurse through working directories,
       but we recurse into a directory if it is exists in the working
       directory *or* it exists in the repository.  If a directory
       does not exist in the working directory, the direntproc must
       either tell us to skip it (R_SKIP_ALL), or must create it (I
       think those are the only two cases).  */
    int which,

    int aflag,
    int readlock,
    const char *update_preload,
	const char *repos_preload,
    int dosrcs,
    PERMPROC permproc,
    const char *tag)
{
    int i, err = 0;
    List *args_to_send_when_finished = NULL;
    List *files_by_dir = NULL;
    struct recursion_frame frame;

	TRACE(3,"start_recursion()");	

    frame.fileproc = fileproc;
    frame.filesdoneproc = filesdoneproc;
	frame.predirentproc = predirentproc;
    frame.direntproc = direntproc;
    frame.dirleaveproc = dirleaveproc;
    frame.callerdat = callerdat;
    frame.flags = local ? R_SKIP_DIRS : R_PROCESS;
    frame.which = which;
    frame.aflag = aflag;
    frame.readlock = readlock;
    frame.dosrcs = dosrcs;
    frame.permproc = permproc;
    frame.tag = tag;

    expand_wild (argc, argv, &argc, &argv);

    if (update_preload == NULL)
	update_dir = xstrdup ("");
    else
	update_dir = xstrdup (update_preload);

    /* clean up from any previous calls to start_recursion */
	xfree (repository);
    if (filelist)
	dellist (&filelist); /* FIXME-krp: no longer correct. */
    if (dirlist)
	dellist (&dirlist);

	update_repos = xstrdup(repos_preload);

	for (i = 0; i < argc; ++i)
	{
#ifdef SERVER_SUPPORT
	    if (server_active)
		    server_pathname_check (argv[i]);
		else
#endif
			if(isabsolute(argv[i]))
				error(1,0,"Absolute filenames not allowed");
    }

    if (argc == 0)
    {
	int just_subdirs = (which & W_LOCAL) && !noexec && !isdir (CVSADM);

	if (!just_subdirs
	    && CVSroot_cmdline == NULL
	    && current_parsed_root->isremote)
	{
	    char *root = Name_Root (NULL, update_dir);
	    if (root && strcmp (root, current_parsed_root->original) != 0)
		/* We're skipping this directory because it is for
		   a different root.  Therefore, we just want to
		   do the subdirectories only.  Processing files would
		   cause a working directory from one repository to be
		   processed against a different repository, which could
		   cause all kinds of spurious conflicts and such.

		   Question: what about the case of "cvs update foo"
		   where we process foo/bar and not foo itself?  That
		   seems to be handled somewhere (else) but why should
		   it be a separate case?  Needs investigation...  */
		just_subdirs = 1;
	    xfree (root);
	}

	/*
	 * There were no arguments, so we'll probably just recurse. The
	 * exception to the rule is when we are called from a directory
	 * without any CVS administration files.  That has always meant to
	 * process each of the sub-directories, so we pretend like we were
	 * called with the list of sub-dirs of the current dir as args
	 */
	if (just_subdirs)
	{
	    dirlist = Find_Directories ((char *) NULL, W_LOCAL, (List *) NULL, NULL);
	    /* If there are no sub-directories, there is a certain logic in
	       favor of doing nothing, but in fact probably the user is just
	       confused about what directory they are in, or whether they
	       cvs add'd a new directory.  In the case of at least one
	       sub-directory, at least when we recurse into them we
	       notice (hopefully) whether they are under CVS control.  */
	    if (list_isempty (dirlist) && !noexec)
	    {
		if (update_dir[0] == '\0')
		    error (0, 0, "in directory .:");
		else
		    error (0, 0, "in directory %s:", update_dir);
		error (1, 0,
		       "there is no version here; run '%s checkout' first",
		       program_name);
	    }
	    else if (current_parsed_root->isremote && server_started)
	    {
		/* In the the case "cvs update foo bar baz", a call to
		   send_file_names in update.c will have sent the
		   appropriate "Argument" commands to the server.  In
		   this case, that won't have happened, so we need to
		   do it here.  While this example uses "update", this
		   generalizes to other commands.  */

		/* This is the same call to Find_Directories as above.
                   FIXME: perhaps it would be better to write a
                   function that duplicates a list. */
		args_to_send_when_finished = Find_Directories ((char *) NULL,
							       W_LOCAL,
							       (List *) NULL, NULL);
	    }
	}
	else
	{
	    addlist (&dirlist, ".");
	}

	goto do_the_work;
    }


    /*
     * There were arguments, so we have to handle them by hand. To do
     * that, we set up the filelist and dirlist with the arguments and
     * call do_recursion.  do_recursion recognizes the fact that the
     * lists are non-null when it starts and doesn't update them.
     *
     * explicitly named directories are stored in dirlist.
     * explicitly named files are stored in filelist.
     * other possibility is named entities whicha are not currently in
     * the working directory.
     */
    
    for (i = 0; i < argc; i++)
    {
	/* if this argument is a directory, then add it to the list of
	   directories. */

	if (isdir (argv[i]))
	{
	    strip_trailing_slashes (argv[i]);
	    addlist (&dirlist, argv[i]);
	}
	else
	{
	    /* otherwise, split argument into directory and component names. */
	    char *dir;
	    char *comp;
	    char *file_to_try;

	    /* Now break out argv[i] into directory part (DIR) and file part (COMP).
		   DIR and COMP will each point to a newly malloc'd string.  */
	    dir = xstrdup (argv[i]);
	    comp = (char*)last_component (dir);
	    if (comp == dir)
	    {
		/* no dir component.  What we have is an implied "./" */
		dir = xstrdup(".");
	    }
	    else
	    {
		char *p = comp;

		p[-1] = '\0';
		comp = xstrdup (p);
	    }

	    /* if this argument exists as a file in the current
	       working directory tree, then add it to the files list.  */

	    if (!(which & W_LOCAL))
	    {
		/* If doing rtag, we've done a chdir to the repository. */
		file_to_try = (char*)xmalloc (strlen (argv[i]) + sizeof (RCSEXT) + 5);
		sprintf (file_to_try, "%s%s", argv[i], RCSEXT);
	    }
	    else
		file_to_try = xstrdup (argv[i]);

	    if (isfile (file_to_try))
	    {
			const char *tag;
			const char *date;
			int nonbranch;
			const char *message;
			const char *v_type;
			/* before we do anything else, see if we have any
			   per-directory tags */

			ParseTag_Dir (dir, &tag, &date, &nonbranch, NULL);
			
	        if (! verify_access (frame.permproc, dir, file_to_try, update_dir,tag,&message,&v_type))
			{
				if(tag && !quiet && !(which&W_QUIET))
					error (0, 0, "User %s is unable to %s %s/%s on branch/tag %s - ignoring",CVS_Username,v_type,dir,file_to_try?file_to_try:"",tag);
				else if(!quiet && !(which&W_QUIET))
					error (0, 0, "User %s is unable to %s %s/%s - ignoring",CVS_Username,v_type,dir,file_to_try?file_to_try:"");
				if(message && !quiet && !(which&W_QUIET))
					error (0, 0, "%s", message);
			}
			else
		{
		   addfile (&files_by_dir, dir, comp);
		}
	    }
	    else if (isdir (dir))
	    {
		if ((which & W_LOCAL) && isdir (CVSADM)
		    && !current_parsed_root->isremote
		    )
		{
		    /* otherwise, look for it in the repository. */
		    char *tmp_update_dir;
		    char *repos;
		    char *reposfile;

		    tmp_update_dir = (char*)xmalloc (strlen (update_dir)
					      + strlen (dir)
					      + 5);
		    strcpy (tmp_update_dir, update_dir);

		    if (*tmp_update_dir != '\0')
			(void) strcat (tmp_update_dir, "/");

		    (void) strcat (tmp_update_dir, dir);

		    /* look for it in the repository. */
		    repos = Name_Repository (dir, tmp_update_dir);
		    reposfile = (char*)xmalloc (strlen (repos)
					 + strlen (comp)
					 + 5);
		    (void) sprintf (reposfile, "%s/%s", repos, comp);
		    xfree (repos);

		    if (isdir (reposfile))
			{
			addlist (&dirlist, argv[i]);
			}
		    else
			addfile (&files_by_dir, dir, comp);

		    xfree (tmp_update_dir);
		    xfree (reposfile);
		}
		else
		    addfile (&files_by_dir, dir, comp);
	    }
	    else
		{
			error (1, 0, "no such directory `%s'", dir);
		}

	    xfree (file_to_try);
	    xfree (dir);
	    xfree (comp);
	}
    }

    /* At this point we have looped over all named arguments and built
       a coupla lists.  Now we unroll the lists, setting up and
       calling do_recursion. */

    err += walklist (files_by_dir, unroll_files_proc, (void *) &frame);
    if (files_by_dir)
    dellist(&files_by_dir);

    /* then do_recursion on the dirlist. */
    if (dirlist != NULL)
    {
    do_the_work:
	err += do_recursion (&frame, 1);
    }
	
    /* Free the data which expand_wild allocated.  */
    free_names (&argc, argv);

    xfree (update_dir);
	xfree (update_repos);

    if (args_to_send_when_finished != NULL)
    {
	/* FIXME (njc): in the multiroot case, we don't want to send
	   argument commands for those top-level directories which do
	   not contain any subdirectories which have files checked out
	   from current_parsed_root->original.  If we do, and two repositories
	   have a module with the same name, nasty things could happen.

	   This is hard.  Perhaps we should send the Argument commands
	   later in this procedure, after we've had a chance to notice
	   which directores we're using (after do_recursion has been
	   called once).  This means a _lot_ of rewriting, however.

	   What we need to do for that to happen is descend the tree
	   and construct a list of directories which are checked out
	   from current_cvsroot.  Now, we eliminate from the list all
	   of those directories which are immediate subdirectories of
	   another directory in the list.  To say that the opposite
	   way, we keep the directories which are not immediate
	   subdirectories of any other in the list.  Here's a picture:

			      a
			     / \
			    B   C
			   / \
			  D   e
			     / \
			    F   G
			       / \
			      H   I

	   The node in capitals are those directories which are
	   checked out from current_cvsroot.  We want the list to
	   contain B, C, F, and G.  D, H, and I are not included,
	   because their parents are also checked out from
	   current_cvsroot.

	   The algorithm should be:
		   
	   1) construct a tree of all directory names where each
	   element contains a directory name and a flag which notes if
	   that directory is checked out from current_cvsroot

			      a0
			     / \
			    B1  C1
			   / \
			  D1  e0
			     / \
			    F1  G1
			       / \
			      H1  I1

	   2) Recursively descend the tree.  For each node, recurse
	   before processing the node.  If the flag is zero, do
	   nothing.  If the flag is 1, check the node's parent.  If
	   the parent's flag is one, change the current entry's flag
	   to zero.

			      a0
			     / \
			    B1  C1
			   / \
			  D0  e0
			     / \
			    F1  G1
			       / \
			      H0  I0

	   3) Walk the tree and spit out "Argument" commands to tell
	   the server which directories to munge.
		   
	   Yuck.  It's not clear this is worth spending time on, since
	   we might want to disable cvs commands entirely from
	   directories that do not have CVSADM files...

	   Anyways, the solution as it stands has modified server.c
	   (dirswitch) to create admin files [via server.c
	   (create_adm_p)] in all path elements for a client's
	   "Directory xxx" command, which forces the server to descend
	   and serve the files there.  client.c (send_file_names) has
	   also been modified to send only those arguments which are
	   appropriate to current_parsed_root->original.

	*/
		
	/* Construct a fake argc/argv pair. */
		
	int our_argc = 0, i;
	char **our_argv = NULL;

	if (! list_isempty (args_to_send_when_finished))
	{
	    Node *head, *p;

	    head = args_to_send_when_finished->list;

	    /* count the number of nodes */
	    i = 0;
	    for (p = head->next; p != head; p = p->next)
		i++;
	    our_argc = i;

	    /* create the argument vector */
	    our_argv = (char **) xmalloc (sizeof (char *) * our_argc);

	    /* populate it */
	    i = 0;
	    for (p = head->next; p != head; p = p->next)
		our_argv[i++] = xstrdup (p->key);
	}

	/* We don't want to expand widcards, since we've just created
	   a list of directories directly from the filesystem. */
	send_file_names (our_argc, our_argv, 0);

	/* Free our argc/argv. */
	if (our_argv != NULL)
	{
	    for (i = 0; i < our_argc; i++)
		xfree (our_argv[i]);
	    xfree (our_argv);
	}

	if (args_to_send_when_finished)
	dellist (&args_to_send_when_finished);
    }
    
    return (err);
}
Пример #12
0
/*
 * This is the recursive function that processes a module name.
 * It calls back the passed routine for each directory of a module
 * It runs the post checkout or post tag proc from the modules file
 */
int
my_module (DBM *db, char *mname, enum mtype m_type, char *msg,
            CALLBACKPROC callback_proc, char *where, int shorten,
            int local_specified, int run_module_prog, int build_dirs,
            char *extra_arg, List *stack)
{
    char *checkout_prog = NULL;
    char *export_prog = NULL;
    char *tag_prog = NULL;
    struct saved_cwd cwd;
    int cwd_saved = 0;
    char *line;
    int modargc;
    int xmodargc;
    char **modargv = NULL;
    char **xmodargv = NULL;
    /* Found entry from modules file, including options and such.  */
    char *value = NULL;
    char *mwhere = NULL;
    char *mfile = NULL;
    char *spec_opt = NULL;
    char *xvalue = NULL;
    int alias = 0;
    datum key, val;
    char *cp;
    int c, err = 0;
    int nonalias_opt = 0;

#ifdef SERVER_SUPPORT
    int restore_server_dir = 0;
    char *server_dir_to_restore = NULL;
#endif

    TRACE (TRACE_FUNCTION, "my_module (%s, %s, %s, %s)",
           mname ? mname : "(null)", msg ? msg : "(null)",
           where ? where : "NULL", extra_arg ? extra_arg : "NULL");

    /* Don't process absolute directories.  Anything else could be a security
     * problem.  Before this check was put in place:
     *
     *   $ cvs -d:fork:/cvsroot co /foo
     *   cvs server: warning: cannot make directory CVS in /: Permission denied
     *   cvs [server aborted]: cannot make directory /foo: Permission denied
     *   $
     */
    if (ISABSOLUTE (mname))
	error (1, 0, "Absolute module reference invalid: `%s'", mname);

    /* Similarly for directories that attempt to step above the root of the
     * repository.
     */
    if (pathname_levels (mname) > 0)
	error (1, 0, "up-level in module reference (`..') invalid: `%s'.",
               mname);

    /* if this is a directory to ignore, add it to that list */
    if (mname[0] == '!' && mname[1] != '\0')
    {
	ign_dir_add (mname+1);
	goto do_module_return;
    }

    /* strip extra stuff from the module name */
    strip_trailing_slashes (mname);

    /*
     * Look up the module using the following scheme:
     *	1) look for mname as a module name
     *	2) look for mname as a directory
     *	3) look for mname as a file
     *  4) take mname up to the first slash and look it up as a module name
     *	   (this is for checking out only part of a module)
     */

    /* look it up as a module name */
    key.dptr = mname;
    key.dsize = strlen (key.dptr);
    if (db != NULL)
	val = dbm_fetch (db, key);
    else
	val.dptr = NULL;
    if (val.dptr != NULL)
    {
	/* copy and null terminate the value */
	value = xmalloc (val.dsize + 1);
	memcpy (value, val.dptr, val.dsize);
	value[val.dsize] = '\0';

	/* If the line ends in a comment, strip it off */
	if ((cp = strchr (value, '#')) != NULL)
	    *cp = '\0';
	else
	    cp = value + val.dsize;

	/* Always strip trailing spaces */
	while (cp > value && isspace ((unsigned char) *--cp))
	    *cp = '\0';

	mwhere = xstrdup (mname);
	goto found;
    }
    else
    {
	char *file;
	char *attic_file;
	char *acp;
	int is_found = 0;

	/* check to see if mname is a directory or file */
	file = xmalloc (strlen (current_parsed_root->directory)
			+ strlen (mname) + sizeof(RCSEXT) + 2);
	(void) sprintf (file, "%s/%s", current_parsed_root->directory, mname);
	attic_file = xmalloc (strlen (current_parsed_root->directory)
			      + strlen (mname)
			      + sizeof (CVSATTIC) + sizeof (RCSEXT) + 3);
	if ((acp = strrchr (mname, '/')) != NULL)
	{
	    *acp = '\0';
	    (void) sprintf (attic_file, "%s/%s/%s/%s%s", current_parsed_root->directory,
			    mname, CVSATTIC, acp + 1, RCSEXT);
	    *acp = '/';
	}
	else
	    (void) sprintf (attic_file, "%s/%s/%s%s",
	                    current_parsed_root->directory,
			    CVSATTIC, mname, RCSEXT);

	if (isdir (file))
	{
	    modargv = xmalloc (sizeof (*modargv));
	    modargv[0] = xstrdup (mname);
	    modargc = 1;
	    is_found = 1;
	}
	else
	{
	    (void) strcat (file, RCSEXT);
	    if (isfile (file) || isfile (attic_file))
	    {
		/* if mname was a file, we have to split it into "dir file" */
		if ((cp = strrchr (mname, '/')) != NULL && cp != mname)
		{
		    modargv = xnmalloc (2, sizeof (*modargv));
		    modargv[0] = xmalloc (strlen (mname) + 2);
		    strncpy (modargv[0], mname, cp - mname);
		    modargv[0][cp - mname] = '\0';
		    modargv[1] = xstrdup (cp + 1);
		    modargc = 2;
		}
		else
		{
		    /*
		     * the only '/' at the beginning or no '/' at all
		     * means the file we are interested in is in CVSROOT
		     * itself so the directory should be '.'
		     */
		    if (cp == mname)
		    {
			/* drop the leading / if specified */
			modargv = xnmalloc (2, sizeof (*modargv));
			modargv[0] = xstrdup (".");
			modargv[1] = xstrdup (mname + 1);
			modargc = 2;
		    }
		    else
		    {
			/* otherwise just copy it */
			modargv = xnmalloc (2, sizeof (*modargv));
			modargv[0] = xstrdup (".");
			modargv[1] = xstrdup (mname);
			modargc = 2;
		    }
		}
		is_found = 1;
	    }
	}
	free (attic_file);
	free (file);

	if (is_found)
	{
	    assert (value == NULL);

	    /* OK, we have now set up modargv with the actual
	       file/directory we want to work on.  We duplicate a
	       small amount of code here because the vast majority of
	       the code after the "found" label does not pertain to
	       the case where we found a file/directory rather than
	       finding an entry in the modules file.  */
	    if (save_cwd (&cwd))
		error (1, errno, "Failed to save current directory.");
	    cwd_saved = 1;

	    err += callback_proc (modargc, modargv, where, mwhere, mfile,
				  shorten,
				  local_specified, mname, msg);

	    free_names (&modargc, modargv);

	    /* cd back to where we started.  */
	    if (restore_cwd (&cwd))
		error (1, errno, "Failed to restore current directory, `%s'.",
		       cwd.name);
	    free_cwd (&cwd);
	    cwd_saved = 0;

	    goto do_module_return;
	}
    }

    /* look up everything to the first / as a module */
    if (mname[0] != '/' && (cp = strchr (mname, '/')) != NULL)
    {
	/* Make the slash the new end of the string temporarily */
	*cp = '\0';
	key.dptr = mname;
	key.dsize = strlen (key.dptr);

	/* do the lookup */
	if (db != NULL)
	    val = dbm_fetch (db, key);
	else
	    val.dptr = NULL;

	/* if we found it, clean up the value and life is good */
	if (val.dptr != NULL)
	{
	    char *cp2;

	    /* copy and null terminate the value */
	    value = xmalloc (val.dsize + 1);
	    memcpy (value, val.dptr, val.dsize);
	    value[val.dsize] = '\0';

	    /* If the line ends in a comment, strip it off */
	    if ((cp2 = strchr (value, '#')) != NULL)
		*cp2 = '\0';
	    else
		cp2 = value + val.dsize;

	    /* Always strip trailing spaces */
	    while (cp2 > value  &&  isspace ((unsigned char) *--cp2))
		*cp2 = '\0';

	    /* mwhere gets just the module name */
	    mwhere = xstrdup (mname);
	    mfile = cp + 1;
	    assert (strlen (mfile));

	    /* put the / back in mname */
	    *cp = '/';

	    goto found;
	}

	/* put the / back in mname */
	*cp = '/';
    }

    /* if we got here, we couldn't find it using our search, so give up */
    error (0, 0, "cannot find module `%s' - ignored", mname);
    err++;
    goto do_module_return;


    /*
     * At this point, we found what we were looking for in one
     * of the many different forms.
     */
  found:

    /* remember where we start */
    if (save_cwd (&cwd))
	error (1, errno, "Failed to save current directory.");
    cwd_saved = 1;

    assert (value != NULL);

    /* search the value for the special delimiter and save for later */
    if ((cp = strchr (value, CVSMODULE_SPEC)) != NULL)
    {
	*cp = '\0';			/* null out the special char */
	spec_opt = cp + 1;		/* save the options for later */

	/* strip whitespace if necessary */
	while (cp > value  &&  isspace ((unsigned char) *--cp))
	    *cp = '\0';
    }

    /* don't do special options only part of a module was specified */
    if (mfile != NULL)
	spec_opt = NULL;

    /*
     * value now contains one of the following:
     *    1) dir
     *	  2) dir file
     *    3) the value from modules without any special args
     *		    [ args ] dir [file] [file] ...
     *	     or     -a module [ module ] ...
     */

    /* Put the value on a line with XXX prepended for getopt to eat */
    line = Xasprintf ("XXX %s", value);

    /* turn the line into an argv[] array */
    line2argv (&xmodargc, &xmodargv, line, " \t");
    free (line);
    modargc = xmodargc;
    modargv = xmodargv;

    /* parse the args */
    getoptreset ();
    while ((c = getopt (modargc, modargv, CVSMODULE_OPTS)) != -1)
    {
	switch (c)
	{
	    case 'a':
		alias = 1;
		break;
	    case 'd':
		if (mwhere)
		    free (mwhere);
		mwhere = xstrdup (optarg);
		nonalias_opt = 1;
		break;
	    case 'l':
		local_specified = 1;
		nonalias_opt = 1;
		break;
	    case 'o':
		if (checkout_prog)
		    free (checkout_prog);
		checkout_prog = xstrdup (optarg);
		nonalias_opt = 1;
		break;
	    case 'e':
		if (export_prog)
		    free (export_prog);
		export_prog = xstrdup (optarg);
		nonalias_opt = 1;
		break;
	    case 't':
		if (tag_prog)
		    free (tag_prog);
		tag_prog = xstrdup (optarg);
		nonalias_opt = 1;
		break;
	    case '?':
		error (0, 0,
		       "modules file has invalid option for key %s value %s",
		       key.dptr, value);
		err++;
		goto do_module_return;
	}
    }
    modargc -= optind;
    modargv += optind;
    if (modargc == 0  &&  spec_opt == NULL)
    {
	error (0, 0, "modules file missing directory for module %s", mname);
	++err;
	goto do_module_return;
    }

    if (alias && nonalias_opt)
    {
	/* The documentation has never said it is valid to specify
	   -a along with another option.  And I believe that in the past
	   CVS has ignored the options other than -a, more or less, in this
	   situation.  */
	error (0, 0, "\
-a cannot be specified in the modules file along with other options");
	++err;
	goto do_module_return;
    }
Пример #13
0
int autoupgrade_client(struct async *as, struct conf *conf)
{
	int a=0;
	int ret=-1;
	char *cp=NULL;
	char *copy=NULL;
	char *script_path=NULL;
	char script_name[32]="";
	char package_name[32]="";
	char write_str[256]="";
	const char *args[2];
	struct iobuf *rbuf=NULL;
	struct asfd *asfd;
	asfd=as->asfd;

	if(!conf->autoupgrade_dir)
	{
		logp("autoupgrade_dir not set!\n");
		goto end;
	}
	if(!conf->autoupgrade_os)
	{
		logp("autoupgrade_os not set!\n");
		goto end;
	}
	if(!(copy=strdup(conf->autoupgrade_dir)))
	{
		log_out_of_memory(__func__);
		goto end;
	}

	strip_trailing_slashes(&copy);
	if((cp=strchr(copy, '/'))) *cp='\0';
	if(mkpath(&(conf->autoupgrade_dir), copy))
		goto end;

	// Let the server know we are ready.
	snprintf(write_str, sizeof(write_str),
		"autoupgrade:%s", conf->autoupgrade_os);
	if(asfd->write_str(asfd, CMD_GEN, write_str))
		goto end;

	if(!(a=asfd->simple_loop(asfd,
		conf, NULL, __func__, autoupgrade_func)))
	{
		ret=0; // No autoupgrade.
		goto end;
	}
	else if(a<0) // Error.

#ifdef HAVE_WIN32
	win32_enable_backup_privileges();
	snprintf(script_name, sizeof(script_name), "script.bat");
	snprintf(package_name, sizeof(package_name), "package.exe");
#else
	snprintf(script_name, sizeof(script_name), "script");
	snprintf(package_name, sizeof(package_name), "package");
#endif

	if(receive_file(asfd, conf->autoupgrade_dir, script_name, conf))
	{
		logp("Problem receiving %s/%s\n",
			conf->autoupgrade_dir, script_name);
		goto end;
	}
	if(receive_file(asfd, conf->autoupgrade_dir, package_name, conf))
	{
		logp("Problem receiving %s/%s\n",
			conf->autoupgrade_dir, package_name);
		goto end;
	}

	if(!(script_path=prepend_s(conf->autoupgrade_dir, script_name)))
		goto end;

	chmod(script_path, 0755);

	/* Run the script here. */
	a=0;
	args[a++]=script_path;
	args[a++]=NULL;
	ret=run_script(asfd, args, NULL, conf,
		0 /* do not wait */, 1 /* use logp */, 1 /* use logw */);
	/* To get round Windows problems to do with installing over files
	   that the current process is running from, I am forking the child,
	   then immediately exiting the parent process. */

	printf("\n");
	logp("The server tried to upgrade your client.\n");
	logp("You will need to try your command again.\n");
	asfd_free(&as->asfd);

	exit(0);
end:
	if(copy) free(copy);
	if(script_path) free(script_path);
	iobuf_free(rbuf);
	return ret;
}
Пример #14
0
int cmd_clone(int argc, const char **argv, const char *prefix)
{
	int use_local_hardlinks = 1;
	int use_separate_remote = 1;
	int is_bundle = 0;
	struct stat buf;
	const char *repo_name, *repo, *work_tree, *git_dir;
	char *path, *dir;
	const struct ref *refs, *head_points_at, *remote_head, *mapped_refs;
	char branch_top[256], key[256], value[256];
	struct strbuf reflog_msg = STRBUF_INIT;
	struct transport *transport = NULL;
	char *src_ref_prefix = "refs/heads/";

	struct refspec refspec;

	junk_pid = getpid();

	argc = parse_options(argc, argv, builtin_clone_options,
			     builtin_clone_usage, 0);

	if (argc == 0)
		die("You must specify a repository to clone.");

	if (option_no_hardlinks)
		use_local_hardlinks = 0;

	if (option_mirror)
		option_bare = 1;

	if (option_bare) {
		if (option_origin)
			die("--bare and --origin %s options are incompatible.",
			    option_origin);
		option_no_checkout = 1;
		use_separate_remote = 0;
	}

	if (!option_origin)
		option_origin = "origin";

	repo_name = argv[0];

	path = get_repo_path(repo_name, &is_bundle);
	if (path)
		repo = xstrdup(make_nonrelative_path(repo_name));
	else if (!strchr(repo_name, ':'))
		repo = xstrdup(make_absolute_path(repo_name));
	else
		repo = repo_name;

	if (argc == 2)
		dir = xstrdup(argv[1]);
	else
		dir = guess_dir_name(repo_name, is_bundle, option_bare);
	strip_trailing_slashes(dir);

	if (!stat(dir, &buf))
		die("destination directory '%s' already exists.", dir);

	strbuf_addf(&reflog_msg, "clone: from %s", repo);

	if (option_bare)
		work_tree = NULL;
	else {
		work_tree = getenv("GIT_WORK_TREE");
		if (work_tree && !stat(work_tree, &buf))
			die("working tree '%s' already exists.", work_tree);
	}

	if (option_bare || work_tree)
		git_dir = xstrdup(dir);
	else {
		work_tree = dir;
		git_dir = xstrdup(mkpath("%s/.git", dir));
	}

	if (!option_bare) {
		junk_work_tree = work_tree;
		if (safe_create_leading_directories_const(work_tree) < 0)
			die("could not create leading directories of '%s': %s",
					work_tree, strerror(errno));
		if (mkdir(work_tree, 0755))
			die("could not create work tree dir '%s': %s.",
					work_tree, strerror(errno));
		set_git_work_tree(work_tree);
	}
	junk_git_dir = git_dir;
	atexit(remove_junk);
	signal(SIGINT, remove_junk_on_signal);

	setenv(CONFIG_ENVIRONMENT, xstrdup(mkpath("%s/config", git_dir)), 1);

	if (safe_create_leading_directories_const(git_dir) < 0)
		die("could not create leading directories of '%s'", git_dir);
	set_git_dir(make_absolute_path(git_dir));

	init_db(option_template, option_quiet ? INIT_DB_QUIET : 0);

	/*
	 * At this point, the config exists, so we do not need the
	 * environment variable.  We actually need to unset it, too, to
	 * re-enable parsing of the global configs.
	 */
	unsetenv(CONFIG_ENVIRONMENT);

	if (option_reference)
		setup_reference(git_dir);

	git_config(git_default_config, NULL);

	if (option_bare) {
		if (option_mirror)
			src_ref_prefix = "refs/";
		strcpy(branch_top, src_ref_prefix);

		git_config_set("core.bare", "true");
	} else {
		snprintf(branch_top, sizeof(branch_top),
			 "refs/remotes/%s/", option_origin);
	}

	if (option_mirror || !option_bare) {
		/* Configure the remote */
		if (option_mirror) {
			snprintf(key, sizeof(key),
					"remote.%s.mirror", option_origin);
			git_config_set(key, "true");
		}

		snprintf(key, sizeof(key), "remote.%s.url", option_origin);
		git_config_set(key, repo);

		snprintf(key, sizeof(key), "remote.%s.fetch", option_origin);
		snprintf(value, sizeof(value),
				"+%s*:%s*", src_ref_prefix, branch_top);
		git_config_set_multivar(key, value, "^$", 0);
	}

	refspec.force = 0;
	refspec.pattern = 1;
	refspec.src = src_ref_prefix;
	refspec.dst = branch_top;

	if (path && !is_bundle)
		refs = clone_local(path, git_dir);
	else {
		struct remote *remote = remote_get(argv[0]);
		transport = transport_get(remote, remote->url[0]);

		if (!transport->get_refs_list || !transport->fetch)
			die("Don't know how to clone %s", transport->url);

		transport_set_option(transport, TRANS_OPT_KEEP, "yes");

		if (option_depth)
			transport_set_option(transport, TRANS_OPT_DEPTH,
					     option_depth);

		if (option_quiet)
			transport->verbose = -1;
		else if (option_verbose)
			transport->progress = 1;

		if (option_upload_pack)
			transport_set_option(transport, TRANS_OPT_UPLOADPACK,
					     option_upload_pack);

		refs = transport_get_remote_refs(transport);
		transport_fetch_refs(transport, refs);
	}

	clear_extra_refs();

	mapped_refs = write_remote_refs(refs, &refspec, reflog_msg.buf);

	head_points_at = locate_head(refs, mapped_refs, &remote_head);

	if (head_points_at) {
		/* Local default branch link */
		create_symref("HEAD", head_points_at->name, NULL);

		if (!option_bare) {
			struct strbuf head_ref = STRBUF_INIT;
			const char *head = head_points_at->name;

			if (!prefixcmp(head, "refs/heads/"))
				head += 11;

			/* Set up the initial local branch */

			/* Local branch initial value */
			update_ref(reflog_msg.buf, "HEAD",
				   head_points_at->old_sha1,
				   NULL, 0, DIE_ON_ERR);

			strbuf_addstr(&head_ref, branch_top);
			strbuf_addstr(&head_ref, "HEAD");

			/* Remote branch link */
			create_symref(head_ref.buf,
				      head_points_at->peer_ref->name,
				      reflog_msg.buf);

			snprintf(key, sizeof(key), "branch.%s.remote", head);
			git_config_set(key, option_origin);
			snprintf(key, sizeof(key), "branch.%s.merge", head);
			git_config_set(key, head_points_at->name);
		}
	} else if (remote_head) {
		/* Source had detached HEAD pointing somewhere. */
		if (!option_bare)
			update_ref(reflog_msg.buf, "HEAD",
				   remote_head->old_sha1,
				   NULL, REF_NODEREF, DIE_ON_ERR);
	} else {
		/* Nothing to checkout out */
		if (!option_no_checkout)
			warning("remote HEAD refers to nonexistent ref, "
				"unable to checkout.\n");
		option_no_checkout = 1;
	}

	if (transport)
		transport_unlock_pack(transport);

	if (!option_no_checkout) {
		struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file));
		struct unpack_trees_options opts;
		struct tree *tree;
		struct tree_desc t;
		int fd;

		/* We need to be in the new work tree for the checkout */
		setup_work_tree();

		fd = hold_locked_index(lock_file, 1);

		memset(&opts, 0, sizeof opts);
		opts.update = 1;
		opts.merge = 1;
		opts.fn = oneway_merge;
		opts.verbose_update = !option_quiet;
		opts.src_index = &the_index;
		opts.dst_index = &the_index;

		tree = parse_tree_indirect(remote_head->old_sha1);
		parse_tree(tree);
		init_tree_desc(&t, tree->buffer, tree->size);
		unpack_trees(1, &t, &opts);

		if (write_cache(fd, active_cache, active_nr) ||
		    commit_locked_index(lock_file))
			die("unable to write new index file");
	}

	strbuf_release(&reflog_msg);
	junk_pid = 0;
	return 0;
}