Index: embios/trunk/global.h |
— | — | @@ -28,7 +28,9 @@ |
29 | 29 | #include <stdint.h>
|
30 | 30 | #include <stddef.h>
|
31 | 31 | #include <stdbool.h>
|
32 | | -#include <stdio.h>
|
| 32 | +typedef int32_t ssize_t;
|
| 33 | +typedef int32_t mode_t;
|
| 34 | +typedef int32_t off_t;
|
33 | 35 | #endif
|
34 | 36 |
|
35 | 37 | #include "build/version.h"
|
Index: embios/trunk/fat.c |
— | — | @@ -20,13 +20,12 @@ |
21 | 21 | ****************************************************************************/ |
22 | 22 | #include "global.h" |
23 | 23 | #include "thread.h" |
24 | | -#include <stdio.h> |
25 | 24 | #include <string.h> |
26 | | -#include <ctype.h> |
27 | 25 | #include "fat.h" |
28 | 26 | #include "storage.h" |
29 | 27 | #include "debug.h" |
30 | 28 | #include "panic.h" |
| 29 | +#include "snprintf.h" |
31 | 30 | |
32 | 31 | #define BYTES2INT16(array,pos) \ |
33 | 32 | (array[pos] | (array[pos+1] << 8 )) |
Index: embios/trunk/dir.c |
— | — | @@ -1,337 +1,336 @@ |
2 | | -/*************************************************************************** |
3 | | - * __________ __ ___. |
4 | | - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ |
5 | | - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / |
6 | | - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < |
7 | | - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ |
8 | | - * \/ \/ \/ \/ \/ |
9 | | - * $Id: dir.c 13741 2007-06-30 02:08:27Z jethead71 $ |
10 | | - * |
11 | | - * Copyright (C) 2002 by Björn Stenberg |
12 | | - * |
13 | | - * This program is free software; you can redistribute it and/or |
14 | | - * modify it under the terms of the GNU General Public License |
15 | | - * as published by the Free Software Foundation; either version 2 |
16 | | - * of the License, or (at your option) any later version. |
17 | | - * |
18 | | - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY |
19 | | - * KIND, either express or implied. |
20 | | - * |
21 | | - ****************************************************************************/ |
22 | | -#include "global.h" |
23 | | -#include <stdio.h> |
24 | | -#include <errno.h> |
25 | | -#include <string.h> |
26 | | -#include "fat.h" |
27 | | -#include "dir.h" |
28 | | -#include "debug.h" |
29 | | - |
30 | | -#ifndef MAX_OPEN_DIRS |
31 | | -#define MAX_OPEN_DIRS 16 |
32 | | -#endif |
33 | | - |
| 2 | +/***************************************************************************
|
| 3 | + * __________ __ ___.
|
| 4 | + * Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
| 5 | + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
| 6 | + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
| 7 | + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
| 8 | + * \/ \/ \/ \/ \/
|
| 9 | + * $Id: dir.c 13741 2007-06-30 02:08:27Z jethead71 $
|
| 10 | + *
|
| 11 | + * Copyright (C) 2002 by Björn Stenberg
|
| 12 | + *
|
| 13 | + * This program is free software; you can redistribute it and/or
|
| 14 | + * modify it under the terms of the GNU General Public License
|
| 15 | + * as published by the Free Software Foundation; either version 2
|
| 16 | + * of the License, or (at your option) any later version.
|
| 17 | + *
|
| 18 | + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
| 19 | + * KIND, either express or implied.
|
| 20 | + *
|
| 21 | + ****************************************************************************/
|
| 22 | +#include "global.h"
|
| 23 | +#include <errno.h>
|
| 24 | +#include <string.h>
|
| 25 | +#include "fat.h"
|
| 26 | +#include "dir.h"
|
| 27 | +#include "debug.h"
|
| 28 | +
|
| 29 | +#ifndef MAX_OPEN_DIRS
|
| 30 | +#define MAX_OPEN_DIRS 16
|
| 31 | +#endif
|
| 32 | +
|
34 | 33 | extern struct scheduler_thread* current_thread;
|
35 | | -static DIR opendirs[MAX_OPEN_DIRS]; |
36 | | - |
37 | | -#ifdef HAVE_HOTSWAP |
38 | | -// release all dir handles on a given volume "by force", to avoid leaks |
39 | | -int release_dirs(int volume) |
40 | | -{ |
41 | | - DIR* pdir = opendirs; |
42 | | - int dd; |
43 | | - int closed = 0; |
44 | | - for ( dd=0; dd<MAX_OPEN_DIRS; dd++, pdir++) |
45 | | - { |
46 | | -#ifdef HAVE_MULTIVOLUME |
47 | | - if (pdir->fatdir.file.volume == volume) |
48 | | -#else |
49 | | - (void)volume; |
50 | | -#endif |
51 | | - { |
52 | | - pdir->busy = false; /* mark as available, no further action */ |
53 | | - closed++; |
54 | | - } |
55 | | - } |
56 | | - return closed; /* return how many we did */ |
57 | | -} |
58 | | -#endif /* #ifdef HAVE_HOTSWAP */ |
59 | | - |
60 | | -DIR* opendir(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* pdir = opendirs; |
68 | | -#ifdef HAVE_MULTIVOLUME |
69 | | - int volume; |
70 | | -#endif |
71 | | - |
72 | | - if ( name[0] != '/' ) { |
73 | | - DEBUGF("Only absolute paths supported right now"); |
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"); |
84 | | - errno = EMFILE; |
85 | | - return NULL; |
86 | | - } |
87 | | - |
88 | | - pdir->busy = true; |
89 | | - pdir->process = current_thread; |
90 | | - |
91 | | -#ifdef HAVE_MULTIVOLUME |
92 | | - /* try to extract a heading volume name, if present */ |
93 | | - volume = strip_volume(name, namecopy); |
94 | | - pdir->volumecounter = 0; |
95 | | -#else |
96 | | - strlcpy(namecopy, name, sizeof(namecopy)); /* just copy */ |
97 | | -#endif |
98 | | - |
99 | | - if ( fat_opendir(IF_MV2(volume,) &pdir->fatdir, 0, NULL) < 0 ) { |
100 | | - DEBUGF("Failed opening root dir"); |
101 | | - pdir->busy = false; |
102 | | - return NULL; |
103 | | - } |
104 | | - |
105 | | - for ( part = strtok_r(namecopy, "/", &end); part; |
106 | | - part = strtok_r(NULL, "/", &end)) { |
107 | | - /* scan dir for name */ |
108 | | - while (1) { |
109 | | - if ((fat_getnext(&pdir->fatdir,&entry) < 0) || |
110 | | - (!entry.name[0])) { |
111 | | - pdir->busy = false; |
112 | | - return NULL; |
113 | | - } |
114 | | - if ( (entry.attr & FAT_ATTR_DIRECTORY) && |
115 | | - (!strcasecmp(part, entry.name)) ) { |
116 | | - /* In reality, the parent_dir parameter of fat_opendir seems |
117 | | - * useless because it's sole purpose it to have a way to |
118 | | - * update the file metadata, but here we are only reading |
119 | | - * a directory so there's no need for that kind of stuff. |
120 | | - * However, the rmdir function uses a ugly hack to |
121 | | - * avoid opening a directory twice when deleting it and thus |
122 | | - * needs those information. That's why we pass pdir->fatdir both |
123 | | - * as the parent directory and the resulting one (this is safe, |
124 | | - * in doubt, check fat_open(dir) code) which will allow this kind of |
125 | | - * (ugly) things */ |
126 | | - if ( fat_opendir(IF_MV2(volume,) |
127 | | - &pdir->fatdir, |
128 | | - entry.firstcluster, |
129 | | - &pdir->fatdir) < 0 ) { |
130 | | - DEBUGF("Failed opening dir '%s' (%ld)", |
131 | | - part, entry.firstcluster); |
132 | | - pdir->busy = false; |
133 | | - return NULL; |
134 | | - } |
135 | | -#ifdef HAVE_MULTIVOLUME |
136 | | - pdir->volumecounter = -1; /* n.a. to subdirs */ |
137 | | -#endif |
138 | | - break; |
139 | | - } |
140 | | - } |
141 | | - } |
142 | | - |
143 | | - return pdir; |
144 | | -} |
145 | | - |
146 | | -int closedir(DIR* dir) |
147 | | -{ |
148 | | - dir->busy=false; |
149 | | - return 0; |
150 | | -} |
151 | | - |
152 | | -int closedir_all_of_process(struct scheduler_thread* process) |
153 | | -{ |
154 | | - DIR* pdir = opendirs; |
155 | | - int dd; |
156 | | - int closed = 0; |
157 | | - for ( dd=0; dd<MAX_OPEN_DIRS; dd++, pdir++) |
158 | | - { |
159 | | - if (pdir->process == process) |
160 | | - { |
161 | | - pdir->busy = false; /* mark as available, no further action */ |
162 | | - closed++; |
163 | | - } |
164 | | - } |
165 | | - return closed; /* return how many we did */ |
166 | | -} |
167 | | - |
168 | | -struct dirent* readdir(DIR* dir) |
169 | | -{ |
170 | | - struct fat_direntry entry; |
171 | | - struct dirent* theent = &(dir->theent); |
172 | | - |
173 | | - if (!dir->busy) |
174 | | - return NULL; |
175 | | - |
176 | | -#ifdef HAVE_MULTIVOLUME |
177 | | - /* Volumes (secondary file systems) get inserted into the root directory |
178 | | - of the first volume, since we have no separate top level. */ |
179 | | - if (dir->volumecounter >= 0 /* on a root dir */ |
180 | | - && dir->volumecounter < NUM_VOLUMES /* in range */ |
181 | | - && dir->fatdir.file.volume == 0) /* at volume 0 */ |
182 | | - { /* fake special directories, which don't really exist, but |
183 | | - will get redirected upon opendir() */ |
184 | | - while (++dir->volumecounter < NUM_VOLUMES) |
185 | | - { |
186 | | - if (fat_ismounted(dir->volumecounter)) |
187 | | - { |
188 | | - memset(theent, 0, sizeof(*theent)); |
189 | | - theent->attribute = FAT_ATTR_DIRECTORY | FAT_ATTR_VOLUME; |
190 | | - snprintf(theent->d_name, sizeof(theent->d_name), |
191 | | - VOL_NAMES, dir->volumecounter); |
192 | | - return theent; |
193 | | - } |
194 | | - } |
195 | | - } |
196 | | -#endif |
197 | | - /* normal directory entry fetching follows here */ |
198 | | - if (fat_getnext(&(dir->fatdir),&entry) < 0) |
199 | | - return NULL; |
200 | | - |
201 | | - if ( !entry.name[0] ) |
202 | | - return NULL; |
203 | | - |
204 | | - strlcpy(theent->d_name, entry.name, sizeof(theent->d_name)); |
205 | | - theent->attribute = entry.attr; |
206 | | - theent->size = entry.filesize; |
207 | | - theent->startcluster = entry.firstcluster; |
208 | | - theent->wrtdate = entry.wrtdate; |
209 | | - theent->wrttime = entry.wrttime; |
210 | | - |
211 | | - return theent; |
212 | | -} |
213 | | - |
214 | | -int mkdir(const char *name) |
215 | | -{ |
216 | | - DIR *dir; |
217 | | - char namecopy[MAX_PATH]; |
218 | | - char* end; |
219 | | - char *basename; |
220 | | - char *parent; |
221 | | - struct dirent *entry; |
222 | | - struct fat_dir newdir; |
223 | | - int rc; |
224 | | - |
225 | | - if ( name[0] != '/' ) { |
226 | | - DEBUGF("mkdir: Only absolute paths supported right now"); |
227 | | - return -1; |
228 | | - } |
229 | | - |
230 | | - strlcpy(namecopy, name, sizeof(namecopy)); |
231 | | - |
232 | | - /* Split the base name and the path */ |
233 | | - end = strrchr(namecopy, '/'); |
234 | | - *end = 0; |
235 | | - basename = end+1; |
236 | | - |
237 | | - if(namecopy == end) /* Root dir? */ |
238 | | - parent = "/"; |
239 | | - else |
240 | | - parent = namecopy; |
241 | | - |
242 | | - DEBUGF("mkdir: parent: %s, name: %s", parent, basename); |
243 | | - |
244 | | - dir = opendir(parent); |
245 | | - |
246 | | - if(!dir) { |
247 | | - DEBUGF("mkdir: can't open parent dir"); |
248 | | - return -2; |
249 | | - } |
250 | | - |
251 | | - if(basename[0] == 0) { |
252 | | - DEBUGF("mkdir: Empty dir name"); |
253 | | - errno = EINVAL; |
254 | | - return -3; |
255 | | - } |
256 | | - |
257 | | - /* Now check if the name already exists */ |
258 | | - while ((entry = readdir(dir))) { |
259 | | - if ( !strcasecmp(basename, entry->d_name) ) { |
260 | | - DEBUGF("mkdir error: file exists"); |
261 | | - errno = EEXIST; |
262 | | - closedir(dir); |
263 | | - return - 4; |
264 | | - } |
265 | | - } |
266 | | - |
267 | | - memset(&newdir, 0, sizeof(struct fat_dir)); |
268 | | - |
269 | | - rc = fat_create_dir(basename, &newdir, &(dir->fatdir)); |
270 | | - closedir(dir); |
271 | | - |
272 | | - return rc; |
273 | | -} |
274 | | - |
275 | | -int rmdir(const char* name) |
276 | | -{ |
277 | | - int rc; |
278 | | - DIR* dir; |
279 | | - struct dirent* entry; |
280 | | - |
281 | | - dir = opendir(name); |
282 | | - if (!dir) |
283 | | - { |
284 | | - errno = ENOENT; /* open error */ |
285 | | - return -1; |
286 | | - } |
287 | | - |
288 | | - /* check if the directory is empty */ |
289 | | - while ((entry = readdir(dir))) |
290 | | - { |
291 | | - if (strcmp(entry->d_name, ".") && |
292 | | - strcmp(entry->d_name, "..")) |
293 | | - { |
294 | | - DEBUGF("rmdir error: not empty"); |
295 | | - errno = ENOTEMPTY; |
296 | | - closedir(dir); |
297 | | - return -2; |
298 | | - } |
299 | | - } |
300 | | - |
301 | | - rc = fat_remove(&(dir->fatdir.file)); |
302 | | - if ( rc < 0 ) { |
303 | | - DEBUGF("Failed removing dir: %d", rc); |
304 | | - errno = EIO; |
305 | | - rc = rc * 10 - 3; |
306 | | - } |
307 | | - |
308 | | - closedir(dir); |
309 | | - return rc; |
310 | | -} |
311 | | - |
312 | | -#ifdef HAVE_MULTIVOLUME |
313 | | -/* returns on which volume this is, and copies the reduced name |
314 | | - (sortof a preprocessor for volume-decorated pathnames) */ |
315 | | -int strip_volume(const char* name, char* namecopy) |
316 | | -{ |
317 | | - int volume = 0; |
318 | | - const char *temp = name; |
319 | | - |
320 | | - while (*temp == '/') /* skip all leading slashes */ |
321 | | - ++temp; |
322 | | - |
323 | | - if (*temp && !strncmp(temp, VOL_NAMES, VOL_ENUM_POS)) |
324 | | - { |
325 | | - temp += VOL_ENUM_POS; /* behind special name */ |
326 | | - volume = atoi(temp); /* number is following */ |
327 | | - temp = strchr(temp, '/'); /* search for slash behind */ |
328 | | - if (temp != NULL) |
329 | | - name = temp; /* use the part behind the volume */ |
330 | | - else |
331 | | - name = "/"; /* else this must be the root dir */ |
332 | | - } |
333 | | - |
334 | | - strlcpy(namecopy, name, MAX_PATH); |
335 | | - |
336 | | - return volume; |
337 | | -} |
338 | | -#endif /* #ifdef HAVE_MULTIVOLUME */ |
| 34 | +static DIR opendirs[MAX_OPEN_DIRS];
|
| 35 | +
|
| 36 | +#ifdef HAVE_HOTSWAP
|
| 37 | +// release all dir handles on a given volume "by force", to avoid leaks
|
| 38 | +int release_dirs(int volume)
|
| 39 | +{
|
| 40 | + DIR* pdir = opendirs;
|
| 41 | + int dd;
|
| 42 | + int closed = 0;
|
| 43 | + for ( dd=0; dd<MAX_OPEN_DIRS; dd++, pdir++)
|
| 44 | + {
|
| 45 | +#ifdef HAVE_MULTIVOLUME
|
| 46 | + if (pdir->fatdir.file.volume == volume)
|
| 47 | +#else
|
| 48 | + (void)volume;
|
| 49 | +#endif
|
| 50 | + {
|
| 51 | + pdir->busy = false; /* mark as available, no further action */
|
| 52 | + closed++;
|
| 53 | + }
|
| 54 | + }
|
| 55 | + return closed; /* return how many we did */
|
| 56 | +}
|
| 57 | +#endif /* #ifdef HAVE_HOTSWAP */
|
| 58 | +
|
| 59 | +DIR* opendir(const char* name)
|
| 60 | +{
|
| 61 | + char namecopy[MAX_PATH];
|
| 62 | + char* part;
|
| 63 | + char* end;
|
| 64 | + struct fat_direntry entry;
|
| 65 | + int dd;
|
| 66 | + DIR* pdir = opendirs;
|
| 67 | +#ifdef HAVE_MULTIVOLUME
|
| 68 | + int volume;
|
| 69 | +#endif
|
| 70 | +
|
| 71 | + if ( name[0] != '/' ) {
|
| 72 | + DEBUGF("Only absolute paths supported right now");
|
| 73 | + return NULL;
|
| 74 | + }
|
| 75 | +
|
| 76 | + /* find a free dir descriptor */
|
| 77 | + for ( dd=0; dd<MAX_OPEN_DIRS; dd++, pdir++)
|
| 78 | + if ( !pdir->busy )
|
| 79 | + break;
|
| 80 | +
|
| 81 | + if ( dd == MAX_OPEN_DIRS ) {
|
| 82 | + DEBUGF("Too many dirs open");
|
| 83 | + errno = EMFILE;
|
| 84 | + return NULL;
|
| 85 | + }
|
| 86 | +
|
| 87 | + pdir->busy = true;
|
| 88 | + pdir->process = current_thread;
|
| 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_MV2(volume,) &pdir->fatdir, 0, NULL) < 0 ) {
|
| 99 | + DEBUGF("Failed opening root dir");
|
| 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 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_MV2(volume,)
|
| 126 | + &pdir->fatdir,
|
| 127 | + entry.firstcluster,
|
| 128 | + &pdir->fatdir) < 0 ) {
|
| 129 | + DEBUGF("Failed opening dir '%s' (%ld)",
|
| 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(DIR* dir)
|
| 146 | +{
|
| 147 | + dir->busy=false;
|
| 148 | + return 0;
|
| 149 | +}
|
| 150 | +
|
| 151 | +int closedir_all_of_process(struct scheduler_thread* process)
|
| 152 | +{
|
| 153 | + DIR* pdir = opendirs;
|
| 154 | + int dd;
|
| 155 | + int closed = 0;
|
| 156 | + for ( dd=0; dd<MAX_OPEN_DIRS; dd++, pdir++)
|
| 157 | + {
|
| 158 | + if (pdir->process == process)
|
| 159 | + {
|
| 160 | + pdir->busy = false; /* mark as available, no further action */
|
| 161 | + closed++;
|
| 162 | + }
|
| 163 | + }
|
| 164 | + return closed; /* return how many we did */
|
| 165 | +}
|
| 166 | +
|
| 167 | +struct dirent* readdir(DIR* dir)
|
| 168 | +{
|
| 169 | + struct fat_direntry entry;
|
| 170 | + struct dirent* theent = &(dir->theent);
|
| 171 | +
|
| 172 | + if (!dir->busy)
|
| 173 | + return NULL;
|
| 174 | +
|
| 175 | +#ifdef HAVE_MULTIVOLUME
|
| 176 | + /* Volumes (secondary file systems) get inserted into the root directory
|
| 177 | + of the first volume, since we have no separate top level. */
|
| 178 | + if (dir->volumecounter >= 0 /* on a root dir */
|
| 179 | + && dir->volumecounter < NUM_VOLUMES /* in range */
|
| 180 | + && dir->fatdir.file.volume == 0) /* at volume 0 */
|
| 181 | + { /* fake special directories, which don't really exist, but
|
| 182 | + will get redirected upon opendir() */
|
| 183 | + while (++dir->volumecounter < NUM_VOLUMES)
|
| 184 | + {
|
| 185 | + if (fat_ismounted(dir->volumecounter))
|
| 186 | + {
|
| 187 | + memset(theent, 0, sizeof(*theent));
|
| 188 | + theent->attribute = FAT_ATTR_DIRECTORY | FAT_ATTR_VOLUME;
|
| 189 | + snprintf(theent->d_name, sizeof(theent->d_name),
|
| 190 | + VOL_NAMES, dir->volumecounter);
|
| 191 | + return theent;
|
| 192 | + }
|
| 193 | + }
|
| 194 | + }
|
| 195 | +#endif
|
| 196 | + /* normal directory entry fetching follows here */
|
| 197 | + if (fat_getnext(&(dir->fatdir),&entry) < 0)
|
| 198 | + return NULL;
|
| 199 | +
|
| 200 | + if ( !entry.name[0] )
|
| 201 | + return NULL;
|
| 202 | +
|
| 203 | + strlcpy(theent->d_name, entry.name, sizeof(theent->d_name));
|
| 204 | + theent->attribute = entry.attr;
|
| 205 | + theent->size = entry.filesize;
|
| 206 | + theent->startcluster = entry.firstcluster;
|
| 207 | + theent->wrtdate = entry.wrtdate;
|
| 208 | + theent->wrttime = entry.wrttime;
|
| 209 | +
|
| 210 | + return theent;
|
| 211 | +}
|
| 212 | +
|
| 213 | +int mkdir(const char *name)
|
| 214 | +{
|
| 215 | + DIR *dir;
|
| 216 | + char namecopy[MAX_PATH];
|
| 217 | + char* end;
|
| 218 | + char *basename;
|
| 219 | + char *parent;
|
| 220 | + struct dirent *entry;
|
| 221 | + struct fat_dir newdir;
|
| 222 | + int rc;
|
| 223 | +
|
| 224 | + if ( name[0] != '/' ) {
|
| 225 | + DEBUGF("mkdir: Only absolute paths supported right now");
|
| 226 | + return -1;
|
| 227 | + }
|
| 228 | +
|
| 229 | + strlcpy(namecopy, name, sizeof(namecopy));
|
| 230 | +
|
| 231 | + /* Split the base name and the path */
|
| 232 | + end = strrchr(namecopy, '/');
|
| 233 | + *end = 0;
|
| 234 | + basename = end+1;
|
| 235 | +
|
| 236 | + if(namecopy == end) /* Root dir? */
|
| 237 | + parent = "/";
|
| 238 | + else
|
| 239 | + parent = namecopy;
|
| 240 | +
|
| 241 | + DEBUGF("mkdir: parent: %s, name: %s", parent, basename);
|
| 242 | +
|
| 243 | + dir = opendir(parent);
|
| 244 | +
|
| 245 | + if(!dir) {
|
| 246 | + DEBUGF("mkdir: can't open parent dir");
|
| 247 | + return -2;
|
| 248 | + }
|
| 249 | +
|
| 250 | + if(basename[0] == 0) {
|
| 251 | + DEBUGF("mkdir: Empty dir name");
|
| 252 | + errno = EINVAL;
|
| 253 | + return -3;
|
| 254 | + }
|
| 255 | +
|
| 256 | + /* Now check if the name already exists */
|
| 257 | + while ((entry = readdir(dir))) {
|
| 258 | + if ( !strcasecmp(basename, entry->d_name) ) {
|
| 259 | + DEBUGF("mkdir error: file exists");
|
| 260 | + errno = EEXIST;
|
| 261 | + closedir(dir);
|
| 262 | + return - 4;
|
| 263 | + }
|
| 264 | + }
|
| 265 | +
|
| 266 | + memset(&newdir, 0, sizeof(struct fat_dir));
|
| 267 | +
|
| 268 | + rc = fat_create_dir(basename, &newdir, &(dir->fatdir));
|
| 269 | + closedir(dir);
|
| 270 | +
|
| 271 | + return rc;
|
| 272 | +}
|
| 273 | +
|
| 274 | +int rmdir(const char* name)
|
| 275 | +{
|
| 276 | + int rc;
|
| 277 | + DIR* dir;
|
| 278 | + struct dirent* entry;
|
| 279 | +
|
| 280 | + dir = opendir(name);
|
| 281 | + if (!dir)
|
| 282 | + {
|
| 283 | + errno = ENOENT; /* open error */
|
| 284 | + return -1;
|
| 285 | + }
|
| 286 | +
|
| 287 | + /* check if the directory is empty */
|
| 288 | + while ((entry = readdir(dir)))
|
| 289 | + {
|
| 290 | + if (strcmp(entry->d_name, ".") &&
|
| 291 | + strcmp(entry->d_name, ".."))
|
| 292 | + {
|
| 293 | + DEBUGF("rmdir error: not empty");
|
| 294 | + errno = ENOTEMPTY;
|
| 295 | + closedir(dir);
|
| 296 | + return -2;
|
| 297 | + }
|
| 298 | + }
|
| 299 | +
|
| 300 | + rc = fat_remove(&(dir->fatdir.file));
|
| 301 | + if ( rc < 0 ) {
|
| 302 | + DEBUGF("Failed removing dir: %d", rc);
|
| 303 | + errno = EIO;
|
| 304 | + rc = rc * 10 - 3;
|
| 305 | + }
|
| 306 | +
|
| 307 | + closedir(dir);
|
| 308 | + return rc;
|
| 309 | +}
|
| 310 | +
|
| 311 | +#ifdef HAVE_MULTIVOLUME
|
| 312 | +/* returns on which volume this is, and copies the reduced name
|
| 313 | + (sortof a preprocessor for volume-decorated pathnames) */
|
| 314 | +int strip_volume(const char* name, char* namecopy)
|
| 315 | +{
|
| 316 | + int volume = 0;
|
| 317 | + const char *temp = name;
|
| 318 | +
|
| 319 | + while (*temp == '/') /* skip all leading slashes */
|
| 320 | + ++temp;
|
| 321 | +
|
| 322 | + if (*temp && !strncmp(temp, VOL_NAMES, VOL_ENUM_POS))
|
| 323 | + {
|
| 324 | + temp += VOL_ENUM_POS; /* behind special name */
|
| 325 | + volume = atoi(temp); /* number is following */
|
| 326 | + temp = strchr(temp, '/'); /* search for slash behind */
|
| 327 | + if (temp != NULL)
|
| 328 | + name = temp; /* use the part behind the volume */
|
| 329 | + else
|
| 330 | + name = "/"; /* else this must be the root dir */
|
| 331 | + }
|
| 332 | +
|
| 333 | + strlcpy(namecopy, name, MAX_PATH);
|
| 334 | +
|
| 335 | + return volume;
|
| 336 | +}
|
| 337 | +#endif /* #ifdef HAVE_MULTIVOLUME */
|