summaryrefslogtreecommitdiff
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
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
-rw-r--r--apps/tagcache.c130
-rw-r--r--firmware/include/dir.h1
-rw-r--r--firmware/target/hosted/android/fs-android.c35
-rw-r--r--uisimulator/common/io.c36
4 files changed, 164 insertions, 38 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;
diff --git a/firmware/include/dir.h b/firmware/include/dir.h
index 3a582c3865..4f1993143c 100644
--- a/firmware/include/dir.h
+++ b/firmware/include/dir.h
@@ -48,6 +48,7 @@
48#define ATTR_DIRECTORY 0x10 48#define ATTR_DIRECTORY 0x10
49#define ATTR_ARCHIVE 0x20 49#define ATTR_ARCHIVE 0x20
50#define ATTR_VOLUME 0x40 /* this is a volume, not a real directory */ 50#define ATTR_VOLUME 0x40 /* this is a volume, not a real directory */
51#define ATTR_LINK 0x80
51 52
52#ifdef HAVE_DIRCACHE 53#ifdef HAVE_DIRCACHE
53# include "dircache.h" 54# include "dircache.h"
diff --git a/firmware/target/hosted/android/fs-android.c b/firmware/target/hosted/android/fs-android.c
index 1967198d3d..c6d22a477e 100644
--- a/firmware/target/hosted/android/fs-android.c
+++ b/firmware/target/hosted/android/fs-android.c
@@ -105,26 +105,37 @@ struct dirinfo dir_get_info(struct DIR* _parent, struct dirent *dir)
105{ 105{
106 struct __dir *parent = (struct __dir*)_parent; 106 struct __dir *parent = (struct __dir*)_parent;
107 struct stat s; 107 struct stat s;
108 struct tm *tm; 108 struct tm *tm = NULL;
109 struct dirinfo ret; 109 struct dirinfo ret;
110 char path[MAX_PATH]; 110 char path[MAX_PATH];
111 111
112 snprintf(path, sizeof(path), "%s/%s", parent->path, dir->d_name); 112 snprintf(path, sizeof(path), "%s/%s", parent->path, dir->d_name);
113 stat(path, &s);
114 memset(&ret, 0, sizeof(ret)); 113 memset(&ret, 0, sizeof(ret));
115 114
116 if (S_ISDIR(s.st_mode)) 115 if (!stat(path, &s))
117 { 116 {
118 ret.attribute = ATTR_DIRECTORY; 117 if (S_ISDIR(s.st_mode))
118 {
119 ret.attribute = ATTR_DIRECTORY;
120 }
121 ret.size = s.st_size;
122 tm = localtime(&(s.st_mtime));
123 }
124
125 if (!lstat(path, &s) && S_ISLNK(s.st_mode))
126 {
127 ret.attribute |= ATTR_LINK;
128 }
129
130 if (tm)
131 {
132 ret.wrtdate = ((tm->tm_year - 80) << 9) |
133 ((tm->tm_mon + 1) << 5) |
134 tm->tm_mday;
135 ret.wrttime = (tm->tm_hour << 11) |
136 (tm->tm_min << 5) |
137 (tm->tm_sec >> 1);
119 } 138 }
120 139
121 ret.size = s.st_size;
122 tm = localtime(&(s.st_mtime));
123 ret.wrtdate = ((tm->tm_year - 80) << 9) |
124 ((tm->tm_mon + 1) << 5) |
125 tm->tm_mday;
126 ret.wrttime = (tm->tm_hour << 11) |
127 (tm->tm_min << 5) |
128 (tm->tm_sec >> 1);
129 return ret; 140 return ret;
130} 141}
diff --git a/uisimulator/common/io.c b/uisimulator/common/io.c
index fe7bad438f..56abf4b6ad 100644
--- a/uisimulator/common/io.c
+++ b/uisimulator/common/io.c
@@ -28,6 +28,7 @@
28#include "config.h" 28#include "config.h"
29 29
30#define HAVE_STATVFS (!defined(WIN32)) 30#define HAVE_STATVFS (!defined(WIN32))
31#define HAVE_LSTAT (!defined(WIN32))
31 32
32#if HAVE_STATVFS 33#if HAVE_STATVFS
33#include <sys/statvfs.h> 34#include <sys/statvfs.h>
@@ -314,7 +315,7 @@ struct sim_dirent *sim_readdir(MYDIR *dir)
314 static struct sim_dirent secret; 315 static struct sim_dirent secret;
315 STAT_T s; 316 STAT_T s;
316 DIRENT_T *x11 = READDIR(dir->dir); 317 DIRENT_T *x11 = READDIR(dir->dir);
317 struct tm* tm; 318 struct tm tm;
318 319
319 if(!x11) 320 if(!x11)
320 return (struct sim_dirent *)0; 321 return (struct sim_dirent *)0;
@@ -324,20 +325,35 @@ struct sim_dirent *sim_readdir(MYDIR *dir)
324 /* build file name */ 325 /* build file name */
325 snprintf(buffer, sizeof(buffer), "%s/%s", 326 snprintf(buffer, sizeof(buffer), "%s/%s",
326 get_sim_pathname(dir->name), secret.d_name); 327 get_sim_pathname(dir->name), secret.d_name);
327 STAT(buffer, &s); /* get info */ 328 if (STAT(buffer, &s)) /* get info */
329 return NULL;
328 330
329#define ATTR_DIRECTORY 0x10 331#define ATTR_DIRECTORY 0x10
330 332
331 secret.info.attribute = S_ISDIR(s.st_mode)?ATTR_DIRECTORY:0; 333 secret.info.attribute = 0;
334
335 if (S_ISDIR(s.st_mode))
336 secret.info.attribute = ATTR_DIRECTORY;
337
332 secret.info.size = s.st_size; 338 secret.info.size = s.st_size;
339
340 if (localtime_r(&(s.st_mtime), &tm) == NULL)
341 return NULL;
342 secret.info.wrtdate = ((tm.tm_year - 80) << 9) |
343 ((tm.tm_mon + 1) << 5) |
344 tm.tm_mday;
345 secret.info.wrttime = (tm.tm_hour << 11) |
346 (tm.tm_min << 5) |
347 (tm.tm_sec >> 1);
348
349#ifdef HAVE_LSTAT
350#define ATTR_LINK 0x80
351 if (!lstat(buffer, &s) && S_ISLNK(s.st_mode))
352 {
353 secret.info.attribute |= ATTR_LINK;
354 }
355#endif
333 356
334 tm = localtime(&(s.st_mtime));
335 secret.info.wrtdate = ((tm->tm_year - 80) << 9) |
336 ((tm->tm_mon + 1) << 5) |
337 tm->tm_mday;
338 secret.info.wrttime = (tm->tm_hour << 11) |
339 (tm->tm_min << 5) |
340 (tm->tm_sec >> 1);
341 return &secret; 357 return &secret;
342} 358}
343 359