aboutsummaryrefslogtreecommitdiff
path: root/src/util
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2015-05-28 09:02:31 +0000
committerChristian Grothoff <christian@grothoff.org>2015-05-28 09:02:31 +0000
commit078f7063aef1d4105e71160b8764ab95c2dcdfbe (patch)
tree86d498356ceaaa1ba738f64a158cce2cd0163a15 /src/util
parent9469cd334f29ca9437e13eb951b53b7690f10be9 (diff)
downloadgnunet-078f7063aef1d4105e71160b8764ab95c2dcdfbe.tar.gz
gnunet-078f7063aef1d4105e71160b8764ab95c2dcdfbe.zip
adding --enable-taler-wallet configure option to build a reduced version of libgnunetutil with only the parts needed by GNU Taler wallets
Diffstat (limited to 'src/util')
-rw-r--r--src/util/Makefile.am65
-rw-r--r--src/util/configuration.c43
-rw-r--r--src/util/configuration_loader.c69
-rw-r--r--src/util/crypto_ecc.c401
-rw-r--r--src/util/crypto_ecc_setup.c431
-rw-r--r--src/util/crypto_hash.c189
-rw-r--r--src/util/crypto_hash_file.c215
-rw-r--r--src/util/disk.c139
-rw-r--r--src/util/disk_iterator.c166
9 files changed, 935 insertions, 783 deletions
diff --git a/src/util/Makefile.am b/src/util/Makefile.am
index 685632b49..a2482fc87 100644
--- a/src/util/Makefile.am
+++ b/src/util/Makefile.am
@@ -46,12 +46,6 @@ gnunet_helper_w32_console_SOURCES = \
46gnunet_helper_w32_console_LDADD = \ 46gnunet_helper_w32_console_LDADD = \
47 libgnunetutil.la 47 libgnunetutil.la
48 48
49noinst_PROGRAMS = \
50 gnunet-config-diff \
51 $(W32CAT) \
52 test_common_logging_dummy
53
54
55gnunet_config_diff_SOURCES = \ 49gnunet_config_diff_SOURCES = \
56 gnunet-config-diff.c 50 gnunet-config-diff.c
57gnunet_config_diff_LDADD = \ 51gnunet_config_diff_LDADD = \
@@ -62,8 +56,6 @@ test_common_logging_dummy_SOURCES = \
62test_common_logging_dummy_LDADD = \ 56test_common_logging_dummy_LDADD = \
63 libgnunetutil.la 57 libgnunetutil.la
64 58
65lib_LTLIBRARIES = libgnunetutil.la
66
67libgnunetutil_la_SOURCES = \ 59libgnunetutil_la_SOURCES = \
68 bandwidth.c \ 60 bandwidth.c \
69 bio.c \ 61 bio.c \
@@ -73,6 +65,7 @@ libgnunetutil_la_SOURCES = \
73 common_endian.c \ 65 common_endian.c \
74 common_logging.c \ 66 common_logging.c \
75 configuration.c \ 67 configuration.c \
68 configuration_loader.c \
76 connection.c \ 69 connection.c \
77 container_bloomfilter.c \ 70 container_bloomfilter.c \
78 container_heap.c \ 71 container_heap.c \
@@ -83,7 +76,9 @@ libgnunetutil_la_SOURCES = \
83 crypto_symmetric.c \ 76 crypto_symmetric.c \
84 crypto_crc.c \ 77 crypto_crc.c \
85 crypto_ecc.c \ 78 crypto_ecc.c \
79 crypto_ecc_setup.c \
86 crypto_hash.c \ 80 crypto_hash.c \
81 crypto_hash_file.c \
87 crypto_hkdf.c \ 82 crypto_hkdf.c \
88 crypto_kdf.c \ 83 crypto_kdf.c \
89 crypto_mpi.c \ 84 crypto_mpi.c \
@@ -91,6 +86,7 @@ libgnunetutil_la_SOURCES = \
91 crypto_random.c \ 86 crypto_random.c \
92 crypto_rsa.c \ 87 crypto_rsa.c \
93 disk.c \ 88 disk.c \
89 disk_iterator.c \
94 disk.h \ 90 disk.h \
95 getopt.c \ 91 getopt.c \
96 getopt_helpers.c \ 92 getopt_helpers.c \
@@ -127,11 +123,46 @@ libgnunetutil_la_LDFLAGS = \
127 $(GN_LIB_LDFLAGS) \ 123 $(GN_LIB_LDFLAGS) \
128 -version-info 13:0:0 124 -version-info 13:0:0
129 125
126
127libgnunetutil_taler_wallet_la_SOURCES = \
128 common_allocation.c \
129 common_endian.c \
130 common_logging.c \
131 configuration.c \
132 container_heap.c \
133 container_multihashmap.c \
134 container_multihashmap32.c \
135 crypto_symmetric.c \
136 crypto_crc.c \
137 crypto_ecc.c \
138 crypto_hash.c \
139 crypto_hkdf.c \
140 crypto_kdf.c \
141 crypto_mpi.c \
142 crypto_random.c \
143 crypto_rsa.c \
144 disk.c \
145 disk.h \
146 strings.c \
147 time.c
148
149libgnunetutil_taler_wallet_la_LIBADD = \
150 $(LIBGCRYPT_LIBS) \
151 -lunistring
152
153libgnunetutil_taler_wallet_la_LDFLAGS = \
154 $(GN_LIB_LDFLAGS) \
155 -version-info 0:0:0
156
130if HAVE_TESTING 157if HAVE_TESTING
131 GNUNET_ECC = gnunet-ecc 158 GNUNET_ECC = gnunet-ecc
132 GNUNET_SCRYPT = gnunet-scrypt 159 GNUNET_SCRYPT = gnunet-scrypt
133endif 160endif
134 161
162if TALER_ONLY
163lib_LTLIBRARIES = libgnunetutil_taler_wallet.la
164else
165lib_LTLIBRARIES = libgnunetutil.la
135 166
136libexec_PROGRAMS = \ 167libexec_PROGRAMS = \
137 gnunet-service-resolver \ 168 gnunet-service-resolver \
@@ -147,6 +178,20 @@ bin_PROGRAMS = \
147 $(GNUNET_SCRYPT) \ 178 $(GNUNET_SCRYPT) \
148 gnunet-uri 179 gnunet-uri
149 180
181noinst_PROGRAMS = \
182 gnunet-config-diff \
183 $(W32CAT) \
184 test_common_logging_dummy
185
186
187if ENABLE_TEST_RUN
188AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;
189TESTS = $(check_PROGRAMS)
190endif
191
192endif
193
194
150do_subst = $(SED) -e 's,[@]PYTHON[@],$(PYTHON),g' 195do_subst = $(SED) -e 's,[@]PYTHON[@],$(PYTHON),g'
151 196
152gnunet-qr: gnunet-qr.py.in Makefile 197gnunet-qr: gnunet-qr.py.in Makefile
@@ -266,10 +311,6 @@ check_PROGRAMS = \
266 test_os_start_process \ 311 test_os_start_process \
267 test_common_logging_runtime_loglevels 312 test_common_logging_runtime_loglevels
268 313
269if ENABLE_TEST_RUN
270AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;
271TESTS = $(check_PROGRAMS)
272endif
273 314
274# Declare .nc (NO-CONCURRENCY) as a test extension so that we can impart 315# Declare .nc (NO-CONCURRENCY) as a test extension so that we can impart
275# sequential execution order for them 316# sequential execution order for them
diff --git a/src/util/configuration.c b/src/util/configuration.c
index 24b38f933..f61b43d57 100644
--- a/src/util/configuration.c
+++ b/src/util/configuration.c
@@ -1694,47 +1694,4 @@ GNUNET_CONFIGURATION_load_from (struct GNUNET_CONFIGURATION_Handle *cfg,
1694} 1694}
1695 1695
1696 1696
1697/**
1698 * Load configuration (starts with defaults, then loads
1699 * system-specific configuration).
1700 *
1701 * @param cfg configuration to update
1702 * @param filename name of the configuration file, NULL to load defaults
1703 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
1704 */
1705int
1706GNUNET_CONFIGURATION_load (struct GNUNET_CONFIGURATION_Handle *cfg,
1707 const char *filename)
1708{
1709 char *baseconfig;
1710 char *ipath;
1711
1712 ipath = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_DATADIR);
1713 if (NULL == ipath)
1714 return GNUNET_SYSERR;
1715 baseconfig = NULL;
1716 GNUNET_asprintf (&baseconfig, "%s%s", ipath, "config.d");
1717 GNUNET_free (ipath);
1718 if (GNUNET_SYSERR ==
1719 GNUNET_DISK_directory_scan (baseconfig, &parse_configuration_file, cfg))
1720 {
1721 GNUNET_free (baseconfig);
1722 return GNUNET_SYSERR; /* no configuration at all found */
1723 }
1724 GNUNET_free (baseconfig);
1725 if ((NULL != filename) &&
1726 (GNUNET_OK != GNUNET_CONFIGURATION_parse (cfg, filename)))
1727 {
1728 /* specified configuration not found */
1729 return GNUNET_SYSERR;
1730 }
1731 if (((GNUNET_YES !=
1732 GNUNET_CONFIGURATION_have_value (cfg, "PATHS", "DEFAULTCONFIG"))) &&
1733 (filename != NULL))
1734 GNUNET_CONFIGURATION_set_value_string (cfg, "PATHS", "DEFAULTCONFIG",
1735 filename);
1736 return GNUNET_OK;
1737}
1738
1739
1740/* end of configuration.c */ 1697/* end of configuration.c */
diff --git a/src/util/configuration_loader.c b/src/util/configuration_loader.c
new file mode 100644
index 000000000..0b7f2865d
--- /dev/null
+++ b/src/util/configuration_loader.c
@@ -0,0 +1,69 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2006, 2007, 2008, 2009, 2013 Christian Grothoff (and other contributing authors)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21/**
22 * @file src/util/configuration_loader.c
23 * @brief configuration loading
24 * @author Christian Grothoff
25 */
26
27/**
28 * Load configuration (starts with defaults, then loads
29 * system-specific configuration).
30 *
31 * @param cfg configuration to update
32 * @param filename name of the configuration file, NULL to load defaults
33 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
34 */
35int
36GNUNET_CONFIGURATION_load (struct GNUNET_CONFIGURATION_Handle *cfg,
37 const char *filename)
38{
39 char *baseconfig;
40 char *ipath;
41
42 ipath = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_DATADIR);
43 if (NULL == ipath)
44 return GNUNET_SYSERR;
45 baseconfig = NULL;
46 GNUNET_asprintf (&baseconfig, "%s%s", ipath, "config.d");
47 GNUNET_free (ipath);
48 if (GNUNET_SYSERR ==
49 GNUNET_DISK_directory_scan (baseconfig, &parse_configuration_file, cfg))
50 {
51 GNUNET_free (baseconfig);
52 return GNUNET_SYSERR; /* no configuration at all found */
53 }
54 GNUNET_free (baseconfig);
55 if ((NULL != filename) &&
56 (GNUNET_OK != GNUNET_CONFIGURATION_parse (cfg, filename)))
57 {
58 /* specified configuration not found */
59 return GNUNET_SYSERR;
60 }
61 if (((GNUNET_YES !=
62 GNUNET_CONFIGURATION_have_value (cfg, "PATHS", "DEFAULTCONFIG"))) &&
63 (filename != NULL))
64 GNUNET_CONFIGURATION_set_value_string (cfg, "PATHS", "DEFAULTCONFIG",
65 filename);
66 return GNUNET_OK;
67}
68
69/* end of configuration_loader.c */
diff --git a/src/util/crypto_ecc.c b/src/util/crypto_ecc.c
index e6d6bc133..87c787185 100644
--- a/src/util/crypto_ecc.c
+++ b/src/util/crypto_ecc.c
@@ -658,407 +658,6 @@ GNUNET_CRYPTO_ecdsa_key_get_anonymous ()
658 658
659 659
660/** 660/**
661 * Wait for a short time (we're trying to lock a file or want
662 * to give another process a shot at finishing a disk write, etc.).
663 * Sleeps for 100ms (as that should be long enough for virtually all
664 * modern systems to context switch and allow another process to do
665 * some 'real' work).
666 */
667static void
668short_wait ()
669{
670 struct GNUNET_TIME_Relative timeout;
671
672 timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 100);
673 (void) GNUNET_NETWORK_socket_select (NULL, NULL, NULL, timeout);
674}
675
676
677/**
678 * Create a new private key by reading it from a file. If the
679 * files does not exist, create a new key and write it to the
680 * file. Caller must free return value. Note that this function
681 * can not guarantee that another process might not be trying
682 * the same operation on the same file at the same time.
683 * If the contents of the file
684 * are invalid the old file is deleted and a fresh key is
685 * created.
686 *
687 * @param filename name of file to use to store the key
688 * @return new private key, NULL on error (for example,
689 * permission denied)
690 */
691struct GNUNET_CRYPTO_EddsaPrivateKey *
692GNUNET_CRYPTO_eddsa_key_create_from_file (const char *filename)
693{
694 struct GNUNET_CRYPTO_EddsaPrivateKey *priv;
695 struct GNUNET_DISK_FileHandle *fd;
696 unsigned int cnt;
697 int ec;
698 uint64_t fs;
699
700 if (GNUNET_SYSERR == GNUNET_DISK_directory_create_for_file (filename))
701 return NULL;
702 while (GNUNET_YES != GNUNET_DISK_file_test (filename))
703 {
704 fd = GNUNET_DISK_file_open (filename,
705 GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_CREATE
706 | GNUNET_DISK_OPEN_FAILIFEXISTS,
707 GNUNET_DISK_PERM_USER_READ |
708 GNUNET_DISK_PERM_USER_WRITE);
709 if (NULL == fd)
710 {
711 if (EEXIST == errno)
712 {
713 if (GNUNET_YES != GNUNET_DISK_file_test (filename))
714 {
715 /* must exist but not be accessible, fail for good! */
716 if (0 != ACCESS (filename, R_OK))
717 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "access", filename);
718 else
719 GNUNET_break (0); /* what is going on!? */
720 return NULL;
721 }
722 continue;
723 }
724 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "open", filename);
725 return NULL;
726 }
727 cnt = 0;
728 while (GNUNET_YES !=
729 GNUNET_DISK_file_lock (fd, 0,
730 sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey),
731 GNUNET_YES))
732 {
733 short_wait ();
734 if (0 == ++cnt % 10)
735 {
736 ec = errno;
737 LOG (GNUNET_ERROR_TYPE_ERROR,
738 _("Could not acquire lock on file `%s': %s...\n"), filename,
739 STRERROR (ec));
740 }
741 }
742 LOG (GNUNET_ERROR_TYPE_INFO,
743 _("Creating a new private key. This may take a while.\n"));
744 priv = GNUNET_CRYPTO_eddsa_key_create ();
745 GNUNET_assert (NULL != priv);
746 GNUNET_assert (sizeof (*priv) ==
747 GNUNET_DISK_file_write (fd, priv, sizeof (*priv)));
748 GNUNET_DISK_file_sync (fd);
749 if (GNUNET_YES !=
750 GNUNET_DISK_file_unlock (fd, 0,
751 sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey)))
752 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename);
753 GNUNET_assert (GNUNET_YES == GNUNET_DISK_file_close (fd));
754 return priv;
755 }
756 /* key file exists already, read it! */
757 fd = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_READ,
758 GNUNET_DISK_PERM_NONE);
759 if (NULL == fd)
760 {
761 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "open", filename);
762 return NULL;
763 }
764 cnt = 0;
765 while (1)
766 {
767 if (GNUNET_YES !=
768 GNUNET_DISK_file_lock (fd, 0,
769 sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey),
770 GNUNET_NO))
771 {
772 if (0 == ++cnt % 60)
773 {
774 ec = errno;
775 LOG (GNUNET_ERROR_TYPE_ERROR,
776 _("Could not acquire lock on file `%s': %s...\n"), filename,
777 STRERROR (ec));
778 LOG (GNUNET_ERROR_TYPE_ERROR,
779 _
780 ("This may be ok if someone is currently generating a private key.\n"));
781 }
782 short_wait ();
783 continue;
784 }
785 if (GNUNET_YES != GNUNET_DISK_file_test (filename))
786 {
787 /* eh, what!? File we opened is now gone!? */
788 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "stat", filename);
789 if (GNUNET_YES !=
790 GNUNET_DISK_file_unlock (fd, 0,
791 sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey)))
792 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename);
793 GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fd));
794
795 return NULL;
796 }
797 if (GNUNET_OK != GNUNET_DISK_file_size (filename, &fs, GNUNET_YES, GNUNET_YES))
798 fs = 0;
799 if (fs < sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey))
800 {
801 /* maybe we got the read lock before the key generating
802 * process had a chance to get the write lock; give it up! */
803 if (GNUNET_YES !=
804 GNUNET_DISK_file_unlock (fd, 0,
805 sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey)))
806 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename);
807 if (0 == ++cnt % 10)
808 {
809 LOG (GNUNET_ERROR_TYPE_ERROR,
810 _("When trying to read key file `%s' I found %u bytes but I need at least %u.\n"),
811 filename, (unsigned int) fs,
812 (unsigned int) sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey));
813 LOG (GNUNET_ERROR_TYPE_ERROR,
814 _("This may be ok if someone is currently generating a key.\n"));
815 }
816 short_wait (); /* wait a bit longer! */
817 continue;
818 }
819 break;
820 }
821 fs = sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey);
822 priv = GNUNET_malloc (fs);
823 GNUNET_assert (fs == GNUNET_DISK_file_read (fd, priv, fs));
824 if (GNUNET_YES !=
825 GNUNET_DISK_file_unlock (fd, 0,
826 sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey)))
827 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename);
828 GNUNET_assert (GNUNET_YES == GNUNET_DISK_file_close (fd));
829 return priv;
830}
831
832
833/**
834 * Create a new private key by reading it from a file. If the
835 * files does not exist, create a new key and write it to the
836 * file. Caller must free return value. Note that this function
837 * can not guarantee that another process might not be trying
838 * the same operation on the same file at the same time.
839 * If the contents of the file
840 * are invalid the old file is deleted and a fresh key is
841 * created.
842 *
843 * @param filename name of file to use to store the key
844 * @return new private key, NULL on error (for example,
845 * permission denied)
846 */
847struct GNUNET_CRYPTO_EcdsaPrivateKey *
848GNUNET_CRYPTO_ecdsa_key_create_from_file (const char *filename)
849{
850 struct GNUNET_CRYPTO_EcdsaPrivateKey *priv;
851 struct GNUNET_DISK_FileHandle *fd;
852 unsigned int cnt;
853 int ec;
854 uint64_t fs;
855
856 if (GNUNET_SYSERR == GNUNET_DISK_directory_create_for_file (filename))
857 return NULL;
858 while (GNUNET_YES != GNUNET_DISK_file_test (filename))
859 {
860 fd = GNUNET_DISK_file_open (filename,
861 GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_CREATE
862 | GNUNET_DISK_OPEN_FAILIFEXISTS,
863 GNUNET_DISK_PERM_USER_READ |
864 GNUNET_DISK_PERM_USER_WRITE);
865 if (NULL == fd)
866 {
867 if (EEXIST == errno)
868 {
869 if (GNUNET_YES != GNUNET_DISK_file_test (filename))
870 {
871 /* must exist but not be accessible, fail for good! */
872 if (0 != ACCESS (filename, R_OK))
873 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "access", filename);
874 else
875 GNUNET_break (0); /* what is going on!? */
876 return NULL;
877 }
878 continue;
879 }
880 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "open", filename);
881 return NULL;
882 }
883 cnt = 0;
884 while (GNUNET_YES !=
885 GNUNET_DISK_file_lock (fd, 0,
886 sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey),
887 GNUNET_YES))
888 {
889 short_wait ();
890 if (0 == ++cnt % 10)
891 {
892 ec = errno;
893 LOG (GNUNET_ERROR_TYPE_ERROR,
894 _("Could not acquire lock on file `%s': %s...\n"), filename,
895 STRERROR (ec));
896 }
897 }
898 LOG (GNUNET_ERROR_TYPE_INFO,
899 _("Creating a new private key. This may take a while.\n"));
900 priv = GNUNET_CRYPTO_ecdsa_key_create ();
901 GNUNET_assert (NULL != priv);
902 GNUNET_assert (sizeof (*priv) ==
903 GNUNET_DISK_file_write (fd, priv, sizeof (*priv)));
904 GNUNET_DISK_file_sync (fd);
905 if (GNUNET_YES !=
906 GNUNET_DISK_file_unlock (fd, 0,
907 sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey)))
908 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename);
909 GNUNET_assert (GNUNET_YES == GNUNET_DISK_file_close (fd));
910 return priv;
911 }
912 /* key file exists already, read it! */
913 fd = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_READ,
914 GNUNET_DISK_PERM_NONE);
915 if (NULL == fd)
916 {
917 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "open", filename);
918 return NULL;
919 }
920 cnt = 0;
921 while (1)
922 {
923 if (GNUNET_YES !=
924 GNUNET_DISK_file_lock (fd, 0,
925 sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey),
926 GNUNET_NO))
927 {
928 if (0 == ++cnt % 60)
929 {
930 ec = errno;
931 LOG (GNUNET_ERROR_TYPE_ERROR,
932 _("Could not acquire lock on file `%s': %s...\n"), filename,
933 STRERROR (ec));
934 LOG (GNUNET_ERROR_TYPE_ERROR,
935 _
936 ("This may be ok if someone is currently generating a private key.\n"));
937 }
938 short_wait ();
939 continue;
940 }
941 if (GNUNET_YES != GNUNET_DISK_file_test (filename))
942 {
943 /* eh, what!? File we opened is now gone!? */
944 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "stat", filename);
945 if (GNUNET_YES !=
946 GNUNET_DISK_file_unlock (fd, 0,
947 sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey)))
948 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename);
949 GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fd));
950
951 return NULL;
952 }
953 if (GNUNET_OK != GNUNET_DISK_file_size (filename, &fs, GNUNET_YES, GNUNET_YES))
954 fs = 0;
955 if (fs < sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey))
956 {
957 /* maybe we got the read lock before the key generating
958 * process had a chance to get the write lock; give it up! */
959 if (GNUNET_YES !=
960 GNUNET_DISK_file_unlock (fd, 0,
961 sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey)))
962 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename);
963 if (0 == ++cnt % 10)
964 {
965 LOG (GNUNET_ERROR_TYPE_ERROR,
966 _("When trying to read key file `%s' I found %u bytes but I need at least %u.\n"),
967 filename, (unsigned int) fs,
968 (unsigned int) sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey));
969 LOG (GNUNET_ERROR_TYPE_ERROR,
970 _("This may be ok if someone is currently generating a key.\n"));
971 }
972 short_wait (); /* wait a bit longer! */
973 continue;
974 }
975 break;
976 }
977 fs = sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey);
978 priv = GNUNET_malloc (fs);
979 GNUNET_assert (fs == GNUNET_DISK_file_read (fd, priv, fs));
980 if (GNUNET_YES !=
981 GNUNET_DISK_file_unlock (fd, 0,
982 sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey)))
983 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename);
984 GNUNET_assert (GNUNET_YES == GNUNET_DISK_file_close (fd));
985 return priv;
986}
987
988
989/**
990 * Create a new private key by reading our peer's key from
991 * the file specified in the configuration.
992 *
993 * @param cfg the configuration to use
994 * @return new private key, NULL on error (for example,
995 * permission denied)
996 */
997struct GNUNET_CRYPTO_EddsaPrivateKey *
998GNUNET_CRYPTO_eddsa_key_create_from_configuration (const struct GNUNET_CONFIGURATION_Handle *cfg)
999{
1000 struct GNUNET_CRYPTO_EddsaPrivateKey *priv;
1001 char *fn;
1002
1003 if (GNUNET_OK !=
1004 GNUNET_CONFIGURATION_get_value_filename (cfg, "PEER", "PRIVATE_KEY", &fn))
1005 return NULL;
1006 priv = GNUNET_CRYPTO_eddsa_key_create_from_file (fn);
1007 GNUNET_free (fn);
1008 return priv;
1009}
1010
1011
1012/**
1013 * Setup a key file for a peer given the name of the
1014 * configuration file (!). This function is used so that
1015 * at a later point code can be certain that reading a
1016 * key is fast (for example in time-dependent testcases).
1017 *
1018 * @param cfg_name name of the configuration file to use
1019 */
1020void
1021GNUNET_CRYPTO_eddsa_setup_key (const char *cfg_name)
1022{
1023 struct GNUNET_CONFIGURATION_Handle *cfg;
1024 struct GNUNET_CRYPTO_EddsaPrivateKey *priv;
1025
1026 cfg = GNUNET_CONFIGURATION_create ();
1027 (void) GNUNET_CONFIGURATION_load (cfg, cfg_name);
1028 priv = GNUNET_CRYPTO_eddsa_key_create_from_configuration (cfg);
1029 if (NULL != priv)
1030 GNUNET_free (priv);
1031 GNUNET_CONFIGURATION_destroy (cfg);
1032}
1033
1034
1035/**
1036 * Retrieve the identity of the host's peer.
1037 *
1038 * @param cfg configuration to use
1039 * @param dst pointer to where to write the peer identity
1040 * @return #GNUNET_OK on success, #GNUNET_SYSERR if the identity
1041 * could not be retrieved
1042 */
1043int
1044GNUNET_CRYPTO_get_peer_identity (const struct GNUNET_CONFIGURATION_Handle *cfg,
1045 struct GNUNET_PeerIdentity *dst)
1046{
1047 struct GNUNET_CRYPTO_EddsaPrivateKey *priv;
1048
1049 if (NULL == (priv = GNUNET_CRYPTO_eddsa_key_create_from_configuration (cfg)))
1050 {
1051 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1052 _("Could not load peer's private key\n"));
1053 return GNUNET_SYSERR;
1054 }
1055 GNUNET_CRYPTO_eddsa_key_get_public (priv, &dst->public_key);
1056 GNUNET_free (priv);
1057 return GNUNET_OK;
1058}
1059
1060
1061/**
1062 * Compare two Peer Identities. 661 * Compare two Peer Identities.
1063 * 662 *
1064 * @param first first peer identity 663 * @param first first peer identity
diff --git a/src/util/crypto_ecc_setup.c b/src/util/crypto_ecc_setup.c
new file mode 100644
index 000000000..32e1acee3
--- /dev/null
+++ b/src/util/crypto_ecc_setup.c
@@ -0,0 +1,431 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012, 2013, 2015 Christian Grothoff (and other contributing authors)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21/**
22 * @file util/crypto_ecc_setup.c
23 * @brief helper function for easy EdDSA key setup
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include <gcrypt.h>
28#include "gnunet_util_lib.h"
29
30
31/**
32 * Wait for a short time (we're trying to lock a file or want
33 * to give another process a shot at finishing a disk write, etc.).
34 * Sleeps for 100ms (as that should be long enough for virtually all
35 * modern systems to context switch and allow another process to do
36 * some 'real' work).
37 */
38static void
39short_wait ()
40{
41 struct GNUNET_TIME_Relative timeout;
42
43 timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 100);
44 (void) GNUNET_NETWORK_socket_select (NULL, NULL, NULL, timeout);
45}
46
47
48/**
49 * Create a new private key by reading it from a file. If the
50 * files does not exist, create a new key and write it to the
51 * file. Caller must free return value. Note that this function
52 * can not guarantee that another process might not be trying
53 * the same operation on the same file at the same time.
54 * If the contents of the file
55 * are invalid the old file is deleted and a fresh key is
56 * created.
57 *
58 * @param filename name of file to use to store the key
59 * @return new private key, NULL on error (for example,
60 * permission denied)
61 */
62struct GNUNET_CRYPTO_EddsaPrivateKey *
63GNUNET_CRYPTO_eddsa_key_create_from_file (const char *filename)
64{
65 struct GNUNET_CRYPTO_EddsaPrivateKey *priv;
66 struct GNUNET_DISK_FileHandle *fd;
67 unsigned int cnt;
68 int ec;
69 uint64_t fs;
70
71 if (GNUNET_SYSERR == GNUNET_DISK_directory_create_for_file (filename))
72 return NULL;
73 while (GNUNET_YES != GNUNET_DISK_file_test (filename))
74 {
75 fd = GNUNET_DISK_file_open (filename,
76 GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_CREATE
77 | GNUNET_DISK_OPEN_FAILIFEXISTS,
78 GNUNET_DISK_PERM_USER_READ |
79 GNUNET_DISK_PERM_USER_WRITE);
80 if (NULL == fd)
81 {
82 if (EEXIST == errno)
83 {
84 if (GNUNET_YES != GNUNET_DISK_file_test (filename))
85 {
86 /* must exist but not be accessible, fail for good! */
87 if (0 != ACCESS (filename, R_OK))
88 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "access", filename);
89 else
90 GNUNET_break (0); /* what is going on!? */
91 return NULL;
92 }
93 continue;
94 }
95 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "open", filename);
96 return NULL;
97 }
98 cnt = 0;
99 while (GNUNET_YES !=
100 GNUNET_DISK_file_lock (fd, 0,
101 sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey),
102 GNUNET_YES))
103 {
104 short_wait ();
105 if (0 == ++cnt % 10)
106 {
107 ec = errno;
108 LOG (GNUNET_ERROR_TYPE_ERROR,
109 _("Could not acquire lock on file `%s': %s...\n"), filename,
110 STRERROR (ec));
111 }
112 }
113 LOG (GNUNET_ERROR_TYPE_INFO,
114 _("Creating a new private key. This may take a while.\n"));
115 priv = GNUNET_CRYPTO_eddsa_key_create ();
116 GNUNET_assert (NULL != priv);
117 GNUNET_assert (sizeof (*priv) ==
118 GNUNET_DISK_file_write (fd, priv, sizeof (*priv)));
119 GNUNET_DISK_file_sync (fd);
120 if (GNUNET_YES !=
121 GNUNET_DISK_file_unlock (fd, 0,
122 sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey)))
123 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename);
124 GNUNET_assert (GNUNET_YES == GNUNET_DISK_file_close (fd));
125 return priv;
126 }
127 /* key file exists already, read it! */
128 fd = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_READ,
129 GNUNET_DISK_PERM_NONE);
130 if (NULL == fd)
131 {
132 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "open", filename);
133 return NULL;
134 }
135 cnt = 0;
136 while (1)
137 {
138 if (GNUNET_YES !=
139 GNUNET_DISK_file_lock (fd, 0,
140 sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey),
141 GNUNET_NO))
142 {
143 if (0 == ++cnt % 60)
144 {
145 ec = errno;
146 LOG (GNUNET_ERROR_TYPE_ERROR,
147 _("Could not acquire lock on file `%s': %s...\n"), filename,
148 STRERROR (ec));
149 LOG (GNUNET_ERROR_TYPE_ERROR,
150 _
151 ("This may be ok if someone is currently generating a private key.\n"));
152 }
153 short_wait ();
154 continue;
155 }
156 if (GNUNET_YES != GNUNET_DISK_file_test (filename))
157 {
158 /* eh, what!? File we opened is now gone!? */
159 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "stat", filename);
160 if (GNUNET_YES !=
161 GNUNET_DISK_file_unlock (fd, 0,
162 sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey)))
163 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename);
164 GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fd));
165
166 return NULL;
167 }
168 if (GNUNET_OK != GNUNET_DISK_file_size (filename, &fs, GNUNET_YES, GNUNET_YES))
169 fs = 0;
170 if (fs < sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey))
171 {
172 /* maybe we got the read lock before the key generating
173 * process had a chance to get the write lock; give it up! */
174 if (GNUNET_YES !=
175 GNUNET_DISK_file_unlock (fd, 0,
176 sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey)))
177 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename);
178 if (0 == ++cnt % 10)
179 {
180 LOG (GNUNET_ERROR_TYPE_ERROR,
181 _("When trying to read key file `%s' I found %u bytes but I need at least %u.\n"),
182 filename, (unsigned int) fs,
183 (unsigned int) sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey));
184 LOG (GNUNET_ERROR_TYPE_ERROR,
185 _("This may be ok if someone is currently generating a key.\n"));
186 }
187 short_wait (); /* wait a bit longer! */
188 continue;
189 }
190 break;
191 }
192 fs = sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey);
193 priv = GNUNET_malloc (fs);
194 GNUNET_assert (fs == GNUNET_DISK_file_read (fd, priv, fs));
195 if (GNUNET_YES !=
196 GNUNET_DISK_file_unlock (fd, 0,
197 sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey)))
198 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename);
199 GNUNET_assert (GNUNET_YES == GNUNET_DISK_file_close (fd));
200 return priv;
201}
202
203
204/**
205 * Create a new private key by reading it from a file. If the
206 * files does not exist, create a new key and write it to the
207 * file. Caller must free return value. Note that this function
208 * can not guarantee that another process might not be trying
209 * the same operation on the same file at the same time.
210 * If the contents of the file
211 * are invalid the old file is deleted and a fresh key is
212 * created.
213 *
214 * @param filename name of file to use to store the key
215 * @return new private key, NULL on error (for example,
216 * permission denied)
217 */
218struct GNUNET_CRYPTO_EcdsaPrivateKey *
219GNUNET_CRYPTO_ecdsa_key_create_from_file (const char *filename)
220{
221 struct GNUNET_CRYPTO_EcdsaPrivateKey *priv;
222 struct GNUNET_DISK_FileHandle *fd;
223 unsigned int cnt;
224 int ec;
225 uint64_t fs;
226
227 if (GNUNET_SYSERR == GNUNET_DISK_directory_create_for_file (filename))
228 return NULL;
229 while (GNUNET_YES != GNUNET_DISK_file_test (filename))
230 {
231 fd = GNUNET_DISK_file_open (filename,
232 GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_CREATE
233 | GNUNET_DISK_OPEN_FAILIFEXISTS,
234 GNUNET_DISK_PERM_USER_READ |
235 GNUNET_DISK_PERM_USER_WRITE);
236 if (NULL == fd)
237 {
238 if (EEXIST == errno)
239 {
240 if (GNUNET_YES != GNUNET_DISK_file_test (filename))
241 {
242 /* must exist but not be accessible, fail for good! */
243 if (0 != ACCESS (filename, R_OK))
244 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "access", filename);
245 else
246 GNUNET_break (0); /* what is going on!? */
247 return NULL;
248 }
249 continue;
250 }
251 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "open", filename);
252 return NULL;
253 }
254 cnt = 0;
255 while (GNUNET_YES !=
256 GNUNET_DISK_file_lock (fd, 0,
257 sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey),
258 GNUNET_YES))
259 {
260 short_wait ();
261 if (0 == ++cnt % 10)
262 {
263 ec = errno;
264 LOG (GNUNET_ERROR_TYPE_ERROR,
265 _("Could not acquire lock on file `%s': %s...\n"), filename,
266 STRERROR (ec));
267 }
268 }
269 LOG (GNUNET_ERROR_TYPE_INFO,
270 _("Creating a new private key. This may take a while.\n"));
271 priv = GNUNET_CRYPTO_ecdsa_key_create ();
272 GNUNET_assert (NULL != priv);
273 GNUNET_assert (sizeof (*priv) ==
274 GNUNET_DISK_file_write (fd, priv, sizeof (*priv)));
275 GNUNET_DISK_file_sync (fd);
276 if (GNUNET_YES !=
277 GNUNET_DISK_file_unlock (fd, 0,
278 sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey)))
279 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename);
280 GNUNET_assert (GNUNET_YES == GNUNET_DISK_file_close (fd));
281 return priv;
282 }
283 /* key file exists already, read it! */
284 fd = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_READ,
285 GNUNET_DISK_PERM_NONE);
286 if (NULL == fd)
287 {
288 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "open", filename);
289 return NULL;
290 }
291 cnt = 0;
292 while (1)
293 {
294 if (GNUNET_YES !=
295 GNUNET_DISK_file_lock (fd, 0,
296 sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey),
297 GNUNET_NO))
298 {
299 if (0 == ++cnt % 60)
300 {
301 ec = errno;
302 LOG (GNUNET_ERROR_TYPE_ERROR,
303 _("Could not acquire lock on file `%s': %s...\n"), filename,
304 STRERROR (ec));
305 LOG (GNUNET_ERROR_TYPE_ERROR,
306 _
307 ("This may be ok if someone is currently generating a private key.\n"));
308 }
309 short_wait ();
310 continue;
311 }
312 if (GNUNET_YES != GNUNET_DISK_file_test (filename))
313 {
314 /* eh, what!? File we opened is now gone!? */
315 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "stat", filename);
316 if (GNUNET_YES !=
317 GNUNET_DISK_file_unlock (fd, 0,
318 sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey)))
319 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename);
320 GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fd));
321
322 return NULL;
323 }
324 if (GNUNET_OK != GNUNET_DISK_file_size (filename, &fs, GNUNET_YES, GNUNET_YES))
325 fs = 0;
326 if (fs < sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey))
327 {
328 /* maybe we got the read lock before the key generating
329 * process had a chance to get the write lock; give it up! */
330 if (GNUNET_YES !=
331 GNUNET_DISK_file_unlock (fd, 0,
332 sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey)))
333 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename);
334 if (0 == ++cnt % 10)
335 {
336 LOG (GNUNET_ERROR_TYPE_ERROR,
337 _("When trying to read key file `%s' I found %u bytes but I need at least %u.\n"),
338 filename, (unsigned int) fs,
339 (unsigned int) sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey));
340 LOG (GNUNET_ERROR_TYPE_ERROR,
341 _("This may be ok if someone is currently generating a key.\n"));
342 }
343 short_wait (); /* wait a bit longer! */
344 continue;
345 }
346 break;
347 }
348 fs = sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey);
349 priv = GNUNET_malloc (fs);
350 GNUNET_assert (fs == GNUNET_DISK_file_read (fd, priv, fs));
351 if (GNUNET_YES !=
352 GNUNET_DISK_file_unlock (fd, 0,
353 sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey)))
354 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename);
355 GNUNET_assert (GNUNET_YES == GNUNET_DISK_file_close (fd));
356 return priv;
357}
358
359
360/**
361 * Create a new private key by reading our peer's key from
362 * the file specified in the configuration.
363 *
364 * @param cfg the configuration to use
365 * @return new private key, NULL on error (for example,
366 * permission denied)
367 */
368struct GNUNET_CRYPTO_EddsaPrivateKey *
369GNUNET_CRYPTO_eddsa_key_create_from_configuration (const struct GNUNET_CONFIGURATION_Handle *cfg)
370{
371 struct GNUNET_CRYPTO_EddsaPrivateKey *priv;
372 char *fn;
373
374 if (GNUNET_OK !=
375 GNUNET_CONFIGURATION_get_value_filename (cfg, "PEER", "PRIVATE_KEY", &fn))
376 return NULL;
377 priv = GNUNET_CRYPTO_eddsa_key_create_from_file (fn);
378 GNUNET_free (fn);
379 return priv;
380}
381
382
383/**
384 * Retrieve the identity of the host's peer.
385 *
386 * @param cfg configuration to use
387 * @param dst pointer to where to write the peer identity
388 * @return #GNUNET_OK on success, #GNUNET_SYSERR if the identity
389 * could not be retrieved
390 */
391int
392GNUNET_CRYPTO_get_peer_identity (const struct GNUNET_CONFIGURATION_Handle *cfg,
393 struct GNUNET_PeerIdentity *dst)
394{
395 struct GNUNET_CRYPTO_EddsaPrivateKey *priv;
396
397 if (NULL == (priv = GNUNET_CRYPTO_eddsa_key_create_from_configuration (cfg)))
398 {
399 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
400 _("Could not load peer's private key\n"));
401 return GNUNET_SYSERR;
402 }
403 GNUNET_CRYPTO_eddsa_key_get_public (priv, &dst->public_key);
404 GNUNET_free (priv);
405 return GNUNET_OK;
406}
407
408
409/**
410 * Setup a key file for a peer given the name of the
411 * configuration file (!). This function is used so that
412 * at a later point code can be certain that reading a
413 * key is fast (for example in time-dependent testcases).
414 *
415 * @param cfg_name name of the configuration file to use
416 */
417void
418GNUNET_CRYPTO_eddsa_setup_key (const char *cfg_name)
419{
420 struct GNUNET_CONFIGURATION_Handle *cfg;
421 struct GNUNET_CRYPTO_EddsaPrivateKey *priv;
422
423 cfg = GNUNET_CONFIGURATION_create ();
424 (void) GNUNET_CONFIGURATION_load (cfg, cfg_name);
425 priv = GNUNET_CRYPTO_eddsa_key_create_from_configuration (cfg);
426 if (NULL != priv)
427 GNUNET_free (priv);
428 GNUNET_CONFIGURATION_destroy (cfg);
429}
430
431/* end of crypto_ecc_setup.c */
diff --git a/src/util/crypto_hash.c b/src/util/crypto_hash.c
index 64f55e14c..9456e343b 100644
--- a/src/util/crypto_hash.c
+++ b/src/util/crypto_hash.c
@@ -21,7 +21,7 @@
21 21
22/** 22/**
23 * @file util/crypto_hash.c 23 * @file util/crypto_hash.c
24 * @brief SHA-512 GNUNET_CRYPTO_hash related functions 24 * @brief SHA-512 #GNUNET_CRYPTO_hash() related functions
25 * @author Christian Grothoff 25 * @author Christian Grothoff
26 */ 26 */
27 27
@@ -49,193 +49,6 @@ GNUNET_CRYPTO_hash (const void *block,
49} 49}
50 50
51 51
52/**
53 * Context used when hashing a file.
54 */
55struct GNUNET_CRYPTO_FileHashContext
56{
57
58 /**
59 * Function to call upon completion.
60 */
61 GNUNET_CRYPTO_HashCompletedCallback callback;
62
63 /**
64 * Closure for callback.
65 */
66 void *callback_cls;
67
68 /**
69 * IO buffer.
70 */
71 unsigned char *buffer;
72
73 /**
74 * Name of the file we are hashing.
75 */
76 char *filename;
77
78 /**
79 * File descriptor.
80 */
81 struct GNUNET_DISK_FileHandle *fh;
82
83 /**
84 * Cummulated hash.
85 */
86 gcry_md_hd_t md;
87
88 /**
89 * Size of the file.
90 */
91 uint64_t fsize;
92
93 /**
94 * Current offset.
95 */
96 uint64_t offset;
97
98 /**
99 * Current task for hashing.
100 */
101 struct GNUNET_SCHEDULER_Task * task;
102
103 /**
104 * Priority we use.
105 */
106 enum GNUNET_SCHEDULER_Priority priority;
107
108 /**
109 * Blocksize.
110 */
111 size_t bsize;
112
113};
114
115
116/**
117 * Report result of hash computation to callback
118 * and free associated resources.
119 */
120static void
121file_hash_finish (struct GNUNET_CRYPTO_FileHashContext *fhc,
122 const struct GNUNET_HashCode * res)
123{
124 fhc->callback (fhc->callback_cls, res);
125 GNUNET_free (fhc->filename);
126 if (!GNUNET_DISK_handle_invalid (fhc->fh))
127 GNUNET_break (GNUNET_OK == GNUNET_DISK_file_close (fhc->fh));
128 gcry_md_close (fhc->md);
129 GNUNET_free (fhc); /* also frees fhc->buffer */
130}
131
132
133/**
134 * File hashing task.
135 *
136 * @param cls closure
137 * @param tc context
138 */
139static void
140file_hash_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
141{
142 struct GNUNET_CRYPTO_FileHashContext *fhc = cls;
143 struct GNUNET_HashCode *res;
144 size_t delta;
145
146 fhc->task = NULL;
147 GNUNET_assert (fhc->offset <= fhc->fsize);
148 delta = fhc->bsize;
149 if (fhc->fsize - fhc->offset < delta)
150 delta = fhc->fsize - fhc->offset;
151 if (delta != GNUNET_DISK_file_read (fhc->fh, fhc->buffer, delta))
152 {
153 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "read", fhc->filename);
154 file_hash_finish (fhc, NULL);
155 return;
156 }
157 gcry_md_write (fhc->md, fhc->buffer, delta);
158 fhc->offset += delta;
159 if (fhc->offset == fhc->fsize)
160 {
161 res = (struct GNUNET_HashCode *) gcry_md_read (fhc->md, GCRY_MD_SHA512);
162 file_hash_finish (fhc, res);
163 return;
164 }
165 fhc->task = GNUNET_SCHEDULER_add_with_priority (fhc->priority,
166 &file_hash_task, fhc);
167}
168
169
170/**
171 * Compute the hash of an entire file.
172 *
173 * @param priority scheduling priority to use
174 * @param filename name of file to hash
175 * @param blocksize number of bytes to process in one task
176 * @param callback function to call upon completion
177 * @param callback_cls closure for callback
178 * @return NULL on (immediate) errror
179 */
180struct GNUNET_CRYPTO_FileHashContext *
181GNUNET_CRYPTO_hash_file (enum GNUNET_SCHEDULER_Priority priority,
182 const char *filename, size_t blocksize,
183 GNUNET_CRYPTO_HashCompletedCallback callback,
184 void *callback_cls)
185{
186 struct GNUNET_CRYPTO_FileHashContext *fhc;
187
188 GNUNET_assert (blocksize > 0);
189 fhc =
190 GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_FileHashContext) + blocksize);
191 fhc->callback = callback;
192 fhc->callback_cls = callback_cls;
193 fhc->buffer = (unsigned char *) &fhc[1];
194 fhc->filename = GNUNET_strdup (filename);
195 if (GPG_ERR_NO_ERROR != gcry_md_open (&fhc->md, GCRY_MD_SHA512, 0))
196 {
197 GNUNET_break (0);
198 GNUNET_free (fhc);
199 return NULL;
200 }
201 fhc->bsize = blocksize;
202 if (GNUNET_OK != GNUNET_DISK_file_size (filename, &fhc->fsize, GNUNET_NO, GNUNET_YES))
203 {
204 GNUNET_free (fhc->filename);
205 GNUNET_free (fhc);
206 return NULL;
207 }
208 fhc->fh =
209 GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_READ,
210 GNUNET_DISK_PERM_NONE);
211 if (!fhc->fh)
212 {
213 GNUNET_free (fhc->filename);
214 GNUNET_free (fhc);
215 return NULL;
216 }
217 fhc->priority = priority;
218 fhc->task =
219 GNUNET_SCHEDULER_add_with_priority (priority, &file_hash_task, fhc);
220 return fhc;
221}
222
223
224/**
225 * Cancel a file hashing operation.
226 *
227 * @param fhc operation to cancel (callback must not yet have been invoked)
228 */
229void
230GNUNET_CRYPTO_hash_file_cancel (struct GNUNET_CRYPTO_FileHashContext *fhc)
231{
232 GNUNET_SCHEDULER_cancel (fhc->task);
233 GNUNET_free (fhc->filename);
234 GNUNET_break (GNUNET_OK == GNUNET_DISK_file_close (fhc->fh));
235 GNUNET_free (fhc);
236}
237
238
239/* ***************** binary-ASCII encoding *************** */ 52/* ***************** binary-ASCII encoding *************** */
240 53
241 54
diff --git a/src/util/crypto_hash_file.c b/src/util/crypto_hash_file.c
new file mode 100644
index 000000000..2d15fac36
--- /dev/null
+++ b/src/util/crypto_hash_file.c
@@ -0,0 +1,215 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2001-2013 Christian Grothoff (and other contributing authors)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19
20*/
21
22/**
23 * @file util/crypto_hash_file.c
24 * @brief incremental hashing of files
25 * @author Christian Grothoff
26 */
27
28
29/**
30 * Context used when hashing a file.
31 */
32struct GNUNET_CRYPTO_FileHashContext
33{
34
35 /**
36 * Function to call upon completion.
37 */
38 GNUNET_CRYPTO_HashCompletedCallback callback;
39
40 /**
41 * Closure for callback.
42 */
43 void *callback_cls;
44
45 /**
46 * IO buffer.
47 */
48 unsigned char *buffer;
49
50 /**
51 * Name of the file we are hashing.
52 */
53 char *filename;
54
55 /**
56 * File descriptor.
57 */
58 struct GNUNET_DISK_FileHandle *fh;
59
60 /**
61 * Cummulated hash.
62 */
63 gcry_md_hd_t md;
64
65 /**
66 * Size of the file.
67 */
68 uint64_t fsize;
69
70 /**
71 * Current offset.
72 */
73 uint64_t offset;
74
75 /**
76 * Current task for hashing.
77 */
78 struct GNUNET_SCHEDULER_Task * task;
79
80 /**
81 * Priority we use.
82 */
83 enum GNUNET_SCHEDULER_Priority priority;
84
85 /**
86 * Blocksize.
87 */
88 size_t bsize;
89
90};
91
92
93/**
94 * Report result of hash computation to callback
95 * and free associated resources.
96 */
97static void
98file_hash_finish (struct GNUNET_CRYPTO_FileHashContext *fhc,
99 const struct GNUNET_HashCode * res)
100{
101 fhc->callback (fhc->callback_cls, res);
102 GNUNET_free (fhc->filename);
103 if (!GNUNET_DISK_handle_invalid (fhc->fh))
104 GNUNET_break (GNUNET_OK == GNUNET_DISK_file_close (fhc->fh));
105 gcry_md_close (fhc->md);
106 GNUNET_free (fhc); /* also frees fhc->buffer */
107}
108
109
110/**
111 * File hashing task.
112 *
113 * @param cls closure
114 * @param tc context
115 */
116static void
117file_hash_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
118{
119 struct GNUNET_CRYPTO_FileHashContext *fhc = cls;
120 struct GNUNET_HashCode *res;
121 size_t delta;
122
123 fhc->task = NULL;
124 GNUNET_assert (fhc->offset <= fhc->fsize);
125 delta = fhc->bsize;
126 if (fhc->fsize - fhc->offset < delta)
127 delta = fhc->fsize - fhc->offset;
128 if (delta != GNUNET_DISK_file_read (fhc->fh, fhc->buffer, delta))
129 {
130 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "read", fhc->filename);
131 file_hash_finish (fhc, NULL);
132 return;
133 }
134 gcry_md_write (fhc->md, fhc->buffer, delta);
135 fhc->offset += delta;
136 if (fhc->offset == fhc->fsize)
137 {
138 res = (struct GNUNET_HashCode *) gcry_md_read (fhc->md, GCRY_MD_SHA512);
139 file_hash_finish (fhc, res);
140 return;
141 }
142 fhc->task = GNUNET_SCHEDULER_add_with_priority (fhc->priority,
143 &file_hash_task, fhc);
144}
145
146
147/**
148 * Compute the hash of an entire file.
149 *
150 * @param priority scheduling priority to use
151 * @param filename name of file to hash
152 * @param blocksize number of bytes to process in one task
153 * @param callback function to call upon completion
154 * @param callback_cls closure for callback
155 * @return NULL on (immediate) errror
156 */
157struct GNUNET_CRYPTO_FileHashContext *
158GNUNET_CRYPTO_hash_file (enum GNUNET_SCHEDULER_Priority priority,
159 const char *filename, size_t blocksize,
160 GNUNET_CRYPTO_HashCompletedCallback callback,
161 void *callback_cls)
162{
163 struct GNUNET_CRYPTO_FileHashContext *fhc;
164
165 GNUNET_assert (blocksize > 0);
166 fhc =
167 GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_FileHashContext) + blocksize);
168 fhc->callback = callback;
169 fhc->callback_cls = callback_cls;
170 fhc->buffer = (unsigned char *) &fhc[1];
171 fhc->filename = GNUNET_strdup (filename);
172 if (GPG_ERR_NO_ERROR != gcry_md_open (&fhc->md, GCRY_MD_SHA512, 0))
173 {
174 GNUNET_break (0);
175 GNUNET_free (fhc);
176 return NULL;
177 }
178 fhc->bsize = blocksize;
179 if (GNUNET_OK != GNUNET_DISK_file_size (filename, &fhc->fsize, GNUNET_NO, GNUNET_YES))
180 {
181 GNUNET_free (fhc->filename);
182 GNUNET_free (fhc);
183 return NULL;
184 }
185 fhc->fh =
186 GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_READ,
187 GNUNET_DISK_PERM_NONE);
188 if (!fhc->fh)
189 {
190 GNUNET_free (fhc->filename);
191 GNUNET_free (fhc);
192 return NULL;
193 }
194 fhc->priority = priority;
195 fhc->task =
196 GNUNET_SCHEDULER_add_with_priority (priority, &file_hash_task, fhc);
197 return fhc;
198}
199
200
201/**
202 * Cancel a file hashing operation.
203 *
204 * @param fhc operation to cancel (callback must not yet have been invoked)
205 */
206void
207GNUNET_CRYPTO_hash_file_cancel (struct GNUNET_CRYPTO_FileHashContext *fhc)
208{
209 GNUNET_SCHEDULER_cancel (fhc->task);
210 GNUNET_free (fhc->filename);
211 GNUNET_break (GNUNET_OK == GNUNET_DISK_file_close (fhc->fh));
212 GNUNET_free (fhc);
213}
214
215/* end of crypto_hash_file.c */
diff --git a/src/util/disk.c b/src/util/disk.c
index da78a1e1d..81413265e 100644
--- a/src/util/disk.c
+++ b/src/util/disk.c
@@ -1278,145 +1278,6 @@ GNUNET_DISK_directory_scan (const char *dir_name,
1278 1278
1279 1279
1280/** 1280/**
1281 * Opaque handle used for iterating over a directory.
1282 */
1283struct GNUNET_DISK_DirectoryIterator
1284{
1285
1286 /**
1287 * Function to call on directory entries.
1288 */
1289 GNUNET_DISK_DirectoryIteratorCallback callback;
1290
1291 /**
1292 * Closure for callback.
1293 */
1294 void *callback_cls;
1295
1296 /**
1297 * Reference to directory.
1298 */
1299 DIR *directory;
1300
1301 /**
1302 * Directory name.
1303 */
1304 char *dirname;
1305
1306 /**
1307 * Next filename to process.
1308 */
1309 char *next_name;
1310
1311 /**
1312 * Our priority.
1313 */
1314 enum GNUNET_SCHEDULER_Priority priority;
1315
1316};
1317
1318
1319/**
1320 * Task used by the directory iterator.
1321 */
1322static void
1323directory_iterator_task (void *cls,
1324 const struct GNUNET_SCHEDULER_TaskContext *tc)
1325{
1326 struct GNUNET_DISK_DirectoryIterator *iter = cls;
1327 char *name;
1328
1329 name = iter->next_name;
1330 GNUNET_assert (name != NULL);
1331 iter->next_name = NULL;
1332 iter->callback (iter->callback_cls, iter, name, iter->dirname);
1333 GNUNET_free (name);
1334}
1335
1336
1337/**
1338 * This function must be called during the DiskIteratorCallback
1339 * (exactly once) to schedule the task to process the next
1340 * filename in the directory (if there is one).
1341 *
1342 * @param iter opaque handle for the iterator
1343 * @param can set to GNUNET_YES to terminate the iteration early
1344 * @return GNUNET_YES if iteration will continue,
1345 * GNUNET_NO if this was the last entry (and iteration is complete),
1346 * GNUNET_SYSERR if abort was YES
1347 */
1348int
1349GNUNET_DISK_directory_iterator_next (struct GNUNET_DISK_DirectoryIterator *iter,
1350 int can)
1351{
1352 struct dirent *finfo;
1353
1354 GNUNET_assert (iter->next_name == NULL);
1355 if (can == GNUNET_YES)
1356 {
1357 CLOSEDIR (iter->directory);
1358 GNUNET_free (iter->dirname);
1359 GNUNET_free (iter);
1360 return GNUNET_SYSERR;
1361 }
1362 while (NULL != (finfo = READDIR (iter->directory)))
1363 {
1364 if ((0 == strcmp (finfo->d_name, ".")) ||
1365 (0 == strcmp (finfo->d_name, "..")))
1366 continue;
1367 GNUNET_asprintf (&iter->next_name, "%s%s%s", iter->dirname,
1368 DIR_SEPARATOR_STR, finfo->d_name);
1369 break;
1370 }
1371 if (finfo == NULL)
1372 {
1373 GNUNET_DISK_directory_iterator_next (iter, GNUNET_YES);
1374 return GNUNET_NO;
1375 }
1376 GNUNET_SCHEDULER_add_with_priority (iter->priority, &directory_iterator_task,
1377 iter);
1378 return GNUNET_YES;
1379}
1380
1381
1382/**
1383 * Scan a directory for files using the scheduler to run a task for
1384 * each entry. The name of the directory must be expanded first (!).
1385 * If a scheduler does not need to be used, GNUNET_DISK_directory_scan
1386 * may provide a simpler API.
1387 *
1388 * @param prio priority to use
1389 * @param dir_name the name of the directory
1390 * @param callback the method to call for each file
1391 * @param callback_cls closure for callback
1392 * @return GNUNET_YES if directory is not empty and 'callback'
1393 * will be called later, GNUNET_NO otherwise, GNUNET_SYSERR on error.
1394 */
1395int
1396GNUNET_DISK_directory_iterator_start (enum GNUNET_SCHEDULER_Priority prio,
1397 const char *dir_name,
1398 GNUNET_DISK_DirectoryIteratorCallback
1399 callback, void *callback_cls)
1400{
1401 struct GNUNET_DISK_DirectoryIterator *di;
1402
1403 di = GNUNET_new (struct GNUNET_DISK_DirectoryIterator);
1404 di->callback = callback;
1405 di->callback_cls = callback_cls;
1406 di->directory = OPENDIR (dir_name);
1407 if (di->directory == NULL)
1408 {
1409 GNUNET_free (di);
1410 callback (callback_cls, NULL, NULL, NULL);
1411 return GNUNET_SYSERR;
1412 }
1413 di->dirname = GNUNET_strdup (dir_name);
1414 di->priority = prio;
1415 return GNUNET_DISK_directory_iterator_next (di, GNUNET_NO);
1416}
1417
1418
1419/**
1420 * Function that removes the given directory by calling 1281 * Function that removes the given directory by calling
1421 * "GNUNET_DISK_directory_remove". 1282 * "GNUNET_DISK_directory_remove".
1422 * 1283 *
diff --git a/src/util/disk_iterator.c b/src/util/disk_iterator.c
new file mode 100644
index 000000000..118823df6
--- /dev/null
+++ b/src/util/disk_iterator.c
@@ -0,0 +1,166 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2001--2013 Christian Grothoff (and other contributing authors)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20/**
21 * @file util/disk_iterator.c
22 * @brief asynchronous iteration over a directory
23 * @author Christian Grothoff
24 * @author Nils Durner
25 */
26
27
28/**
29 * Opaque handle used for iterating over a directory.
30 */
31struct GNUNET_DISK_DirectoryIterator
32{
33
34 /**
35 * Function to call on directory entries.
36 */
37 GNUNET_DISK_DirectoryIteratorCallback callback;
38
39 /**
40 * Closure for @e callback.
41 */
42 void *callback_cls;
43
44 /**
45 * Reference to directory.
46 */
47 DIR *directory;
48
49 /**
50 * Directory name.
51 */
52 char *dirname;
53
54 /**
55 * Next filename to process.
56 */
57 char *next_name;
58
59 /**
60 * Our priority.
61 */
62 enum GNUNET_SCHEDULER_Priority priority;
63
64};
65
66
67/**
68 * Task used by the directory iterator.
69 */
70static void
71directory_iterator_task (void *cls,
72 const struct GNUNET_SCHEDULER_TaskContext *tc)
73{
74 struct GNUNET_DISK_DirectoryIterator *iter = cls;
75 char *name;
76
77 name = iter->next_name;
78 GNUNET_assert (name != NULL);
79 iter->next_name = NULL;
80 iter->callback (iter->callback_cls, iter, name, iter->dirname);
81 GNUNET_free (name);
82}
83
84
85/**
86 * This function must be called during the DiskIteratorCallback
87 * (exactly once) to schedule the task to process the next
88 * filename in the directory (if there is one).
89 *
90 * @param iter opaque handle for the iterator
91 * @param can set to #GNUNET_YES to terminate the iteration early
92 * @return #GNUNET_YES if iteration will continue,
93 * #GNUNET_NO if this was the last entry (and iteration is complete),
94 * #GNUNET_SYSERR if abort was YES
95 */
96int
97GNUNET_DISK_directory_iterator_next (struct GNUNET_DISK_DirectoryIterator *iter,
98 int can)
99{
100 struct dirent *finfo;
101
102 GNUNET_assert (iter->next_name == NULL);
103 if (can == GNUNET_YES)
104 {
105 CLOSEDIR (iter->directory);
106 GNUNET_free (iter->dirname);
107 GNUNET_free (iter);
108 return GNUNET_SYSERR;
109 }
110 while (NULL != (finfo = READDIR (iter->directory)))
111 {
112 if ((0 == strcmp (finfo->d_name, ".")) ||
113 (0 == strcmp (finfo->d_name, "..")))
114 continue;
115 GNUNET_asprintf (&iter->next_name, "%s%s%s", iter->dirname,
116 DIR_SEPARATOR_STR, finfo->d_name);
117 break;
118 }
119 if (finfo == NULL)
120 {
121 GNUNET_DISK_directory_iterator_next (iter, GNUNET_YES);
122 return GNUNET_NO;
123 }
124 GNUNET_SCHEDULER_add_with_priority (iter->priority, &directory_iterator_task,
125 iter);
126 return GNUNET_YES;
127}
128
129
130/**
131 * Scan a directory for files using the scheduler to run a task for
132 * each entry. The name of the directory must be expanded first (!).
133 * If a scheduler does not need to be used, GNUNET_DISK_directory_scan
134 * may provide a simpler API.
135 *
136 * @param prio priority to use
137 * @param dir_name the name of the directory
138 * @param callback the method to call for each file
139 * @param callback_cls closure for @a callback
140 * @return #GNUNET_YES if directory is not empty and @a callback
141 * will be called later, #GNUNET_NO otherwise, #GNUNET_SYSERR on error.
142 */
143int
144GNUNET_DISK_directory_iterator_start (enum GNUNET_SCHEDULER_Priority prio,
145 const char *dir_name,
146 GNUNET_DISK_DirectoryIteratorCallback
147 callback, void *callback_cls)
148{
149 struct GNUNET_DISK_DirectoryIterator *di;
150
151 di = GNUNET_new (struct GNUNET_DISK_DirectoryIterator);
152 di->callback = callback;
153 di->callback_cls = callback_cls;
154 di->directory = OPENDIR (dir_name);
155 if (di->directory == NULL)
156 {
157 GNUNET_free (di);
158 callback (callback_cls, NULL, NULL, NULL);
159 return GNUNET_SYSERR;
160 }
161 di->dirname = GNUNET_strdup (dir_name);
162 di->priority = prio;
163 return GNUNET_DISK_directory_iterator_next (di, GNUNET_NO);
164}
165
166/* end of disk_iterator */