lessfs  1.7.0
About: Lessfs is a inline data deduplicating file system for Linux (implemented in user space with FUSE; especially useful for backup purposes).
  Fossies Dox: lessfs-1.7.0.tar.gz  ("inofficial" and yet experimental doxygen-generated source code documentation)  

lib_common.c
Go to the documentation of this file.
1 /*
2  * Lessfs: A data deduplicating filesystem.
3  * Copyright (C) 2008 Mark Ruijter <mruijter@lessfs.com>
4  *
5  * This program is s_free software.
6  * You can redistribute lessfs and/or modify it under the terms of either
7  * (1) the GNU General Public License; either version 3 of the License,
8  * or (at your option) any later version as published by
9  * the Free Software Foundation; or (2) obtain a commercial license
10  * by contacting the Author.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
15  * the GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20  */
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24 #ifndef LFATAL
25 #include "lib_log.h"
26 #endif
27 
28 #include <fuse.h>
29 #include <stdio.h>
30 #include <string.h>
31 #include <unistd.h>
32 #include <fcntl.h>
33 #include <dirent.h>
34 #include <errno.h>
35 #include <malloc.h>
36 #include <sys/time.h>
37 #include <sys/stat.h>
38 #include <sys/types.h>
39 #include <sys/socket.h>
40 #include <sys/file.h>
41 #include <sys/un.h>
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <pthread.h>
45 #include <signal.h>
46 #include <stdarg.h>
47 #include <libgen.h>
48 #include <sys/utsname.h>
49 #include <sys/vfs.h>
50 #include <sys/time.h>
51 #include <sys/resource.h>
52 #include <sys/types.h>
53 #include <sys/wait.h>
54 #include <mhash.h>
55 #include <tcutil.h>
56 #include <tchdb.h>
57 #include <tcbdb.h>
58 #include <stdlib.h>
59 #include <stdbool.h>
60 #include "lib_cfg.h"
61 #include "lib_safe.h"
62 #include "lib_common.h"
63 #ifdef LZO
64 #include "lib_lzo.h"
65 #endif
66 #ifdef SNAPPY
67 #include "lib_snappy.h"
68 #endif
69 #include "lib_qlz.h"
70 #include "lib_qlz15.h"
71 #ifdef BERKELEYDB
72 #include <db.h>
73 #include "lib_bdb.h"
74 #else
75 #ifndef HAMSTERDB
76 #include "lib_tc.h"
77 #else
78 #include "lib_hamster.h"
79 #endif
80 #endif
81 #include "lib_net.h"
82 #include "file_io.h"
83 #include "lib_repl.h"
84 #include "retcodes.h"
85 #ifdef ENABLE_CRYPTO
86 #include "lib_crypto.h"
87 #endif
88 
89 extern struct configdata *config;
90 unsigned long long nextoffset;
91 extern int fdbdta;
92 extern int frepl;
93 extern int freplbl; /* Backlog processing */
94 extern int BLKSIZE;
95 extern long working;
96 
97 #ifndef HAMSTERDB
98 TCHDB *dbb = NULL;
99 TCHDB *dbu = NULL;
100 TCHDB *dbp = NULL;
101 TCBDB *dbl = NULL; // Hardlink
102 TCHDB *dbs = NULL; // Symlink
103 TCHDB *dbdta = NULL;
104 TCBDB *dbdirent = NULL;
105 TCBDB *freelist = NULL; // Free list for file_io
106 #endif
107 
108 TCTREE *workqtree; // Used to buffer incoming data (writes)
109 TCTREE *readcachetree; // Used to cache chunks of data that are likely to be read
110 TCTREE *path2inotree; // Used to cache path to inode translations
111 TCTREE *hashtree; // Used to lock hashes
112 TCTREE *inodetree; // Used to lock inodes
113 TCTREE *metatree; // Used to cache metadata of open files (e.g. inode -> struct stat).
114 
115 static pthread_mutex_t global_lock_mutex = PTHREAD_MUTEX_INITIALIZER;
116 const char *global_lockedby;
117 static pthread_mutex_t write_mutex = PTHREAD_MUTEX_INITIALIZER;
118 const char *write_lockedby;
119 static pthread_mutex_t hash_mutex = PTHREAD_MUTEX_INITIALIZER;
120 const char *hash_lockedby;
121 static pthread_mutex_t inode_mutex = PTHREAD_MUTEX_INITIALIZER;
122 const char *inode_lockedby;
123 static pthread_mutex_t offset_mutex = PTHREAD_MUTEX_INITIALIZER;
124 const char *offset_lockedby;
125 static pthread_mutex_t worker_mutex = PTHREAD_MUTEX_INITIALIZER;
126 const char *worker_lockedby;
127 static pthread_mutex_t meta_mutex = PTHREAD_MUTEX_INITIALIZER;
128 const char *meta_lockedby;
129 static pthread_mutex_t repl_mutex = PTHREAD_MUTEX_INITIALIZER;
130 const char *repl_lockedby;
131 static pthread_mutex_t replbl_mutex = PTHREAD_MUTEX_INITIALIZER;
132 const char *replbl_lockedby;
133 static pthread_mutex_t relax_mutex = PTHREAD_MUTEX_INITIALIZER;
134 const char *cachep2i_lockedby;
135 static pthread_mutex_t cachep2i_mutex = PTHREAD_MUTEX_INITIALIZER;
136 
138 {
139  char *high;
140  char *medium;
141  char *low;
142  struct stat stbuf;
143 
144  if ( -1 == stat(config->blockdata,&stbuf)) die_dataerr("init_chunk_io : path %s does not exist",config->blockdata);
145  if (!S_ISDIR(stbuf.st_mode)) die_dataerr("init_chunk_io : path %s is not a directory",config->blockdata);
146  high=as_sprintf(__FILE__, __LINE__,"%s/high",config->blockdata);
147  medium=as_sprintf(__FILE__, __LINE__,"%s/medium",config->blockdata);
148  low=as_sprintf(__FILE__, __LINE__,"%s/low",config->blockdata);
149  //mkchunk_dir(high);
150  mkchunk_dir(medium);
151  //mkchunk_dir(low);
152  s_free(low);
153  s_free(medium);
154  s_free(high);
155 }
156 
157 void mkchunk_dir(char *path)
158 {
159  int n,e,f,g,h;
160  char *a="0123456789ABCDEF";
161  char p[2];
162  char q[2];
163  char r[2];
164  char s[2];
165  char t[2];
166 
167  p[1]=0;
168  q[1]=0;
169  r[1]=0;
170  s[1]=0;
171  t[1]=0;
172 
173  if ( -1 == chdir(config->blockdata)) die_syserr();
174  mkdir(path,0755);
175  if ( -1 == chdir(path)) die_syserr();
176 
177  for (n =0; n<16 ; n++)
178  {
179  p[0]=a[n];
180  mkdir(p,0755);
181  if ( -1 == chdir(p)) die_syserr();
182  for (e=0; e<16; e++)
183  {
184  q[0]=a[e];
185  mkdir(q,0755);
186  if ( config->chunk_depth > 2 ) {
187  if ( -1 == chdir(q)) die_syserr();
188  for (f=0; f<16; f++)
189  {
190  r[0]=a[f];
191  mkdir(r,0755);
192  if ( config->chunk_depth > 3 ) {
193  if ( -1 == chdir(r)) die_syserr();
194  for (g=0; g<16; g++){
195  s[0]=a[g];
196  mkdir(s,0755);
197  if ( config->chunk_depth > 4 ) {
198  if ( -1 == chdir(s)) die_syserr();
199  for (h=0; h<16; h++){
200  t[0]=a[h];
201  mkdir(t,0755);
202  }
203  if ( -1 == chdir("..")) die_syserr();
204  }
205  }
206  if ( -1 == chdir("..")) die_syserr();
207  }
208  }
209  if ( -1 == chdir("..")) die_syserr();
210  }
211  }
212  if ( -1 == chdir("..")) die_syserr();
213  }
214 }
215 
216 unsigned char *thash(unsigned char *buf, int size)
217 {
218  MHASH td;
219  unsigned char *hash;
220 
221  td = mhash_init(config->selected_hash);
222  if (td == MHASH_FAILED)
223  exit(1);
224 
225  mhash(td, buf, size);
226  hash = mhash_end(td);
227  return hash;
228 }
229 
231 {
232  struct stat stbuf;
233  unsigned long long rsize;
234 
235  FUNC;
236  if (-1 == stat(config->blockdata, &stbuf))
237  die_dataerr("Failed to stat %s\n", config->blockdata);
238  if (stbuf.st_size > nextoffset) {
239  LDEBUG("nextoffset = %llu, real size = %llu", nextoffset,
240  stbuf.st_size);
241  rsize = round_512(nextoffset);
242  if (-1 == ftruncate(fdbdta, rsize))
243  die_dataerr("Failed to truncate %s to %llu bytes\n",
244  config->blockdata, rsize);
245  }
246  EFUNC;
247 }
248 
249 INUSE *get_offset(unsigned long long size)
250 {
251  unsigned long long mbytes;
252  unsigned long long offset;
253  unsigned long long notfound = (0 - 1);
254  time_t thetime;
255  INUSE *inuse = NULL;
256 
257  LDEBUG("get_offset %llu", size);
258  thetime = time(NULL);
259  get_offset_lock((char *) __PRETTY_FUNCTION__);
260  mbytes = round_512(size);
261  mbytes = mbytes / 512;
262  if ( config->reclaim) {
263  offset = get_offset_fast(mbytes);
264  if (offset == notfound) {
265  if (config->nospace != -ENOSPC && config->nospace != ENOSPC
267  offset = nextoffset;
268  set_new_offset(size);
269  } else {
270  inuse = get_offset_reclaim(mbytes, offset);
271  if (NULL == inuse) {
272  // We failed to reclaim space.
273  // Write this last block and disable new writes
274  offset = nextoffset;
275  set_new_offset(size);
276  config->nospace = ENOSPC;
277  } else
278  inuse->size = size;
279  }
280  }
281  } else {
282  offset = nextoffset;
283  set_new_offset(size);
284  }
285  if (NULL == inuse) {
286  inuse = s_zmalloc(sizeof(INUSE));
287  inuse->offset = offset;
288  inuse->size = size;
289  inuse->allocated_size = round_512(size);
290  } else
291  LDEBUG("get_offset : needed %llu bytes, got %llu", size,
292  inuse->allocated_size);
294  LDEBUG("/get_offset %llu", size);
295  return inuse;
296 }
297 
298 int fs_symlink(char *from, char *to)
299 {
300  int res = 0;
301  char *todir;
302 
303  todir = s_dirname(to);
304  dbmknod(to, 0777 | S_IFLNK, from, 0);
305  res = update_parent_time(todir, 0);
306  s_free(todir);
307  return (res);
308 }
309 
310 int fs_readlink(const char *path, char *buf, size_t size)
311 {
312  int res = 0;
313  DAT *data;
314  unsigned long long inode;
315 
316  FUNC;
317  inode = get_inode(path);
318  if (0 == inode)
319  return (-ENOENT);
320 
321  data = search_dbdata(DBS, &inode, sizeof(unsigned long long), LOCK);
322  if (NULL == data) {
323  res = -ENOENT;
324  } else {
325  if (size - 1 > data->size) {
326  memcpy(buf, data->data, data->size + 1);
327  } else {
328  memcpy(buf, data->data, size - 1);
329  }
330  DATfree(data);
331  }
332  return (res);
333 }
334 
335 void invalidate_p2i(char *filename)
336 {
337  cachep2i_lock((char *) __PRETTY_FUNCTION__);
338  tctreeout(path2inotree, filename, strlen(filename));
340  return;
341 }
342 
343 void erase_p2i()
344 {
345  cachep2i_lock((char *) __PRETTY_FUNCTION__);
346  tctreeclear(path2inotree);
348  return;
349 }
350 
351 
352 /* Compare two list elements in INOBNO order.
353  `a' specifies the pointer to one element.
354  `b' specifies the pointer to the other element.
355  The return value is positive if the former is big, negative if the latter is big, 0 if both
356  are equivalent. */
357 static int inobnolistelemcmp(const void *a, const void *b){
358  INOBNO *left;
359  INOBNO *right;
360  TCLISTDATUM *c;
361  TCLISTDATUM *d;
362  int ret=1;
363 
364  if ( a == NULL && b == NULL ) return(0);
365  if ( a == NULL ) return(-1);
366  if ( b == NULL ) return(-1);
367  c=(TCLISTDATUM *)a;
368  d=(TCLISTDATUM *)b;
369  if ( c->size != sizeof(INOBNO)) return(-1);
370  if ( d->size != sizeof(INOBNO)) return(-1);
371  left=(INOBNO *)c->ptr;
372  right=(INOBNO *)d->ptr;
373  if ( left->inode < right->inode ) ret=-1;
374  if ( left->inode == right->inode ) {
375  if ( left->blocknr < right->blocknr ) ret=-1;
376  if ( left->blocknr == right->blocknr ) ret=0;
377  }
378  return(ret);
379 }
380 
381 void inobnolistsort(TCLIST *list){
382  qsort(list->array + list->start, list->num, sizeof(list->array[0]), inobnolistelemcmp);
383 }
384 
385 void cache_p2i(char *filename, struct stat *stbuf)
386 {
387  cachep2i_lock((char *) __PRETTY_FUNCTION__);
388  LDEBUG("Cache |%s|", filename);
389  if (tctreernum(path2inotree) > MAX_META_CACHE) {
390  LINFO
391  ("Clearing path2inode cache, when this message is logged with high frequency consider raising MAX_META_CACHE");
392  tctreeclear(path2inotree);
393  }
394  tctreeput(path2inotree, filename, strlen(filename), (void *) stbuf,
395  sizeof(struct stat));
397  return;
398 }
399 
400 #ifdef DEBUG
401 void logiv(char *msg, unsigned char *bhash)
402 {
403  char *ascii_hash = NULL;
404  int n;
405  char *p1, *p2;
406 
407  for (n = 0; n < 8; n++) {
408  p1 = as_sprintf(__FILE__, __LINE__, "%02X", bhash[n]);
409  if (n == 0) {
410  ascii_hash = s_strdup(p1);
411  } else {
412  p2 = s_strdup(ascii_hash);
414  ascii_hash = as_sprintf(__FILE__, __LINE__, "%s%s", p2, p1);
415  s_free(p2);
416  }
417  s_free(p1);
418  }
419  LDEBUG("%s : %s", msg, ascii_hash);
421 }
422 #else
423 void logiv(char *msg, unsigned char *bhash)
424 {
425 }
426 #endif
427 
428 #ifdef DEBUG
429 void loghash(char *msg, unsigned char *bhash)
430 {
431  char *ascii_hash = NULL;
432  int n;
433  char *p1, *p2;
434 
435  for (n = 0; n < config->hashlen; n++) {
436  p1 = as_sprintf(__FILE__, __LINE__, "%02X", bhash[n]);
437  if (n == 0) {
438  ascii_hash = s_strdup(p1);
439  } else {
440  p2 = s_strdup(ascii_hash);
442  ascii_hash = as_sprintf(__FILE__, __LINE__, "%s%s", p2, p1);
443  s_free(p2);
444  }
445  s_free(p1);
446  }
447  LDEBUG("%s : %s", msg, ascii_hash);
449 }
450 # else
451 void loghash(char *msg, unsigned char *bhash)
452 {
453 }
454 # endif
455 
456 void log_fatal_hash(char *msg, unsigned char *bhash)
457 {
458  char *ascii_hash = NULL;
459  int n;
460  char *p1, *p2;
461 
462  for (n = 0; n < config->hashlen; n++) {
463  p1 = as_sprintf(__FILE__, __LINE__, "%02X", bhash[n]);
464  if (n == 0) {
465  ascii_hash = s_strdup(p1);
466  } else {
467  p2 = s_strdup(ascii_hash);
469  ascii_hash = as_sprintf(__FILE__, __LINE__, "%s%s", p2, p1);
470  s_free(p2);
471  }
472  s_free(p1);
473  }
474  LFATAL("%s : %s", msg, ascii_hash);
476 }
477 
478 unsigned char *hash_to_ascii(unsigned char *bhash)
479 {
480  char *ascii_hash = NULL;
481  int n;
482  char *p1, *p2;
483 
484  for (n = 0; n < config->hashlen; n++) {
485  p1 = as_sprintf(__FILE__, __LINE__, "%02X", bhash[n]);
486  if (n == 0) {
487  ascii_hash = s_strdup(p1);
488  } else {
489  p2 = s_strdup(ascii_hash);
491  ascii_hash = as_sprintf(__FILE__, __LINE__, "%s%s", p2, p1);
492  s_free(p2);
493  }
494  s_free(p1);
495  }
496  return (unsigned char *)ascii_hash;
497 }
498 
499 void create_hash_note(unsigned char *hash)
500 {
501  unsigned long long inuse = 0;
502  wait_hash_pending(hash);
503  tctreeput(hashtree, (void *) hash, config->hashlen, &inuse,
504  sizeof(unsigned long long));
506 }
507 
508 void wait_hash_pending(unsigned char *hash)
509 {
510  const char *data = NULL;
511  int vsize;
512  while (1) {
513  get_hash_lock((char *) __PRETTY_FUNCTION__);
514  data = tctreeget(hashtree, hash, config->hashlen, &vsize);
515  if (NULL == data)
516  break;
518  usleep(10);
519  }
520 }
521 
522 void delete_hash_note(unsigned char *hash)
523 {
524  get_hash_lock((char *) __PRETTY_FUNCTION__);
525  tctreeout(hashtree, (void *) hash, config->hashlen);
527 }
528 
529 
530 void create_inode_note(unsigned long long inode)
531 {
532  wait_inode_pending(inode);
533  LDEBUG("create_inode_note : %llu locked", inode);
534  tctreeput(inodetree, (void *) &inode, sizeof(unsigned long long),
535  &inode, sizeof(unsigned long long));
537 }
538 
539 void wait_inode_pending(unsigned long long inode)
540 {
541  const char *data = NULL;
542  int vsize;
543  while (1) {
544  get_inode_lock((char *) __PRETTY_FUNCTION__);
545  data = tctreeget(inodetree, &inode,
546  sizeof(unsigned long long), &vsize);
547  if (NULL == data)
548  break;
550  usleep(10);
551  }
552 }
553 
554 int inode_isnot_locked(unsigned long long inode)
555 {
556  const char *data = NULL;
557  int vsize;
558  int ret = 0;
559 
560  get_inode_lock((char *) __PRETTY_FUNCTION__);
561  data = tctreeget(inodetree, &inode,
562  sizeof(unsigned long long), &vsize);
563  if (NULL == data)
564  ret = 1;
566  return (ret);
567 }
568 
569 void wait_inode_pending2(unsigned long long inode)
570 {
571  const char *data = NULL;
572  int vsize;
573  while (1) {
574  get_inode_lock((char *) __PRETTY_FUNCTION__);
575  data = tctreeget(inodetree, &inode,
576  sizeof(unsigned long long), &vsize);
577  if (NULL == data)
578  break;
579  LDEBUG("wait_inode_pending2 : waiting on locked inode %llu",
580  inode);
582  usleep(10);
583  }
585 }
586 
587 void delete_inode_note(unsigned long long inode)
588 {
589  get_inode_lock((char *) __PRETTY_FUNCTION__);
590  tctreeout(inodetree, (void *) &inode, sizeof(unsigned long long));
591  LDEBUG("delete_inode_note : %llu unlocked", inode);
593 }
594 
595 void die_lock_report(const char *msg, const char *msg2)
596 {
597  LFATAL("die_lock_report : timeout on %s, called by %s", msg2, msg);
598  if (0 == try_global_lock()) {
599  LFATAL("global_lock : 0 (unset)");
600  } else {
601  LFATAL("global_lock : 1 (set)");
602  }
603  if (0 == try_write_lock()) {
604  LFATAL("write_lock : 0 (unset)");
605  } else {
606  LFATAL("write_lock : 1 (set)");
607  }
608  if (0 == try_meta_lock()) {
609  LFATAL("meta_lock : 0 (unset)");
610  } else {
611  LFATAL("meta_lock : 1 (set)");
612  }
613  die_dataerr("Abort after deadlock");
614 }
615 
616 void get_global_lock(const char *msg)
617 {
618  FUNC;
619 #ifdef DBGLOCK
620  struct timespec deltatime;
621  deltatime.tv_sec = time(NULL) + GLOBAL_LOCK_TIMEOUT;
622  deltatime.tv_nsec = 0;
623  int err_code;
624 
625  err_code = pthread_mutex_timedlock(&global_lock_mutex, &deltatime);
626  if (err_code != 0) {
627  die_lock_report(msg, __PRETTY_FUNCTION__);
628  }
629 #else
630  pthread_mutex_lock(&global_lock_mutex);
631 #endif
632  global_lockedby = msg;
633  EFUNC;
634  return;
635 }
636 
638 {
639  FUNC;
640  pthread_mutex_unlock(&global_lock_mutex);
641  EFUNC;
642  return;
643 }
644 
646 {
647  int res;
648  FUNC;
649  res = pthread_mutex_trylock(&global_lock_mutex);
650  EFUNC;
651  return (res);
652 }
653 
654 
656 {
657  int res;
658  FUNC;
659  res = pthread_mutex_trylock(&repl_mutex);
660  EFUNC;
661  return (res);
662 }
663 
665 {
666  int res;
667  FUNC;
668  res = pthread_mutex_trylock(&replbl_mutex);
669  EFUNC;
670  return (res);
671 }
672 
673 
674 void write_lock(const char *msg)
675 {
676 #ifdef DBGLOCK
677  struct timespec deltatime;
678  deltatime.tv_sec = time(NULL) + LOCK_TIMEOUT;
679  deltatime.tv_nsec = 0;
680  int err_code;
681 
682 
683  err_code = pthread_mutex_timedlock(&write_mutex, &deltatime);
684  if (err_code != 0) {
685  die_lock_report(msg, __PRETTY_FUNCTION__);
686  }
687 #else
688  pthread_mutex_lock(&write_mutex);
689 #endif
690  write_lockedby = msg;
691  return;
692 }
693 
695 {
696  pthread_mutex_unlock(&write_mutex);
697  return;
698 }
699 
700 
701 void cachep2i_lock(const char *msg)
702 {
703 #ifdef DBGLOCK
704  struct timespec deltatime;
705  deltatime.tv_sec = time(NULL) + LOCK_TIMEOUT;
706  deltatime.tv_nsec = 0;
707  int err_code;
708 
709 
710  err_code = pthread_mutex_timedlock(&cachep2i_mutex, &deltatime);
711  if (err_code != 0) {
712  die_lock_report(msg, __PRETTY_FUNCTION__);
713  }
714 #else
715  pthread_mutex_lock(&cachep2i_mutex);
716 #endif
717  cachep2i_lockedby = msg;
718  return;
719 }
720 
722 {
723  pthread_mutex_unlock(&cachep2i_mutex);
724  return;
725 }
726 
728 {
729  int res;
730  res = pthread_mutex_trylock(&cachep2i_mutex);
731  return (res);
732 }
733 
734 
736 {
737  int res;
738  res = pthread_mutex_trylock(&write_mutex);
739  return (res);
740 }
741 
743 {
744  FUNC;
745  int res;
746  res = pthread_mutex_trylock(&offset_mutex);
747  EFUNC;
748  return (res);
749 }
750 
751 void get_hash_lock(const char *msg)
752 {
753  FUNC;
754 #ifdef DBGLOCK
755  struct timespec deltatime;
756  deltatime.tv_sec = time(NULL) + LOCK_TIMEOUT;
757  deltatime.tv_nsec = 0;
758  int err_code;
759 
760  FUNC;
761  err_code = pthread_mutex_timedlock(&hash_mutex, &deltatime);
762  if (err_code != 0) {
763  die_lock_report(msg, __PRETTY_FUNCTION__);
764  }
765 #else
766  pthread_mutex_lock(&hash_mutex);
767 #endif
768  hash_lockedby = msg;
769  EFUNC;
770  return;
771 }
772 
774 {
775  FUNC;
776  int res;
777  res = pthread_mutex_trylock(&hash_mutex);
778  EFUNC;
779  return (res);
780 }
781 
783 {
784  FUNC;
785  pthread_mutex_unlock(&hash_mutex);
786  EFUNC;
787  return;
788 }
789 
790 void get_inode_lock(const char *msg)
791 {
792  FUNC;
793 #ifdef DBGLOCK
794  struct timespec deltatime;
795  deltatime.tv_sec = time(NULL) + LOCK_TIMEOUT;
796  deltatime.tv_nsec = 0;
797  int err_code;
798 
799  FUNC;
800  err_code = pthread_mutex_timedlock(&inode_mutex, &deltatime);
801  if (err_code != 0) {
802  die_lock_report(msg, __PRETTY_FUNCTION__);
803  }
804 #else
805  pthread_mutex_lock(&inode_mutex);
806 #endif
807  inode_lockedby = msg;
808  EFUNC;
809  return;
810 }
811 
813 {
814  FUNC;
815  pthread_mutex_unlock(&inode_mutex);
816  EFUNC;
817  return;
818 }
819 
820 void get_offset_lock(const char *msg)
821 {
822  FUNC;
823 #ifdef DBGLOCK
824  struct timespec deltatime;
825  deltatime.tv_sec = time(NULL) + GLOBAL_LOCK_TIMEOUT;
826  deltatime.tv_nsec = 0;
827  int err_code;
828 
829  err_code = pthread_mutex_timedlock(&offset_mutex, &deltatime);
830  if (err_code != 0) {
831  die_lock_report(msg, __PRETTY_FUNCTION__);
832  }
833 #else
834  pthread_mutex_lock(&offset_mutex);
835 
836 #endif
837  offset_lockedby = msg;
838  EFUNC;
839  return;
840 }
841 
843 {
844  FUNC;
845  pthread_mutex_unlock(&offset_mutex);
846  EFUNC;
847  return;
848 }
849 
850 void worker_lock(const char *msg)
851 {
852  FUNC;
853 #ifdef DBGLOCK
854  struct timespec deltatime;
855  deltatime.tv_sec = time(NULL) + GLOBAL_LOCK_TIMEOUT;
856  deltatime.tv_nsec = 0;
857  int err_code;
858 
859  err_code = pthread_mutex_timedlock(&worker_mutex, &deltatime);
860  if (err_code != 0) {
861  die_lock_report(msg, __PRETTY_FUNCTION__);
862  }
863 #else
864  pthread_mutex_lock(&worker_mutex);
865 
866 #endif
867  worker_lockedby = msg;
868  EFUNC;
869  return;
870 }
871 
873 {
874  FUNC;
875  pthread_mutex_unlock(&worker_mutex);
876  EFUNC;
877  return;
878 }
879 
880 void meta_lock(const char *msg)
881 {
882  FUNC;
883 #ifdef DBGLOCK
884  struct timespec deltatime;
885  deltatime.tv_sec = time(NULL) + LOCK_TIMEOUT;
886  deltatime.tv_nsec = 0;
887  int err_code;
888 
889  FUNC;
890  err_code = pthread_mutex_timedlock(&meta_mutex, &deltatime);
891  if (err_code != 0) {
892  die_lock_report(msg, __PRETTY_FUNCTION__);
893  }
894 #else
895  pthread_mutex_lock(&meta_mutex);
896 #endif
897  meta_lockedby = msg;
898  EFUNC;
899  return;
900 }
901 
902 void repl_lock(const char *msg)
903 {
904  //FUNC;
905 #ifdef DBGLOCK
906  struct timespec deltatime;
907  deltatime.tv_sec = time(NULL) + LOCK_TIMEOUT;
908  deltatime.tv_nsec = 0;
909  int err_code;
910 
911  err_code = pthread_mutex_timedlock(&repl_mutex, &deltatime);
912  if (err_code != 0) {
913  die_lock_report(msg, __PRETTY_FUNCTION__);
914  }
915 #else
916  pthread_mutex_lock(&repl_mutex);
917 #endif
918  repl_lockedby = msg;
919  //EFUNC;
920  return;
921 }
922 
924 {
925  pthread_mutex_unlock(&repl_mutex);
926  return;
927 }
928 
930 {
931  pthread_mutex_unlock(&replbl_mutex);
932  return;
933 }
934 
936 {
937  FUNC;
938  pthread_mutex_unlock(&meta_mutex);
939  EFUNC;
940  return;
941 }
942 
944 {
945  int res;
946  res = pthread_mutex_trylock(&meta_mutex);
947  return (res);
948 }
949 
951 {
952  if (config->background_delete != 0) {
953  pthread_mutex_lock(&relax_mutex);
954  }
955  return;
956 }
957 
959 {
960  if (config->background_delete != 0) {
961  pthread_mutex_unlock(&relax_mutex);
962  }
963  return;
964 }
965 
967 {
968  if (config->background_delete != 0) {
969  pthread_mutex_lock(&relax_mutex);
970  pthread_mutex_unlock(&relax_mutex);
971  }
972  return;
973 }
974 
976 {
977  DAT *ddbuf;
978 
979  ddbuf = s_malloc(sizeof(DAT));
980  ddbuf->data = s_malloc(sizeof(MEMDDSTAT));
981  ddbuf->size = sizeof(MEMDDSTAT);
982  memcpy(ddbuf->data, ddstat, sizeof(MEMDDSTAT));
983  return ddbuf;
984 }
985 
987 {
988  DDSTAT *ddbuf;
989  int filelen;
990  DAT *decrypted;
991 
992  FUNC;
993  decrypted = vddstat;
994 #ifdef ENABLE_CRYPTO
996  decrypted = lfsdecrypt(vddstat);
997  }
998 #endif
999  filelen =
1000  decrypted->size - (sizeof(struct stat) +
1001  sizeof(unsigned long long));
1002  ddbuf = s_zmalloc(sizeof(DDSTAT));
1003  memcpy(&ddbuf->stbuf, decrypted->data, sizeof(struct stat));
1004  memcpy(&ddbuf->real_size, decrypted->data + sizeof(struct stat),
1005  sizeof(unsigned long long));
1006  if (1 == filelen) {
1007  ddbuf->filename[0] = 0;
1008  } else {
1009  memcpy(ddbuf->filename,
1010  &decrypted->data[(sizeof(struct stat) +
1011  sizeof(unsigned long long))], filelen);
1012  }
1013  LDEBUG("value_to_ddstat : return %llu", ddbuf->stbuf.st_ino);
1014 #ifdef ENABLE_CRYPTO
1015  if (config->encryptmeta && config->encryptdata) {
1016  DATfree(decrypted);
1017  }
1018 #endif
1019  EFUNC;
1020  return ddbuf;
1021 }
1022 
1023 DAT *create_ddbuf(struct stat stbuf, char *filename,
1024  unsigned long long real_size)
1025 {
1026  DAT *ddbuf;
1027  int len;
1028 #ifdef ENABLE_CRYPTO
1029  DAT *lencrypted;
1030 #endif
1031 
1032  FUNC;
1033  if (filename) {
1034  len =
1035  sizeof(struct stat) + sizeof(unsigned long long) +
1036  strlen((char *) filename) + 1;
1037  } else
1038  len = sizeof(struct stat) + sizeof(unsigned long long) + 1;
1039 
1040  ddbuf = s_malloc(sizeof(DAT));
1041  ddbuf->size = len;
1042  ddbuf->data = s_malloc(ddbuf->size);
1043  memcpy(ddbuf->data, &stbuf, sizeof(struct stat));
1044  memcpy(ddbuf->data + sizeof(struct stat), &real_size,
1045  sizeof(unsigned long long));
1046  if (filename) {
1047  memcpy(ddbuf->data + sizeof(struct stat) +
1048  sizeof(unsigned long long), (char *) filename,
1049  strlen((char *) filename) + 1);
1050  } else
1051  memset(ddbuf->data + sizeof(struct stat) +
1052  sizeof(unsigned long long), 0, 1);
1053 
1054 #ifdef ENABLE_CRYPTO
1055  if (config->encryptmeta && config->encryptdata) {
1056  lencrypted = lfsencrypt(ddbuf->data, ddbuf->size);
1057  DATfree(ddbuf);
1058  EFUNC;
1059  return lencrypted;
1060  }
1061 #endif
1062  EFUNC;
1063  return ddbuf;
1064 }
1065 
1066 void dbmknod(const char *path, mode_t mode, char *linkdest, dev_t rdev)
1067 {
1068  unsigned long long inode;
1069 
1070  FUNC;
1071  LDEBUG("dbmknod : %s", path);
1072  inode = get_next_inode();
1073  write_file_ent(path, inode, mode, linkdest, rdev);
1074  EFUNC;
1075  return;
1076 }
1077 
1078 /* Fill struct stat from cache if present in the cache
1079  return 1 when found or 0 when not found in cache. */
1080 int get_realsize_fromcache(unsigned long long inode, struct stat *stbuf)
1081 {
1082  int result = 0;
1083  const char *data;
1084  MEMDDSTAT *mddstat;
1085  int vsize;
1086  meta_lock((char *) __PRETTY_FUNCTION__);
1087  data = tctreeget(metatree, &inode, sizeof(unsigned long long), &vsize);
1088  if (data == NULL) {
1089  LDEBUG("inode %llu not found use size from database.", inode);
1091  return (result);
1092  }
1093  result++;
1094  mddstat = (MEMDDSTAT *) data;
1095  memcpy(stbuf, &mddstat->stbuf, sizeof(struct stat));
1096  LDEBUG
1097  ("get_realsize_fromcache : return stbuf from cache : size %llu time %lu",
1098  stbuf->st_size, mddstat->stbuf.st_atim.tv_sec);
1100  return (result);
1101 }
1102 
1103 int get_dir_inode(char *dname, struct stat *stbuf, bool cache_request)
1104 {
1105  char *p;
1106  int depth = 0;
1107  DDSTAT *filestat = NULL;
1108  int res = 0, vsize;
1109  unsigned long long inode = 1;
1110  char *basedname;
1111  struct stat *st;
1112 
1113  FUNC;
1114 
1115  basedname = s_dirname(dname);
1116  cachep2i_lock((char *) __PRETTY_FUNCTION__);
1117  st = (struct stat *) tctreeget(path2inotree, (void *) basedname,
1118  strlen(basedname), &vsize);
1119  if (st) {
1120  memcpy(stbuf, st, vsize);
1121  s_free(basedname);
1123  return (res);
1124  }
1126  while (1) {
1127  p = strchr(dname, '/');
1128  if (NULL == p)
1129  break;
1130  p[0] = 0;
1131  LDEBUG("p=%s", p);
1132  if (depth == 0) {
1133  LDEBUG("Lookup inode 1");
1134  filestat =
1135  dnode_bname_to_inode(&inode, sizeof(unsigned long long),
1136  "/");
1137  } else {
1138  ddstatfree(filestat);
1139  inode = stbuf->st_ino;
1140  filestat =
1141  dnode_bname_to_inode(&inode, sizeof(unsigned long long),
1142  dname);
1143  if (NULL == filestat) {
1144  res = -ENOENT;
1145  break;
1146  }
1147  }
1148  memcpy(stbuf, &filestat->stbuf, sizeof(struct stat));
1149  LDEBUG("After memcpy %llu", stbuf->st_ino);
1150  p++;
1151  depth++;
1152  dname = p;
1153  if (NULL == p)
1154  break;
1155  }
1156  if (res == 0) {
1157  ddstatfree(filestat);
1158  if (cache_request)
1159  cache_p2i(basedname, stbuf);
1160  LDEBUG("return %s stbuf.st_ino=%llu", basedname, stbuf->st_ino);
1161  }
1162  s_free(basedname);
1163  EFUNC;
1164  return (res);
1165 }
1166 
1167 int path_from_cache(char *path, struct stat *stbuf)
1168 {
1169  int res = 0, vsize;
1170  struct stat *st;
1171  DAT *statdata;
1172  DDSTAT *ddstat;
1173 
1174  cachep2i_lock((char *) __PRETTY_FUNCTION__);
1175  st = (struct stat *) tctreeget(path2inotree, (void *) path,
1176  strlen(path), &vsize);
1177  if (st) {
1178  res = get_realsize_fromcache(st->st_ino, stbuf);
1179  if (!res) {
1180  memcpy(stbuf, st, vsize);
1181  // We always have to fetch hardlinks from disk.
1182  if (stbuf->st_nlink > 1) {
1183  statdata =
1184  search_dbdata(DBP, &stbuf->st_ino,
1185  sizeof(unsigned long long), LOCK);
1186  if (NULL == statdata) {
1188  return (res);
1189  }
1190  ddstat = value_to_ddstat(statdata);
1191  DATfree(statdata);
1192  memcpy(stbuf, &ddstat->stbuf, sizeof(struct stat));
1193  ddstatfree(ddstat);
1194  }
1195  res = 1;
1196  }
1197  }
1199  LDEBUG("path_from_cache : return %s %i", path, res);
1200  return (res);
1201 }
1202 
1203 
1204 int dbstat(const char *filename, struct stat *stbuf, bool cache_request)
1205 {
1206  int retcode = 0;
1207  char *dname = NULL;
1208  char *bname = NULL;
1209  char *dupdname = NULL;
1210  char *mdupdname = NULL;
1211  DDSTAT *filestat = NULL;
1212 
1213  FUNC;
1214  dname = s_dirname((char *) filename);
1215  bname = s_basename((char *) filename);
1216  dupdname = s_strdup((char *) filename);
1217  mdupdname = dupdname;
1218 
1219 
1220  if (!path_from_cache((char *) filename, stbuf)) {
1221  // Walk the directory
1222  retcode = get_dir_inode(dupdname, stbuf, cache_request);
1223  if (0 == retcode) {
1224  if (0 != strcmp(bname, dname)) { /* This is the rootdir */
1225  // Now find the file within the directory
1226  filestat =
1227  dnode_bname_to_inode(&stbuf->st_ino,
1228  sizeof(unsigned long long),
1229  bname);
1230  if (filestat) {
1231  if (0 == strcmp(bname, filestat->filename)) {
1232  if (0 ==
1233  get_realsize_fromcache(filestat->stbuf.st_ino,
1234  stbuf)) {
1235  memcpy(stbuf, &filestat->stbuf,
1236  sizeof(struct stat));
1237  if (cache_request)
1238  cache_p2i((char *) filename, stbuf);
1239  }
1240  } else {
1241  retcode = -ENOENT;
1242  }
1243  ddstatfree(filestat);
1244  } else {
1245  retcode = -ENOENT;
1246  }
1247  }
1248  } else
1249  retcode = -ENOENT;
1250  }
1251  s_free(mdupdname);
1252  s_free(bname);
1253  s_free(dname);
1254  if (retcode == -ENOENT)
1255  LDEBUG("dbstat : File %s not found.", filename);
1256  EFUNC;
1257  return (retcode);
1258 }
1259 
1260 /* Free the ddstat stucture when not NULL */
1261 void ddstatfree(DDSTAT * ddstat)
1262 {
1263  if (ddstat) {
1264  LDEBUG("ddstatfree really s_free");
1265  s_free(ddstat);
1266  ddstat = NULL;
1267  }
1268 }
1269 
1270 MEMDDSTAT *value_tomem_ddstat(char *value, int size)
1271 {
1272  MEMDDSTAT *memddstat;
1273  memddstat = s_malloc(size);
1274  memcpy(memddstat, value, size);
1275  return memddstat;
1276 }
1277 
1278 void memddstatfree(MEMDDSTAT * ddstat)
1279 {
1280  if (ddstat) {
1281  LDEBUG("memddstatfree really s_free");
1282  s_free(ddstat);
1283  }
1284  ddstat = NULL;
1285  return;
1286 }
1287 
1288 void comprfree(compr * compdata)
1289 {
1290  s_free(compdata->data);
1291  s_free(compdata);
1292 }
1293 
1294 void write_file_ent(const char *filename, unsigned long long inode,
1295  mode_t mode, char *linkdest, dev_t rdev)
1296 {
1297  struct stat stbuf;
1298  struct stat dirstat;
1299  time_t thetime;
1300  char *bname;
1301  char *parentdir;
1302  int res = 0;
1303  DAT *ddbuf;
1304  bool isdot = 0;
1305  bool isrootdir = 0;
1306 
1307  FUNC;
1308  LDEBUG("write_file_ent : filename %s, inodenumber %llu", filename,
1309  inode);
1310  bname = s_basename((char *) filename);
1311  parentdir = s_dirname((char *) filename);
1312  if (0 == strcmp(filename, "/"))
1313  isrootdir = 1;
1314  LDEBUG("write_file_ent: parentdir = %s", parentdir);
1315  write_nfi(inode + 1);
1316 
1317 //Write stat structure to create an empty file.
1318  stbuf.st_ino = inode;
1319  stbuf.st_dev = 999988;
1320  stbuf.st_mode = mode;
1321  if (S_ISDIR(mode)) {
1322  stbuf.st_nlink = 2;
1323  } else
1324  stbuf.st_nlink = 1;
1325  if (!isrootdir) {
1326  if (0 == strcmp(filename, "/lost+found") ||
1327  0 == strcmp(filename, "/.lessfs") ||
1328  0 == strcmp(filename, "/.lessfs/locks") ||
1329  0 == strcmp(filename, "/.lessfs/replication") ||
1330  0 == strcmp(filename, "/.lessfs/replication/enabled") ||
1331  0 == strcmp(filename, "/.lessfs/replication/backlog") ||
1332  0 == strcmp(filename, "/.lessfs/replication/sequence") ||
1333  0 == strcmp(filename, "/.lessfs/replication/rotate_replog") ||
1334  0 == strcmp(filename, "/lost+found/.") ||
1335  0 == strcmp(filename, "/lost+found/..") ||
1336  0 == strcmp(filename, "/.lessfs/lessfs_stats")) {
1337  stbuf.st_uid = 0;
1338  stbuf.st_gid = 0;
1339  } else {
1340  stbuf.st_uid = fuse_get_context()->uid;
1341  stbuf.st_gid = fuse_get_context()->gid;
1342  }
1343  } else {
1344  stbuf.st_uid = 0;
1345  stbuf.st_gid = 0;
1346  }
1347  stbuf.st_rdev = rdev;
1348  if (S_ISDIR(mode)) {
1349  stbuf.st_size = 4096;
1350  stbuf.st_blocks = 1;
1351  } else {
1352  stbuf.st_size = 0;
1353  stbuf.st_blocks = 0;
1354  }
1355  if (S_ISLNK(mode)) {
1356  stbuf.st_size = 3;
1357  stbuf.st_blocks = 1;
1358  }
1359  if (config->sticky_on_locked && S_ISREG(stbuf.st_mode)) {
1360  if (S_ISVTX == (S_ISVTX & stbuf.st_mode)) {
1361  LINFO("reset stickybit on : %llu",
1362  (unsigned long long) stbuf.st_ino);
1363  stbuf.st_mode = stbuf.st_mode ^ S_ISVTX;
1364  }
1365  }
1366  stbuf.st_blksize = BLKSIZE;
1367  thetime = time(NULL);
1368  stbuf.st_atim.tv_sec = thetime;
1369  stbuf.st_atim.tv_nsec = 0;
1370  stbuf.st_mtim.tv_sec = thetime;
1371  stbuf.st_mtim.tv_nsec = 0;
1372  stbuf.st_ctim.tv_sec = thetime;
1373  stbuf.st_ctim.tv_nsec = 0;
1374 
1375  ddbuf = create_ddbuf(stbuf, bname, 0);
1376  LDEBUG("write_file_ent : write dbp inode %llu", inode);
1377  bin_write_dbdata(DBP, &inode, sizeof(inode), ddbuf->data, ddbuf->size);
1378  cache_p2i((char *) filename, &stbuf);
1379  DATfree(ddbuf);
1380  if (linkdest) {
1381  bin_write_dbdata(DBS, &inode, sizeof(unsigned long long), linkdest,
1382  strlen(linkdest) + 1);
1383  }
1384  if (0 == strcmp(bname, "."))
1385  isdot = 1;
1386  if (0 == strcmp(bname, ".."))
1387  isdot = 1;
1388  recurse:
1389  if (S_ISDIR(mode) && isdot != 1) {
1390  btbin_write_dup(DBDIRENT, &stbuf.st_ino, sizeof(stbuf.st_ino),
1391  &inode, sizeof(inode), LOCK);
1392  } else {
1393  res = dbstat(parentdir, &dirstat, 1);
1394  btbin_write_dup(DBDIRENT, &dirstat.st_ino, sizeof(dirstat.st_ino),
1395  &inode, sizeof(inode), LOCK);
1396  }
1397  if (S_ISDIR(mode) && !isdot && !isrootdir) {
1398  // Create the link inode to the previous directory
1399  LDEBUG("Create the link inode to the previous directory");
1400  isdot = 1;
1401  // Only if !isrootdir. Nothing lower the root.
1402  goto recurse;
1403  }
1404  s_free(parentdir);
1405  s_free(bname);
1406  EFUNC;
1407 }
1408 
1409 void write_nfi(unsigned long long nextinode)
1410 {
1411  bin_write_dbdata(DBP, (unsigned char *) "NFI", strlen("NFI"),
1412  (unsigned char *) &nextinode, sizeof(nextinode));
1413  return;
1414 }
1415 
1416 void write_seq(unsigned long sequence)
1417 {
1418  bin_write(DBP, (unsigned char *) "SEQ", strlen("SEQ"),
1419  (unsigned char *) &sequence, sizeof(sequence));
1420  if (config->replication == 1 && config->replication_role == 0) {
1421  write_replication_data(DBP, REPLWRITE, (char *) "SEQ",
1422  strlen("SEQ"), (char *) &sequence,
1423  sizeof(sequence), MAX_ALLOWED_THREADS - 2);
1424  }
1425  return;
1426 }
1427 
1428 unsigned long get_sequence()
1429 {
1430  unsigned long sequence;
1431  DAT *data;
1432  FUNC;
1433  data =
1434  search_dbdata(DBP, (unsigned char *) "SEQ", strlen("SEQ"), LOCK);
1435  if (NULL == data)
1436  die_dataerr
1437  ("Unable to retrieve current replication sequence number");
1438  memcpy(&sequence, data->data, data->size);
1439  DATfree(data);
1440  EFUNC;
1441  return (sequence);
1442 }
1443 
1445 {
1446  unsigned long sequence;
1447  FUNC;
1448  sequence = get_sequence();
1449  sequence++;
1451  EFUNC;
1452  return;
1453 }
1454 
1455 void formatfs()
1456 {
1457  struct stat stbuf;
1458  unsigned long long nextinode = 0;
1459  unsigned char *stiger;
1460  char *blockdatadir;
1461  unsigned long sequence = 0;
1462 #ifdef ENABLE_CRYPTO
1463  CRYPTO crypto;
1464 #endif
1465  char *hashstr;
1466  INUSE inuse;
1467 
1468  FUNC;
1469 
1470  hashstr =
1471  as_sprintf(__FILE__, __LINE__, "%s%i", config->hash,
1472  config->hashlen);
1473  stiger = thash((unsigned char *) hashstr, strlen(hashstr));
1474  s_free(hashstr);
1476  update_inuse(stiger, 1);
1477  } else {
1478  inuse.inuse = 1;
1479  inuse.size = 0;
1480  inuse.offset = 0;
1481  file_update_inuse(stiger, &inuse);
1482  }
1484  s_free(stiger);
1485 
1486 #ifdef ENABLE_CRYPTO
1487  if (config->encryptdata) {
1488  stiger = thash(config->passwd, strlen((char *) config->passwd));
1489  loghash("store passwd as hash", stiger);
1490  memcpy(&crypto.passwd, stiger, config->hashlen);
1491  memcpy(&crypto.iv, config->iv, 8);
1492  bin_write_dbdata(DBP, &nextinode, sizeof(unsigned long long),
1493  &crypto, sizeof(CRYPTO));
1494  s_free(stiger);
1495  }
1496 #endif
1497  nextinode = 1;
1499  blockdatadir = s_dirname(config->blockdata);
1500  stat(blockdatadir, &stbuf);
1501  s_free(blockdatadir);
1502  } else {
1503  stat(config->blockdata, &stbuf);
1504  }
1505  write_nfi(nextinode);
1506  fs_mkdir("/", stbuf.st_mode);
1507  fs_mkdir("/.lessfs", stbuf.st_mode);
1508  fs_mkdir("/.lessfs/locks", stbuf.st_mode);
1509  dbmknod("/.lessfs/lessfs_stats", 0755 | S_IFREG, NULL, 0);
1510  fs_mkdir("/.lessfs/replication", stbuf.st_mode);
1511  dbmknod("/.lessfs/replication/enabled", 0755 | S_IFREG, NULL, 0);
1512  dbmknod("/.lessfs/replication/backlog", 0755 | S_IFREG, NULL, 0);
1513  dbmknod("/.lessfs/replication/sequence", 0755 | S_IFREG, NULL, 0);
1514  dbmknod("/.lessfs/replication/rotate_replog", 0755 | S_IFREG, NULL, 0);
1515  /* All database transactions are written to the replog file
1516  In the case of formatting the filesystem the information
1517  should not be replicated, so we truncate replog */
1518  if (-1 == ftruncate(frepl, 0))
1519  die_syserr();
1521  nextinode = 100;
1522  write_nfi(nextinode);
1523  db_close(0);
1524  return;
1525 }
1526 
1528 {
1529  DAT *data = NULL;
1530  int rsize;
1531  DAT *decrypted;
1532 
1533  decrypted = cdata;
1534 #ifdef ENABLE_CRYPTO
1535  if (config->encryptdata) {
1536  decrypted = lfsdecrypt(cdata);
1537  }
1538 #endif
1539 
1540  if (decrypted->data[0] == 0 || decrypted->data[0] == 'Q') {
1541  data = (DAT *) clz_decompress(decrypted->data, decrypted->size);
1542  goto end;
1543  }
1544  if (decrypted->data[0] == 0 || decrypted->data[0] == 'P') {
1545  data = (DAT *) clz15_decompress(decrypted->data, decrypted->size);
1546  goto end;
1547  }
1548  if (decrypted->data[0] == 'S') {
1549 #ifdef SNAPPY
1550  data = (DAT *) lfssnappy_decompress(decrypted->data, decrypted->size);
1551  goto end;
1552 #else
1553  LFATAL("lessfs is compiled without support for SNAPPY");
1554  db_close(0);
1555  exit(EXIT_DATAERR);
1556 #endif
1557  }
1558  if (decrypted->data[0] == 'L') {
1559 #ifdef LZO
1560  data = (DAT *) lzo_decompress(decrypted->data, decrypted->size);
1561  goto end;
1562 #else
1563  LFATAL("lessfs is compiled without LZO support");
1564  db_close(0);
1565  exit(EXIT_DATAERR);
1566 #endif
1567  }
1568  if (decrypted->data[0] == 'G') {
1569  data = s_malloc(sizeof(DAT));
1570  data->data = (unsigned char *) tcgzipdecode((const char *)
1571  &decrypted->data[1],
1572  decrypted->size - 1,
1573  &rsize);
1574  data->size = rsize;
1575  goto end;
1576  }
1577  if (decrypted->data[0] == 'B') {
1578  data = s_malloc(sizeof(DAT));
1579  data->data = (unsigned char *) tcbzipdecode((const char *)
1580  &decrypted->data[1],
1581  decrypted->size - 1,
1582  &rsize);
1583  data->size = rsize;
1584  goto end;
1585  }
1586  if (decrypted->data[0] == 'D') {
1587  data = s_malloc(sizeof(DAT));
1588  data->data =
1589  (unsigned char *) tcinflate((const char *) &decrypted->data[1],
1590  decrypted->size - 1, &rsize);
1591  data->size = rsize;
1592  goto end;
1593  }
1594  LFATAL("Data found with unsupported compression type %c",
1595  decrypted->data[0]);
1596  end:
1597 #ifdef ENABLE_CRYPTO
1598  if (config->encryptdata) {
1599  DATfree(decrypted);
1600  }
1601 #endif
1602  return data;
1603 }
1604 
1605 void auto_repair(INOBNO * inobno)
1606 {
1607  LINFO("Inode %llu is damaged at offset %llu", inobno->inode,
1608  inobno->blocknr * BLKSIZE);
1609  delete_dbb(inobno);
1610  return;
1611 }
1612 
1613 unsigned long long readBlock(unsigned long long blocknr,
1614  char *blockdata, size_t rsize,
1615  size_t block_offset, unsigned long long inode)
1616 {
1617  char *cachedata;
1618  DAT *cdata;
1619  DAT *data;
1620  INOBNO inobno;
1621  CCACHEDTA *ccachedta = NULL;
1622  DAT *tdata;
1623  int vsize;
1624  uintptr_t p;
1625  int locked;
1626  int ret = 0;
1627 
1628  inobno.inode = inode;
1629  inobno.blocknr = blocknr;
1630 
1631  locked = inode_isnot_locked(inode);
1632  write_lock((char *) __PRETTY_FUNCTION__);
1633  cachedata =
1634  (char *) tctreeget(readcachetree, (void *) &inobno, sizeof(INOBNO),
1635  &vsize);
1636  if (NULL == cachedata) {
1637  tdata = check_block_exists(&inobno);
1638  if (NULL == tdata) {
1640  return (0);
1641  }
1642  cdata = search_dbdata(DBDTA, tdata->data, tdata->size, LOCK);
1643  if (NULL == cdata) {
1644  auto_repair(&inobno);
1645  DATfree(tdata);
1647  return (0);
1648  }
1649  DATfree(tdata);
1650  data = lfsdecompress(cdata);
1651  if ( NULL == data ) die_dataerr("inode %llu - %llu failed to decompress block", inobno.inode,inobno.blocknr);
1652  LDEBUG("readBlock blocknr %llu comes from db", blocknr);
1653  if (block_offset < data->size) {
1654  if (rsize > data->size - block_offset) {
1655  memcpy(blockdata, data->data + block_offset,
1656  data->size - block_offset);
1657  } else {
1658  memcpy(blockdata, data->data + block_offset, rsize);
1659  }
1660  }
1661  DATfree(cdata);
1662 //---
1663 // Do not cache blocks as long as the inode is being truncated
1664  if (locked) {
1665 // When we read a block < BLKSIZE there it is likely that we need
1666 // to read it again so it makes sense to put it in a cache.
1667  if (rsize < BLKSIZE) {
1668 // Make sure that we don't overflow the cache.
1669  if (tctreernum(workqtree) * 2 > config->cachesize ||
1670  tctreernum(readcachetree) * 2 > config->cachesize) {
1671  flush_wait(inobno.inode);
1672  purge_read_cache(0, 1, (char *) __PRETTY_FUNCTION__);
1673  }
1674  ccachedta = s_zmalloc(sizeof(CCACHEDTA));
1675  p = (uintptr_t) ccachedta;
1676  ccachedta->dirty = 0;
1677  ccachedta->pending = 0;
1678  ccachedta->creationtime = time(NULL);
1679  memcpy(&ccachedta->data, data->data, data->size);
1680  ccachedta->datasize = data->size;
1681  tctreeput(readcachetree, (void *) &inobno, sizeof(INOBNO),
1682  (void *) &p, sizeof(unsigned long long));
1683  }
1684  }
1685 //---
1686  DATfree(data);
1688  ret = BLKSIZE;
1689  return (ret);
1690 // Fetch the block from disk and put it in the cache.
1691  }
1692  memcpy(&p, cachedata, vsize);
1693  ccachedta = get_ccachedta(p);
1694  ccachedta->creationtime = time(NULL);
1695  if (rsize > BLKSIZE - block_offset) {
1696  memcpy(blockdata, &ccachedta->data[block_offset],
1697  BLKSIZE - block_offset);
1698  } else {
1699  memcpy(blockdata, &ccachedta->data[block_offset], rsize);
1700  }
1701  ret = BLKSIZE;
1703  return (ret);
1704 }
1705 
1706 void delete_inuse(unsigned char *stiger)
1707 {
1708  loghash("delete_inuse", stiger);
1709  delete_key(DBU, stiger, config->hashlen, (char *) __PRETTY_FUNCTION__);
1710  return;
1711 }
1712 
1713 void delete_dbb(INOBNO * inobno)
1714 {
1715  LDEBUG("delete_dbb: %llu-%llu", inobno->inode, inobno->blocknr);
1716  delete_key(DBB, inobno, sizeof(INOBNO), (char *) __PRETTY_FUNCTION__);
1717  return;
1718 }
1719 
1720 /* Return the number of times this block is linked to files */
1721 unsigned long long getInUse(unsigned char *tigerstr)
1722 {
1723  unsigned long long counter;
1724  DAT *data;
1725 
1726  loghash("getInuse search", tigerstr);
1727  if (NULL == tigerstr) {
1728  LDEBUG("getInuse : return 0");
1729  return (0);
1730  }
1731 
1732  data = search_dbdata(DBU, tigerstr, config->hashlen, LOCK);
1733  if (NULL == data) {
1734  loghash("getInuse nothing found return 0 ", tigerstr);
1735  LDEBUG("getInuse nothing found return 0.");
1736  return (0);
1737  }
1738  memcpy(&counter, data->data, sizeof(counter));
1739  DATfree(data);
1740  LDEBUG("getInuse : return %llu", counter);
1741  return counter;
1742 }
1743 
1744 void DATfree(DAT * data)
1745 {
1746  s_free(data->data);
1747  s_free(data);
1748  data = NULL;
1749 }
1750 
1751 void update_inuse(unsigned char *hashdata, unsigned long long inuse)
1752 {
1753  loghash("update_inuse ", hashdata);
1754  if (inuse > 0) {
1755  bin_write_dbdata(DBU, hashdata, config->hashlen,
1756  (unsigned char *) &inuse,
1757  sizeof(unsigned long long));
1758  } else {
1759  LDEBUG("update_inuse : skip %llu", inuse);
1760  loghash("update_inuse : skip", hashdata);
1761  }
1762  EFUNC;
1763  return;
1764 }
1765 
1766 unsigned long long get_next_inode()
1767 {
1768  DAT *data;
1769  unsigned long long nextinode = 0;
1770  FUNC;
1771 
1772  data =
1773  search_dbdata(DBP, (unsigned char *) "NFI", strlen("NFI"), LOCK);
1774  if (data) {
1775  memcpy(&nextinode, data->data, sizeof(nextinode));
1776  DATfree(data);
1777  }
1778  LDEBUG("Found next inode number: %llu", nextinode);
1779  EFUNC;
1780  return (nextinode);
1781 }
1782 
1783 MEMDDSTAT *inode_meta_from_cache(unsigned long long inode)
1784 {
1785  const char *dataptr;
1786  int vsize;
1787 
1788  MEMDDSTAT *memddstat = NULL;
1789  dataptr =
1790  tctreeget(metatree, &inode, sizeof(unsigned long long), &vsize);
1791  if (dataptr == NULL) {
1792  LDEBUG("inode %llu not found to update.", inode);
1794  return NULL;
1795  }
1796  memddstat = value_tomem_ddstat((char *) dataptr, vsize);
1797  return memddstat;
1798 }
1799 
1800 void update_filesize_onclose(unsigned long long inode)
1801 {
1802  MEMDDSTAT *memddstat;
1803 
1804  LDEBUG("update_filesize_onclose : inode %llu", inode);
1805  memddstat = inode_meta_from_cache(inode);
1806  if (NULL == memddstat) {
1807  LDEBUG("inode %llu not found to update.", inode);
1808  return;
1809  }
1810  hash_update_filesize(memddstat, inode);
1811  memddstatfree(memddstat);
1812  return;
1813 }
1814 
1815 int update_filesize_cache(struct stat *stbuf, off_t size)
1816 {
1817  const char *data;
1818  DAT *dskdata;
1819  int vsize;
1820  MEMDDSTAT *memddstat;
1821  DDSTAT *ddstat = NULL;
1822  DAT *ddbuf;
1823  time_t thetime;
1824 
1825  thetime = time(NULL);
1826  LDEBUG("update_filesize_cache : %llu", stbuf->st_ino);
1827  meta_lock((char *) __PRETTY_FUNCTION__);
1828  data = tctreeget(metatree, &stbuf->st_ino,
1829  sizeof(unsigned long long), &vsize);
1830  if (data) {
1831  memddstat = (MEMDDSTAT *) data;
1832  memcpy(&memddstat->stbuf, stbuf, sizeof(struct stat));
1833  memddstat->stbuf.st_size = size;
1834  memddstat->stbuf.st_ctim.tv_sec = thetime;
1835  memddstat->stbuf.st_ctim.tv_nsec = 0;
1836  memddstat->stbuf.st_mtim.tv_sec = thetime;
1837  memddstat->stbuf.st_mtim.tv_nsec = 0;
1838  memddstat->stbuf.st_blocks = size / 512;
1839  if (512 * memddstat->stbuf.st_blocks < memddstat->stbuf.st_size)
1840  memddstat->stbuf.st_blocks++;
1841  memddstat->stbuf.st_mode = stbuf->st_mode;
1842  memddstat->updated = 1;
1843  ddbuf = create_mem_ddbuf(memddstat);
1844  tctreeput(metatree, &stbuf->st_ino,
1845  sizeof(unsigned long long), (void *) ddbuf->data,
1846  ddbuf->size);
1847  DATfree(ddbuf);
1848  } else {
1849  ddstatfree(ddstat);
1850  dskdata =
1851  search_dbdata(DBP, &stbuf->st_ino, sizeof(unsigned long long),
1852  LOCK);
1853  if (NULL == dskdata) {
1855  return (-ENOENT);
1856  }
1857  ddstat = value_to_ddstat(dskdata);
1858  ddstat->stbuf.st_mtim.tv_sec = thetime;
1859  ddstat->stbuf.st_mtim.tv_nsec = 0;
1860  ddstat->stbuf.st_ctim.tv_sec = thetime;
1861  ddstat->stbuf.st_ctim.tv_nsec = 0;
1862  ddstat->stbuf.st_size = size;
1863  ddstat->stbuf.st_mode = stbuf->st_mode;
1864  ddstat->stbuf.st_blocks = stbuf->st_size / 512;
1865  if (512 * ddstat->stbuf.st_blocks < stbuf->st_size)
1866  ddstat->stbuf.st_blocks++;
1867  DATfree(dskdata);
1868  dskdata =
1869  create_ddbuf(ddstat->stbuf, ddstat->filename,
1870  ddstat->real_size);
1871  bin_write_dbdata(DBP, &stbuf->st_ino, sizeof(unsigned long long),
1872  (void *) dskdata->data, dskdata->size);
1873  DATfree(dskdata);
1874  }
1875  ddstatfree(ddstat);
1877  return (0);
1878 }
1879 
1880 void update_filesize(unsigned long long inode, unsigned long long fsize,
1881  unsigned int offsetblock, unsigned long long blocknr)
1882 {
1883  const char *dataptr;
1884  MEMDDSTAT *memddstat;
1885  DAT *ddbuf;
1886  int addblocks;
1887  INOBNO inobno;
1888  int vsize;
1889 
1890  meta_lock((char *) __PRETTY_FUNCTION__);
1891  LDEBUG
1892  ("update_filesize : inode %llu, filesize %llu, offsetblock %u, blocknr %llu",
1893  inode, fsize, offsetblock, blocknr);
1894  dataptr =
1895  tctreeget(metatree, &inode, sizeof(unsigned long long), &vsize);
1896  if (dataptr == NULL)
1897  goto endupdate;
1898  memddstat = (MEMDDSTAT *) dataptr;
1899  memddstat->updated++;
1900  memddstat->blocknr = blocknr;
1901  memddstat->stbuf.st_mtim.tv_sec = time(NULL);
1902  memddstat->stbuf.st_mtim.tv_nsec = 0;
1903 
1904  addblocks = fsize / 512;
1905  if ((memddstat->stbuf.st_blocks + addblocks) * 512 <
1906  memddstat->stbuf.st_size + fsize)
1907  addblocks++;
1908  // The file has not grown in size. This is an updated block.
1909  if (((blocknr * BLKSIZE) + offsetblock + fsize) <=
1910  memddstat->stbuf.st_size) {
1911  inobno.inode = inode;
1912  inobno.blocknr = blocknr;
1913  ddbuf = create_mem_ddbuf(memddstat);
1914  tctreeput(metatree, &inode, sizeof(unsigned long long),
1915  (void *) ddbuf->data, ddbuf->size);
1916  DATfree(ddbuf);
1917  goto endupdate;
1918  }
1919  if (blocknr < 1) {
1920  if (memddstat->stbuf.st_size < fsize + offsetblock)
1921  memddstat->stbuf.st_size = fsize + offsetblock;
1922  } else {
1923  if (memddstat->stbuf.st_size <
1924  (blocknr * BLKSIZE) + fsize + offsetblock)
1925  memddstat->stbuf.st_size =
1926  fsize + offsetblock + (blocknr * BLKSIZE);
1927  }
1928  if (memddstat->stbuf.st_size > (512 * memddstat->stbuf.st_blocks)) {
1929  memddstat->stbuf.st_blocks = memddstat->stbuf.st_size / 512;
1930  if (512 * memddstat->stbuf.st_blocks < memddstat->stbuf.st_size)
1931  memddstat->stbuf.st_blocks++;
1932  }
1933  ddbuf = create_mem_ddbuf(memddstat);
1934  tctreeput(metatree, &inode, sizeof(unsigned long long),
1935  (void *) ddbuf->data, ddbuf->size);
1936  DATfree(ddbuf);
1937  cache_p2i(memddstat->filename, &memddstat->stbuf);
1938 // Do not flush data until cachesize is reached
1939  if (memddstat->updated > config->cachesize) {
1940  hash_update_filesize(memddstat, inode);
1941  memddstat->updated = 0;
1942  ddbuf = create_mem_ddbuf(memddstat);
1943  tctreeput(metatree, &inode, sizeof(unsigned long long),
1944  (void *) ddbuf->data, ddbuf->size);
1945  DATfree(ddbuf);
1946  }
1947  endupdate:
1949  return;
1950 }
1951 
1952 void hash_update_filesize(MEMDDSTAT * memddstat, unsigned long long inode)
1953 {
1954  DAT *ddbuf;
1955 // Wait until the data queue is written before we update the filesize
1956  if (memddstat->stbuf.st_nlink > 1) {
1957  ddbuf = create_ddbuf(memddstat->stbuf, NULL, memddstat->real_size);
1958  } else {
1959  ddbuf =
1960  create_ddbuf(memddstat->stbuf, memddstat->filename,
1961  memddstat->real_size);
1962  }
1963  bin_write_dbdata(DBP, &inode,
1964  sizeof(unsigned long long), (void *) ddbuf->data,
1965  ddbuf->size);
1966  cache_p2i(memddstat->filename, &memddstat->stbuf);
1967  DATfree(ddbuf);
1968  return;
1969 }
1970 
1972 {
1973  DAT *data = NULL;
1974  FUNC;
1975  data = search_dbdata(DBB, inobno, sizeof(INOBNO), LOCK);
1976  EFUNC;
1977  return data;
1978 }
1979 
1980 int db_unlink_file(const char *path)
1981 {
1982  int res = 0;
1983  int haslinks = 0;
1984  int dir_links = 0;
1985  struct stat st;
1986  struct stat dirst;
1987  char *dname;
1988  char *bname;
1989  unsigned long long inode;
1990  time_t thetime;
1991  DAT *vdirnode;
1992  DAT *ddbuf;
1993  DAT *dataptr;
1994  DDSTAT *ddstat;
1995  DINOINO dinoino;
1996  INOBNO inobno;
1997  DAT *fname;
1998 
1999  FUNC;
2000 
2001  LDEBUG("unlink_file %s", path);
2002  res = dbstat(path, &st, 0);
2003  if (res == -ENOENT)
2004  return (res);
2005  inode = st.st_ino;
2006  haslinks = st.st_nlink;
2007  thetime = time(NULL);
2008  dname = s_dirname((char *) path);
2009  /* Change ctime and mtime of the parentdir Posix std posix behavior */
2010  res = update_parent_time(dname, 0);
2011  bname = s_basename((char *) path);
2012  res = dbstat(dname, &dirst, 1);
2013  if (S_ISLNK(st.st_mode) && haslinks == 1) {
2014  LDEBUG("unlink symlink %s inode %llu", path, inode);
2015  delete_key(DBS, &inode, sizeof(unsigned long long),
2016  (char *) __PRETTY_FUNCTION__);
2017  LDEBUG("unlink symlink done %s", path);
2018  }
2019  inobno.inode = inode;
2020  inobno.blocknr = st.st_size / BLKSIZE;
2021  if (inobno.blocknr * BLKSIZE < st.st_size)
2022  inobno.blocknr = 1 + st.st_size / BLKSIZE;
2023 // Start deleting the actual data blocks.
2024  db_fs_truncate(&st, 0, bname, 1);
2025  if (haslinks == 1) {
2026  if (0 !=
2027  (res =
2028  btdelete_curkey(DBDIRENT, &dirst.st_ino,
2029  sizeof(unsigned long long), &inode,
2030  sizeof(unsigned long long),
2031  (char *) __PRETTY_FUNCTION__))) {
2032  s_free(bname);
2033  s_free(dname);
2034  return (res);
2035  }
2036  delete_key(DBP, (unsigned char *) &inode,
2037  sizeof(unsigned long long),
2038  (char *) __PRETTY_FUNCTION__);
2039  } else {
2040  dataptr =
2041  search_dbdata(DBP, (unsigned char *) &inode,
2042  sizeof(unsigned long long), LOCK);
2043  if (dataptr == NULL) {
2044  die_dataerr("Failed to find file %llu", inode);
2045  }
2046  ddstat = value_to_ddstat(dataptr);
2047  ddstat->stbuf.st_nlink--;
2048  ddstat->stbuf.st_ctim.tv_sec = thetime;
2049  ddstat->stbuf.st_ctim.tv_nsec = 0;
2050  ddstat->stbuf.st_mtim.tv_sec = thetime;
2051  ddstat->stbuf.st_mtim.tv_nsec = 0;
2052  dinoino.dirnode = dirst.st_ino;
2053  dinoino.inode = ddstat->stbuf.st_ino;
2054  dir_links = count_dirlinks(&dinoino, sizeof(DINOINO));
2055  res =
2056  btdelete_curkey(DBL, &dinoino, sizeof(DINOINO), bname,
2057  strlen(bname), (char *) __PRETTY_FUNCTION__);
2058  btdelete_curkey(DBL, &ddstat->stbuf.st_ino,
2059  sizeof(unsigned long long), &dinoino,
2060  sizeof(DINOINO), (char *) __PRETTY_FUNCTION__);
2061 // Restore to regular file settings and clean up.
2062  if (ddstat->stbuf.st_nlink == 1) {
2063  vdirnode =
2064  btsearch_keyval(DBL, &ddstat->stbuf.st_ino,
2065  sizeof(unsigned long long), NULL, 0, LOCK);
2066  memcpy(&dinoino, vdirnode->data, vdirnode->size);
2067  DATfree(vdirnode);
2068  fname =
2069  btsearch_keyval(DBL, &dinoino, sizeof(DINOINO),
2070  NULL, 0, LOCK);
2071  memcpy(&ddstat->filename, fname->data, fname->size);
2072  DATfree(fname);
2073  btdelete_curkey(DBL, &dinoino, sizeof(DINOINO),
2074  ddstat->filename, strlen(ddstat->filename),
2075  (char *) __PRETTY_FUNCTION__);
2076  btdelete_curkey(DBL, &ddstat->stbuf.st_ino,
2077  sizeof(unsigned long long), &dinoino,
2078  sizeof(DINOINO), (char *) __PRETTY_FUNCTION__);
2079  btdelete_curkey(DBL, &inode, sizeof(unsigned long long),
2080  &dinoino, sizeof(DINOINO),
2081  (char *) __PRETTY_FUNCTION__);
2082  res = 0;
2083  }
2084  if (dir_links == 1) {
2085  if (0 !=
2086  (res =
2087  btdelete_curkey(DBDIRENT, &dirst.st_ino,
2088  sizeof(unsigned long long), &inode,
2089  sizeof(unsigned long long),
2090  (char *) __PRETTY_FUNCTION__))) {
2091  die_dataerr("unlink_file : Failed to delete record.");
2092  }
2093  }
2094  ddbuf =
2095  create_ddbuf(ddstat->stbuf, ddstat->filename,
2096  ddstat->real_size);
2097  bin_write_dbdata(DBP, &inode, sizeof(unsigned long long),
2098  (void *) ddbuf->data, ddbuf->size);
2099  DATfree(dataptr);
2100  DATfree(ddbuf);
2101  ddstatfree(ddstat);
2102  }
2103  s_free(bname);
2104  s_free(dname);
2105  EFUNC;
2106  return (res);
2107 }
2108 
2109 int fs_mkdir(const char *path, mode_t mode)
2110 {
2111  unsigned long long inode;
2112  char *rdir;
2113  char *pdir;
2114  int rootdir = 0;
2115  int res;
2116 
2117  FUNC;
2118  LDEBUG("mode =%i", mode);
2119  if (0 == strcmp("/", path))
2120  rootdir = 1;
2121  inode = get_next_inode();
2122  write_file_ent(path, inode, S_IFDIR | mode, NULL, 0);
2123  if (rootdir) {
2124  rdir = as_sprintf(__FILE__, __LINE__, "%s.", path);
2125  } else {
2126  rdir = as_sprintf(__FILE__, __LINE__, "%s/.", path);
2127  }
2128  inode = get_next_inode();
2129  write_file_ent(rdir, inode, S_IFDIR | 0755, NULL, 0);
2130  s_free(rdir);
2131  if (rootdir) {
2132  rdir = as_sprintf(__FILE__, __LINE__, "%s..", path);
2133  } else {
2134  rdir = as_sprintf(__FILE__, __LINE__, "%s/..", path);
2135  }
2136  inode = get_next_inode();
2137  write_file_ent(rdir, inode, S_IFDIR | 0755, NULL, 0);
2138  s_free(rdir);
2139  /* Change ctime and mtime of the parentdir Posix std posix behavior */
2140  pdir = s_dirname((char *) path);
2141  res = update_parent_time(pdir, 1);
2142  s_free(pdir);
2143  return (res);
2144 }
2145 
2146 DAT *tc_compress(unsigned char *dbdata, unsigned long dsize)
2147 {
2148  DAT *compressed;
2149  int rsize;
2150  char *data = NULL;
2151 
2152  compressed = s_malloc(sizeof(DAT));
2153  switch (config->compression) {
2154  case 'G':
2155  data = tcgzipencode((const char *) dbdata, dsize, &rsize);
2156  if (rsize > dsize)
2157  goto def;
2158  compressed->data = s_malloc(rsize + 1);
2159  compressed->data[0] = 'G';
2160  break;
2161  case 'B':
2162  data = tcbzipencode((const char *) dbdata, dsize, &rsize);
2163  if (rsize > dsize)
2164  goto def;
2165  compressed->data = s_malloc(rsize + 1);
2166  compressed->data[0] = 'B';
2167  break;
2168  case 'D':
2169  data = tcdeflate((const char *) dbdata, dsize, &rsize);
2170  if (rsize > dsize)
2171  goto def;
2172  compressed->data = s_malloc(rsize + 1);
2173  compressed->data[0] = 'D';
2174  break;
2175  default:
2176  def:
2177  if (data)
2178  s_free(data);
2179  compressed->data = s_malloc(dsize + 1);
2180  memcpy(&compressed->data[1], dbdata, dsize);
2181  compressed->data[0] = 0;
2182  compressed->size = dsize + 1;
2183  return compressed;
2184  }
2185  memcpy(&compressed->data[1], data, rsize);
2186  compressed->size = rsize + 1;
2187  s_free(data);
2188  return compressed;
2189 }
2190 
2191 DAT *lfscompress(unsigned char *dbdata, unsigned long dsize)
2192 {
2193  DAT *compressed = NULL;
2194 #ifdef ENABLE_CRYPTO
2195  DAT *encrypted;
2196 #endif
2197 
2198  switch (config->compression) {
2199  case 'L':
2200 #ifdef LZO
2201  compressed = (DAT *) lzo_compress(dbdata, dsize);
2202 #else
2203  LFATAL("lessfs is compiled without support for LZO");
2204  db_close(0);
2205  exit(EXIT_DATAERR);
2206 #endif
2207  break;
2208  case 'Q':
2209  compressed = (DAT *) clz_compress(dbdata, dsize);
2210  break;
2211  case 'R':
2212  compressed = (DAT *) clz15_compress(dbdata, dsize);
2213  break;
2214  case 'S':
2215 #ifdef SNAPPY
2216  compressed = (DAT *) lfssnappy_compress(dbdata, dsize);
2217 #else
2218  LFATAL("lessfs is compiled without support for SNAPPY");
2219  db_close(0);
2220  exit(EXIT_DATAERR);
2221 #endif
2222  break;
2223  default:
2224  compressed = (DAT *) tc_compress(dbdata, dsize);
2225  }
2226 
2227 #ifdef ENABLE_CRYPTO
2228  if (config->encryptdata) {
2229  encrypted = lfsencrypt(compressed->data, compressed->size);
2230  DATfree(compressed);
2231  return encrypted;
2232  }
2233 #endif
2234  return compressed;
2235 }
2236 
2237 unsigned int db_commit_block(unsigned char *dbdata,
2238  INOBNO inobno, unsigned long dsize)
2239 {
2240  unsigned char *stiger = NULL;
2241  DAT *compressed;
2242  unsigned long long inuse;
2243  unsigned int ret = 0;
2244 
2245  FUNC;
2246  LDEBUG("db_commit_block");
2247  stiger = thash(dbdata, dsize);
2248  create_hash_note(stiger);
2249  inuse = getInUse(stiger);
2250  if (0 == inuse) {
2251  compressed = lfscompress((unsigned char *) dbdata, dsize);
2252  ret = compressed->size;
2253  bin_write_dbdata(DBDTA, stiger, config->hashlen, compressed->data,
2254  compressed->size);
2255  DATfree(compressed);
2256  } else {
2257  loghash("commit_block : only updated inuse for hash ", stiger);
2258  }
2259  inuse++;
2260  update_inuse(stiger, inuse);
2261  LDEBUG("db_commit_block : dbb %llu-%llu", inobno.inode,
2262  inobno.blocknr);
2263  bin_write_dbdata(DBB, (char *) &inobno, sizeof(INOBNO), stiger,
2264  config->hashlen);
2265  delete_hash_note(stiger);
2266  s_free(stiger);
2267  return (ret);
2268 }
2269 
2270 void partial_truncate_block(unsigned long long inode,
2271  unsigned long long blocknr,
2272  unsigned int offset)
2273 {
2274  unsigned char *blockdata;
2275  DAT *uncompdata;
2276  INOBNO inobno;
2277  DAT *data;
2278 #ifdef ENABLE_CRYPTO
2279  DAT *encrypted;
2280 #endif
2281  unsigned char *stiger;
2282  unsigned long long inuse;
2283 
2284  FUNC;
2285  LDEBUG("partial_truncate_block : inode %llu, blocknr %llu, offset %u",
2286  inode, blocknr, offset);
2287  inobno.inode = inode;
2288  inobno.blocknr = blocknr;
2289 
2290  data = search_dbdata(DBB, &inobno, sizeof(INOBNO), LOCK);
2291  if (NULL == data) {
2292  LDEBUG("Deletion of non existent block?");
2293  return;
2294  }
2295  stiger = s_malloc(data->size);
2296  memcpy(stiger, data->data, data->size);
2297  DATfree(data);
2298  data = search_dbdata(DBDTA, stiger, config->hashlen, LOCK);
2299  if (NULL == data) {
2300  log_fatal_hash("Hmmm, did not expect this to happen.", stiger);
2301  die_dataerr("Hmmm, did not expect this to happen.");
2302  }
2303  create_hash_note(stiger);
2304  inuse = getInUse(stiger);
2305 //---
2306  blockdata = s_zmalloc(BLKSIZE);
2307  uncompdata = lfsdecompress(data);
2308  if ( NULL == uncompdata ) die_dataerr("partial_truncate_block: inode %llu - %llu failed to decompress block", inobno.inode,inobno.blocknr);
2309  if (uncompdata->size >= offset) {
2310  memcpy(blockdata, uncompdata->data, offset);
2311  } else {
2312  memcpy(blockdata, uncompdata->data, uncompdata->size);
2313  }
2314  DATfree(uncompdata);
2315  db_commit_block(blockdata, inobno, offset);
2316 //---
2317 
2318 // Not needed, is overwritten by db_commit_block.
2319 // delete_dbb(&inobno);
2320  if (inuse == 1) {
2321  loghash("partial_truncate_block : delete hash", stiger);
2322  delete_inuse(stiger);
2323  delete_key(DBDTA, stiger, config->hashlen,
2324  (char *) __PRETTY_FUNCTION__);
2325  } else {
2326  if (inuse > 1)
2327  inuse--;
2328  update_inuse(stiger, inuse);
2329  }
2330  DATfree(data);
2331  s_free(blockdata);
2332  delete_hash_note(stiger);
2333  s_free(stiger);
2334  return;
2335 }
2336 
2337 void *tc_truncate_worker(void *threadarg)
2338 {
2339  unsigned long long blocknr;
2340  unsigned long long lastblocknr;
2341  struct truncate_thread_data *trunc_data;
2342  unsigned char *stiger;
2343  DAT *data;
2344  unsigned long long inuse;
2345  INOBNO inobno;
2346  unsigned int offsetblock;
2347 
2348  trunc_data = (struct truncate_thread_data *) threadarg;
2349  lastblocknr = trunc_data->lastblocknr;
2350  blocknr = trunc_data->blocknr;
2351  offsetblock = trunc_data->offsetblock;
2352  inobno.blocknr = trunc_data->blocknr;
2353  inobno.inode = trunc_data->inode;
2354 
2355  FUNC;
2356  while (lastblocknr >= blocknr) {
2357  if (config->background_delete != 0) {
2358  truncation_wait();
2359  write_lock((char *) __PRETTY_FUNCTION__);
2360  }
2361  if (offsetblock != 0 && lastblocknr == blocknr) {
2362  if (config->background_delete != 0)
2364  break;
2365  }
2366  inobno.blocknr = lastblocknr;
2367  data = search_dbdata(DBB, &inobno, sizeof(INOBNO), LOCK);
2368  if (NULL == data) {
2369  LDEBUG
2370  ("Deletion of non existent block inode : %llu, blocknr %llu",
2371  inobno.inode, inobno.blocknr);
2372  if (lastblocknr > 0)
2373  lastblocknr--;
2374  else {
2375  if (config->background_delete != 0)
2377  break;
2378  }
2379 // Need to continue in case of a sparse file.
2380  if (config->background_delete != 0)
2382  continue;
2383  }
2384  stiger = s_malloc(data->size);
2385  memcpy(stiger, data->data, data->size);
2386  LDEBUG("lessfs_truncate Search to delete blocknr %llu:",
2387  lastblocknr);
2388  loghash("lessfs_truncate tiger :", stiger);
2389  DATfree(data);
2390  create_hash_note(stiger);
2391  delete_dbb(&inobno);
2392  inuse = getInUse(stiger);
2393  if (inuse == 1) {
2394  loghash("truncate : delete hash", stiger);
2395  delete_inuse(stiger);
2396  delete_key(DBDTA, stiger, config->hashlen,
2397  (char *) __PRETTY_FUNCTION__);
2398  } else {
2399  if (inuse > 1)
2400  inuse--;
2401  update_inuse(stiger, inuse);
2402  }
2403  delete_hash_note(stiger);
2404  s_free(stiger);
2405  if (lastblocknr > 0)
2406  lastblocknr--;
2407  if (config->background_delete) {
2409  if (config->shutdown) {
2410  LINFO("Truncation thread aborts truncating inode %llu",
2411  inobno.inode);
2412  pthread_exit(NULL);
2413  }
2414  }
2415  }
2416 
2417  if (0 != offsetblock) {
2418  if (config->background_delete != 0)
2419  write_lock((char *) __PRETTY_FUNCTION__);
2421  if (config->background_delete != 0)
2423  }
2424  delete_inode_note(inobno.inode);
2425  write_lock((char *) __PRETTY_FUNCTION__);
2426  btdelete_curkey(FREELIST, "TRNCTD", strlen("TRNCTD"), threadarg,
2427  sizeof(struct truncate_thread_data),
2428  (char *) __PRETTY_FUNCTION__);
2430  s_free(threadarg);
2431  EFUNC;
2432  if (config->background_delete == 0) {
2433  return NULL;
2434  } else
2435  pthread_exit(NULL);
2436 }
2437 
2438 struct tm *init_transactions()
2439 {
2440  INUSE *finuse;
2441  unsigned long long inuse;
2442  time_t tdate;
2443  struct tm *timeinfo = NULL;
2444  unsigned long replogsize;
2445  struct stat stbuf;
2446 
2447  if (config->transactions) {
2448  config->commithash =
2449  thash((unsigned char *) "COMMITSTAMP", strlen("COMMITSTAMP"));
2451  inuse = getInUse((unsigned char *) config->commithash);
2452  if (0 == inuse) {
2453  LFATAL("COMMITSTAMP not found");
2455  inuse = getInUse((unsigned char *) config->commithash);
2456  }
2457  tdate = inuse;
2458  } else {
2459  finuse = file_get_inuse((unsigned char *) config->commithash);
2460  if (NULL == finuse) {
2461  LFATAL
2462  ("COMMITSTAMP not found, upgrading the filesystem to support transactions");
2464  finuse =
2465  file_get_inuse((unsigned char *) config->commithash);
2466  }
2467  replogsize=finuse->size;
2468  if ( -1 == fstat(frepl, &stbuf)) die_syserr();
2469  if ( replogsize < stbuf.st_size ) {
2470  if ( -1 == ftruncate(frepl,replogsize) ) die_syserr();
2471  }
2472  tdate = finuse->inuse;
2473  if (finuse)
2474  s_free(finuse);
2475  }
2476  timeinfo = localtime(&tdate);
2477  }
2478  return timeinfo;
2479 }
2480 
2481 int update_parent_time(char *path, int linkcount)
2482 {
2483  int res;
2484  struct stat stbuf;
2485  time_t thetime;
2486 
2487  FUNC;
2488  LDEBUG("update_parent_time : %s", path);
2489  thetime = time(NULL);
2490  /* Change ctime and mtime of the parentdir Posix std posix behavior */
2491  res = dbstat(path, &stbuf, 0);
2492  if (0 != res)
2493  return (res);
2494  stbuf.st_ctim.tv_sec = thetime;
2495  stbuf.st_ctim.tv_nsec = 0;
2496  stbuf.st_mtim.tv_sec = thetime;
2497  stbuf.st_mtim.tv_nsec = 0;
2498  stbuf.st_nlink = stbuf.st_nlink + linkcount;
2499  res = update_stat(path, &stbuf);
2500  EFUNC;
2501  return (res);
2502 }
2503 
2504 int update_stat(char *path, struct stat *stbuf)
2505 {
2506  DDSTAT *ddstat;
2507  MEMDDSTAT *memddstat;
2508  DAT *ddbuf;
2509  DAT *dataptr;
2510  const char *cdata;
2511  int vsize;
2512  unsigned long long inode;
2513  int ret = 0;
2514 
2515  FUNC;
2516  inode = stbuf->st_ino;
2517 
2518  meta_lock((char *) __PRETTY_FUNCTION__);
2519  cdata = tctreeget(metatree, (unsigned char *) &inode,
2520  sizeof(unsigned long long), &vsize);
2521  if (cdata) {
2522  memddstat = (MEMDDSTAT *) cdata;
2523  memcpy(&memddstat->stbuf, stbuf, sizeof(struct stat));
2524  ddbuf = create_mem_ddbuf(memddstat);
2525  tctreeput(metatree, &inode, sizeof(unsigned long long),
2526  (void *) ddbuf->data, ddbuf->size);
2527  DATfree(ddbuf);
2528  goto unlock_return;
2529  }
2530  dataptr = search_dbdata(DBP, &inode, sizeof(unsigned long long), LOCK);
2531  if (dataptr == NULL) {
2532  ret = -ENOENT;
2533  goto unlock_return;
2534  }
2535  ddstat = value_to_ddstat(dataptr);
2536  memcpy(&ddstat->stbuf, stbuf, sizeof(struct stat));
2537  ddbuf =
2538  create_ddbuf(ddstat->stbuf, ddstat->filename, ddstat->real_size);
2539  bin_write_dbdata(DBP, &inode, sizeof(unsigned long long),
2540  (void *) ddbuf->data, ddbuf->size);
2541  DATfree(dataptr);
2542  ddstatfree(ddstat);
2543  DATfree(ddbuf);
2544  unlock_return:
2545  cache_p2i(path, stbuf);
2547  EFUNC;
2548  return (ret);
2549 }
2550 
2551 void db_close(bool defrag)
2552 {
2553 #ifdef BERKELEYDB
2554  bdb_close();
2555 #else
2556 #ifndef HAMSTERDB
2557  tc_close(defrag);
2558 #else
2559  hm_close(defrag);
2560 #endif
2561 #endif
2562 }
2563 
2564 void flush_wait(unsigned long long inode)
2565 {
2566  char *key;
2567  int size;
2568  int vsize;
2569  char *val;
2570  uintptr_t p;
2571  INOBNO *inobno;
2572  CCACHEDTA *ccachedta;
2573  TCLIST *keylist;
2574  int i;
2575 
2577  while (1) {
2578  LDEBUG("working=%lu - tctreernum = %llu", working,
2579  (unsigned long long) tctreernum(workqtree));
2580  if (working == 0 && 0 == tctreernum(workqtree))
2581  break;
2582  usleep(1);
2583  }
2584  write_lock((char *) __PRETTY_FUNCTION__);
2585  keylist = tctreekeys(readcachetree);
2586  inobnolistsort(keylist);
2587 
2588  for (i = 0; i < tclistnum(keylist); i++) {
2589  key = (char *) tclistval(keylist, i, &size);
2590  val =
2591  (char *) tctreeget(readcachetree, (void *) key, size, &vsize);
2592  if (val) {
2593  memcpy(&p, val, vsize);
2594  ccachedta = get_ccachedta(p);
2595  inobno = (INOBNO *) key;
2596  if (ccachedta->pending)
2597  continue;
2598  if (inode == inobno->inode || inode == 0) {
2599  if (ccachedta->dirty == 1 && ccachedta->pending != 1) {
2600  ccachedta->pending = 1;
2601  tctreeout(workqtree, key, size);
2602  LDEBUG("flush_wait : cook_cache %llu-%llu",
2603  inobno->inode, inobno->blocknr);
2604  cook_cache(key, size, ccachedta, 0 );
2605  ccachedta->dirty = 0;
2606  ccachedta->pending = 0;
2607  }
2608  }
2609  }
2610  }
2611  tclistdel(keylist);
2612  return;
2613 }
2614 
2615 void cook_cache(char *key, int ksize, CCACHEDTA * ccachedta, unsigned long sequence)
2616 {
2617  INOBNO *inobno;
2618  unsigned char *hash;
2619  inobno = (INOBNO *) key;
2620  LDEBUG("cook_cache : %llu-%llu", inobno->inode, inobno->blocknr);
2621  hash = thash((unsigned char *) &ccachedta->data, ccachedta->datasize);
2622  memcpy(&ccachedta->hash, hash, config->hashlen);
2623  free(hash);
2625  tc_write_cache(ccachedta, inobno);
2626  } else {
2627  fl_write_cache(ccachedta, inobno);
2628  }
2629  return;
2630 }
2631 
2632 unsigned long long get_inode(const char *path)
2633 {
2634  struct stat stbuf;
2635 
2636  FUNC;
2637  if (0 != dbstat(path, &stbuf, 1)) {
2638  LDEBUG("get_inode : nothing found for %s", path);
2639  return (0);
2640  }
2641  EFUNC;
2642  return (stbuf.st_ino);
2643 }
2644 
2645 void purge_read_cache(unsigned long long inode, bool force, char *caller)
2646 {
2647  char *key;
2648  int size;
2649  int vsize;
2650  char *val;
2651  uintptr_t p;
2652  INOBNO *inobno;
2653  CCACHEDTA *ccachedta;
2654  bool pending;
2655 
2656  restart:
2657  pending = 0;
2658  LDEBUG("purge_read_cache %llu", inode);
2659  tctreeiterinit(readcachetree);
2660  while (key = (char *) tctreeiternext(readcachetree, &size)) {
2661  val =
2662  (char *) tctreeget(readcachetree, (void *) key, size, &vsize);
2663  if (val) {
2664  memcpy(&p, val, vsize);
2665  ccachedta = get_ccachedta(p);
2666  inobno = (INOBNO *) key;
2667  if (ccachedta->pending) {
2668  pending = 1;
2669  continue;
2670  }
2671  if (ccachedta->dirty == 1) {
2672  if (inode == 0 || inode == inobno->inode) {
2673  ccachedta->pending = 1;
2674  LDEBUG("purge_read_cache : cook_cache %llu-%llu",
2675  inobno->inode, inobno->blocknr);
2676  cook_cache(key, size, ccachedta,0);
2677  tctreeout(workqtree, key, size);
2678  tctreeout(readcachetree, key, size);
2679  s_free(ccachedta);
2680  continue;
2681  }
2682  }
2683  if (inode == 0) {
2684  if (force) {
2685  tctreeout(readcachetree, key, size);
2686  s_free(ccachedta);
2687  } else {
2688  if (ccachedta->creationtime + CACHE_MAX_AGE <
2689  time(NULL)) {
2690  tctreeout(readcachetree, key, size);
2691  s_free(ccachedta);
2692  }
2693  }
2694  continue;
2695  }
2696  if (inode == inobno->inode) {
2697  if (force) {
2698  tctreeout(readcachetree, key, size);
2699  s_free(ccachedta);
2700  } else {
2701  if (ccachedta->creationtime + CACHE_MAX_AGE <
2702  time(NULL)) {
2703  tctreeout(readcachetree, key, size);
2704  s_free(ccachedta);
2705  }
2706  }
2707  }
2708  }
2709  }
2710  if (pending)
2711  goto restart;
2712  EFUNC;
2713  return;
2714 }
2715 
2716 void update_meta(unsigned long long inode, unsigned long size, int sign)
2717 {
2718  const char *data;
2719  int vsize;
2720  MEMDDSTAT *mddstat;
2721  DAT *statdata;
2722  DDSTAT *ddstat;
2723  DAT *ddbuf;
2724 
2725  LDEBUG("update_meta : inode %llu database.", inode);
2726  meta_lock((char *) __PRETTY_FUNCTION__);
2727  data = tctreeget(metatree, &inode, sizeof(unsigned long long), &vsize);
2728  if (data == NULL) {
2729  LDEBUG("meta update on inode not in cache");
2730  statdata =
2731  search_dbdata(DBP, &inode, sizeof(unsigned long long), LOCK);
2732  if (NULL == statdata)
2733  goto bailout;
2734  ddstat = value_to_ddstat(statdata);
2735  if (sign == 1) {
2736  ddstat->real_size = ddstat->real_size + size;
2737  } else {
2738  if (ddstat->real_size < size) {
2739  ddstat->real_size = 0;
2740  } else
2741  ddstat->real_size = ddstat->real_size - size;
2742  }
2743  ddbuf =
2744  create_ddbuf(ddstat->stbuf, ddstat->filename,
2745  ddstat->real_size);
2746  bin_write_dbdata(DBP, &inode, sizeof(unsigned long long),
2747  ddbuf->data, ddbuf->size);
2748 // cache_p2i(ddstat->filename, &ddstat->stbuf, NOLOCK);
2749  DATfree(statdata);
2750  ddstatfree(ddstat);
2751  DATfree(ddbuf);
2752  } else {
2753  mddstat = (MEMDDSTAT *) data;
2754  if (sign == 1) {
2755  mddstat->real_size = mddstat->real_size + size;
2756  } else {
2757  if (mddstat->real_size < size) {
2758  mddstat->real_size = 0;
2759  } else
2760  mddstat->real_size = mddstat->real_size - size;
2761  }
2762  tctreeput(metatree, &inode, sizeof(unsigned long long),
2763  (void *) mddstat, vsize);
2764  }
2765  bailout:
2766  EFUNC;
2768  return;
2769 }
2770 
2772 {
2773  unsigned long long ldate;
2774  time_t tdate;
2775  INUSE finuse;
2776  struct tm *timeinfo;
2777  struct stat stbuf;
2778 
2779  tdate = time(NULL);
2780  timeinfo = localtime(&tdate);
2781  ldate = tdate;
2782  LDEBUG("lessfs_trans_stamp : filesystem commit at %s",
2783  asctime(timeinfo));
2784  if ( -1 == fstat(frepl, &stbuf)) die_syserr();
2786  finuse.inuse = ldate;
2787  finuse.size = stbuf.st_size;
2788  finuse.offset = 0;
2789  finuse.allocated_size = 0;
2791  (unsigned char *) &finuse, sizeof(INUSE));
2792  } else {
2794  (unsigned char *) &ldate,
2795  sizeof(unsigned long long));
2796  }
2797  return;
2798 }
2799 
2800 int db_fs_truncate(struct stat *stbuf, off_t size, char *bname,
2801  bool unlink)
2802 {
2803  unsigned int offsetblock;
2804  unsigned long long blocknr;
2805  unsigned long long lastblocknr;
2806  off_t oldsize;
2807  time_t thetime;
2808  pthread_t truncate_thread;
2809  struct truncate_thread_data *trunc_data;
2810 
2811  FUNC;
2812 
2813  trunc_data = s_zmalloc(sizeof(struct truncate_thread_data));
2814  LDEBUG("lessfs_truncate inode %llu - size %llu", stbuf->st_ino,
2815  (unsigned long long) size);
2816  thetime = time(NULL);
2817  blocknr = size / BLKSIZE;
2818  offsetblock = size - (blocknr * BLKSIZE);
2819  oldsize = stbuf->st_size;
2820  lastblocknr = oldsize / BLKSIZE;
2821  LDEBUG
2822  ("db_fs_truncate : (got inode lock) truncate new block %llu, oldblock %llu size=%llu",
2823  blocknr, lastblocknr, size);
2824  trunc_data->inode = stbuf->st_ino;
2825  trunc_data->blocknr = blocknr;
2826  trunc_data->lastblocknr = lastblocknr;
2827  trunc_data->offsetblock = offsetblock;
2828  memcpy(&trunc_data->stbuf, stbuf, sizeof(struct stat));
2829  trunc_data->stbuf.st_size = size;
2830  trunc_data->unlink = unlink;
2831  if (!unlink)
2833  if (config->background_delete == 0) {
2834  tc_truncate_worker((void *) trunc_data);
2835  } else {
2836  write_trunc_todolist(trunc_data);
2837  if (0 !=
2838  pthread_create(&truncate_thread, NULL, tc_truncate_worker,
2839  (void *) trunc_data))
2840  die_syserr();
2841  if (0 != pthread_detach(truncate_thread))
2842  die_syserr();
2843  }
2844  return (0);
2845 }
2846 
2848 {
2849  char *key = "TRNCTD";
2850 
2851  FUNC;
2852  LDEBUG
2853  ("write_trunc_todolist : inode %llu : start %llu -> end %llu size %llu",
2854  trunc_data->inode, trunc_data->blocknr, trunc_data->lastblocknr,
2855  (unsigned long long) trunc_data->stbuf.st_size);
2856  btbin_write_dup(FREELIST, key, strlen(key),
2857  (unsigned char *) trunc_data,
2858  sizeof(struct truncate_thread_data), LOCK);
2859  EFUNC;
2860  return;
2861 }
2862 
2863 void tc_write_cache(CCACHEDTA * ccachedta, INOBNO * inobno)
2864 {
2865  unsigned long long inuse;
2866  DAT *compressed;
2867 
2868  create_hash_note((unsigned char *) &ccachedta->hash);
2869  db_delete_stored(inobno);
2870  inuse = getInUse((unsigned char *) &ccachedta->hash);
2871  if (inuse == 0) {
2872  compressed = lfscompress(ccachedta->data, ccachedta->datasize);
2873  bin_write_dbdata(DBDTA, &ccachedta->hash, config->hashlen,
2874  compressed->data, compressed->size);
2875  if (ccachedta->newblock == 1)
2876  update_meta(inobno->inode, compressed->size, 1);
2877  if (ccachedta->updated != 0) {
2878  if (compressed->size > ccachedta->updated) {
2879  update_meta(inobno->inode,
2880  compressed->size - ccachedta->updated, 1);
2881  } else {
2882  update_meta(inobno->inode,
2883  ccachedta->updated - compressed->size, 0);
2884  }
2885  }
2886  DATfree(compressed);
2887  }
2888  inuse++;
2889  update_inuse((unsigned char *) &ccachedta->hash, inuse);
2890  bin_write_dbdata(DBB, (char *) inobno, sizeof(INOBNO), ccachedta->hash,
2891  config->hashlen);
2892  delete_hash_note((unsigned char *) &ccachedta->hash);
2893  ccachedta->dirty = 0;
2894  ccachedta->pending = 0;
2895  ccachedta->newblock = 0;
2896  return;
2897 }
2898 
2899 void db_delete_stored(INOBNO * inobno)
2900 {
2901  unsigned long long inuse;
2902  unsigned char *hash;
2903  DAT *data;
2904 
2905  data = search_dbdata(DBB, inobno, sizeof(INOBNO), LOCK);
2906  if (NULL == data)
2907  return;
2908  hash = data->data;
2909  delete_dbb(inobno);
2910  inuse = getInUse(hash);
2911  if (inuse <= 1) {
2912  delete_inuse(hash);
2913  delete_key(DBDTA, hash, config->hashlen, NULL);
2914  if (config->replication == 1 && config->replication_role == 0) {
2915  write_repl_data(DBDTA, REPLDELETE, (char *) hash,
2916  config->hashlen, NULL, 0,
2917  MAX_ALLOWED_THREADS - 2);
2918  }
2919  } else {
2920  inuse--;
2921  update_inuse(hash, inuse);
2922  }
2923  DATfree(data);
2924  return;
2925 }
2926 
2927 void fil_fuse_info(DDSTAT * ddstat, void *buf, fuse_fill_dir_t filler,
2928  struct fuse_file_info *fi)
2929 {
2930  struct stat st;
2931  char *bname;
2932 
2933  memcpy(&st, &ddstat->stbuf, sizeof(struct stat));
2934  bname = s_basename(ddstat->filename);
2935  if (bname) {
2936  // Don't show the directory
2937  if (0 != strcmp(bname, "/")) {
2938  filler(buf, bname, &st, 0);
2939  }
2940  }
2941  s_free(bname);
2942 }
2943 
2944 void locks_to_dir(void *buf, fuse_fill_dir_t filler,
2945  struct fuse_file_info *fi)
2946 {
2947  struct stat stbuf;
2948  char *bname;
2949  const char *key;
2950  unsigned long long inode;
2951  int size;
2952 
2953  FUNC;
2954  get_inode_lock((char *) __PRETTY_FUNCTION__);
2955  tctreeiterinit(inodetree);
2956  while (key = tctreeiternext(inodetree, &size)) {
2957  memcpy(&inode, key, sizeof(unsigned long long));
2958  bname = as_sprintf(__FILE__, __LINE__, "%llu", inode);
2959  lckname_to_stat(bname, &stbuf);
2960  filler(buf, bname, &stbuf, 0);
2961  s_free(bname);
2962  }
2963  EFUNC;
2965  return;
2966 }
2967 
2968 int lckname_to_stat(char *path, struct stat *stbuf)
2969 {
2970  const char *data;
2971  time_t thetime;
2972  int vsize;
2973  unsigned long long inode;
2974 
2975  FUNC;
2976  sscanf(path, "%llu", &inode);
2977  data = tctreeget(inodetree, &inode,
2978  sizeof(unsigned long long), &vsize);
2979  if (NULL == data)
2980  return (-ENOENT);
2981  stbuf->st_ino = inode;
2982  stbuf->st_dev = 999988;
2983  stbuf->st_mode = 33060;
2984  stbuf->st_nlink = 1;
2985  stbuf->st_uid = 0;
2986  stbuf->st_gid = 0;
2987  stbuf->st_size = 0;
2988  stbuf->st_blocks = 1;
2989  stbuf->st_blksize = BLKSIZE;
2990  thetime = time(NULL);
2991  stbuf->st_atim.tv_sec = thetime;
2992  stbuf->st_atim.tv_nsec = 0;
2993  stbuf->st_mtim.tv_sec = thetime;
2994  stbuf->st_mtim.tv_nsec = 0;
2995  stbuf->st_ctim.tv_sec = thetime;
2996  stbuf->st_ctim.tv_nsec = 0;
2997  EFUNC;
2998  return (0);
2999 }
3000 
3001 int fs_link(char *from, char *to)
3002 {
3003  int res = 0;
3004  unsigned long long inode;
3005  unsigned long long todirnode;
3006  unsigned long long fromdirnode;
3007  struct stat stbuf;
3008  struct stat tobuf;
3009  struct stat frombuf;
3010  char *bfrom;
3011  char *bto;
3012  char *todir;
3013  char *fromdir;
3014  DAT *ddbuf;
3015  DAT *symdata;
3016  time_t thetime;
3017  DINOINO dinoino;
3018  const char *data;
3019  int vsize;
3020  MEMDDSTAT *memddstat;
3021 
3022  FUNC;
3023  LDEBUG("fs_link called with from=%s to=%s", from, to);
3024  res = dbstat(from, &stbuf, 0);
3025 
3026  if (res != 0)
3027  return (res);
3028  fromdir = s_dirname(from);
3029  res = dbstat(fromdir, &frombuf, 1);
3030  todir = s_dirname(to);
3031  res = dbstat(todir, &tobuf, 0);
3032  if (res != 0) {
3033  s_free(todir);
3034  s_free(fromdir);
3035  return -ENOENT;
3036  }
3037  bfrom = s_basename(from);
3038  bto = s_basename(to);
3039 /* Update inode nrlinks */
3040  todirnode = tobuf.st_ino;
3041  fromdirnode = frombuf.st_ino;
3042  inode = stbuf.st_ino;
3043  // Update nr of links.
3044  if (stbuf.st_nlink == 1)
3045  invalidate_p2i(from);
3046  stbuf.st_nlink++;
3047  thetime = time(NULL);
3048 
3049  meta_lock((char *) __PRETTY_FUNCTION__);
3050  data = tctreeget(metatree, &stbuf.st_ino,
3051  sizeof(unsigned long long), &vsize);
3052  stbuf.st_ctim.tv_sec = thetime;
3053  stbuf.st_ctim.tv_nsec = 0;
3054  if (data) {
3055  memddstat = (MEMDDSTAT *) data;
3056  memddstat->stbuf.st_ctim.tv_sec = thetime;
3057  memddstat->stbuf.st_ctim.tv_nsec = 0;
3058  memddstat->stbuf.st_mtim.tv_sec = thetime;
3059  memddstat->stbuf.st_mtim.tv_nsec = 0;
3060  memddstat->stbuf.st_nlink++;
3061  memddstat->updated = 1;
3062  //memset(&memddstat->filename,0,2);
3063  ddbuf = create_mem_ddbuf(memddstat);
3064  tctreeput(metatree, &stbuf.st_ino,
3065  sizeof(unsigned long long), (void *) ddbuf->data,
3066  ddbuf->size);
3067  DATfree(ddbuf);
3068  }
3070  ddbuf = create_ddbuf(stbuf, NULL, 0);
3071  LDEBUG("fs_link : update links on %llu to %i", inode, stbuf.st_nlink);
3072  bin_write_dbdata(DBP, &inode, sizeof(unsigned long long),
3073  ddbuf->data, ddbuf->size);
3074  DATfree(ddbuf);
3075 /* Link dest filename inode to dest directory if it does not exist*/
3076  if (0 ==
3077  bt_entry_exists(DBDIRENT, &todirnode, sizeof(unsigned long long),
3078  &inode, sizeof(unsigned long long))) {
3079  LDEBUG("fs_link : write link %llu : %llu", todirnode, inode);
3080  btbin_write_dup(DBDIRENT, &todirnode, sizeof(unsigned long long),
3081  &inode, sizeof(unsigned long long), LOCK);
3082  }
3083 
3084 /* Link some more, hardlink a symlink. */
3085  if (S_ISLNK(stbuf.st_mode)) {
3086  LDEBUG("fs_link : hardlink a symlink");
3087  symdata =
3088  search_dbdata(DBS, &inode, sizeof(unsigned long long), LOCK);
3089  if (NULL == symdata)
3090  die_dataerr("Unable to read symlink");
3091  DATfree(symdata);
3092  }
3093 /* Write L_destinodedir_inode : dest filename */
3094  dinoino.dirnode = tobuf.st_ino;
3095  dinoino.inode = stbuf.st_ino;
3096  LDEBUG("A. fs_link : write link %llu-%llu : %s", tobuf.st_ino,
3097  stbuf.st_ino, bto);
3098  btbin_write_dup(DBL, &dinoino, sizeof(DINOINO), bto, strlen(bto),
3099  LOCK);
3100  btbin_write_dup(DBL, &stbuf.st_ino, sizeof(unsigned long long),
3101  &dinoino, sizeof(DINOINO), LOCK);
3102 
3103 /* Write Lfrominode_inode : from filename */
3104  dinoino.dirnode = frombuf.st_ino;
3105  dinoino.inode = stbuf.st_ino;
3106  if (stbuf.st_nlink == 2) {
3107  btbin_write_dup(DBL, &dinoino, sizeof(DINOINO), bfrom,
3108  strlen(bfrom), LOCK);
3109  btbin_write_dup(DBL, &stbuf.st_ino, sizeof(unsigned long long),
3110  &dinoino, sizeof(DINOINO), LOCK);
3111  }
3112  res = update_parent_time(todir, 0);
3113  s_free(todir);
3114  s_free(fromdir);
3115  s_free(bfrom);
3116  s_free(bto);
3117  EFUNC;
3118  return (res);
3119 }
3120 
3121 int fs_rename_link(const char *from, const char *to, struct stat stbuf)
3122 {
3123  unsigned long long fromnode;
3124  unsigned long long tonode;
3125  unsigned long long inode;
3126  char *fromdir;
3127  char *todir;
3128  char *bfrom;
3129  char *bto;
3130  struct stat st;
3131  int res = 0;
3132  DINOINO dinoino;
3133 
3134  FUNC;
3135 
3136  LDEBUG("fs_rename_link from: %s : to %s", (char *) from, (char *) to);
3137  if (0 == strcmp(from, to))
3138  return (0);
3139  if (-ENOENT != dbstat(to, &st, 0)) {
3141  db_unlink_file(to);
3142  } else {
3143  file_unlink_file(to);
3144  }
3145  }
3146  fromdir = s_dirname((char *) from);
3147  todir = s_dirname((char *) to);
3148  bfrom = s_basename((char *) from);
3149  bto = s_basename((char *) to);
3150  inode = stbuf.st_ino;
3151 
3152  fromnode = get_inode(fromdir);
3153  tonode = get_inode(todir);
3154  if (0 == fromnode)
3155  die_dataerr("Unable to find directory %s for file %s", fromdir,
3156  from);
3157  if (0 == tonode)
3158  die_dataerr("Unable to find directory %s for file %s", todir, to);
3159 
3160  dinoino.dirnode = fromnode;
3161  dinoino.inode = stbuf.st_ino;
3162  btdelete_curkey(DBL, &dinoino, sizeof(DINOINO), bfrom, strlen(bfrom),
3163  (char *) __PRETTY_FUNCTION__);
3164  if (count_dirlinks(&dinoino, sizeof(DINOINO)) > 1) {
3165  btdelete_curkey(DBDIRENT, &fromnode, sizeof(unsigned long long),
3166  &inode, sizeof(unsigned long long),
3167  (char *) __PRETTY_FUNCTION__);
3168  btbin_write_dup(DBDIRENT, &tonode, sizeof(unsigned long long),
3169  &inode, sizeof(unsigned long long), LOCK);
3170  }
3171  dinoino.dirnode = tonode;
3172  dinoino.inode = stbuf.st_ino;
3173  btbin_write_dup(DBL, &dinoino, sizeof(DINOINO), bto, strlen(bto),
3174  LOCK);
3175  s_free(fromdir);
3176  s_free(bfrom);
3177  s_free(bto);
3178  s_free(todir);
3179  EFUNC;
3180  return (res);
3181 }
3182 
3183 int fs_rename(const char *from, const char *to, struct stat stbuf)
3184 {
3185  DAT *dataptr;
3186  DDSTAT *ddstat;
3187  DAT *ddbuf;
3188  int res = 0;
3189  unsigned long long inode;
3190  time_t thetime;
3191  char *bto;
3192  char *bfrom;
3193  char *fromdir;
3194  char *todir;
3195  unsigned long long fromdirnode;
3196  unsigned long long todirnode;
3197  unsigned long long tonode;
3198  struct stat st;
3199  unsigned long long dirnodes;
3200 
3201  FUNC;
3202 
3203  LDEBUG("fs_rename from: %s : to %s", (char *) from, (char *) to);
3204  todir = s_dirname((char *) to);
3205  todirnode = get_inode(todir);
3206  tonode = get_inode(to);
3207  bto = s_basename((char *) to);
3208  bfrom = s_basename((char *) from);
3209  if (-ENOENT != dbstat(to, &st, 0)) {
3210  if (S_ISDIR(st.st_mode)) {
3211  LDEBUG("fs_rename bto %s bfrom %s", bto, bfrom);
3212  dirnodes = has_nodes(tonode);
3213  if (0 != dirnodes) {
3214  if (0 != strcmp(bto, bfrom)) {
3215  LDEBUG
3216  ("fs_rename : Cannot rename directory %llu with %llu files",
3217  todirnode, dirnodes);
3218  s_free(todir);
3219  s_free(bfrom);
3220  s_free(bto);
3221  EFUNC;
3222  return -ENOTEMPTY;
3223  }
3224  }
3225  fs_rmdir(to);
3226  } else {
3227  LDEBUG("fs_rename : destination file %s exists, unlink_file.",
3228  to);
3230  db_unlink_file(to);
3231  } else {
3232  file_unlink_file(to);
3233  }
3234  }
3235  }
3236  s_free(bfrom);
3237  inode = stbuf.st_ino;
3238  fromdir = s_dirname((char *) from);
3239  fromdirnode = get_inode(fromdir);
3240  LDEBUG("fs_rename : bto = %s", bto);
3241  dataptr = search_dbdata(DBP, &inode, sizeof(unsigned long long), LOCK);
3242  if (dataptr == NULL) {
3243  die_dataerr("Failed to find file %llu", inode);
3244  }
3245  ddstat = value_to_ddstat(dataptr);
3246  thetime = time(NULL);
3247  ddstat->stbuf.st_ctim.tv_sec = thetime;
3248  ddstat->stbuf.st_ctim.tv_nsec = 0;
3249  ddbuf = create_ddbuf(ddstat->stbuf, (char *) bto, ddstat->real_size);
3250  bin_write_dbdata(DBP, &inode,
3251  sizeof(unsigned long long), (void *) ddbuf->data,
3252  ddbuf->size);
3253  if (fromdirnode != todirnode) {
3254  LDEBUG("fs_rename : rename inode %llu : %llu to another path %llu",
3255  inode, fromdirnode, todirnode);
3256  btdelete_curkey(DBDIRENT, &fromdirnode, sizeof(unsigned long long),
3257  &inode, sizeof(unsigned long long),
3258  (char *) __PRETTY_FUNCTION__);
3259  btbin_write_dup(DBDIRENT, &todirnode, sizeof(unsigned long long),
3260  &inode, sizeof(unsigned long long), LOCK);
3261  }
3262  DATfree(dataptr);
3263  DATfree(ddbuf);
3264  ddstatfree(ddstat);
3265  s_free(bto);
3266  s_free(fromdir);
3267  s_free(todir);
3268  EFUNC;
3269  return (res);
3270 }
3271 
3272 int fs_rmdir(const char *path)
3273 {
3274  int res;
3275  char *dotstr;
3276  char *dotdotstr;
3277  char *dname;
3278  unsigned long long dirnode;
3279  unsigned long long keynode;
3280  unsigned long long pathnode;
3281  unsigned long long dirnodes;
3282 
3283  FUNC;
3284  LDEBUG("rmdir called : %s", path);
3285 
3286  pathnode = get_inode(path);
3287  dirnodes = has_nodes(pathnode);
3288  if (0 != dirnodes) {
3289  LDEBUG("fs_rmdir : Cannot remove directory %s with %llu files",
3290  path, dirnodes);
3291  EFUNC;
3292  return -ENOTEMPTY;
3293  }
3294 
3295  dname = s_dirname((char *) path);
3296  dotstr = as_sprintf(__FILE__, __LINE__, "%s/.", path);
3297  dotdotstr = as_sprintf(__FILE__, __LINE__, "%s/..", path);
3298  invalidate_p2i((char *) dotstr);
3299  invalidate_p2i((char *) dotdotstr);
3300 
3301  keynode = get_inode(dotstr);
3302  LDEBUG("inode for %s is %llu", dotstr, keynode);
3303  delete_key(DBP, &keynode, sizeof(unsigned long long),
3304  (char *) __PRETTY_FUNCTION__);
3305  btdelete_curkey(DBDIRENT, &pathnode, sizeof(unsigned long long),
3306  &keynode, sizeof(unsigned long long),
3307  (char *) __PRETTY_FUNCTION__);
3308  keynode = get_inode(dotdotstr);
3309  delete_key(DBP, &keynode, sizeof(unsigned long long),
3310  (char *) __PRETTY_FUNCTION__);
3311  btdelete_curkey(DBDIRENT, &pathnode, sizeof(unsigned long long),
3312  &keynode, sizeof(unsigned long long),
3313  (char *) __PRETTY_FUNCTION__);
3314 
3315  dirnode = get_inode(dname);
3316  delete_key(DBP, &pathnode, sizeof(unsigned long long),
3317  (char *) __PRETTY_FUNCTION__);
3318  btdelete_curkey(DBDIRENT, &dirnode, sizeof(unsigned long long),
3319  &pathnode, sizeof(unsigned long long),
3320  (char *) __PRETTY_FUNCTION__);
3321  btdelete_curkey(DBDIRENT, &pathnode, sizeof(unsigned long long),
3322  &pathnode, sizeof(unsigned long long),
3323  (char *) __PRETTY_FUNCTION__);
3324  s_free(dotstr);
3325  s_free(dotdotstr);
3326  res = update_parent_time(dname, -1);
3327  s_free(dname);
3328  return (res);
3329 }
3330 
3332 {
3333  unsigned char *stiger;
3334  char *brand;
3335  brand = as_sprintf(__FILE__, __LINE__, "LESSFS_DIRTY");
3336  stiger = thash((unsigned char *) brand, strlen(brand));
3337  delete_key(DBU, stiger, config->hashlen, NULL);
3338  free(stiger);
3339  s_free(brand);
3340  return;
3341 }
3342 
3343 void parseconfig(int mklessfs, bool force_optimize)
3344 {
3345  char *cache, *flushtime;
3346  unsigned int cs = 0;
3347  unsigned long calc;
3348 #ifdef ENABLE_CRYPTO
3349  unsigned long long pwl = 0;
3350  unsigned char *stiger;
3351  DAT *ivdb;
3352  CRYPTO *crypto;
3353 #endif
3354  char *iv;
3355  char *dbpath;
3356  struct stat stbuf;
3357 
3358  FUNC;
3359  config = s_zmalloc(sizeof(struct configdata));
3360  config->shutdown = 0;
3361  config->chunk_depth=2;
3362  if (iv=getenv("CHUNK_DEPTH")) {
3363  config->chunk_depth=atoi(iv);
3364  if ( config->chunk_depth <= 1 ) config->chunk_depth=2;
3365  if ( config->chunk_depth > MAX_CHUNK_DEPTH ) {
3366  LFATAL("CHUNK_DEPTH > %i, if you really want this change MAX_CHUNK_DEPTH",MAX_CHUNK_DEPTH);
3368  }
3369  }
3370  config->reclaim = 0;
3371  config->bdb_private = 0;
3372  iv=getenv("BLKSIZE");
3373  if (iv) BLKSIZE=atoi(iv);
3374  if ( BLKSIZE < 4096 || BLKSIZE > 131072 ) {
3375  die_dataerr("Invalid BLKSIZE specified.\n");
3376  } else LINFO("Blocksize = %u bytes",BLKSIZE);
3378  iv = getenv("TUNEFORSIZE");
3379  if (iv) {
3380  if ( 0 == strcasecmp("medium",iv)) config->tune_for_size=LFSMEDIUM;
3381  if ( 0 == strcasecmp("huge",iv)) config->tune_for_size=LFSHUGE;
3382  }
3383  if (NULL == getenv("MIN_SPACE_CLEAN")) {
3384  config->nospace = 1;
3385  LINFO
3386  ("MIN_SPACE_CLEAN is not set, lessfs runs -ENOSPC when reaching MIN_SPACE_FREE");
3387  } else
3388  config->nospace = 0;
3389  iv=getenv("BDB_PRIVATE");
3390  if (iv) {
3391  if ( 0 == strcasecmp("on",iv)) config->bdb_private=1;
3392  }
3393  config->frozen = 0;
3394  config->safe_down = 0;
3395  config->max_backlog_size = 0;
3396  config->tuneforspeed = 0;
3397  config->replication_watchdir = NULL;
3398  config->replication_last_rotated = time(NULL);
3399 // BLOCKDATA_IO_TYPE tokyocabinet (default), file_io
3400  config->blockdata = read_val("BLOCKDATA_PATH");
3402  iv = getenv("BLOCKDATA_IO_TYPE");
3403  if (NULL == iv) {
3405  LINFO("The selected data store is file_io.");
3406  } else {
3407  if (0 == strncasecmp(iv, "file_io", strlen("file_io"))) {
3409  config->blockdatabs = NULL;
3410 #ifdef BERKELEYDB
3411  iv = getenv("TUNEFORSPEED");
3412  if (iv) {
3413  if (0 == strncasecmp(iv, "yes", strlen("yes"))) {
3414  config->tuneforspeed = 1;
3415  LINFO("Warning : tuneforspeed may cause loss of data");
3416  LINFO
3417  ("Read the Berkeleydb documentation about DB_TXN_WRITE_NOSYNC");
3418  }
3419  }
3420 #endif
3421  LINFO("The selected data store is file_io.");
3422  } else {
3423  if (0 == strncasecmp(iv, "chunk_io", strlen("chunk_io"))) {
3425  config->blockdatabs = NULL;
3426  LINFO("The selected data store is chunk_io.");
3427  } else {
3428  if ( 0 != mklessfs ) fprintf(stderr,"Using tokyocabinet as datastore is deprecated!\n");
3429  LINFO("The selected data store is tokyocabinet.");
3430  config->blockdatabs = read_val("BLOCKDATA_BS");
3431  }
3432  }
3433  }
3434 #ifndef BERKELEYDB
3435 #ifndef HAMSTERDB
3436  if ( 0 != mklessfs ) {
3437  fprintf(stderr,"Using tokyocabinet is DEPRECATED and no longer recommended. Please consider using (1) Berkeley DB or (2) Hamsterdb.\n");
3438  }
3439 #endif
3440 #endif
3441 #ifdef BERKELEYDB
3443  if ( 0 != mklessfs ) fprintf(stderr,"Configuration error : berkeleydb only supports file_io or chunk_io\n");
3444  die_dataerr
3445  ("Configuration error : berkeleydb only supports file_io or chunk_io");
3446  }
3447 #endif
3448 #ifdef HAMSTERDB
3450  if ( 0 != mklessfs ) fprintf(stderr,"Configuration error : hamsterdb only supports file_io or chunk_io\n");
3451  die_dataerr
3452  ("Configuration error : hamsterdb only supports file_io or chunk_io");
3453  }
3454 #endif
3455  iv = getenv("MAX_BACKLOG_SIZE");
3456  if (iv) {
3457  sscanf(iv, "%lu", &config->max_backlog_size);
3458  LINFO("The maximum backlog size is %lu bytes",
3460  }
3461  iv = getenv("ENABLE_TRANSACTIONS");
3462  if (NULL == iv) {
3463  config->transactions = 0;
3464  LINFO("Lessfs transaction support is disabled.");
3465  } else {
3466  if (0 == strncasecmp(iv, "on", strlen("on"))) {
3467  config->transactions = 1;
3468  LINFO("Lessfs transaction support is enabled.");
3469  } else {
3470  config->transactions = 0;
3471  LINFO("Lessfs transaction support is disabled.");
3472  }
3473  }
3474 #ifdef BERKELEYDB
3475  config->meta = read_val("META_PATH");
3476 #else
3477 #ifdef HAMSTERDB
3478  config->meta = read_val("META_PATH");
3479 #else
3480  config->freelist = read_val("FREELIST_PATH");
3481  config->freelistbs = read_val("FREELIST_BS");
3482  config->blockusage = read_val("BLOCKUSAGE_PATH");
3483  config->blockusagebs = read_val("BLOCKUSAGE_BS");
3484  config->dirent = read_val("DIRENT_PATH");
3485  config->direntbs = read_val("DIRENT_BS");
3486  config->fileblock = read_val("FILEBLOCK_PATH");
3487  config->fileblockbs = read_val("FILEBLOCK_BS");
3488  config->meta = read_val("META_PATH");
3489  config->metabs = read_val("META_BS");
3490  config->hardlink = read_val("HARDLINK_PATH");
3491  config->hardlinkbs = read_val("HARDLINK_BS");
3492  config->symlink = read_val("SYMLINK_PATH");
3493  config->symlinkbs = read_val("SYMLINK_BS");
3494 #endif
3495 #endif
3496  LINFO("config->blockdata = %s", config->blockdata);
3497 
3498  config->encryptdata = 0;
3499  config->encryptmeta = 1;
3500  config->hashlen = 24;
3501  config->hash = "MHASH_TIGER192";
3502  config->selected_hash = MHASH_TIGER192;
3503  config->compression = 'Q';
3504 // Background delete is now enabled by default
3506  config->sticky_on_locked = 0;
3507  iv = getenv("COMPRESSION");
3508  if (iv) {
3509  LINFO("compression = %s",iv);
3510 #ifdef SNAPPY
3511  if (0 == strcasecmp("snappy", iv))
3512  config->compression = 'S';
3513 #else
3514  if (0 == strcasecmp("snappy", iv))
3515  die_dataerr
3516  ("SNAPPY support is not available: please configure with --with-snappy");
3517 #endif
3518  if (0 == strcasecmp("qlz151", iv))
3519  config->compression = 'P';
3520  if (0 == strcasecmp("qlz", iv))
3521  config->compression = 'Q';
3522  if (0 == strcasecmp("qlz141", iv))
3523  config->compression = 'Q';
3524 #ifdef LZO
3525  if (0 == strcasecmp("lzo", iv))
3526  config->compression = 'L';
3527 #else
3528  if (0 == strcasecmp("lzo", iv))
3529  die_dataerr
3530  ("LZO support is not available: please configure with --with-lzo");
3531 #endif
3532  if (0 == strcasecmp("gzip", iv))
3533  config->compression = 'G';
3534  if (0 == strcasecmp("bzip", iv))
3535  config->compression = 'B';
3536  if (0 == strcasecmp("deflate", iv))
3537  config->compression = 'D';
3538  if (0 == strcasecmp("disabled", iv))
3539  config->compression = 0;
3540  if (0 == strcasecmp("none", iv))
3541  config->compression = 0;
3542  }
3543  iv = getenv("BACKGROUND_DELETE");
3544  if (iv) {
3545  if (0 == strcasecmp(iv, "off")) {
3547  LINFO("Threaded background delete is disabled");
3548  }
3549  }
3550  if (config->background_delete) {
3551  LINFO("Threaded background delete is enabled");
3552  iv = getenv("STICKY_ON_LOCKED");
3553  if (iv) {
3554  if (0 == strcasecmp(iv, "on")) {
3555  config->sticky_on_locked = 1;
3556  LINFO
3557  ("Stickybit will be set during background delete and truncation.");
3558  LINFO("Indicating that the file is write locked.");
3559  }
3560  }
3561  }
3562  iv = getenv("HASHNAME");
3563  if (iv) {
3564  config->hash = iv;
3565  if (0 == strcmp("MHASH_SHA256", iv)) {
3566  config->selected_hash = MHASH_SHA256;
3567  LINFO("Hash SHA256 has been selected");
3568  }
3569  if (0 == strcmp("MHASH_SHA512", iv)) {
3570  config->selected_hash = MHASH_SHA512;
3571  LINFO("Hash SHA512 has been selected");
3572  }
3573  if (0 == strcmp("MHASH_WHIRLPOOL", iv)) {
3574  config->selected_hash = MHASH_WHIRLPOOL;
3575  LINFO("Hash WHIRLPOOL has been selected");
3576  }
3577  if (0 == strcmp("MHASH_HAVAL256", iv)) {
3578  config->selected_hash = MHASH_HAVAL256;
3579  LINFO("Hash HAVAL has been selected");
3580  }
3581  if (0 == strcmp("MHASH_SNEFRU256", iv)) {
3582  config->selected_hash = MHASH_SNEFRU256;
3583  LINFO("Hash SNEFRU has been selected");
3584  }
3585  if (0 == strcmp("MHASH_RIPEMD256", iv)) {
3586  config->selected_hash = MHASH_RIPEMD256;
3587  LINFO("Hash RIPEMD256 has been selected");
3588  }
3589  if (config->selected_hash == MHASH_TIGER192)
3590  LINFO("Hash MHASH_TIGER192 has been selected");
3591  } else
3592  LINFO("Hash MHASH_TIGER192 been selected");
3593  iv = getenv("HASHLEN");
3594  if (iv) {
3595  if (atoi(iv) >= 20 && atoi(iv) <= MAX_HASH_LEN) {
3596  if (atoi(iv) > 24 && config->selected_hash == MHASH_TIGER192) {
3597  die_dataerr
3598  ("MHASH_TIGER192 can not be used with MAX_HASH_LEN > 24");
3599  }
3600  config->hashlen = atoi(iv);
3601  } else {
3602  LFATAL("The hash length is invalid.");
3603  exit(EXIT_USAGE);
3604  }
3605  }
3606  LINFO("Lessfs uses a %i bytes long hash.", config->hashlen);
3607  iv = getenv("SYNC_RELAX");
3608  if (NULL == iv) {
3609  config->relax = 0;
3610  } else {
3611  config->relax = atoi(iv);
3612  if (0 != config->relax) {
3613  LINFO
3614  ("Lessfs fsync does not sync the databases to the disk when fsync is called on an inode");
3615  }
3616  }
3617  iv = getenv("REPLICATION");
3618  config->replication = 0;
3623  if (iv) {
3624  if (0 == strcasecmp(iv, "masterslave"))
3625  config->replication = 1;
3626  }
3627  iv = getenv("ROTATE_REPLOG_SIZE");
3628  if (iv)
3629  sscanf(iv, "%lu", &config->rotate_replog_size);
3630  if (1 == config->replication) {
3632  iv = read_val("REPLICATION_ROLE");
3633  if (0 == strcasecmp(iv, "master")) {
3634  config->replication_role = 0; // 0=master
3636  read_val("REPLICATION_PARTNER_IP");
3638  read_val("REPLICATION_PARTNER_PORT");
3639  } else {
3640  config->replication_role = 1; // 1=slave
3642  getenv("REPLICATION_LISTEN_IP");
3644  if (0 == strcmp(config->replication_listen_ip, "0.0.0.0"))
3645  config->replication_listen_ip = NULL;
3646  }
3647  iv = getenv("REPLICATION_WATCHDIR");
3648  if (iv)
3651  read_val("REPLICATION_LISTEN_PORT");
3652  }
3653  iv = getenv("REPLICATION_ENABLED");
3654  if (iv) {
3655  if (0 != strcasecmp(iv, "on"))
3657  }
3658  }
3659  iv = getenv("INSPECT_DISK_INTERVAL");
3660  if (NULL == iv) {
3662  } else {
3663  config->inspectdiskinterval = atoi(iv);
3664  }
3665  iv = getenv("DYNAMIC_DEFRAGMENTATION");
3666  config->defrag = 0;
3667  if (iv) {
3668  if (0 == strcasecmp("on", iv)) {
3669  config->defrag = 1;
3670  }
3671  }
3672  if (config->defrag)
3673  LINFO("Automatic defragmentation is enabled.");
3674  cache = read_val("CACHESIZE");
3675  if (cache)
3676  cs = atoi(cache);
3677  if (cs <= 0)
3678  cs = 1;
3679  calc = cs;
3680  config->cachesize = (calc * 1024 * 1024) / MAX_FUSE_BLKSIZE;
3681  flushtime = read_val("COMMIT_INTERVAL");
3682  cs = atoi(flushtime);
3683  if (cs <= 0)
3684  cs = 30;
3685  config->flushtime = cs;
3686  LINFO("cache %llu data blocks", config->cachesize);
3687 #ifdef HAMSTERDB
3688  iv = getenv("HAMSTERDB_CACHESIZE");
3689  if (iv) {
3690  sscanf(iv, "%lu", &config->hamsterdb_cachesize);
3691  } else config->hamsterdb_cachesize=calc * 1024 * 1024/10;
3692  LINFO("The hamsterdb cache size is %lu bytes",
3694 #endif
3695  if (mklessfs == 1) {
3696  dbpath =
3697  as_sprintf(__FILE__, __LINE__, "%s/fileblock.tch",
3698  config->fileblock);
3699  if (-1 != stat(dbpath, &stbuf)) {
3700  fprintf(stderr,
3701  "Data %s already exists, please remove it and try again\n",
3702  dbpath);
3703  exit(EXIT_DATAERR);
3704  }
3706 #ifdef HAMSTERDB
3707  hm_create(0);
3708 #endif
3709  }
3710  if (mklessfs == 2) {
3711  if (config->blockdata_io_type == CHUNK_IO) {
3712  LFATAL("Please remove old datafiles manually and rerun mklessfs without -f");
3713  die_dataerr("Overwrite is not supported with chunk_io");
3714  }
3715  drop_databases();
3716 #ifdef BERKELEYDB
3717  bdb_open();
3718 #else
3719 #ifdef HAMSTERDB
3720  hm_create(1);
3721 #else
3722  if (NULL == dbp)
3723  tc_open(0, 1, force_optimize);
3724 #endif
3725 #endif
3726  } else {
3727 #ifdef BERKELEYDB
3728  bdb_open();
3729 #else
3730 #ifdef HAMSTERDB
3731  if (mklessfs == 0 || mklessfs == 3)
3732  hm_open();
3733 #else
3734  if (NULL == dbp)
3735  tc_open(0, 0, force_optimize);
3736 #endif
3737 #endif
3738  }
3739 
3740  if (mklessfs == 0 || mklessfs == 3) {
3741 #ifdef ENABLE_CRYPTO
3742  iv = read_val("ENCRYPT_DATA");
3743  if (iv) {
3744  if (0 == strcasecmp(iv, "ON")) {
3745  config->encryptdata = 1;
3746  iv = getenv("ENCRYPT_META");
3747  LINFO("Data encryption is on");
3748  if (iv) {
3749  if (0 != strcasecmp(iv, "ON")) {
3750  LINFO("Metadata encryption is off");
3751  config->encryptmeta = 0;
3752  }
3753  }
3754  }
3755  }
3756  if (config->encryptdata) {
3757  if (NULL == getenv("PASSWORD")) {
3758  config->passwd =
3759  (unsigned char *) s_strdup(getpass("Password: "));
3760  } else
3761  config->passwd =
3762  (unsigned char *) s_strdup(getenv("PASSWORD"));
3763  unsetenv("PASSWORD"); /* Eat it after receiving.. */
3764  stiger =
3765  thash(config->passwd, strlen((char *) config->passwd));
3766  ivdb =
3767  search_dbdata(DBP, &pwl, sizeof(unsigned long long), LOCK);
3768  if (NULL == ivdb) {
3769  db_close(0);
3770  die_dataerr
3771  ("The filesystem has not been formatted with encryption support.");
3772  }
3773  config->iv = s_malloc(8);
3774  crypto = (CRYPTO *) ivdb->data;
3775  memcpy(config->iv, crypto->iv, 8);
3776  //config->passwd is plain, crypto->passwd is hashed.
3777  checkpasswd(crypto->passwd);
3778  s_free(stiger);
3779  DATfree(ivdb);
3780  }
3781 #endif
3782  if (0 == get_next_inode())
3783  die_dataerr
3784  ("Please format lessfs with mklessfs before mounting!");
3785  }
3786  return;
3787 }
3788 
3790 {
3791  unsigned long long inode;
3792  const char *key;
3793  FUNC;
3794  meta_lock((char *) __PRETTY_FUNCTION__);
3795  tctreeiterinit(metatree);
3796  while (key = tctreeiternext2(metatree)) {
3797  memcpy(&inode, key, sizeof(unsigned long long));
3798  update_filesize_onclose(inode);
3799  }
3801  EFUNC;
3802  return;
3803 }
3804 
3806 {
3807  unsigned char *stiger;
3808  char *brand;
3809  INUSE *finuse;
3810  int blksize = 4096;
3811  unsigned long long inuse;
3812 
3813  brand = as_sprintf(__FILE__, __LINE__, "LESSFS_BLOCKSIZE");
3814  stiger = thash((unsigned char *) brand, strlen(brand));
3815  if (config->blockdatabs) {
3816  inuse = getInUse(stiger);
3817  if (0 == inuse) {
3818  brand_blocksize();
3819  blksize = BLKSIZE;
3820  } else {
3821  blksize = inuse;
3822  }
3823  } else {
3824  finuse = file_get_inuse(stiger);
3825  if (NULL == finuse) {
3826  brand_blocksize();
3827  blksize = BLKSIZE;
3828  } else {
3829  blksize = finuse->inuse;
3830  }
3831  }
3832  free(stiger);
3833  s_free(brand);
3834  return (blksize);
3835 }
3836 
3837 /* Add the hash for string LESSFS_BLOCKSIZE
3838  to lessfs so that we know the blocksize for
3839  lessfsck and when someone is foolish enough to
3840  remount with a different blocksize */
3842 {
3843  unsigned char *stiger;
3844  char *brand;
3845  INUSE inuse;
3846 
3847  brand = as_sprintf(__FILE__, __LINE__, "LESSFS_BLOCKSIZE");
3848  stiger = thash((unsigned char *) brand, strlen(brand));
3849  if (config->blockdatabs) {
3850  update_inuse(stiger, BLKSIZE);
3851  } else {
3852  inuse.inuse = BLKSIZE;
3853  inuse.size = 0;
3854  inuse.offset = 0;
3855  file_update_inuse(stiger, &inuse);
3856  }
3857  free(stiger);
3858  s_free(brand);
3859  return;
3860 }
3861 
3862 #ifdef ENABLE_CRYPTO
3863 void checkpasswd(char *cryptopasswd)
3864 {
3865  unsigned char *stiger;
3866 
3867  FUNC;
3868  stiger = thash(config->passwd, strlen((char *) config->passwd));
3869  if (0 != memcmp(cryptopasswd, stiger, config->hashlen)) {
3870  sleep(5);
3871  fprintf(stderr, "Invalid password entered.\n");
3872  exit(EXIT_PASSWD);
3873  }
3874  s_free(stiger);
3875  EFUNC;
3876  return;
3877 }
3878 #endif
3879 
3880 char *ascii_hash(unsigned char *bhash)
3881 {
3882  char *ascii_hash = NULL;
3883  int n;
3884  char *p1 = NULL, *p2 = NULL;
3885 
3886  for (n = 0; n < config->hashlen; n++) {
3887  p1 = as_sprintf(__FILE__, __LINE__, "%02X", bhash[n]);
3888  if (n == 0) {
3889  ascii_hash = s_strdup(p1);
3890  } else {
3891  p2 = s_strdup(ascii_hash);
3892  s_free(ascii_hash);
3893  ascii_hash = as_sprintf(__FILE__, __LINE__, "%s%s", p2, p1);
3894  s_free(p2);
3895  }
3896  s_free(p1);
3897  }
3898  return (ascii_hash);
3899 }
3900 
3901 
3903 {
3904  workqtree = tctreenew();
3905  readcachetree = tctreenew();
3906  hashtree = tctreenew();
3907  inodetree = tctreenew();
3908  metatree = tctreenew();
3909  path2inotree = tctreenew();
3910 }
3911 
3913 {
3914  tctreeclear(workqtree);
3915  tctreeclear(readcachetree);
3916  tctreeclear(hashtree);
3917  tctreeclear(inodetree);
3918  tctreeclear(metatree);
3919  tctreeclear(path2inotree);
3920 
3921  tctreedel(workqtree);
3922  tctreedel(readcachetree);
3923  tctreedel(hashtree);
3924  tctreedel(inodetree);
3925  tctreedel(metatree);
3926  tctreedel(path2inotree);
3927 }
CCACHEDTA::updated
unsigned long updated
Definition: lib_common.h:101
tc_close
void tc_close(bool defrag)
Definition: lib_tc.c:522
create_ddbuf
DAT * create_ddbuf(struct stat stbuf, char *filename, unsigned long long real_size)
Definition: lib_common.c:1023
bdb_close
void bdb_close()
CCACHEDTA
Definition: lib_common.h:93
CCACHEDTA::hash
unsigned char hash[64]
Definition: lib_common.h:96
lib_hamster.h
lib_qlz.h
get_next_inode
unsigned long long get_next_inode()
Definition: lib_common.c:1766
clz15_decompress
compr * clz15_decompress(unsigned char *buf, int buflen)
Definition: lib_qlz15.c:51
next_sequence
void next_sequence()
Definition: lib_common.c:1444
lib_safe.h
cachep2i_lock
void cachep2i_lock(const char *msg)
Definition: lib_common.c:701
write_trunc_todolist
void write_trunc_todolist(struct truncate_thread_data *trunc_data)
Definition: lib_common.c:2847
lfscompress
DAT * lfscompress(unsigned char *dbdata, unsigned long dsize)
Definition: lib_common.c:2191
dbp
TCHDB * dbp
Definition: lib_common.c:100
lib_common.h
configdata::replication_partner_port
char * replication_partner_port
Definition: lib_cfg.h:66
configdata::tuneforspeed
int tuneforspeed
Definition: lib_cfg.h:79
DBL
#define DBL
Definition: lib_repl.h:26
worker_mutex
static pthread_mutex_t worker_mutex
Definition: lib_common.c:125
FUNC
#define FUNC
Definition: lib_log.h:76
set_new_offset
void set_new_offset(unsigned long long size)
Definition: file_io.c:158
CRYPTO::iv
char iv[8]
Definition: lib_common.h:72
get_offset_reclaim
INUSE * get_offset_reclaim(unsigned long long, unsigned long long)
Definition: lib_tc.c:1554
comprfree
void comprfree(compr *compdata)
Definition: lib_common.c:1288
MAX_ALLOWED_THREADS
#define MAX_ALLOWED_THREADS
Definition: lib_common.h:13
fl_write_cache
void fl_write_cache(CCACHEDTA *ccachedta, INOBNO *inobno)
Definition: file_io.c:262
release_worker_lock
void release_worker_lock()
Definition: lib_common.c:872
configdata::freelist
char * freelist
Definition: lib_cfg.h:40
DATfree
void DATfree(DAT *data)
Definition: lib_common.c:1744
CCACHEDTA::newblock
char newblock
Definition: lib_common.h:100
FILE_IO
Definition: lib_common.h:33
EFUNC
#define EFUNC
Definition: lib_log.h:77
hash_mutex
static pthread_mutex_t hash_mutex
Definition: lib_common.c:119
MEMDDSTAT::blocknr
unsigned long long blocknr
Definition: lib_common.h:78
lzo_compress
compr * lzo_compress(unsigned char *, int)
DAT
Definition: lib_common.h:59
configdata::background_delete
int background_delete
Definition: lib_cfg.h:69
CCACHEDTA::dirty
int dirty
Definition: lib_common.h:97
CRYPTO
Definition: lib_common.h:70
compr::data
unsigned char * data
Definition: lib_safe.h:33
lfsencrypt
DAT * lfsencrypt(unsigned char *, unsigned long)
configdata::freelistbs
char * freelistbs
Definition: lib_cfg.h:41
try_global_lock
int try_global_lock()
Definition: lib_common.c:645
db_unlink_file
int db_unlink_file(const char *path)
Definition: lib_common.c:1980
offset_lockedby
const char * offset_lockedby
Definition: lib_common.c:124
relax_mutex
static pthread_mutex_t relax_mutex
Definition: lib_common.c:133
memddstatfree
void memddstatfree(MEMDDSTAT *ddstat)
Definition: lib_common.c:1278
drop_databases
void drop_databases()
Definition: lib_tc.c:1298
MAX_META_CACHE
#define MAX_META_CACHE
Definition: lib_common.h:17
configdata::encryptmeta
unsigned int encryptmeta
Definition: lib_cfg.h:58
configdata::replication
int replication
Definition: lib_cfg.h:62
file_update_inuse
void file_update_inuse(unsigned char *stiger, INUSE *inuse)
Definition: file_io.c:126
init_chunk_io
void init_chunk_io()
Definition: lib_common.c:137
CACHE_MAX_AGE
#define CACHE_MAX_AGE
Definition: lib_common.h:12
configdata::hamsterdb_cachesize
unsigned long hamsterdb_cachesize
Definition: lib_cfg.h:85
lckname_to_stat
int lckname_to_stat(char *path, struct stat *stbuf)
Definition: lib_common.c:2968
truncate_thread_data::stbuf
struct stat stbuf
Definition: lib_common.h:89
fs_symlink
int fs_symlink(char *from, char *to)
Definition: lib_common.c:298
try_replbl_lock
int try_replbl_lock()
Definition: lib_common.c:664
configdata::replication_backlog
int replication_backlog
Definition: lib_cfg.h:71
DAT::data
unsigned char * data
Definition: lib_common.h:61
readcachetree
TCTREE * readcachetree
Definition: lib_common.c:109
INUSE::size
unsigned long size
Definition: lib_common.h:37
lfssnappy_decompress
compr * lfssnappy_decompress(unsigned char *, int)
ddstatfree
void ddstatfree(DDSTAT *ddstat)
Definition: lib_common.c:1261
s_basename
#define s_basename(path)
Definition: lib_safe.h:28
db_close
void db_close(bool defrag)
Definition: lib_common.c:2551
CRYPTO::passwd
char passwd[64]
Definition: lib_common.h:71
REPLDELETE
#define REPLDELETE
Definition: lib_repl.h:13
inode_isnot_locked
int inode_isnot_locked(unsigned long long inode)
Definition: lib_common.c:554
write_mutex
static pthread_mutex_t write_mutex
Definition: lib_common.c:117
db_commit_block
unsigned int db_commit_block(unsigned char *dbdata, INOBNO inobno, unsigned long dsize)
Definition: lib_common.c:2237
configdata::direntbs
char * direntbs
Definition: lib_cfg.h:31
EXIT_DATAERR
#define EXIT_DATAERR
Definition: retcodes.h:24
metatree
TCTREE * metatree
Definition: lib_common.c:113
CCACHEDTA::data
unsigned char data[131072]
Definition: lib_common.h:94
replbl_lockedby
const char * replbl_lockedby
Definition: lib_common.c:132
DBDTA
#define DBDTA
Definition: lib_repl.h:21
write_nfi
void write_nfi(unsigned long long nextinode)
Definition: lib_common.c:1409
configdata::passwd
unsigned char * passwd
Definition: lib_cfg.h:51
db_fs_truncate
int db_fs_truncate(struct stat *stbuf, off_t size, char *bname, bool unlink)
Definition: lib_common.c:2800
read_val
char * read_val(char *token)
Definition: lib_cfg.c:76
update_filesize_onclose
void update_filesize_onclose(unsigned long long inode)
Definition: lib_common.c:1800
configdata::fileblockbs
char * fileblockbs
Definition: lib_cfg.h:33
dnode_bname_to_inode
DDSTAT * dnode_bname_to_inode(void *, int, char *)
Definition: lib_tc.c:706
cachep2i_lockedby
const char * cachep2i_lockedby
Definition: lib_common.c:134
die_dataerr
#define die_dataerr(f...)
Definition: file_io.c:94
lib_log.h
delete_dbb
void delete_dbb(INOBNO *inobno)
Definition: lib_common.c:1713
lfssnappy_compress
compr * lfssnappy_compress(unsigned char *, int)
partial_truncate_block
void partial_truncate_block(unsigned long long inode, unsigned long long blocknr, unsigned int offset)
Definition: lib_common.c:2270
offset_mutex
static pthread_mutex_t offset_mutex
Definition: lib_common.c:123
die_lock_report
void die_lock_report(const char *msg, const char *msg2)
Definition: lib_common.c:595
create_mem_ddbuf
DAT * create_mem_ddbuf(MEMDDSTAT *ddstat)
Definition: lib_common.c:975
get_offset_lock
void get_offset_lock(const char *msg)
Definition: lib_common.c:820
sync_all_filesizes
void sync_all_filesizes()
Definition: lib_common.c:3789
erase_p2i
void erase_p2i()
Definition: lib_common.c:343
release_replbl_lock
void release_replbl_lock()
Definition: lib_common.c:929
lfsdecrypt
DAT * lfsdecrypt(DAT *)
INUSE::offset
unsigned long long offset
Definition: lib_common.h:36
freelist
TCBDB * freelist
Definition: lib_common.c:105
MAX_HASH_LEN
#define MAX_HASH_LEN
Definition: lib_common.h:11
get_blocksize
int get_blocksize()
Definition: lib_common.c:3805
configdata::blockusagebs
char * blockusagebs
Definition: lib_cfg.h:29
global_lock_mutex
static pthread_mutex_t global_lock_mutex
Definition: lib_common.c:115
delete_inuse
void delete_inuse(unsigned char *stiger)
Definition: lib_common.c:1706
configdata::selected_hash
unsigned int selected_hash
Definition: lib_cfg.h:59
parseconfig
void parseconfig(int mklessfs, bool force_optimize)
Definition: lib_common.c:3343
configdata::fileblock
char * fileblock
Definition: lib_cfg.h:32
inode_meta_from_cache
MEMDDSTAT * inode_meta_from_cache(unsigned long long inode)
Definition: lib_common.c:1783
fil_fuse_info
void fil_fuse_info(DDSTAT *ddstat, void *buf, fuse_fill_dir_t filler, struct fuse_file_info *fi)
Definition: lib_common.c:2927
lessfs_trans_stamp
void lessfs_trans_stamp()
Definition: lib_common.c:2771
create_inode_note
void create_inode_note(unsigned long long inode)
Definition: lib_common.c:530
get_offset_fast
unsigned long long get_offset_fast(unsigned long long)
Definition: lib_tc.c:1644
truncate_thread_data::inode
unsigned long long inode
Definition: lib_common.h:87
configdata::replication_listen_ip
char * replication_listen_ip
Definition: lib_cfg.h:67
try_offset_lock
int try_offset_lock()
Definition: lib_common.c:742
RECLAIM_AGRESSIVE
#define RECLAIM_AGRESSIVE
Definition: lib_common.h:19
CCACHEDTA::creationtime
time_t creationtime
Definition: lib_common.h:98
release_meta_lock
void release_meta_lock()
Definition: lib_common.c:935
configdata::shutdown
int shutdown
Definition: lib_cfg.h:76
write_seq
void write_seq(unsigned long sequence)
Definition: lib_common.c:1416
meta_mutex
static pthread_mutex_t meta_mutex
Definition: lib_common.c:127
value_to_ddstat
DDSTAT * value_to_ddstat(DAT *vddstat)
Definition: lib_common.c:986
configdata::replication_partner_ip
char * replication_partner_ip
Definition: lib_cfg.h:65
release_offset_lock
void release_offset_lock()
Definition: lib_common.c:842
DDSTAT::filename
char filename[256+1]
Definition: lib_common.h:67
DDSTAT::stbuf
struct stat stbuf
Definition: lib_common.h:65
configdata::commithash
unsigned char * commithash
Definition: lib_cfg.h:46
get_sequence
unsigned long get_sequence()
Definition: lib_common.c:1428
flush_wait
void flush_wait(unsigned long long inode)
Definition: lib_common.c:2564
release_repl_lock
void release_repl_lock()
Definition: lib_common.c:923
configdata::rotate_replog_size
unsigned long rotate_replog_size
Definition: lib_cfg.h:72
INOBNO
Definition: lib_common.h:48
configdata::reclaim
int reclaim
Definition: lib_cfg.h:82
meta_lockedby
const char * meta_lockedby
Definition: lib_common.c:128
tc_open
void tc_open(bool defrag, bool createpath, bool force_optimize)
Definition: lib_tc.c:353
configdata::defrag
unsigned int defrag
Definition: lib_cfg.h:55
configdata::blockdata
char * blockdata
Definition: lib_cfg.h:25
configdata::tune_for_size
int tune_for_size
Definition: lib_cfg.h:83
dbdirent
TCBDB * dbdirent
Definition: lib_common.c:104
fdbdta
int fdbdta
Definition: lib_tc.c:92
EXIT_PASSWD
#define EXIT_PASSWD
Definition: retcodes.h:28
repl_lockedby
const char * repl_lockedby
Definition: lib_common.c:130
DINOINO::dirnode
unsigned long long dirnode
Definition: lib_common.h:55
bin_write_dbdata
void bin_write_dbdata(int, void *, int, void *, int)
Definition: lib_tc.c:658
init_transactions
struct tm * init_transactions()
Definition: lib_common.c:2438
truncate_thread_data::unlink
bool unlink
Definition: lib_common.h:90
BLKSIZE
int BLKSIZE
Definition: commons.h:8
as_sprintf
void * as_sprintf(char *file, unsigned int line, const char *fmt,...)
Definition: lib_safe.c:564
release_global_lock
void release_global_lock()
Definition: lib_common.c:637
INOBNO::blocknr
unsigned long long blocknr
Definition: lib_common.h:50
meta_lock
void meta_lock(const char *msg)
Definition: lib_common.c:880
update_stat
int update_stat(char *path, struct stat *stbuf)
Definition: lib_common.c:2504
s_dirname
#define s_dirname(path)
Definition: lib_safe.h:27
fs_rename_link
int fs_rename_link(const char *from, const char *to, struct stat stbuf)
Definition: lib_common.c:3121
btsearch_keyval
DAT * btsearch_keyval(int, void *, int, void *, int, bool)
Definition: lib_tc.c:919
INOBNO::inode
unsigned long long inode
Definition: lib_common.h:49
formatfs
void formatfs()
Definition: lib_common.c:1455
workqtree
TCTREE * workqtree
Definition: lib_common.c:108
truncation_wait
void truncation_wait()
Definition: lib_common.c:966
configdata::safe_down
int safe_down
Definition: lib_cfg.h:78
hashtree
TCTREE * hashtree
Definition: lib_common.c:111
inobnolistsort
void inobnolistsort(TCLIST *list)
Definition: lib_common.c:381
DBB
#define DBB
Definition: lib_repl.h:23
get_global_lock
void get_global_lock(const char *msg)
Definition: lib_common.c:616
bt_entry_exists
int bt_entry_exists(int, void *, int, void *, int)
Definition: lib_tc.c:1253
path_from_cache
int path_from_cache(char *path, struct stat *stbuf)
Definition: lib_common.c:1167
fs_readlink
int fs_readlink(const char *path, char *buf, size_t size)
Definition: lib_common.c:310
global_lockedby
const char * global_lockedby
Definition: lib_common.c:116
configdata::meta
char * meta
Definition: lib_cfg.h:34
release_write_lock
void release_write_lock()
Definition: lib_common.c:694
hm_open
void hm_open()
LFSMEDIUM
#define LFSMEDIUM
Definition: lib_common.h:25
try_repl_lock
int try_repl_lock()
Definition: lib_common.c:655
replbl_mutex
static pthread_mutex_t replbl_mutex
Definition: lib_common.c:131
try_hash_lock
int try_hash_lock()
Definition: lib_common.c:773
MEMDDSTAT::real_size
unsigned long long real_size
Definition: lib_common.h:80
LFSHUGE
#define LFSHUGE
Definition: lib_common.h:26
try_meta_lock
int try_meta_lock()
Definition: lib_common.c:943
lib_tc.h
hash_update_filesize
void hash_update_filesize(MEMDDSTAT *memddstat, unsigned long long inode)
Definition: lib_common.c:1952
configdata::nospace
int nospace
Definition: lib_cfg.h:80
btdelete_curkey
int btdelete_curkey(int, void *, int, void *, int, const char *)
Definition: lib_tc.c:854
configdata::flushtime
unsigned int flushtime
Definition: lib_cfg.h:53
LINFO
#define LINFO(f...)
Definition: lib_log.h:69
compr
Definition: lib_safe.h:31
get_offset
INUSE * get_offset(unsigned long long size)
Definition: lib_common.c:249
configdata::blockdata_io_type
int blockdata_io_type
Definition: lib_cfg.h:27
lib_bdb.h
lzo_decompress
compr * lzo_decompress(unsigned char *, int)
try_write_lock
int try_write_lock()
Definition: lib_common.c:735
configdata::encryptdata
unsigned int encryptdata
Definition: lib_cfg.h:57
s_zmalloc
#define s_zmalloc(size)
Definition: lib_safe.h:24
create_hash_note
void create_hash_note(unsigned char *hash)
Definition: lib_common.c:499
cook_cache
void cook_cache(char *key, int ksize, CCACHEDTA *ccachedta, unsigned long sequence)
Definition: lib_common.c:2615
configdata::replication_watchdir
char * replication_watchdir
Definition: lib_cfg.h:44
readBlock
unsigned long long readBlock(unsigned long long blocknr, char *blockdata, size_t rsize, size_t block_offset, unsigned long long inode)
Definition: lib_common.c:1613
DINOINO
Definition: lib_common.h:53
locks_to_dir
void locks_to_dir(void *buf, fuse_fill_dir_t filler, struct fuse_file_info *fi)
Definition: lib_common.c:2944
count_dirlinks
int count_dirlinks(void *, int)
Definition: lib_tc.c:976
update_parent_time
int update_parent_time(char *path, int linkcount)
Definition: lib_common.c:2481
config
struct configdata * config
Definition: lib_cfg.h:91
configdata::metabs
char * metabs
Definition: lib_cfg.h:35
get_inode_lock
void get_inode_lock(const char *msg)
Definition: lib_common.c:790
logiv
void logiv(char *msg, unsigned char *bhash)
Definition: lib_common.c:423
ascii_hash
char * ascii_hash(unsigned char *bhash)
Definition: lib_common.c:3880
worker_lock
void worker_lock(const char *msg)
Definition: lib_common.c:850
dbmknod
void dbmknod(const char *path, mode_t mode, char *linkdest, dev_t rdev)
Definition: lib_common.c:1066
hash_lockedby
const char * hash_lockedby
Definition: lib_common.c:120
fs_link
int fs_link(char *from, char *to)
Definition: lib_common.c:3001
CCACHEDTA::datasize
unsigned long datasize
Definition: lib_common.h:95
inodetree
TCTREE * inodetree
Definition: lib_common.c:112
check_datafile_sanity
void check_datafile_sanity()
Definition: lib_common.c:230
configdata::transactions
int transactions
Definition: lib_cfg.h:61
hm_close
void hm_close(bool)
LFATAL
#define LFATAL(f...)
Definition: lib_log.h:68
cache_p2i
void cache_p2i(char *filename, struct stat *stbuf)
Definition: lib_common.c:385
LOCK_TIMEOUT
#define LOCK_TIMEOUT
Definition: lib_common.h:16
MAX_FUSE_BLKSIZE
#define MAX_FUSE_BLKSIZE
Definition: lib_common.h:9
dbs
TCHDB * dbs
Definition: lib_common.c:102
lib_crypto.h
lib_net.h
get_inode
unsigned long long get_inode(const char *path)
Definition: lib_common.c:2632
MAX_CHUNK_DEPTH
#define MAX_CHUNK_DEPTH
Definition: lib_common.h:23
tc_write_cache
void tc_write_cache(CCACHEDTA *ccachedta, INOBNO *inobno)
Definition: lib_common.c:2863
dbl
TCBDB * dbl
Definition: lib_common.c:101
cachep2i_mutex
static pthread_mutex_t cachep2i_mutex
Definition: lib_common.c:135
truncate_thread_data::lastblocknr
unsigned long long lastblocknr
Definition: lib_common.h:86
configdata::max_backlog_size
unsigned long max_backlog_size
Definition: lib_cfg.h:86
wait_hash_pending
void wait_hash_pending(unsigned char *hash)
Definition: lib_common.c:508
configdata::hardlink
char * hardlink
Definition: lib_cfg.h:36
lfsdecompress
DAT * lfsdecompress(DAT *cdata)
Definition: lib_common.c:1527
freplbl
int freplbl
Definition: lib_tc.c:94
dbdta
TCHDB * dbdta
Definition: lib_common.c:103
LOCK
#define LOCK
Definition: lib_common.h:5
path2inotree
TCTREE * path2inotree
Definition: lib_common.c:110
delete_hash_note
void delete_hash_note(unsigned char *hash)
Definition: lib_common.c:522
LDEBUG
#define LDEBUG(f...)
Definition: lib_log.h:78
get_realsize_fromcache
int get_realsize_fromcache(unsigned long long inode, struct stat *stbuf)
Definition: lib_common.c:1080
MEMDDSTAT::updated
unsigned int updated
Definition: lib_common.h:77
dbstat
int dbstat(const char *filename, struct stat *stbuf, bool cache_request)
Definition: lib_common.c:1204
configdata::compression
unsigned char compression
Definition: lib_cfg.h:49
wait_inode_pending2
void wait_inode_pending2(unsigned long long inode)
Definition: lib_common.c:569
configdata::replication_last_rotated
time_t replication_last_rotated
Definition: lib_cfg.h:45
s_malloc
#define s_malloc(size)
Definition: lib_safe.h:23
clear_dirty
void clear_dirty()
Definition: lib_common.c:3331
invalidate_p2i
void invalidate_p2i(char *filename)
Definition: lib_common.c:335
brand_blocksize
void brand_blocksize()
Definition: lib_common.c:3841
file_io.h
file_unlink_file
int file_unlink_file(const char *path)
Definition: file_io.c:804
trunc_lock
void trunc_lock()
Definition: lib_common.c:950
value_tomem_ddstat
MEMDDSTAT * value_tomem_ddstat(char *value, int size)
Definition: lib_common.c:1270
fs_rename
int fs_rename(const char *from, const char *to, struct stat stbuf)
Definition: lib_common.c:3183
close_trees
void close_trees()
Definition: lib_common.c:3912
btbin_write_dup
void btbin_write_dup(int, void *, int, void *, int, bool)
Definition: lib_tc.c:581
update_filesize_cache
int update_filesize_cache(struct stat *stbuf, off_t size)
Definition: lib_common.c:1815
DAT::size
unsigned long size
Definition: lib_common.h:60
ROTATE_REPLOG_SIZE
#define ROTATE_REPLOG_SIZE
Definition: lib_common.h:18
configdata::frozen
int frozen
Definition: lib_cfg.h:77
MEMDDSTAT::filename
char filename[256+1]
Definition: lib_common.h:81
file_get_inuse
INUSE * file_get_inuse(unsigned char *stiger)
Definition: file_io.c:96
DDSTAT::real_size
unsigned long long real_size
Definition: lib_common.h:66
configdata::sticky_on_locked
int sticky_on_locked
Definition: lib_cfg.h:75
REPLWRITE
#define REPLWRITE
Definition: lib_repl.h:12
DBP
#define DBP
Definition: lib_repl.h:24
has_nodes
unsigned long long has_nodes(unsigned long long)
Definition: lib_tc.c:1079
tc_truncate_worker
void * tc_truncate_worker(void *threadarg)
Definition: lib_common.c:2337
search_dbdata
DAT * search_dbdata(int, void *, int, bool)
Definition: lib_tc.c:816
retcodes.h
repl_mutex
static pthread_mutex_t repl_mutex
Definition: lib_common.c:129
truncate_thread_data::blocknr
unsigned long long blocknr
Definition: lib_common.h:85
thash
unsigned char * thash(unsigned char *buf, int size)
Definition: lib_common.c:216
getInUse
unsigned long long getInUse(unsigned char *tigerstr)
Definition: lib_common.c:1721
MEMDDSTAT::stbuf
struct stat stbuf
Definition: lib_common.h:76
release_hash_lock
void release_hash_lock()
Definition: lib_common.c:782
worker_lockedby
const char * worker_lockedby
Definition: lib_common.c:126
GLOBAL_LOCK_TIMEOUT
#define GLOBAL_LOCK_TIMEOUT
Definition: lib_common.h:15
open_trees
void open_trees()
Definition: lib_common.c:3902
INUSE
Definition: lib_common.h:35
configdata::hardlinkbs
char * hardlinkbs
Definition: lib_cfg.h:37
configdata::hashlen
int hashlen
Definition: lib_cfg.h:60
lib_repl.h
clz_decompress
compr * clz_decompress(unsigned char *buf, int buflen)
Definition: lib_qlz.c:49
EXIT_USAGE
#define EXIT_USAGE
Definition: retcodes.h:23
INUSE::allocated_size
unsigned long long allocated_size
Definition: lib_common.h:38
DBDIRENT
#define DBDIRENT
Definition: lib_repl.h:28
configdata::relax
unsigned int relax
Definition: lib_cfg.h:56
configdata::replication_listen_port
char * replication_listen_port
Definition: lib_cfg.h:68
DDSTAT
Definition: lib_common.h:64
configdata::iv
unsigned char * iv
Definition: lib_cfg.h:50
auto_repair
void auto_repair(INOBNO *inobno)
Definition: lib_common.c:1605
lib_cfg.h
DBS
#define DBS
Definition: lib_repl.h:25
MEMDDSTAT
Definition: lib_common.h:75
update_meta
void update_meta(unsigned long long inode, unsigned long size, int sign)
Definition: lib_common.c:2716
configdata::symlinkbs
char * symlinkbs
Definition: lib_cfg.h:39
s_strdup
#define s_strdup(size)
Definition: lib_safe.h:26
TOKYOCABINET
Definition: lib_common.h:33
truncate_thread_data
Definition: lib_common.h:84
frepl
int frepl
Definition: lib_tc.c:93
release_cachep2i_lock
void release_cachep2i_lock()
Definition: lib_common.c:721
configdata::replication_enabled
int replication_enabled
Definition: lib_cfg.h:70
lib_qlz15.h
release_trunc_lock
void release_trunc_lock()
Definition: lib_common.c:958
purge_read_cache
void purge_read_cache(unsigned long long inode, bool force, char *caller)
Definition: lib_common.c:2645
try_cachep2i_lock
int try_cachep2i_lock()
Definition: lib_common.c:727
delete_key
void delete_key(int, void *, int, const char *)
Definition: lib_tc.c:1007
fs_rmdir
int fs_rmdir(const char *path)
Definition: lib_common.c:3272
db_delete_stored
void db_delete_stored(INOBNO *inobno)
Definition: lib_common.c:2899
checkpasswd
void checkpasswd(char *)
configdata::bdb_private
int bdb_private
Definition: lib_cfg.h:84
DINOINO::inode
unsigned long long inode
Definition: lib_common.h:56
configdata
Definition: lib_cfg.h:24
get_ccachedta
static CCACHEDTA * get_ccachedta(uintptr_t p)
Definition: lib_common.h:104
bin_write
void bin_write(int, void *, int, void *, int)
Definition: lib_tc.c:692
dbb
TCHDB * dbb
Definition: lib_common.c:98
hm_create
void hm_create(bool)
configdata::inspectdiskinterval
unsigned int inspectdiskinterval
Definition: lib_cfg.h:54
inobnolistelemcmp
static int inobnolistelemcmp(const void *a, const void *b)
Definition: lib_common.c:357
configdata::chunk_depth
int chunk_depth
Definition: lib_cfg.h:81
sequence
unsigned long sequence
Definition: lessfs.c:101
mkchunk_dir
void mkchunk_dir(char *path)
Definition: lib_common.c:157
inode_lockedby
const char * inode_lockedby
Definition: lib_common.c:122
inode_mutex
static pthread_mutex_t inode_mutex
Definition: lib_common.c:121
CHUNK_IO
Definition: lib_common.h:33
release_inode_lock
void release_inode_lock()
Definition: lib_common.c:812
nextoffset
unsigned long long nextoffset
Definition: lib_common.c:90
get_hash_lock
void get_hash_lock(const char *msg)
Definition: lib_common.c:751
get_dir_inode
int get_dir_inode(char *dname, struct stat *stbuf, bool cache_request)
Definition: lib_common.c:1103
fs_mkdir
int fs_mkdir(const char *path, mode_t mode)
Definition: lib_common.c:2109
write_file_ent
void write_file_ent(const char *filename, unsigned long long inode, mode_t mode, char *linkdest, dev_t rdev)
Definition: lib_common.c:1294
tc_compress
DAT * tc_compress(unsigned char *dbdata, unsigned long dsize)
Definition: lib_common.c:2146
repl_lock
void repl_lock(const char *msg)
Definition: lib_common.c:902
DBU
#define DBU
Definition: lib_repl.h:22
clz_compress
compr * clz_compress(unsigned char *buf, int buflen)
Definition: lib_qlz.c:74
update_filesize
void update_filesize(unsigned long long inode, unsigned long long fsize, unsigned int offsetblock, unsigned long long blocknr)
Definition: lib_common.c:1880
die_syserr
#define die_syserr()
Definition: lessfsck.c:71
write_replication_data
void write_replication_data(unsigned char db, unsigned char op, char *key, int ksize, char *value, int vsize, int threadnr)
Definition: lib_repl.c:397
bdb_open
void bdb_open()
INUSE::inuse
unsigned long long inuse
Definition: lib_common.h:39
configdata::blockdatabs
char * blockdatabs
Definition: lib_cfg.h:26
truncate_thread_data::offsetblock
unsigned int offsetblock
Definition: lib_common.h:88
configdata::symlink
char * symlink
Definition: lib_cfg.h:38
delete_inode_note
void delete_inode_note(unsigned long long inode)
Definition: lib_common.c:587
clz15_compress
compr * clz15_compress(unsigned char *buf, int buflen)
Definition: lib_qlz15.c:73
configdata::hash
char * hash
Definition: lib_cfg.h:47
round_512
unsigned long long round_512(unsigned long long size)
Definition: file_io.c:140
dbu
TCHDB * dbu
Definition: lib_common.c:99
lib_lzo.h
CCACHEDTA::pending
int pending
Definition: lib_common.h:99
FREELIST
#define FREELIST
Definition: lib_repl.h:27
check_block_exists
DAT * check_block_exists(INOBNO *inobno)
Definition: lib_common.c:1971
configdata::cachesize
unsigned long long cachesize
Definition: lib_cfg.h:52
working
long working
Definition: defrag_lessfs.c:38
write_repl_data
void write_repl_data(unsigned char db, unsigned char op, char *key, int ksize, char *value, int vsize, int threadnr)
Definition: lib_repl.c:450
loghash
void loghash(char *msg, unsigned char *bhash)
Definition: lib_common.c:451
LFSSMALL
#define LFSSMALL
Definition: lib_common.h:24
configdata::dirent
char * dirent
Definition: lib_cfg.h:30
configdata::replication_role
int replication_role
Definition: lib_cfg.h:63
s_free
#define s_free(mem_ref)
Definition: lib_safe.h:25
write_lock
void write_lock(const char *msg)
Definition: lib_common.c:674
hash_to_ascii
unsigned char * hash_to_ascii(unsigned char *bhash)
Definition: lib_common.c:478
configdata::blockusage
char * blockusage
Definition: lib_cfg.h:28
lib_snappy.h
log_fatal_hash
void log_fatal_hash(char *msg, unsigned char *bhash)
Definition: lib_common.c:456
wait_inode_pending
void wait_inode_pending(unsigned long long inode)
Definition: lib_common.c:539
write_lockedby
const char * write_lockedby
Definition: lib_common.c:118
update_inuse
void update_inuse(unsigned char *hashdata, unsigned long long inuse)
Definition: lib_common.c:1751