示例#1
0
/*
 * Gets called for every file/folder in /sys/fs/cgroup/cpu,cpuacct (or
 * wherever cpuacct is mounted on the system). Calls walk_directory with the
 * read_cpuacct_procs callback on every folder it finds, such as "system".
 */
static int read_cpuacct_root (const char *dirname, const char *filename,
		void *user_data)
{
	char abs_path[PATH_MAX];
	struct stat statbuf;
	int status;

	ssnprintf (abs_path, sizeof (abs_path), "%s/%s", dirname, filename);

	status = lstat (abs_path, &statbuf);
	if (status != 0)
	{
		ERROR ("cgroups plugin: stat (%s) failed.", abs_path);
		return (-1);
	}

	if (S_ISDIR (statbuf.st_mode))
	{
		status = walk_directory (abs_path, read_cpuacct_procs,
				/* user_data = */ NULL,
				/* include_hidden = */ 0);
		return (status);
	}

	return (0);
}
示例#2
0
文件: hugepages.c 项目: bzed/collectd
static int read_syshugepages(const char* path, const char* node)
{
  static const char hugepages_dir[] = "hugepages";
  DIR *dir;
  struct dirent *result;
  char path2[PATH_MAX];
  struct entry_info e_info;
  long lim;

  dir = opendir(path);
  if (dir == NULL) {
    ERROR("%s: cannot open directory %s", g_plugin_name, path);
    return -1;
  }

  errno = 0;
  if ((lim = pathconf(path, _PC_NAME_MAX)) == -1) {
    /* Limit not defined if errno == 0, otherwise error */
    if (errno != 0) {
      ERROR("%s: pathconf failed", g_plugin_name);
      closedir(dir);
      return -1;
    } else {
      lim = PATH_MAX;
    }
  }

  /* read "hugepages-XXXXXkB" entries */
  while ((result = readdir(dir)) != NULL) {
    if (strncmp(result->d_name, hugepages_dir, sizeof(hugepages_dir)-1)) {
      /* not node dir */
      errno = 0;
      continue;
    }

    /* /sys/devices/system/node/node?/hugepages/ */
    ssnprintf(path2, (size_t) lim, "%s/%s", path, result->d_name);

    e_info.d_name = result->d_name;
    e_info.node = node;
    walk_directory(path2, read_hugepage_entry, &e_info, 0);
    errno = 0;
  }

  /* Check if NULL return from readdir() was an error */
  if (errno != 0) {
      ERROR("%s: readdir failed", g_plugin_name);
      closedir(dir);
      return -1;
  }

  closedir(dir);
  return 0;
}
示例#3
0
文件: battery.c 项目: Civil/collectd
static int read_acpi (void) /* {{{ */
{
	int status;
	int battery_counter = 0;

	if (access (PROC_ACPI_PATH, R_OK) != 0)
		return (ENOENT);

	status = walk_directory (PROC_ACPI_PATH, read_acpi_callback,
			/* user_data = */ &battery_counter,
			/* include hidden */ 0);
	return (status);
} /* }}} int read_acpi */
示例#4
0
int impl_fuse_context::find_files(LPCWSTR file_name,
                                  PFillFindData fill_find_data,
                                  PDOKAN_FILE_INFO dokan_file_info) {
  if ((!ops_.readdir && !ops_.getdir) || !ops_.getattr)
    return -EINVAL;

  std::string fname = unixify(wchar_to_utf8_cstr(file_name));
  CHECKED(check_and_resolve(&fname));

  walk_data wd;
  wd.ctx = this;
  wd.dirname = fname;
  if (*fname.rbegin() != '/')
    wd.dirname.append("/");
  wd.delegate = fill_find_data;
  wd.DokanFileInfo = dokan_file_info;

  if (ops_.readdir) {
    impl_file_handle *hndl =
        reinterpret_cast<impl_file_handle *>(dokan_file_info->Context);
    if (hndl != NULL) {
      fuse_file_info finfo(hndl->make_finfo());
      return ops_.readdir(fname.c_str(), &wd, &walk_directory, 0, &finfo);
    } else
      return ops_.readdir(fname.c_str(), &wd, &walk_directory, 0, NULL);
  } else {
    CHECKED(
        ops_.getdir(fname.c_str(), (fuse_dirh_t)&wd, &walk_directory_getdir));
    // Convert returned data The getdir_data array will be filled during
    // getdir() call.
    // We emulate FUSE behavior and do not pass information directly to Dokan
    // in walk_directory_getdir callback. This can cause excessive network
    // traffic
    // in sshfs because it populates stat buffer cache AFTER calling our
    // callback.
    // See: cache.c file, function cache_dirfill() in SSHFS 2.2
    for (std::vector<std::string>::const_iterator f = wd.getdir_data.begin();
         f != wd.getdir_data.end(); ++f)
      CHECKED(walk_directory(&wd, f->c_str(), 0, 0));
  }

  return 0;
}
示例#5
0
static int cgroups_read (void)
{
	cu_mount_t *mnt_list;
	cu_mount_t *mnt_ptr;
	_Bool cgroup_found = 0;

	mnt_list = NULL;
	if (cu_mount_getlist (&mnt_list) == NULL)
	{
		ERROR ("cgroups plugin: cu_mount_getlist failed.");
		return (-1);
	}

	for (mnt_ptr = mnt_list; mnt_ptr != NULL; mnt_ptr = mnt_ptr->next)
	{
		/* Find the cgroup mountpoint which contains the cpuacct
		 * controller. */
		if ((strcmp(mnt_ptr->type, "cgroup") != 0)
				|| !cu_mount_checkoption(mnt_ptr->options,
					"cpuacct", /* full = */ 1))
			continue;

		walk_directory (mnt_ptr->dir, read_cpuacct_root,
				/* user_data = */ NULL,
				/* include_hidden = */ 0);
		cgroup_found = 1;
		/* It doesn't make sense to check other cpuacct mount-points
		 * (if any), they contain the same data. */
		break;
	}

	cu_mount_freelist (mnt_list);

	if (!cgroup_found)
	{
		WARNING ("cgroups plugin: Unable to find cgroup "
				"mount-point with the \"cpuacct\" option.");
		return (-1);
	}

	return (0);
} /* int cgroup_read */
示例#6
0
文件: main.c 项目: manevich/firejail
static void walk_directory(const char *dirname) {
	assert(dirname);

	DIR *dir = opendir(dirname);
	if (dir) {
		struct dirent *entry;
		while ((entry = readdir(dir)) != NULL) {
			if (strcmp(entry->d_name, ".") == 0)
				continue;
			if (strcmp(entry->d_name, "..") == 0)
				continue;

			// build full path
			char *path;
			if (asprintf(&path, "%s/%s", dirname, entry->d_name) == -1)
				errExit("asprintf");

			// check regular so library
			char *ptr = strstr(entry->d_name, ".so");
			if (ptr && is_lib_64(path)) {
				if (*(ptr + 3) == '\0' || *(ptr + 3) == '.') {
					parse_elf(path);
					free(path);
					continue;
				}
			}

			// check directory
			// entry->d_type field is supported  in glibc since version 2.19 (Feb 2014)
			// we'll use stat to check for directories
			struct stat s;
			if (stat(path, &s) == -1)
				errExit("stat");
			if (S_ISDIR(s.st_mode))
				walk_directory(path);
		}
		closedir(dir);
	}
}
示例#7
0
static int fc_read_dir (fc_directory_conf_t *dir)
{
  int status;

  dir->files_num = 0;
  dir->files_size = 0;

  if (dir->mtime != 0)
    dir->now = time (NULL);
    
  status = walk_directory (dir->path, fc_read_dir_callback, dir,
      /* include hidden */ (dir->options & FC_HIDDEN) ? 1 : 0);
  if (status != 0)
  {
    WARNING ("filecount plugin: walk_directory (%s) failed.", dir->path);
    return (-1);
  }

  fc_submit_dir (dir);

  return (0);
} /* int fc_read_dir */
示例#8
0
文件: tests.c 项目: weezel/fcd
void
test_walk_directory(void)
{
	walk_directory("/home/weezel/ohj");
}
示例#9
0
文件: main.c 项目: manevich/firejail
int main(int argc, char **argv) {
#if 0
{
//system("cat /proc/self/status");
int i;
for (i = 0; i < argc; i++)
        printf("*%s* ", argv[i]);
printf("\n");
}
#endif
	if (argc < 2) {
		fprintf(stderr, "Error fldd: invalid arguments\n");
		usage();
		exit(1);
	}


	if (strcmp(argv[1], "--help") == 0) {
		usage();
		return 0;
	}

	// check program access
	if (access(argv[1], R_OK)) {
		fprintf(stderr, "Error fldd: cannot access %s\n", argv[1]);
		exit(1);
	}

	char *quiet = getenv("FIREJAIL_QUIET");
	if (quiet && strcmp(quiet, "yes") == 0)
		arg_quiet = 1;

	if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") ==0) {
		usage();
		return 0;
	}

	int fd = STDOUT_FILENO;
	// attempt to open the file
	if (argc == 3) {
		fd = open(argv[2], O_CREAT | O_TRUNC | O_WRONLY, 0644);
		if (!fd) {
			fprintf(stderr, "Error fldd: invalid arguments\n");
			usage();
			exit(1);
		}
	}

	// initialize local storage
	lib_paths_init();

	// process files
	struct stat s;
	if (stat(argv[1], &s) == -1)
		errExit("stat");
	if (S_ISDIR(s.st_mode))
		walk_directory(argv[1]);
	else {
		if (is_lib_64(argv[1]))
			parse_elf(argv[1]);
		else
			fprintf(stderr, "Warning fldd: %s is not a 64bit program/library\n", argv[1]);
	}


	// print libraries and exit
	storage_print(libs, fd);
	if (argc == 3)
		close(fd);
	return 0;
}
示例#10
0
static struct imgspec* create_imgspec(int argc, char* argv[])
{
	struct imgspec* spec = malloc(sizeof(*spec));
	if (!spec)
		error("failed to allocate an image spec");
	memset(spec, 0, sizeof(*spec));
	
	spec->sp_root = malloc(sizeof(*spec->sp_root));
	if (!spec->sp_root)
		error("failed to allocate the root entry");
	memset(spec->sp_root, 0, sizeof(*spec->sp_root));
	
	spec->sp_name = MICROFS_DEFAULTNAME;
	spec->sp_shareblocks = 1;
	spec->sp_lib = hostprog_lib_find_any();
	if (!spec->sp_lib) {
		error("could not determine which hostprog lib to use");
	}
	
	spec->sp_pagesz = sysconf(_SC_PAGESIZE);
	spec->sp_blksz = MICROFS_DEFAULBLKSZ;
	spec->sp_szpad = spec->sp_pagesz;
	
	if (argc < 2)
		usage(argc > 0 ? argv[0] : "microfsmki", stderr, spec);
	
	/* Check what the user want.
	 */
	
	int option;
	char optionbuffer[3];
	while ((option = getopt(argc, argv, MKI_OPTIONS)) != EOF) {
		size_t len;
		switch (option) {
			case 'h':
				usage(argv[0], stdout, spec);
				break;
			case 'v':
				hostprog_verbosity++;
				break;
			case 'e':
				hostprog_werror = 1;
				break;
			case 'p':
				spec->sp_pad = 1;
				break;
			case 'q':
				spec->sp_squashperms = 1;
				break;
			case 's':
				spec->sp_incsocks = 1;
				break;
			case 'S':
				spec->sp_shareblocks = 0;
				break;
			case 'b':
				opt_strtolx(ul, optiontostr(option, optionbuffer),
					optarg, spec->sp_blksz);
				if (!microfs_ispow2(spec->sp_blksz))
					error("the block size must be a power of two");
				if (spec->sp_blksz < MICROFS_MINBLKSZ ||
					spec->sp_blksz > MICROFS_MAXBLKSZ) {
					error("block size out of boundaries, %llu given;"
						" min=%d, max=%d", spec->sp_blksz,
						MICROFS_MINBLKSZ, MICROFS_MAXBLKSZ);
				}
				break;
			case 'u':
				opt_strtolx(ull, optiontostr(option, optionbuffer),
					optarg, spec->sp_usrupperbound);
				break;
			case 'P':
				opt_strtolx(ull, optiontostr(option, optionbuffer),
					optarg, spec->sp_szpad);
				if (!microfs_ispow2(spec->sp_szpad))
					error("the size padding must be a power of two");
				break;
			case 'n':
				spec->sp_name = optarg;
				len = strlen(spec->sp_name);
				if (len > MICROFS_SBNAME_LENGTH) {
					warning("image name \"%s\" is too long"
						" it will be truncated from %zu to %d bytes",
						spec->sp_name, len, MICROFS_SBNAME_LENGTH);
				}
				break;
			case 'c':
				spec->sp_lib = hostprog_lib_find_byname(optarg);
				if (!spec->sp_lib)
					error("could not find a compression library named %s", optarg);
				break;
			case 'D':
				spec->sp_devtable = optarg;
				break;
			case 'l':
				spec->sp_lib_options = optarg;
				break;
			default:
				/* Ignore it.
				 */
				warning("unrecognized option -%c", option);
				break;
		}
	}
	
	/* The block size should now be correctly set, which means
	 * that the block left shift can be calculated.
	 */
	__u64 blksz = spec->sp_blksz;
	while ((blksz >>= 1) > 0)
		spec->sp_blkshift++;
	
	if (spec->sp_usrupperbound % spec->sp_blksz != 0)
		error("upper bound must be a multiple of the block size");
	
	if (hostprog_stack_create(&spec->sp_regstack, 64, 64) < 0)
		error("failed to create the regular file stack");
	
	if (spec->sp_squashperms && spec->sp_devtable) {
		warning("both -q and -d are set, this might not be a good idea"
			" - the device table could override some or all permissions");
	}
	
	spec->sp_upperbound = sizeof(struct microfs_sb);
	if (spec->sp_pad)
		spec->sp_upperbound += MICROFS_PADDING;
	
	if ((argc - optind) != 2)
		usage(argv[0], stderr, spec);
	spec->sp_rootdir = argv[optind + 0];
	spec->sp_outfile = argv[optind + 1];
	
	if (!spec->sp_lib->hl_compiled)
		error("%s support has not been compiled", spec->sp_lib->hl_info->li_name);
	if (spec->sp_lib->hl_init(&spec->sp_lib_data, spec->sp_blksz) < 0)
		error("failed to init %s", spec->sp_lib->hl_info->li_name);
	
	lib_options(spec);
	
	spec->sp_upperbound += spec->sp_lib->hl_info->li_dd_sz;
	
	if (spec->sp_lib->hl_info->li_min_blksz == 0 && spec->sp_blksz < spec->sp_pagesz) {
		warning("block size smaller than page size of host"
			" - the resulting image can not be used on this host");
	}
	
	struct stat st;
	if (stat(spec->sp_rootdir, &st) == 0) {
		if (!S_ISDIR(st.st_mode))
			error("\"%s\" is not a directory", spec->sp_rootdir);
	} else
		error("can not stat \"%s\": %s", spec->sp_rootdir, strerror(errno));
	
	struct hostprog_path* path = NULL;
	if (hostprog_path_create(&path, spec->sp_rootdir,
			MICROFS_MAXNAMELEN,	MICROFS_MAXNAMELEN) != 0) {
		error("failed to create the path for the rootdir: %s", strerror(errno));
	}
	
	spec->sp_root->e_mode = st.st_mode;
	spec->sp_root->e_uid = st.st_uid;
	spec->sp_root->e_gid = st.st_gid;
	spec->sp_root->e_size = walk_directory(spec, path,
		&spec->sp_root->e_firstchild);
	
	hostprog_path_destroy(path);
	
	if (spec->sp_shareblocks)
		find_duplicates(spec);
	
	if (spec->sp_devtable)
		devtable_parse(devtable_process_dentry, spec,
			spec->sp_devtable, MICROFS_ISIZE_WIDTH);
	
	if (spec->sp_usrupperbound && spec->sp_upperbound > spec->sp_usrupperbound) {
		warning("the estimated upper bound %llu is larger than the"
			" user requested upper bound %llu", spec->sp_upperbound,
			spec->sp_usrupperbound);
	}
	
	/* Allocate a max block size sized multiple of bytes.
	 */
	spec->sp_upperbound = sz_blkceil(spec->sp_upperbound,
		MICROFS_MAXBLKSZ);
	
	if (spec->sp_upperbound > MICROFS_MAXIMGSIZE) {
		warning("upper bound image size (absolute worst-case scenario)"
			" of %llu bytes is larger than the max image size of %llu bytes,"
			" there might not be room for everything", spec->sp_upperbound,
			MICROFS_MAXIMGSIZE);
		spec->sp_upperbound = MICROFS_MAXIMGSIZE;
	}
	
	int flags = O_RDWR | O_CREAT | O_TRUNC;
	spec->sp_fd = open(spec->sp_outfile, flags, 0666);
	if (spec->sp_fd < 0)
		error("failed to open \"%s\": %s", spec->sp_rootdir, strerror(errno));
	
	/* The worst case compression scenario will always fit in the
	 * buffer since the upper bound for a data size smaller than
	 * a block is always smaller than the upper bound for an entire
	 * block.
	 */
	spec->sp_compressionbufsz = spec->sp_lib->hl_upperbound(
		spec->sp_lib_data, spec->sp_blksz);
	spec->sp_compressionbuf = malloc(spec->sp_compressionbufsz);
	if (!spec->sp_compressionbuf)
		error("failed to allocate the compression buffer");
	
	message(VERBOSITY_1, "Block size: %llu", spec->sp_blksz);
	message(VERBOSITY_1, "Block shift: %llu", spec->sp_blkshift);
	
	message(VERBOSITY_0, "Compression library: %s", spec->sp_lib->hl_info->li_name);
	message(VERBOSITY_0, "Upper bound image size: %llu bytes", spec->sp_upperbound);
	message(VERBOSITY_0, "Number of files: %llu", spec->sp_files);
	message(VERBOSITY_0, "Directories: %llu", spec->sp_dirnodes);
	message(VERBOSITY_0, "Regular files: %llu", spec->sp_regnodes);
	message(VERBOSITY_0, "Duplicate files: %llu", spec->sp_duplicatenodes);
	message(VERBOSITY_0, "Special files: %llu", spec->sp_specnodes);
	message(VERBOSITY_0, "Skipped files: %llu", spec->sp_skipnodes);
	message(VERBOSITY_1, "Data size: %llu", spec->sp_datasz);
	message(VERBOSITY_1, "Real data size: %llu", spec->sp_realdatasz);
	message(VERBOSITY_1, "Block pointers required: %llu", spec->sp_blkptrs);
	
	if (spec->sp_skipnodes) {
		warning("not all files will be included in the image");
		if (hostprog_verbosity < VERBOSITY_1)
			message(VERBOSITY_0, ">>> use -v to get more information");
	}
	
	return spec;
}
示例#11
0
static unsigned int walk_directory(struct imgspec* const spec,
	struct hostprog_path* const path, struct entry** previous)
{
	struct dirent** dirlst;
	int dirlst_count;
	int dirlst_index;
	
	__u64 dir_sz = 0;
	__u64 dir_lvl = hostprog_path_lvls(path);
	
	dirlst_count = scandir(path->p_path, &dirlst, NULL, hostprog_scandirsort);
	if (dirlst_count < 0)
		error("failed to read \"%s\": %s", path->p_path, strerror(errno));
	
	for (dirlst_index = 0; dirlst_index < dirlst_count; dirlst_index++) {
		struct dirent* dent = dirlst[dirlst_index];
		
		/* Skip "." and ".." directories, just like mkcramfs.
		 */
		if (hostprog_path_dotdir(dent->d_name))
			continue;
		
		hostprog_path_dirnamelvl(path, dir_lvl);
		if (hostprog_path_append(path, dent->d_name) != 0)
			error("failed to add a filename to the hostprog_path");
		
		struct stat st;
		if (lstat(path->p_path, &st) < 0) {
			/* Maybe this should be an error? Files missing in the image
			 * could possibly seem like an error to the user.
			 */
			warning("skipping \"unlstatable\" file \"%s\": %s",
				path->p_path, strerror(errno));
			spec->sp_skipnodes++;
			continue;
		}
		
		if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) {
			/* If the file is a regular file which can not be read, then
			 * it might as well be skipped.
			 * 
			 * This should also possibly be an error.
			 */
			if (access(path->p_path, R_OK) < 0) {
				warning("skipping unreadable file \"%s\": %s",
					path->p_path, strerror(errno));
				spec->sp_skipnodes++;
				continue;
			}
			/* Completely empty files seems pretty pointless to include
			 * in the image.
			 */
			if (!st.st_size) {
				message(VERBOSITY_1, ">>> skipping empty file \"%s\"", path->p_path);
				spec->sp_skipnodes++;
				continue;
			}
		} else if (!spec->sp_incsocks && S_ISSOCK(st.st_mode)) {
			warning("skipping socket \"%s\"", path->p_path);
			spec->sp_skipnodes++;
			continue;
		}
		
		/* Files should never be skipped after this point since that
		 * would mess up the image size estimation.
		 */
		
		struct entry* ent = malloc(sizeof(*ent));
		if (!ent)
			error("failed to alloc an entry for \"%s\"", path->p_path);
		
		memset(ent, 0, sizeof(*ent));
		
		ent->e_name = strdup(dent->d_name);
		if (!ent->e_name)
			error("failed to copy the entry name for \"%s\"", path->p_path);
		ent->e_mode = st.st_mode;
		ent->e_size = st.st_size;
		ent->e_fd = -1;
		
		ENTRY_SET_XID(spec, ent, e_uid, st.st_uid, MICROFS_IUID_WIDTH);
		ENTRY_SET_XID(spec, ent, e_gid, st.st_gid, MICROFS_IGID_WIDTH);
		
		if (S_ISDIR(ent->e_mode)) {
			ent->e_size = walk_directory(spec, path, &ent->e_firstchild);
		} else if (S_ISREG(ent->e_mode) || S_ISLNK(ent->e_mode)) {
			if (ent->e_size > MICROFS_MAXFILESIZE) {
				error("\"%s\" is too big, max file size is %llu bytes",
					path->p_path, MICROFS_MAXFILESIZE);
			} else if (ent->e_size > MICROFS_MAXCRAMSIZE) {
				warning("\"%s\" is a big file, microfs works best with files"
					" smaller than %llu bytes",
					path->p_path, MICROFS_MAXCRAMSIZE);
			}
			ent->e_path = strdup(path->p_path);
			if (!ent->e_path) {
				error("failed to copy the entry path for \"%s\"",
					path->p_path);
			}
			if (spec->sp_shareblocks) {
				if (hostprog_stack_push(spec->sp_regstack, ent) < 0)
					error("failed to push an entry to the regular file stack: %s",
						strerror(errno));
			}
		} else if (S_ISCHR(ent->e_mode) || S_ISBLK(ent->e_mode)) {
			ent->e_size = makedev_lim(major(st.st_rdev), minor(st.st_rdev),
				MICROFS_ISIZE_WIDTH);
		} else if (S_ISFIFO(ent->e_mode) || S_ISSOCK(ent->e_mode)) {
			ent->e_size = 0;
		} else {
			error("unexpected file mode encountered");
		}
		
		/* %namelen() could actually fail here if the d_name is too
		 * long, but that will terminate the program, so that is fine.
		 */
		dir_sz += update_upperbound(spec, ent, namelen(dent->d_name));
		
		update_stats(spec, ent);
		
		message(VERBOSITY_1, "+ %c %s", nodtype(ent->e_mode), path->p_path);
		
		*previous = ent;
		previous = &ent->e_sibling;
	}
	
	free(dirlst);
	hostprog_path_dirnamelvl(path, dir_lvl);
	
	/* This should never happen, but if it ever does, it is
	 * clearly an error.
	 */
	if (dir_sz > MICROFS_MAXDIRSIZE) {
		error("achievement unlocked: the directory size for \"%s\""
			" is %llu bytes, the maximum supported size is %llu bytes"
			" - this is impressive in a very scary way",
			path->p_path, dir_sz, MICROFS_MAXDIRSIZE);
	}
	
	return dir_sz;
}
示例#12
0
文件: thermal.c 项目: johnl/collectd
static int thermal_procfs_read (void)
{
	return walk_directory (dirname_procfs, thermal_procfs_device_read,
			/* user_data = */ NULL);
}
示例#13
0
static int fc_read_dir_callback (const char *dirname, const char *filename,
    void *user_data)
{
  fc_directory_conf_t *dir = user_data;
  char abs_path[PATH_MAX];
  struct stat statbuf;
  int status;

  if (dir == NULL)
    return (-1);

  ssnprintf (abs_path, sizeof (abs_path), "%s/%s", dirname, filename);

  status = lstat (abs_path, &statbuf);
  if (status != 0)
  {
    ERROR ("filecount plugin: stat (%s) failed.", abs_path);
    return (-1);
  }

  if (S_ISDIR (statbuf.st_mode) && (dir->options & FC_RECURSIVE))
  {
    status = walk_directory (abs_path, fc_read_dir_callback, dir,
        /* include hidden = */ (dir->options & FC_HIDDEN) ? 1 : 0);
    return (status);
  }
  else if (!S_ISREG (statbuf.st_mode))
  {
    return (0);
  }

  if (dir->name != NULL)
  {
    status = fnmatch (dir->name, filename, /* flags = */ 0);
    if (status != 0)
      return (0);
  }

  if (dir->mtime != 0)
  {
    time_t mtime = dir->now;

    if (dir->mtime < 0)
      mtime += dir->mtime;
    else
      mtime -= dir->mtime;

    DEBUG ("filecount plugin: Only collecting files that were touched %s %u.",
        (dir->mtime < 0) ? "after" : "before",
        (unsigned int) mtime);

    if (((dir->mtime < 0) && (statbuf.st_mtime < mtime))
        || ((dir->mtime > 0) && (statbuf.st_mtime > mtime)))
      return (0);
  }

  if (dir->size != 0)
  {
    off_t size;

    if (dir->size < 0)
      size = (off_t) ((-1) * dir->size);
    else
      size = (off_t) dir->size;

    if (((dir->size < 0) && (statbuf.st_size > size))
        || ((dir->size > 0) && (statbuf.st_size < size)))
      return (0);
  }

  dir->files_num++;
  dir->files_size += (uint64_t) statbuf.st_size;

  return (0);
} /* int fc_read_dir_callback */