summaryrefslogtreecommitdiff
path: root/firmware/common/rbpaths.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/common/rbpaths.c')
-rw-r--r--firmware/common/rbpaths.c117
1 files changed, 94 insertions, 23 deletions
diff --git a/firmware/common/rbpaths.c b/firmware/common/rbpaths.c
index 8efb6dd238..dba39476fc 100644
--- a/firmware/common/rbpaths.c
+++ b/firmware/common/rbpaths.c
@@ -48,6 +48,7 @@
48#undef rmdir 48#undef rmdir
49#undef dirent 49#undef dirent
50#undef DIR 50#undef DIR
51#undef readlink
51 52
52#if (CONFIG_PLATFORM & PLATFORM_ANDROID) 53#if (CONFIG_PLATFORM & PLATFORM_ANDROID)
53static const char rbhome[] = "/sdcard"; 54static const char rbhome[] = "/sdcard";
@@ -61,6 +62,9 @@ const char *rbhome;
61 * over the ones where Rockbox is installed to. Classic example would be 62 * over the ones where Rockbox is installed to. Classic example would be
62 * $HOME/.config/rockbox.org vs /usr/share/rockbox */ 63 * $HOME/.config/rockbox.org vs /usr/share/rockbox */
63#define HAVE_SPECIAL_DIRS 64#define HAVE_SPECIAL_DIRS
65#define IS_HOME(p) (!strcmp(p, rbhome))
66#else
67#define IS_HOME(p) (!strcmp(p, HOME_DIR))
64#endif 68#endif
65 69
66/* flags for get_user_file_path() */ 70/* flags for get_user_file_path() */
@@ -70,6 +74,35 @@ const char *rbhome;
70/* file or directory? */ 74/* file or directory? */
71#define IS_FILE (1<<1) 75#define IS_FILE (1<<1)
72 76
77#ifdef HAVE_MULTIDRIVE
78/* A special link is created under e.g. HOME_DIR/<microSD1>, e.g. to access
79 * external storage in a convinient location, much similar to the mount
80 * point on our native targets. Here they are treated as symlink (one which
81 * doesn't actually exist in the filesystem and therefore we have to override
82 * readlink() */
83static const char *handle_special_links(const char* link, unsigned flags,
84 char *buf, const size_t bufsize)
85{
86 (void) flags;
87 char vol_string[VOL_ENUM_POS + 8];
88 int len = sprintf(vol_string, VOL_NAMES, 1);
89
90 /* link might be passed with or without HOME_DIR expanded. To handle
91 * both perform substring matching (VOL_NAMES is unique enough) */
92 const char *begin = strstr(link, vol_string);
93 if (begin)
94 {
95 /* begin now points to the start of vol_string within link,
96 * we want to copy the remainder of the paths, prefixed by
97 * the actual mount point (the remainder might be "") */
98 snprintf(buf, bufsize, MULTIDRIVE_DIR"%s", begin + len);
99 return buf;
100 }
101
102 return link;
103}
104#endif
105
73#ifdef HAVE_SPECIAL_DIRS 106#ifdef HAVE_SPECIAL_DIRS
74void paths_init(void) 107void paths_init(void)
75{ 108{
@@ -156,38 +189,31 @@ static const char* _get_user_file_path(const char *path,
156 return ret; 189 return ret;
157} 190}
158 191
192#elif !defined(paths_init)
193void paths_init(void) { }
194#endif
159 195
160static const char* handle_special_dirs(const char* dir, unsigned flags, 196static const char* handle_special_dirs(const char* dir, unsigned flags,
161 char *buf, const size_t bufsize) 197 char *buf, const size_t bufsize)
162{ 198{
199 (void) flags; (void) buf; (void) bufsize;
200#ifdef HAVE_SPECIAL_DIRS
163 if (!strncmp(HOME_DIR, dir, HOME_DIR_LEN)) 201 if (!strncmp(HOME_DIR, dir, HOME_DIR_LEN))
164 { 202 {
165 const char *p = dir + HOME_DIR_LEN; 203 const char *p = dir + HOME_DIR_LEN;
166 while (*p == '/') p++; 204 while (*p == '/') p++;
167 snprintf(buf, bufsize, "%s/%s", rbhome, p); 205 snprintf(buf, bufsize, "%s/%s", rbhome, p);
168 return buf; 206 dir = buf;
169 } 207 }
170 else if (!strncmp(ROCKBOX_DIR, dir, ROCKBOX_DIR_LEN)) 208 else if (!strncmp(ROCKBOX_DIR, dir, ROCKBOX_DIR_LEN))
171 return _get_user_file_path(dir, flags, buf, bufsize); 209 dir = _get_user_file_path(dir, flags, buf, bufsize);
172 210#endif
173 return dir; 211#ifdef HAVE_MULTIDRIVE
174} 212 dir = handle_special_links(dir, flags, buf, bufsize);
175
176#else /* !HAVE_SPECIAL_DIRS */
177
178#ifndef paths_init
179void paths_init(void) { }
180#endif 213#endif
181
182static const char* handle_special_dirs(const char* dir, unsigned flags,
183 char *buf, const size_t bufsize)
184{
185 (void) flags; (void) buf; (void) bufsize;
186 return dir; 214 return dir;
187} 215}
188 216
189#endif
190
191int app_open(const char *name, int o, ...) 217int app_open(const char *name, int o, ...)
192{ 218{
193 char realpath[MAX_PATH]; 219 char realpath[MAX_PATH];
@@ -235,6 +261,7 @@ int app_rename(const char *old, const char *new)
235 * get_dir_info() */ 261 * get_dir_info() */
236struct __dir { 262struct __dir {
237 DIR *dir; 263 DIR *dir;
264 IF_MD(int volumes_returned);
238 char path[]; 265 char path[];
239}; 266};
240 267
@@ -246,23 +273,31 @@ struct dirinfo dir_get_info(DIR* _parent, struct dirent *dir)
246 struct dirinfo ret; 273 struct dirinfo ret;
247 char path[MAX_PATH]; 274 char path[MAX_PATH];
248 275
249 snprintf(path, sizeof(path), "%s/%s", parent->path, dir->d_name);
250 memset(&ret, 0, sizeof(ret)); 276 memset(&ret, 0, sizeof(ret));
251 277
278#ifdef HAVE_MULTIDRIVE
279 char vol_string[VOL_ENUM_POS + 8];
280 sprintf(vol_string, VOL_NAMES, 1);
281 if (!strcmp(vol_string, dir->d_name))
282 {
283 ret.attribute = ATTR_LINK;
284 strcpy(path, MULTIDRIVE_DIR);
285 }
286 else
287#endif
288 snprintf(path, sizeof(path), "%s/%s", parent->path, dir->d_name);
289
252 if (!stat(path, &s)) 290 if (!stat(path, &s))
253 { 291 {
254 if (S_ISDIR(s.st_mode)) 292 if (S_ISDIR(s.st_mode))
255 { 293 ret.attribute |= ATTR_DIRECTORY;
256 ret.attribute = ATTR_DIRECTORY; 294
257 }
258 ret.size = s.st_size; 295 ret.size = s.st_size;
259 tm = localtime(&(s.st_mtime)); 296 tm = localtime(&(s.st_mtime));
260 } 297 }
261 298
262 if (!lstat(path, &s) && S_ISLNK(s.st_mode)) 299 if (!lstat(path, &s) && S_ISLNK(s.st_mode))
263 {
264 ret.attribute |= ATTR_LINK; 300 ret.attribute |= ATTR_LINK;
265 }
266 301
267 if (tm) 302 if (tm)
268 { 303 {
@@ -296,6 +331,7 @@ DIR* app_opendir(const char *_name)
296 free(buf); 331 free(buf);
297 return NULL; 332 return NULL;
298 } 333 }
334 IF_MD(this->volumes_returned = 0);
299 return (DIR*)this; 335 return (DIR*)this;
300} 336}
301 337
@@ -311,6 +347,18 @@ int app_closedir(DIR *dir)
311struct dirent* app_readdir(DIR* dir) 347struct dirent* app_readdir(DIR* dir)
312{ 348{
313 struct __dir *d = (struct __dir*)dir; 349 struct __dir *d = (struct __dir*)dir;
350#ifdef HAVE_MULTIDRIVE
351 /* this is not MT-safe but OK according to man readdir */
352 static struct dirent voldir;
353 if (d->volumes_returned < (NUM_VOLUMES-1)
354 && volume_present(d->volumes_returned+1)
355 && IS_HOME(d->path))
356 {
357 d->volumes_returned += 1;
358 sprintf(voldir.d_name, VOL_NAMES, d->volumes_returned);
359 return &voldir;
360 }
361#endif
314 return readdir(d->dir); 362 return readdir(d->dir);
315} 363}
316 364
@@ -329,3 +377,26 @@ int app_rmdir(const char* name)
329 const char *fname = handle_special_dirs(name, NEED_WRITE, realpath, sizeof(realpath)); 377 const char *fname = handle_special_dirs(name, NEED_WRITE, realpath, sizeof(realpath));
330 return rmdir(fname); 378 return rmdir(fname);
331} 379}
380
381
382/* On MD we create a virtual symlink for the external drive,
383 * for this we need to override readlink(). */
384ssize_t app_readlink(const char *path, char *buf, size_t bufsiz)
385{
386 char _buf[MAX_PATH];
387 (void) path; (void) buf; (void) bufsiz;
388 path = handle_special_dirs(path, 0, _buf, sizeof(_buf));
389#ifdef HAVE_MULTIDRIVE
390 /* if path == _buf then we can be sure handle_special_dir() did something
391 * and path is not an ordinary directory */
392 if (path == _buf && !strncmp(path, MULTIDRIVE_DIR, sizeof(MULTIDRIVE_DIR)-1))
393 {
394 /* copying NUL is not required as per readlink specification */
395 ssize_t len = strlen(path);
396 memcpy(buf, path, len);
397 return len;
398 }
399#endif
400 /* does not append NUL !! */
401 return readlink(path, buf, bufsiz);
402}