A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita
audio
rust
zig
deno
mpris
rockbox
mpd
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2014 by Michael Sevakis
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#ifndef _DIRCACHE_REDIRECT_H_
22
23#include "rbpaths.h"
24#include "pathfuncs.h"
25#include "dir.h"
26#include "dircache.h"
27#include "file.h"
28
29#if defined(HAVE_MULTIBOOT) && !defined(SIMULATOR) && !defined(BOOTLOADER)
30#include "rb-loader.h"
31#include "multiboot.h"
32#include "bootdata.h"
33#endif
34
35#ifndef RB_ROOT_VOL_HIDDEN
36#define RB_ROOT_VOL_HIDDEN(v) (0 == 0)
37#endif
38#ifndef RB_ROOT_CONTENTS_DIR
39#define RB_ROOT_CONTENTS_DIR "/"
40#endif
41/***
42 ** Internal redirects that depend upon whether or not dircache is made
43 **
44 ** Some stuff deals with it, some doesn't right now. This is a nexus point..
45 **/
46
47/** File binding **/
48
49static inline void get_rootinfo_internal(struct file_base_info *infop)
50{
51#ifdef HAVE_DIRCACHE
52 dircache_get_rootinfo(infop);
53#else
54 (void)infop;
55#endif
56}
57
58static inline void fileobj_bind_file(struct file_base_binding *bindp)
59{
60#ifdef HAVE_DIRCACHE
61 dircache_bind_file(bindp);
62#else
63 file_binding_insert_last(bindp);
64#endif
65}
66
67static inline void fileobj_unbind_file(struct file_base_binding *bindp)
68{
69#ifdef HAVE_DIRCACHE
70 dircache_unbind_file(bindp);
71#else
72 file_binding_remove(bindp);
73#endif
74}
75
76
77/** File event handlers **/
78
79static inline void fileop_onopen_internal(struct filestr_base *stream,
80 struct file_base_info *srcinfop,
81 unsigned int callflags)
82{
83 fileobj_fileop_open(stream, srcinfop, callflags);
84}
85
86static inline void fileop_onclose_internal(struct filestr_base *stream)
87{
88 fileobj_fileop_close(stream);
89}
90
91static inline void fileop_oncreate_internal(struct filestr_base *stream,
92 struct file_base_info *srcinfop,
93 unsigned int callflags,
94 struct file_base_info *dirinfop,
95 const char *basename)
96{
97#ifdef HAVE_DIRCACHE
98 dircache_dcfile_init(&srcinfop->dcfile);
99#endif
100 fileobj_fileop_create(stream, srcinfop, callflags);
101#ifdef HAVE_DIRCACHE
102 struct dirinfo_native din;
103 fill_dirinfo_native(&din);
104 dircache_fileop_create(dirinfop, stream->bindp, basename, &din);
105#endif
106 (void)dirinfop; (void)basename;
107}
108
109static inline void fileop_onremove_internal(struct filestr_base *stream,
110 struct file_base_info *oldinfop)
111{
112 fileobj_fileop_remove(stream, oldinfop);
113#ifdef HAVE_DIRCACHE
114 dircache_fileop_remove(stream->bindp);
115#endif
116}
117
118static inline void fileop_onrename_internal(struct filestr_base *stream,
119 struct file_base_info *oldinfop,
120 struct file_base_info *dirinfop,
121 const char *basename)
122{
123 fileobj_fileop_rename(stream, oldinfop);
124#ifdef HAVE_DIRCACHE
125 dircache_fileop_rename(dirinfop, stream->bindp, basename);
126#endif
127 (void)dirinfop; (void)basename;
128}
129
130static inline void fileop_onsync_internal(struct filestr_base *stream)
131{
132 fileobj_fileop_sync(stream);
133#ifdef HAVE_DIRCACHE
134 struct dirinfo_native din;
135 fill_dirinfo_native(&din);
136 dircache_fileop_sync(stream->bindp, &din);
137#endif
138}
139
140#if defined(HAVE_MULTIBOOT) && !defined(SIMULATOR) && !defined(BOOTLOADER)
141static inline bool multiboot_is_boot_volume(int volume)
142{
143 if (boot_data.version == 0)
144 {
145 /*
146 * Version 0 bootloaders just pass the volume number, but that's
147 * dynamically assigned and sometimes differs by the time we get
148 * into the firmware. So we can't rely on the volume passed by
149 * the bootloader.
150 */
151#if CONFIG_CPU == X1000
152 /* The affected X1000 players only have one drive to begin with */
153 return volume_drive(volume) == 0;
154#else
155 /* FIXME: Anything else that can get here is a Sansa. */
156 return volume_drive(volume) == boot_data._boot_volume ||
157 volume == boot_data._boot_volume;
158#endif
159 }
160
161 if (boot_data.version == 1)
162 {
163 /*
164 * Since version 1 the bootloader passes drive and partition
165 * number which unambiguously identifies the boot volume.
166 */
167 return volume_drive(volume) == boot_data.boot_drive &&
168 volume_partition(volume) == boot_data.boot_partition;
169 }
170
171 return false;
172}
173#endif
174
175static inline void volume_onmount_internal(IF_MV_NONVOID(int volume))
176{
177#if defined(HAVE_MULTIBOOT) && !defined(SIMULATOR) && !defined(BOOTLOADER)
178 char path[VOL_MAX_LEN+2];
179 char rtpath[MAX_PATH / 2];
180 make_volume_root(volume, path);
181
182 if (boot_data_valid)
183 {
184 /* we need to mount the drive before we can access it */
185 root_mount_path(path, 0); /* root could be different folder don't hide */
186
187 if (multiboot_is_boot_volume(IF_MV_VOL(volume)))
188 {
189 /* get the full path to the BOOTFILE
190 ie. /<0>/redirectdir/.rockbox/rockbox.ext */
191 int rtlen = get_redirect_dir(rtpath, sizeof(rtpath),
192 volume, BOOTDIR, BOOTFILE);
193
194 if (rtlen <= 0 || rtlen >= (int) sizeof(rtpath))
195 rtlen = 0; /* path too long or sprintf error */
196 else if (file_exists(rtpath))
197 {
198 rtlen = get_redirect_dir(rtpath, sizeof(rtpath), volume, "", "");
199 while (rtlen > 0 && rtpath[--rtlen] == PATH_SEPCH)
200 rtpath[rtlen] = '\0'; /* remove separators */
201 }
202 else
203 rtlen = 0; /* No BOOTFILE found */
204
205#if 0 /*removed, causes issues with playback for now?*/
206 if (rtlen <= 0 || rtpath[rtlen] == VOL_END_TOK)
207 root_unmount_volume(volume); /* unmount so root can be hidden*/
208#endif
209 if (rtlen <= 0 || root_mount_path(rtpath, NSITEM_CONTENTS) != 0)
210 { /* Error occurred, card removed? Set root to default */
211 boot_data_valid = false;
212 root_unmount_volume(volume); /* unmount so root can be hidden*/
213 goto standard_redirect;
214 }
215 }
216 }
217 else
218 {
219standard_redirect:
220 root_mount_path(path, RB_ROOT_VOL_HIDDEN(volume) ? NSITEM_HIDDEN : 0);
221 if (volume == path_strip_volume(RB_ROOT_CONTENTS_DIR, NULL, false))
222 root_mount_path(RB_ROOT_CONTENTS_DIR, NSITEM_CONTENTS);
223 }
224#elif defined(HAVE_MULTIVOLUME)
225 char path[VOL_MAX_LEN+2];
226 make_volume_root(volume, path);
227 root_mount_path(path, RB_ROOT_VOL_HIDDEN(volume) ? NSITEM_HIDDEN : 0);
228 if (volume == path_strip_volume(RB_ROOT_CONTENTS_DIR, NULL, false))
229 root_mount_path(RB_ROOT_CONTENTS_DIR, NSITEM_CONTENTS);
230#else
231 const char *path = PATH_ROOTSTR;
232 root_mount_path(path, RB_ROOT_VOL_HIDDEN(volume) ? NSITEM_HIDDEN : 0);
233 root_mount_path(RB_ROOT_CONTENTS_DIR, NSITEM_CONTENTS);
234#endif /* HAVE_MULTIBOOT */
235
236#ifdef HAVE_DIRCACHE
237 dircache_mount();
238#endif
239}
240
241static inline void volume_onunmount_internal(IF_MV_NONVOID(int volume))
242{
243#ifdef HAVE_DIRCACHE
244 /* First, to avoid update of something about to be destroyed anyway */
245 dircache_unmount(IF_MV(volume));
246#endif
247 root_unmount_volume(IF_MV(volume));
248 fileobj_mgr_unmount(IF_MV(volume));
249}
250
251static inline void fileop_onunmount_internal(struct filestr_base *stream)
252{
253
254 if (stream->flags & FD_WRITE)
255 force_close_writer_internal(stream); /* try to save stuff */
256 else
257 fileop_onclose_internal(stream); /* just readers, bye */
258}
259
260
261/** Directory reading **/
262
263static inline int readdir_dirent(struct filestr_base *stream,
264 struct dirscan_info *scanp,
265 struct DIRENT *entry)
266{
267#ifdef HAVE_DIRCACHE
268 return dircache_readdir_dirent(stream, scanp, entry);
269#else
270 return uncached_readdir_dirent(stream, scanp, entry);
271#endif
272}
273
274static inline void rewinddir_dirent(struct dirscan_info *scanp)
275{
276#ifdef HAVE_DIRCACHE
277 dircache_rewinddir_dirent(scanp);
278#else
279 uncached_rewinddir_dirent(scanp);
280#endif
281}
282
283static inline int readdir_internal(struct filestr_base *stream,
284 struct file_base_info *infop,
285 struct fat_direntry *fatent)
286{
287#ifdef HAVE_DIRCACHE
288 return dircache_readdir_internal(stream, infop, fatent);
289#else
290 return uncached_readdir_internal(stream, infop, fatent);
291#endif
292}
293
294static inline void rewinddir_internal(struct file_base_info *infop)
295{
296#ifdef HAVE_DIRCACHE
297 dircache_rewinddir_internal(infop);
298#else
299 uncached_rewinddir_internal(infop);
300#endif
301}
302
303
304/** Misc. stuff **/
305
306static inline struct fat_direntry *get_dir_fatent_dircache(void)
307{
308#ifdef HAVE_DIRCACHE
309 return get_dir_fatent();
310#else
311 return NULL;
312#endif
313}
314
315#endif /* _DIRCACHE_REDIRECT_H_ */