示例#1
0
NTSTATUS close_file(struct smb_request *req, files_struct *fsp,
		    enum file_close_type close_type)
{
	NTSTATUS status;
	struct files_struct *base_fsp = fsp->base_fsp;

	if(fsp->is_directory) {
		status = close_directory(req, fsp, close_type);
	} else if (fsp->fake_file_handle != NULL) {
		status = close_fake_file(req, fsp);
	} else {
		status = close_normal_file(req, fsp, close_type);
	}

	if ((base_fsp != NULL) && (close_type != SHUTDOWN_CLOSE)) {

		/*
		 * fsp was a stream, the base fsp can't be a stream as well
		 *
		 * For SHUTDOWN_CLOSE this is not possible here, because
		 * SHUTDOWN_CLOSE only happens from files.c which walks the
		 * complete list of files. If we mess with more than one fsp
		 * those loops will become confused.
		 */

		SMB_ASSERT(base_fsp->base_fsp == NULL);
		close_file(req, base_fsp, close_type);
	}

	return status;
}
示例#2
0
文件: stock.c 项目: jwalle/ft_ls
ll_list	*ll_stock(char *str)
{
	ll_list			*head;
	ll_list			*current;
	DIR				*dir;
	struct dirent	*dp;

	head = NULL;
	current = head;
	if ((dir = opendir(str)) == NULL)
		return (fail_open_directory(str));
	while ((dp = readdir(dir)))
	{
		if (head == NULL)
		{
			head = ll_copy_new(dp->d_name, dp, head, str);
			current = head;
		}
		else
		{
			while (current->next != NULL)
				current = current->next;
			current = ll_copy_cur(dp->d_name, dp, current, str);
		}
	}
	close_directory(dir);
	return (head);
}
示例#3
0
bool DOS_Drive_Cache::OpenDir(CFileInfo* dir, const char* expand, Bit16u& id) {
	id = GetFreeID(dir);
	dirSearch[id] = dir;
	char expandcopy [CROSS_LEN];
	strcpy(expandcopy,expand);   
	// Add "/"
	char end[2]={CROSS_FILESPLIT,0};
	if (expandcopy[strlen(expandcopy)-1]!=CROSS_FILESPLIT) strcat(expandcopy,end);
	// open dir
	if (dirSearch[id]) {
		// open dir
		dir_information* dirp = open_directory(expandcopy);
		if (dirp) { 
			// Reset it..
			close_directory(dirp);
			strcpy(dirPath,expandcopy);
			return true;
		}
		if (dirSearch[id]) {
			dirSearch[id]->id = MAX_OPENDIRS;
			dirSearch[id] = 0;
		}
	};
	return false;
}
示例#4
0
文件: ui.c 项目: Harvie/Programs
void update_directory(GNode *directory)
{
	close_directory(directory);
	destroy_directory_content(directory);
	open_directory(directory);

	if (FILE(directory)->show_dotfiles == TRUE)
		show_dotfiles(directory);
}
示例#5
0
NTSTATUS close_file(files_struct *fsp, enum file_close_type close_type)
{
	if(fsp->is_directory) {
		return close_directory(fsp, close_type);
	} else if (fsp->is_stat) {
		return close_stat(fsp);
	} else if (fsp->fake_file_handle != NULL) {
		return close_fake_file(fsp);
	}
	return close_normal_file(fsp, close_type);
}
示例#6
0
文件: dump.c 项目: mommel/alien-svn
static svn_error_t *
verify_close_directory(void *dir_baton,
                apr_pool_t *pool)
{
  struct dir_baton *db = dir_baton;
  apr_hash_t *dirents;
  SVN_ERR(svn_fs_dir_entries(&dirents, db->edit_baton->fs_root,
                             db->path, pool));
  SVN_ERR(svn_iter_apr_hash(NULL, dirents, verify_directory_entry,
                            dir_baton, pool));
  return close_directory(dir_baton, pool);
}
示例#7
0
FILE * OpenCaptureFile(const char * type,const char * ext) {
	if(capturedir.empty()) {
		LOG_MSG("Please specify a capture directory");
		return 0;
	}

	Bitu last=0;
	char file_start[16];
	dir_information * dir;
	/* Find a filename to open */
	dir = open_directory(capturedir.c_str());
	if (!dir) {
		//Try creating it first
		Cross::CreateDir(capturedir);
		dir=open_directory(capturedir.c_str());
		if(!dir) {
		
			LOG_MSG("Can't open dir %s for capturing %s",capturedir.c_str(),type);
			return 0;
		}
	}
	strcpy(file_start,RunningProgram);
	lowcase(file_start);
	strcat(file_start,"_");
	bool is_directory;
	char tempname[CROSS_LEN];
	bool testRead = read_directory_first(dir, tempname, is_directory );
	for ( ; testRead; testRead = read_directory_next(dir, tempname, is_directory) ) {
		char * test=strstr(tempname,ext);
		if (!test || strlen(test)!=strlen(ext)) 
			continue;
		*test=0;
		if (strncasecmp(tempname,file_start,strlen(file_start))!=0) continue;
		Bitu num=atoi(&tempname[strlen(file_start)]);
		if (num>=last) last=num+1;
	}
	close_directory( dir );
	char file_name[CROSS_LEN];
	sprintf(file_name,"%s%c%s%03d%s",capturedir.c_str(),CROSS_FILESPLIT,file_start,last,ext);
	/* Open the actual file */
	FILE * handle=fopen(file_name,"wb");
	if (handle) {
		LOG_MSG("Capturing %s to %s",type,file_name);
	} else {
		LOG_MSG("Failed to open %s for capturing %s",file_name,type);
	}
	return handle;
}
示例#8
0
bool DOS_Drive_Cache::ReadDir(Bit16u id, char* &result) {
	// shouldnt happen...
	if (id>MAX_OPENDIRS) return false;

	if (!IsCachedIn(dirSearch[id])) {
		// Try to open directory
		dir_information* dirp = open_directory(dirPath);
		if (!dirp) {
			if (dirSearch[id]) {
				dirSearch[id]->id = MAX_OPENDIRS;
				dirSearch[id] = 0;
			}
			return false;
		}
		// Read complete directory
		char dir_name[CROSS_LEN];
		bool is_directory;
		if (read_directory_first(dirp, dir_name, is_directory)) {
			CreateEntry(dirSearch[id], dir_name, is_directory);
			while (read_directory_next(dirp, dir_name, is_directory)) {
				CreateEntry(dirSearch[id], dir_name, is_directory);
			}
		}

		// close dir
		close_directory(dirp);

		// Info
/*		if (!dirp) {
			LOG_DEBUG("DIR: Error Caching in %s",dirPath);			
			return false;
		} else {	
			char buffer[128];
			sprintf(buffer,"DIR: Caching in %s (%d Files)",dirPath,dirSearch[srchNr]->fileList.size());
			LOG_DEBUG(buffer);
		};*/
	};
	if (SetResult(dirSearch[id], result, dirSearch[id]->nextEntry)) return true;
	if (dirSearch[id]) {
		dirSearch[id]->id = MAX_OPENDIRS;
		dirSearch[id] = 0;
	}
	return false;
}
示例#9
0
int
file_completion(char *path, int index)
{
    static int      dir_in_use = 0;
    static char    *head, *tail = NULL;
    static int      tail_offset;

    char            nbuf[FILENAME], buffer[FILENAME];
    char           *dir, *base;

    if (path) {
	if (dir_in_use) {
	    close_directory();
	    dir_in_use = 0;
	}
	if (index < 0)
	    return 0;

	head = path;
	tail = path + index;
    }
    if (!dir_in_use) {
	path = head;
	*tail = NUL;

	if (*path == '|')
	    return -1;		/* no completion for pipes */

	if (*path == '+' || *path == '~') {
	    if (!expand_file_name(nbuf, path, 0x11))
		return 0;	/* no completions */
	} else
	    strcpy(nbuf, path);

	if ((base = strrchr(nbuf, '/'))) {
	    if (base == nbuf) {
		dir = "/";
		base++;
	    } else {
		*base++ = NUL;
		dir = nbuf;
	    }
	} else {
	    base = nbuf;
	    dir = ".";
	}

	tail_offset = strlen(base);

	dir_in_use = list_directory(dir, base);

	return dir_in_use;
    }
    if (index)
	return compl_help_directory();

    if (!next_directory(buffer, 1))
	return 0;

    strcpy(tail, buffer + tail_offset);

    return 1;
}
示例#10
0
gboolean remove_from_tree(GNode *file, gboolean unmount)
{
	int position = g_list_position(lines, FILE(file)->line);
	gboolean refresh_needed = FALSE;
	GList *line_ptr, *line_ptr2;
	GNode *dir_ptr;

	if (G_NODE_IS_ROOT(file)) {
		endwin();
		clean_up();
		printf("The tree root was removed\n");
		exit(EXIT_SUCCESS);
	}
	if (g_node_is_ancestor(file, NODE(selected_line)))
		select_file(file);
	if (FILE(file)->type == directory_type) {
		close_directory(file);
		destroy_directory_content_real(file, FALSE);
		if (unmount)
			return TRUE;
	} else if (FILE(file)->type == file_type) {
		for (dir_ptr = file->parent; !G_NODE_IS_ROOT(dir_ptr);
				dir_ptr = dir_ptr->parent) {
			if (FILE(dir_ptr)->open == FALSE) {
				g_node_unlink(file);
				return FALSE;
			}
		}
		if (FILE(dir_ptr)->open == FALSE) {
			g_node_unlink(file);
			return FALSE;
		}
	}
	g_node_unlink(file);

	if (g_list_position(lines, first_line) <= position &&
			position <= g_list_position(lines, last_line)) {
		if (first_line == FILE(file)->line && selected_line == FILE(file)->line) {
			selected_line = first_line = g_list_previous(first_line);
			lines = g_list_delete_link(lines, FILE(file)->line);
			print_lines(first_line, first_line, FALSE);
		} else if (position < g_list_position(lines, selected_line)) {
			if (first_line == FILE(file)->line)
				first_line = g_list_next(first_line);
			line_ptr = g_list_previous(FILE(file)->line);
			lines = g_list_delete_link(lines, FILE(file)->line);
			if ((line_ptr2 = g_list_previous(first_line)) != NULL) {
				first_line = line_ptr2;
				print_lines(first_line, line_ptr, FALSE);
			} else if ((line_ptr2 = g_list_next(last_line)) != NULL) {
				last_line = line_ptr2;
				print_lines(line_ptr, last_line, FALSE);
			} else
				print_lines(line_ptr, last_line, TRUE);
		} else {
			if (FILE(file)->line == selected_line)
				selected_line = g_list_previous(selected_line);
			if (last_line == FILE(file)->line)
				last_line = g_list_previous(last_line);
			line_ptr = g_list_previous(FILE(file)->line);
			lines = g_list_delete_link(lines, FILE(file)->line);
			if ((line_ptr2 = g_list_next(last_line)) != NULL) {
				last_line = line_ptr2;
				print_lines(line_ptr, last_line, FALSE);
			} else
				print_lines(line_ptr, last_line, TRUE);
		}
		refresh_needed = TRUE;
	} else {
		if (last_line == g_list_previous(FILE(file)->line)) {
			lines = g_list_delete_link(lines, FILE(file)->line);
			print_lines(last_line, last_line, FALSE);
			refresh_needed = TRUE;
		} else
			lines = g_list_delete_link(lines, FILE(file)->line);
	}
	free_node_data(file, NULL);
	g_node_destroy(file);

	return refresh_needed;
}
示例#11
0
文件: recurse.cpp 项目: acml/cvsnt
/*
 * Process each of the directories in the list (recursing as we go)
 */
static int do_dir_proc (Node *p, void *closure)
{
    struct frame_and_entries *frent = (struct frame_and_entries *) closure;
    struct recursion_frame *frame = frent->frame;
    struct recursion_frame xframe;
    char *dir = p->key;
    char *newrepos, *virtrepos;
    List *sdirlist;
    char *srepository;
	char *smapped_repository;
    Dtype dir_return = R_PROCESS;
	Dtype hint;
    int stripped_dot = 0;
    int err = 0;
    struct saved_cwd cwd;
    char *saved_update_dir;
    int process_this_directory = 1;
	int directory_opened = 0;
	char *old_update_repos = NULL;
	int directory_not_valid = 0;

    if (fncmp (dir, CVSADM) == 0
		|| fncmp (dir, CVSDUMMY) == 0)
    {
	/* This seems to most often happen when users (beginning users,
	   generally), try "cvs ci *" or something similar.  On that
	   theory, it is possible that we should just silently skip the
	   CVSADM directories, but on the other hand, using a wildcard
	   like this isn't necessarily a practice to encourage (it operates
	   only on files which exist in the working directory, unlike
	   regular CVS recursion).  */

	/* FIXME-reentrancy: printed_cvs_msg should be in a "command
	   struct" or some such, so that it gets cleared for each new
	   command (this is possible using the remote protocol and a
	   custom-written client).  The struct recursion_frame is not
	   far back enough though, some commands (commit at least)
	   will call start_recursion several times.  An alternate solution
	   would be to take this whole check and move it to a new function
	   validate_arguments or some such that all the commands call
	   and which snips the offending directory from the argc,argv
	   vector.  */
	static int printed_cvs_msg = 0;
	if (!printed_cvs_msg)
	{
	    error (0, 0, "warning: directory %s specified in argument",
		   dir);
	    error (0, 0, "but CVS uses %s for its own purposes; skipping %s directory", dir, dir);
	    printed_cvs_msg = 1;
	}
	return 0;
    }

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

    /* set up update_dir - skip dots if not at start */
    if (strcmp (dir, ".") != 0)
    {
	if (update_dir[0] != '\0')
	{
	    (void) strcat (update_dir, "/");
	    (void) strcat (update_dir, dir);
	}
	else
	    (void) strcpy (update_dir, dir);

	/*
	 * Here we need a plausible repository name for the sub-directory. We
	 * create one by concatenating the new directory name onto the
	 * previous repository name.  The only case where the name should be
	 * used is in the case where we are creating a new sub-directory for
	 * update -d and in that case the generated name will be correct.
	 */
	if (repository == NULL)
	{
	    newrepos = xstrdup ("");
		virtrepos = xstrdup ("");
	}
	else
	{
		if(frame->which&W_LOCAL)
		{
			char *d=(char*)xmalloc(strlen(dir)+strlen(CVSADM_REP)+32);
			sprintf(d,"%s/%s",dir,CVSADM_REP);
			if(isfile(d))
				virtrepos = Name_Repository(dir,update_dir);
			else
			{
				virtrepos = (char*)xmalloc (strlen (repository) + strlen (dir) + 5);
				sprintf (virtrepos, "%s/%s", repository, dir);
			}
			xfree(d);

		}
		else
		{
			virtrepos = (char*)xmalloc (strlen (repository) + strlen (dir) + 5);
			sprintf (virtrepos, "%s/%s", repository, dir);
		}
		if(!current_parsed_root->isremote)
		{
			newrepos = map_repository(virtrepos);
			if(!newrepos)
				error(1,0,"Internal error - couldn't map %s to anything",virtrepos);
		}
		else
			newrepos = xstrdup(virtrepos);
	}
    }
    else
    {
	if (update_dir[0] == '\0')
	    (void) strcpy (update_dir, dir);

	if (repository == NULL)
	{
	    newrepos = xstrdup ("");
		virtrepos = xstrdup ("");
	}
	else
	{
	    newrepos = xstrdup (mapped_repository);
		virtrepos = xstrdup (repository);
	}
    }

	/* Check to see that the CVSADM directory, if it exists, seems to be
       well-formed.  It can be missing files if the user hit ^C in the
       middle of a previous run.  We want to (a) make this a nonfatal
       error, and (b) make sure we print which directory has the
       problem.

       Do this before the direntproc, so that (1) the direntproc
       doesn't have to guess/deduce whether we will skip the directory
       (e.g. send_dirent_proc and whether to send the directory), and
       (2) so that the warm fuzzy doesn't get printed if we skip the
       directory.  */
    if (frame->which & W_LOCAL)
    {
	char *cvsadmdir;

	cvsadmdir = (char*)xmalloc (strlen (dir)
			     + sizeof (CVSADM_REP)
			     + sizeof (CVSADM_ENT)
			     + 80);

	strcpy (cvsadmdir, dir);
	strcat (cvsadmdir, "/");
	strcat (cvsadmdir, CVSADM);
	if (isdir (cvsadmdir))
	{
	    strcpy (cvsadmdir, dir);
	    strcat (cvsadmdir, "/");
	    strcat (cvsadmdir, CVSADM_REP);
	    if (!isfile (cvsadmdir))
	    {
		/* Some commands like update may have printed "? foo" but
		   if we were planning to recurse, and don't on account of
		   CVS/Repository, we want to say why.  */
		error (0, 0, "ignoring %s (%s missing)", update_dir,
		       CVSADM_REP);
		dir_return = R_SKIP_ALL;
	    }

	    /* Likewise for CVS/Entries.  */
	    if (dir_return != R_SKIP_ALL)
	    {
		strcpy (cvsadmdir, dir);
		strcat (cvsadmdir, "/");
		strcat (cvsadmdir, CVSADM_ENT);
		if (!isfile (cvsadmdir))
		{
		    /* Some commands like update may have printed "? foo" but
		       if we were planning to recurse, and don't on account of
		       CVS/Repository, we want to say why.  */
		    error (0, 0, "ignoring %s (%s missing)", update_dir,
			   CVSADM_ENT);
		    dir_return = R_SKIP_ALL;
		}
	    }
	}
	xfree (cvsadmdir);
    }

    /* Only process this directory if the root matches.  This nearly
       duplicates code in do_recursion. */

	/* If -d was specified, it should override CVS/Root.

	   In the single-repository case, it is long-standing CVS behavior
	   and makes sense - the user might want another access method,
	   another server (which mounts the same repository), &c.

	   In the multiple-repository case, -d overrides all CVS/Root
	   files.  That is the only plausible generalization I can
	   think of.  */
    if (!(frame->which&W_FAKE) && CVSroot_cmdline == NULL && !server_active)
    {
	char *this_root = Name_Root (dir, update_dir);
	if (this_root != NULL)
	{
	    if (findnode_fn (root_directories, this_root) == NULL)
	    {
		/* Add it to our list. */

		Node *n = getnode ();
		n->type = NT_UNKNOWN;
		n->key = xstrdup (this_root);

		if (addnode (root_directories, n))
		    error (1, 0, "cannot add new CVSROOT %s", this_root);

	    }

	    process_this_directory = (fncmp (current_parsed_root->original, this_root) == 0);

	    xfree (this_root);
	}
    }
    /*
     * Do we have access to this directory?
     */
	if(!current_parsed_root->isremote)
	{
		const char *tag=NULL;
		const char *date=NULL;
		int nonbranch=0;
		const char *message;
		const char *v_msg;

		/* before we do anything else, see if we have any
		   per-directory tags */
		ParseTag (&tag, &date, &nonbranch, NULL);
		if (! verify_access (frame->permproc, newrepos, NULL, update_dir, frame->tag?frame->tag:tag,&message, &v_msg))
		{
			if(frame->permproc!=verify_read)
			{
			  if(tag)
			    error (0, 0, "User '%s' cannot %s %s on tag/branch %s", CVS_Username, v_msg, fn_root(virtrepos), tag);
			  else
			    error (0, 0, "User '%s' cannot %s %s", CVS_Username, v_msg, fn_root(virtrepos));
			  if(message)
				error(0,0,"%s",message);	
			}
			dir_return = R_SKIP_ALL;
		}
		xfree(tag);
		xfree(date);
	}

	if(dir_return!=R_SKIP_ALL)
	{
		/* Generic behavior.  I don't see a reason to make the caller specify
		a direntproc just to get this.  */
		if ((frame->which & (W_LOCAL|W_FAKE)))
		{
			if(!isdir (dir))
				hint = R_SKIP_ALL;
			else
				hint = R_PROCESS;
		}
		else if(!isdir(newrepos))
			hint = R_SKIP_ALL;
		else
			hint = R_PROCESS;
	}

    if (dir_return == R_SKIP_ALL || dir_return == R_ERROR)
	;
    else if(process_this_directory)
	{
		int directory_opened_status=-1;
		const char *dirversion=NULL;
		const char *dirtag=NULL;
		const char *dirdate=NULL;
		int dirnonbranch=0;

		if(frame->predirentproc != NULL)
		{
			frame->predirentproc (frame->callerdat, dir, newrepos,
							update_dir, frent->entries, virtrepos, hint);
		}

		/* before we do anything else, see if we have any
			per-directory tags */
		ParseTag_Dir (dir, &dirtag, &dirdate, &dirnonbranch, &dirversion);
		directory_opened_status=open_directory(newrepos,dir,dirtag,dirdate,dirnonbranch,dirversion,current_parsed_root->isremote);
		if (directory_opened_status!=-1)
			directory_opened = 1;
		xfree(dirversion);
		xfree(dirtag);
		xfree(dirdate);
		if(!current_parsed_root->isremote)
			fileattr_startdir(newrepos);
	}

	/* call-back dir entry proc (if any) */
    if (dir_return == R_SKIP_ALL || dir_return == R_ERROR)
		;
    else if (frame->direntproc != NULL)
    {
	/* If we're doing the actual processing, call direntproc.
           Otherwise, assume that we need to process this directory
           and recurse. FIXME. */

	if (process_this_directory)
	    dir_return = frame->direntproc (frame->callerdat, dir, newrepos,
					    update_dir, frent->entries, virtrepos, hint);
	else
	    dir_return = R_PROCESS;
    }
    else
    {
	/* Generic behavior.  I don't see a reason to make the caller specify
	   a direntproc just to get this.  */
		dir_return = hint;
    }

    /* only process the dir if the return code was 0 */
    if (dir_return != R_SKIP_ALL && dir_return !=R_ERROR)
    {
		/* save our current directory and static vars */
        if (save_cwd (&cwd))
			error_exit ();

		sdirlist = dirlist;
		srepository = repository;
		smapped_repository = mapped_repository;
		dirlist = NULL;

		/* cd to the sub-directory */
		if (!(frame->which&(W_LOCAL|W_FAKE)))
		{
			if ( CVS_CHDIR (newrepos) < 0)
			{
				error (1, errno, "could not chdir to %s", fn_root(newrepos));
			}
		}
		else
		{
			if ( !(frame->which&W_FAKE) && CVS_CHDIR (dir) < 0)
			{
				if(!noexec)
					error (1, errno, "could not chdir to %s", fn_root(update_dir));
				else
					directory_not_valid=1;
			}

		}
		old_update_repos = update_repos;
		update_repos = xstrdup(newrepos);

		/* honor the global SKIP_DIRS (a.k.a. local) */
		if (frame->flags == R_SKIP_DIRS)
			dir_return = R_SKIP_DIRS;

		/* remember if the `.' will be stripped for subsequent dirs */
		if (strcmp (update_dir, ".") == 0)
		{
			update_dir[0] = '\0';
			stripped_dot = 1;
		}

		/* make the recursive call */
		xframe = *frame;
		xframe.flags = dir_return;
		if(directory_not_valid)
		{
			xframe.which &= ~W_LOCAL;
			xframe.which |= W_FAKE;
		}
		err += do_recursion (&xframe, 0);

		/* put the `.' back if necessary */
		if (stripped_dot)
			(void) strcpy (update_dir, ".");

		/* call-back dir leave proc (if any) */
		if (process_this_directory && frame->dirleaveproc != NULL)
			err = frame->dirleaveproc (frame->callerdat, dir, err, update_dir,
						frent->entries);

		if(directory_opened)
			close_directory();

		/* get back to where we started and restore state vars */
		if (restore_cwd (&cwd, NULL))
			error_exit ();

		xfree(update_repos);
		update_repos = old_update_repos;

		free_cwd (&cwd);
		dirlist = sdirlist;
		repository = srepository;
		mapped_repository = smapped_repository;
    }
	else
	{
		if(directory_opened)
			close_directory();
		fileattr_write();
		fileattr_free();
	}

    xfree (newrepos);
	xfree (virtrepos);
    xfree (update_dir);
    update_dir = saved_update_dir;

	if(dir_return == R_ERROR)
		err++;

    return (err);
}
示例#12
0
文件: recurse.cpp 项目: acml/cvsnt
static int unroll_files_proc (Node *p, void *closure)
{
	int directory_opened = 0;
    Node *n;
    struct recursion_frame *frame = (struct recursion_frame *) closure;
    int err = 0;
    List *save_dirlist;
    char *save_update_dir = NULL;
    struct saved_cwd cwd;
	char *dir = p->key;

    /* if this dir was also an explicitly named argument, then skip
       it.  We'll catch it later when we do dirs. */
    n = findnode_fn (dirlist, dir);
    if (n != NULL)
	return (0);

    /* otherwise, call dorecusion for this list of files. */
    filelist = (List *) p->data;
    p->data = NULL;
    save_dirlist = dirlist;
    dirlist = NULL;

    if (strcmp(dir, ".") != 0)
    {
        if (save_cwd (&cwd))
	    error_exit ();
	if ( CVS_CHDIR (dir) < 0)
	    error (1, errno, "could not chdir to %s", dir);

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

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

	(void) strcat (update_dir, dir);
    }


	if(frame->which&W_LOCAL)
	{
		int directory_opened_status=-1;
		const char *version;
		const char *tag;
		const char *date;
		int nonbranch;
		char *repository = Name_Repository(NULL,update_dir);

		ParseTag(&tag, &date, &nonbranch, &version);
		directory_opened_status=open_directory(repository,".",tag,date,nonbranch,version,current_parsed_root->isremote);
		if (directory_opened_status!=-1)
			directory_opened = 1;
		xfree(repository);
		xfree(version);
		xfree(tag);
		xfree(date);
	}
	else
	{
		int directory_opened_status=-1;
		/* we can't simply call Name_Repository() here, if we do we get:
		-> Name_Repository((null),cvsnt/src)
		cvs server: in directory cvsnt/src:
		cvs [server aborted]: CVS directory without administration files present.  Cannot continue until this directory is deleted or renamed.
		*/
		directory_opened_status=open_directory(NULL,".",NULL,NULL,0,NULL,1); /* We want to open the directory anyway, so treat it as 'remote'.  This only affects rlog, etc. */
		if (directory_opened_status!=-1)
			directory_opened = 1;
	}

    err += do_recursion (frame, 1);

	if(directory_opened)
		close_directory();

    if (save_update_dir != NULL)
    {
	xfree (update_dir);
	update_dir = save_update_dir;

	if (restore_cwd (&cwd, NULL))
	    error_exit ();
	free_cwd (&cwd);
    }

    dirlist = save_dirlist;
    if (filelist)
	dellist (&filelist);
    return(err);
}