fix
[oweals/gnunet.git] / src / fs / fs_file_information.c
1 /*
2      This file is part of GNUnet.
3      (C) 2009 Christian Grothoff (and other contributing authors)
4
5      GNUnet is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 2, or (at your
8      option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, USA.
19 */
20
21 /**
22  * @file fs/fs_file_information.c
23  * @brief  Manage information for publishing directory hierarchies
24  * @author Christian Grothoff
25  *
26  * TODO:
27  * - serialization/deserialization (& deserialization API)
28  * - metadata filename clean up code
29  * - metadata/ksk generation for directories from contained files
30  */
31 #include "platform.h"
32 #include <extractor.h>
33 #include "gnunet_fs_service.h"
34 #include "fs.h"
35 #include "fs_tree.h"
36
37
38 /**
39  * Obtain the name under which this file information
40  * structure is stored on disk.  Only works for top-level
41  * file information structures.
42  *
43  * @param s structure to get the filename for
44  * @return NULL on error, otherwise filename that
45  *         can be passed to "GNUNET_FS_file_information_recover"
46  *         to read this fi-struct from disk.
47  */
48 const char *
49 GNUNET_FS_file_information_get_id (struct GNUNET_FS_FileInformation *s)
50 {
51   if (NULL != s->dir)
52     return NULL;
53   return s->serialization;
54 }
55
56
57 /**
58  * Create an entry for a file in a publish-structure.
59  *
60  * @param h handle to the file sharing subsystem
61  * @param client_info initial value for the client-info value for this entry
62  * @param filename name of the file or directory to publish
63  * @param keywords under which keywords should this file be available
64  *         directly; can be NULL
65  * @param meta metadata for the file
66  * @param do_index GNUNET_YES for index, GNUNET_NO for insertion,
67  *                GNUNET_SYSERR for simulation
68  * @param anonymity what is the desired anonymity level for sharing?
69  * @param priority what is the priority for OUR node to
70  *   keep this file available?  Use 0 for maximum anonymity and
71  *   minimum reliability...
72  * @param expirationTime when should this content expire?
73  * @return publish structure entry for the file
74  */
75 struct GNUNET_FS_FileInformation *
76 GNUNET_FS_file_information_create_from_file (struct GNUNET_FS_Handle *h,
77                                              void *client_info,
78                                              const char *filename,
79                                              const struct GNUNET_FS_Uri *keywords,
80                                              const struct GNUNET_CONTAINER_MetaData *meta,
81                                              int do_index,
82                                              uint32_t anonymity,
83                                              uint32_t priority,
84                                              struct GNUNET_TIME_Absolute expirationTime)
85 {
86   struct FileInfo *fi;
87   struct stat sbuf;
88   struct GNUNET_FS_FileInformation *ret;
89   const char *fn;
90   const char *ss;
91
92   if (0 != STAT (filename, &sbuf))
93     {
94       GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
95                                 "stat",
96                                 filename);
97       return NULL;
98     }
99   fi = GNUNET_FS_make_file_reader_context_ (filename);
100   if (fi == NULL)
101     {
102       GNUNET_break (0);
103       return NULL;
104     }
105   ret = GNUNET_FS_file_information_create_from_reader (h,
106                                                        client_info,
107                                                        sbuf.st_size,
108                                                        &GNUNET_FS_data_reader_file_,
109                                                        fi,
110                                                        keywords,
111                                                        meta,
112                                                        do_index,
113                                                        anonymity,
114                                                        priority,
115                                                        expirationTime);
116   ret->h = h;
117   ret->filename = GNUNET_strdup (filename);
118   fn = filename;
119   while (NULL != (ss = strstr (fn,
120                                DIR_SEPARATOR_STR)))
121     fn = ss + 1;
122   GNUNET_CONTAINER_meta_data_insert (ret->meta,
123                                      "<gnunet>",
124                                      EXTRACTOR_METATYPE_FILENAME,
125                                      EXTRACTOR_METAFORMAT_C_STRING,
126                                      "text/plain",
127                                      fn,
128                                      strlen (fn) + 1);
129   return ret;
130 }
131
132
133 /**
134  * Create an entry for a file in a publish-structure.
135  *
136  * @param h handle to the file sharing subsystem
137  * @param client_info initial value for the client-info value for this entry
138  * @param length length of the file
139  * @param data data for the file (should not be used afterwards by
140  *        the caller; callee will "free")
141  * @param keywords under which keywords should this file be available
142  *         directly; can be NULL
143  * @param meta metadata for the file
144  * @param do_index GNUNET_YES for index, GNUNET_NO for insertion,
145  *                GNUNET_SYSERR for simulation
146  * @param anonymity what is the desired anonymity level for sharing?
147  * @param priority what is the priority for OUR node to
148  *   keep this file available?  Use 0 for maximum anonymity and
149  *   minimum reliability...
150  * @param expirationTime when should this content expire?
151  * @return publish structure entry for the file
152  */
153 struct GNUNET_FS_FileInformation *
154 GNUNET_FS_file_information_create_from_data (struct GNUNET_FS_Handle *h,
155                                              void *client_info,
156                                              uint64_t length,
157                                              void *data,
158                                              const struct GNUNET_FS_Uri *keywords,
159                                              const struct GNUNET_CONTAINER_MetaData *meta,
160                                              int do_index,
161                                              uint32_t anonymity,
162                                              uint32_t priority,
163                                              struct GNUNET_TIME_Absolute expirationTime)
164 {
165   if (GNUNET_YES == do_index)        
166     {
167       GNUNET_break (0);
168       return NULL;
169     }
170   return GNUNET_FS_file_information_create_from_reader (h,
171                                                         client_info,
172                                                         length,
173                                                         &GNUNET_FS_data_reader_copy_,
174                                                         data,
175                                                         keywords,
176                                                         meta,
177                                                         do_index,
178                                                         anonymity,
179                                                         priority,
180                                                         expirationTime);
181 }
182
183
184 /**
185  * Create an entry for a file in a publish-structure.
186  *
187  * @param h handle to the file sharing subsystem
188  * @param client_info initial value for the client-info value for this entry
189  * @param length length of the file
190  * @param reader function that can be used to obtain the data for the file 
191  * @param reader_cls closure for "reader"
192  * @param keywords under which keywords should this file be available
193  *         directly; can be NULL
194  * @param meta metadata for the file
195  * @param do_index GNUNET_YES for index, GNUNET_NO for insertion,
196  *                GNUNET_SYSERR for simulation
197  * @param anonymity what is the desired anonymity level for sharing?
198  * @param priority what is the priority for OUR node to
199  *   keep this file available?  Use 0 for maximum anonymity and
200  *   minimum reliability...
201  * @param expirationTime when should this content expire?
202  * @return publish structure entry for the file
203  */
204 struct GNUNET_FS_FileInformation *
205 GNUNET_FS_file_information_create_from_reader (struct GNUNET_FS_Handle *h,
206                                                void *client_info,
207                                                uint64_t length,
208                                                GNUNET_FS_DataReader reader,
209                                                void *reader_cls,
210                                                const struct GNUNET_FS_Uri *keywords,
211                                                const struct GNUNET_CONTAINER_MetaData *meta,
212                                                int do_index,
213                                                uint32_t anonymity,
214                                                uint32_t priority,
215                                                struct GNUNET_TIME_Absolute expirationTime)
216 {
217   struct GNUNET_FS_FileInformation *ret;
218
219   if ( (GNUNET_YES == do_index) &&
220        (reader != &GNUNET_FS_data_reader_file_) )
221     {
222       GNUNET_break (0);
223       return NULL;
224     }
225   ret = GNUNET_malloc (sizeof (struct GNUNET_FS_FileInformation));
226   ret->h = h;
227   ret->client_info = client_info;  
228   ret->meta = GNUNET_CONTAINER_meta_data_duplicate (meta);
229   if (ret->meta == NULL)
230     ret->meta = GNUNET_CONTAINER_meta_data_create ();
231   ret->keywords = (keywords == NULL) ? NULL : GNUNET_FS_uri_dup (keywords);
232   ret->expirationTime = expirationTime;
233   ret->data.file.reader = reader; 
234   ret->data.file.reader_cls = reader_cls;
235   ret->data.file.do_index = do_index;
236   ret->data.file.file_size = length;
237   ret->anonymity = anonymity;
238   ret->priority = priority;
239   return ret;
240 }
241
242
243 /**
244  * Closure for "dir_scan_cb".
245  */
246 struct DirScanCls 
247 {
248   /**
249    * Metadata extractors to use.
250    */
251   struct EXTRACTOR_PluginList *extractors;
252
253   /**
254    * Master context.
255    */ 
256   struct GNUNET_FS_Handle *h;
257
258   /**
259    * Function to call on each directory entry.
260    */
261   GNUNET_FS_FileProcessor proc;
262   
263   /**
264    * Closure for proc.
265    */
266   void *proc_cls;
267
268   /**
269    * Scanner to use for subdirectories.
270    */
271   GNUNET_FS_DirectoryScanner scanner;
272
273   /**
274    * Closure for scanner.
275    */
276   void *scanner_cls;
277
278   /**
279    * Set to an error message (if any).
280    */
281   char *emsg; 
282
283   /**
284    * Should files be indexed?
285    */ 
286   int do_index;
287
288   /**
289    * Desired anonymity level.
290    */
291   uint32_t anonymity;
292
293   /**
294    * Desired publishing priority.
295    */
296   uint32_t priority;
297
298   /**
299    * Expiration time for publication.
300    */
301   struct GNUNET_TIME_Absolute expiration;
302 };
303
304
305 /**
306  * Function called on each entry in a file to
307  * cause default-publishing.
308  * @param cls closure (struct DirScanCls)
309  * @param filename name of the file to be published
310  * @return GNUNET_OK on success, GNUNET_SYSERR to abort
311  */
312 static int
313 dir_scan_cb (void *cls,
314              const char *filename)
315 {
316   struct DirScanCls *dsc = cls;  
317   struct stat sbuf;
318   struct GNUNET_FS_FileInformation *fi;
319   struct GNUNET_FS_Uri *ksk_uri;
320   struct GNUNET_FS_Uri *keywords;
321   struct GNUNET_CONTAINER_MetaData *meta;
322
323   if (0 != STAT (filename, &sbuf))
324     {
325       GNUNET_asprintf (&dsc->emsg,
326                        _("`%s' failed on file `%s': %s"),
327                        "stat",
328                        filename,
329                        STRERROR (errno));
330       return GNUNET_SYSERR;
331     }
332   if (S_ISDIR (sbuf.st_mode))
333     {
334       fi = GNUNET_FS_file_information_create_from_directory (dsc->h,
335                                                              NULL,
336                                                              filename,
337                                                              dsc->scanner,
338                                                              dsc->scanner_cls,
339                                                              dsc->do_index,
340                                                              dsc->anonymity,
341                                                              dsc->priority,
342                                                              dsc->expiration,
343                                                              &dsc->emsg);
344       if (NULL == fi)
345         {
346           GNUNET_assert (NULL != dsc->emsg);
347           return GNUNET_SYSERR;
348         }
349     }
350   else
351     {
352       meta = GNUNET_CONTAINER_meta_data_create ();
353       GNUNET_CONTAINER_meta_data_extract_from_file (meta,
354                                                     filename,
355                                                     dsc->extractors);
356       // FIXME: remove path from filename in metadata!
357       keywords = GNUNET_FS_uri_ksk_create_from_meta_data (meta);
358       ksk_uri = GNUNET_FS_uri_ksk_canonicalize (keywords);
359       fi = GNUNET_FS_file_information_create_from_file (dsc->h,
360                                                         NULL,
361                                                         filename,
362                                                         ksk_uri,
363                                                         meta,
364                                                         dsc->do_index,
365                                                         dsc->anonymity,
366                                                         dsc->priority,
367                                                         dsc->expiration);
368       GNUNET_CONTAINER_meta_data_destroy (meta);
369       GNUNET_FS_uri_destroy (keywords);
370       GNUNET_FS_uri_destroy (ksk_uri);
371     }
372   dsc->proc (dsc->proc_cls,
373              filename,
374              fi);
375   return GNUNET_OK;
376 }
377
378
379 /**
380  * Simple, useful default implementation of a directory scanner
381  * (GNUNET_FS_DirectoryScanner).  This implementation expects to get a
382  * UNIX filename, will publish all files in the directory except hidden
383  * files (those starting with a ".").  Metadata will be extracted
384  * using GNU libextractor; the specific list of plugins should be
385  * specified in "cls", passing NULL will disable (!)  metadata
386  * extraction.  Keywords will be derived from the metadata and be
387  * subject to default canonicalization.  This is strictly a
388  * convenience function.
389  *
390  * @param cls must be of type "struct EXTRACTOR_Extractor*"
391  * @param h handle to the file sharing subsystem
392  * @param dirname name of the directory to scan
393  * @param do_index should files be indexed or inserted
394  * @param anonymity desired anonymity level
395  * @param priority priority for publishing
396  * @param expirationTime expiration for publication
397  * @param proc function called on each entry
398  * @param proc_cls closure for proc
399  * @param emsg where to store an error message (on errors)
400  * @return GNUNET_OK on success
401  */
402 int
403 GNUNET_FS_directory_scanner_default (void *cls,
404                                      struct GNUNET_FS_Handle *h,
405                                      const char *dirname,
406                                      int do_index,
407                                      uint32_t anonymity,
408                                      uint32_t priority,
409                                      struct GNUNET_TIME_Absolute expirationTime,
410                                      GNUNET_FS_FileProcessor proc,
411                                      void *proc_cls,
412                                      char **emsg)
413 {
414   struct EXTRACTOR_PluginList *ex = cls;
415   struct DirScanCls dsc;
416
417   dsc.h = h;
418   dsc.extractors = ex;
419   dsc.proc = proc;
420   dsc.proc_cls = proc_cls;
421   dsc.scanner = &GNUNET_FS_directory_scanner_default;
422   dsc.scanner_cls = cls;
423   dsc.do_index = do_index;
424   dsc.anonymity = anonymity;
425   dsc.priority = priority;
426   dsc.expiration = expirationTime;
427   if (-1 == GNUNET_DISK_directory_scan (dirname,
428                                         &dir_scan_cb,
429                                         &dsc))
430     {
431       GNUNET_assert (NULL != dsc.emsg);
432       *emsg = dsc.emsg;
433       return GNUNET_SYSERR;
434     }
435   return GNUNET_OK;
436 }
437
438
439 /**
440  * Closure for dirproc function.
441  */
442 struct EntryProcCls
443 {
444   /**
445    * Linked list of directory entries that is being
446    * created.
447    */
448   struct GNUNET_FS_FileInformation *entries;
449
450 };
451
452
453 /**
454  * Function that processes a directory entry that
455  * was obtained from the scanner.
456  * @param cls our closure
457  * @param filename name of the file (unused, why there???)
458  * @param fi information for publishing the file
459  */
460 static void
461 dirproc (void *cls,
462          const char *filename,
463          struct GNUNET_FS_FileInformation *fi)
464 {
465   struct EntryProcCls *dc = cls;
466
467   GNUNET_assert (fi->next == NULL);
468   GNUNET_assert (fi->dir == NULL);
469   fi->next = dc->entries;
470   dc->entries = fi;
471 }
472
473
474 /**
475  * Create a publish-structure from an existing file hierarchy, inferring
476  * and organizing keywords and metadata as much as possible.  This
477  * function primarily performs the recursive build and re-organizes
478  * keywords and metadata; for automatically getting metadata
479  * extraction, scanning of directories and creation of the respective
480  * GNUNET_FS_FileInformation entries the default scanner should be
481  * passed (GNUNET_FS_directory_scanner_default).  This is strictly a
482  * convenience function.
483  *
484  * @param h handle to the file sharing subsystem
485  * @param client_info initial value for the client-info value for this entry
486  * @param filename name of the top-level file or directory
487  * @param scanner function used to get a list of files in a directory
488  * @param scanner_cls closure for scanner
489  * @param do_index should files in the hierarchy be indexed?
490  * @param anonymity what is the desired anonymity level for sharing?
491  * @param priority what is the priority for OUR node to
492  *   keep this file available?  Use 0 for maximum anonymity and
493  *   minimum reliability...
494  * @param expirationTime when should this content expire?
495  * @param emsg where to store an error message
496  * @return publish structure entry for the directory, NULL on error
497  */
498 struct GNUNET_FS_FileInformation *
499 GNUNET_FS_file_information_create_from_directory (struct GNUNET_FS_Handle *h,
500                                                   void *client_info,
501                                                   const char *filename,
502                                                   GNUNET_FS_DirectoryScanner scanner,
503                                                   void *scanner_cls,
504                                                   int do_index,
505                                                   uint32_t anonymity,
506                                                   uint32_t priority,
507                                                   struct GNUNET_TIME_Absolute expirationTime,
508                                                   char **emsg)
509 {
510   struct GNUNET_FS_FileInformation *ret;
511   struct EntryProcCls dc;
512   struct GNUNET_FS_Uri *ksk;
513   struct GNUNET_CONTAINER_MetaData *meta;
514   const char *fn;
515   const char *ss;
516
517   dc.entries = NULL;
518   meta = GNUNET_CONTAINER_meta_data_create ();
519   GNUNET_FS_meta_data_make_directory (meta);
520   scanner (scanner_cls,
521            h,
522            filename,
523            do_index,
524            anonymity,
525            priority,
526            expirationTime,
527            &dirproc,
528            &dc,
529            emsg);
530   ksk = NULL; // FIXME...
531   // FIXME: create meta!
532   ret = GNUNET_FS_file_information_create_empty_directory (h,
533                                                            client_info,
534                                                            ksk,
535                                                            meta,
536                                                            anonymity,
537                                                            priority,
538                                                            expirationTime);
539   GNUNET_CONTAINER_meta_data_destroy (meta);
540   ret->data.dir.entries = dc.entries;
541   while (dc.entries != NULL)
542     {
543       dc.entries->dir = ret;
544       dc.entries = dc.entries->next;
545     }
546   fn = filename;
547   while (NULL != (ss = strstr (fn,
548                                DIR_SEPARATOR_STR)))
549     fn = ss + 1;
550   GNUNET_CONTAINER_meta_data_insert (ret->meta,
551                                      "<gnunet>",
552                                      EXTRACTOR_METATYPE_FILENAME,
553                                      EXTRACTOR_METAFORMAT_C_STRING,
554                                      "text/plain",
555                                      fn,
556                                      strlen (fn) + 1);
557   ret->filename = GNUNET_strdup (filename);
558   return ret;
559 }
560
561
562 /**
563  * Create an entry for an empty directory in a publish-structure.
564  * This function should be used by applications for which the
565  * use of "GNUNET_FS_file_information_create_from_directory"
566  * is not appropriate.
567  *
568  * @param h handle to the file sharing subsystem
569  * @param client_info initial value for the client-info value for this entry
570  * @param meta metadata for the directory
571  * @param keywords under which keywords should this directory be available
572  *         directly; can be NULL
573  * @param anonymity what is the desired anonymity level for sharing?
574  * @param priority what is the priority for OUR node to
575  *   keep this file available?  Use 0 for maximum anonymity and
576  *   minimum reliability...
577  * @param expirationTime when should this content expire?
578  * @return publish structure entry for the directory , NULL on error
579  */
580 struct GNUNET_FS_FileInformation *
581 GNUNET_FS_file_information_create_empty_directory (struct GNUNET_FS_Handle *h,
582                                                    void *client_info,
583                                                    const struct GNUNET_FS_Uri *keywords,
584                                                    const struct GNUNET_CONTAINER_MetaData *meta,
585                                                    uint32_t anonymity,
586                                                    uint32_t priority,
587                                                    struct GNUNET_TIME_Absolute expirationTime)
588 {
589   struct GNUNET_FS_FileInformation *ret;
590
591   ret = GNUNET_malloc (sizeof (struct GNUNET_FS_FileInformation));
592   ret->h = h;
593   ret->client_info = client_info;
594   ret->meta = GNUNET_CONTAINER_meta_data_duplicate (meta);
595   ret->keywords = GNUNET_FS_uri_dup (keywords);
596   ret->expirationTime = expirationTime;
597   ret->is_directory = GNUNET_YES;
598   ret->anonymity = anonymity;
599   ret->priority = priority;
600   return ret;
601 }
602
603
604 /**
605  * Add an entry to a directory in a publish-structure.  Clients
606  * should never modify publish structures that were passed to
607  * "GNUNET_FS_publish_start" already.
608  *
609  * @param dir the directory
610  * @param ent the entry to add; the entry must not have been
611  *            added to any other directory at this point and 
612  *            must not include "dir" in its structure
613  * @return GNUNET_OK on success, GNUNET_SYSERR on error
614  */
615 int
616 GNUNET_FS_file_information_add (struct GNUNET_FS_FileInformation *dir,
617                                 struct GNUNET_FS_FileInformation *ent)
618 {
619   if ( (ent->dir != NULL) ||
620        (ent->next != NULL) ||
621        (! dir->is_directory) )
622     {
623       GNUNET_break (0);
624       return GNUNET_SYSERR;
625     }
626   ent->dir = dir;
627   ent->next = dir->data.dir.entries;
628   dir->data.dir.entries = ent;
629   dir->data.dir.dir_size = 0;
630   return GNUNET_OK;
631 }
632
633
634 /**
635  * Inspect a file or directory in a publish-structure.  Clients
636  * should never modify publish structures that were passed to
637  * "GNUNET_FS_publish_start" already.  When called on a directory,
638  * this function will FIRST call "proc" with information about
639  * the directory itself and then for each of the files in the
640  * directory (but not for files in subdirectories).  When called
641  * on a file, "proc" will be called exactly once (with information
642  * about the specific file).
643  *
644  * @param dir the directory
645  * @param proc function to call on each entry
646  * @param proc_cls closure for proc
647  */
648 void
649 GNUNET_FS_file_information_inspect (struct GNUNET_FS_FileInformation *dir,
650                                     GNUNET_FS_FileInformationProcessor proc,
651                                     void *proc_cls)
652 {
653   struct GNUNET_FS_FileInformation *pos;
654
655   if (GNUNET_OK !=
656       proc (proc_cls, 
657             dir,
658             (dir->is_directory) ? dir->data.dir.dir_size : dir->data.file.file_size,
659             dir->meta,
660             &dir->keywords,
661             &dir->anonymity,
662             &dir->priority,
663             &dir->expirationTime,
664             &dir->client_info))
665     return;
666   if (! dir->is_directory)
667     return;
668   pos = dir->data.dir.entries;
669   while (pos != NULL)
670     {
671       if (GNUNET_OK != 
672           proc (proc_cls, 
673                 pos,
674                 (pos->is_directory) ? pos->data.dir.dir_size : pos->data.file.file_size,
675                 pos->meta,
676                 &pos->keywords,
677                 &pos->anonymity,
678                 &pos->priority,
679                 &pos->expirationTime,
680                 &pos->client_info))
681         break;
682       pos = pos->next;
683     }
684 }
685
686
687 /**
688  * Destroy publish-structure.  Clients should never destroy publish
689  * structures that were passed to "GNUNET_FS_publish_start" already.
690  *
691  * @param fi structure to destroy
692  * @param cleaner function to call on each entry in the structure
693  *        (useful to clean up client_info); can be NULL; return
694  *        values are ignored
695  * @param cleaner_cls closure for cleaner
696  */
697 void
698 GNUNET_FS_file_information_destroy (struct GNUNET_FS_FileInformation *fi,
699                                     GNUNET_FS_FileInformationProcessor cleaner,
700                                     void *cleaner_cls)
701 {
702   struct GNUNET_FS_FileInformation *pos;
703
704   if (fi->is_directory)
705     {
706       /* clean up directory */
707       while (NULL != (pos = fi->data.dir.entries))
708         {
709           fi->data.dir.entries = pos->next;
710           GNUNET_FS_file_information_destroy (pos, cleaner, cleaner_cls);
711         }
712       /* clean up client-info */
713       if (NULL != cleaner)
714         cleaner (cleaner_cls, 
715                  fi,
716                  fi->data.dir.dir_size,
717                  fi->meta,
718                  &fi->keywords,
719                  &fi->anonymity,
720                  &fi->priority,
721                  &fi->expirationTime,
722                  &fi->client_info);
723       GNUNET_free_non_null (fi->data.dir.dir_data);
724     }
725   else
726     {
727       /* call clean-up function of the reader */
728       if (fi->data.file.reader != NULL)
729         fi->data.file.reader (fi->data.file.reader_cls, 0, 0, 
730                               NULL, NULL);
731       /* clean up client-info */
732       if (NULL != cleaner)
733         cleaner (cleaner_cls, 
734                  fi,
735                  fi->data.file.file_size,
736                  fi->meta,
737                  &fi->keywords,
738                  &fi->anonymity,
739                  &fi->priority,
740                  &fi->expirationTime,
741                  &fi->client_info);
742     }
743   GNUNET_free_non_null (fi->filename);
744   GNUNET_free_non_null (fi->emsg);
745   GNUNET_free_non_null (fi->chk_uri);
746   /* clean up serialization */
747   if ( (NULL != fi->serialization) &&
748        (0 != UNLINK (fi->serialization)) )
749     GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
750                               "unlink",
751                               fi->serialization);
752   if (NULL != fi->keywords)
753     GNUNET_FS_uri_destroy (fi->keywords);
754   if (NULL != fi->meta)
755     GNUNET_CONTAINER_meta_data_destroy (fi->meta);
756   GNUNET_free_non_null (fi->serialization);
757   if (fi->te != NULL)
758     {
759       GNUNET_FS_tree_encoder_finish (fi->te,
760                                      NULL, NULL);
761       fi->te = NULL;
762     }
763   GNUNET_free (fi);
764 }
765
766
767 /* end of fs_file_information.c */