summaryrefslogtreecommitdiff
path: root/apps/tagcache.c
diff options
context:
space:
mode:
authorThomas Martitz <kugel@rockbox.org>2010-12-23 19:02:18 +0000
committerThomas Martitz <kugel@rockbox.org>2010-12-23 19:02:18 +0000
commit87c8be4a08b4864f0df588c80bc90586f5e512a0 (patch)
treec2265c82437eae7533569f1c6b6e254a321a06f4 /apps/tagcache.c
parente1b1183f401974700a67db76f39e2bba9a5984e1 (diff)
downloadrockbox-87c8be4a08b4864f0df588c80bc90586f5e512a0.tar.gz
rockbox-87c8be4a08b4864f0df588c80bc90586f5e512a0.zip
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
Diffstat (limited to 'apps/tagcache.c')
-rw-r--r--apps/tagcache.c130
1 files changed, 114 insertions, 16 deletions
diff --git a/apps/tagcache.c b/apps/tagcache.c
index 3565d8e5d4..0831bab32d 100644
--- a/apps/tagcache.c
+++ b/apps/tagcache.c
@@ -60,6 +60,9 @@
60#include <stdio.h> 60#include <stdio.h>
61#include <stdlib.h> 61#include <stdlib.h>
62#include <ctype.h> 62#include <ctype.h>
63#ifdef APPLICATION
64#include <unistd.h> /* readlink() */
65#endif
63#include "config.h" 66#include "config.h"
64#include "ata_idle_notify.h" 67#include "ata_idle_notify.h"
65#include "thread.h" 68#include "thread.h"
@@ -77,6 +80,7 @@
77#include "dir.h" 80#include "dir.h"
78#include "filefuncs.h" 81#include "filefuncs.h"
79#include "structec.h" 82#include "structec.h"
83#include "debug.h"
80 84
81#ifndef __PCTOOL__ 85#ifndef __PCTOOL__
82#include "lang.h" 86#include "lang.h"
@@ -4189,6 +4193,88 @@ static void __attribute__ ((noinline)) check_ignore(const char *dirname,
4189 *unignore = file_exists(newpath); 4193 *unignore = file_exists(newpath);
4190} 4194}
4191 4195
4196static struct search_roots_ll {
4197 const char *path;
4198 struct search_roots_ll * next;
4199} roots_ll;
4200
4201#ifdef APPLICATION
4202/*
4203 * This adds a path to the search roots, possibly during traveling through
4204 * the filesystem. It only adds if the path is not inside an already existing
4205 * search root.
4206 *
4207 * Returns true if it added the path to the search roots
4208 *
4209 * Windows 2000 and greater supports symlinks, but they don't provide
4210 * realpath() or readlink(), and symlinks are rarely used on them so
4211 * ignore this for windows for now
4212 **/
4213static bool add_search_root(const char *name)
4214{
4215 (void)name;
4216#ifndef WIN32
4217 struct search_roots_ll *this, *prev = NULL;
4218 char target[MAX_PATH];
4219 char _abs_target[MAX_PATH];
4220 char * abs_target;
4221 ssize_t len;
4222
4223 len = readlink(name, target, sizeof(target));
4224 if (len < 0)
4225 return false;
4226
4227 target[len] = '\0';
4228 /* realpath(target, NULL) doesn't work on android ... */
4229 abs_target = realpath(target, _abs_target);
4230 if (abs_target == NULL)
4231 return false;
4232
4233 for(this = &roots_ll; this; prev = this, this = this->next)
4234 {
4235 size_t root_len = strlen(this->path);
4236 /* check if the link target is inside of an existing search root
4237 * don't add if target is inside, we'll scan it later */
4238 if (!strncmp(this->path, abs_target, root_len))
4239 return false;
4240 }
4241
4242 if (prev)
4243 {
4244 size_t len = strlen(abs_target) + 1; /* count \0 */
4245 this = malloc(sizeof(struct search_roots_ll) + len );
4246 if (!this || len > MAX_PATH)
4247 {
4248 logf("Error at adding a search root: %s", this ? "path too long":"OOM");
4249 free(this);
4250 prev->next = NULL;
4251 }
4252 this->path = ((char*)this) + sizeof(struct search_roots_ll);
4253 strcpy((char*)this->path, abs_target); /* ok to cast const away here */
4254 this->next = NULL;
4255 prev->next = this;
4256 logf("Added %s to the search roots\n", abs_target);
4257 return true;
4258 }
4259#endif
4260 return false;
4261}
4262
4263static int free_search_roots(struct search_roots_ll * start)
4264{
4265 int ret = 0;
4266 if (start->next)
4267 {
4268 ret += free_search_roots(start->next);
4269 ret += sizeof(struct search_roots_ll);
4270 free(start->next);
4271 }
4272 return ret;
4273}
4274#else /* native, simulator */
4275#define add_search_root(a) do {} while(0)
4276#define free_search_roots(a) do {} while(0)
4277#endif
4192 4278
4193static bool check_dir(const char *dirname, int add_files) 4279static bool check_dir(const char *dirname, int add_files)
4194{ 4280{
@@ -4203,7 +4289,6 @@ static bool check_dir(const char *dirname, int add_files)
4203 logf("tagcache: opendir(%s) failed", dirname); 4289 logf("tagcache: opendir(%s) failed", dirname);
4204 return false; 4290 return false;
4205 } 4291 }
4206
4207 /* check for a database.ignore and database.unignore */ 4292 /* check for a database.ignore and database.unignore */
4208 check_ignore(dirname, &ignore, &unignore); 4293 check_ignore(dirname, &ignore, &unignore);
4209 4294
@@ -4218,31 +4303,35 @@ static bool check_dir(const char *dirname, int add_files)
4218 while (!check_event_queue()) 4303 while (!check_event_queue())
4219#endif 4304#endif
4220 { 4305 {
4221 struct dirent *entry; 4306 struct dirent *entry = readdir(dir);
4222
4223 entry = readdir(dir);
4224
4225 if (entry == NULL) 4307 if (entry == NULL)
4226 { 4308 {
4227 success = true; 4309 success = true;
4228 break ; 4310 break;
4229 } 4311 }
4230 4312
4231 struct dirinfo info = dir_get_info(dir, entry);
4232
4233 if (!strcmp((char *)entry->d_name, ".") || 4313 if (!strcmp((char *)entry->d_name, ".") ||
4234 !strcmp((char *)entry->d_name, "..")) 4314 !strcmp((char *)entry->d_name, ".."))
4235 continue; 4315 continue;
4236 4316
4317 struct dirinfo info = dir_get_info(dir, entry);
4318
4237 yield(); 4319 yield();
4238 4320
4239 len = strlen(curpath); 4321 len = strlen(curpath);
4240 snprintf(&curpath[len], sizeof(curpath) - len, "/%s", 4322 /* don't add an extra / for curpath == / */
4241 entry->d_name); 4323 if (len <= 1) len = 0;
4242 4324 snprintf(&curpath[len], sizeof(curpath) - len, "/%s", entry->d_name);
4325
4243 processed_dir_count++; 4326 processed_dir_count++;
4244 if (info.attribute & ATTR_DIRECTORY) 4327 if (info.attribute & ATTR_DIRECTORY)
4245 check_dir(curpath, add_files); 4328 { /* don't follow symlinks to dirs, but try to add it as a search root
4329 * this makes able to avoid looping in recursive symlinks */
4330 if (info.attribute & ATTR_LINK)
4331 add_search_root(curpath);
4332 else
4333 check_dir(curpath, add_files);
4334 }
4246 else if (add_files) 4335 else if (add_files)
4247 { 4336 {
4248 tc_stat.curentry = curpath; 4337 tc_stat.curentry = curpath;
@@ -4320,10 +4409,19 @@ void tagcache_build(const char *path)
4320 memset(&header, 0, sizeof(struct tagcache_header)); 4409 memset(&header, 0, sizeof(struct tagcache_header));
4321 write(cachefd, &header, sizeof(struct tagcache_header)); 4410 write(cachefd, &header, sizeof(struct tagcache_header));
4322 4411
4323 if (strcmp("/", path) != 0) 4412 ret = true;
4324 strcpy(curpath, path); 4413 roots_ll.path = path;
4325 ret = check_dir(path, true); 4414 roots_ll.next = NULL;
4326 4415 struct search_roots_ll * this;
4416 /* check_dir might add new roots */
4417 for(this = &roots_ll; this; this = this->next)
4418 {
4419 strcpy(curpath, this->path);
4420 ret = ret && check_dir(this->path, true);
4421 }
4422 if (roots_ll.next)
4423 free_search_roots(roots_ll.next);
4424
4327 /* Write the header. */ 4425 /* Write the header. */
4328 header.magic = TAGCACHE_MAGIC; 4426 header.magic = TAGCACHE_MAGIC;
4329 header.datasize = data_size; 4427 header.datasize = data_size;