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