Пример #1
0
static char *
gfs_realpath_canonical_parent(const char *path, char **abspathp)
{
	char *e, *par_dir;
	const char *base;
	int need_free = 0;

	base = gfarm_path_dir_skip(path);
	if (base == path)
		par_dir = ".";
	else if (base == path + 1)
		par_dir = "/";
	else {
		par_dir = malloc(base - path);
		if (par_dir == NULL)
			return (GFARM_ERR_NO_MEMORY);
		/* do not copy the last '/' */
		memcpy(par_dir, path, base - path - 1);
		par_dir[base - path - 1] = '\0';
		need_free = 1;
	}
	if (strcmp(path, par_dir) == 0) {
		/* this should not happen but ensures termination */
		e = GFARM_ERR_NO_SUCH_OBJECT;
	}
	else
		e = gfs_i_realpath_canonical(par_dir, abspathp);
	if (need_free)
		free(par_dir);
	return (e);
}
Пример #2
0
static char *
gfs_dircache_modify_parent(const char *pathname)
{
	char *e = NULL;
	char *parent = strdup(pathname), *b;
	struct gfarm_path_info pi;
	struct timeval now;

	if (parent == NULL)
		return (GFARM_ERR_NO_MEMORY);

	/* create parent directory canonic path */
	for (b = (char *)gfarm_path_dir_skip(parent);
	    b > parent && b[-1] == '/'; --b)
		;
	*b = '\0';

	/* NOTE: We don't have path_info for the root directory */
	if (b > parent &&
	    (e = gfarm_metadb_path_info_get(parent, &pi)) == NULL) {
		gettimeofday(&now, NULL);
		pi.status.st_mtimespec.tv_sec = now.tv_sec;
		pi.status.st_mtimespec.tv_nsec = now.tv_usec *
		    GFARM_MILLISEC_BY_MICROSEC;
		/* the following calls gfs_dircache_enter_path() internally */
		e = gfarm_path_info_replace(parent, &pi);
		gfarm_path_info_free(&pi);
	}
	free(parent);
	return (e);
}
Пример #3
0
static void
register_fragment(int is_dir, char *gfarm_url, int index, int nfragments,
	char *hostname,
	char *filename, int use_file_mode, gfarm_mode_t file_mode)
{
	char *e;
	int fd, fd_needs_close;
	char *target_url;
	GFS_File gf;
	char section[GFARM_INT32STRLEN + 1];

	if (!open_file(filename, &fd, &fd_needs_close))
		return;
	if (!use_file_mode && !get_file_mode(fd, filename, &file_mode))
		goto finish;

	if (!is_dir)
		target_url = gfarm_url;
	else if (!concat_dir_name(gfarm_url, gfarm_path_dir_skip(filename),
	    &target_url))
		goto finish;

	if (nfragments == GFARM_FILE_DONTCARE &&
	    !get_nsections(target_url, &nfragments))
		goto finish_url;

	sprintf(section, "%d", index);
	if (opt_force || section_does_not_exists(target_url, section)) {
		e = gfs_pio_create(target_url,
		    GFARM_FILE_WRONLY|GFARM_FILE_TRUNC, file_mode, &gf);
		if (e != NULL) {
			fprintf(stderr, "%s: cannot open %s: %s\n",
			    program_name, target_url, e);
			error_happened = 1;
		} else {
			if ((e = gfs_pio_set_view_index(gf, nfragments, index,
			    hostname, 0)) != NULL) {
				fprintf(stderr, "%s: cannot open %s:%d: %s\n",
				    program_name, target_url, index, e);
				error_happened = 1;
			} else {
				copy_file(fd, gf, target_url, section);
			}
			gfs_pio_close(gf);
		}
	}
 finish_url:
	if (target_url != gfarm_url)
		free(target_url);
 finish:
	if (fd_needs_close)
		close(fd);
}
Пример #4
0
static void
register_program(int is_dir, char *gfarm_url, char *section, char *hostname,
	char *filename, int use_file_mode, gfarm_mode_t file_mode)
{
	char *e;
	int fd, fd_needs_close;
	char *target_url;
	GFS_File gf;

	if (!open_file(filename, &fd, &fd_needs_close))
		return;
	if (!use_file_mode && !get_file_mode(fd, filename, &file_mode))
		goto finish;

	if (!is_dir)
		target_url = gfarm_url;
	else if (!concat_dir_name(gfarm_url, gfarm_path_dir_skip(filename),
	    &target_url))
		goto finish;

	if (opt_force || section_does_not_exists(target_url, section)) {
		e = gfs_pio_create(target_url,
		    GFARM_FILE_WRONLY|GFARM_FILE_TRUNC, file_mode, &gf);
		if (e != NULL) {
			fprintf(stderr, "%s: cannot open %s: %s\n",
			    program_name, target_url, e);
			error_happened = 1;
		} else {
			if ((e = gfs_pio_set_view_section(gf, section,
			    hostname, 0)) != NULL) {
				fprintf(stderr, "%s: cannot open %s:%s: %s\n",
				    program_name, target_url, section, e);
				error_happened = 1;
			} else {
				copy_file(fd, gf, target_url, section);
			}
			gfs_pio_close(gf);
		}
	}
	if (target_url != gfarm_url)
		free(target_url);
 finish:
	if (fd_needs_close)
		close(fd);
}
Пример #5
0
static int
concat_dir_name(const char *gfarm_url, const char *base_name,
	char **target_url_p)
{
	char *target_url =
	    malloc(strlen(gfarm_url) + 1 + strlen(base_name) + 1);

	if (target_url == NULL) {
		fprintf(stderr, "%s: %s\n", program_name, GFARM_ERR_NO_MEMORY);
		error_happened = 1;
		return (0);
	}
	if (*gfarm_path_dir_skip(gfarm_url_prefix_skip(gfarm_url)) != '\0')
		sprintf(target_url, "%s/%s", gfarm_url, base_name);
	else
		sprintf(target_url, "%s%s", gfarm_url, base_name);
	*target_url_p = target_url;
	return (1);
}
Пример #6
0
gfarm_error_t
gfs_opendir_caching_internal(const char *path, GFS_Dir *dirp)
{
	gfarm_error_t e;
	GFS_DirPlus dp;
	struct gfs_dir_caching *dir;
	char *p;
	static struct gfs_dir_ops ops = {
		gfs_closedir_caching_internal,
		gfs_readdir_caching_internal,
		gfs_seekdir_unimpl,
		gfs_telldir_unimpl
	};

	if ((e = gfs_opendirplus(path, &dp)) != GFARM_ERR_NO_ERROR)
		return (e);

	GFARM_MALLOC(dir);
	if (*gfarm_path_dir_skip(path) != '\0') {
		GFARM_MALLOC_ARRAY(p, strlen(path) + 1 + 1);
		if (p != NULL)
			sprintf(p, "%s/", path);
	} else {
		GFARM_MALLOC_ARRAY(p, strlen(path) + 1);
		if (p != NULL)
			strcpy(p, path);
	}

	if (dir == NULL || p == NULL) {
		gfs_closedirplus(dp);
		if (dir != NULL)
			free(dir);
		if (p != NULL)
			free(p);
		return (GFARM_ERR_NO_MEMORY);
	}

	dir->super.ops = &ops;
	dir->dp = dp;
	dir->path = p;
	*dirp = &dir->super;
	return (GFARM_ERR_NO_ERROR);
}
Пример #7
0
static char *
remove_whole_file_or_dir(char *path,
	Unlink_Ops ops, void *closure, int is_recursive)
{
	struct gfs_stat gs;
	char *e, cwdbuf[PATH_MAX * 2];
	const char *b;
	gfarm_mode_t mode;

	b = gfarm_path_dir_skip(gfarm_url_prefix_skip(path));
	if (b[0] == '.' && (b[1] == '\0' || (b[1] == '.' && b[2] == '\0')))
		return ("cannot remove \'.\' or \'..\'");

	e = gfs_stat(path, &gs);
	if (e == GFARM_ERR_NO_FRAGMENT_INFORMATION)
		return (ops->unlink(path, closure));
	if (e != NULL)
		return (e);

	mode = gs.st_mode;
	gfs_stat_free(&gs);

	if (GFARM_S_ISREG(mode)) {
		e = ops->unlink(path, closure);
	} else if (GFARM_S_ISDIR(mode)) {
		if (!is_recursive)
			return (GFARM_ERR_IS_A_DIRECTORY);
		e = gfs_getcwd(cwdbuf, sizeof(cwdbuf));
		if (e != NULL)
			return (e);
		e = gfs_chdir(path);
		if (e != NULL)
			return (e);
		remove_cwd_entries(ops, closure);
		e = gfs_chdir_canonical(cwdbuf);
		if (e != NULL)
			return (e);
		e = ops->rmdir(path, closure);
	}
	return (e);
}
Пример #8
0
char *
gfarm_canonical_path_for_creation(const char *gfarm_file, char **canonic_pathp)
{
	const char *basename, *p0;
	char *e, *p1, *dir, *dir_canonic, *lastc, cwd[PATH_MAX + 1];

	*canonic_pathp = NULL; /* cause SEGV, if return value is ignored */

	/* '' or 'gfarm:' case */
	if (gfarm_file[0] == '\0') {
		e = gfs_getcwd(cwd, sizeof(cwd));
		if (e != NULL)
			return (e);
		p0 = cwd;
	}
	else
		p0 = gfarm_file;

	/* Expand '~'. */
	e = gfarm_path_expand_home(p0, &p1);
	if (e != NULL)
		return (e);

	/* Eliminate unnecessary '/'s following the basename. */
	lastc = &p1[strlen(p1) - 1];
	if (*lastc == '/') {
		while (p1 < lastc && *lastc == '/')
			--lastc;
		if (p1 == lastc) {
			/*
			 * In this case, given gfarm_file is '/' or contains
			 * only several '/'s.  This means to attempt to create
			 * the root directory.  Because the root directory
			 * should exist, the attempt will fail with the error
			 * of 'already exist'.  However, this case such that
			 * the canonical name is "" causes many problems.
			 * That is why the error of 'already exist' is
			 * returned here.
			 */
			free(p1);
			return (GFARM_ERR_ALREADY_EXISTS);
		}
		else {
			*(lastc + 1) = '\0';
		}
	}

	basename = gfarm_path_dir_skip(p1);
	if (basename == p1)	     /* "filename" */
		dir = ".";
	else if (basename == p1 + 1) /* "/filename" */
		dir = "/";
	else {			     /* /.../.../filename */
		p1[basename - 1 - p1] = '\0';
		dir = p1;
	}
	/* Check the existence of the parent directory. */
	e = gfarm_canonical_path(dir, &dir_canonic);
	if (e != NULL)
		goto free_p1;

	/*
	 * check whether parent directory is writable or not.
	 * XXX this isn't enough yet, due to missing X-bits check.
	 */
	if (dir_canonic[0] != '\0') { /* XXX "/" is always OK for now */
		struct gfarm_path_info pi;

		e = gfarm_path_info_get(dir_canonic, &pi);
		if (e != NULL)
			goto free_dir_canonic;

		e = gfarm_path_info_access(&pi, GFS_W_OK);
		gfarm_path_info_free(&pi);
		if (e != NULL)
			goto free_dir_canonic;
	}

	*canonic_pathp = malloc(strlen(dir_canonic) + 1 +
				strlen(basename) + 1); 
	if (*canonic_pathp == NULL) {
		e = GFARM_ERR_NO_MEMORY;
		goto free_dir_canonic;
	}

	/*
	 * When the 'dir_canonic' is a null string, *canonic_pathp
	 * will start with '/' incorrectly.
	 */
	if (dir_canonic[0] == '\0')
		strcpy(*canonic_pathp, basename);
	else
		sprintf(*canonic_pathp, "%s/%s", dir_canonic, basename);
	e = NULL;
free_dir_canonic:
	free(dir_canonic);
free_p1:
	free(p1);
	return (e);
}
Пример #9
0
int
try_to_make_parent_dir(char *pathname)
{
	char *e, *p, *parent, *dirbuf;
	int rv, dirlen;
	gfarm_mode_t mode;
	struct stat st;
	struct gfarm_path_info pi;

	parent = strdup(pathname);
	if (parent == NULL) /* give up */
		return (0);

	/* get parent directory */
	p = (char *)gfarm_path_dir_skip(parent);
	while (p > parent && p[-1] == '/')
		*--p = '\0';
	if (p == parent) { /* no directory part */
		free(parent);
		return (0);
	}

	if (stat(parent, &st) == 0) { /* parent directory already exists */
		free(parent);
		return (0);
	}
	
	dirbuf = strdup(parent);
	if (dirbuf == NULL) {
		free(parent);
		return (0);
	}

	for (dirlen = 0;;) {
		dirlen += strcspn(parent + dirlen, "/");
		memcpy(dirbuf, parent, dirlen);
		dirbuf[dirlen] = '\0';
		if (stat(dirbuf, &st) == 0) {
			if (!S_ISDIR(st.st_mode)) {
				free(dirbuf);
				free(parent);
				return (0);
			}
		} else {
			e = gfarm_path_info_get(dirbuf, &pi);
			mode = pi.status.st_mode;
			if (e != NULL || !GFARM_S_ISDIR(mode)) {
				if (e == NULL)
					gfarm_path_info_free(&pi);
				free(dirbuf);
				free(parent);
				return (0);
			}
			mode &= GFARM_S_ALLPERM;
			if (strcmp(pi.status.st_user,
			    gfarm_get_global_username()) != 0) {
				mode |= 0777;
			}
			gfarm_path_info_free(&pi);
			rv = mkdir(dirbuf, mode);
			if (rv == -1) {
				free(dirbuf);
				free(parent);
				return (0);
			}
		}
		dirlen += strspn(parent + dirlen, "/");
		if (parent[dirlen] == '\0') { /* OK, made */
			free(dirbuf);
			free(parent);
			return (1);
		}
	}
}
Пример #10
0
char *
gfs_i_realpath_canonical(const char *path, char **abspathp)
{
	struct node *n, *p;
	char *e, *abspath;
	int l, len;

	e = gfs_refreshdir();
	if (e != NULL) 
		return (e);
	e = lookup_path(path, -1, GFARM_INODE_LOOKUP, &n);
	if (e != NULL) {
		char *p_dir, *c_path;
		const char *base;
		struct gfarm_path_info info;
		/*
		 * Before uncaching the metadata, check a typical case
		 * such that the parent directory exists.
		 */
		if (gfs_realpath_canonical_parent(path, &p_dir) == NULL) {
			base = gfarm_path_dir_skip(path);
			c_path = malloc(strlen(p_dir) + 1 + strlen(base) + 1);
			if (c_path == NULL) {
				free(p_dir);
				return (GFARM_ERR_NO_MEMORY);
			}
			sprintf(c_path, "%s/%s", p_dir, base);
			free(p_dir);
			e = gfarm_i_path_info_get(c_path, &info);
			free(c_path);
			if (e != NULL)
				return (e);
			else
				gfarm_path_info_free(&info);
		}
		/* there may be inconsistency, refresh and lookup again. */
		gfs_i_uncachedir();
		if (gfs_refreshdir() == NULL)
			e = lookup_path(path, -1, GFARM_INODE_LOOKUP, &n);
	}
	if (e != NULL)
		return (e);
	len = 0;
	for (p = n; p != root; p = p->parent) {
		if (p != n)
			++len; /* for '/' */
		len += strlen(p->name);
	}
	abspath = malloc(len + 1);
	if (abspath == NULL)
		return (GFARM_ERR_NO_MEMORY);
	abspath[len] = '\0';
	for (p = n; p != root; p = p->parent) {
		if (p != n)
			abspath[--len] = '/';
		l = strlen(p->name);
		len -= l;
		memcpy(abspath + len, p->name, l);
	}
	*abspathp = abspath;
	return (NULL);
}
Пример #11
0
char *
gfarm_canonical_path_for_creation(const char *gfarm_file, char **canonic_pathp)
{
	const char *basename;
	char *dir, *e, *dir_canonic;
	const char *lastc, *ini_lastc;

	*canonic_pathp = NULL; /* cause SEGV, if return value is ignored */

	/* Expand '~'. */
	if (gfarm_file[0] == '~') {
		char *expanded_gfarm_file;

		e = gfarm_path_expand_home(gfarm_file, &expanded_gfarm_file);
		if (e != NULL)
			return (e);
		assert(expanded_gfarm_file[0] != '~');
		e = gfarm_canonical_path_for_creation(
			expanded_gfarm_file, canonic_pathp);
		free(expanded_gfarm_file);

		return (e);
	}
	/* '' or 'gfarm:' case */
	if (gfarm_file[0] == '\0') {
		char cwd[PATH_MAX + 1];

		e = gfs_getcwd(cwd, sizeof(cwd));
		if (e != NULL)
			return (e);
		return (gfarm_canonical_path_for_creation(cwd, canonic_pathp));
	}
	/* Eliminate unnecessary '/'s following the basename. */
	lastc = ini_lastc = &gfarm_file[strlen(gfarm_file) - 1];
	while (gfarm_file < lastc && *lastc == '/')
		--lastc;
	if (gfarm_file == lastc) {
		/*
		 * In this case, given gfarm_file is '/' or contains
		 * only several '/'s.  This means to attempt to create
		 * the root directory.  Because the root directory
		 * should exist, the attempt will fail with the error
		 * of 'already exist'.  However, this case such that
		 * the canonical name is "" causes many problems.
		 * That is why the error of 'already exist' is
		 * returned here.
		 */
		return (GFARM_ERR_ALREADY_EXISTS);
	}
	else if (lastc != ini_lastc) {
		char *eliminated_gfarm_file;

		++lastc;
		eliminated_gfarm_file = malloc(lastc - gfarm_file + 1);
		if (eliminated_gfarm_file == NULL)
			return (GFARM_ERR_NO_MEMORY);
		strncpy(eliminated_gfarm_file, gfarm_file, lastc - gfarm_file);
		eliminated_gfarm_file[lastc - gfarm_file] = '\0';
		e = gfarm_canonical_path_for_creation(
			eliminated_gfarm_file, canonic_pathp);
		free(eliminated_gfarm_file);

		return (e);
	}

	basename = gfarm_path_dir_skip(gfarm_file);
	dir = NULL;
	if (basename == gfarm_file) { /* "filename" */ 
		dir = strdup(".");
		if (dir == NULL)
			return (GFARM_ERR_NO_MEMORY);
	} else if (basename == gfarm_file + 1) { /* "/filename" */
		dir = strdup("/");
		if (dir == NULL)
			return (GFARM_ERR_NO_MEMORY);
	} else { /* /.../.../filename */
		dir = malloc(basename - 2 - gfarm_file + 2);
		if (dir == NULL)
			return (GFARM_ERR_NO_MEMORY);
		strncpy(dir, gfarm_file, basename - 2 - gfarm_file + 1);
		dir[basename - 2 - gfarm_file + 1] = '\0';
	}

	/* Check the existence of the parent directory. */
	e = gfarm_canonical_path(dir, &dir_canonic);
	free(dir);
	if (e != NULL)
		return (e);

	*canonic_pathp = malloc(strlen(dir_canonic) + 1 +
				strlen(basename) + 1); 
	if (*canonic_pathp == NULL)
		return (GFARM_ERR_NO_MEMORY);

	/*
	 * When the 'dir_canonic' is a null string, *canonic_pathp
	 * will start with '/' incorrectly.
	 */
	if (dir_canonic[0] == '\0')
		strcpy(*canonic_pathp, basename);
	else
		sprintf(*canonic_pathp, "%s/%s", dir_canonic, basename);
	free(dir_canonic);

	return (NULL);
}
Пример #12
0
static int
gfarm_register_file(char *gfarm_url, char *node_index, char *hostname,
	int total_nodes, char *filename, int auto_index)
{
	struct stat s;
	struct gfs_stat gs;
	char *e, *target_url = NULL;
	int executable_file = 0;

	if (stat(filename, &s) == 0) {
		if (!S_ISREG(s.st_mode)) {
			fprintf(stderr, "%s: not a regular file", filename);
			return (-1);
		}
		if ((s.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) != 0)
			executable_file = 1;
	}
	else if (strcmp(filename, "-")) {
		perror(filename);
		return (-1);
	}

	e = gfs_stat(gfarm_url, &gs);
	if (e == NULL && GFARM_S_ISDIR(gs.st_mode)) {
		char *bname;
		/* gfarm_url is a directory */

		gfs_stat_free(&gs);

		if (auto_index && total_nodes > 1 && !executable_file) {
			/*
			 * In the auto index mode, the target Gfarm URL
			 * should be a regular file when two or more local
			 * non-executable files will be registered for
			 * preventing unexpected results.
			 */
			fprintf(stderr, "%s: not a regular file.  "
				"The target Gfarm URL should be a "
				"regular file when registering two or "
				"more local files.\n", gfarm_url);
			return (-1);
		}

		bname = basename(filename);

		target_url = malloc(strlen(gfarm_url) + strlen(bname) + 2);
		if (target_url == NULL) {
			fprintf(stderr, "not enough memory\n");
			return (-1);
		}

		strcpy(target_url, gfarm_url);
		if (*gfarm_path_dir_skip(gfarm_url_prefix_skip(target_url))
		    != '\0')
			strcat(target_url, "/");
		strcat(target_url, bname);
	}
	else if (e == NULL)
		gfs_stat_free(&gs);

	if (target_url == NULL) {
		target_url = strdup(gfarm_url);
		if (target_url == NULL) {
			fprintf(stderr, "not enough memory\n");
			return (-1);
		}
	}

	if (executable_file) {
		/* register a binary executable. */

		/*
		 * In auto index case, node_index does not stand for
		 * architecture.
		 */
		if (auto_index)
			node_index = NULL;

		if (node_index == NULL) {
			if (hostname == NULL) {
				char *self_name;

				e = gfarm_host_get_canonical_self_name(
					&self_name);
				if (e != NULL) {
					fprintf(stderr, "%s: %s\n",
						gfarm_host_get_self_name(), e);
					return (-1);
				}
				node_index =
				    gfarm_host_info_get_architecture_by_host(
					    self_name);
			}
			else {
				char *c_name;

				e = gfarm_host_get_canonical_name(
					hostname, &c_name);
				if (e != NULL) {
					fprintf(stderr, "%s: %s\n",
						hostname, e);
					return (-1);
				}
				node_index = 
				    gfarm_host_info_get_architecture_by_host(
					    c_name);
				free(c_name);
			}
		}
		if (node_index == NULL) {
			fprintf(stderr,
				"%s: cannot determine the architecture "
				"of %s.\n",
				program_name, gfarm_host_get_self_name());
			return (-1);
		}
		if (total_nodes <= 0) {
			if (gfs_pio_get_node_size(&total_nodes) != NULL)
				total_nodes = 1;
		}

		if (!opt_force) {
			struct gfs_stat s;

			if (gfs_stat_section(target_url, node_index, &s)
			    == NULL) {
				gfs_stat_free(&s);
				e = "already exist";
				goto finish;
			}
		}

		e = gfarm_url_fragment_register(target_url, node_index,
			GFARM_FILE_DONTCARE, hostname, filename);
		/*
		 * XXX - gfarm_url_replicate() to replicate
		 * 'total_nodes' copies of target_url.
		 */

	} else {
		char index_str[GFARM_INT32STRLEN + 1];

		/* register a file fragment. */
		if (node_index == NULL) {
			int index;

			e = gfs_pio_get_node_rank(&index);
			if (e != NULL) {
				fprintf(stderr,
					"%s: missing -I <Gfarm index>\n",
					program_name);
				return (-1);
			}
			sprintf(index_str, "%d", index);
			node_index = index_str;
		}

		if (total_nodes <= 0) {
			e = gfs_pio_get_node_size(&total_nodes);
			if (e != NULL) {
				fprintf(stderr,
					"%s: missing -N "
					"<total num of fragments>\n",
					program_name);
				return (-1);
			}
		}

		if (!opt_force) {
			struct gfs_stat s;

			if (gfs_stat_section(target_url, node_index, &s)
			    == NULL) {
				gfs_stat_free(&s);
				e = "already exist";
				goto finish;
			}
		}

		e = gfarm_url_fragment_register(target_url, node_index,
			total_nodes, hostname, filename);
	}
 finish:
	if (e != NULL) {
		fprintf(stderr, "%s: %s\n", target_url, e);
		return (-1);
	}

	free(target_url);

	return (0);
}
Пример #13
0
char *
list_dir(char *prefix, char *dirname, int *need_newline)
{
	char *e, *s, *path, *e_save = NULL;
	gfarm_stringlist names;
	gfs_glob_t types;
	GFS_Dir dir;
	struct gfs_dirent *entry;
	int len = strlen(prefix) + strlen(dirname);

	path = malloc(len + 1 + 1);
	if (path == NULL)
		return (GFARM_ERR_NO_MEMORY);
	sprintf(path, "%s%s", prefix, dirname);
	e = gfarm_stringlist_init(&names);
	if (e != NULL) {
		fprintf(stderr, "%s: %s\n", program_name, e);
		free(path);
		return (e);
	}
	e = gfs_glob_init(&types);
	if (e != NULL) {
		fprintf(stderr, "%s: %s\n", program_name, e);
		gfarm_stringlist_free(&names);
		free(path);
		return (e);
	}
	e = gfs_opendir(path, &dir);
	if (e != NULL) {
		fprintf(stderr, "%s: %s\n", path, e);
		gfs_glob_free(&types);
		gfarm_stringlist_free(&names);
		free(path);
		return (e);
	}
	while ((e = gfs_readdir(dir, &entry)) == NULL && entry != NULL) {
		s = strdup(entry->d_name);
		if (s == NULL) {
			e = GFARM_ERR_NO_MEMORY;
			break;
		}
		gfarm_stringlist_add(&names, s);
		gfs_glob_add(&types, entry->d_type);
	}
	if (e != NULL) {
		fprintf(stderr, "%s%s: %s\n", prefix, dirname, e);
		e_save = e;
	}
	gfs_closedir(dir);
	if (*gfarm_path_dir_skip(gfarm_url_prefix_skip(path)) != '\0') {
		path[len] = '/';
		path[len + 1] = '\0';
	}
	e = list_files(path, gfarm_stringlist_length(&names),
	    GFARM_STRINGLIST_STRARRAY(names), need_newline);
	if (e_save == NULL)
		e_save = e;
	if (option_recursive) {
		int i;

		for (i = 0; i < gfarm_stringlist_length(&names); i++) {
			s = GFARM_STRINGLIST_STRARRAY(names)[i];
			if (s[0] == '.' && (s[1] == '\0' ||
			    (s[1] == '.' && s[2] == '\0')))
				continue;
			if (gfs_glob_elem(&types, i) == GFS_DT_DIR) {
				e = list_dirs(path, 1, &s, need_newline);
				if (e_save == NULL)
					e_save = e;
			}
		}
	}
	gfs_glob_free(&types);
	gfarm_stringlist_free_deeply(&names);
	free(path);
	return (e_save);
}