diff options
author | Christian Grothoff <christian@grothoff.org> | 2015-05-28 09:02:31 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2015-05-28 09:02:31 +0000 |
commit | 078f7063aef1d4105e71160b8764ab95c2dcdfbe (patch) | |
tree | 86d498356ceaaa1ba738f64a158cce2cd0163a15 /src/util | |
parent | 9469cd334f29ca9437e13eb951b53b7690f10be9 (diff) | |
download | gnunet-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.am | 65 | ||||
-rw-r--r-- | src/util/configuration.c | 43 | ||||
-rw-r--r-- | src/util/configuration_loader.c | 69 | ||||
-rw-r--r-- | src/util/crypto_ecc.c | 401 | ||||
-rw-r--r-- | src/util/crypto_ecc_setup.c | 431 | ||||
-rw-r--r-- | src/util/crypto_hash.c | 189 | ||||
-rw-r--r-- | src/util/crypto_hash_file.c | 215 | ||||
-rw-r--r-- | src/util/disk.c | 139 | ||||
-rw-r--r-- | src/util/disk_iterator.c | 166 |
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 = \ | |||
46 | gnunet_helper_w32_console_LDADD = \ | 46 | gnunet_helper_w32_console_LDADD = \ |
47 | libgnunetutil.la | 47 | libgnunetutil.la |
48 | 48 | ||
49 | noinst_PROGRAMS = \ | ||
50 | gnunet-config-diff \ | ||
51 | $(W32CAT) \ | ||
52 | test_common_logging_dummy | ||
53 | |||
54 | |||
55 | gnunet_config_diff_SOURCES = \ | 49 | gnunet_config_diff_SOURCES = \ |
56 | gnunet-config-diff.c | 50 | gnunet-config-diff.c |
57 | gnunet_config_diff_LDADD = \ | 51 | gnunet_config_diff_LDADD = \ |
@@ -62,8 +56,6 @@ test_common_logging_dummy_SOURCES = \ | |||
62 | test_common_logging_dummy_LDADD = \ | 56 | test_common_logging_dummy_LDADD = \ |
63 | libgnunetutil.la | 57 | libgnunetutil.la |
64 | 58 | ||
65 | lib_LTLIBRARIES = libgnunetutil.la | ||
66 | |||
67 | libgnunetutil_la_SOURCES = \ | 59 | libgnunetutil_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 | |||
127 | libgnunetutil_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 | |||
149 | libgnunetutil_taler_wallet_la_LIBADD = \ | ||
150 | $(LIBGCRYPT_LIBS) \ | ||
151 | -lunistring | ||
152 | |||
153 | libgnunetutil_taler_wallet_la_LDFLAGS = \ | ||
154 | $(GN_LIB_LDFLAGS) \ | ||
155 | -version-info 0:0:0 | ||
156 | |||
130 | if HAVE_TESTING | 157 | if HAVE_TESTING |
131 | GNUNET_ECC = gnunet-ecc | 158 | GNUNET_ECC = gnunet-ecc |
132 | GNUNET_SCRYPT = gnunet-scrypt | 159 | GNUNET_SCRYPT = gnunet-scrypt |
133 | endif | 160 | endif |
134 | 161 | ||
162 | if TALER_ONLY | ||
163 | lib_LTLIBRARIES = libgnunetutil_taler_wallet.la | ||
164 | else | ||
165 | lib_LTLIBRARIES = libgnunetutil.la | ||
135 | 166 | ||
136 | libexec_PROGRAMS = \ | 167 | libexec_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 | ||
181 | noinst_PROGRAMS = \ | ||
182 | gnunet-config-diff \ | ||
183 | $(W32CAT) \ | ||
184 | test_common_logging_dummy | ||
185 | |||
186 | |||
187 | if ENABLE_TEST_RUN | ||
188 | AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH; | ||
189 | TESTS = $(check_PROGRAMS) | ||
190 | endif | ||
191 | |||
192 | endif | ||
193 | |||
194 | |||
150 | do_subst = $(SED) -e 's,[@]PYTHON[@],$(PYTHON),g' | 195 | do_subst = $(SED) -e 's,[@]PYTHON[@],$(PYTHON),g' |
151 | 196 | ||
152 | gnunet-qr: gnunet-qr.py.in Makefile | 197 | gnunet-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 | ||
269 | if ENABLE_TEST_RUN | ||
270 | AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH; | ||
271 | TESTS = $(check_PROGRAMS) | ||
272 | endif | ||
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 | */ | ||
1705 | int | ||
1706 | GNUNET_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 | */ | ||
35 | int | ||
36 | GNUNET_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 | */ | ||
667 | static void | ||
668 | short_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 | */ | ||
691 | struct GNUNET_CRYPTO_EddsaPrivateKey * | ||
692 | GNUNET_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 | */ | ||
847 | struct GNUNET_CRYPTO_EcdsaPrivateKey * | ||
848 | GNUNET_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 | */ | ||
997 | struct GNUNET_CRYPTO_EddsaPrivateKey * | ||
998 | GNUNET_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 | */ | ||
1020 | void | ||
1021 | GNUNET_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 | */ | ||
1043 | int | ||
1044 | GNUNET_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 | */ | ||
38 | static void | ||
39 | short_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 | */ | ||
62 | struct GNUNET_CRYPTO_EddsaPrivateKey * | ||
63 | GNUNET_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 | */ | ||
218 | struct GNUNET_CRYPTO_EcdsaPrivateKey * | ||
219 | GNUNET_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 | */ | ||
368 | struct GNUNET_CRYPTO_EddsaPrivateKey * | ||
369 | GNUNET_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 | */ | ||
391 | int | ||
392 | GNUNET_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 | */ | ||
417 | void | ||
418 | GNUNET_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 | */ | ||
55 | struct 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 | */ | ||
120 | static void | ||
121 | file_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 | */ | ||
139 | static void | ||
140 | file_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 | */ | ||
180 | struct GNUNET_CRYPTO_FileHashContext * | ||
181 | GNUNET_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 | */ | ||
229 | void | ||
230 | GNUNET_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 | */ | ||
32 | struct 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 | */ | ||
97 | static void | ||
98 | file_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 | */ | ||
116 | static void | ||
117 | file_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 | */ | ||
157 | struct GNUNET_CRYPTO_FileHashContext * | ||
158 | GNUNET_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 | */ | ||
206 | void | ||
207 | GNUNET_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 | */ | ||
1283 | struct 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 | */ | ||
1322 | static void | ||
1323 | directory_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 | */ | ||
1348 | int | ||
1349 | GNUNET_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 | */ | ||
1395 | int | ||
1396 | GNUNET_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 | */ | ||
31 | struct 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 | */ | ||
70 | static void | ||
71 | directory_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 | */ | ||
96 | int | ||
97 | GNUNET_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 | */ | ||
143 | int | ||
144 | GNUNET_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 */ | ||