summaryrefslogtreecommitdiff
path: root/firmware/include/file_internal.h
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/include/file_internal.h')
-rw-r--r--firmware/include/file_internal.h371
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
88enum 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
94struct 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
101void file_cache_init(struct filestr_cache *cachep);
102void file_cache_reset(struct filestr_cache *cachep);
103void file_cache_alloc(struct filestr_cache *cachep);
104void file_cache_free(struct filestr_cache *cachep);
105
106
107/** Common bitflags used throughout **/
108
109/* bitflags used by open files and descriptors */
110enum 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 */
143struct 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 */
162struct 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 */
172struct 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 */
183struct 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
196void filestr_base_init(struct filestr_base *stream);
197void filestr_base_destroy(struct filestr_base *stream);
198void filestr_alloc_cache(struct filestr_base *stream);
199void filestr_free_cache(struct filestr_base *stream);
200void filestr_assign_cache(struct filestr_base *stream,
201 struct filestr_cache *cachep);
202void filestr_copy_cache(struct filestr_base *stream,
203 struct filestr_cache *cachep);
204void filestr_discard_cache(struct filestr_base *stream);
205
206/* allocates a cache buffer if needed and returns the cache pointer */
207static inline struct filestr_cache *
208filestr_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
218static inline void filestr_lock(struct filestr_base *stream)
219{
220 mutex_lock(stream->mtx);
221}
222
223static 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 */
241struct 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
251int open_stream_internal(const char *path, unsigned int callflags,
252 struct filestr_base *stream,
253 struct path_component_info *compinfo);
254int close_stream_internal(struct filestr_base *stream);
255int 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);
259int remove_stream_internal(const char *path, struct filestr_base *stream,
260 unsigned int callflags);
261int test_stream_exists_internal(const char *path, unsigned int callflags);
262
263int open_noiso_internal(const char *path, int oflag); /* file.c */
264
265struct dirent;
266int uncached_readdir_dirent(struct filestr_base *stream,
267 struct dirscan_info *scanp,
268 struct dirent *entry);
269void uncached_rewinddir_dirent(struct dirscan_info *scanp);
270
271int uncached_readdir_internal(struct filestr_base *stream,
272 struct file_base_info *infop,
273 struct fat_direntry *fatent);
274void uncached_rewinddir_internal(struct file_base_info *infop);
275
276int test_dir_empty_internal(struct filestr_base *stream);
277
278struct 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 */
289static 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 */
296static 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 */
303static 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 */
310static 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 */
356static inline struct fat_direntry *get_dir_fatent(void)
357{
358 extern struct fat_direntry dir_fatent;
359 return &dir_fatent;
360}
361
362void iso_decode_d_name(char *d_name);
363
364#ifdef HAVE_DIRCACHE
365void empty_dirent(struct dirent *entry);
366void fill_dirinfo_native(struct dirinfo_native *din);
367#endif /* HAVE_DIRCACHE */
368
369void filesystem_init(void) INIT_ATTR;
370
371#endif /* _FILE_INTERNAL_H_ */