#include "config.h"
#include <sys/time.h>
#include <sys/types.h>
#include <dirent.h>
#include <sys/stat.h>
#include <time.h>
#include <gtk/gtk.h>
#include <unistd.h>
#include <stdlib.h>
#include "log.h"
#include "filetypes.h"
#include "index_db.h"
#include "index.h"
#include "tags.h"
#include "index_ipc.h"
#include "shortcut.h"
Go to the source code of this file.
Data Structures | |
struct | fs_entry_t |
Typedefs | |
typedef unsigned long long | u_int64_t |
Functions | |
u_int64_t | getCurrentTime () |
static gboolean | fs_ignore_filename (const gchar *filename) |
static db_entry_t * | create_db_entry (const fs_entry_t *fs_entry) |
static db_entry_t * | get_entry (const GSList *db_model, const char *filepath, const char *filename) |
static void | compare_entry (GSList **db_model, fs_entry_t *fs_entry) |
static gboolean | ignore_dir (const char *name) |
static gboolean | ignore_file (const char *filename, const char *ext, gboolean is_dir) |
static gboolean | ignore_thumbnail_generation (db_entry_t *db_entry) |
static void | read_directory (const gchar *name, GSList **db_model) |
static gboolean | send_store_metadata (db_entry_t *db_entry) |
static gboolean | check_shortcut (const GSList *db_model, const char *filepath, const char *filename, char **display_name, char **author) |
static gboolean | handle_changes (const GSList *db_model, const char *dir, gboolean skip_thumbnails) |
void | store_metadata_ready () |
Handle next documents. | |
gboolean | index_full (gchar *dir, gboolean skip_thumbnails) |
Variables | |
const GSList * | g_iter |
gchar | startdir [256] |
int | startdirlen = 0 |
gchar | drz_dir [256] |
gchar | shortcut_dir [256] |
gchar | ade_thumbs_dir [256] |
static const char * | HIDDEN_FILENAMES [] |
static gboolean check_shortcut | ( | const GSList * | db_model, | |
const char * | filepath, | |||
const char * | filename, | |||
char ** | display_name, | |||
char ** | author | |||
) | [static] |
Definition at line 318 of file index.c.
References shortcut_t::details, ER_OK, shortcut_t::file, get_entry(), is_shortcut_file(), LOGPRINTF, shortcut_t::name, parse_shortcut_file(), shortcut_free, SHORTCUT_TO_APPLICATION, SHORTCUT_TO_FILE, SHORTCUT_TO_FOLDER, startdirlen, and shortcut_t::type.
Referenced by handle_changes().
00323 { 00324 shortcut_t *shortcut = NULL; 00325 int ret = parse_shortcut_file(filepath, filename, &shortcut); 00326 if (ret != ER_OK) { 00327 LOGPRINTF("DENYING: %s/%s - invalid shortcut file", filepath, filename); 00328 return FALSE; 00329 } 00330 g_assert(shortcut); 00331 00332 if (shortcut->type == SHORTCUT_TO_APPLICATION) { 00333 // dont check application shortcuts 00334 // name and author deliberatly empty, will be read from .desktop file on runtime 00335 *author = g_strdup(""); 00336 *display_name = g_strdup(""); 00337 goto allowed; 00338 } 00339 00340 // only allow shortcuts to file or directory (not apps?) 00341 if (shortcut->type != SHORTCUT_TO_FILE && 00342 shortcut->type != SHORTCUT_TO_FOLDER) 00343 { 00344 LOGPRINTF("DENYING: %s/%s - not shortcut to file/folder", filepath, filename); 00345 goto not_allowed; 00346 } 00347 00348 // dont allow nested shortcuts 00349 if (is_shortcut_file(shortcut->details.file.filename)) { 00350 LOGPRINTF("DENYING: %s/%s - shortcut to shortcut", filepath, filename); 00351 goto not_allowed; 00352 } 00353 00354 // check if destination exists in db 00355 if (get_entry(db_model, shortcut->details.file.directory, 00356 shortcut->details.file.filename) == NULL) 00357 { 00358 LOGPRINTF("DENYING: %s/%s - target unknown", filepath, filename); 00359 goto not_allowed; 00360 } 00361 00362 // pass ownership to display_name 00363 *display_name = shortcut->name; 00364 shortcut->name = NULL; 00365 00366 // pass target dir relative to startdir (= mountpoint) 00367 const char* localdir = shortcut->details.file.directory + startdirlen; 00368 if (localdir[0] == '/') { // have subdir 00369 *author = g_strdup_printf("%s/%s", localdir+1, shortcut->details.file.filename); 00370 } else { // no subdir 00371 *author = g_strdup(shortcut->details.file.filename); 00372 } 00373 00374 allowed: 00375 shortcut_free(shortcut); 00376 return TRUE; 00377 not_allowed: 00378 shortcut_free(shortcut); 00379 return FALSE; 00380 }
static void compare_entry | ( | GSList ** | db_model, | |
fs_entry_t * | fs_entry | |||
) | [static] |
Definition at line 138 of file index.c.
References CHANGED, create_db_entry(), fs_entry_t::date_modified, fs_entry_t::filename, fs_entry_t::filepath, fs_entry_t::filesize, db_entry_t::filesize, get_entry(), fs_entry_t::is_dir, db_entry_t::is_dir, db_entry_t::last_modified, SAME, db_entry_t::state, and UNKNOWN.
Referenced by read_directory().
00139 { 00140 db_entry_t* db_entry = get_entry(*db_model, fs_entry->filepath, fs_entry->filename); 00141 if (db_entry) { // entry exists 00142 if (db_entry->is_dir != fs_entry->is_dir) { 00143 // add new entry, old entry will be deleted automatically 00144 db_entry_t* new_entry = create_db_entry(fs_entry); 00145 // NOTE: entry should be appended! (first delete old one, then add new one) 00146 *db_model = g_slist_append(*db_model, new_entry); 00147 return; 00148 } 00149 if (!db_entry->is_dir && db_entry->filesize != fs_entry->filesize) { 00150 db_entry->filesize = fs_entry->filesize; 00151 db_entry->state = CHANGED; 00152 } 00153 if (db_entry->last_modified != fs_entry->date_modified) { 00154 db_entry->last_modified = fs_entry->date_modified; 00155 db_entry->state = CHANGED; 00156 } 00157 if (db_entry->state == UNKNOWN) db_entry->state = SAME; 00158 } else { // unknown entry, add to list 00159 db_entry_t* new_entry = create_db_entry(fs_entry); 00160 *db_model = g_slist_prepend(*db_model, new_entry); 00161 // NOTE: on all entries marked NEW there is memory management on strings!! 00162 } 00163 }
static db_entry_t* create_db_entry | ( | const fs_entry_t * | fs_entry | ) | [static] |
Definition at line 107 of file index.c.
References fs_entry_t::date_modified, fs_entry_t::filename, db_entry_t::filename, fs_entry_t::filepath, db_entry_t::filepath, fs_entry_t::filesize, db_entry_t::filesize, fs_entry_t::is_dir, db_entry_t::is_dir, db_entry_t::last_modified, NEW, and db_entry_t::state.
Referenced by compare_entry().
00108 { 00109 db_entry_t* entry = g_malloc(sizeof(db_entry_t)); 00110 memset(entry, 0, sizeof(db_entry_t)); 00111 entry->filename = g_strdup(fs_entry->filename); 00112 entry->filepath = g_strdup(fs_entry->filepath); 00113 entry->is_dir = fs_entry->is_dir; 00114 entry->filesize = fs_entry->filesize; 00115 entry->last_modified = fs_entry->date_modified; 00116 entry->state = NEW; 00117 return entry; 00118 }
static gboolean fs_ignore_filename | ( | const gchar * | filename | ) | [static] |
Definition at line 88 of file index.c.
References HIDDEN_FILENAMES.
Referenced by ignore_file().
00089 { 00090 int len = strlen(filename); 00091 if (len == 0) return TRUE; 00092 00093 // check on hidden prefix 00094 if (filename[0] == '.' || filename[0] == '_') return TRUE; 00095 00096 // check on hidden filename 00097 const char** cpp = NULL; 00098 for (cpp = HIDDEN_FILENAMES ; *cpp; cpp++) 00099 { 00100 if ( strcmp(filename, *cpp) == 0 ) return TRUE; 00101 } 00102 00103 return FALSE; 00104 }
static db_entry_t* get_entry | ( | const GSList * | db_model, | |
const char * | filepath, | |||
const char * | filename | |||
) | [static] |
Definition at line 121 of file index.c.
References db_entry_t::filename, and db_entry_t::filepath.
Referenced by check_shortcut(), and compare_entry().
00122 { 00123 00124 const GSList* iter = db_model; 00125 while (iter) { 00126 db_entry_t* db_entry = iter->data; 00127 if ((strcmp(db_entry->filename, filename) == 0) && 00128 strcmp(db_entry->filepath, filepath) == 0) 00129 { 00130 return db_entry; 00131 } 00132 iter = g_slist_next(iter); 00133 } 00134 return NULL; 00135 }
u_int64_t getCurrentTime | ( | ) |
Definition at line 64 of file index.c.
Referenced by index_full(), main(), on_message_timeout(), and schedule_update().
00065 { 00066 struct timespec now; 00067 00068 clock_gettime(CLOCK_MONOTONIC, &now); 00069 u_int64_t now64 = now.tv_sec; 00070 now64 *= 1000000; 00071 now64 += (now.tv_nsec/1000); 00072 return now64; 00073 }
static gboolean handle_changes | ( | const GSList * | db_model, | |
const char * | dir, | |||
gboolean | skip_thumbnails | |||
) | [static] |
Definition at line 383 of file index.c.
References CHANGED, check_shortcut(), db_add_entry(), db_close(), db_delete_entry(), db_end_transaction(), db_open_global(), db_start_transaction(), db_update_entry(), db_update_shortcut_entry(), ER_OK, ERRORPRINTF, db_entry_t::file_id, db_entry_t::filename, db_entry_t::filepath, g_iter, get_tag_for_file(), ignore_thumbnail_generation(), db_entry_t::is_dir, is_shortcut_file(), LOGPRINTF, NEW, SAME, send_store_metadata(), shortcut_dir, startdir, db_entry_t::state, state2str, tag, UNKNOWN, and WARNPRINTF.
Referenced by index_full().
00384 { 00385 int removed = 0; 00386 int same = 0; 00387 int changed = 0; 00388 int new = 0; 00389 00390 db_state_t db_state; 00391 if (db_open_global(&db_state, dir) != ER_OK) { 00392 ERRORPRINTF("error opening db"); 00393 return FALSE; 00394 } 00395 00396 int ret = db_start_transaction(&db_state); 00397 if (ret != ER_OK) { 00398 ERRORPRINTF("error starting transaction"); 00399 goto error; 00400 } 00401 00402 const GSList* iter = db_model; 00403 while (iter) { 00404 db_entry_t* db_entry = iter->data; 00405 if (db_entry->state != SAME) { 00406 LOGPRINTF(" %s %4lld %s", state2str(db_entry->state), db_entry->file_id, db_entry->filename); 00407 } 00408 00409 gchar* display_name = NULL; 00410 gchar* author = NULL; 00411 00412 gboolean is_shortcut = is_shortcut_file(db_entry->filename) && !db_entry->is_dir; 00413 // special checking for shortcuts 00414 if (is_shortcut && db_entry->state != UNKNOWN) 00415 { 00416 if (!check_shortcut(db_model, db_entry->filepath, db_entry->filename, &display_name, &author)) { 00417 // delete from fs if it's in DIR_SHORTCUTS 00418 if (strcmp(db_entry->filepath, shortcut_dir) == 0) { 00419 char fullname[256]; 00420 sprintf(fullname, "%s/%s", db_entry->filepath, db_entry->filename); 00421 LOGPRINTF("deleting %s", fullname); 00422 int err = unlink(fullname); 00423 if (err) { 00424 WARNPRINTF("cannot delete %s", fullname); 00425 } 00426 } 00427 switch (db_entry->state) { 00428 case UNKNOWN: 00429 // was in db, but now deleted, so ok 00430 break; 00431 case SAME: 00432 case CHANGED: 00433 // was in db, delete by setting to unknown 00434 db_entry->state = UNKNOWN; 00435 break; 00436 case NEW: 00437 // not yet in db, skip it 00438 goto next; 00439 } 00440 } 00441 } 00442 00443 switch (db_entry->state) { 00444 case UNKNOWN: 00445 db_delete_entry(&db_state, db_entry); 00446 removed++; 00447 break; 00448 case SAME: 00449 // do nothing 00450 same++; 00451 break; 00452 case CHANGED: 00453 db_update_entry(&db_state, db_entry); 00454 if (is_shortcut) { 00455 db_update_shortcut_entry(&db_state, db_entry, display_name, author); 00456 } 00457 changed++; 00458 break; 00459 case NEW: 00460 { 00461 const gchar* tag = NULL; 00462 if (!db_entry->is_dir) tag = get_tag_for_file(db_entry->filename, db_entry->filepath, startdir); 00463 db_add_entry(&db_state, db_entry, tag, display_name, author); 00464 new++; 00465 break; 00466 } 00467 } 00468 next: 00469 g_free(display_name); 00470 g_free(author); 00471 iter = g_slist_next(iter); 00472 } 00473 00474 db_end_transaction (&db_state); 00475 00476 if (!skip_thumbnails) { 00477 // This while loop searches for the first document to store metadata and thumbnails for 00478 // The rest of the documents is handled in store_metadata_ready 00479 g_iter = db_model; 00480 while (g_iter) { 00481 db_entry_t* db_entry = g_iter->data; 00482 00483 if (!ignore_thumbnail_generation(db_entry)) 00484 { 00485 if (send_store_metadata(db_entry)) 00486 { 00487 gtk_main(); 00488 break; 00489 } 00490 } 00491 g_iter = g_slist_next(g_iter); 00492 } 00493 } 00494 00495 error: 00496 db_close(&db_state); 00497 printf("mdbindex: new %d removed %d same %d changed %d\n", new, removed, same, changed); 00498 00499 return (new + changed + removed) > 0; 00500 }
static gboolean ignore_dir | ( | const char * | name | ) | [static] |
Definition at line 166 of file index.c.
References ade_thumbs_dir.
Referenced by read_directory().
00167 { 00168 if (strcmp(ade_thumbs_dir, name) == 0) return TRUE; 00169 return FALSE; 00170 }
static gboolean ignore_file | ( | const char * | filename, | |
const char * | ext, | |||
gboolean | is_dir | |||
) | [static] |
Definition at line 173 of file index.c.
References fs_ignore_filename(), get_viewer_from_file_extension(), and is_shortcut_file_extension().
Referenced by read_directory().
00174 { 00175 if (fs_ignore_filename(filename)) return TRUE; 00176 00177 // if is directory, don't skip 00178 if (is_dir) return FALSE; 00179 00180 // ignore files without extension 00181 if (ext[0] == 0) return TRUE; 00182 00183 // don't skip shortcuts 00184 if (is_shortcut_file_extension(ext)) return FALSE; 00185 00186 return (get_viewer_from_file_extension(ext) == NULL); 00187 }
static gboolean ignore_thumbnail_generation | ( | db_entry_t * | db_entry | ) | [static] |
Definition at line 190 of file index.c.
References CHANGED, db_entry_t::filename, g_extension_pointer(), get_generate_thumbnail(), get_viewer_from_file_extension(), db_entry_t::is_dir, NEW, and db_entry_t::state.
Referenced by handle_changes(), and store_metadata_ready().
00191 { 00192 // Only handle changed or new files 00193 if (db_entry->state != CHANGED && db_entry->state != NEW) 00194 return TRUE; 00195 00196 // Ignore directories 00197 if (db_entry->is_dir) 00198 return TRUE; 00199 00200 // Otherwise check extension 00201 const char *ext = g_extension_pointer(db_entry->filename); 00202 00203 // Ignore files not configured 00204 if (get_viewer_from_file_extension(ext) == NULL) 00205 return TRUE; 00206 00207 // Ignore files where thumbnail generation was not enabled for 00208 return (!get_generate_thumbnail(ext)); 00209 }
gboolean index_full | ( | gchar * | dir, | |
gboolean | skip_thumbnails | |||
) |
File Name : index.h Copyright (C) 2009 iRex Technologies B.V. All rights reserved.
Definition at line 525 of file index.c.
References ade_thumbs_dir, db_close(), db_get_model(), db_open_global(), DIR_ADE_THUMBS, DIR_DRZ, DIR_SHORTCUTS, drz_dir, ER_OK, ERRORPRINTF, filetypes_init(), getCurrentTime(), handle_changes(), LOGPRINTF, read_directory(), shortcut_dir, startdir, startdirlen, and WARNPRINTF.
Referenced by main().
00526 { 00527 int len = strlen(dir); 00528 // strip off trailing slash 00529 if (len>0 && dir[len-1] == '/') dir[len-1] = '\0'; 00530 strncpy(startdir, dir, sizeof(startdir)); 00531 startdir[sizeof(startdir)-1] = '\0'; 00532 startdirlen = strlen(startdir); 00533 00534 // check if dir exists and is dir 00535 struct stat statbuf; 00536 int res = stat(dir, &statbuf); 00537 if (res == -1 || !S_ISDIR(statbuf.st_mode)) { 00538 fprintf(stderr, "mdbindex: directory '%s' doesn't exist or is not a dir\n", dir); 00539 return FALSE; 00540 } 00541 00542 // init static dirs with startdir pre-fix 00543 sprintf(drz_dir, "%s/%s", startdir, DIR_DRZ); 00544 sprintf(shortcut_dir, "%s/%s", startdir, DIR_SHORTCUTS); 00545 sprintf(ade_thumbs_dir, "%s/%s", startdir, DIR_ADE_THUMBS); 00546 00547 db_state_t db_state; 00548 if (db_open_global(&db_state, dir) != ER_OK) 00549 { 00550 ERRORPRINTF("Failed to open global db"); 00551 return FALSE; 00552 } 00553 db_close(&db_state); 00554 00555 filetypes_init(FALSE); 00556 00557 // read database model 00558 u_int64_t t1 = getCurrentTime(); 00559 GSList* db_model = db_get_model(dir); 00560 if (db_model == NULL) WARNPRINTF("DB is empty"); 00561 u_int64_t t2 = getCurrentTime(); 00562 u_int64_t diff = t2 - t1; 00563 LOGPRINTF("DB DURATION = %lld ms", diff / 1000); 00564 00565 // read fs and mark changes 00566 t1 = getCurrentTime(); 00567 read_directory(dir, &db_model); 00568 t2 = getCurrentTime(); 00569 diff = t2 - t1; 00570 LOGPRINTF("FS/COMPARE DURATION = %lld ms", diff / 1000); 00571 00572 // update database with changed entries 00573 t1 = getCurrentTime(); 00574 gboolean changed = handle_changes(db_model, dir, skip_thumbnails); 00575 t2 = getCurrentTime(); 00576 diff = t2 - t1; 00577 LOGPRINTF("DB UPDATE DURATION = %lld ms", diff / 1000); 00578 00579 // NOTE: not freeing db_model for speed 00580 return changed; 00581 }
static void read_directory | ( | const gchar * | name, | |
GSList ** | db_model | |||
) | [static] |
Definition at line 212 of file index.c.
References compare_entry(), fs_entry_t::date_modified, drz_dir, ermetadb_close(), ERMETADB_LOCAL_DATABASE_FILE, ermetadb_local_open(), ERRORPRINTF, fs_entry_t::filename, fs_entry_t::filepath, fs_entry_t::filesize, g_extension_pointer(), ignore_dir(), ignore_file(), fs_entry_t::is_dir, is_drz_file_extension(), and LOGPRINTF.
Referenced by index_full().
00213 { 00214 DIR* dir = opendir(name); 00215 if (dir == NULL) { 00216 perror("opendir"); 00217 return; 00218 } 00219 struct dirent* current = readdir(dir); 00220 while (current != 0) 00221 { 00222 if (current->d_name[0] == '.') goto next; 00223 char fullname[1024]; 00224 snprintf(fullname, sizeof(fullname), "%s/%s", name, current->d_name); 00225 struct stat statbuf; 00226 stat(fullname, &statbuf); 00227 00228 gboolean is_dir = S_ISDIR(statbuf.st_mode); 00229 gboolean is_reg = S_ISREG(statbuf.st_mode); 00230 if (!is_dir && !is_reg) goto next; 00231 00232 // try to open and close all local db's for possible version updates 00233 if (strcmp(current->d_name, ERMETADB_LOCAL_DATABASE_FILE) == 0) { 00234 LOGPRINTF("trying to open and close %s", fullname); 00235 erMetadb local_db = ermetadb_local_open(name, TRUE); 00236 if (local_db == NULL) { 00237 ERRORPRINTF("cannot open db %s", fullname); 00238 } 00239 ermetadb_close(local_db); 00240 goto next; 00241 } 00242 00243 const char *ext = g_extension_pointer(current->d_name); 00244 00245 if (is_drz_file_extension(ext)) 00246 { 00247 if (strcmp(name, drz_dir) != 0) { 00248 // create drz dir if it doesn't exist 00249 g_mkdir_with_parents(drz_dir, 644); 00250 00251 // move file to drz directory 00252 char command[256]; 00253 LOGPRINTF("force moving %s to %s/", fullname, drz_dir); 00254 sprintf(command, "mv -f %s %s/", fullname, drz_dir); 00255 system(command); 00256 } 00257 else 00258 { 00259 LOGPRINTF("ignoring %s", current->d_name); 00260 } 00261 goto next; 00262 } 00263 00264 if (ignore_file(current->d_name, ext, is_dir)) 00265 { 00266 LOGPRINTF("ignoring %s", current->d_name); 00267 goto next; 00268 } 00269 00270 if (is_dir && ignore_dir(fullname)) 00271 { 00272 LOGPRINTF("ignoring %s", current->d_name); 00273 goto next; 00274 } 00275 00276 fs_entry_t fs_entry; 00277 fs_entry.filename = current->d_name; 00278 fs_entry.filepath = name; 00279 fs_entry.is_dir = is_dir; 00280 fs_entry.filesize = is_dir ? 0 : statbuf.st_size; 00281 fs_entry.date_modified = statbuf.st_mtime; 00282 compare_entry(db_model, &fs_entry); 00283 00284 if (is_dir) 00285 { 00286 read_directory(fullname, db_model); 00287 } 00288 next: 00289 current = readdir(dir); 00290 } 00291 closedir(dir); 00292 }
static gboolean send_store_metadata | ( | db_entry_t * | db_entry | ) | [static] |
Definition at line 309 of file index.c.
References db_entry_t::filename, db_entry_t::filepath, ipc_send_store_metadata(), and LOGPRINTF.
Referenced by handle_changes(), and store_metadata_ready().
00310 { 00311 LOGPRINTF("Store metadata for [%s/%s]", db_entry->filepath, db_entry->filename); 00312 ipc_send_store_metadata(db_entry->filepath, db_entry->filename); 00313 return TRUE; 00314 }
void store_metadata_ready | ( | ) |
Handle next documents.
Definition at line 505 of file index.c.
References g_iter, ignore_thumbnail_generation(), and send_store_metadata().
Referenced by on_storemetadata_ready().
00506 { 00507 g_iter = g_slist_next(g_iter); 00508 00509 while (g_iter) { 00510 db_entry_t* db_entry = g_iter->data; 00511 00512 if (!ignore_thumbnail_generation(db_entry)) 00513 { 00514 if (send_store_metadata(db_entry)) 00515 { 00516 return; 00517 } 00518 } 00519 g_iter = g_slist_next(g_iter); 00520 } 00521 gtk_main_quit(); 00522 }
gchar ade_thumbs_dir[256] |
Definition at line 51 of file index.c.
Referenced by ignore_dir(), and index_full().
gchar drz_dir[256] |
Definition at line 49 of file index.c.
Referenced by index_full(), and read_directory().
const GSList* g_iter |
Copyright (C) 2008 iRex Technologies B.V. All rights reserved.
Definition at line 46 of file index.c.
Referenced by handle_changes(), and store_metadata_ready().
const char* HIDDEN_FILENAMES[] [static] |
{ ERMETADB_GLOBAL_DATABASE_FILE, ERMETADB_LOCAL_DATABASE_FILE, ERMETADB_LOCAL_DATABASE_FILE "-journal", ERMETADB_LOCAL_DATABASE_FILE ".old", "autorun.inf", "Thumbs.db", NULL }
Definition at line 76 of file index.c.
Referenced by fs_ignore_filename().
gchar shortcut_dir[256] |
Definition at line 50 of file index.c.
Referenced by create_shortcut_item(), handle_changes(), and index_full().
gchar startdir[256] |
Definition at line 47 of file index.c.
Referenced by handle_changes(), and index_full().
int startdirlen = 0 |
Definition at line 48 of file index.c.
Referenced by check_shortcut(), and index_full().