From cfd4bfc8a9a00d2ebf482b0ca6aa0d6f49b8ffa4 Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Sun, 6 Apr 2014 15:27:32 -0400 Subject: wip: Recursive directory enumeration API --- Makefile-libgsystem.am | 7 + Makefile.am | 3 + Makefile.glib | 302 +++++++++++++++++++++++++++++++++++++++++++ configure.ac | 1 + src/gsystem-file-tree-walk.c | 219 +++++++++++++++++++++++++++++++ src/gsystem-file-tree-walk.h | 62 +++++++++ src/libgsystem.h | 1 + 7 files changed, 595 insertions(+) create mode 100644 Makefile.glib create mode 100644 src/gsystem-file-tree-walk.c create mode 100644 src/gsystem-file-tree-walk.h diff --git a/Makefile-libgsystem.am b/Makefile-libgsystem.am index b75d517..bffacf0 100644 --- a/Makefile-libgsystem.am +++ b/Makefile-libgsystem.am @@ -22,6 +22,7 @@ libgsystemheader_HEADERS = \ src/gsystem-local-alloc.h \ src/gsystem-console.h \ src/gsystem-file-utils.h \ + src/gsystem-file-tree-walk.h \ src/gsystem-glib-compat.h \ src/gsystem-shutil.h \ src/gsystem-log.h \ @@ -34,6 +35,7 @@ libgsystem_la_SOURCES = \ src/gsystem-local-alloc.c \ src/gsystem-console.c \ src/gsystem-file-utils.c \ + src/gsystem-file-tree-walk.c \ src/gsystem-shutil.c \ src/gsystem-log.c \ src/gsystem-subprocess-context-private.h \ @@ -60,3 +62,8 @@ gir_DATA += GSystem-1.0.gir typelib_DATA += GSystem-1.0.typelib CLEANFILES += $(gir_DATA) $(typelib_DATA) endif + +GLIB_GENERATED += gsystem-enum-types.h gsystem-enum-types.c +gsystem_enum_types_sources = $(libgsystemheader_HEADERS) $(libgsystem_la_SOURCES) +gsystem_enum_types_MKENUMS_H_FLAGS = --identifier-prefix GS --symbol-prefix gs +gsystem_enum_types_MKENUMS_C_FLAGS = --identifier-prefix GS --symbol-prefix gs diff --git a/Makefile.am b/Makefile.am index 472fbc1..171e408 100644 --- a/Makefile.am +++ b/Makefile.am @@ -16,6 +16,9 @@ # Boston, MA 02111-1307, USA. include Makefile-decls.am +include Makefile.glib +GLIB_GENERATED = +BUILT_SOURCES += $(GLIB_GENERATED) ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS} AM_CPPFLAGS += -DDATADIR='"$(datadir)"' -DLIBEXECDIR='"$(libexecdir)"' \ diff --git a/Makefile.glib b/Makefile.glib new file mode 100644 index 0000000..dadbbdf --- /dev/null +++ b/Makefile.glib @@ -0,0 +1,302 @@ +# -*- Mode: makefile -*- +# +# To use: +# +# In configure.ac: +# add -Wno-portability to AM_INIT_AUTOMAKE +# add GLIB_CONFIG([min-version[, required-modules]]) +# (remove AM_PATH_GLIB_2_0 and GLIB_GSETTINGS) +# +# Add to Makefile.am where your library/program is built: +# include $(GLIB_MAKEFILE) +# +# BUILT_SOURCES = $(GLIB_GENERATED) +# +# Add *.stamp to .gitignore +# +# Add a GLIB_GENERATED variable with the files you want to generate, +# as described below. (The examples below use filenames with hyphens, +# eg foo-marshal.h, but you can omit the hyphens if that matches your +# file naming scheme better.) +# +# You do not need to modify CLEANFILES or EXTRA_DIST for any of these +# macros. + + +# glib-genmarshal +# +# To generate signal marshallers, add files with names ending in +# "marshal.h" and "marshal.c" to GLIB_GENERATED: +# +# GLIB_GENERATED += foo-marshal.h foo-marshal.c +# foo_marshal_sources = aaa.c bbb.c ccc.c ddd.c +# +# Makefile.glib will then generate a foo-marshal.list file containing +# all _foo_marshal_* functions referenced by $(foo_marshal_sources), +# and will rebuild foo-marshal.c/foo-marshal.h whenever the list +# changes. +# +# For your convenience, any .h files or $(GLIB_GENERATED) files in +# $(foo_marshal_sources) will be ignored. This means you can usually just +# set foo_marshal_sources to the value of your library/program's +# _SOURCES variable, even if that variable contains foo-marshal.c. +# +# You can set GLIB_GENMARSHAL_H_FLAGS and GLIB_GENMARSHAL_C_FLAGS (or +# an appropriate file-specific variable, eg +# foo_marshal_GENMARSHAL_H_FLAGS) to set/override glib-genmarshal +# options. + + +# glib-mkenums +# +# To generate enum type registrations, add files with names ending +# in "-enum-types.[ch]" or "enumtypes.[ch]" to GLIB_GENERATED: +# +# GLIB_GENERATED += foo-enum-types.h foo-enum-types.c +# foo_enum_types_sources = aaa.h bbb.h ccc.h ddd.h +# +# Makefile.glib will create a list all of the enum/flags types +# declared in $(foo_enum_type_sources), and will rebuild +# foo-enum-types.c/foo-enum-types.h whenever that list changes. (No +# template files are required.) +# +# For your convenience, any .c files or $(GLIB_GENERATED) files in +# $(foo_enum_types_sources) will be ignored. This means you can +# usually set foo_enum_types_sources to the value of your +# library/program's _HEADERS and/or _SOURCES variables, even if that +# contains foo-enum-types.h. +# +# You can set GLIB_MKENUMS_H_FLAGS and GLIB_MKENUMS_C_FLAGS (or an +# appropriate file-specific variable, eg +# foo_enum_types_MKENUMS_H_FLAGS) to set/override glib-mkenums +# options. In particular, you can do: +# +# GLIB_MKENUMS_C_FLAGS = --fhead "\#define FOO_I_KNOW_THIS_IS_UNSTABLE" +# +# (The backslash is necessary to keep make from thinking the "#" is +# the start of a comment.) + + +# glib-compile-schemas +# +# Any foo.gschemas.xml files listed in gsettingsschema_DATA will be +# validated before installation, and (if --disable-schemas-compile was +# not passed) compiled after installation. +# +# To build an enums file, add it to GLIB_GENERATED (in addition to +# gsettingsschema_DATA): +# +# GLIB_GENERATED += org.gnome.foo.enums.xml +# org_gnome_foo_enums_xml_sources = aaa.h bbb.h ccc.h ddd.h +# +# All enums files will be built before any schema files are validated. + + +######## + +# Notes on Makefile.glib hacking: +# +# - The exact rules that automake generates for a Makefile vary +# depending on what sorts of things were done in the Makefile.am, +# so we have to be careful with what rules we assume are there. +# In particular, (a) the glue to handle BUILT_SOURCES and the +# various hooks won't be output unless those things were +# referenced in the Makefile.am, and (b) a Makefile.am with +# SUBDIRS will get different rules than one without. +# +# - Build rules should always refer to their dependencies via $^, +# not by reusing a variable that is listed in the rule's +# dependencies. This is needed to make srcdir!=builddir builds +# work. You can use $(filter)/$(filter-out) if $^ has things +# you don't want in it. +# +# - When using a filename as something other than a filename, +# consider whether you need to wrap it in $(notdir) to get the +# right result when that file is being pulled out of a +# subdirectory. +# +# - All private variables should be prefixed with _glib or _GLIB +# +# - "make -qp > makefile.out" will give you a copy of the +# Makefile after all macros are expanded. +# +# The genmarshal code is commented; the mkenums and schema code is +# generally similar. + +_GLIB_CLEANFILES = +_GLIB_DISTCLEANFILES = + +_GLIB_V_GEN = $(_glib_v_gen_$(V)) +_glib_v_gen_ = $(_glib_v_gen_$(AM_DEFAULT_VERBOSITY)) +_glib_v_gen_0 = @echo " GEN " $(subst .stamp,,$@); + + +### glib-genmarshal + +# _GLIB_MARSHAL_GENERATED contains the basenames (eg, "foo-marshal") +# of all the marshal-related files to be generated. +_GLIB_MARSHAL_GENERATED = $(subst .h,,$(filter %marshal.h,$(GLIB_GENERATED))) + +# These are used as macros (with the value of $(1) inherited from the "caller") +# _glib_marshal_prefix("foo-marshal") = "foo" (used in the C marshal names) +# _glib_marshal_sources_var("foo-marshal") = "foo_marshal_sources" +# _glib_marshal_sources = the filtered value of $(foo_marshal_sources) +_glib_marshal_prefix = $(subst marshal,,$(subst _marshal,,$(subst -,_,$(notdir $(1)))))_marshal +_glib_marshal_sources_var = $(subst -,_,$(notdir $(1)))_sources +_glib_marshal_sources = $(filter-out %.h,$(filter-out $(GLIB_GENERATED),$($(_glib_marshal_sources_var)))) + +# This is a multi-line macro (ending with the "endef" below) that +# outputs a set of rules for a single .h/.c pair (whose basename is +# $(1)). The initial $(if) line makes make error out if +# foo_marshal_sources wasn't set. Note that single-$ variables are +# expanded when the macro is called, and double-$ variables are +# expanded when the rule is invoked. +define _glib_make_genmarshal_rules +$(if $(_glib_marshal_sources),,$(error Need to define $(_glib_marshal_sources_var) for $(1).[ch])) + +$(1).list.stamp: $(_glib_marshal_sources) Makefile + $$(_GLIB_V_GEN) LC_ALL=C sed -ne 's/.*_$(_glib_marshal_prefix)_\([_A-Z]*\).*/\1/p' $$(filter-out Makefile, $$^) | sort -u | sed -e 's/__/:/' -e 's/_/,/g' > $(1).list.tmp && \ + (cmp -s $(1).list.tmp $(1).list || cp $(1).list.tmp $(1).list) && \ + rm -f $(1).list.tmp && \ + echo timestamp > $$@ + +$(1).list: $(1).list.stamp + @true + +$(1).h: $(1).list + $$(_GLIB_V_GEN) $$(GLIB_GENMARSHAL) \ + --prefix=_$(_glib_marshal_prefix) --header \ + $$(GLIB_GENMARSHAL_H_FLAGS) \ + $$($(_glib_marshal_prefix)_GENMARSHAL_H_FLAGS) \ + $$< > $$@.tmp && \ + mv $$@.tmp $$@ + +$(1).c: $(1).list + $$(_GLIB_V_GEN) (echo "#include \"$$(subst .c,.h,$$(@F))\""; $$(GLIB_GENMARSHAL) \ + --prefix=_$(_glib_marshal_prefix) --body \ + $$(GLIB_GENMARSHAL_C_FLAGS) \ + $$($(_glib_marshal_prefix)_GENMARSHAL_C_FLAGS) \ + $$< ) > $$@.tmp && \ + mv $$@.tmp $$@ + +_GLIB_CLEANFILES += $(1).list.stamp $(1).list +_GLIB_DISTCLEANFILES += $(1).h $(1).c +endef + +# Run _glib_make_genmarshal_rules for each set of generated files +$(foreach f,$(_GLIB_MARSHAL_GENERATED),$(eval $(call _glib_make_genmarshal_rules,$f))) + + +### glib-mkenums + +_GLIB_ENUM_TYPES_GENERATED = $(subst .h,,$(filter %enum-types.h %enumtypes.h,$(GLIB_GENERATED))) + +_glib_enum_types_prefix = $(subst -,_,$(notdir $(1))) +_glib_enum_types_guard = __$(shell LC_ALL=C echo $(_glib_enum_types_prefix) | tr 'a-z' 'A-Z')_H__ +_glib_enum_types_sources_var = $(_glib_enum_types_prefix)_sources +_glib_enum_types_sources = $(filter-out $(GLIB_GENERATED),$($(_glib_enum_types_sources_var))) +_glib_enum_types_h_sources = $(filter-out %-private.h,$(filter %.h,$(_glib_enum_types_sources))) + +define _glib_make_mkenums_rules +$(if $(_glib_enum_types_sources),,$(error Need to define $(_glib_enum_types_sources_var) for $(1).[ch])) + +$(1).h.stamp: $(_glib_enum_types_h_sources) Makefile + $$(_GLIB_V_GEN) $$(GLIB_MKENUMS) \ + --fhead "/* Generated by glib-mkenums. Do not edit */\n\n#ifndef $(_glib_enum_types_guard)\n#define $(_glib_enum_types_guard)\n\n" \ + $$(GLIB_MKENUMS_H_FLAGS) \ + $$($(_glib_enum_types_prefix)_MKENUMS_H_FLAGS) \ + --fhead "#include \n\nG_BEGIN_DECLS\n" \ + --vhead "GType @enum_name@_get_type (void) G_GNUC_CONST;\n#define @ENUMPREFIX@_TYPE_@ENUMSHORT@ (@enum_name@_get_type ())\n" \ + --ftail "G_END_DECLS\n\n#endif /* $(_glib_enum_types_guard) */" \ + $$(filter-out Makefile, $$^) > $(1).h.tmp && \ + (cmp -s $(1).h.tmp $(1).h || cp $(1).h.tmp $(1).h) && \ + rm -f $(1).h.tmp && \ + echo timestamp > $$@ + +$(1).h: $(1).h.stamp + @true + +$(1).c.stamp: $(_glib_enum_types_h_sources) Makefile + $$(_GLIB_V_GEN) $$(GLIB_MKENUMS) \ + --fhead "/* Generated by glib-mkenums. Do not edit */\n\n#include \"$(notdir $(1)).h\"\n" \ + $$(GLIB_MKENUMS_C_FLAGS) \ + $$($(_glib_enum_types_prefix)_MKENUMS_C_FLAGS) \ + --fhead "$$(foreach f,$$(filter-out Makefile,$$(^F)),\n#include \"$$(f)\")\n\n" \ + --vhead "GType\n@enum_name@_get_type (void)\n{\n static volatile gsize g_define_type_id__volatile = 0;\n\n if (g_once_init_enter (&g_define_type_id__volatile))\n {\n static const G@Type@Value values[] = {\n" \ + --vprod " { @VALUENAME@, \"@VALUENAME@\", \"@valuenick@\" },\n" \ + --vtail " { 0, NULL, NULL }\n };\n GType g_define_type_id =\n g_@type@_register_static (g_intern_static_string (\"@EnumName@\"), values);\n g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);\n }\n\n return g_define_type_id__volatile;\n}\n" \ + $$(filter-out Makefile, $$^) > $(1).c.tmp && \ + (cmp -s $(1).c.tmp $(1).c || cp $(1).c.tmp $(1).c) && \ + rm -f $(1).c.tmp && \ + echo timestamp > $$@ + +$(1).c: $(1).c.stamp + @true + +_GLIB_CLEANFILES += $(1).h.stamp $(1).c.stamp +_GLIB_DISTCLEANFILES += $(1).h $(1).c $(1).h.stamp $(1).c.stamp +endef + +$(foreach f,$(_GLIB_ENUM_TYPES_GENERATED),$(eval $(call _glib_make_mkenums_rules,$f))) + + +### glib-compile-schemas + +_GLIB_ENUMS_XML_GENERATED = $(filter %.enums.xml,$(GLIB_GENERATED)) +_GLIB_GSETTINGS_SCHEMA_FILES = $(filter %.gschema.xml,$(gsettingsschema_DATA)) +_GLIB_GSETTINGS_VALID_FILES = $(subst .xml,.valid,$(_GLIB_GSETTINGS_SCHEMA_FILES)) + +_glib_enums_xml_prefix = $(subst .,_,$(notdir $(1))) +_glib_enums_xml_sources_var = $(_glib_enums_xml_prefix)_sources +_glib_enums_xml_sources = $(filter-out $(GLIB_GENERATED),$($(_glib_enums_xml_sources_var))) +_glib_enums_xml_namespace = $(subst .enums.xml,,$(notdir $(1))) + +define _glib_make_enums_xml_rule +$(if $(_glib_enums_xml_sources),,$(error Need to define $(_glib_enums_xml_sources_var) for $(1))) + +$(1): $(_glib_enums_xml_sources) Makefile + $$(_GLIB_V_GEN) $$(GLIB_MKENUMS) --comments '' --fhead "" --vhead " <@type@ id='$(_glib_enums_xml_namespace).@EnumName@'>" --vprod " " --vtail " " --ftail "" $$(filter-out Makefile, $$^) > $$@.tmp && mv $$@.tmp $$@ +endef + +_GLIB_V_CHECK = $(_glib_v_check_$(V)) +_glib_v_check_ = $(_glib_v_check_$(AM_DEFAULT_VERBOSITY)) +_glib_v_check_0 = @echo " CHECK " $(subst .valid,.xml,$@); + +define _glib_make_schema_validate_rule +$(subst .xml,.valid,$(1)): $(_GLIB_ENUMS_XML_GENERATED) $(1) + $$(_GLIB_V_CHECK) $$(GLIB_COMPILE_SCHEMAS) --strict --dry-run $$(addprefix --schema-file=,$$^) && touch $$@ +endef + +define _glib_make_schema_rules +all-am: $(_GLIB_GSETTINGS_VALID_FILES) + +install-data-am: glib-install-schemas-hook + +glib-install-schemas-hook: install-gsettingsschemaDATA + @test -n "$(GSETTINGS_DISABLE_SCHEMAS_COMPILE)$(DESTDIR)" || (echo $(GLIB_COMPILE_SCHEMAS) $(gsettingsschemadir); $(GLIB_COMPILE_SCHEMAS) $(gsettingsschemadir)) + +uninstall-am: glib-uninstall-schemas-hook + +glib-uninstall-schemas-hook: uninstall-gsettingsschemaDATA + @test -n "$(GSETTINGS_DISABLE_SCHEMAS_COMPILE)$(DESTDIR)" || (echo $(GLIB_COMPILE_SCHEMAS) $(gsettingsschemadir); $(GLIB_COMPILE_SCHEMAS) $(gsettingsschemadir)) + +.PHONY: glib-install-schemas-hook glib-uninstall-schemas-hook +endef + +_GLIB_CLEANFILES += $(_GLIB_ENUMS_XML_GENERATED) $(_GLIB_GSETTINGS_VALID_FILES) + +$(foreach f,$(_GLIB_ENUMS_XML_GENERATED),$(eval $(call _glib_make_enums_xml_rule,$f))) +$(foreach f,$(_GLIB_GSETTINGS_SCHEMA_FILES),$(eval $(call _glib_make_schema_validate_rule,$f))) +$(if $(_GLIB_GSETTINGS_SCHEMA_FILES),$(eval $(_glib_make_schema_rules))) + + +### Cleanup +.PHONY: clean-glib distclean-glib + +clean-am: clean-glib +clean-glib: + $(if $(strip $(_GLIB_CLEANFILES)),-rm -f $(_GLIB_CLEANFILES)) + +distclean-am: distclean-glib +distclean-glib: + $(if $(strip $(_GLIB_DISTCLEANFILES)),-rm -f $(_GLIB_DISTCLEANFILES)) diff --git a/configure.ac b/configure.ac index bc608ad..bde4570 100644 --- a/configure.ac +++ b/configure.ac @@ -35,6 +35,7 @@ PKG_PROG_PKG_CONFIG GIO_DEPENDENCY="gio-unix-2.0 >= 2.34.0" PKG_CHECK_MODULES(BUILDDEP_GIO_UNIX, $GIO_DEPENDENCY) +AM_PATH_GLIB_2_0 GTK_DOC_CHECK([1.15], [--flavour no-tmpl]) AC_PATH_PROG([XSLTPROC], [xsltproc]) diff --git a/src/gsystem-file-tree-walk.c b/src/gsystem-file-tree-walk.c new file mode 100644 index 0000000..0d42479 --- /dev/null +++ b/src/gsystem-file-tree-walk.c @@ -0,0 +1,219 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2014 Colin Walters + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/** + * SECTION:gsfiletreewalk + * @title: GSFileTreeWalk + * @short_description: Recurse over a directory tree + * + * While #GFileEnumerator provides an API to iterate over one + * directory, in many cases one wants to operate recursively. + * This API is designed to do that. + * + * In addition, a #GSFileTreeWalk contains Unix-native API such as + * file descriptor based enumeration. + */ + +#include "config.h" + +#define _GSYSTEM_NO_LOCAL_ALLOC +#include "libgsystem.h" +#include "gsystem-file-tree-walk.h" +#include "gsystem-enum-types.h" +#include +#include +#include +#include +#include + +/* Taken from systemd/src/shared/util.h */ +union dirent_storage { + struct dirent dent; + guint8 storage[offsetof(struct dirent, d_name) + + ((NAME_MAX + 1 + sizeof(long)) & ~(sizeof(long) - 1))]; +}; + +typedef GObjectClass GSFileTreeWalkClass; + +struct _GSFileTreeWalk +{ + GObject parent; + + GSFileTreeWalkFlags flags; + int origin_dfd; + struct stat origin_stbuf; + + guint owns_dfd : 1; +}; + +G_DEFINE_TYPE (GSFileTreeWalk, gs_file_tree_walk, G_TYPE_OBJECT); + +enum +{ + PROP_0, + PROP_FLAGS, + N_PROPS +}; + +static GParamSpec *gs_file_tree_walk_pspecs[N_PROPS]; + +static void +gs_file_tree_walk_init (GSFileTreeWalk *self) +{ + self->origin_dfd = -1; +} + +static void +gs_file_tree_walk_finalize (GObject *object) +{ + GSFileTreeWalk *self = GS_FILE_TREE_WALK (object); + + if (self->owns_dfd && self->origin_dfd != -1) + (void) close (self->origin_dfd); + + if (G_OBJECT_CLASS (gs_file_tree_walk_class)->finalize != NULL) + G_OBJECT_CLASS (gs_file_tree_walk_class)->finalize (object); +} + +static void +gs_file_tree_walk_class_init (GSFileTreeWalkClass *class) +{ + /** + * GSFileTreeWalk:flags: + */ + gs_file_tree_walk_pspecs[PROP_FLAGS] = g_param_spec_flags ("flags", "", "", + GS_TYPE_FILE_TREE_WALK_FLAGS, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties (gobject_class, N_PROPS, gs_file_tree_walk_pspecs); +} + +static void +gs_file_tree_walk_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GSFileTreeWalk *self = GS_FILE_TREE_WALK (object); + + switch (prop_id) + { + case PROP_FLAGS: + self->flags = g_value_get_flags (value); + break; + + default: + g_assert_not_reached (); + } +} + +static void +gs_file_tree_walk_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GSFileTreeWalk *self = GS_FILE_TREE_WALK (object); + + switch (prop_id) + { + case PROP_FLAGS: + g_value_set_flags (value, self->flags); + break; + + default: + g_assert_not_reached (); + } +} + +/** + * gs_file_tree_walk_open: + * @path: Directory to enumerate + * @flags: Flags controlling enumeration + * @cancellable: Cancellable + * @error: Error + * + * Returns: (transfer full): A new directory enumerator + */ +GSFileTreeWalk * +gs_file_tree_walk_open (GFile *path, + GSFileTreeWalkFlags flags, + GCancellable *cancellable, + GError **error) +{ + gs_unref_object GSFileTreeWalk *ftw = g_object_new (GS_TYPE_FILE_TREE_WALK, "flags", flags, NULL); + + ftw->owns_dfd = TRUE; + + if (!gs_file_open_dir_fd (path, &ftw->origin_dfd, + cancellable, error)) + return NULL; + + return g_object_ref (ftw); +} + +/** + * gs_file_tree_walk_open_at: + * @dfd: Directory file descriptor + * @flags: Flags controlling enumeration + * @cancellable: Cancellable + * @error: Error + * + * Returns: (transfer full): A new directory enumerator + */ +GSFileTreeWalk * +gs_file_tree_walk_open_at (int dfd, + GSFileTreeWalkFlags flags, + GCancellable *cancellable, + GError **error) +{ + gs_unref_object GSFileTreeWalk *ftw = g_object_new (GS_TYPE_FILE_TREE_WALK, "flags", flags, NULL); + + ftw->origin_dfd = dfd; + if (fstat (ftw->origin_dfd, &ftw->origin_stbuf) != 0) + { + int errsv = errno; + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "fstat: %s", g_strerror (errsv)); + return NULL; + } + + return g_object_ref (ftw); +} + +/** + * gs_file_tree_walk_next: + * @self: Self + * @out_file_type: (out): File type, may be %G_FILE_TYPE_UNKNOWN + * + * Returns: %TRUE if there are more files to traverse + */ +gboolean +gs_file_tree_walk_next (GSFileTreeWalk *self, + GFileType *out_file_type) +{ +} + +int gs_file_tree_walk_get_dirfd (GSFileTreeWalk *self); + +const char *gs_file_tree_walk_get_name (GSFileTreeWalk *self); + +char *gs_file_tree_walk_get_relpath (GSFileTreeWalk *self); diff --git a/src/gsystem-file-tree-walk.h b/src/gsystem-file-tree-walk.h new file mode 100644 index 0000000..582ff7f --- /dev/null +++ b/src/gsystem-file-tree-walk.h @@ -0,0 +1,62 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2014 Colin Walters . + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GSYSTEM_FILE_TREEWALK_H__ +#define __GSYSTEM_FILE_TREEWALK_H__ + +#include + +G_BEGIN_DECLS + +#define GS_TYPE_FILE_TREE_WALK (gs_file_tree_walk_get_type ()) +#define GS_FILE_TREE_WALK(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GS_TYPE_FILE_TREE_WALK, GSFileTreeWalk)) +#define GS_IS_FILE_TREE_WALK(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GS_TYPE_FILE_TREE_WALK)) + +typedef struct _GSFileTreeWalk GSFileTreeWalk; + +GType gs_file_tree_walk_get_type (void) G_GNUC_CONST; + +typedef enum { + GS_FILE_TREE_WALK_FLAG_DEPTH = 1 << 0, + GS_FILE_TREE_WALK_FLAG_NOXDEV = 1 << 1 +} GSFileTreeWalkFlags; + +GSFileTreeWalk *gs_file_tree_walk_open (GFile *path, + GSFileTreeWalkFlags flags, + GCancellable *cancellable, + GError **error); + +GSFileTreeWalk *gs_file_tree_walk_open_at (int dfd, + GSFileTreeWalkFlags flags, + GCancellable *cancellable, + GError **error); + +gboolean gs_file_tree_walk_next (GSFileTreeWalk *self, + GFileType *out_file_type); + +int gs_file_tree_walk_get_dirfd (GSFileTreeWalk *self); + +const char *gs_file_tree_walk_get_name (GSFileTreeWalk *self); + +char *gs_file_tree_walk_get_relpath (GSFileTreeWalk *self); + +G_END_DECLS + +#endif diff --git a/src/libgsystem.h b/src/libgsystem.h index 60884b6..59df669 100644 --- a/src/libgsystem.h +++ b/src/libgsystem.h @@ -34,6 +34,7 @@ G_BEGIN_DECLS } G_STMT_END; #include +#include #include #include #if GLIB_CHECK_VERSION(2,34,0) -- cgit v1.2.1