RaaA: Improve tagcache search to make the database built.
First, it add the ability to tagcache to walk through multiple search roots. Second, it adds symlinks targets to the search roots if they're are not inside any of the current search roots, otherwise the symlink is ignored (unless it's a file). The default search root is still /, so no search root will be actually added. But the tagcache now isn't trapped by recursive symlinks anymore and successfully builds, and it's prepared for a future music directory setting. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@28884 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
e1b1183f40
commit
87c8be4a08
4 changed files with 165 additions and 39 deletions
130
apps/tagcache.c
130
apps/tagcache.c
|
@ -60,6 +60,9 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#ifdef APPLICATION
|
||||
#include <unistd.h> /* readlink() */
|
||||
#endif
|
||||
#include "config.h"
|
||||
#include "ata_idle_notify.h"
|
||||
#include "thread.h"
|
||||
|
@ -77,6 +80,7 @@
|
|||
#include "dir.h"
|
||||
#include "filefuncs.h"
|
||||
#include "structec.h"
|
||||
#include "debug.h"
|
||||
|
||||
#ifndef __PCTOOL__
|
||||
#include "lang.h"
|
||||
|
@ -4189,6 +4193,88 @@ static void __attribute__ ((noinline)) check_ignore(const char *dirname,
|
|||
*unignore = file_exists(newpath);
|
||||
}
|
||||
|
||||
static struct search_roots_ll {
|
||||
const char *path;
|
||||
struct search_roots_ll * next;
|
||||
} roots_ll;
|
||||
|
||||
#ifdef APPLICATION
|
||||
/*
|
||||
* This adds a path to the search roots, possibly during traveling through
|
||||
* the filesystem. It only adds if the path is not inside an already existing
|
||||
* search root.
|
||||
*
|
||||
* Returns true if it added the path to the search roots
|
||||
*
|
||||
* Windows 2000 and greater supports symlinks, but they don't provide
|
||||
* realpath() or readlink(), and symlinks are rarely used on them so
|
||||
* ignore this for windows for now
|
||||
**/
|
||||
static bool add_search_root(const char *name)
|
||||
{
|
||||
(void)name;
|
||||
#ifndef WIN32
|
||||
struct search_roots_ll *this, *prev = NULL;
|
||||
char target[MAX_PATH];
|
||||
char _abs_target[MAX_PATH];
|
||||
char * abs_target;
|
||||
ssize_t len;
|
||||
|
||||
len = readlink(name, target, sizeof(target));
|
||||
if (len < 0)
|
||||
return false;
|
||||
|
||||
target[len] = '\0';
|
||||
/* realpath(target, NULL) doesn't work on android ... */
|
||||
abs_target = realpath(target, _abs_target);
|
||||
if (abs_target == NULL)
|
||||
return false;
|
||||
|
||||
for(this = &roots_ll; this; prev = this, this = this->next)
|
||||
{
|
||||
size_t root_len = strlen(this->path);
|
||||
/* check if the link target is inside of an existing search root
|
||||
* don't add if target is inside, we'll scan it later */
|
||||
if (!strncmp(this->path, abs_target, root_len))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (prev)
|
||||
{
|
||||
size_t len = strlen(abs_target) + 1; /* count \0 */
|
||||
this = malloc(sizeof(struct search_roots_ll) + len );
|
||||
if (!this || len > MAX_PATH)
|
||||
{
|
||||
logf("Error at adding a search root: %s", this ? "path too long":"OOM");
|
||||
free(this);
|
||||
prev->next = NULL;
|
||||
}
|
||||
this->path = ((char*)this) + sizeof(struct search_roots_ll);
|
||||
strcpy((char*)this->path, abs_target); /* ok to cast const away here */
|
||||
this->next = NULL;
|
||||
prev->next = this;
|
||||
logf("Added %s to the search roots\n", abs_target);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
static int free_search_roots(struct search_roots_ll * start)
|
||||
{
|
||||
int ret = 0;
|
||||
if (start->next)
|
||||
{
|
||||
ret += free_search_roots(start->next);
|
||||
ret += sizeof(struct search_roots_ll);
|
||||
free(start->next);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
#else /* native, simulator */
|
||||
#define add_search_root(a) do {} while(0)
|
||||
#define free_search_roots(a) do {} while(0)
|
||||
#endif
|
||||
|
||||
static bool check_dir(const char *dirname, int add_files)
|
||||
{
|
||||
|
@ -4203,7 +4289,6 @@ static bool check_dir(const char *dirname, int add_files)
|
|||
logf("tagcache: opendir(%s) failed", dirname);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* check for a database.ignore and database.unignore */
|
||||
check_ignore(dirname, &ignore, &unignore);
|
||||
|
||||
|
@ -4218,31 +4303,35 @@ static bool check_dir(const char *dirname, int add_files)
|
|||
while (!check_event_queue())
|
||||
#endif
|
||||
{
|
||||
struct dirent *entry;
|
||||
|
||||
entry = readdir(dir);
|
||||
|
||||
struct dirent *entry = readdir(dir);
|
||||
if (entry == NULL)
|
||||
{
|
||||
success = true;
|
||||
break ;
|
||||
break;
|
||||
}
|
||||
|
||||
struct dirinfo info = dir_get_info(dir, entry);
|
||||
|
||||
if (!strcmp((char *)entry->d_name, ".") ||
|
||||
!strcmp((char *)entry->d_name, ".."))
|
||||
continue;
|
||||
|
||||
struct dirinfo info = dir_get_info(dir, entry);
|
||||
|
||||
yield();
|
||||
|
||||
len = strlen(curpath);
|
||||
snprintf(&curpath[len], sizeof(curpath) - len, "/%s",
|
||||
entry->d_name);
|
||||
|
||||
/* don't add an extra / for curpath == / */
|
||||
if (len <= 1) len = 0;
|
||||
snprintf(&curpath[len], sizeof(curpath) - len, "/%s", entry->d_name);
|
||||
|
||||
processed_dir_count++;
|
||||
if (info.attribute & ATTR_DIRECTORY)
|
||||
check_dir(curpath, add_files);
|
||||
{ /* don't follow symlinks to dirs, but try to add it as a search root
|
||||
* this makes able to avoid looping in recursive symlinks */
|
||||
if (info.attribute & ATTR_LINK)
|
||||
add_search_root(curpath);
|
||||
else
|
||||
check_dir(curpath, add_files);
|
||||
}
|
||||
else if (add_files)
|
||||
{
|
||||
tc_stat.curentry = curpath;
|
||||
|
@ -4320,10 +4409,19 @@ void tagcache_build(const char *path)
|
|||
memset(&header, 0, sizeof(struct tagcache_header));
|
||||
write(cachefd, &header, sizeof(struct tagcache_header));
|
||||
|
||||
if (strcmp("/", path) != 0)
|
||||
strcpy(curpath, path);
|
||||
ret = check_dir(path, true);
|
||||
|
||||
ret = true;
|
||||
roots_ll.path = path;
|
||||
roots_ll.next = NULL;
|
||||
struct search_roots_ll * this;
|
||||
/* check_dir might add new roots */
|
||||
for(this = &roots_ll; this; this = this->next)
|
||||
{
|
||||
strcpy(curpath, this->path);
|
||||
ret = ret && check_dir(this->path, true);
|
||||
}
|
||||
if (roots_ll.next)
|
||||
free_search_roots(roots_ll.next);
|
||||
|
||||
/* Write the header. */
|
||||
header.magic = TAGCACHE_MAGIC;
|
||||
header.datasize = data_size;
|
||||
|
|
|
@ -48,6 +48,7 @@
|
|||
#define ATTR_DIRECTORY 0x10
|
||||
#define ATTR_ARCHIVE 0x20
|
||||
#define ATTR_VOLUME 0x40 /* this is a volume, not a real directory */
|
||||
#define ATTR_LINK 0x80
|
||||
|
||||
#ifdef HAVE_DIRCACHE
|
||||
# include "dircache.h"
|
||||
|
|
|
@ -105,26 +105,37 @@ struct dirinfo dir_get_info(struct DIR* _parent, struct dirent *dir)
|
|||
{
|
||||
struct __dir *parent = (struct __dir*)_parent;
|
||||
struct stat s;
|
||||
struct tm *tm;
|
||||
struct tm *tm = NULL;
|
||||
struct dirinfo ret;
|
||||
char path[MAX_PATH];
|
||||
|
||||
snprintf(path, sizeof(path), "%s/%s", parent->path, dir->d_name);
|
||||
stat(path, &s);
|
||||
memset(&ret, 0, sizeof(ret));
|
||||
|
||||
if (S_ISDIR(s.st_mode))
|
||||
if (!stat(path, &s))
|
||||
{
|
||||
ret.attribute = ATTR_DIRECTORY;
|
||||
if (S_ISDIR(s.st_mode))
|
||||
{
|
||||
ret.attribute = ATTR_DIRECTORY;
|
||||
}
|
||||
ret.size = s.st_size;
|
||||
tm = localtime(&(s.st_mtime));
|
||||
}
|
||||
|
||||
if (!lstat(path, &s) && S_ISLNK(s.st_mode))
|
||||
{
|
||||
ret.attribute |= ATTR_LINK;
|
||||
}
|
||||
|
||||
if (tm)
|
||||
{
|
||||
ret.wrtdate = ((tm->tm_year - 80) << 9) |
|
||||
((tm->tm_mon + 1) << 5) |
|
||||
tm->tm_mday;
|
||||
ret.wrttime = (tm->tm_hour << 11) |
|
||||
(tm->tm_min << 5) |
|
||||
(tm->tm_sec >> 1);
|
||||
}
|
||||
|
||||
ret.size = s.st_size;
|
||||
tm = localtime(&(s.st_mtime));
|
||||
ret.wrtdate = ((tm->tm_year - 80) << 9) |
|
||||
((tm->tm_mon + 1) << 5) |
|
||||
tm->tm_mday;
|
||||
ret.wrttime = (tm->tm_hour << 11) |
|
||||
(tm->tm_min << 5) |
|
||||
(tm->tm_sec >> 1);
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include "config.h"
|
||||
|
||||
#define HAVE_STATVFS (!defined(WIN32))
|
||||
#define HAVE_LSTAT (!defined(WIN32))
|
||||
|
||||
#if HAVE_STATVFS
|
||||
#include <sys/statvfs.h>
|
||||
|
@ -314,7 +315,7 @@ struct sim_dirent *sim_readdir(MYDIR *dir)
|
|||
static struct sim_dirent secret;
|
||||
STAT_T s;
|
||||
DIRENT_T *x11 = READDIR(dir->dir);
|
||||
struct tm* tm;
|
||||
struct tm tm;
|
||||
|
||||
if(!x11)
|
||||
return (struct sim_dirent *)0;
|
||||
|
@ -324,20 +325,35 @@ struct sim_dirent *sim_readdir(MYDIR *dir)
|
|||
/* build file name */
|
||||
snprintf(buffer, sizeof(buffer), "%s/%s",
|
||||
get_sim_pathname(dir->name), secret.d_name);
|
||||
STAT(buffer, &s); /* get info */
|
||||
if (STAT(buffer, &s)) /* get info */
|
||||
return NULL;
|
||||
|
||||
#define ATTR_DIRECTORY 0x10
|
||||
|
||||
secret.info.attribute = S_ISDIR(s.st_mode)?ATTR_DIRECTORY:0;
|
||||
secret.info.size = s.st_size;
|
||||
secret.info.attribute = 0;
|
||||
|
||||
if (S_ISDIR(s.st_mode))
|
||||
secret.info.attribute = ATTR_DIRECTORY;
|
||||
|
||||
secret.info.size = s.st_size;
|
||||
|
||||
if (localtime_r(&(s.st_mtime), &tm) == NULL)
|
||||
return NULL;
|
||||
secret.info.wrtdate = ((tm.tm_year - 80) << 9) |
|
||||
((tm.tm_mon + 1) << 5) |
|
||||
tm.tm_mday;
|
||||
secret.info.wrttime = (tm.tm_hour << 11) |
|
||||
(tm.tm_min << 5) |
|
||||
(tm.tm_sec >> 1);
|
||||
|
||||
#ifdef HAVE_LSTAT
|
||||
#define ATTR_LINK 0x80
|
||||
if (!lstat(buffer, &s) && S_ISLNK(s.st_mode))
|
||||
{
|
||||
secret.info.attribute |= ATTR_LINK;
|
||||
}
|
||||
#endif
|
||||
|
||||
tm = localtime(&(s.st_mtime));
|
||||
secret.info.wrtdate = ((tm->tm_year - 80) << 9) |
|
||||
((tm->tm_mon + 1) << 5) |
|
||||
tm->tm_mday;
|
||||
secret.info.wrttime = (tm->tm_hour << 11) |
|
||||
(tm->tm_min << 5) |
|
||||
(tm->tm_sec >> 1);
|
||||
return &secret;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue