1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
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 ****************************************************************************/
29 #define MAX_OPEN_DIRS 8
31 static DIR 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 */
41 static const char* vol_names
= "<HD%d>";
42 #define VOL_ENUM_POS 3
45 /* returns on which volume this is, and copies the reduced name
46 (sortof a preprocessor for volume-decorated pathnames) */
47 static int strip_volume(const char* name
, char* namecopy
)
50 const char *temp
= name
;
52 while (*temp
== '/') /* skip all leading slashes */
55 if (*temp
&& !strncmp(temp
, vol_names
, VOL_ENUM_POS
))
57 temp
+= VOL_ENUM_POS
; /* behind special name */
58 volume
= atoi(temp
); /* number is following */
59 temp
= strchr(temp
, '/'); /* search for slash behind */
61 name
= temp
; /* use the part behind the volume */
63 name
= "/"; /* else this must be the root dir */
66 strncpy(namecopy
, name
, MAX_PATH
);
67 namecopy
[MAX_PATH
-1] = '\0';
71 #endif /* #ifdef HAVE_MULTIVOLUME */
75 // release all dir handles on a given volume "by force", to avoid leaks
76 int release_dirs(int volume
)
81 for ( dd
=0; dd
<MAX_OPEN_DIRS
; dd
++, pdir
++)
83 if (pdir
->fatdir
.file
.volume
== volume
)
85 pdir
->busy
= false; /* mark as available, no further action */
89 return closed
; /* return how many we did */
91 #endif /* #ifdef HAVE_HOTSWAP */
93 DIR* opendir(const char* name
)
95 char namecopy
[MAX_PATH
];
98 struct fat_direntry entry
;
100 DIR* pdir
= opendirs
;
101 #ifdef HAVE_MULTIVOLUME
105 if ( name
[0] != '/' ) {
106 DEBUGF("Only absolute paths supported right now\n");
110 /* find a free dir descriptor */
111 for ( dd
=0; dd
<MAX_OPEN_DIRS
; dd
++, pdir
++)
115 if ( dd
== MAX_OPEN_DIRS
) {
116 DEBUGF("Too many dirs open\n");
123 #ifdef HAVE_MULTIVOLUME
124 /* try to extract a heading volume name, if present */
125 volume
= strip_volume(name
, namecopy
);
126 pdir
->volumecounter
= 0;
128 strncpy(namecopy
,name
,sizeof(namecopy
)); /* just copy */
129 namecopy
[sizeof(namecopy
)-1] = '\0';
132 if ( fat_opendir(IF_MV2(volume
,) &pdir
->fatdir
, 0, NULL
) < 0 ) {
133 DEBUGF("Failed opening root dir\n");
138 for ( part
= strtok_r(namecopy
, "/", &end
); part
;
139 part
= strtok_r(NULL
, "/", &end
)) {
140 /* scan dir for name */
142 if ((fat_getnext(&pdir
->fatdir
,&entry
) < 0) ||
147 if ( (entry
.attr
& FAT_ATTR_DIRECTORY
) &&
148 (!strcasecmp(part
, entry
.name
)) ) {
149 pdir
->parent_dir
= pdir
->fatdir
;
150 if ( fat_opendir(IF_MV2(volume
,)
153 &pdir
->parent_dir
) < 0 ) {
154 DEBUGF("Failed opening dir '%s' (%ld)\n",
155 part
, entry
.firstcluster
);
159 #ifdef HAVE_MULTIVOLUME
160 pdir
->volumecounter
= -1; /* n.a. to subdirs */
170 int closedir(DIR* dir
)
176 struct dirent
* readdir(DIR* dir
)
178 struct fat_direntry entry
;
179 struct dirent
* theent
= &(dir
->theent
);
184 #ifdef HAVE_MULTIVOLUME
185 /* Volumes (secondary file systems) get inserted into the root directory
186 of the first volume, since we have no separate top level. */
187 if (dir
->volumecounter
>= 0 /* on a root dir */
188 && dir
->volumecounter
< NUM_VOLUMES
/* in range */
189 && dir
->fatdir
.file
.volume
== 0) /* at volume 0 */
190 { /* fake special directories, which don't really exist, but
191 will get redirected upon opendir() */
192 while (++dir
->volumecounter
< NUM_VOLUMES
)
194 if (fat_ismounted(dir
->volumecounter
))
196 memset(theent
, 0, sizeof(*theent
));
197 theent
->attribute
= FAT_ATTR_DIRECTORY
| FAT_ATTR_VOLUME
;
198 snprintf(theent
->d_name
, sizeof(theent
->d_name
),
199 vol_names
, dir
->volumecounter
);
205 /* normal directory entry fetching follows here */
206 if (fat_getnext(&(dir
->fatdir
),&entry
) < 0)
209 if ( !entry
.name
[0] )
212 strncpy(theent
->d_name
, entry
.name
, sizeof( theent
->d_name
) );
213 theent
->attribute
= entry
.attr
;
214 theent
->size
= entry
.filesize
;
215 theent
->startcluster
= entry
.firstcluster
;
216 theent
->wrtdate
= entry
.wrtdate
;
217 theent
->wrttime
= entry
.wrttime
;
222 int mkdir(const char *name
, int mode
)
225 char namecopy
[MAX_PATH
];
229 struct dirent
*entry
;
230 struct fat_dir newdir
;
235 if ( name
[0] != '/' ) {
236 DEBUGF("mkdir: Only absolute paths supported right now\n");
240 strncpy(namecopy
,name
,sizeof(namecopy
));
241 namecopy
[sizeof(namecopy
)-1] = 0;
243 /* Split the base name and the path */
244 end
= strrchr(namecopy
, '/');
248 if(namecopy
== end
) /* Root dir? */
253 DEBUGF("mkdir: parent: %s, name: %s\n", parent
, basename
);
255 dir
= opendir(parent
);
258 DEBUGF("mkdir: can't open parent dir\n");
262 if(basename
[0] == 0) {
263 DEBUGF("mkdir: Empty dir name\n");
268 /* Now check if the name already exists */
269 while ((entry
= readdir(dir
))) {
270 if ( !strcasecmp(basename
, entry
->d_name
) ) {
271 DEBUGF("mkdir error: file exists\n");
278 memset(&newdir
, sizeof(struct fat_dir
), 0);
280 rc
= fat_create_dir(basename
, &newdir
, &(dir
->fatdir
));
283 dircache_mkdir(name
);
291 int rmdir(const char* name
)
295 struct dirent
* entry
;
300 errno
= ENOENT
; /* open error */
304 /* check if the directory is empty */
305 while ((entry
= readdir(dir
)))
307 if (strcmp(entry
->d_name
, ".") &&
308 strcmp(entry
->d_name
, ".."))
310 DEBUGF("rmdir error: not empty\n");
317 rc
= fat_remove(&(dir
->fatdir
.file
));
319 DEBUGF("Failed removing dir: %d\n", rc
);
326 dircache_rmdir(name
);