LCOV - code coverage report
Current view: top level - test - test_storagedir.c (source / functions) Hit Total Coverage
Test: lcov.info Lines: 252 252 100.0 %
Date: 2021-11-24 03:28:48 Functions: 7 7 100.0 %

          Line data    Source code
       1             : /* Copyright (c) 2017-2021, The Tor Project, Inc. */
       2             : /* See LICENSE for licensing information */
       3             : 
       4             : #include "core/or/or.h"
       5             : #include "lib/crypt_ops/crypto_rand.h"
       6             : #include "lib/fs/storagedir.h"
       7             : #include "lib/encoding/confline.h"
       8             : #include "test/test.h"
       9             : 
      10             : #ifdef HAVE_UTIME_H
      11             : #include <utime.h>
      12             : #endif
      13             : 
      14             : static void
      15           1 : test_storagedir_empty(void *arg)
      16             : {
      17           1 :   char *dirname = tor_strdup(get_fname_rnd("store_dir"));
      18           1 :   storage_dir_t *d = NULL;
      19           1 :   (void)arg;
      20             : 
      21           1 :   tt_int_op(FN_NOENT, OP_EQ, file_status(dirname));
      22             : 
      23           1 :   d = storage_dir_new(dirname, 10);
      24           1 :   tt_assert(d);
      25             : 
      26           1 :   tt_int_op(FN_DIR, OP_EQ, file_status(dirname));
      27             : 
      28           1 :   tt_int_op(0, OP_EQ, smartlist_len(storage_dir_list(d)));
      29           1 :   tt_u64_op(0, OP_EQ, storage_dir_get_usage(d));
      30             : 
      31           1 :   storage_dir_free(d);
      32           1 :   d = storage_dir_new(dirname, 10);
      33           1 :   tt_assert(d);
      34             : 
      35           1 :   tt_int_op(FN_DIR, OP_EQ, file_status(dirname));
      36             : 
      37           1 :   tt_int_op(0, OP_EQ, smartlist_len(storage_dir_list(d)));
      38           1 :   tt_u64_op(0, OP_EQ, storage_dir_get_usage(d));
      39             : 
      40           1 :  done:
      41           1 :   storage_dir_free(d);
      42           1 :   tor_free(dirname);
      43           1 : }
      44             : 
      45             : static void
      46           1 : test_storagedir_basic(void *arg)
      47             : {
      48           1 :   char *dirname = tor_strdup(get_fname_rnd("store_dir"));
      49           1 :   storage_dir_t *d = NULL;
      50           1 :   uint8_t *junk = NULL, *bytes = NULL;
      51           1 :   const size_t junklen = 1024;
      52           1 :   char *fname1 = NULL, *fname2 = NULL;
      53           1 :   const char hello_str[] = "then what are we but cold, alone ... ?";
      54           1 :   tor_mmap_t *mapping = NULL;
      55           1 :   (void)arg;
      56             : 
      57           1 :   junk = tor_malloc(junklen);
      58           1 :   crypto_rand((void*)junk, junklen);
      59             : 
      60           1 :   d = storage_dir_new(dirname, 10);
      61           1 :   tt_assert(d);
      62           1 :   tt_u64_op(0, OP_EQ, storage_dir_get_usage(d));
      63             : 
      64           1 :   int r;
      65           1 :   r = storage_dir_save_string_to_file(d, hello_str, 1, &fname1);
      66           1 :   tt_int_op(r, OP_EQ, 0);
      67           1 :   tt_ptr_op(fname1, OP_NE, NULL);
      68           1 :   tt_u64_op(strlen(hello_str), OP_EQ, storage_dir_get_usage(d));
      69             : 
      70           1 :   r = storage_dir_save_bytes_to_file(d, junk, junklen, 1, &fname2);
      71           1 :   tt_int_op(r, OP_EQ, 0);
      72           1 :   tt_ptr_op(fname2, OP_NE, NULL);
      73             : 
      74           1 :   tt_str_op(fname1, OP_NE, fname2);
      75             : 
      76           1 :   tt_int_op(2, OP_EQ, smartlist_len(storage_dir_list(d)));
      77           1 :   tt_u64_op(junklen + strlen(hello_str), OP_EQ, storage_dir_get_usage(d));
      78           1 :   tt_assert(smartlist_contains_string(storage_dir_list(d), fname1));
      79           1 :   tt_assert(smartlist_contains_string(storage_dir_list(d), fname2));
      80             : 
      81           1 :   storage_dir_free(d);
      82           1 :   d = storage_dir_new(dirname, 10);
      83           1 :   tt_assert(d);
      84           1 :   tt_int_op(2, OP_EQ, smartlist_len(storage_dir_list(d)));
      85           1 :   tt_u64_op(junklen + strlen(hello_str), OP_EQ, storage_dir_get_usage(d));
      86           1 :   tt_assert(smartlist_contains_string(storage_dir_list(d), fname1));
      87           1 :   tt_assert(smartlist_contains_string(storage_dir_list(d), fname2));
      88             : 
      89           1 :   size_t n;
      90           1 :   bytes = storage_dir_read(d, fname2, 1, &n);
      91           1 :   tt_assert(bytes);
      92           1 :   tt_u64_op(n, OP_EQ, junklen);
      93           1 :   tt_mem_op(bytes, OP_EQ, junk, junklen);
      94             : 
      95           1 :   mapping = storage_dir_map(d, fname1);
      96           1 :   tt_assert(mapping);
      97           1 :   tt_u64_op(mapping->size, OP_EQ, strlen(hello_str));
      98           1 :   tt_mem_op(mapping->data, OP_EQ, hello_str, strlen(hello_str));
      99             : 
     100           1 :  done:
     101           1 :   tor_free(dirname);
     102           1 :   tor_free(junk);
     103           1 :   tor_free(bytes);
     104           1 :   tor_munmap_file(mapping);
     105           1 :   storage_dir_free(d);
     106           1 :   tor_free(fname1);
     107           1 :   tor_free(fname2);
     108           1 : }
     109             : 
     110             : static void
     111           1 : test_storagedir_deletion(void *arg)
     112             : {
     113           1 :   (void)arg;
     114           1 :   char *dirname = tor_strdup(get_fname_rnd("store_dir"));
     115           1 :   storage_dir_t *d = NULL;
     116           1 :   char *fn1 = NULL, *fn2 = NULL;
     117           1 :   char *bytes = NULL;
     118           1 :   int r;
     119           1 :   const char str1[] = "There are nine and sixty ways to disguise communiques";
     120           1 :   const char str2[] = "And rather more than one of them is right";
     121             : 
     122             :   // Make sure the directory is there. */
     123           1 :   d = storage_dir_new(dirname, 10);
     124           1 :   storage_dir_free(d);
     125           1 :   d = NULL;
     126             : 
     127           1 :   tor_asprintf(&fn1, "%s/1007", dirname);
     128           1 :   r = write_str_to_file(fn1, str1, 0);
     129           1 :   tt_int_op(r, OP_EQ, 0);
     130             : 
     131           1 :   tor_asprintf(&fn2, "%s/1003.tmp", dirname);
     132           1 :   r = write_str_to_file(fn2, str2, 0);
     133           1 :   tt_int_op(r, OP_EQ, 0);
     134             : 
     135             :   // The tempfile should be deleted the next time we list the directory.
     136           1 :   d = storage_dir_new(dirname, 10);
     137           1 :   tt_int_op(1, OP_EQ, smartlist_len(storage_dir_list(d)));
     138           1 :   tt_u64_op(strlen(str1), OP_EQ, storage_dir_get_usage(d));
     139           1 :   tt_int_op(FN_FILE, OP_EQ, file_status(fn1));
     140           1 :   tt_int_op(FN_NOENT, OP_EQ, file_status(fn2));
     141             : 
     142           1 :   bytes = (char*) storage_dir_read(d, "1007", 1, NULL);
     143           1 :   tt_str_op(bytes, OP_EQ, str1);
     144             : 
     145             :   // Should have no effect; file already gone.
     146           1 :   storage_dir_remove_file(d, "1003.tmp");
     147           1 :   tt_int_op(1, OP_EQ, smartlist_len(storage_dir_list(d)));
     148           1 :   tt_u64_op(strlen(str1), OP_EQ, storage_dir_get_usage(d));
     149             : 
     150             :   // Actually remove a file.
     151           1 :   storage_dir_remove_file(d, "1007");
     152           1 :   tt_int_op(FN_NOENT, OP_EQ, file_status(fn1));
     153           1 :   tt_int_op(0, OP_EQ, smartlist_len(storage_dir_list(d)));
     154           1 :   tt_u64_op(0, OP_EQ, storage_dir_get_usage(d));
     155             : 
     156           1 :  done:
     157           1 :   tor_free(dirname);
     158           1 :   tor_free(fn1);
     159           1 :   tor_free(fn2);
     160           1 :   storage_dir_free(d);
     161           1 :   tor_free(bytes);
     162           1 : }
     163             : 
     164             : static void
     165           1 : test_storagedir_full(void *arg)
     166             : {
     167           1 :   (void)arg;
     168             : 
     169           1 :   char *dirname = tor_strdup(get_fname_rnd("store_dir"));
     170           1 :   storage_dir_t *d = NULL;
     171           1 :   const char str[] = "enemies of the peephole";
     172           1 :   int r;
     173             : 
     174           1 :   d = storage_dir_new(dirname, 3);
     175           1 :   tt_assert(d);
     176             : 
     177           1 :   r = storage_dir_save_string_to_file(d, str, 1, NULL);
     178           1 :   tt_int_op(r, OP_EQ, 0);
     179           1 :   r = storage_dir_save_string_to_file(d, str, 1, NULL);
     180           1 :   tt_int_op(r, OP_EQ, 0);
     181           1 :   r = storage_dir_save_string_to_file(d, str, 1, NULL);
     182           1 :   tt_int_op(r, OP_EQ, 0);
     183             : 
     184             :   // These should fail!
     185           1 :   r = storage_dir_save_string_to_file(d, str, 1, NULL);
     186           1 :   tt_int_op(r, OP_EQ, -1);
     187           1 :   r = storage_dir_save_string_to_file(d, str, 1, NULL);
     188           1 :   tt_int_op(r, OP_EQ, -1);
     189             : 
     190           1 :   tt_u64_op(strlen(str) * 3, OP_EQ, storage_dir_get_usage(d));
     191             : 
     192           1 :  done:
     193           1 :   tor_free(dirname);
     194           1 :   storage_dir_free(d);
     195           1 : }
     196             : 
     197             : static void
     198           1 : test_storagedir_cleaning(void *arg)
     199             : {
     200           1 :   (void)arg;
     201             : 
     202           1 :   char *dirname = tor_strdup(get_fname_rnd("store_dir"));
     203           1 :   storage_dir_t *d = NULL;
     204           1 :   const char str[] =
     205             :     "On a mountain halfway between Reno and Rome / "
     206             :     "We have a machine in a plexiglass dome / "
     207             :     "Which listens and looks into everyone's home."
     208             :     " -- Dr. Seuss";
     209           1 :   char *fns[8];
     210           1 :   int r, i;
     211             : 
     212           1 :   memset(fns, 0, sizeof(fns));
     213           1 :   d = storage_dir_new(dirname, 10);
     214           1 :   tt_assert(d);
     215             : 
     216           9 :   for (i = 0; i < 8; ++i) {
     217           8 :     r = storage_dir_save_string_to_file(d, str+i*2, 1, &fns[i]);
     218           8 :     tt_int_op(r, OP_EQ, 0);
     219             :   }
     220             : 
     221             :   /* Now we're going to make sure all the files have distinct mtimes. */
     222           1 :   time_t now = time(NULL);
     223           1 :   struct utimbuf ub;
     224           1 :   ub.actime = now;
     225           1 :   ub.modtime = now - 1000;
     226           9 :   for (i = 0; i < 8; ++i) {
     227           8 :     char *f = NULL;
     228           8 :     tor_asprintf(&f, "%s/%s", dirname, fns[i]);
     229           8 :     r = utime(f, &ub);
     230           8 :     tor_free(f);
     231           8 :     tt_int_op(r, OP_EQ, 0);
     232           8 :     ub.modtime += 5;
     233             :   }
     234             : 
     235           1 :   const uint64_t usage_orig = storage_dir_get_usage(d);
     236             :   /* No changes needed if we are already under target. */
     237           1 :   storage_dir_shrink(d, 1024*1024, 0);
     238           1 :   tt_u64_op(usage_orig, OP_EQ, storage_dir_get_usage(d));
     239             : 
     240             :   /* Get rid of at least one byte.  This will delete fns[0]. */
     241           1 :   storage_dir_shrink(d, usage_orig - 1, 0);
     242           1 :   tt_u64_op(usage_orig, OP_GT, storage_dir_get_usage(d));
     243           1 :   tt_u64_op(usage_orig - strlen(str), OP_EQ, storage_dir_get_usage(d));
     244             : 
     245             :   /* Get rid of at least two files.  This will delete fns[1] and fns[2]. */
     246           1 :   storage_dir_shrink(d, 1024*1024, 2);
     247           1 :   tt_u64_op(usage_orig - strlen(str)*3 + 6, OP_EQ, storage_dir_get_usage(d));
     248             : 
     249             :   /* Get rid of everything. */
     250           1 :   storage_dir_remove_all(d);
     251           1 :   tt_u64_op(0, OP_EQ, storage_dir_get_usage(d));
     252             : 
     253           1 :  done:
     254           1 :   tor_free(dirname);
     255           1 :   storage_dir_free(d);
     256          10 :   for (i = 0; i < 8; ++i) {
     257           8 :     tor_free(fns[i]);
     258             :   }
     259           1 : }
     260             : 
     261             : static void
     262           1 : test_storagedir_save_labeled(void *arg)
     263             : {
     264           1 :   (void)arg;
     265           1 :   char *dirname = tor_strdup(get_fname_rnd("store_dir"));
     266           1 :   storage_dir_t *d = NULL;
     267           1 :   uint8_t *inp = tor_malloc_zero(8192);
     268           1 :   config_line_t *labels = NULL;
     269           1 :   char *fname = NULL;
     270           1 :   uint8_t *saved = NULL;
     271             : 
     272           1 :   d = storage_dir_new(dirname, 10);
     273           1 :   tt_assert(d);
     274             : 
     275           1 :   crypto_rand((char *)inp, 8192);
     276             : 
     277           1 :   config_line_append(&labels, "Foo", "bar baz");
     278           1 :   config_line_append(&labels, "quux", "quuzXxz");
     279           1 :   const char expected[] =
     280             :     "Foo bar baz\n"
     281             :     "quux quuzXxz\n";
     282             : 
     283           1 :   int r = storage_dir_save_labeled_to_file(d, labels, inp, 8192, &fname);
     284           1 :   tt_int_op(r, OP_EQ, 0);
     285             : 
     286           1 :   size_t n = 0;
     287           1 :   saved = storage_dir_read(d, fname, 1, &n);
     288           1 :   tt_assert(memchr(saved, '\0', n));
     289           1 :   tt_str_op((char*)saved, OP_EQ, expected); /* NUL guarantees strcmp works */
     290           1 :   tt_mem_op(saved+strlen(expected)+1, OP_EQ, inp, 8192);
     291             : 
     292           1 :  done:
     293           1 :   storage_dir_free(d);
     294           1 :   tor_free(dirname);
     295           1 :   tor_free(inp);
     296           1 :   tor_free(fname);
     297           1 :   config_free_lines(labels);
     298           1 :   tor_free(saved);
     299           1 : }
     300             : 
     301             : static void
     302           1 : test_storagedir_read_labeled(void *arg)
     303             : {
     304           1 :   (void)arg;
     305           1 :   char *dirname = tor_strdup(get_fname_rnd("store_dir"));
     306           1 :   storage_dir_t *d = NULL;
     307           1 :   uint8_t *inp = tor_malloc_zero(8192);
     308           1 :   config_line_t *labels = NULL, *labels2 = NULL;
     309           1 :   char *fname = NULL;
     310           1 :   tor_mmap_t *map = NULL;
     311           1 :   uint8_t *as_read = NULL;
     312             : 
     313           1 :   d = storage_dir_new(dirname, 10);
     314           1 :   tt_assert(d);
     315             : 
     316           1 :   tor_snprintf((char*)inp, 8192,
     317             :                "Hello world\n"
     318             :                "This is a test\n"
     319             :                "Yadda yadda.\n");
     320           1 :   size_t bodylen = 8192 - strlen((char*)inp) - 1;
     321           1 :   crypto_rand((char *)inp+strlen((char*)inp)+1, bodylen);
     322             : 
     323           1 :   int r = storage_dir_save_bytes_to_file(d, inp, 8192, 1, &fname);
     324           1 :   tt_int_op(r, OP_EQ, 0);
     325             : 
     326             :   /* Try mapping */
     327           1 :   const uint8_t *datap = NULL;
     328           1 :   size_t sz = 0;
     329           1 :   map = storage_dir_map_labeled(d, fname, &labels, &datap, &sz);
     330           1 :   tt_assert(map);
     331           1 :   tt_assert(datap);
     332           1 :   tt_u64_op(sz, OP_EQ, bodylen);
     333           1 :   tt_mem_op(datap, OP_EQ, inp+strlen((char*)inp)+1, bodylen);
     334           1 :   tt_assert(labels);
     335           1 :   tt_str_op(labels->key, OP_EQ, "Hello");
     336           1 :   tt_str_op(labels->value, OP_EQ, "world");
     337           1 :   tt_assert(labels->next);
     338           1 :   tt_str_op(labels->next->key, OP_EQ, "This");
     339           1 :   tt_str_op(labels->next->value, OP_EQ, "is a test");
     340           1 :   tt_assert(labels->next->next);
     341           1 :   tt_str_op(labels->next->next->key, OP_EQ, "Yadda");
     342           1 :   tt_str_op(labels->next->next->value, OP_EQ, "yadda.");
     343           1 :   tt_ptr_op(labels->next->next->next, OP_EQ, NULL);
     344             : 
     345             :   /* Try reading this time. */
     346           1 :   sz = 0;
     347           1 :   as_read = storage_dir_read_labeled(d, fname, &labels2, &sz);
     348           1 :   tt_assert(as_read);
     349           1 :   tt_u64_op(sz, OP_EQ, bodylen);
     350           1 :   tt_mem_op(as_read, OP_EQ, inp+strlen((char*)inp)+1, bodylen);
     351           1 :   tt_assert(config_lines_eq(labels, labels2));
     352             : 
     353           1 :  done:
     354           1 :   storage_dir_free(d);
     355           1 :   tor_free(dirname);
     356           1 :   tor_free(inp);
     357           1 :   tor_free(fname);
     358           1 :   config_free_lines(labels);
     359           1 :   config_free_lines(labels2);
     360           1 :   tor_munmap_file(map);
     361           1 :   tor_free(as_read);
     362           1 : }
     363             : 
     364             : #define ENT(name)                                               \
     365             :   { #name, test_storagedir_ ## name, TT_FORK, NULL, NULL }
     366             : 
     367             : struct testcase_t storagedir_tests[] = {
     368             :   ENT(empty),
     369             :   ENT(basic),
     370             :   ENT(deletion),
     371             :   ENT(full),
     372             :   ENT(cleaning),
     373             :   ENT(save_labeled),
     374             :   ENT(read_labeled),
     375             :   END_OF_TESTCASES
     376             : };

Generated by: LCOV version 1.14