1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
8 * $Id: dir.c 13741 2007-06-30 02:08:27Z jethead71 $
10 * Copyright (C) 2002 by Björn Stenberg
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.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
29 #include "filefuncs.h"
32 #define MAX_OPEN_DIRS 12
34 #define MAX_OPEN_DIRS 8
37 static DIR_UNCACHED opendirs
[MAX_OPEN_DIRS
];
39 // release all dir handles on a given volume "by force", to avoid leaks
40 int release_dirs(int volume
)
42 DIR_UNCACHED
* pdir
= opendirs
;
45 for ( dd
=0; dd
<MAX_OPEN_DIRS
; dd
++, pdir
++)
47 #ifdef HAVE_MULTIVOLUME
48 if (pdir
->fatdir
.file
.volume
== volume
)
53 pdir
->busy
= false; /* mark as available, no further action */
57 return closed
; /* return how many we did */
60 DIR_UNCACHED
* opendir_uncached(const char* name
)
62 char namecopy
[MAX_PATH
];
65 struct fat_direntry entry
;
67 DIR_UNCACHED
* pdir
= opendirs
;
68 #ifdef HAVE_MULTIVOLUME
72 if ( name
[0] != '/' ) {
73 DEBUGF("Only absolute paths supported right now\n");
77 /* find a free dir descriptor */
78 for ( dd
=0; dd
<MAX_OPEN_DIRS
; dd
++, pdir
++)
82 if ( dd
== MAX_OPEN_DIRS
) {
83 DEBUGF("Too many dirs open\n");
90 #ifdef HAVE_MULTIVOLUME
91 /* try to extract a heading volume name, if present */
92 volume
= strip_volume(name
, namecopy
);
93 pdir
->volumecounter
= 0;
95 strlcpy(namecopy
, name
, sizeof(namecopy
)); /* just copy */
98 if ( fat_opendir(IF_MV2(volume
,) &pdir
->fatdir
, 0, NULL
) < 0 ) {
99 DEBUGF("Failed opening root dir\n");
104 for ( part
= strtok_r(namecopy
, "/", &end
); part
;
105 part
= strtok_r(NULL
, "/", &end
)) {
106 /* scan dir for name */
108 if ((fat_getnext(&pdir
->fatdir
,&entry
) < 0) ||
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
125 if ( fat_opendir(IF_MV2(volume
,)
128 &pdir
->fatdir
) < 0 ) {
129 DEBUGF("Failed opening dir '%s' (%ld)\n",
130 part
, entry
.firstcluster
);
134 #ifdef HAVE_MULTIVOLUME
135 pdir
->volumecounter
= -1; /* n.a. to subdirs */
145 int closedir_uncached(DIR_UNCACHED
* dir
)
151 struct dirent_uncached
* readdir_uncached(DIR_UNCACHED
* dir
)
153 struct fat_direntry entry
;
154 struct dirent_uncached
* theent
= &(dir
->theent
);
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
)
169 if (fat_ismounted(dir
->volumecounter
))
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
);
180 /* normal directory entry fetching follows here */
181 if (fat_getnext(&(dir
->fatdir
),&entry
) < 0)
184 if ( !entry
.name
[0] )
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
;
197 int mkdir_uncached(const char *name
)
200 char namecopy
[MAX_PATH
];
204 struct dirent_uncached
*entry
;
206 DIR_UNCACHED
* pdir
= opendirs
;
207 struct fat_dir
*newdir
;
210 if ( name
[0] != '/' ) {
211 DEBUGF("mkdir: Only absolute paths supported right now\n");
214 /* find a free dir descriptor */
215 for ( dd
=0; dd
<MAX_OPEN_DIRS
; dd
++, pdir
++)
219 if ( dd
== MAX_OPEN_DIRS
) {
220 DEBUGF("Too many dirs open\n");
226 newdir
= &pdir
->fatdir
;
228 strlcpy(namecopy
, name
, sizeof(namecopy
));
230 /* Split the base name and the path */
231 end
= strrchr(namecopy
, '/');
235 if(namecopy
== end
) /* Root dir? */
240 DEBUGF("mkdir: parent: %s, name: %s\n", parent
, basename
);
242 dir
= opendir_uncached(parent
);
245 DEBUGF("mkdir: can't open parent dir\n");
250 if(basename
[0] == 0) {
251 DEBUGF("mkdir: Empty dir name\n");
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");
262 closedir_uncached(dir
);
268 memset(newdir
, 0, sizeof(struct fat_dir
));
270 rc
= fat_create_dir(basename
, newdir
, &(dir
->fatdir
));
271 closedir_uncached(dir
);
277 int rmdir_uncached(const char* name
)
281 struct dirent_uncached
* entry
;
283 dir
= opendir_uncached(name
);
286 errno
= ENOENT
; /* open error */
290 /* check if the directory is empty */
291 while ((entry
= readdir_uncached(dir
)))
293 if (strcmp(entry
->d_name
, ".") &&
294 strcmp(entry
->d_name
, ".."))
296 DEBUGF("rmdir error: not empty\n");
298 closedir_uncached(dir
);
303 rc
= fat_remove(&(dir
->fatdir
.file
));
305 DEBUGF("Failed removing dir: %d\n", rc
);
310 closedir_uncached(dir
);