fs_file_information.c | fs_file_information.c | |||
---|---|---|---|---|
skipping to change at line 25 | skipping to change at line 25 | |||
You should have received a copy of the GNU General Public License | You should have received a copy of the GNU General Public License | |||
along with GNUnet; see the file COPYING. If not, write to the | along with GNUnet; see the file COPYING. If not, write to the | |||
Free Software Foundation, Inc., 59 Temple Place - Suite 330, | Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |||
Boston, MA 02111-1307, USA. | Boston, MA 02111-1307, USA. | |||
*/ | */ | |||
/** | /** | |||
* @file fs/fs_file_information.c | * @file fs/fs_file_information.c | |||
* @brief Manage information for publishing directory hierarchies | * @brief Manage information for publishing directory hierarchies | |||
* @author Christian Grothoff | * @author Christian Grothoff | |||
* | ||||
* TODO: | ||||
* - metadata filename clean up code | ||||
* - metadata/ksk generation for directories from contained files | ||||
*/ | */ | |||
#include "platform.h" | #include "platform.h" | |||
#include <extractor.h> | #include <extractor.h> | |||
#include "gnunet_fs_service.h" | #include "gnunet_fs_service.h" | |||
#include "fs_api.h" | #include "fs_api.h" | |||
#include "fs_tree.h" | #include "fs_tree.h" | |||
/** | /** | |||
* Add meta data that libextractor finds to our meta data | ||||
* container. | ||||
* | ||||
* @param cls closure, our meta data container | ||||
* @param plugin_name name of the plugin that produced this value; | ||||
* special values can be used (i.e. '<zlib>' for zlib being | ||||
* used in the main libextractor library and yielding | ||||
* meta data). | ||||
* @param type libextractor-type describing the meta data | ||||
* @param format basic format information about data | ||||
* @param data_mime_type mime-type of data (not of the original file); | ||||
* can be NULL (if mime-type is not known) | ||||
* @param data actual meta-data found | ||||
* @param data_len number of bytes in data | ||||
* @return always 0 to continue extracting | ||||
*/ | ||||
static int | ||||
add_to_md (void *cls, const char *plugin_name, enum EXTRACTOR_MetaType type | ||||
, | ||||
enum EXTRACTOR_MetaFormat format, const char *data_mime_type, | ||||
const char *data, size_t data_len) | ||||
{ | ||||
struct GNUNET_CONTAINER_MetaData *md = cls; | ||||
(void) GNUNET_CONTAINER_meta_data_insert (md, plugin_name, type, format, | ||||
data_mime_type, data, data_len) | ||||
; | ||||
return 0; | ||||
} | ||||
/** | ||||
* Extract meta-data from a file. | ||||
* | ||||
* @return GNUNET_SYSERR on error, otherwise the number | ||||
* of meta-data items obtained | ||||
*/ | ||||
int | ||||
GNUNET_FS_meta_data_extract_from_file (struct GNUNET_CONTAINER_MetaData *md | ||||
, | ||||
const char *filename, | ||||
struct EXTRACTOR_PluginList *extract | ||||
ors) | ||||
{ | ||||
int old; | ||||
if (filename == NULL) | ||||
return GNUNET_SYSERR; | ||||
if (extractors == NULL) | ||||
return 0; | ||||
old = GNUNET_CONTAINER_meta_data_iterate (md, NULL, NULL); | ||||
GNUNET_assert (old >= 0); | ||||
EXTRACTOR_extract (extractors, filename, NULL, 0, &add_to_md, md); | ||||
return (GNUNET_CONTAINER_meta_data_iterate (md, NULL, NULL) - old); | ||||
} | ||||
/** | ||||
* Obtain the name under which this file information | * Obtain the name under which this file information | |||
* structure is stored on disk. Only works for top-level | * structure is stored on disk. Only works for top-level | |||
* file information structures. | * file information structures. | |||
* | * | |||
* @param s structure to get the filename for | * @param s structure to get the filename for | |||
* @return NULL on error, otherwise filename that | * @return NULL on error, otherwise filename that | |||
* can be passed to "GNUNET_FS_file_information_recover" | * can be passed to "GNUNET_FS_file_information_recover" | |||
* to read this fi-struct from disk. | * to read this fi-struct from disk. | |||
*/ | */ | |||
const char * | const char * | |||
GNUNET_FS_file_information_get_id (struct GNUNET_FS_FileInformation *s) | GNUNET_FS_file_information_get_id (struct GNUNET_FS_FileInformation *s) | |||
{ | { | |||
if (NULL != s->dir) | if (NULL != s->dir) | |||
return NULL; | return NULL; | |||
return s->serialization; | return s->serialization; | |||
} | } | |||
/** | /** | |||
* Obtain the filename from the file information structure. | ||||
* | ||||
* @param s structure to get the filename for | ||||
* @return "filename" field of the structure (can be NULL) | ||||
*/ | ||||
const char * | ||||
GNUNET_FS_file_information_get_filename (struct GNUNET_FS_FileInformation * | ||||
s) | ||||
{ | ||||
return s->filename; | ||||
} | ||||
/** | ||||
* Set the filename in the file information structure. | ||||
* If filename was already set, frees it before setting the new one. | ||||
* Makes a copy of the argument. | ||||
* | ||||
* @param s structure to get the filename for | ||||
* @param filename filename to set | ||||
*/ | ||||
void | ||||
GNUNET_FS_file_information_set_filename (struct GNUNET_FS_FileInformation * | ||||
s, | ||||
const char *filename) | ||||
{ | ||||
GNUNET_free_non_null (s->filename); | ||||
if (filename) | ||||
s->filename = GNUNET_strdup (filename); | ||||
else | ||||
s->filename = NULL; | ||||
} | ||||
/** | ||||
* Create an entry for a file in a publish-structure. | * Create an entry for a file in a publish-structure. | |||
* | * | |||
* @param h handle to the file sharing subsystem | * @param h handle to the file sharing subsystem | |||
* @param client_info initial value for the client-info value for this entr y | * @param client_info initial value for the client-info value for this entr y | |||
* @param filename name of the file or directory to publish | * @param filename name of the file or directory to publish | |||
* @param keywords under which keywords should this file be available | * @param keywords under which keywords should this file be available | |||
* directly; can be NULL | * directly; can be NULL | |||
* @param meta metadata for the file | * @param meta metadata for the file | |||
* @param do_index GNUNET_YES for index, GNUNET_NO for insertion, | * @param do_index GNUNET_YES for index, GNUNET_NO for insertion, | |||
* GNUNET_SYSERR for simulation | * GNUNET_SYSERR for simulation | |||
skipping to change at line 171 | skipping to change at line 146 | |||
ret->h = h; | ret->h = h; | |||
ret->filename = GNUNET_strdup (filename); | ret->filename = GNUNET_strdup (filename); | |||
#if !WINDOWS | #if !WINDOWS | |||
fn = filename; | fn = filename; | |||
#else | #else | |||
plibc_conv_to_win_path (filename, fn_conv); | plibc_conv_to_win_path (filename, fn_conv); | |||
fn = fn_conv; | fn = fn_conv; | |||
#endif | #endif | |||
while (NULL != (ss = strstr (fn, DIR_SEPARATOR_STR))) | while (NULL != (ss = strstr (fn, DIR_SEPARATOR_STR))) | |||
fn = ss + 1; | fn = ss + 1; | |||
#if !WINDOWS | ||||
GNUNET_CONTAINER_meta_data_insert (ret->meta, "<gnunet>", | GNUNET_CONTAINER_meta_data_insert (ret->meta, "<gnunet>", | |||
EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FIL ENAME, | EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FIL ENAME, | |||
EXTRACTOR_METAFORMAT_C_STRING, | EXTRACTOR_METAFORMAT_C_STRING, | |||
"text/plain", fn, strlen (fn) + 1); | "text/plain", fn, strlen (fn) + 1); | |||
#else | ||||
GNUNET_CONTAINER_meta_data_insert (ret->meta, "<gnunet>", | ||||
EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FIL | ||||
ENAME, | ||||
EXTRACTOR_METAFORMAT_UTF8, | ||||
"text/plain", fn, strlen (fn) + 1); | ||||
#endif | ||||
return ret; | return ret; | |||
} | } | |||
/** | /** | |||
* Create an entry for a file in a publish-structure. | * Create an entry for a file in a publish-structure. | |||
* | * | |||
* @param h handle to the file sharing subsystem | * @param h handle to the file sharing subsystem | |||
* @param client_info initial value for the client-info value for this entr y | * @param client_info initial value for the client-info value for this entr y | |||
* @param length length of the file | * @param length length of the file | |||
* @param data data for the file (should not be used afterwards by | * @param data data for the file (should not be used afterwards by | |||
skipping to change at line 270 | skipping to change at line 252 | |||
ret->keywords = (keywords == NULL) ? NULL : GNUNET_FS_uri_dup (keywords); | ret->keywords = (keywords == NULL) ? NULL : GNUNET_FS_uri_dup (keywords); | |||
ret->data.file.reader = reader; | ret->data.file.reader = reader; | |||
ret->data.file.reader_cls = reader_cls; | ret->data.file.reader_cls = reader_cls; | |||
ret->data.file.do_index = do_index; | ret->data.file.do_index = do_index; | |||
ret->data.file.file_size = length; | ret->data.file.file_size = length; | |||
ret->bo = *bo; | ret->bo = *bo; | |||
return ret; | return ret; | |||
} | } | |||
/** | /** | |||
* Closure for "dir_scan_cb". | ||||
*/ | ||||
struct DirScanCls | ||||
{ | ||||
/** | ||||
* Metadata extractors to use. | ||||
*/ | ||||
struct EXTRACTOR_PluginList *extractors; | ||||
/** | ||||
* Master context. | ||||
*/ | ||||
struct GNUNET_FS_Handle *h; | ||||
/** | ||||
* Function to call on each directory entry. | ||||
*/ | ||||
GNUNET_FS_FileProcessor proc; | ||||
/** | ||||
* Closure for proc. | ||||
*/ | ||||
void *proc_cls; | ||||
/** | ||||
* Scanner to use for subdirectories. | ||||
*/ | ||||
GNUNET_FS_DirectoryScanner scanner; | ||||
/** | ||||
* Closure for scanner. | ||||
*/ | ||||
void *scanner_cls; | ||||
/** | ||||
* Set to an error message (if any). | ||||
*/ | ||||
char *emsg; | ||||
/** | ||||
* Block options. | ||||
*/ | ||||
const struct GNUNET_FS_BlockOptions *bo; | ||||
/** | ||||
* Should files be indexed? | ||||
*/ | ||||
int do_index; | ||||
}; | ||||
/** | ||||
* Function called on each entry in a file to cause | ||||
* default-publishing. | ||||
* | ||||
* @param cls closure (struct DirScanCls) | ||||
* @param filename name of the file to be published | ||||
* @return GNUNET_OK on success, GNUNET_SYSERR to abort | ||||
*/ | ||||
static int | ||||
dir_scan_cb (void *cls, const char *filename) | ||||
{ | ||||
struct DirScanCls *dsc = cls; | ||||
struct stat sbuf; | ||||
struct GNUNET_FS_FileInformation *fi; | ||||
struct GNUNET_FS_Uri *keywords; | ||||
struct GNUNET_CONTAINER_MetaData *meta; | ||||
if (0 != STAT (filename, &sbuf)) | ||||
{ | ||||
GNUNET_asprintf (&dsc->emsg, _("`%s' failed on file `%s': %s"), "stat", | ||||
filename, STRERROR (errno)); | ||||
return GNUNET_SYSERR; | ||||
} | ||||
if (S_ISDIR (sbuf.st_mode)) | ||||
{ | ||||
fi = GNUNET_FS_file_information_create_from_directory (dsc->h, NULL, | ||||
filename, | ||||
dsc->scanner, | ||||
dsc->scanner_cls | ||||
, | ||||
dsc->do_index, | ||||
dsc->bo, &dsc->e | ||||
msg); | ||||
if (NULL == fi) | ||||
{ | ||||
GNUNET_assert (NULL != dsc->emsg); | ||||
return GNUNET_SYSERR; | ||||
} | ||||
} | ||||
else | ||||
{ | ||||
meta = GNUNET_CONTAINER_meta_data_create (); | ||||
GNUNET_FS_meta_data_extract_from_file (meta, filename, dsc->extractors) | ||||
; | ||||
keywords = GNUNET_FS_uri_ksk_create_from_meta_data (meta); | ||||
fi = GNUNET_FS_file_information_create_from_file (dsc->h, NULL, filenam | ||||
e, | ||||
keywords, meta, | ||||
dsc->do_index, dsc->b | ||||
o); | ||||
GNUNET_CONTAINER_meta_data_destroy (meta); | ||||
GNUNET_FS_uri_destroy (keywords); | ||||
} | ||||
dsc->proc (dsc->proc_cls, filename, fi); | ||||
return GNUNET_OK; | ||||
} | ||||
/** | ||||
* Simple, useful default implementation of a directory scanner | ||||
* (GNUNET_FS_DirectoryScanner). This implementation expects to get a | ||||
* UNIX filename, will publish all files in the directory except hidden | ||||
* files (those starting with a "."). Metadata will be extracted | ||||
* using GNU libextractor; the specific list of plugins should be | ||||
* specified in "cls", passing NULL will disable (!) metadata | ||||
* extraction. Keywords will be derived from the metadata and be | ||||
* subject to default canonicalization. This is strictly a | ||||
* convenience function. | ||||
* | ||||
* @param cls must be of type "struct EXTRACTOR_Extractor*" | ||||
* @param h handle to the file sharing subsystem | ||||
* @param dirname name of the directory to scan | ||||
* @param do_index should files be indexed or inserted | ||||
* @param bo block options | ||||
* @param proc function called on each entry | ||||
* @param proc_cls closure for proc | ||||
* @param emsg where to store an error message (on errors) | ||||
* @return GNUNET_OK on success | ||||
*/ | ||||
int | ||||
GNUNET_FS_directory_scanner_default (void *cls, struct GNUNET_FS_Handle *h, | ||||
const char *dirname, int do_index, | ||||
const struct GNUNET_FS_BlockOptions *b | ||||
o, | ||||
GNUNET_FS_FileProcessor proc, | ||||
void *proc_cls, char **emsg) | ||||
{ | ||||
struct EXTRACTOR_PluginList *ex = cls; | ||||
struct DirScanCls dsc; | ||||
dsc.h = h; | ||||
dsc.extractors = ex; | ||||
dsc.proc = proc; | ||||
dsc.proc_cls = proc_cls; | ||||
dsc.scanner = &GNUNET_FS_directory_scanner_default; | ||||
dsc.scanner_cls = cls; | ||||
dsc.do_index = do_index; | ||||
dsc.bo = bo; | ||||
if (-1 == GNUNET_DISK_directory_scan (dirname, &dir_scan_cb, &dsc)) | ||||
{ | ||||
GNUNET_assert (NULL != dsc.emsg); | ||||
*emsg = dsc.emsg; | ||||
return GNUNET_SYSERR; | ||||
} | ||||
return GNUNET_OK; | ||||
} | ||||
/** | ||||
* Aggregate information we keep for meta data in each directory. | ||||
*/ | ||||
struct MetaValueInformation | ||||
{ | ||||
/** | ||||
* Mime-type of data. | ||||
*/ | ||||
const char *mime_type; | ||||
/** | ||||
* The actual meta data. | ||||
*/ | ||||
const char *data; | ||||
/** | ||||
* Number of bytes in 'data'. | ||||
*/ | ||||
size_t data_size; | ||||
/** | ||||
* Type of the meta data. | ||||
*/ | ||||
enum EXTRACTOR_MetaType type; | ||||
/** | ||||
* Format of the meta data. | ||||
*/ | ||||
enum EXTRACTOR_MetaFormat format; | ||||
/** | ||||
* How often does this meta value occur in this directory? | ||||
*/ | ||||
unsigned int frequency; | ||||
}; | ||||
/** | ||||
* Type of a function that libextractor calls for each | ||||
* meta data item found. | ||||
* | ||||
* @param cls the container multihashmap to update | ||||
* @param plugin_name name of the plugin that produced this value; | ||||
* special values can be used (i.e. '<zlib>' for zlib being | ||||
* used in the main libextractor library and yielding | ||||
* meta data). | ||||
* @param type libextractor-type describing the meta data | ||||
* @param format basic format information about data | ||||
* @param data_mime_type mime-type of data (not of the original file); | ||||
* can be NULL (if mime-type is not known) | ||||
* @param data actual meta-data found | ||||
* @param data_len number of bytes in data | ||||
* @return 0 to continue extracting / iterating | ||||
*/ | ||||
static int | ||||
update_metamap (void *cls, const char *plugin_name, | ||||
enum EXTRACTOR_MetaType type, enum EXTRACTOR_MetaFormat for | ||||
mat, | ||||
const char *data_mime_type, const char *data, size_t data_l | ||||
en) | ||||
{ | ||||
struct GNUNET_CONTAINER_MultiHashMap *map = cls; | ||||
GNUNET_HashCode key; | ||||
struct MetaValueInformation *mvi; | ||||
GNUNET_CRYPTO_hash (data, data_len, &key); | ||||
mvi = GNUNET_CONTAINER_multihashmap_get (map, &key); | ||||
if (mvi == NULL) | ||||
{ | ||||
mvi = GNUNET_malloc (sizeof (struct MetaValueInformation)); | ||||
mvi->mime_type = data_mime_type; | ||||
mvi->data = data; | ||||
mvi->data_size = data_len; | ||||
mvi->type = type; | ||||
mvi->format = format; | ||||
GNUNET_CONTAINER_multihashmap_put (map, &key, mvi, | ||||
GNUNET_CONTAINER_MULTIHASHMAPOPTION_ | ||||
UNIQUE_ONLY); | ||||
} | ||||
mvi->frequency++; | ||||
return 0; | ||||
} | ||||
/** | ||||
* Aggregate information we keep for keywords in each directory. | ||||
*/ | ||||
struct KeywordInformation | ||||
{ | ||||
/** | ||||
* Mime-type of keyword. | ||||
*/ | ||||
const char *keyword; | ||||
/** | ||||
* How often does this meta value occur in this directory? | ||||
*/ | ||||
unsigned int frequency; | ||||
}; | ||||
/** | ||||
* Closure for dirproc function. | ||||
*/ | ||||
struct EntryProcCls | ||||
{ | ||||
/** | ||||
* Linked list of directory entries that is being | ||||
* created. | ||||
*/ | ||||
struct GNUNET_FS_FileInformation *entries; | ||||
/** | ||||
* Map describing the meta data for all entries in the | ||||
* directory. Keys are the hash of the meta-value, | ||||
* values are of type 'struct MetaValueInformation'. | ||||
*/ | ||||
struct GNUNET_CONTAINER_MultiHashMap *metamap; | ||||
/** | ||||
* Map describing the keywords for all entries in the | ||||
* directory. Keys are the hash of the keyword, | ||||
* values are of type 'struct KeywordInformation'. | ||||
*/ | ||||
struct GNUNET_CONTAINER_MultiHashMap *keywordmap; | ||||
/** | ||||
* Number of entries in 'entries'. | ||||
*/ | ||||
unsigned int count; | ||||
}; | ||||
/** | ||||
* Function that processes a directory entry that | ||||
* was obtained from the scanner. Adds each entry to | ||||
* the directory and computes directroy meta map. | ||||
* | ||||
* @param cls our closure | ||||
* @param filename name of the file (unused, why there???) | ||||
* @param fi information for publishing the file | ||||
*/ | ||||
static void | ||||
dirproc_add (void *cls, const char *filename, | ||||
struct GNUNET_FS_FileInformation *fi) | ||||
{ | ||||
struct EntryProcCls *dc = cls; | ||||
unsigned int i; | ||||
const char *kw; | ||||
struct KeywordInformation *ki; | ||||
GNUNET_HashCode key; | ||||
GNUNET_assert (fi->next == NULL); | ||||
GNUNET_assert (fi->dir == NULL); | ||||
fi->next = dc->entries; | ||||
dc->entries = fi; | ||||
dc->count++; | ||||
if (NULL != fi->meta) | ||||
GNUNET_CONTAINER_meta_data_iterate (fi->meta, &update_metamap, dc->meta | ||||
map); | ||||
for (i = 0; i < fi->keywords->data.ksk.keywordCount; i++) | ||||
{ | ||||
kw = fi->keywords->data.ksk.keywords[i]; | ||||
GNUNET_CRYPTO_hash (kw, strlen (kw), &key); | ||||
ki = GNUNET_CONTAINER_multihashmap_get (dc->keywordmap, &key); | ||||
if (ki == NULL) | ||||
{ | ||||
ki = GNUNET_malloc (sizeof (struct KeywordInformation)); | ||||
ki->keyword = &kw[1]; | ||||
GNUNET_CONTAINER_multihashmap_put (dc->keywordmap, &key, ki, | ||||
GNUNET_CONTAINER_MULTIHASHMAPOPTIO | ||||
N_UNIQUE_ONLY); | ||||
} | ||||
ki->frequency++; | ||||
} | ||||
} | ||||
/** | ||||
* Closure for 'compute_directory_metadata'. | ||||
*/ | ||||
struct ComputeDirectoryMetadataContext | ||||
{ | ||||
/** | ||||
* Where to store the extracted keywords. | ||||
*/ | ||||
struct GNUNET_FS_Uri *ksk; | ||||
/** | ||||
* Where to store the extracted meta data. | ||||
*/ | ||||
struct GNUNET_CONTAINER_MetaData *meta; | ||||
/** | ||||
* Threshold to apply for adding meta data. | ||||
*/ | ||||
unsigned int threshold; | ||||
}; | ||||
/** | ||||
* Add metadata that occurs in more than the threshold entries of the | ||||
* directory to the directory itself. For example, if most files in a | ||||
* directory are of the same mime-type, the directory should have that | ||||
* mime-type as a keyword. | ||||
* | ||||
* @param cls the 'struct ComputeDirectoryMetadataContext' | ||||
* @param key unused | ||||
* @param value the 'struct MetaValueInformation' (to be freed as well) | ||||
* @return GNUNET_OK | ||||
*/ | ||||
static int | ||||
compute_directory_metadata (void *cls, const GNUNET_HashCode * key, void *v | ||||
alue) | ||||
{ | ||||
struct ComputeDirectoryMetadataContext *cdmc = cls; | ||||
struct MetaValueInformation *mvi = value; | ||||
if (mvi->frequency > cdmc->threshold) | ||||
{ | ||||
if (mvi->type != EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME) | ||||
(void) GNUNET_CONTAINER_meta_data_insert (cdmc->meta, "<children>", | ||||
mvi->type, mvi->format, | ||||
mvi->mime_type, mvi->data, | ||||
mvi->data_size); | ||||
if ((mvi->format == EXTRACTOR_METAFORMAT_UTF8) || | ||||
(mvi->format == EXTRACTOR_METAFORMAT_C_STRING)) | ||||
GNUNET_FS_uri_ksk_add_keyword (cdmc->ksk, mvi->data, GNUNET_NO); | ||||
} | ||||
GNUNET_free (mvi); | ||||
return GNUNET_OK; | ||||
} | ||||
/** | ||||
* Add keywords that occur in more than the threshold entries of the | ||||
* directory to the directory itself. | ||||
* | ||||
* @param cls the 'struct ComputeDirectoryMetadataContext' | ||||
* @param key unused | ||||
* @param value the 'struct Keywordnformation' (to be freed as well) | ||||
* @return GNUNET_OK | ||||
*/ | ||||
static int | ||||
compute_directory_keywords (void *cls, const GNUNET_HashCode * key, void *v | ||||
alue) | ||||
{ | ||||
struct ComputeDirectoryMetadataContext *cdmc = cls; | ||||
struct KeywordInformation *ki = value; | ||||
if (ki->frequency > cdmc->threshold) | ||||
(void) GNUNET_FS_uri_ksk_add_keyword (cdmc->ksk, ki->keyword, GNUNET_NO | ||||
); | ||||
GNUNET_free (ki); | ||||
return GNUNET_OK; | ||||
} | ||||
/** | ||||
* Create a publish-structure from an existing file hierarchy, inferring | ||||
* and organizing keywords and metadata as much as possible. This | ||||
* function primarily performs the recursive build and re-organizes | ||||
* keywords and metadata; for automatically getting metadata | ||||
* extraction, scanning of directories and creation of the respective | ||||
* GNUNET_FS_FileInformation entries the default scanner should be | ||||
* passed (GNUNET_FS_directory_scanner_default). This is strictly a | ||||
* convenience function. | ||||
* | ||||
* @param h handle to the file sharing subsystem | ||||
* @param client_info initial value for the client-info value for this entr | ||||
y | ||||
* @param filename name of the top-level file or directory | ||||
* @param scanner function used to get a list of files in a directory | ||||
* @param scanner_cls closure for scanner | ||||
* @param do_index should files in the hierarchy be indexed? | ||||
* @param bo block options | ||||
* @param emsg where to store an error message | ||||
* @return publish structure entry for the directory, NULL on error | ||||
*/ | ||||
struct GNUNET_FS_FileInformation * | ||||
GNUNET_FS_file_information_create_from_directory (struct GNUNET_FS_Handle * | ||||
h, | ||||
void *client_info, | ||||
const char *filename, | ||||
GNUNET_FS_DirectoryScanne | ||||
r | ||||
scanner, void *scanner_cl | ||||
s, | ||||
int do_index, | ||||
const struct | ||||
GNUNET_FS_BlockOptions *b | ||||
o, | ||||
char **emsg) | ||||
{ | ||||
struct GNUNET_FS_FileInformation *ret; | ||||
struct ComputeDirectoryMetadataContext cdmc; | ||||
struct EntryProcCls dc; | ||||
const char *fn; | ||||
const char *ss; | ||||
char *dn; | ||||
struct GNUNET_FS_FileInformation *epos; | ||||
unsigned int i; | ||||
const char *kw; | ||||
dc.entries = NULL; | ||||
dc.count = 0; | ||||
dc.metamap = GNUNET_CONTAINER_multihashmap_create (64); | ||||
dc.keywordmap = GNUNET_CONTAINER_multihashmap_create (64); | ||||
/* update children to point to directory and generate statistics | ||||
* on all meta data in children */ | ||||
scanner (scanner_cls, h, filename, do_index, bo, &dirproc_add, &dc, emsg) | ||||
; | ||||
cdmc.meta = GNUNET_CONTAINER_meta_data_create (); | ||||
cdmc.ksk = GNUNET_malloc (sizeof (struct GNUNET_FS_Uri)); | ||||
cdmc.ksk->type = ksk; | ||||
cdmc.threshold = 1 + dc.count / 2; /* 50% threshold for now */ | ||||
GNUNET_FS_meta_data_make_directory (cdmc.meta); | ||||
GNUNET_CONTAINER_multihashmap_iterate (dc.metamap, | ||||
&compute_directory_metadata, &cdmc | ||||
); | ||||
GNUNET_CONTAINER_multihashmap_iterate (dc.keywordmap, | ||||
&compute_directory_keywords, &cdmc | ||||
); | ||||
GNUNET_CONTAINER_multihashmap_destroy (dc.metamap); | ||||
GNUNET_CONTAINER_multihashmap_destroy (dc.keywordmap); | ||||
/* remove keywords in children that are already in the | ||||
* parent */ | ||||
for (epos = dc.entries; NULL != epos; epos = epos->next) | ||||
{ | ||||
for (i = 0; i < cdmc.ksk->data.ksk.keywordCount; i++) | ||||
{ | ||||
kw = cdmc.ksk->data.ksk.keywords[i]; | ||||
GNUNET_FS_uri_ksk_remove_keyword (epos->keywords, &kw[1]); | ||||
} | ||||
} | ||||
GNUNET_FS_uri_ksk_add_keyword (cdmc.ksk, GNUNET_FS_DIRECTORY_MIME, GNUNET | ||||
_NO); | ||||
ret = | ||||
GNUNET_FS_file_information_create_empty_directory (h, client_info, cd | ||||
mc.ksk, | ||||
cdmc.meta, bo); | ||||
GNUNET_CONTAINER_meta_data_destroy (cdmc.meta); | ||||
GNUNET_FS_uri_destroy (cdmc.ksk); | ||||
ret->data.dir.entries = dc.entries; | ||||
while (dc.entries != NULL) | ||||
{ | ||||
dc.entries->dir = ret; | ||||
dc.entries = dc.entries->next; | ||||
} | ||||
fn = filename; | ||||
while ((NULL != (ss = strstr (fn, DIR_SEPARATOR_STR))) && (strlen (ss) > | ||||
1)) | ||||
fn = ss + 1; | ||||
GNUNET_asprintf (&dn, "%s/", fn); | ||||
GNUNET_CONTAINER_meta_data_insert (ret->meta, "<gnunet>", | ||||
EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FIL | ||||
ENAME, | ||||
EXTRACTOR_METAFORMAT_C_STRING, | ||||
"text/plain", dn, strlen (dn) + 1); | ||||
GNUNET_free (dn); | ||||
ret->filename = GNUNET_strdup (filename); | ||||
return ret; | ||||
} | ||||
/** | ||||
* Test if a given entry represents a directory. | * Test if a given entry represents a directory. | |||
* | * | |||
* @param ent check if this FI represents a directory | * @param ent check if this FI represents a directory | |||
* @return GNUNET_YES if so, GNUNET_NO if not | * @return GNUNET_YES if so, GNUNET_NO if not | |||
*/ | */ | |||
int | int | |||
GNUNET_FS_file_information_is_directory (const struct GNUNET_FS_FileInforma tion | GNUNET_FS_file_information_is_directory (const struct GNUNET_FS_FileInforma tion | |||
*ent) | *ent) | |||
{ | { | |||
return ent->is_directory; | return ent->is_directory; | |||
skipping to change at line 788 | skipping to change at line 276 | |||
* This function should be used by applications for which the | * This function should be used by applications for which the | |||
* use of "GNUNET_FS_file_information_create_from_directory" | * use of "GNUNET_FS_file_information_create_from_directory" | |||
* is not appropriate. | * is not appropriate. | |||
* | * | |||
* @param h handle to the file sharing subsystem | * @param h handle to the file sharing subsystem | |||
* @param client_info initial value for the client-info value for this entr y | * @param client_info initial value for the client-info value for this entr y | |||
* @param meta metadata for the directory | * @param meta metadata for the directory | |||
* @param keywords under which keywords should this directory be available | * @param keywords under which keywords should this directory be available | |||
* directly; can be NULL | * directly; can be NULL | |||
* @param bo block options | * @param bo block options | |||
* @param filename name of the directory; can be NULL | ||||
* @return publish structure entry for the directory , NULL on error | * @return publish structure entry for the directory , NULL on error | |||
*/ | */ | |||
struct GNUNET_FS_FileInformation * | struct GNUNET_FS_FileInformation * | |||
GNUNET_FS_file_information_create_empty_directory (struct GNUNET_FS_Handle *h, | GNUNET_FS_file_information_create_empty_directory (struct GNUNET_FS_Handle *h, | |||
void *client_info, | void *client_info, | |||
const struct GNUNET_FS_U ri | const struct GNUNET_FS_U ri | |||
*keywords, | *keywords, | |||
const struct | const struct | |||
GNUNET_CONTAINER_MetaDat a | GNUNET_CONTAINER_MetaDat a | |||
*meta, | *meta, | |||
const struct | const struct | |||
GNUNET_FS_BlockOptions * | GNUNET_FS_BlockOptions * | |||
bo) | bo, | |||
const char *filename) | ||||
{ | { | |||
struct GNUNET_FS_FileInformation *ret; | struct GNUNET_FS_FileInformation *ret; | |||
ret = GNUNET_malloc (sizeof (struct GNUNET_FS_FileInformation)); | ret = GNUNET_malloc (sizeof (struct GNUNET_FS_FileInformation)); | |||
ret->h = h; | ret->h = h; | |||
ret->client_info = client_info; | ret->client_info = client_info; | |||
ret->meta = GNUNET_CONTAINER_meta_data_duplicate (meta); | ret->meta = GNUNET_CONTAINER_meta_data_duplicate (meta); | |||
ret->keywords = GNUNET_FS_uri_dup (keywords); | ret->keywords = GNUNET_FS_uri_dup (keywords); | |||
ret->bo = *bo; | ret->bo = *bo; | |||
ret->is_directory = GNUNET_YES; | ret->is_directory = GNUNET_YES; | |||
if (filename != NULL) | ||||
ret->filename = GNUNET_strdup (filename); | ||||
return ret; | return ret; | |||
} | } | |||
/** | /** | |||
* Add an entry to a directory in a publish-structure. Clients | * Add an entry to a directory in a publish-structure. Clients | |||
* should never modify publish structures that were passed to | * should never modify publish structures that were passed to | |||
* "GNUNET_FS_publish_start" already. | * "GNUNET_FS_publish_start" already. | |||
* | * | |||
* @param dir the directory | * @param dir the directory | |||
* @param ent the entry to add; the entry must not have been | * @param ent the entry to add; the entry must not have been | |||
* added to any other directory at this point and | * added to any other directory at this point and | |||
* must not include "dir" in its structure | * must not include "dir" in its structure | |||
* @return GNUNET_OK on success, GNUNET_SYSERR on error | * @return GNUNET_OK on success, GNUNET_SYSERR on error | |||
*/ | */ | |||
int | int | |||
GNUNET_FS_file_information_add (struct GNUNET_FS_FileInformation *dir, | GNUNET_FS_file_information_add (struct GNUNET_FS_FileInformation *dir, | |||
struct GNUNET_FS_FileInformation *ent) | struct GNUNET_FS_FileInformation *ent) | |||
{ | { | |||
if ((ent->dir != NULL) || (ent->next != NULL) || (!dir->is_directory)) | if ((ent->dir != NULL) || (ent->next != NULL) || (dir->is_directory != GN UNET_YES)) | |||
{ | { | |||
GNUNET_break (0); | GNUNET_break (0); | |||
return GNUNET_SYSERR; | return GNUNET_SYSERR; | |||
} | } | |||
ent->dir = dir; | ent->dir = dir; | |||
ent->next = dir->data.dir.entries; | ent->next = dir->data.dir.entries; | |||
dir->data.dir.entries = ent; | dir->data.dir.entries = ent; | |||
dir->data.dir.dir_size = 0; | dir->data.dir.dir_size = 0; | |||
return GNUNET_OK; | return GNUNET_OK; | |||
} | } | |||
skipping to change at line 865 | skipping to change at line 357 | |||
GNUNET_FS_file_information_inspect (struct GNUNET_FS_FileInformation *dir, | GNUNET_FS_file_information_inspect (struct GNUNET_FS_FileInformation *dir, | |||
GNUNET_FS_FileInformationProcessor proc , | GNUNET_FS_FileInformationProcessor proc , | |||
void *proc_cls) | void *proc_cls) | |||
{ | { | |||
struct GNUNET_FS_FileInformation *pos; | struct GNUNET_FS_FileInformation *pos; | |||
int no; | int no; | |||
no = GNUNET_NO; | no = GNUNET_NO; | |||
if (GNUNET_OK != | if (GNUNET_OK != | |||
proc (proc_cls, dir, | proc (proc_cls, dir, | |||
(dir->is_directory) ? dir->data.dir.dir_size : dir->data. | (dir->is_directory == GNUNET_YES) ? dir->data.dir.dir_size : di r->data. | |||
file.file_size, dir->meta, &dir->keywords, &dir->bo, | file.file_size, dir->meta, &dir->keywords, &dir->bo, | |||
(dir->is_directory) ? &no : &dir->data.file.do_index, | (dir->is_directory == GNUNET_YES) ? &no : &dir->data.file.do_in dex, | |||
&dir->client_info)) | &dir->client_info)) | |||
return; | return; | |||
if (!dir->is_directory) | if (dir->is_directory != GNUNET_YES) | |||
return; | return; | |||
pos = dir->data.dir.entries; | pos = dir->data.dir.entries; | |||
while (pos != NULL) | while (pos != NULL) | |||
{ | { | |||
no = GNUNET_NO; | no = GNUNET_NO; | |||
if (GNUNET_OK != | if (GNUNET_OK != | |||
proc (proc_cls, pos, | proc (proc_cls, pos, | |||
(pos->is_directory) ? pos->data.dir.dir_size : pos->data. | (pos->is_directory == GNUNET_YES) ? pos->data.dir.dir_size : pos->data. | |||
file.file_size, pos->meta, &pos->keywords, &pos->bo, | file.file_size, pos->meta, &pos->keywords, &pos->bo, | |||
(dir->is_directory) ? &no : &dir->data.file.do_index, | (pos->is_directory == GNUNET_YES) ? &no : &pos->data.file.do_ index, | |||
&pos->client_info)) | &pos->client_info)) | |||
break; | break; | |||
pos = pos->next; | pos = pos->next; | |||
} | } | |||
} | } | |||
/** | /** | |||
* Destroy publish-structure. Clients should never destroy publish | * Destroy publish-structure. Clients should never destroy publish | |||
* structures that were passed to "GNUNET_FS_publish_start" already. | * structures that were passed to "GNUNET_FS_publish_start" already. | |||
* | * | |||
skipping to change at line 906 | skipping to change at line 398 | |||
*/ | */ | |||
void | void | |||
GNUNET_FS_file_information_destroy (struct GNUNET_FS_FileInformation *fi, | GNUNET_FS_file_information_destroy (struct GNUNET_FS_FileInformation *fi, | |||
GNUNET_FS_FileInformationProcessor clea ner, | GNUNET_FS_FileInformationProcessor clea ner, | |||
void *cleaner_cls) | void *cleaner_cls) | |||
{ | { | |||
struct GNUNET_FS_FileInformation *pos; | struct GNUNET_FS_FileInformation *pos; | |||
int no; | int no; | |||
no = GNUNET_NO; | no = GNUNET_NO; | |||
if (fi->is_directory) | if (fi->is_directory == GNUNET_YES) | |||
{ | { | |||
/* clean up directory */ | /* clean up directory */ | |||
while (NULL != (pos = fi->data.dir.entries)) | while (NULL != (pos = fi->data.dir.entries)) | |||
{ | { | |||
fi->data.dir.entries = pos->next; | fi->data.dir.entries = pos->next; | |||
GNUNET_FS_file_information_destroy (pos, cleaner, cleaner_cls); | GNUNET_FS_file_information_destroy (pos, cleaner, cleaner_cls); | |||
} | } | |||
/* clean up client-info */ | /* clean up client-info */ | |||
if (NULL != cleaner) | if (NULL != cleaner) | |||
cleaner (cleaner_cls, fi, fi->data.dir.dir_size, fi->meta, &fi->keywo rds, | cleaner (cleaner_cls, fi, fi->data.dir.dir_size, fi->meta, &fi->keywo rds, | |||
End of changes. 16 change blocks. | ||||
589 lines changed or deleted | 54 lines changed or added | |||
This html diff was produced by rfcdiff 1.41. The latest version is available from http://tools.ietf.org/tools/rfcdiff/ |