diff options
Diffstat (limited to 'src/util/disk.c')
-rw-r--r-- | src/util/disk.c | 194 |
1 files changed, 187 insertions, 7 deletions
diff --git a/src/util/disk.c b/src/util/disk.c index 3bafe311d..2efb52d46 100644 --- a/src/util/disk.c +++ b/src/util/disk.c | |||
@@ -432,9 +432,15 @@ GNUNET_DISK_directory_test (const char *fil, int is_readable) | |||
432 | return GNUNET_YES; | 432 | return GNUNET_YES; |
433 | } | 433 | } |
434 | 434 | ||
435 | 435 | /** | |
436 | enum GNUNET_GenericReturnValue | 436 | * Check if fil can be accessed using amode. |
437 | GNUNET_DISK_file_test (const char *fil) | 437 | * |
438 | * @param fil file to check for | ||
439 | * @param amode access mode | ||
440 | * @returns GNUnet error code | ||
441 | */ | ||
442 | static enum GNUNET_GenericReturnValue | ||
443 | file_test_internal (const char *fil, int amode) | ||
438 | { | 444 | { |
439 | struct stat filestat; | 445 | struct stat filestat; |
440 | int ret; | 446 | int ret; |
@@ -449,7 +455,7 @@ GNUNET_DISK_file_test (const char *fil) | |||
449 | { | 455 | { |
450 | if (errno != ENOENT) | 456 | if (errno != ENOENT) |
451 | { | 457 | { |
452 | LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "stat", rdir); | 458 | LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_DEBUG, "stat", rdir); |
453 | GNUNET_free (rdir); | 459 | GNUNET_free (rdir); |
454 | return GNUNET_SYSERR; | 460 | return GNUNET_SYSERR; |
455 | } | 461 | } |
@@ -461,9 +467,9 @@ GNUNET_DISK_file_test (const char *fil) | |||
461 | GNUNET_free (rdir); | 467 | GNUNET_free (rdir); |
462 | return GNUNET_NO; | 468 | return GNUNET_NO; |
463 | } | 469 | } |
464 | if (access (rdir, F_OK) < 0) | 470 | if (access (rdir, amode) < 0) |
465 | { | 471 | { |
466 | LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "access", rdir); | 472 | LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_DEBUG, "access", rdir); |
467 | GNUNET_free (rdir); | 473 | GNUNET_free (rdir); |
468 | return GNUNET_SYSERR; | 474 | return GNUNET_SYSERR; |
469 | } | 475 | } |
@@ -473,6 +479,20 @@ GNUNET_DISK_file_test (const char *fil) | |||
473 | 479 | ||
474 | 480 | ||
475 | enum GNUNET_GenericReturnValue | 481 | enum GNUNET_GenericReturnValue |
482 | GNUNET_DISK_file_test (const char *fil) | ||
483 | { | ||
484 | return file_test_internal (fil, F_OK); | ||
485 | } | ||
486 | |||
487 | |||
488 | enum GNUNET_GenericReturnValue | ||
489 | GNUNET_DISK_file_test_read (const char *fil) | ||
490 | { | ||
491 | return file_test_internal (fil, R_OK); | ||
492 | } | ||
493 | |||
494 | |||
495 | enum GNUNET_GenericReturnValue | ||
476 | GNUNET_DISK_directory_create (const char *dir) | 496 | GNUNET_DISK_directory_create (const char *dir) |
477 | { | 497 | { |
478 | char *rdir; | 498 | char *rdir; |
@@ -882,6 +902,166 @@ GNUNET_DISK_directory_scan (const char *dir_name, | |||
882 | return count; | 902 | return count; |
883 | } | 903 | } |
884 | 904 | ||
905 | /** | ||
906 | * Check for a simple wildcard match. | ||
907 | * Only asterisks are allowed. | ||
908 | * Asterisks match everything, including slashes. | ||
909 | * | ||
910 | * @param pattern pattern with wildcards | ||
911 | * @param str string to match against | ||
912 | * @returns true on match, false otherwise | ||
913 | */ | ||
914 | static bool | ||
915 | glob_match (const char *pattern, const char *str) | ||
916 | { | ||
917 | /* Position in the input string */ | ||
918 | const char *str_pos = str; | ||
919 | /* Position in the pattern */ | ||
920 | const char *pat_pos = pattern; | ||
921 | /* Backtrack position in string */ | ||
922 | const char *str_bt = NULL; | ||
923 | /* Backtrack position in pattern */ | ||
924 | const char *pat_bt = NULL; | ||
925 | |||
926 | for (;;) | ||
927 | { | ||
928 | if (*pat_pos == '*') | ||
929 | { | ||
930 | str_bt = str_pos; | ||
931 | pat_bt = pat_pos++; | ||
932 | } | ||
933 | else if (*pat_pos == *str_pos) | ||
934 | { | ||
935 | if ('\0' == *pat_pos) | ||
936 | return true; | ||
937 | str_pos++; | ||
938 | pat_pos++; | ||
939 | } | ||
940 | else | ||
941 | { | ||
942 | if (NULL == str_bt) | ||
943 | return false; | ||
944 | /* Backtrack to match one more | ||
945 | character as part of the asterisk. */ | ||
946 | str_pos = str_bt + 1; | ||
947 | if ('\0' == *str_pos) | ||
948 | return false; | ||
949 | pat_pos = pat_bt; | ||
950 | } | ||
951 | } | ||
952 | } | ||
953 | |||
954 | struct GlobClosure | ||
955 | { | ||
956 | const char *glob; | ||
957 | GNUNET_FileNameCallback cb; | ||
958 | void *cls; | ||
959 | |||
960 | /** | ||
961 | * Number of files that actually matched the glob pattern. | ||
962 | */ | ||
963 | int nres; | ||
964 | }; | ||
965 | |||
966 | /** | ||
967 | * Function called with a filename. | ||
968 | * | ||
969 | * @param cls closure | ||
970 | * @param filename complete filename (absolute path) | ||
971 | * @return #GNUNET_OK to continue to iterate, | ||
972 | * #GNUNET_NO to stop iteration with no error, | ||
973 | * #GNUNET_SYSERR to abort iteration with error! | ||
974 | */ | ||
975 | static enum GNUNET_GenericReturnValue | ||
976 | glob_cb (void *cls, | ||
977 | const char *filename) | ||
978 | { | ||
979 | struct GlobClosure *gc = cls; | ||
980 | const char *fn; | ||
981 | |||
982 | fn = strrchr (filename, DIR_SEPARATOR); | ||
983 | fn = (NULL == fn) ? filename : (fn + 1); | ||
984 | |||
985 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
986 | "checking glob '%s' against '%s'\n", | ||
987 | gc->glob, | ||
988 | fn); | ||
989 | |||
990 | if (glob_match (gc->glob, fn)) | ||
991 | { | ||
992 | enum GNUNET_GenericReturnValue cbret; | ||
993 | |||
994 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
995 | "found glob match '%s'\n", | ||
996 | filename); | ||
997 | gc->nres++; | ||
998 | cbret = gc->cb (gc->cls, filename); | ||
999 | if (GNUNET_OK != cbret) | ||
1000 | return cbret; | ||
1001 | } | ||
1002 | return GNUNET_OK; | ||
1003 | } | ||
1004 | |||
1005 | |||
1006 | int | ||
1007 | GNUNET_DISK_glob (const char *glob_pattern, | ||
1008 | GNUNET_FileNameCallback callback, | ||
1009 | void *callback_cls) | ||
1010 | { | ||
1011 | char *mypat = GNUNET_strdup (glob_pattern); | ||
1012 | char *sep; | ||
1013 | int ret; | ||
1014 | |||
1015 | if ( (NULL != strrchr (glob_pattern, '+')) || | ||
1016 | (NULL != strrchr (glob_pattern, '[')) || | ||
1017 | (NULL != strrchr (glob_pattern, '+')) || | ||
1018 | (NULL != strrchr (glob_pattern, '~')) ) | ||
1019 | { | ||
1020 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
1021 | "unsupported glob pattern: '%s'\n", | ||
1022 | glob_pattern); | ||
1023 | GNUNET_free (mypat); | ||
1024 | return -1; | ||
1025 | } | ||
1026 | |||
1027 | sep = strrchr (mypat, DIR_SEPARATOR); | ||
1028 | if (NULL == sep) | ||
1029 | { | ||
1030 | GNUNET_free (mypat); | ||
1031 | return -1; | ||
1032 | } | ||
1033 | |||
1034 | *sep = '\0'; | ||
1035 | |||
1036 | if (NULL != strchr (mypat, '*')) | ||
1037 | { | ||
1038 | GNUNET_free (mypat); | ||
1039 | GNUNET_break (0); | ||
1040 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
1041 | "glob pattern may only contain '*' in the final path component\n"); | ||
1042 | return -1; | ||
1043 | } | ||
1044 | |||
1045 | { | ||
1046 | struct GlobClosure gc = { | ||
1047 | .glob = sep + 1, | ||
1048 | .cb = callback, | ||
1049 | .cls = callback_cls, | ||
1050 | .nres = 0, | ||
1051 | }; | ||
1052 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1053 | "scanning directory '%s' for glob matches on '%s'\n", | ||
1054 | mypat, | ||
1055 | gc.glob); | ||
1056 | ret = GNUNET_DISK_directory_scan (mypat, | ||
1057 | glob_cb, | ||
1058 | &gc | ||
1059 | ); | ||
1060 | GNUNET_free (mypat); | ||
1061 | return (ret < 0) ? ret : gc.nres; | ||
1062 | } | ||
1063 | } | ||
1064 | |||
885 | 1065 | ||
886 | /** | 1066 | /** |
887 | * Function that removes the given directory by calling | 1067 | * Function that removes the given directory by calling |
@@ -997,7 +1177,7 @@ GNUNET_DISK_file_copy (const char *src, | |||
997 | GNUNET_DISK_file_close (in); | 1177 | GNUNET_DISK_file_close (in); |
998 | GNUNET_DISK_file_close (out); | 1178 | GNUNET_DISK_file_close (out); |
999 | return GNUNET_OK; | 1179 | return GNUNET_OK; |
1000 | FAIL: | 1180 | FAIL: |
1001 | GNUNET_free (buf); | 1181 | GNUNET_free (buf); |
1002 | GNUNET_DISK_file_close (in); | 1182 | GNUNET_DISK_file_close (in); |
1003 | GNUNET_DISK_file_close (out); | 1183 | GNUNET_DISK_file_close (out); |