diff options
author | Thomas Martitz <kugel@rockbox.org> | 2010-12-23 19:02:18 +0000 |
---|---|---|
committer | Thomas Martitz <kugel@rockbox.org> | 2010-12-23 19:02:18 +0000 |
commit | 87c8be4a08b4864f0df588c80bc90586f5e512a0 (patch) | |
tree | c2265c82437eae7533569f1c6b6e254a321a06f4 /apps/tagcache.c | |
parent | e1b1183f401974700a67db76f39e2bba9a5984e1 (diff) | |
download | rockbox-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.c | 130 |
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 | ||
4196 | static 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 | **/ | ||
4213 | static 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 | |||
4263 | static 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 | ||
4193 | static bool check_dir(const char *dirname, int add_files) | 4279 | static 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; |