summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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