]> git.sur5r.net Git - freertos/blob - FreeRTOS-Plus/Source/FreeRTOS-Plus-FAT-SL/fat_sl/common/dir.c
Slight modification to license blub text in header comments.
[freertos] / FreeRTOS-Plus / Source / FreeRTOS-Plus-FAT-SL / fat_sl / common / dir.c
1 /*\r
2  * FreeRTOS+FAT FS V1.0.0 (C) 2013 HCC Embedded\r
3  *\r
4  * The FreeRTOS+FAT SL license terms are different to the FreeRTOS license \r
5  * terms.\r
6  * \r
7  * FreeRTOS+FAT SL uses a dual license model that allows the software to be used \r
8  * under a standard GPL open source license, or a commercial license.  The \r
9  * standard GPL license (unlike the modified GPL license under which FreeRTOS \r
10  * itself is distributed) requires that all software statically linked with \r
11  * FreeRTOS+FAT SL is also distributed under the same GPL V2 license terms.  \r
12  * Details of both license options follow:\r
13  * \r
14  * - Open source licensing -\r
15  * FreeRTOS+FAT SL is a free download and may be used, modified, evaluated and\r
16  * distributed without charge provided the user adheres to version two of the \r
17  * GNU General Public License (GPL) and does not remove the copyright notice or \r
18  * this text.  The GPL V2 text is available on the gnu.org web site, and on the\r
19  * following URL: http://www.FreeRTOS.org/gpl-2.0.txt.\r
20  * \r
21  * - Commercial licensing -\r
22  * Businesses and individuals who for commercial or other reasons cannot comply\r
23  * with the terms of the GPL V2 license must obtain a commercial license before \r
24  * incorporating FreeRTOS+FAT SL into proprietary software for distribution in \r
25  * any form.  Commercial licenses can be purchased from \r
26  * http://shop.freertos.org/fat_sl and do not require any source files to be \r
27  * changed.\r
28  *\r
29  * FreeRTOS+FAT SL is distributed in the hope that it will be useful.  You\r
30  * cannot use FreeRTOS+FAT SL unless you agree that you use the software 'as\r
31  * is'.  FreeRTOS+FAT SL is provided WITHOUT ANY WARRANTY; without even the\r
32  * implied warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A\r
33  * PARTICULAR PURPOSE. Real Time Engineers Ltd. and HCC Embedded disclaims all\r
34  * conditions and terms, be they implied, expressed, or statutory.\r
35  *\r
36  * http://www.FreeRTOS.org\r
37  * http://www.FreeRTOS.org/FreeRTOS-Plus\r
38  *\r
39  */\r
40 \r
41 #include "../../api/fat_sl.h"\r
42 #include "../../psp/include/psp_string.h"\r
43 \r
44 #include "dir.h"\r
45 #include "util.h"\r
46 #include "volume.h"\r
47 #include "drv.h"\r
48 #include "fat.h"\r
49 #include "file.h"\r
50 \r
51 #include "../../version/ver_fat_sl.h"\r
52 #if VER_FAT_SL_MAJOR != 3 || VER_FAT_SL_MINOR != 2\r
53  #error Incompatible FAT_SL version number!\r
54 #endif\r
55 \r
56 \r
57 /****************************************************************************\r
58  *\r
59  * _f_findfilewc\r
60  *\r
61  * internal function to finding file in directory entry with or without\r
62  * wildcard\r
63  *\r
64  * INPUTS\r
65  *\r
66  * name - filename\r
67  * ext - fileextension\r
68  * pos - where to start searching, and contains current position\r
69  * pde - store back the directory entry pointer\r
70  * wc - wildcard checking?\r
71  *\r
72  * RETURNS\r
73  *\r
74  * 0 - if file was not found\r
75  * 1 - if file was found\r
76  *\r
77  ***************************************************************************/\r
78 unsigned char _f_findfilewc ( char * name, char * ext, F_POS * pos, F_DIRENTRY * * pde, unsigned char wc )\r
79 {\r
80   while ( pos->cluster < F_CLUSTER_RESERVED )\r
81   {\r
82     for ( ; pos->sector < pos->sectorend ; pos->sector++ )\r
83     {\r
84       F_DIRENTRY * de = (F_DIRENTRY *)( gl_sector + sizeof( F_DIRENTRY ) * pos->pos );\r
85 \r
86       if ( _f_readglsector( pos->sector ) )\r
87       {\r
88         return 0;                                         /*not found*/\r
89       }\r
90 \r
91       for ( ; pos->pos < F_SECTOR_SIZE / sizeof( F_DIRENTRY ) ; de++, pos->pos++ )\r
92       {\r
93         unsigned char  b, ok;\r
94 \r
95         if ( !de->name[0] )\r
96         {\r
97           return 0;                                                /*empty*/\r
98         }\r
99 \r
100         if ( (unsigned char)( de->name[0] ) == 0xe5 )\r
101         {\r
102           continue;                                                 /*deleted*/\r
103         }\r
104 \r
105         if ( de->attr & F_ATTR_VOLUME )\r
106         {\r
107           continue;\r
108         }\r
109 \r
110         if ( wc )\r
111         {\r
112           for ( b = 0, ok = 1 ; b < sizeof( de->name ) ; b++ )\r
113           {\r
114             if ( name[b] == '*' )\r
115             {\r
116               break;\r
117             }\r
118 \r
119             if ( name[b] != '?' )\r
120             {\r
121               if ( de->name[b] != name[b] )\r
122               {\r
123                 ok = 0;\r
124                 break;\r
125               }\r
126             }\r
127           }\r
128 \r
129           if ( ok )\r
130           {\r
131             for ( b = 0, ok = 1 ; b < sizeof( de->ext ) ; b++ )\r
132             {\r
133               if ( ext[b] == '*' )\r
134               {\r
135                 if ( pde )\r
136                 {\r
137                   *pde = de;\r
138                 }\r
139 \r
140                 return 1;\r
141               }\r
142 \r
143               if ( ext[b] != '?' )\r
144               {\r
145                 if ( de->ext[b] != ext[b] )\r
146                 {\r
147                   ok = 0;\r
148                   break;\r
149                 }\r
150               }\r
151             }\r
152 \r
153             if ( ok )\r
154             {\r
155               if ( pde )\r
156               {\r
157                 *pde = de;\r
158               }\r
159 \r
160               return 1;\r
161             }\r
162           }\r
163         }\r
164         else\r
165         {\r
166           for ( b = 0, ok = 1 ; b < sizeof( de->name ) ; b++ )\r
167           {\r
168             if ( de->name[b] != name[b] )\r
169             {\r
170               ok = 0;\r
171               break;\r
172             }\r
173           }\r
174 \r
175           if ( ok )\r
176           {\r
177             for ( b = 0, ok = 1 ; b < sizeof( de->ext ) ; b++ )\r
178             {\r
179               if ( de->ext[b] != ext[b] )\r
180               {\r
181                 ok = 0;\r
182                 break;\r
183               }\r
184             }\r
185 \r
186             if ( ok )\r
187             {\r
188               if ( pde )\r
189               {\r
190                 *pde = de;\r
191               }\r
192 \r
193               return 1;\r
194             }\r
195           }\r
196         }\r
197       }\r
198 \r
199       pos->pos = 0;\r
200     }\r
201 \r
202     if ( !pos->cluster )\r
203     {\r
204       if ( gl_volume.mediatype == F_FAT32_MEDIA )\r
205       {\r
206         pos->cluster = gl_volume.bootrecord.rootcluster;\r
207       }\r
208       else\r
209         return 0;\r
210     }\r
211 \r
212     {\r
213       unsigned long  nextcluster;\r
214       gl_volume.fatsector = (unsigned long)-1;\r
215       if ( _f_getclustervalue( pos->cluster, &nextcluster ) )\r
216       {\r
217         return 0;                                                          /*not found*/\r
218       }\r
219 \r
220       if ( nextcluster >= F_CLUSTER_RESERVED )\r
221       {\r
222         return 0;                                            /*eof*/\r
223       }\r
224 \r
225       _f_clustertopos( nextcluster, pos );\r
226     }\r
227   } /* _f_findfilewc */\r
228 \r
229   return 0;\r
230 }\r
231 \r
232 \r
233 /****************************************************************************\r
234  *\r
235  * _f_getfilename\r
236  *\r
237  * create a complete filename from name and extension\r
238  *\r
239  * INPUTS\r
240  *\r
241  * dest - where to store filename\r
242  * name - name of the file\r
243  * ext - extension of the file\r
244  *\r
245  ***************************************************************************/\r
246 static void _f_getfilename ( char * dest, char * name, char * ext )\r
247 {\r
248   unsigned char  a, len;\r
249 \r
250   for ( len = a = F_MAXNAME ; a ; a--, len-- )\r
251   {\r
252     if ( name[a - 1] != ' ' )\r
253     {\r
254       break;\r
255     }\r
256   }\r
257 \r
258   for ( a = 0 ; a < len ; a++ )\r
259   {\r
260     *dest++ = *name++;\r
261   }\r
262 \r
263 \r
264   for ( len = a = F_MAXEXT ; a ; a--, len-- )\r
265   {\r
266     if ( ext[a - 1] != ' ' )\r
267     {\r
268       break;\r
269     }\r
270   }\r
271 \r
272   if ( len )\r
273   {\r
274     *dest++ = '.';\r
275   }\r
276 \r
277   for ( a = 0 ; a < len ; a++ )\r
278   {\r
279     *dest++ = *ext++;\r
280   }\r
281 \r
282   *dest = 0; /*terminateit*/\r
283 } /* _f_getfilename */\r
284 \r
285 \r
286 \r
287 \r
288 /****************************************************************************\r
289  *\r
290  * _f_getdecluster\r
291  *\r
292  * get a directory entry structure start cluster value\r
293  *\r
294  * INPUTS\r
295  *\r
296  * de - directory entry\r
297  *\r
298  * RETURNS\r
299  *\r
300  * directory entry cluster value\r
301  *\r
302  ***************************************************************************/\r
303 unsigned long _f_getdecluster ( F_DIRENTRY * de )\r
304 {\r
305   unsigned long  cluster;\r
306   if ( gl_volume.mediatype == F_FAT32_MEDIA )\r
307   {\r
308     cluster = _f_getword( &de->clusterhi );\r
309     cluster <<= 16;\r
310     cluster |= _f_getword( &de->clusterlo );\r
311     return cluster;\r
312   }\r
313 \r
314   return _f_getword( &de->clusterlo );\r
315 }\r
316 \r
317 \r
318 /****************************************************************************\r
319  *\r
320  * _f_setdecluster\r
321  *\r
322  * set a directory entry structure start cluster value\r
323  *\r
324  * INPUTS\r
325  *\r
326  * de - directory entry\r
327  * cluster - value of the start cluster\r
328  *\r
329  ***************************************************************************/\r
330 void _f_setdecluster ( F_DIRENTRY * de, unsigned long cluster )\r
331 {\r
332   _f_setword( &de->clusterlo, (unsigned short)( cluster & 0xffff ) );\r
333   if ( gl_volume.mediatype == F_FAT32_MEDIA )\r
334   {\r
335     _f_setword( &de->clusterhi, (unsigned short)( cluster >> 16 ) );\r
336   }\r
337   else\r
338   {\r
339     _f_setword( &de->clusterhi, (unsigned short)0 );\r
340   }\r
341 }\r
342 \r
343 \r
344 /****************************************************************************\r
345  *\r
346  * _f_findpath\r
347  *\r
348  * finding out if path is valid in F_NAME and\r
349  * correct path info with absolute path (removes relatives)\r
350  *\r
351  * INPUTS\r
352  *\r
353  * fsname - filled structure with path,drive\r
354  * pos - where to start searching, and contains current position\r
355  *\r
356  * RETURNS\r
357  *\r
358  * 0 - if path was not found or invalid\r
359  * 1 - if path was found\r
360  *\r
361  ***************************************************************************/\r
362 unsigned char _f_findpath ( F_NAME * fsname, F_POS * pos )\r
363 {\r
364   char       * path = fsname->path;\r
365   char       * mpath = path;\r
366   F_DIRENTRY * de;\r
367 \r
368   _f_clustertopos( 0, pos );\r
369 \r
370   for ( ; *path ; )\r
371   {\r
372     char           name[F_MAXNAME];\r
373     char           ext[F_MAXEXT];\r
374 \r
375     unsigned char  len = _f_setnameext( path, name, ext );\r
376 \r
377     if ( ( pos->cluster == 0 ) && ( len == 1 ) && ( name[0] == '.' ) )\r
378     {\r
379       _f_clustertopos( 0, pos );\r
380     }\r
381     else\r
382     {\r
383       if ( !_f_findfilewc( name, ext, pos, &de, 0 ) )\r
384       {\r
385         return 0;\r
386       }\r
387       if ( !( de->attr & F_ATTR_DIR ) )\r
388       {\r
389         return 0;\r
390       }\r
391 \r
392       _f_clustertopos( _f_getdecluster( de ), pos );\r
393     }\r
394 \r
395 \r
396     if ( name[0] == '.' )\r
397     {\r
398       if ( len == 1 )\r
399       {\r
400         path += len;\r
401 \r
402         if ( !( *path ) )\r
403         {\r
404           if ( mpath != fsname->path )\r
405           {\r
406             mpath--;                                  /*if we are now at the top*/\r
407           }\r
408 \r
409           break;\r
410         }\r
411 \r
412         path++;\r
413         continue;\r
414       }\r
415 \r
416       if ( name[1] != '.' )\r
417       {\r
418         return 0;                       /*invalid name*/\r
419       }\r
420 \r
421       if ( len != 2 )\r
422       {\r
423         return 0;                 /*invalid name !*/\r
424       }\r
425 \r
426       path += len;\r
427 \r
428       if ( mpath == fsname->path )\r
429       {\r
430         return 0;                              /*we are in the top*/\r
431       }\r
432 \r
433       mpath--;       /*no on separator*/\r
434       for ( ; ; )\r
435       {\r
436         if ( mpath == fsname->path )\r
437         {\r
438           break;                                /*we are now at the top*/\r
439         }\r
440 \r
441         mpath--;\r
442         if ( *mpath == '/' )\r
443         {\r
444           mpath++;\r
445           break;\r
446         }\r
447       }\r
448 \r
449       if ( !( *path ) )\r
450       {\r
451         if ( mpath != fsname->path )\r
452         {\r
453           mpath--;                                /*if we are now at the top*/\r
454         }\r
455 \r
456         break;\r
457       }\r
458 \r
459       path++;\r
460       continue;\r
461     }\r
462     else\r
463     {\r
464       if ( path == mpath )                              /*if no was dots just step*/\r
465       {\r
466         path += len;\r
467         mpath += len;\r
468       }\r
469       else\r
470       {\r
471         unsigned char  a;\r
472         for ( a = 0 ; a < len ; a++ )\r
473         {\r
474           *mpath++ = *path++;                            /*copy if in different pos*/\r
475         }\r
476       }\r
477     }\r
478 \r
479     if ( !( *path ) )\r
480     {\r
481       break;\r
482     }\r
483 \r
484     path++;\r
485     *mpath++ = '/';   /*add separator*/\r
486   }\r
487 \r
488   *mpath = 0; /*terminate it*/\r
489   return 1;\r
490 } /* _f_findpath */\r
491 \r
492 \r
493 /****************************************************************************\r
494  *\r
495  * fn_getcwd\r
496  *\r
497  * getting a current working directory of current drive\r
498  *\r
499  * INPUTS\r
500  *\r
501  * buffer - where to store current working folder\r
502  * maxlen - buffer length (possible size is F_MAXPATH)\r
503  *\r
504  * RETURNS\r
505  *\r
506  * error code or zero if successful\r
507  *\r
508  ***************************************************************************/\r
509 \r
510 \r
511 unsigned char fn_getcwd ( char * buffer, unsigned char maxlen, char root )\r
512 {\r
513   unsigned char  a;\r
514 \r
515   if ( !maxlen )\r
516   {\r
517     return F_NO_ERROR;\r
518   }\r
519 \r
520   maxlen--;     /*need for termination*/\r
521   if ( root && maxlen )\r
522   {\r
523     *buffer++ = '/';\r
524     maxlen--;\r
525   }\r
526 \r
527   for ( a = 0 ; a < maxlen ; a++ )\r
528   {\r
529     char  ch = gl_volume.cwd[a];\r
530     buffer[a] = ch;\r
531     if ( !ch )\r
532     {\r
533       break;\r
534     }\r
535   }\r
536 \r
537   buffer[a] = 0;    /*add terminator at the end*/\r
538 \r
539   return F_NO_ERROR;\r
540 } /* fn_getcwd */\r
541 \r
542 \r
543 \r
544 /****************************************************************************\r
545  *\r
546  * fn_findfirst\r
547  *\r
548  * find a file(s) or directory(s) in directory\r
549  *\r
550  * INPUTS\r
551  *\r
552  * filename - filename (with or without wildcards)\r
553  * find - where to store found file information\r
554  *\r
555  * RETURNS\r
556  *\r
557  * error code or zero if successful\r
558  *\r
559  ***************************************************************************/\r
560 \r
561 \r
562 unsigned char fn_findfirst ( const char * filename, F_FIND * find )\r
563 {\r
564   unsigned char  ret;\r
565 \r
566   if ( _f_setfsname( filename, &find->findfsname ) )\r
567   {\r
568     return F_ERR_INVALIDNAME;  /*invalid name*/\r
569   }\r
570 \r
571   if ( _f_checkname( find->findfsname.filename, find->findfsname.fileext ) )\r
572   {\r
573     return F_ERR_INVALIDNAME;  /*invalid name, wildcard is ok*/\r
574   }\r
575 \r
576 \r
577   ret = _f_getvolume();\r
578   if ( ret )\r
579   {\r
580     return ret;\r
581   }\r
582 \r
583   if ( !_f_findpath( &find->findfsname, &find->pos ) )\r
584   {\r
585     return F_ERR_INVALIDDIR;   /*search for path*/\r
586   }\r
587 \r
588   return fn_findnext( find );\r
589 } /* fn_findfirst */\r
590 \r
591 \r
592 \r
593 /****************************************************************************\r
594  *\r
595  * fn_findnext\r
596  *\r
597  * find further file(s) or directory(s) in directory\r
598  *\r
599  * INPUTS\r
600  *\r
601  * find - where to store found file information (findfirst should call 1st)\r
602  *\r
603  * RETURNS\r
604  *\r
605  * error code or zero if successful\r
606  *\r
607  ***************************************************************************/\r
608 \r
609 \r
610 unsigned char fn_findnext ( F_FIND * find )\r
611 {\r
612   F_DIRENTRY   * de;\r
613   unsigned char  a;\r
614   unsigned char  ret;\r
615 \r
616   ret = _f_getvolume();\r
617   if ( ret )\r
618   {\r
619     return ret;\r
620   }\r
621 \r
622   if ( !_f_findfilewc( find->findfsname.filename, find->findfsname.fileext, &find->pos, &de, 1 ) )\r
623   {\r
624     return F_ERR_NOTFOUND;\r
625   }\r
626 \r
627   for ( a = 0 ; a < F_MAXNAME ; a++ )\r
628   {\r
629     find->name[a] = de->name[a];\r
630   }\r
631 \r
632   for ( a = 0 ; a < F_MAXEXT ; a++ )\r
633   {\r
634     find->ext[a] = de->ext[a];\r
635   }\r
636 \r
637   _f_getfilename( find->filename, (char *)de->name, (char *)de->ext );\r
638 \r
639   find->attr = de->attr;\r
640   find->cdate = _f_getword( &de->cdate );\r
641   find->ctime = _f_getword( &de->ctime );\r
642   find->filesize = (long)_f_getlong( &de->filesize );\r
643   find->cluster = _f_getdecluster( de );\r
644   find->pos.pos++;   /*goto next position*/\r
645 \r
646   return 0;\r
647 } /* fn_findnext */\r
648 \r
649 \r
650 \r
651 /****************************************************************************\r
652  *\r
653  * fn_chdir\r
654  *\r
655  * change current working directory\r
656  *\r
657  * INPUTS\r
658  *\r
659  * dirname - new working directory name\r
660  *\r
661  * RETURNS\r
662  *\r
663  * 0 - if successfully\r
664  * other - if any error\r
665  *\r
666  ***************************************************************************/\r
667 unsigned char fn_chdir ( const char * dirname )\r
668 {\r
669   F_POS          pos;\r
670   F_NAME         fsname;\r
671   unsigned char  len;\r
672   unsigned char  a;\r
673   unsigned char  ret;\r
674 \r
675   ret = _f_setfsname( dirname, &fsname );\r
676 \r
677   if ( ret == 1 )\r
678   {\r
679     return F_ERR_INVALIDNAME;             /*invalid name*/\r
680   }\r
681 \r
682   if ( _f_checknamewc( fsname.filename, fsname.fileext ) )\r
683   {\r
684     return F_ERR_INVALIDNAME;                                                    /*invalid name*/\r
685   }\r
686 \r
687   ret = _f_getvolume();\r
688   if ( ret )\r
689   {\r
690     return ret;\r
691   }\r
692 \r
693   for ( len = 0 ; fsname.path[len] ; )\r
694   {\r
695     len++;\r
696   }\r
697 \r
698   if ( len && ( ( fsname.filename[0] != 32 ) || ( fsname.fileext[0] != 32 ) ) )\r
699   {\r
700     fsname.path[len++] = '/';\r
701   }\r
702 \r
703   _f_getfilename( fsname.path + len, fsname.filename, fsname.fileext );\r
704 \r
705   if ( !( _f_findpath( &fsname, &pos ) ) )\r
706   {\r
707     return F_ERR_NOTFOUND;\r
708   }\r
709 \r
710   for ( a = 0 ; a < F_MAXPATH ; a++ )\r
711   {\r
712     gl_volume.cwd[a] = fsname.path[a];\r
713   }\r
714 \r
715   return F_NO_ERROR;\r
716 } /* fn_chdir */\r
717 \r
718 \r
719 \r
720 /****************************************************************************\r
721  *\r
722  * _f_initentry\r
723  *\r
724  * init directory entry, this function is called if a new entry is coming\r
725  *\r
726  * INPUTS\r
727  *\r
728  * de - directory entry which needs to be initialized\r
729  * name - fil ename  (8)\r
730  * ext - file extension (3)\r
731  *\r
732  ***************************************************************************/\r
733 static void _f_initentry ( F_DIRENTRY * de, char * name, char * ext )\r
734 {\r
735   unsigned short  date;\r
736   unsigned short  time;\r
737 \r
738   psp_memset( de, 0, sizeof( F_DIRENTRY ) ); /*reset all entries*/\r
739 \r
740   psp_memcpy( de->name, name, sizeof( de->name ) );\r
741   psp_memcpy( de->ext, ext, sizeof( de->ext ) );\r
742 \r
743   f_igettimedate( &time, &date );\r
744   _f_setword( &de->cdate, date ); /*if there is realtime clock then creation date could be set from*/\r
745   _f_setword( &de->ctime, time ); /*if there is realtime clock then creation time could be set from*/\r
746 }\r
747 \r
748 \r
749 \r
750 \r
751 \r
752 /****************************************************************************\r
753  *\r
754  * _f_addentry\r
755  *\r
756  * Add a new directory entry into driectory list\r
757  *\r
758  * INPUTS\r
759  *\r
760  * fs_name - filled structure what to add into directory list\r
761  * pos - where directory cluster chains starts\r
762  * pde - F_DIRENTRY pointer where to store the entry where it was added\r
763  *\r
764  * RETURNS\r
765  *\r
766  * 0 - if successfully added\r
767  * other - if any error (see FS_xxx errorcodes)\r
768  *\r
769  ***************************************************************************/\r
770 unsigned char _f_addentry ( F_NAME * fsname, F_POS * pos, F_DIRENTRY * * pde )\r
771 {\r
772   unsigned char   ret;\r
773   unsigned short  date;\r
774   unsigned short  time;\r
775 \r
776   if ( !fsname->filename[0] )\r
777   {\r
778     return F_ERR_INVALIDNAME;\r
779   }\r
780 \r
781   if ( fsname->filename[0] == '.' )\r
782   {\r
783     return F_ERR_INVALIDNAME;\r
784   }\r
785 \r
786   while ( pos->cluster < F_CLUSTER_RESERVED )\r
787   {\r
788     for ( ; pos->sector < pos->sectorend ; pos->sector++ )\r
789     {\r
790       F_DIRENTRY * de = (F_DIRENTRY *)( gl_sector + sizeof( F_DIRENTRY ) * pos->pos );\r
791 \r
792       ret = _f_readglsector( pos->sector );\r
793       if ( ret )\r
794       {\r
795         return ret;\r
796       }\r
797 \r
798       for ( ; pos->pos < F_SECTOR_SIZE / sizeof( F_DIRENTRY ) ; de++, pos->pos++ )\r
799       {\r
800         if ( ( !de->name[0] ) || ( (unsigned char)( de->name[0] ) == 0xe5 ) )\r
801         {\r
802           _f_initentry( de, fsname->filename, fsname->fileext );\r
803           if ( gl_volume.mediatype == F_FAT32_MEDIA )\r
804           {\r
805             f_igettimedate( &time, &date );\r
806             _f_setword( &de->crtdate, date );             /*if there is realtime clock then creation date could be set from*/\r
807             _f_setword( &de->crttime, time );             /*if there is realtime clock then creation time could be set from*/\r
808             _f_setword( &de->lastaccessdate, date );      /*if there is realtime clock then creation date could be set from*/\r
809           }\r
810 \r
811           if ( pde )\r
812           {\r
813             *pde = de;\r
814           }\r
815 \r
816           return F_NO_ERROR;\r
817         }\r
818       }\r
819 \r
820       pos->pos = 0;\r
821     }\r
822 \r
823     if ( !pos->cluster )\r
824     {\r
825       if ( gl_volume.mediatype == F_FAT32_MEDIA )\r
826       {\r
827         pos->cluster = gl_volume.bootrecord.rootcluster;\r
828       }\r
829       else\r
830         return F_ERR_NOMOREENTRY;\r
831     }\r
832 \r
833     {\r
834       unsigned long  cluster;\r
835 \r
836       gl_volume.fatsector = (unsigned long)-1;\r
837       ret = _f_getclustervalue( pos->cluster, &cluster );    /*try to get next cluster*/\r
838       if ( ret )\r
839       {\r
840         return ret;\r
841       }\r
842 \r
843       if ( cluster < F_CLUSTER_RESERVED )\r
844       {\r
845         _f_clustertopos( cluster, pos );\r
846       }\r
847       else\r
848       {\r
849         ret = _f_alloccluster( &cluster );        /*get a new one*/\r
850         if ( ret )\r
851         {\r
852           return ret;\r
853         }\r
854 \r
855         if ( cluster < F_CLUSTER_RESERVED )\r
856         {\r
857           if ( gl_file.mode != F_FILE_CLOSE )\r
858           {\r
859             return F_ERR_NOMOREENTRY;\r
860           }\r
861 \r
862           _f_clustertopos( cluster, &gl_file.pos );\r
863 \r
864           ret = _f_setclustervalue( gl_file.pos.cluster, F_CLUSTER_LAST );\r
865           if ( ret )\r
866           {\r
867             return ret;\r
868           }\r
869 \r
870           ret = _f_setclustervalue( pos->cluster, gl_file.pos.cluster );\r
871           if ( ret )\r
872           {\r
873             return ret;\r
874           }\r
875 \r
876           ret = _f_writefatsector();\r
877           if ( ret )\r
878           {\r
879             return ret;\r
880           }\r
881 \r
882           gl_volume.fatsector = (unsigned long)-1;\r
883           psp_memset( gl_sector, 0, F_SECTOR_SIZE );\r
884           while ( gl_file.pos.sector < gl_file.pos.sectorend )\r
885           {\r
886             ret = _f_writeglsector( gl_file.pos.sector );\r
887             if ( ret )\r
888             {\r
889               return ret;\r
890             }\r
891 \r
892             gl_file.pos.sector++;\r
893           }\r
894 \r
895           _f_clustertopos( gl_file.pos.cluster, pos );\r
896         }\r
897         else\r
898         {\r
899           return F_ERR_NOMOREENTRY;\r
900         }\r
901       }\r
902     }\r
903   } /* _f_addentry */\r
904 \r
905   return F_ERR_NOMOREENTRY;\r
906 }\r
907 \r
908 \r
909 \r
910 /****************************************************************************\r
911  *\r
912  * fn_mkdir\r
913  *\r
914  * making a new directory\r
915  *\r
916  * INPUTS\r
917  *\r
918  * dirname - new directory name\r
919  *\r
920  * RETURNS\r
921  *\r
922  * error code or zero if successful\r
923  *\r
924  ***************************************************************************/\r
925 unsigned char fn_mkdir ( const char * dirname )\r
926 {\r
927   F_POS          posdir;\r
928   F_POS          pos;\r
929   F_DIRENTRY   * de;\r
930   F_NAME         fsname;\r
931   unsigned long  cluster;\r
932   unsigned char  ret;\r
933 \r
934  #if F_FILE_CHANGED_EVENT\r
935   ST_FILE_CHANGED  fc;\r
936  #endif\r
937 \r
938   if ( _f_setfsname( dirname, &fsname ) )\r
939   {\r
940     return F_ERR_INVALIDNAME;                                    /*invalid name*/\r
941   }\r
942 \r
943   if ( _f_checknamewc( fsname.filename, fsname.fileext ) )\r
944   {\r
945     return F_ERR_INVALIDNAME;                                                    /*invalid name*/\r
946   }\r
947 \r
948   ret = _f_getvolume();\r
949   if ( ret )\r
950   {\r
951     return ret;\r
952   }\r
953 \r
954   if ( !_f_findpath( &fsname, &posdir ) )\r
955   {\r
956     return F_ERR_INVALIDDIR;\r
957   }\r
958 \r
959   pos = posdir;\r
960 \r
961   if ( fsname.filename[0] == '.' )\r
962   {\r
963     return F_ERR_NOTFOUND;\r
964   }\r
965 \r
966   if ( _f_findfilewc( fsname.filename, fsname.fileext, &pos, &de, 0 ) )\r
967   {\r
968     return F_ERR_DUPLICATED;\r
969   }\r
970 \r
971   pos = posdir;\r
972 \r
973   gl_volume.fatsector = (unsigned long)-1;\r
974   ret = _f_alloccluster( &cluster );\r
975   if ( ret )\r
976   {\r
977     return ret;\r
978   }\r
979 \r
980   ret = _f_addentry( &fsname, &pos, &de );\r
981   if ( ret )\r
982   {\r
983     return ret;\r
984   }\r
985 \r
986   de->attr |= F_ATTR_DIR;       /*set as directory*/\r
987 \r
988  #if F_FILE_CHANGED_EVENT\r
989   if ( f_filechangedevent )\r
990   {\r
991     fc.action = FACTION_ADDED;\r
992     fc.flags = FFLAGS_DIR_NAME | FFLAGS_ATTRIBUTES | FFLAGS_SIZE | FFLAGS_LAST_WRITE;\r
993     fc.attr = de->attr;\r
994     fc.ctime = _f_getword( de->ctime );\r
995     fc.cdate = _f_getword( de->cdate );\r
996     fc.filesize = _f_getlong( de->filesize );\r
997   }\r
998 \r
999  #endif\r
1000 \r
1001   if ( gl_file.mode != F_FILE_CLOSE )\r
1002   {\r
1003     return F_ERR_LOCKED;\r
1004   }\r
1005 \r
1006   _f_clustertopos( cluster, &gl_file.pos );\r
1007   _f_setdecluster( de, cluster ); /*new dir*/\r
1008 \r
1009   (void)_f_writeglsector( (unsigned long)-1 );  /*write actual directory sector*/\r
1010 \r
1011 \r
1012   de = (F_DIRENTRY *)gl_sector;\r
1013 \r
1014   _f_initentry( de, ".       ", "   " );\r
1015   de->attr = F_ATTR_DIR;          /*set as directory*/\r
1016   _f_setdecluster( de, cluster ); /*current*/\r
1017   de++;\r
1018 \r
1019   _f_initentry( de, "..      ", "   " );\r
1020   de->attr = F_ATTR_DIR;                 /*set as directory*/\r
1021   _f_setdecluster( de, posdir.cluster ); /*parent*/\r
1022   de++;\r
1023 \r
1024   psp_memset( de, 0, ( F_SECTOR_SIZE - 2 * sizeof( F_DIRENTRY ) ) );\r
1025 \r
1026 \r
1027   ret = _f_writeglsector( gl_file.pos.sector );\r
1028   if ( ret )\r
1029   {\r
1030     return ret;\r
1031   }\r
1032 \r
1033   gl_file.pos.sector++;\r
1034   psp_memset( gl_sector, 0, ( 2 * sizeof( F_DIRENTRY ) ) );\r
1035   while ( gl_file.pos.sector < gl_file.pos.sectorend )\r
1036   {\r
1037     ret = _f_writeglsector( gl_file.pos.sector );\r
1038     if ( ret )\r
1039     {\r
1040       return ret;\r
1041     }\r
1042 \r
1043     gl_file.pos.sector++;\r
1044   }\r
1045 \r
1046   gl_volume.fatsector = (unsigned long)-1;\r
1047   ret = _f_setclustervalue( gl_file.pos.cluster, F_CLUSTER_LAST );\r
1048   if ( ret )\r
1049   {\r
1050     return ret;\r
1051   }\r
1052 \r
1053   ret = _f_writefatsector();\r
1054  #if F_FILE_CHANGED_EVENT\r
1055   if ( f_filechangedevent && !ret )\r
1056   {\r
1057     fc.action = FACTION_ADDED;\r
1058     fc.flags = FFLAGS_DIR_NAME;\r
1059 \r
1060     if ( !_f_createfullname( fc.filename, sizeof( fc.filename ), fsname.path, fsname.filename, fsname.fileext ) )\r
1061     {\r
1062       f_filechangedevent( &fc );\r
1063     }\r
1064   }\r
1065 \r
1066  #endif\r
1067 \r
1068   return ret;\r
1069 } /* fn_mkdir */\r
1070 \r
1071 \r
1072 \r
1073 /****************************************************************************\r
1074  *\r
1075  * fn_rmdir\r
1076  *\r
1077  * Remove directory, only could be removed if empty\r
1078  *\r
1079  * INPUTS\r
1080  *\r
1081  * dirname - which directory needed to be removed\r
1082  *\r
1083  * RETURNS\r
1084  *\r
1085  * error code or zero if successful\r
1086  *\r
1087  ***************************************************************************/\r
1088 unsigned char fn_rmdir ( const char * dirname )\r
1089 {\r
1090   unsigned char  ret;\r
1091   F_POS          pos;\r
1092   F_DIRENTRY   * de;\r
1093   F_NAME         fsname;\r
1094   unsigned long  dirsector;\r
1095   unsigned char  a;\r
1096 \r
1097   if ( _f_setfsname( dirname, &fsname ) )\r
1098   {\r
1099     return F_ERR_INVALIDNAME;                                    /*invalid name*/\r
1100   }\r
1101 \r
1102   if ( _f_checknamewc( fsname.filename, fsname.fileext ) )\r
1103   {\r
1104     return F_ERR_INVALIDNAME;                                                    /*invalid name*/\r
1105   }\r
1106 \r
1107   if ( fsname.filename[0] == '.' )\r
1108   {\r
1109     return F_ERR_NOTFOUND;\r
1110   }\r
1111 \r
1112   ret = _f_getvolume();\r
1113   if ( ret )\r
1114   {\r
1115     return ret;\r
1116   }\r
1117 \r
1118   if ( !( _f_findpath( &fsname, &pos ) ) )\r
1119   {\r
1120     return F_ERR_INVALIDDIR;\r
1121   }\r
1122 \r
1123   if ( !_f_findfilewc( fsname.filename, fsname.fileext, &pos, &de, 0 ) )\r
1124   {\r
1125     return F_ERR_NOTFOUND;\r
1126   }\r
1127 \r
1128   if ( !( de->attr & F_ATTR_DIR ) )\r
1129   {\r
1130     return F_ERR_INVALIDDIR;                                       /*not a directory*/\r
1131   }\r
1132 \r
1133   dirsector = gl_volume.actsector;\r
1134 \r
1135   if ( gl_file.mode != F_FILE_CLOSE )\r
1136   {\r
1137     return F_ERR_LOCKED;\r
1138   }\r
1139 \r
1140   _f_clustertopos( _f_getdecluster( de ), &gl_file.pos );\r
1141 \r
1142   for ( ; ; )\r
1143   {\r
1144     F_DIRENTRY * de2;\r
1145     char         ch = 0;\r
1146 \r
1147     ret = _f_getcurrsector();\r
1148     if ( ret == F_ERR_EOF )\r
1149     {\r
1150       break;\r
1151     }\r
1152 \r
1153     if ( ret )\r
1154     {\r
1155       return ret;\r
1156     }\r
1157 \r
1158     de2 = (F_DIRENTRY *)gl_sector;\r
1159     for ( a = 0 ; a < ( F_SECTOR_SIZE / sizeof( F_DIRENTRY ) ) ; a++, de2++ )\r
1160     {\r
1161       ch = de2->name[0];\r
1162       if ( !ch )\r
1163       {\r
1164         break;\r
1165       }\r
1166 \r
1167       if ( (unsigned char)ch == 0xe5 )\r
1168       {\r
1169         continue;\r
1170       }\r
1171 \r
1172       if ( ch == '.' )\r
1173       {\r
1174         continue;\r
1175       }\r
1176 \r
1177       return F_ERR_NOTEMPTY;       /*something is there*/\r
1178     }\r
1179 \r
1180     if ( !ch )\r
1181     {\r
1182       break;\r
1183     }\r
1184 \r
1185     gl_file.pos.sector++;\r
1186   }\r
1187 \r
1188   ret = _f_readglsector( dirsector );\r
1189   if ( ret )\r
1190   {\r
1191     return ret;\r
1192   }\r
1193 \r
1194   de->name[0] = (unsigned char)0xe5;\r
1195 \r
1196   ret = _f_writeglsector( dirsector );\r
1197   if ( ret )\r
1198   {\r
1199     return ret;\r
1200   }\r
1201 \r
1202   gl_volume.fatsector = (unsigned long)-1;\r
1203   ret = _f_removechain( _f_getdecluster( de ) );\r
1204  #if F_FILE_CHANGED_EVENT\r
1205   if ( f_filechangedevent && !ret )\r
1206   {\r
1207     ST_FILE_CHANGED  fc;\r
1208     fc.action = FACTION_REMOVED;\r
1209     fc.flags = FFLAGS_DIR_NAME;\r
1210 \r
1211     if ( !_f_createfullname( fc.filename, sizeof( fc.filename ), fsname.path, fsname.filename, fsname.fileext ) )\r
1212     {\r
1213       f_filechangedevent( &fc );\r
1214     }\r
1215   }\r
1216 \r
1217  #endif\r
1218   return ret;\r
1219 } /* fn_rmdir */\r
1220 \r
1221 \r