aboutsummaryrefslogtreecommitdiff
path: root/src/util/disk.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/util/disk.c')
-rw-r--r--src/util/disk.c194
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/**
436enum GNUNET_GenericReturnValue 436 * Check if fil can be accessed using amode.
437GNUNET_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 */
442static enum GNUNET_GenericReturnValue
443file_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
475enum GNUNET_GenericReturnValue 481enum GNUNET_GenericReturnValue
482GNUNET_DISK_file_test (const char *fil)
483{
484 return file_test_internal (fil, F_OK);
485}
486
487
488enum GNUNET_GenericReturnValue
489GNUNET_DISK_file_test_read (const char *fil)
490{
491 return file_test_internal (fil, R_OK);
492}
493
494
495enum GNUNET_GenericReturnValue
476GNUNET_DISK_directory_create (const char *dir) 496GNUNET_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 */
914static bool
915glob_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
954struct 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 */
975static enum GNUNET_GenericReturnValue
976glob_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
1006int
1007GNUNET_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;
1000FAIL: 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);