diff options
-rw-r--r-- | apps/tagcache.c | 130 | ||||
-rw-r--r-- | firmware/include/dir.h | 1 | ||||
-rw-r--r-- | firmware/target/hosted/android/fs-android.c | 35 | ||||
-rw-r--r-- | uisimulator/common/io.c | 36 |
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 | ||
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; |
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 | ||