diff options
Diffstat (limited to 'firmware/include/file_internal.h')
-rw-r--r-- | firmware/include/file_internal.h | 371 |
1 files changed, 371 insertions, 0 deletions
diff --git a/firmware/include/file_internal.h b/firmware/include/file_internal.h new file mode 100644 index 0000000000..d1bb67406a --- /dev/null +++ b/firmware/include/file_internal.h | |||
@@ -0,0 +1,371 @@ | |||
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 _FILE_INTERNAL_H_ | ||
22 | #define _FILE_INTERNAL_H_ | ||
23 | |||
24 | #include <sys/types.h> | ||
25 | #include <stdlib.h> | ||
26 | #include "mv.h" | ||
27 | #include "linked_list.h" | ||
28 | #include "mutex.h" | ||
29 | #include "mrsw_lock.h" | ||
30 | #include "fs_attr.h" | ||
31 | #include "fat.h" | ||
32 | #ifdef HAVE_DIRCACHE | ||
33 | #include "dircache.h" | ||
34 | #endif | ||
35 | |||
36 | /** Tuneable parameters **/ | ||
37 | |||
38 | /* limits for number of open descriptors - if you increase these values, make | ||
39 | certain that the disk cache has enough available buffers */ | ||
40 | #define MAX_OPEN_FILES 11 | ||
41 | #define MAX_OPEN_DIRS 12 | ||
42 | #define MAX_OPEN_HANDLES (MAX_OPEN_FILES+MAX_OPEN_DIRS) | ||
43 | |||
44 | /* internal functions open streams as well; make sure they don't fail if all | ||
45 | user descs are busy; this needs to be at least the greatest quantity needed | ||
46 | at once by all internal functions */ | ||
47 | #ifdef HAVE_DIRCACHE | ||
48 | #define AUX_FILEOBJS 3 | ||
49 | #else | ||
50 | #define AUX_FILEOBJS 2 | ||
51 | #endif | ||
52 | |||
53 | /* number of components statically allocated to handle the vast majority | ||
54 | of path depths; should maybe be tuned for >= 90th percentile but for now, | ||
55 | imma just guessing based on something like: | ||
56 | root + 'Music' + 'Artist' + 'Album' + 'Disc N' + filename */ | ||
57 | #define STATIC_PATHCOMP_NUM 6 | ||
58 | |||
59 | #define MAX_NAME 255 | ||
60 | |||
61 | /* unsigned value that will also hold the off_t range we need without | ||
62 | overflow */ | ||
63 | #define file_size_t uint32_t | ||
64 | |||
65 | #ifdef __USE_FILE_OFFSET64 | ||
66 | /* if we want, we can deal with files up to 2^32-1 bytes-- the full FAT16/32 | ||
67 | range */ | ||
68 | #define FILE_SIZE_MAX (0xffffffffu) | ||
69 | #else | ||
70 | /* file contents and size will be preserved by the APIs so long as ftruncate() | ||
71 | isn't used; bytes passed 2^31-1 will not accessible nor will writes succeed | ||
72 | that would extend the file beyond the max for a 32-bit off_t */ | ||
73 | #define FILE_SIZE_MAX (0x7fffffffu) | ||
74 | #endif | ||
75 | |||
76 | /* if file is "large(ish)", then get rid of the contents now rather than | ||
77 | lazily when the file is synced or closed in order to free-up space */ | ||
78 | #define O_TRUNC_THRESH 65536 | ||
79 | |||
80 | /* default attributes when creating new files and directories */ | ||
81 | #define ATTR_NEW_FILE (ATTR_ARCHIVE) | ||
82 | #define ATTR_NEW_DIRECTORY (ATTR_DIRECTORY) | ||
83 | |||
84 | #define ATTR_MOUNT_POINT (ATTR_VOLUME | ATTR_DIRECTORY) | ||
85 | |||
86 | /** File sector cache **/ | ||
87 | |||
88 | enum filestr_cache_flags | ||
89 | { | ||
90 | FSC_DIRTY = 0x1, /* buffer is dirty (needs writeback) */ | ||
91 | FSC_NEW = 0x2, /* buffer is new (never yet written) */ | ||
92 | }; | ||
93 | |||
94 | struct filestr_cache | ||
95 | { | ||
96 | uint8_t *buffer; /* buffer to hold sector */ | ||
97 | unsigned long sector; /* file sector that is in buffer */ | ||
98 | unsigned int flags; /* FSC_* bits */ | ||
99 | }; | ||
100 | |||
101 | void file_cache_init(struct filestr_cache *cachep); | ||
102 | void file_cache_reset(struct filestr_cache *cachep); | ||
103 | void file_cache_alloc(struct filestr_cache *cachep); | ||
104 | void file_cache_free(struct filestr_cache *cachep); | ||
105 | |||
106 | |||
107 | /** Common bitflags used throughout **/ | ||
108 | |||
109 | /* bitflags used by open files and descriptors */ | ||
110 | enum fildes_and_obj_flags | ||
111 | { | ||
112 | /* used in descriptor and common */ | ||
113 | FDO_BUSY = 0x0001, /* descriptor/object is in use */ | ||
114 | /* only used in individual stream descriptor */ | ||
115 | FD_WRITE = 0x0002, /* descriptor has write mode */ | ||
116 | FD_WRONLY = 0x0004, /* descriptor is write mode only */ | ||
117 | FD_APPEND = 0x0008, /* descriptor is append mode */ | ||
118 | /* only used as common flags */ | ||
119 | FO_DIRECTORY = 0x0010, /* fileobj is a directory */ | ||
120 | FO_TRUNC = 0x0020, /* fileobj is opened to be truncated */ | ||
121 | FO_REMOVED = 0x0040, /* fileobj was deleted while open */ | ||
122 | FO_SINGLE = 0x0080, /* fileobj has only one stream open */ | ||
123 | FDO_MASK = 0x00ff, | ||
124 | /* bitflags that instruct various 'open' functions how to behave */ | ||
125 | FF_FILE = 0x0000, /* expect file; accept file only */ | ||
126 | FF_DIR = 0x0100, /* expect dir; accept dir only */ | ||
127 | FF_ANYTYPE = 0x0200, /* succeed if either file or dir */ | ||
128 | FF_TYPEMASK = 0x0300, /* mask of typeflags */ | ||
129 | FF_CREAT = 0x0400, /* create if file doesn't exist */ | ||
130 | FF_EXCL = 0x0800, /* fail if creating and file exists */ | ||
131 | FF_CHECKPREFIX = 0x1000, /* detect if file is prefix of path */ | ||
132 | FF_NOISO = 0x2000, /* do not decode ISO filenames to UTF-8 */ | ||
133 | FF_MASK = 0x3f00, | ||
134 | /* special values used in isolation */ | ||
135 | FV_NONEXIST = 0x8000, /* closed but not freed (unmounted) */ | ||
136 | FV_OPENSYSROOT = 0xc001, /* open sysroot, volume 0 not mounted */ | ||
137 | }; | ||
138 | |||
139 | |||
140 | /** Common data structures used throughout **/ | ||
141 | |||
142 | /* basic file information about its location */ | ||
143 | struct file_base_info | ||
144 | { | ||
145 | union { | ||
146 | #ifdef HAVE_MULTIVOLUME | ||
147 | int volume; /* file's volume (overlaps fatfile.volume) */ | ||
148 | #endif | ||
149 | #if CONFIG_PLATFORM & PLATFORM_NATIVE | ||
150 | struct fat_file fatfile; /* FS driver file info */ | ||
151 | #endif | ||
152 | }; | ||
153 | #ifdef HAVE_DIRCACHE | ||
154 | struct dircache_file dcfile; /* dircache file info */ | ||
155 | #endif | ||
156 | }; | ||
157 | |||
158 | #define BASEINFO_VOL(infop) \ | ||
159 | IF_MV_VOL((infop)->volume) | ||
160 | |||
161 | /* open files binding item */ | ||
162 | struct file_base_binding | ||
163 | { | ||
164 | struct ll_node node; /* list item node (first!) */ | ||
165 | struct file_base_info info; /* basic file info */ | ||
166 | }; | ||
167 | |||
168 | #define BASEBINDING_VOL(bindp) \ | ||
169 | BASEINFO_VOL(&(bindp)->info) | ||
170 | |||
171 | /* directory scanning position info */ | ||
172 | struct dirscan_info | ||
173 | { | ||
174 | #if CONFIG_PLATFORM & PLATFORM_NATIVE | ||
175 | struct fat_dirscan_info fatscan; /* FS driver scan info */ | ||
176 | #endif | ||
177 | #ifdef HAVE_DIRCACHE | ||
178 | struct dircache_file dcscan; /* dircache scan info */ | ||
179 | #endif | ||
180 | }; | ||
181 | |||
182 | /* describes the file as an open stream */ | ||
183 | struct filestr_base | ||
184 | { | ||
185 | struct ll_node node; /* list item node (first!) */ | ||
186 | uint16_t flags; /* FD_* bits of this stream */ | ||
187 | uint16_t unused; /* not used */ | ||
188 | struct filestr_cache cache; /* stream-local cache */ | ||
189 | struct filestr_cache *cachep; /* the cache in use (local or shared) */ | ||
190 | struct file_base_info *infop; /* base file information */ | ||
191 | struct fat_filestr fatstr; /* FS driver information */ | ||
192 | struct file_base_binding *bindp; /* common binding for file/dir */ | ||
193 | struct mutex *mtx; /* serialization for this stream */ | ||
194 | }; | ||
195 | |||
196 | void filestr_base_init(struct filestr_base *stream); | ||
197 | void filestr_base_destroy(struct filestr_base *stream); | ||
198 | void filestr_alloc_cache(struct filestr_base *stream); | ||
199 | void filestr_free_cache(struct filestr_base *stream); | ||
200 | void filestr_assign_cache(struct filestr_base *stream, | ||
201 | struct filestr_cache *cachep); | ||
202 | void filestr_copy_cache(struct filestr_base *stream, | ||
203 | struct filestr_cache *cachep); | ||
204 | void filestr_discard_cache(struct filestr_base *stream); | ||
205 | |||
206 | /* allocates a cache buffer if needed and returns the cache pointer */ | ||
207 | static inline struct filestr_cache * | ||
208 | filestr_get_cache(struct filestr_base *stream) | ||
209 | { | ||
210 | struct filestr_cache *cachep = stream->cachep; | ||
211 | |||
212 | if (!cachep->buffer) | ||
213 | filestr_alloc_cache(stream); | ||
214 | |||
215 | return cachep; | ||
216 | } | ||
217 | |||
218 | static inline void filestr_lock(struct filestr_base *stream) | ||
219 | { | ||
220 | mutex_lock(stream->mtx); | ||
221 | } | ||
222 | |||
223 | static inline void filestr_unlock(struct filestr_base *stream) | ||
224 | { | ||
225 | mutex_unlock(stream->mtx); | ||
226 | } | ||
227 | |||
228 | /* stream lock doesn't have to be used if getting RW lock writer access */ | ||
229 | #define FILESTR_WRITER 0 | ||
230 | #define FILESTR_READER 1 | ||
231 | |||
232 | #define FILESTR_LOCK(type, stream) \ | ||
233 | ({ if (FILESTR_##type) filestr_lock(stream); }) | ||
234 | |||
235 | #define FILESTR_UNLOCK(type, stream) \ | ||
236 | ({ if (FILESTR_##type) filestr_unlock(stream); }) | ||
237 | |||
238 | #define ATTR_PREFIX (0x8000) /* out of the way of all ATTR_* bits */ | ||
239 | |||
240 | /* structure to return detailed information about what you opened */ | ||
241 | struct path_component_info | ||
242 | { | ||
243 | const char *name; /* pointer to name within 'path' */ | ||
244 | size_t length; /* length of component within 'path' */ | ||
245 | file_size_t filesize; /* size of the opened file (0 if dir) */ | ||
246 | unsigned int attr; /* attributes of this component */ | ||
247 | struct file_base_info *prefixp; /* base info to check as prefix (IN) */ | ||
248 | struct file_base_info parentinfo; /* parent directory info of file */ | ||
249 | }; | ||
250 | |||
251 | int open_stream_internal(const char *path, unsigned int callflags, | ||
252 | struct filestr_base *stream, | ||
253 | struct path_component_info *compinfo); | ||
254 | int close_stream_internal(struct filestr_base *stream); | ||
255 | int create_stream_internal(struct file_base_info *parentinfop, | ||
256 | const char *basename, size_t length, | ||
257 | unsigned int attr, unsigned int callflags, | ||
258 | struct filestr_base *stream); | ||
259 | int remove_stream_internal(const char *path, struct filestr_base *stream, | ||
260 | unsigned int callflags); | ||
261 | int test_stream_exists_internal(const char *path, unsigned int callflags); | ||
262 | |||
263 | int open_noiso_internal(const char *path, int oflag); /* file.c */ | ||
264 | |||
265 | struct dirent; | ||
266 | int uncached_readdir_dirent(struct filestr_base *stream, | ||
267 | struct dirscan_info *scanp, | ||
268 | struct dirent *entry); | ||
269 | void uncached_rewinddir_dirent(struct dirscan_info *scanp); | ||
270 | |||
271 | int uncached_readdir_internal(struct filestr_base *stream, | ||
272 | struct file_base_info *infop, | ||
273 | struct fat_direntry *fatent); | ||
274 | void uncached_rewinddir_internal(struct file_base_info *infop); | ||
275 | |||
276 | int test_dir_empty_internal(struct filestr_base *stream); | ||
277 | |||
278 | struct dirinfo_internal | ||
279 | { | ||
280 | unsigned int attr; | ||
281 | file_size_t size; | ||
282 | uint16_t wrtdate; | ||
283 | uint16_t wrttime; | ||
284 | }; | ||
285 | |||
286 | /** Synchronization used throughout **/ | ||
287 | |||
288 | /* acquire the filesystem lock as READER */ | ||
289 | static inline void file_internal_lock_READER(void) | ||
290 | { | ||
291 | extern struct mrsw_lock file_internal_mrsw; | ||
292 | mrsw_read_acquire(&file_internal_mrsw); | ||
293 | } | ||
294 | |||
295 | /* release the filesystem lock as READER */ | ||
296 | static inline void file_internal_unlock_READER(void) | ||
297 | { | ||
298 | extern struct mrsw_lock file_internal_mrsw; | ||
299 | mrsw_read_release(&file_internal_mrsw); | ||
300 | } | ||
301 | |||
302 | /* acquire the filesystem lock as WRITER */ | ||
303 | static inline void file_internal_lock_WRITER(void) | ||
304 | { | ||
305 | extern struct mrsw_lock file_internal_mrsw; | ||
306 | mrsw_write_acquire(&file_internal_mrsw); | ||
307 | } | ||
308 | |||
309 | /* release the filesystem lock as WRITER */ | ||
310 | static inline void file_internal_unlock_WRITER(void) | ||
311 | { | ||
312 | extern struct mrsw_lock file_internal_mrsw; | ||
313 | mrsw_write_release(&file_internal_mrsw); | ||
314 | } | ||
315 | |||
316 | #define ERRNO 0 /* maintain errno value */ | ||
317 | #define RC 0 /* maintain rc value */ | ||
318 | |||
319 | /* NOTES: if _errno is a non-constant expression, it must set an error | ||
320 | * number and not return the ERRNO constant which will merely set | ||
321 | * errno to zero, not preserve the current value; if you must set | ||
322 | * errno to zero, set it explicitly, not in the macro | ||
323 | * | ||
324 | * if _rc is constant-expression evaluation to 'RC', then rc will | ||
325 | * NOT be altered; i.e. if you must set rc to zero, set it explicitly, | ||
326 | * not in the macro | ||
327 | */ | ||
328 | |||
329 | /* set errno and rc and proceed to the "file_error:" label */ | ||
330 | #define FILE_ERROR(_errno, _rc) \ | ||
331 | ({ __builtin_constant_p(_errno) ? \ | ||
332 | ({ if ((_errno) != ERRNO) errno = (_errno); }) : \ | ||
333 | ({ errno = (_errno); }); \ | ||
334 | __builtin_constant_p(_rc) ? \ | ||
335 | ({ if ((_rc) != RC) rc = (_rc); }) : \ | ||
336 | ({ rc = (_rc); }); \ | ||
337 | goto file_error; }) | ||
338 | |||
339 | /* set errno and return a value at the point of invocation */ | ||
340 | #define FILE_ERROR_RETURN(_errno, _rc...) \ | ||
341 | ({ __builtin_constant_p(_errno) ? \ | ||
342 | ({ if ((_errno) != ERRNO) errno = (_errno); }) : \ | ||
343 | ({ errno = (_errno); }); \ | ||
344 | return _rc; }) | ||
345 | |||
346 | |||
347 | /** Misc. stuff **/ | ||
348 | |||
349 | /* iterate through all the volumes if volume < 0, else just the given volume */ | ||
350 | #define FOR_EACH_VOLUME(volume, i) \ | ||
351 | for (int i = (IF_MV_VOL(volume) >= 0 ? IF_MV_VOL(volume) : 0), \ | ||
352 | _end = (IF_MV_VOL(volume) >= 0 ? i : NUM_VOLUMES-1); \ | ||
353 | i <= _end; i++) | ||
354 | |||
355 | /* return a pointer to the static struct fat_direntry */ | ||
356 | static inline struct fat_direntry *get_dir_fatent(void) | ||
357 | { | ||
358 | extern struct fat_direntry dir_fatent; | ||
359 | return &dir_fatent; | ||
360 | } | ||
361 | |||
362 | void iso_decode_d_name(char *d_name); | ||
363 | |||
364 | #ifdef HAVE_DIRCACHE | ||
365 | void empty_dirent(struct dirent *entry); | ||
366 | void fill_dirinfo_native(struct dirinfo_native *din); | ||
367 | #endif /* HAVE_DIRCACHE */ | ||
368 | |||
369 | void filesystem_init(void) INIT_ATTR; | ||
370 | |||
371 | #endif /* _FILE_INTERNAL_H_ */ | ||