diff options
Diffstat (limited to 'firmware/common/dir_uncached.c')
-rw-r--r-- | firmware/common/dir_uncached.c | 312 |
1 files changed, 0 insertions, 312 deletions
diff --git a/firmware/common/dir_uncached.c b/firmware/common/dir_uncached.c deleted file mode 100644 index b850a514e7..0000000000 --- a/firmware/common/dir_uncached.c +++ /dev/null | |||
@@ -1,312 +0,0 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id: dir.c 13741 2007-06-30 02:08:27Z jethead71 $ | ||
9 | * | ||
10 | * Copyright (C) 2002 by Björn Stenberg | ||
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 | #include <stdio.h> | ||
22 | #include <errno.h> | ||
23 | #include <string.h> | ||
24 | #include <stdbool.h> | ||
25 | #include <stdlib.h> | ||
26 | #include "fat.h" | ||
27 | #include "dir.h" | ||
28 | #include "debug.h" | ||
29 | #include "filefuncs.h" | ||
30 | |||
31 | #if (MEMORYSIZE > 8) | ||
32 | #define MAX_OPEN_DIRS 12 | ||
33 | #else | ||
34 | #define MAX_OPEN_DIRS 8 | ||
35 | #endif | ||
36 | |||
37 | static DIR_UNCACHED opendirs[MAX_OPEN_DIRS]; | ||
38 | |||
39 | // release all dir handles on a given volume "by force", to avoid leaks | ||
40 | int release_dirs(int volume) | ||
41 | { | ||
42 | DIR_UNCACHED* pdir = opendirs; | ||
43 | int dd; | ||
44 | int closed = 0; | ||
45 | for ( dd=0; dd<MAX_OPEN_DIRS; dd++, pdir++) | ||
46 | { | ||
47 | #ifdef HAVE_MULTIVOLUME | ||
48 | if (pdir->fatdir.file.volume == volume) | ||
49 | #else | ||
50 | (void)volume; | ||
51 | #endif | ||
52 | { | ||
53 | pdir->busy = false; /* mark as available, no further action */ | ||
54 | closed++; | ||
55 | } | ||
56 | } | ||
57 | return closed; /* return how many we did */ | ||
58 | } | ||
59 | |||
60 | DIR_UNCACHED* opendir_uncached(const char* name) | ||
61 | { | ||
62 | char namecopy[MAX_PATH]; | ||
63 | char* part; | ||
64 | char* end; | ||
65 | struct fat_direntry entry; | ||
66 | int dd; | ||
67 | DIR_UNCACHED* pdir = opendirs; | ||
68 | #ifdef HAVE_MULTIVOLUME | ||
69 | int volume; | ||
70 | #endif | ||
71 | |||
72 | if ( name[0] != '/' ) { | ||
73 | DEBUGF("Only absolute paths supported right now\n"); | ||
74 | return NULL; | ||
75 | } | ||
76 | |||
77 | /* find a free dir descriptor */ | ||
78 | for ( dd=0; dd<MAX_OPEN_DIRS; dd++, pdir++) | ||
79 | if ( !pdir->busy ) | ||
80 | break; | ||
81 | |||
82 | if ( dd == MAX_OPEN_DIRS ) { | ||
83 | DEBUGF("Too many dirs open\n"); | ||
84 | errno = EMFILE; | ||
85 | return NULL; | ||
86 | } | ||
87 | |||
88 | pdir->busy = true; | ||
89 | |||
90 | #ifdef HAVE_MULTIVOLUME | ||
91 | /* try to extract a heading volume name, if present */ | ||
92 | volume = strip_volume(name, namecopy); | ||
93 | pdir->volumecounter = 0; | ||
94 | #else | ||
95 | strlcpy(namecopy, name, sizeof(namecopy)); /* just copy */ | ||
96 | #endif | ||
97 | |||
98 | if ( fat_opendir(IF_MV(volume,) &pdir->fatdir, 0, NULL) < 0 ) { | ||
99 | DEBUGF("Failed opening root dir\n"); | ||
100 | pdir->busy = false; | ||
101 | return NULL; | ||
102 | } | ||
103 | |||
104 | for ( part = strtok_r(namecopy, "/", &end); part; | ||
105 | part = strtok_r(NULL, "/", &end)) { | ||
106 | /* scan dir for name */ | ||
107 | while (1) { | ||
108 | if ((fat_getnext(&pdir->fatdir,&entry) < 0) || | ||
109 | (!entry.name[0])) { | ||
110 | pdir->busy = false; | ||
111 | return NULL; | ||
112 | } | ||
113 | if ( (entry.attr & FAT_ATTR_DIRECTORY) && | ||
114 | (!strcasecmp(part, entry.name)) ) { | ||
115 | /* In reality, the parent_dir parameter of fat_opendir seems | ||
116 | * useless because it's sole purpose it to have a way to | ||
117 | * update the file metadata, but here we are only reading | ||
118 | * a directory so there's no need for that kind of stuff. | ||
119 | * However, the rmdir_uncached function uses a ugly hack to | ||
120 | * avoid opening a directory twice when deleting it and thus | ||
121 | * needs those information. That's why we pass pdir->fatdir both | ||
122 | * as the parent directory and the resulting one (this is safe, | ||
123 | * in doubt, check fat_open(dir) code) which will allow this kind of | ||
124 | * (ugly) things */ | ||
125 | if ( fat_opendir(IF_MV(volume,) | ||
126 | &pdir->fatdir, | ||
127 | entry.firstcluster, | ||
128 | &pdir->fatdir) < 0 ) { | ||
129 | DEBUGF("Failed opening dir '%s' (%ld)\n", | ||
130 | part, entry.firstcluster); | ||
131 | pdir->busy = false; | ||
132 | return NULL; | ||
133 | } | ||
134 | #ifdef HAVE_MULTIVOLUME | ||
135 | pdir->volumecounter = -1; /* n.a. to subdirs */ | ||
136 | #endif | ||
137 | break; | ||
138 | } | ||
139 | } | ||
140 | } | ||
141 | |||
142 | return pdir; | ||
143 | } | ||
144 | |||
145 | int closedir_uncached(DIR_UNCACHED* dir) | ||
146 | { | ||
147 | dir->busy=false; | ||
148 | return 0; | ||
149 | } | ||
150 | |||
151 | struct dirent_uncached* readdir_uncached(DIR_UNCACHED* dir) | ||
152 | { | ||
153 | struct fat_direntry entry; | ||
154 | struct dirent_uncached* theent = &(dir->theent); | ||
155 | |||
156 | if (!dir->busy) | ||
157 | return NULL; | ||
158 | |||
159 | #ifdef HAVE_MULTIVOLUME | ||
160 | /* Volumes (secondary file systems) get inserted into the root directory | ||
161 | of the first volume, since we have no separate top level. */ | ||
162 | if (dir->volumecounter >= 0 /* on a root dir */ | ||
163 | && dir->volumecounter < NUM_VOLUMES /* in range */ | ||
164 | && dir->fatdir.file.volume == 0) /* at volume 0 */ | ||
165 | { /* fake special directories, which don't really exist, but | ||
166 | will get redirected upon opendir_uncached() */ | ||
167 | while (++dir->volumecounter < NUM_VOLUMES) | ||
168 | { | ||
169 | if (fat_ismounted(dir->volumecounter)) | ||
170 | { | ||
171 | memset(theent, 0, sizeof(*theent)); | ||
172 | theent->info.attribute = FAT_ATTR_DIRECTORY | FAT_ATTR_VOLUME; | ||
173 | snprintf(theent->d_name, sizeof(theent->d_name), | ||
174 | VOL_NAMES, dir->volumecounter); | ||
175 | return theent; | ||
176 | } | ||
177 | } | ||
178 | } | ||
179 | #endif | ||
180 | /* normal directory entry fetching follows here */ | ||
181 | if (fat_getnext(&(dir->fatdir),&entry) < 0) | ||
182 | return NULL; | ||
183 | |||
184 | if ( !entry.name[0] ) | ||
185 | return NULL; | ||
186 | |||
187 | strlcpy(theent->d_name, entry.name, sizeof(theent->d_name)); | ||
188 | theent->info.attribute = entry.attr; | ||
189 | theent->info.wrtdate = entry.wrtdate; | ||
190 | theent->info.wrttime = entry.wrttime; | ||
191 | theent->info.size = entry.filesize; | ||
192 | theent->startcluster = entry.firstcluster; | ||
193 | |||
194 | return theent; | ||
195 | } | ||
196 | |||
197 | int mkdir_uncached(const char *name) | ||
198 | { | ||
199 | DIR_UNCACHED *dir; | ||
200 | char namecopy[MAX_PATH]; | ||
201 | char* end; | ||
202 | char *basename; | ||
203 | char *parent; | ||
204 | struct dirent_uncached *entry; | ||
205 | int dd; | ||
206 | DIR_UNCACHED* pdir = opendirs; | ||
207 | struct fat_dir *newdir; | ||
208 | int rc; | ||
209 | |||
210 | if ( name[0] != '/' ) { | ||
211 | DEBUGF("mkdir: Only absolute paths supported right now\n"); | ||
212 | return -1; | ||
213 | } | ||
214 | /* find a free dir descriptor */ | ||
215 | for ( dd=0; dd<MAX_OPEN_DIRS; dd++, pdir++) | ||
216 | if ( !pdir->busy ) | ||
217 | break; | ||
218 | |||
219 | if ( dd == MAX_OPEN_DIRS ) { | ||
220 | DEBUGF("Too many dirs open\n"); | ||
221 | errno = EMFILE; | ||
222 | return -5; | ||
223 | } | ||
224 | |||
225 | pdir->busy = true; | ||
226 | newdir = &pdir->fatdir; | ||
227 | |||
228 | strlcpy(namecopy, name, sizeof(namecopy)); | ||
229 | |||
230 | /* Split the base name and the path */ | ||
231 | end = strrchr(namecopy, '/'); | ||
232 | *end = 0; | ||
233 | basename = end+1; | ||
234 | |||
235 | if(namecopy == end) /* Root dir? */ | ||
236 | parent = "/"; | ||
237 | else | ||
238 | parent = namecopy; | ||
239 | |||
240 | DEBUGF("mkdir: parent: %s, name: %s\n", parent, basename); | ||
241 | |||
242 | dir = opendir_uncached(parent); | ||
243 | |||
244 | if(!dir) { | ||
245 | DEBUGF("mkdir: can't open parent dir\n"); | ||
246 | pdir->busy = false; | ||
247 | return -2; | ||
248 | } | ||
249 | |||
250 | if(basename[0] == 0) { | ||
251 | DEBUGF("mkdir: Empty dir name\n"); | ||
252 | pdir->busy = false; | ||
253 | errno = EINVAL; | ||
254 | return -3; | ||
255 | } | ||
256 | |||
257 | /* Now check if the name already exists */ | ||
258 | while ((entry = readdir_uncached(dir))) { | ||
259 | if ( !strcasecmp(basename, entry->d_name) ) { | ||
260 | DEBUGF("mkdir error: file exists\n"); | ||
261 | errno = EEXIST; | ||
262 | closedir_uncached(dir); | ||
263 | pdir->busy = false; | ||
264 | return - 4; | ||
265 | } | ||
266 | } | ||
267 | |||
268 | memset(newdir, 0, sizeof(struct fat_dir)); | ||
269 | |||
270 | rc = fat_create_dir(basename, newdir, &(dir->fatdir)); | ||
271 | closedir_uncached(dir); | ||
272 | pdir->busy = false; | ||
273 | |||
274 | return rc; | ||
275 | } | ||
276 | |||
277 | int rmdir_uncached(const char* name) | ||
278 | { | ||
279 | int rc; | ||
280 | DIR_UNCACHED* dir; | ||
281 | struct dirent_uncached* entry; | ||
282 | |||
283 | dir = opendir_uncached(name); | ||
284 | if (!dir) | ||
285 | { | ||
286 | errno = ENOENT; /* open error */ | ||
287 | return -1; | ||
288 | } | ||
289 | |||
290 | /* check if the directory is empty */ | ||
291 | while ((entry = readdir_uncached(dir))) | ||
292 | { | ||
293 | if (strcmp(entry->d_name, ".") && | ||
294 | strcmp(entry->d_name, "..")) | ||
295 | { | ||
296 | DEBUGF("rmdir error: not empty\n"); | ||
297 | errno = ENOTEMPTY; | ||
298 | closedir_uncached(dir); | ||
299 | return -2; | ||
300 | } | ||
301 | } | ||
302 | |||
303 | rc = fat_remove(&(dir->fatdir.file)); | ||
304 | if ( rc < 0 ) { | ||
305 | DEBUGF("Failed removing dir: %d\n", rc); | ||
306 | errno = EIO; | ||
307 | rc = rc * 10 - 3; | ||
308 | } | ||
309 | |||
310 | closedir_uncached(dir); | ||
311 | return rc; | ||
312 | } | ||