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 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
27 //#include "dircache.h"
29 #define MAX_OPEN_DIRS 8
31 static DIR_UNCACHED opendirs
[MAX_OPEN_DIRS
];
33 #ifdef HAVE_MULTIVOLUME
35 /* how to name volumes, first char must be outside of legal file names,
36 a number gets appended to enumerate, if applicable */
38 static const char* vol_names
= "<MMC%d>";
39 #define VOL_ENUM_POS 4 /* position of %d, to avoid runtime calculation */
40 #elif defined(HAVE_HOTSWAP)
41 static const char* vol_names
= "<microSD%d>";
42 #define VOL_ENUM_POS 8 /* position of %d, to avoid runtime calculation */
44 static const char* vol_names
= "<HD%d>";
45 #define VOL_ENUM_POS 3
48 /* returns on which volume this is, and copies the reduced name
49 (sortof a preprocessor for volume-decorated pathnames) */
50 static int strip_volume(const char* name
, char* namecopy
)
53 const char *temp
= name
;
55 while (*temp
== '/') /* skip all leading slashes */
58 if (*temp
&& !strncmp(temp
, vol_names
, VOL_ENUM_POS
))
60 temp
+= VOL_ENUM_POS
; /* behind special name */
61 volume
= atoi(temp
); /* number is following */
62 temp
= strchr(temp
, '/'); /* search for slash behind */
64 name
= temp
; /* use the part behind the volume */
66 name
= "/"; /* else this must be the root dir */
69 strncpy(namecopy
, name
, MAX_PATH
);
70 namecopy
[MAX_PATH
-1] = '\0';
74 #endif /* #ifdef HAVE_MULTIVOLUME */
78 // release all dir handles on a given volume "by force", to avoid leaks
79 int release_dirs(int volume
)
81 DIR_UNCACHED
* pdir
= opendirs
;
84 for ( dd
=0; dd
<MAX_OPEN_DIRS
; dd
++, pdir
++)
86 if (pdir
->fatdir
.file
.volume
== volume
)
88 pdir
->busy
= false; /* mark as available, no further action */
92 return closed
; /* return how many we did */
94 #endif /* #ifdef HAVE_HOTSWAP */
96 DIR_UNCACHED
* opendir_uncached(const char* name
)
98 char namecopy
[MAX_PATH
];
101 struct fat_direntry entry
;
103 DIR_UNCACHED
* pdir
= opendirs
;
104 #ifdef HAVE_MULTIVOLUME
108 if ( name
[0] != '/' ) {
109 DEBUGF("Only absolute paths supported right now\n");
113 /* find a free dir descriptor */
114 for ( dd
=0; dd
<MAX_OPEN_DIRS
; dd
++, pdir
++)
118 if ( dd
== MAX_OPEN_DIRS
) {
119 DEBUGF("Too many dirs open\n");
126 #ifdef HAVE_MULTIVOLUME
127 /* try to extract a heading volume name, if present */
128 volume
= strip_volume(name
, namecopy
);
129 pdir
->volumecounter
= 0;
131 strncpy(namecopy
,name
,sizeof(namecopy
)); /* just copy */
132 namecopy
[sizeof(namecopy
)-1] = '\0';
135 if ( fat_opendir(IF_MV2(volume
,) &pdir
->fatdir
, 0, NULL
) < 0 ) {
136 DEBUGF("Failed opening root dir\n");
141 for ( part
= strtok_r(namecopy
, "/", &end
); part
;
142 part
= strtok_r(NULL
, "/", &end
)) {
143 /* scan dir for name */
145 if ((fat_getnext(&pdir
->fatdir
,&entry
) < 0) ||
150 if ( (entry
.attr
& FAT_ATTR_DIRECTORY
) &&
151 (!strcasecmp(part
, entry
.name
)) ) {
152 pdir
->parent_dir
= pdir
->fatdir
;
153 if ( fat_opendir(IF_MV2(volume
,)
156 &pdir
->parent_dir
) < 0 ) {
157 DEBUGF("Failed opening dir '%s' (%ld)\n",
158 part
, entry
.firstcluster
);
162 #ifdef HAVE_MULTIVOLUME
163 pdir
->volumecounter
= -1; /* n.a. to subdirs */
173 int closedir_uncached(DIR_UNCACHED
* dir
)
179 struct dirent_uncached
* readdir_uncached(DIR_UNCACHED
* dir
)
181 struct fat_direntry entry
;
182 struct dirent_uncached
* theent
= &(dir
->theent
);
187 #ifdef HAVE_MULTIVOLUME
188 /* Volumes (secondary file systems) get inserted into the root directory
189 of the first volume, since we have no separate top level. */
190 if (dir
->volumecounter
>= 0 /* on a root dir */
191 && dir
->volumecounter
< NUM_VOLUMES
/* in range */
192 && dir
->fatdir
.file
.volume
== 0) /* at volume 0 */
193 { /* fake special directories, which don't really exist, but
194 will get redirected upon opendir_uncached() */
195 while (++dir
->volumecounter
< NUM_VOLUMES
)
197 if (fat_ismounted(dir
->volumecounter
))
199 memset(theent
, 0, sizeof(*theent
));
200 theent
->attribute
= FAT_ATTR_DIRECTORY
| FAT_ATTR_VOLUME
;
201 snprintf(theent
->d_name
, sizeof(theent
->d_name
),
202 vol_names
, dir
->volumecounter
);
208 /* normal directory entry fetching follows here */
209 if (fat_getnext(&(dir
->fatdir
),&entry
) < 0)
212 if ( !entry
.name
[0] )
215 strncpy(theent
->d_name
, entry
.name
, sizeof( theent
->d_name
) );
216 theent
->attribute
= entry
.attr
;
217 theent
->size
= entry
.filesize
;
218 theent
->startcluster
= entry
.firstcluster
;
219 theent
->wrtdate
= entry
.wrtdate
;
220 theent
->wrttime
= entry
.wrttime
;
225 int mkdir_uncached(const char *name
)
228 char namecopy
[MAX_PATH
];
232 struct dirent_uncached
*entry
;
233 struct fat_dir newdir
;
236 if ( name
[0] != '/' ) {
237 DEBUGF("mkdir: Only absolute paths supported right now\n");
241 strncpy(namecopy
,name
,sizeof(namecopy
));
242 namecopy
[sizeof(namecopy
)-1] = 0;
244 /* Split the base name and the path */
245 end
= strrchr(namecopy
, '/');
249 if(namecopy
== end
) /* Root dir? */
254 DEBUGF("mkdir: parent: %s, name: %s\n", parent
, basename
);
256 dir
= opendir_uncached(parent
);
259 DEBUGF("mkdir: can't open parent dir\n");
263 if(basename
[0] == 0) {
264 DEBUGF("mkdir: Empty dir name\n");
269 /* Now check if the name already exists */
270 while ((entry
= readdir_uncached(dir
))) {
271 if ( !strcasecmp(basename
, entry
->d_name
) ) {
272 DEBUGF("mkdir error: file exists\n");
274 closedir_uncached(dir
);
279 memset(&newdir
, sizeof(struct fat_dir
), 0);
281 rc
= fat_create_dir(basename
, &newdir
, &(dir
->fatdir
));
282 closedir_uncached(dir
);
287 int rmdir_uncached(const char* name
)
291 struct dirent_uncached
* entry
;
293 dir
= opendir_uncached(name
);
296 errno
= ENOENT
; /* open error */
300 /* check if the directory is empty */
301 while ((entry
= readdir_uncached(dir
)))
303 if (strcmp(entry
->d_name
, ".") &&
304 strcmp(entry
->d_name
, ".."))
306 DEBUGF("rmdir error: not empty\n");
308 closedir_uncached(dir
);
313 rc
= fat_remove(&(dir
->fatdir
.file
));
315 DEBUGF("Failed removing dir: %d\n", rc
);
320 closedir_uncached(dir
);