]> git.sur5r.net Git - freertos/blob - FreeRTOS-Plus/Source/FreeRTOS-Plus-FAT-SL/fat_sl/common/dir.c
Add missing +TCP code.
[freertos] / FreeRTOS-Plus / Source / FreeRTOS-Plus-FAT-SL / fat_sl / common / dir.c
1 /*\r
2  * FreeRTOS+FAT SL V1.0.1 (C) 2014 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 != 5 || 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       {\r
210         return 0;\r
211       }\r
212     }\r
213 \r
214     {\r
215       unsigned long  nextcluster;\r
216       gl_volume.fatsector = (unsigned long)-1;\r
217       if ( _f_getclustervalue( pos->cluster, &nextcluster ) )\r
218       {\r
219         return 0;                                                          /*not found*/\r
220       }\r
221 \r
222       if ( nextcluster >= F_CLUSTER_RESERVED )\r
223       {\r
224         return 0;                                            /*eof*/\r
225       }\r
226 \r
227       _f_clustertopos( nextcluster, pos );\r
228     }\r
229   } /* _f_findfilewc */\r
230 \r
231   return 0;\r
232 }\r
233 \r
234 \r
235 /****************************************************************************\r
236  *\r
237  * _f_getfilename\r
238  *\r
239  * create a complete filename from name and extension\r
240  *\r
241  * INPUTS\r
242  *\r
243  * dest - where to store filename\r
244  * name - name of the file\r
245  * ext - extension of the file\r
246  *\r
247  ***************************************************************************/\r
248 static void _f_getfilename ( char * dest, char * name, char * ext )\r
249 {\r
250   unsigned char  a, len;\r
251 \r
252   for ( len = a = F_MAXNAME ; a ; a--, len-- )\r
253   {\r
254     if ( name[a - 1] != ' ' )\r
255     {\r
256       break;\r
257     }\r
258   }\r
259 \r
260   for ( a = 0 ; a < len ; a++ )\r
261   {\r
262     *dest++ = *name++;\r
263   }\r
264 \r
265 \r
266   for ( len = a = F_MAXEXT ; a ; a--, len-- )\r
267   {\r
268     if ( ext[a - 1] != ' ' )\r
269     {\r
270       break;\r
271     }\r
272   }\r
273 \r
274   if ( len )\r
275   {\r
276     *dest++ = '.';\r
277   }\r
278 \r
279   for ( a = 0 ; a < len ; a++ )\r
280   {\r
281     *dest++ = *ext++;\r
282   }\r
283 \r
284   *dest = 0; /*terminateit*/\r
285 } /* _f_getfilename */\r
286 \r
287 \r
288 \r
289 \r
290 /****************************************************************************\r
291  *\r
292  * _f_getdecluster\r
293  *\r
294  * get a directory entry structure start cluster value\r
295  *\r
296  * INPUTS\r
297  *\r
298  * de - directory entry\r
299  *\r
300  * RETURNS\r
301  *\r
302  * directory entry cluster value\r
303  *\r
304  ***************************************************************************/\r
305 unsigned long _f_getdecluster ( F_DIRENTRY * de )\r
306 {\r
307   unsigned long  cluster;\r
308 \r
309   if ( gl_volume.mediatype == F_FAT32_MEDIA )\r
310   {\r
311     cluster = _f_getword( &de->clusterhi );\r
312     cluster <<= 16;\r
313     cluster |= _f_getword( &de->clusterlo );\r
314     return cluster;\r
315   }\r
316 \r
317   return _f_getword( &de->clusterlo );\r
318 }\r
319 \r
320 \r
321 /****************************************************************************\r
322  *\r
323  * _f_setdecluster\r
324  *\r
325  * set a directory entry structure start cluster value\r
326  *\r
327  * INPUTS\r
328  *\r
329  * de - directory entry\r
330  * cluster - value of the start cluster\r
331  *\r
332  ***************************************************************************/\r
333 void _f_setdecluster ( F_DIRENTRY * de, unsigned long cluster )\r
334 {\r
335   _f_setword( &de->clusterlo, (unsigned short)( cluster & 0xffff ) );\r
336   if ( gl_volume.mediatype == F_FAT32_MEDIA )\r
337   {\r
338     _f_setword( &de->clusterhi, (unsigned short)( cluster >> 16 ) );\r
339   }\r
340   else\r
341   {\r
342     _f_setword( &de->clusterhi, (unsigned short)0 );\r
343   }\r
344 }\r
345 \r
346 \r
347 /****************************************************************************\r
348  *\r
349  * _f_findpath\r
350  *\r
351  * finding out if path is valid in F_NAME and\r
352  * correct path info with absolute path (removes relatives)\r
353  *\r
354  * INPUTS\r
355  *\r
356  * fsname - filled structure with path,drive\r
357  * pos - where to start searching, and contains current position\r
358  *\r
359  * RETURNS\r
360  *\r
361  * 0 - if path was not found or invalid\r
362  * 1 - if path was found\r
363  *\r
364  ***************************************************************************/\r
365 unsigned char _f_findpath ( F_NAME * fsname, F_POS * pos )\r
366 {\r
367   char       * path = fsname->path;\r
368   char       * mpath = path;\r
369   F_DIRENTRY * de;\r
370 \r
371   _f_clustertopos( 0, pos );\r
372 \r
373   for ( ; *path ; )\r
374   {\r
375     char           name[F_MAXNAME];\r
376     char           ext[F_MAXEXT];\r
377 \r
378     unsigned char  len = _f_setnameext( path, name, ext );\r
379 \r
380     if ( ( pos->cluster == 0 ) && ( len == 1 ) && ( name[0] == '.' ) )\r
381     {\r
382       _f_clustertopos( 0, pos );\r
383     }\r
384     else\r
385     {\r
386       if ( !_f_findfilewc( name, ext, pos, &de, 0 ) )\r
387       {\r
388         return 0;\r
389       }\r
390 \r
391       if ( !( de->attr & F_ATTR_DIR ) )\r
392       {\r
393         return 0;\r
394       }\r
395 \r
396       _f_clustertopos( _f_getdecluster( de ), pos );\r
397     }\r
398 \r
399 \r
400     if ( name[0] == '.' )\r
401     {\r
402       if ( len == 1 )\r
403       {\r
404         path += len;\r
405 \r
406         if ( !( *path ) )\r
407         {\r
408           if ( mpath != fsname->path )\r
409           {\r
410             mpath--;                                  /*if we are now at the top*/\r
411           }\r
412 \r
413           break;\r
414         }\r
415 \r
416         path++;\r
417         continue;\r
418       }\r
419 \r
420       if ( name[1] != '.' )\r
421       {\r
422         return 0;                       /*invalid name*/\r
423       }\r
424 \r
425       if ( len != 2 )\r
426       {\r
427         return 0;                 /*invalid name !*/\r
428       }\r
429 \r
430       path += len;\r
431 \r
432       if ( mpath == fsname->path )\r
433       {\r
434         return 0;                              /*we are in the top*/\r
435       }\r
436 \r
437       mpath--;       /*no on separator*/\r
438       for ( ; ; )\r
439       {\r
440         if ( mpath == fsname->path )\r
441         {\r
442           break;                                /*we are now at the top*/\r
443         }\r
444 \r
445         mpath--;\r
446         if ( *mpath == '/' )\r
447         {\r
448           mpath++;\r
449           break;\r
450         }\r
451       }\r
452 \r
453       if ( !( *path ) )\r
454       {\r
455         if ( mpath != fsname->path )\r
456         {\r
457           mpath--;                                /*if we are now at the top*/\r
458         }\r
459 \r
460         break;\r
461       }\r
462 \r
463       path++;\r
464       continue;\r
465     }\r
466     else\r
467     {\r
468       if ( path == mpath )                              /*if no was dots just step*/\r
469       {\r
470         path += len;\r
471         mpath += len;\r
472       }\r
473       else\r
474       {\r
475         unsigned char  a;\r
476         for ( a = 0 ; a < len ; a++ )\r
477         {\r
478           *mpath++ = *path++;                            /*copy if in different pos*/\r
479         }\r
480       }\r
481     }\r
482 \r
483     if ( !( *path ) )\r
484     {\r
485       break;\r
486     }\r
487 \r
488     path++;\r
489     *mpath++ = '/';   /*add separator*/\r
490   }\r
491 \r
492   *mpath = 0; /*terminate it*/\r
493   return 1;\r
494 } /* _f_findpath */\r
495 \r
496 \r
497 /****************************************************************************\r
498  *\r
499  * fn_getcwd\r
500  *\r
501  * getting a current working directory of current drive\r
502  *\r
503  * INPUTS\r
504  *\r
505  * buffer - where to store current working folder\r
506  * maxlen - buffer length (possible size is F_MAXPATH)\r
507  *\r
508  * RETURNS\r
509  *\r
510  * error code or zero if successful\r
511  *\r
512  ***************************************************************************/\r
513 unsigned char fn_getcwd ( char * buffer, unsigned char maxlen, char root )\r
514 {\r
515   unsigned char  a;\r
516 \r
517   if ( !maxlen )\r
518   {\r
519     return F_NO_ERROR;\r
520   }\r
521 \r
522   maxlen--;     /*need for termination*/\r
523   if ( root && maxlen )\r
524   {\r
525     *buffer++ = '/';\r
526     maxlen--;\r
527   }\r
528 \r
529   for ( a = 0 ; a < maxlen ; a++ )\r
530   {\r
531     char  ch = gl_volume.cwd[a];\r
532     buffer[a] = ch;\r
533     if ( !ch )\r
534     {\r
535       break;\r
536     }\r
537   }\r
538 \r
539   buffer[a] = 0;    /*add terminator at the end*/\r
540 \r
541   return F_NO_ERROR;\r
542 } /* fn_getcwd */\r
543 \r
544 \r
545 \r
546 /****************************************************************************\r
547  *\r
548  * fn_findfirst\r
549  *\r
550  * find a file(s) or directory(s) in directory\r
551  *\r
552  * INPUTS\r
553  *\r
554  * filename - filename (with or without wildcards)\r
555  * find - where to store found file information\r
556  *\r
557  * RETURNS\r
558  *\r
559  * error code or zero if successful\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 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       {\r
829         return F_ERR_NOMOREENTRY;\r
830       }\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