diff options
author | Florian Dold <florian@dold.me> | 2021-07-28 14:31:38 +0200 |
---|---|---|
committer | Florian Dold <florian@dold.me> | 2021-07-28 15:27:39 +0200 |
commit | 7615d46b09275383bd244a0ef1d94b3a77559b88 (patch) | |
tree | f6452173470ae80b186a4ee6da24d1d88d5033f2 /src/util/disk.c | |
parent | 391794a460140192b3466765ebc63797cea44000 (diff) | |
download | gnunet-7615d46b09275383bd244a0ef1d94b3a77559b88.tar.gz gnunet-7615d46b09275383bd244a0ef1d94b3a77559b88.zip |
implement config inline globbing
Diffstat (limited to 'src/util/disk.c')
-rw-r--r-- | src/util/disk.c | 139 |
1 files changed, 138 insertions, 1 deletions
diff --git a/src/util/disk.c b/src/util/disk.c index 3bafe311d..1b909f13e 100644 --- a/src/util/disk.c +++ b/src/util/disk.c | |||
@@ -882,6 +882,143 @@ GNUNET_DISK_directory_scan (const char *dir_name, | |||
882 | return count; | 882 | return count; |
883 | } | 883 | } |
884 | 884 | ||
885 | /** | ||
886 | * Check for a simple wildcard match. | ||
887 | * Only asterisks are allowed. | ||
888 | * Asterisks match everything, including slashes. | ||
889 | * | ||
890 | * @param pattern pattern with wildcards | ||
891 | * @param str string to match against | ||
892 | * @returns true on match, false otherwise | ||
893 | */ | ||
894 | static bool | ||
895 | glob_match (const char *pattern, const char *str) | ||
896 | { | ||
897 | /* Position in the input string */ | ||
898 | const char *str_pos = str; | ||
899 | /* Position in the pattern */ | ||
900 | const char *pat_pos = pattern; | ||
901 | /* Backtrack position in string */ | ||
902 | const char *str_bt = NULL; | ||
903 | /* Backtrack position in pattern */ | ||
904 | const char *pat_bt = NULL; | ||
905 | |||
906 | for (;;) | ||
907 | { | ||
908 | if (*pat_pos == '*') | ||
909 | { | ||
910 | str_bt = str_pos; | ||
911 | pat_bt = pat_pos++; | ||
912 | } | ||
913 | else if (*pat_pos == *str_pos) | ||
914 | { | ||
915 | if ('\0' == *pat_pos) | ||
916 | return true; | ||
917 | str_pos++; | ||
918 | pat_pos++; | ||
919 | } | ||
920 | else | ||
921 | { | ||
922 | if (NULL == str_bt) | ||
923 | return false; | ||
924 | /* Backtrack to match one more | ||
925 | character as part of the asterisk. */ | ||
926 | str_pos = str_bt + 1; | ||
927 | if ('\0' == *str_pos) | ||
928 | return false; | ||
929 | pat_pos = pat_bt; | ||
930 | } | ||
931 | } | ||
932 | } | ||
933 | |||
934 | struct GlobClosure | ||
935 | { | ||
936 | const char *glob; | ||
937 | GNUNET_FileNameCallback cb; | ||
938 | void *cls; | ||
939 | }; | ||
940 | |||
941 | /** | ||
942 | * Function called with a filename. | ||
943 | * | ||
944 | * @param cls closure | ||
945 | * @param filename complete filename (absolute path) | ||
946 | * @return #GNUNET_OK to continue to iterate, | ||
947 | * #GNUNET_NO to stop iteration with no error, | ||
948 | * #GNUNET_SYSERR to abort iteration with error! | ||
949 | */ | ||
950 | static enum GNUNET_GenericReturnValue | ||
951 | glob_cb (void *cls, | ||
952 | const char *filename) | ||
953 | { | ||
954 | struct GlobClosure *gc = cls; | ||
955 | const char *fn; | ||
956 | |||
957 | fn = strrchr (filename, DIR_SEPARATOR); | ||
958 | fn = (NULL == fn) ? filename : (fn + 1); | ||
959 | |||
960 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
961 | "checking glob '%s' against '%s'\n", | ||
962 | gc->glob, | ||
963 | fn); | ||
964 | |||
965 | if (glob_match (gc->glob, fn)) | ||
966 | { | ||
967 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
968 | "found glob match '%s'\n", | ||
969 | filename); | ||
970 | gc->cb (gc->cls, filename); | ||
971 | } | ||
972 | return GNUNET_OK; | ||
973 | } | ||
974 | |||
975 | |||
976 | int | ||
977 | GNUNET_DISK_glob (const char *glob_pattern, | ||
978 | GNUNET_FileNameCallback callback, | ||
979 | void *callback_cls) | ||
980 | { | ||
981 | char *mypat = GNUNET_strdup (glob_pattern); | ||
982 | char *sep; | ||
983 | int ret; | ||
984 | |||
985 | sep = strrchr (mypat, DIR_SEPARATOR); | ||
986 | if (NULL == sep) | ||
987 | { | ||
988 | GNUNET_free (mypat); | ||
989 | return -1; | ||
990 | } | ||
991 | |||
992 | *sep = '\0'; | ||
993 | |||
994 | if (NULL != strchr (mypat, '*')) | ||
995 | { | ||
996 | GNUNET_free (mypat); | ||
997 | GNUNET_break (0); | ||
998 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
999 | "glob pattern may only contain '*' in the final path component\n"); | ||
1000 | return -1; | ||
1001 | } | ||
1002 | |||
1003 | { | ||
1004 | struct GlobClosure gc = { | ||
1005 | .glob = sep + 1, | ||
1006 | .cb = callback, | ||
1007 | .cls = callback_cls, | ||
1008 | }; | ||
1009 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1010 | "scanning directory '%s' for glob matches on '%s'\n", | ||
1011 | mypat, | ||
1012 | gc.glob); | ||
1013 | ret = GNUNET_DISK_directory_scan (mypat, | ||
1014 | glob_cb, | ||
1015 | &gc | ||
1016 | ); | ||
1017 | } | ||
1018 | GNUNET_free (mypat); | ||
1019 | return ret; | ||
1020 | } | ||
1021 | |||
885 | 1022 | ||
886 | /** | 1023 | /** |
887 | * Function that removes the given directory by calling | 1024 | * Function that removes the given directory by calling |
@@ -997,7 +1134,7 @@ GNUNET_DISK_file_copy (const char *src, | |||
997 | GNUNET_DISK_file_close (in); | 1134 | GNUNET_DISK_file_close (in); |
998 | GNUNET_DISK_file_close (out); | 1135 | GNUNET_DISK_file_close (out); |
999 | return GNUNET_OK; | 1136 | return GNUNET_OK; |
1000 | FAIL: | 1137 | FAIL: |
1001 | GNUNET_free (buf); | 1138 | GNUNET_free (buf); |
1002 | GNUNET_DISK_file_close (in); | 1139 | GNUNET_DISK_file_close (in); |
1003 | GNUNET_DISK_file_close (out); | 1140 | GNUNET_DISK_file_close (out); |