]> git.sur5r.net Git - freertos/blob - FreeRTOS-Plus/Source/FreeRTOS-Plus-FAT-SL/fat_sl/common/file.c
Add missing +TCP code.
[freertos] / FreeRTOS-Plus / Source / FreeRTOS-Plus-FAT-SL / fat_sl / common / file.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 "util.h"\r
45 #include "volume.h"\r
46 #include "drv.h"\r
47 #include "fat.h"\r
48 #include "dir.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 static unsigned char _f_stepnextsector ( void );\r
57 \r
58 \r
59 /****************************************************************************\r
60  *\r
61  * fn_filelength\r
62  *\r
63  * Get a file length\r
64  *\r
65  * INPUTS\r
66  *\r
67  * filename - file whose length is needed\r
68  *\r
69  * RETURNS\r
70  *\r
71  * length of the file\r
72  *\r
73  ***************************************************************************/\r
74 \r
75 long fn_filelength ( const char * filename )\r
76 {\r
77   F_POS        pos;\r
78   F_DIRENTRY * de;\r
79   F_NAME       fsname;\r
80 \r
81   if ( _f_setfsname( filename, &fsname ) )\r
82   {\r
83     return 0;                                     /*invalid name*/\r
84   }\r
85 \r
86   if ( _f_checknamewc( fsname.filename, fsname.fileext ) )\r
87   {\r
88     return 0;                                                    /*invalid name*/\r
89   }\r
90 \r
91   if ( _f_getvolume() )\r
92   {\r
93     return 0;                     /*can't get the size*/\r
94   }\r
95 \r
96   if ( !_f_findpath( &fsname, &pos ) )\r
97   {\r
98     return 0;\r
99   }\r
100 \r
101   if ( !_f_findfilewc( fsname.filename, fsname.fileext, &pos, &de, 0 ) )\r
102   {\r
103     return 0;\r
104   }\r
105 \r
106   if ( de->attr & F_ATTR_DIR )\r
107   {\r
108     return 0;                                           /*directory*/\r
109   }\r
110 \r
111   return (long)_f_getlong( &de->filesize );\r
112 } /* fn_filelength */\r
113 \r
114 \r
115 \r
116 \r
117 \r
118 /****************************************************************************\r
119  *\r
120  * _f_emptywritebuffer\r
121  *\r
122  * empty write buffer if it contains unwritten data\r
123  *\r
124  * RETURNS\r
125  * error code or zero if successful\r
126  *\r
127  ***************************************************************************/\r
128 static unsigned char _f_stepnextsector ( void )\r
129 {\r
130   unsigned char  ret;\r
131   unsigned char  b_alloc;\r
132 \r
133   b_alloc = 0;\r
134   gl_volume.fatsector = (unsigned long)-1;\r
135   if ( gl_file.startcluster == 0 )\r
136   {\r
137     b_alloc = 1;\r
138   }\r
139   else\r
140   {\r
141     ++gl_file.pos.sector;\r
142     if ( gl_file.pos.sector >= gl_file.pos.sectorend )\r
143     {\r
144       unsigned long  value;\r
145 \r
146       ret = _f_getclustervalue( gl_file.pos.cluster, &value );\r
147       if ( ret )\r
148       {\r
149         return ret;\r
150       }\r
151 \r
152       if ( ( value >= 2 ) && ( value < F_CLUSTER_RESERVED ) ) /*we are in chain*/\r
153       {\r
154         _f_clustertopos( value, &gl_file.pos );    /*go to next cluster*/\r
155       }\r
156       else\r
157       {\r
158         b_alloc = 1;\r
159       }\r
160     }\r
161   }\r
162 \r
163   if ( b_alloc != 0 )\r
164   {\r
165     unsigned long  nextcluster;\r
166 \r
167     ret = _f_alloccluster( &nextcluster );\r
168     if ( ret )\r
169     {\r
170       return ret;\r
171     }\r
172 \r
173     ret = _f_setclustervalue( nextcluster, F_CLUSTER_LAST );\r
174     if ( ret )\r
175     {\r
176       return ret;\r
177     }\r
178 \r
179     if ( gl_file.startcluster == 0 )\r
180     {\r
181       gl_file.startcluster = nextcluster;\r
182     }\r
183     else\r
184     {\r
185       ret = _f_setclustervalue( gl_file.pos.cluster, nextcluster );\r
186       if ( ret )\r
187       {\r
188         return ret;\r
189       }\r
190     }\r
191 \r
192     _f_clustertopos( nextcluster, &gl_file.pos );\r
193 \r
194     return _f_writefatsector();\r
195   }\r
196 \r
197   return F_NO_ERROR;\r
198 } /* _f_stepnextsector */\r
199 \r
200 \r
201 /****************************************************************************\r
202  *\r
203  * _f_extend\r
204  *\r
205  * Extend file to a certain size\r
206  *\r
207  ***************************************************************************/\r
208 static unsigned char _f_extend ( long size )\r
209 {\r
210   unsigned long  _size;\r
211   unsigned char  rc;\r
212 \r
213   size -= gl_file.filesize;\r
214   _size = (unsigned long)size;\r
215 \r
216   if ( gl_file.startcluster == 0 )\r
217   {\r
218     if ( _f_stepnextsector() )\r
219     {\r
220       return F_ERR_WRITE;\r
221     }\r
222   }\r
223   else\r
224   {\r
225     if ( ( gl_file.relpos > 0 ) && ( gl_file.relpos < F_SECTOR_SIZE ) )\r
226     {\r
227       rc = _f_getcurrsector();\r
228       if ( rc )\r
229       {\r
230         return rc;\r
231       }\r
232     }\r
233   }\r
234 \r
235   if ( gl_file.relpos + _size >= F_SECTOR_SIZE )\r
236   {\r
237     if ( gl_file.relpos < F_SECTOR_SIZE )\r
238     {\r
239       psp_memset( gl_sector + gl_file.relpos, 0, ( F_SECTOR_SIZE - gl_file.relpos ) );\r
240       _size -= ( F_SECTOR_SIZE - gl_file.relpos );\r
241 \r
242       if ( _f_writeglsector( gl_file.pos.sector ) )\r
243       {\r
244         return F_ERR_WRITE;\r
245       }\r
246     }\r
247 \r
248     if ( _f_stepnextsector() )\r
249     {\r
250       return F_ERR_WRITE;\r
251     }\r
252 \r
253     psp_memset( gl_sector, 0, F_SECTOR_SIZE );\r
254 \r
255     while ( _size >= F_SECTOR_SIZE )\r
256     {\r
257       if ( _f_writeglsector( gl_file.pos.sector ) )\r
258       {\r
259         return F_ERR_WRITE;\r
260       }\r
261 \r
262       if ( _f_stepnextsector() )\r
263       {\r
264         return F_ERR_WRITE;\r
265       }\r
266 \r
267       psp_memset( gl_sector, 0, F_SECTOR_SIZE );\r
268 \r
269       _size -= F_SECTOR_SIZE;\r
270     }\r
271   }\r
272   else\r
273   {\r
274     psp_memset( gl_sector + gl_file.relpos, 0, ( F_SECTOR_SIZE - gl_file.relpos ) );\r
275     _size += gl_file.relpos;\r
276   }\r
277 \r
278   gl_file.modified = 1;\r
279   gl_file.filesize += size;\r
280   gl_file.abspos = gl_file.filesize & ( ~( F_SECTOR_SIZE - 1 ) );\r
281   gl_file.relpos = _size;\r
282 \r
283   return F_NO_ERROR;\r
284 } /* _f_extend */\r
285 \r
286 \r
287 \r
288 /****************************************************************************\r
289  *\r
290  * _f_fseek\r
291  *\r
292  * subfunction for f_seek it moves position into given offset and read\r
293  * the current sector\r
294  *\r
295  * INPUTS\r
296  * offset - position from start\r
297  *\r
298  * RETURNS\r
299  *\r
300  * error code or zero if successful\r
301  *\r
302  ***************************************************************************/\r
303 static unsigned char _f_fseek ( long offset )\r
304 {\r
305   unsigned long  cluster;\r
306   unsigned long  tmp;\r
307   unsigned char  ret = F_NO_ERROR;\r
308   long           remain;\r
309 \r
310   if ( offset < 0 )\r
311   {\r
312     offset = 0;\r
313   }\r
314 \r
315   if ( ( (unsigned long) offset <= gl_file.filesize )\r
316        && ( (unsigned long) offset >= gl_file.abspos )\r
317        && ( (unsigned long) offset < gl_file.abspos + F_SECTOR_SIZE ) )\r
318   {\r
319     gl_file.relpos = (unsigned short)( offset - gl_file.abspos );\r
320   }\r
321   else\r
322   {\r
323     if ( gl_file.modified )\r
324     {\r
325       ret = _f_writeglsector( (unsigned long)-1 );\r
326       if ( ret )\r
327       {\r
328         gl_file.mode = F_FILE_CLOSE; /*cant accessed any more*/\r
329         return ret;\r
330       }\r
331     }\r
332 \r
333     if ( gl_file.startcluster )\r
334     {\r
335       gl_file.abspos = 0;\r
336       gl_file.relpos = 0;\r
337       gl_file.pos.cluster = gl_file.startcluster;\r
338       remain = gl_file.filesize;\r
339 \r
340       tmp = gl_volume.bootrecord.sector_per_cluster;\r
341       tmp *= F_SECTOR_SIZE;   /* set to cluster size */\r
342 \r
343       /*calc cluster*/\r
344       gl_volume.fatsector = (unsigned long)-1;\r
345       while ( (unsigned long)offset >= tmp )\r
346       {\r
347         ret = _f_getclustervalue( gl_file.pos.cluster, &cluster );\r
348         if ( ret )\r
349         {\r
350           gl_file.mode = F_FILE_CLOSE;\r
351           return ret;\r
352         }\r
353 \r
354         if ( (long) tmp >= remain )\r
355         {\r
356           break;\r
357         }\r
358 \r
359         remain -= tmp;\r
360         offset -= tmp;\r
361         gl_file.abspos += tmp;\r
362         if ( cluster >= F_CLUSTER_RESERVED )\r
363         {\r
364           break;\r
365         }\r
366 \r
367         gl_file.pos.cluster = cluster;\r
368       }\r
369 \r
370       _f_clustertopos( gl_file.pos.cluster, &gl_file.pos );\r
371       if ( remain && offset )\r
372       {\r
373         while ( ( offset > (long) F_SECTOR_SIZE )\r
374                && ( remain > (long) F_SECTOR_SIZE ) )\r
375         {\r
376           gl_file.pos.sector++;\r
377           offset -= F_SECTOR_SIZE;\r
378           remain -= F_SECTOR_SIZE;\r
379           gl_file.abspos += F_SECTOR_SIZE;\r
380         }\r
381       }\r
382 \r
383       if ( remain < offset )\r
384       {\r
385         gl_file.relpos = (unsigned short)remain;\r
386         ret = _f_extend( gl_file.filesize + offset - remain );\r
387       }\r
388       else\r
389       {\r
390         gl_file.relpos = (unsigned short)offset;\r
391       }\r
392     }\r
393     else\r
394     {\r
395       ret = _f_extend( offset );\r
396     }\r
397   }\r
398 \r
399   return ret;\r
400 } /* _f_fseek */\r
401 \r
402 \r
403 \r
404 /****************************************************************************\r
405  *\r
406  * fn_open\r
407  *\r
408  * open a file for reading/writing/appending\r
409  *\r
410  * INPUTS\r
411  *\r
412  * filename - which file need to be opened\r
413  * mode - string how to open ("r"-read, "w"-write, "w+"-overwrite, "a"-append\r
414  *\r
415  * RETURNS\r
416  *\r
417  * F_FILE pointer if successfully\r
418  * 0 - if any error\r
419  *\r
420  ***************************************************************************/\r
421 F_FILE * fn_open ( const char * filename, const char * mode )\r
422 {\r
423   F_DIRENTRY    * de;\r
424   F_NAME          fsname;\r
425   unsigned short  date;\r
426   unsigned short  time;\r
427   unsigned char   m_mode = F_FILE_CLOSE;\r
428 \r
429   if ( mode[1] == 0 )\r
430   {\r
431     if ( mode[0] == 'r' )\r
432     {\r
433       m_mode = F_FILE_RD;\r
434     }\r
435 \r
436     if ( mode[0] == 'w' )\r
437     {\r
438       m_mode = F_FILE_WR;\r
439     }\r
440 \r
441     if ( mode[0] == 'a' )\r
442     {\r
443       m_mode = F_FILE_A;\r
444     }\r
445   }\r
446 \r
447   if ( ( mode[1] == '+' ) && ( mode[2] == 0 ) )\r
448   {\r
449     if ( mode[0] == 'r' )\r
450     {\r
451       m_mode = F_FILE_RDP;\r
452     }\r
453 \r
454     if ( mode[0] == 'w' )\r
455     {\r
456       m_mode = F_FILE_WRP;\r
457     }\r
458 \r
459     if ( mode[0] == 'a' )\r
460     {\r
461       m_mode = F_FILE_AP;\r
462     }\r
463 \r
464   }\r
465 \r
466   if ( m_mode == F_FILE_CLOSE )\r
467   {\r
468     return 0;                                       /*invalid mode*/\r
469   }\r
470 \r
471   if ( _f_setfsname( filename, &fsname ) )\r
472   {\r
473     return 0;                                     /*invalid name*/\r
474   }\r
475 \r
476   if ( _f_checknamewc( fsname.filename, fsname.fileext ) )\r
477   {\r
478     return 0;                                                    /*invalid name*/\r
479   }\r
480 \r
481   if ( fsname.filename[0] == '.' )\r
482   {\r
483     return 0;\r
484   }\r
485 \r
486   if ( _f_getvolume() )\r
487   {\r
488     return 0;                     /*cant open any*/\r
489   }\r
490 \r
491   if ( gl_file.mode != F_FILE_CLOSE )\r
492   {\r
493     return 0;\r
494   }\r
495 \r
496   psp_memset( &gl_file, 0, sizeof( F_FILE ) );\r
497 \r
498   if ( !_f_findpath( &fsname, &gl_file.dirpos ) )\r
499   {\r
500     return 0;\r
501   }\r
502 \r
503   switch ( m_mode )\r
504   {\r
505     case F_FILE_RDP:   /*r*/\r
506     case F_FILE_RD:   /*r*/\r
507       if ( !_f_findfilewc( fsname.filename, fsname.fileext, &gl_file.dirpos, &de, 0 ) )\r
508       {\r
509         return 0;\r
510       }\r
511 \r
512       if ( de->attr & F_ATTR_DIR )\r
513       {\r
514         return 0;                                      /*directory*/\r
515       }\r
516 \r
517       gl_file.startcluster = _f_getdecluster( de );\r
518 \r
519       if ( gl_file.startcluster )\r
520       {\r
521         _f_clustertopos( gl_file.startcluster, &gl_file.pos );\r
522         gl_file.filesize = _f_getlong( &de->filesize );\r
523         gl_file.abspos = (unsigned long) (-1 * (long) F_SECTOR_SIZE);\r
524         if ( _f_fseek( 0 ) )\r
525         {\r
526           return 0;\r
527         }\r
528       }\r
529 \r
530 #if F_FILE_CHANGED_EVENT\r
531       if ( m_mode == F_FILE_RDP )\r
532       {\r
533         _f_createfullname( gl_file.filename, sizeof( gl_file.filename ), fsname.path, fsname.filename, fsname.fileext );\r
534       }\r
535 \r
536 #endif\r
537 \r
538       break;\r
539 \r
540     case F_FILE_AP:\r
541     case F_FILE_A: /*a*/\r
542       psp_memcpy( &( gl_file.pos ), &( gl_file.dirpos ), sizeof( F_POS ) );\r
543       if ( _f_findfilewc( fsname.filename, fsname.fileext, &gl_file.dirpos, &de, 0 ) )\r
544       {\r
545         if ( de->attr & ( F_ATTR_DIR | F_ATTR_READONLY ) )\r
546         {\r
547           return 0;\r
548         }\r
549 \r
550         gl_file.startcluster = _f_getdecluster( de );\r
551         gl_file.filesize = _f_getlong( &de->filesize );\r
552 \r
553         if ( gl_file.startcluster )\r
554         {\r
555           _f_clustertopos( gl_file.startcluster, &gl_file.pos );\r
556           gl_file.abspos = (unsigned long) (-1 * (long) F_SECTOR_SIZE);   /*forcing seek to read 1st sector! abspos=0;*/\r
557           if ( _f_fseek( (long)gl_file.filesize ) )\r
558           {\r
559             gl_file.mode = F_FILE_CLOSE;\r
560             return 0;\r
561           }\r
562         }\r
563       }\r
564       else\r
565       {\r
566         psp_memcpy( &( gl_file.dirpos ), &( gl_file.pos ), sizeof( F_POS ) );\r
567         _f_clustertopos( gl_file.dirpos.cluster, &gl_file.pos );\r
568 \r
569         if ( _f_addentry( &fsname, &gl_file.dirpos, &de ) )\r
570         {\r
571           return 0;                                                  /*couldnt be added*/\r
572         }\r
573 \r
574         de->attr |= F_ATTR_ARC;         /*set as archiv*/\r
575         if ( _f_writeglsector( (unsigned long)-1 ) )\r
576         {\r
577           return 0;\r
578         }\r
579       }\r
580 \r
581  #if F_FILE_CHANGED_EVENT\r
582       _f_createfullname( gl_file.filename, sizeof( gl_file.filename ), fsname.path, fsname.filename, fsname.fileext );\r
583  #endif\r
584       break;\r
585 \r
586 \r
587     case F_FILE_WR:  /*w*/\r
588     case F_FILE_WRP: /*w+*/\r
589       _f_clustertopos( gl_file.dirpos.cluster, &gl_file.pos );\r
590       if ( _f_findfilewc( fsname.filename, fsname.fileext, &gl_file.pos, &de, 0 ) )\r
591       {\r
592         unsigned long  cluster = _f_getdecluster( de );    /*exist*/\r
593 \r
594         if ( de->attr & ( F_ATTR_DIR | F_ATTR_READONLY ) )\r
595         {\r
596           return 0;\r
597         }\r
598 \r
599         psp_memcpy( &( gl_file.dirpos ), &( gl_file.pos ), sizeof( F_POS ) );\r
600 \r
601         _f_setlong( de->filesize, 0 );  /*reset size;*/\r
602         de->attr |= F_ATTR_ARC;         /*set as archiv*/\r
603         _f_setword( de->clusterlo, 0 ); /*no points anywhere*/\r
604         _f_setword( de->clusterhi, 0 );\r
605 \r
606         if ( gl_volume.mediatype == F_FAT32_MEDIA )\r
607         {\r
608           f_igettimedate( &time, &date );\r
609           _f_setword( &de->crtdate, date );        /*if there is realtime clock then creation date could be set from*/\r
610           _f_setword( &de->crttime, time );        /*if there is realtime clock then creation time could be set from*/\r
611           _f_setword( &de->lastaccessdate, date ); /*if there is realtime clock then creation date could be set from*/\r
612         }\r
613 \r
614         if ( _f_writeglsector( (unsigned long)-1 ) )\r
615         {\r
616           return 0;\r
617         }\r
618 \r
619         if ( _f_removechain( cluster ) )\r
620         {\r
621           return 0;                                /*remove */\r
622         }\r
623       }\r
624       else\r
625       {\r
626         if ( _f_addentry( &fsname, &gl_file.dirpos, &de ) )\r
627         {\r
628           return 0;                                                  /*couldnt be added*/\r
629         }\r
630 \r
631         psp_memset( &gl_file, 0, 21 );\r
632         de->attr |= F_ATTR_ARC;         /*set as archiv*/\r
633         if ( _f_writeglsector( (unsigned long)-1 ) )\r
634         {\r
635           return 0;\r
636         }\r
637       }\r
638 \r
639  #if F_FILE_CHANGED_EVENT\r
640       _f_createfullname( gl_file.filename, sizeof( gl_file.filename ), fsname.path, fsname.filename, fsname.fileext );\r
641  #endif\r
642 \r
643       break;\r
644 \r
645     default:\r
646       return 0;        /*invalid mode*/\r
647   } /* switch */\r
648 \r
649   gl_file.mode = m_mode; /* lock it */\r
650   return (F_FILE *)1;\r
651 } /* fn_open */\r
652 \r
653 \r
654 /****************************************************************************\r
655  * _f_updatefileentry\r
656  * Updated a file directory entry or removes the entry\r
657  * and the fat chain belonging to it.\r
658  ***************************************************************************/\r
659 static unsigned char _f_updatefileentry ( int remove )\r
660 {\r
661   F_DIRENTRY    * de;\r
662   unsigned short  date;\r
663   unsigned short  time;\r
664 \r
665   de = (F_DIRENTRY *)( gl_sector + sizeof( F_DIRENTRY ) * gl_file.dirpos.pos );\r
666   if ( _f_readglsector( gl_file.dirpos.sector ) || remove )\r
667   {\r
668     _f_setdecluster( de, 0 );\r
669     _f_setlong( &de->filesize, 0 );\r
670     (void)_f_writeglsector( (unsigned long)-1 );\r
671     (void)_f_removechain( gl_file.startcluster );\r
672     return F_ERR_WRITE;\r
673   }\r
674 \r
675   _f_setdecluster( de, gl_file.startcluster );\r
676   _f_setlong( &de->filesize, gl_file.filesize );\r
677   f_igettimedate( &time, &date );\r
678   _f_setword( &de->cdate, date );  /*if there is realtime clock then creation date could be set from*/\r
679   _f_setword( &de->ctime, time );  /*if there is realtime clock then creation time could be set from*/\r
680   if ( gl_volume.mediatype == F_FAT32_MEDIA )\r
681   {\r
682     _f_setword( &de->lastaccessdate, date );  /*if there is realtime clock then creation date could be set from*/\r
683   }\r
684 \r
685   return _f_writeglsector( (unsigned long)-1 );\r
686 } /* _f_updatefileentry */\r
687 \r
688 \r
689 /****************************************************************************\r
690  *\r
691  * fn_close\r
692  *\r
693  * close a previously opened file\r
694  *\r
695  * INPUTS\r
696  *\r
697  * filehandle - which file needs to be closed\r
698  *\r
699  * RETURNS\r
700  *\r
701  * error code or zero if successful\r
702  *\r
703  ***************************************************************************/\r
704 unsigned char fn_close ( F_FILE * f )\r
705 {\r
706   unsigned char  ret;\r
707 \r
708 #if F_FILE_CHANGED_EVENT\r
709   unsigned char  mode;\r
710 #endif\r
711 \r
712   if ( !f )\r
713   {\r
714     return F_ERR_NOTOPEN;\r
715   }\r
716 \r
717   ret = _f_getvolume();\r
718   if ( ret )\r
719   {\r
720     return ret;\r
721   }\r
722 \r
723   if ( gl_file.mode == F_FILE_CLOSE )\r
724   {\r
725     return F_ERR_NOTOPEN;\r
726   }\r
727 \r
728   else if ( gl_file.mode == F_FILE_RD )\r
729   {\r
730     gl_file.mode = F_FILE_CLOSE;\r
731     return F_NO_ERROR;\r
732   }\r
733   else\r
734   {\r
735  #if F_FILE_CHANGED_EVENT\r
736     mode = f->mode;\r
737  #endif\r
738     gl_file.mode = F_FILE_CLOSE;\r
739 \r
740     if ( gl_file.modified )\r
741     {\r
742       if ( _f_writeglsector( (unsigned long)-1 ) )\r
743       {\r
744         (void)_f_updatefileentry( 1 );\r
745         return F_ERR_WRITE;\r
746       }\r
747     }\r
748 \r
749     ret = _f_updatefileentry( 0 );\r
750 \r
751  #if F_FILE_CHANGED_EVENT\r
752     if ( f_filechangedevent && !ret )\r
753     {\r
754       ST_FILE_CHANGED  fc;\r
755       if ( ( mode == F_FILE_WR )  || ( mode == F_FILE_WRP ) )\r
756       {\r
757         fc.action = FACTION_ADDED;\r
758         fc.flags  = FFLAGS_FILE_NAME;\r
759       }\r
760       else if ( ( mode == F_FILE_A )  || ( mode == F_FILE_RDP ) )\r
761       {\r
762         fc.action = FACTION_MODIFIED;\r
763         fc.flags  = FFLAGS_FILE_NAME | FFLAGS_SIZE;\r
764       }\r
765 \r
766       strcpy( fc.filename, f->filename );\r
767       if ( f->filename[0] )\r
768       {\r
769         f_filechangedevent( &fc );\r
770       }\r
771 \r
772       f->filename[0] = '\0';\r
773     }\r
774 \r
775  #endif /* if F_FILE_CHANGED_EVENT */\r
776     return ret;\r
777   }\r
778 } /* fn_close */\r
779 \r
780 \r
781 /****************************************************************************\r
782  *\r
783  * fn_flush\r
784  *\r
785  * flush a previously opened file\r
786  *\r
787  * INPUTS\r
788  *\r
789  * filehandle - which file needs to be closed\r
790  *\r
791  * RETURNS\r
792  *\r
793  * error code or zero if successful\r
794  *\r
795  ***************************************************************************/\r
796 unsigned char fn_flush ( F_FILE * f )\r
797 {\r
798   unsigned char  ret;\r
799 \r
800   if ( !f )\r
801   {\r
802     return F_ERR_NOTOPEN;\r
803   }\r
804 \r
805   ret = _f_getvolume();\r
806   if ( ret )\r
807   {\r
808     return ret;\r
809   }\r
810 \r
811   if ( gl_file.mode == F_FILE_CLOSE )\r
812   {\r
813     return F_ERR_NOTOPEN;\r
814   }\r
815   else if ( gl_file.mode != F_FILE_RD )\r
816   {\r
817     if ( gl_file.modified )\r
818     {\r
819       if ( _f_writeglsector( (unsigned long)-1 ) )\r
820       {\r
821         (void)_f_updatefileentry( 1 );\r
822         return F_ERR_WRITE;\r
823       }\r
824     }\r
825 \r
826     return _f_updatefileentry( 0 );\r
827   }\r
828 \r
829   return F_NO_ERROR;\r
830 } /* fn_flush */\r
831 \r
832 \r
833 /****************************************************************************\r
834  *\r
835  * fn_read\r
836  *\r
837  * read data from file\r
838  *\r
839  * INPUTS\r
840  *\r
841  * buf - where the store data\r
842  * size - size of items to be read\r
843  * _size_t - number of items need to be read\r
844  * filehandle - file where to read from\r
845  *\r
846  * RETURNS\r
847  *\r
848  * with the number of read bytes\r
849  *\r
850  ***************************************************************************/\r
851 long fn_read ( void * buf, long size, long _size_st, F_FILE * f )\r
852 {\r
853   char * buffer = (char *)buf;\r
854   long   retsize;\r
855 \r
856   if ( !f )\r
857   {\r
858     return 0;\r
859   }\r
860 \r
861   if ( ( gl_file.mode & ( F_FILE_RD | F_FILE_RDP | F_FILE_WRP | F_FILE_AP ) ) == 0 )\r
862   {\r
863     return 0;\r
864   }\r
865 \r
866   retsize = size;\r
867   size *= _size_st;\r
868   _size_st = retsize;\r
869   retsize = 0;\r
870 \r
871   if ( _f_getvolume() )\r
872   {\r
873     return 0;                     /*cant read any*/\r
874   }\r
875 \r
876   if ( size + gl_file.relpos + gl_file.abspos >= gl_file.filesize ) /*read len longer than the file*/\r
877   {\r
878     size = (long)( ( gl_file.filesize ) - ( gl_file.relpos ) - ( gl_file.abspos ) ); /*calculate new size*/\r
879   }\r
880 \r
881   if ( size <= 0 )\r
882   {\r
883     return 0;\r
884   }\r
885 \r
886   if ( _f_getcurrsector() )\r
887   {\r
888     gl_file.mode = F_FILE_CLOSE; /*no more read allowed*/\r
889     return 0;\r
890   }\r
891 \r
892   for( ; ; )\r
893   {\r
894     unsigned long  rdsize = (unsigned long)size;\r
895 \r
896     if ( gl_file.relpos == F_SECTOR_SIZE )\r
897     {\r
898       unsigned char  ret;\r
899 \r
900       gl_file.abspos += gl_file.relpos;\r
901       gl_file.relpos = 0;\r
902 \r
903       if ( gl_file.modified )\r
904       {\r
905         ret = _f_writeglsector( (unsigned long)-1 );     /*empty write buffer */\r
906         if ( ret )\r
907         {\r
908           gl_file.mode = F_FILE_CLOSE;         /*no more read allowed*/\r
909           return retsize;\r
910         }\r
911       }\r
912 \r
913       gl_file.pos.sector++;         /*goto next*/\r
914 \r
915       ret = _f_getcurrsector();\r
916       if ( ( ret == F_ERR_EOF ) && ( !size ) )\r
917       {\r
918         return retsize;\r
919       }\r
920 \r
921       if ( ret )\r
922       {\r
923         gl_file.mode = F_FILE_CLOSE;       /*no more read allowed*/\r
924         return retsize;\r
925       }\r
926     }\r
927 \r
928     if ( !size )\r
929     {\r
930       break;\r
931     }\r
932 \r
933     if ( rdsize >= F_SECTOR_SIZE - gl_file.relpos )\r
934     {\r
935       rdsize = (unsigned long)( F_SECTOR_SIZE - gl_file.relpos );\r
936     }\r
937 \r
938     psp_memcpy( buffer, gl_sector + gl_file.relpos, rdsize ); /*always less than 512*/\r
939 \r
940     buffer += rdsize;\r
941     gl_file.relpos += rdsize;\r
942     size -= rdsize;\r
943     retsize += rdsize;\r
944   }\r
945 \r
946   return retsize / _size_st;\r
947 } /* fn_read */\r
948 \r
949 \r
950 /****************************************************************************\r
951  *\r
952  * fn_write\r
953  *\r
954  * write data into file\r
955  *\r
956  * INPUTS\r
957  *\r
958  * buf - where the store data\r
959  * size - size of items to be read\r
960  * size_t - number of items need to be read\r
961  * filehandle - file where to read from\r
962  *\r
963  * RETURNS\r
964  *\r
965  * with the number of read bytes\r
966  *\r
967  ***************************************************************************/\r
968 \r
969 long fn_write ( const void * buf, long size, long _size_st, F_FILE * f )\r
970 {\r
971   char * buffer = (char *)buf;\r
972   long   retsize;\r
973   long   ret = 0;\r
974 \r
975   if ( !f )\r
976   {\r
977     return 0;\r
978   }\r
979 \r
980   if ( ( gl_file.mode & ( F_FILE_WR | F_FILE_A | F_FILE_RDP | F_FILE_WRP | F_FILE_AP ) ) == 0 )\r
981   {\r
982     return 0;\r
983   }\r
984 \r
985   retsize = size;\r
986   size *= _size_st;\r
987   _size_st = retsize;\r
988   retsize = 0;\r
989 \r
990   if ( size == 0 )\r
991   {\r
992     return 0;\r
993   }\r
994 \r
995   if ( _f_getvolume() )\r
996   {\r
997     return 0;                     /*can't write*/\r
998   }\r
999 \r
1000   if ( ( gl_file.mode ) & ( F_FILE_A | F_FILE_AP ) )\r
1001   {\r
1002     if ( _f_fseek( (long)gl_file.filesize ) )\r
1003     {\r
1004       gl_file.mode = F_FILE_CLOSE;\r
1005       return 0;\r
1006     }\r
1007   }\r
1008 \r
1009   if ( gl_file.startcluster == 0 )\r
1010   {\r
1011     if ( _f_stepnextsector() )\r
1012     {\r
1013       gl_file.mode = F_FILE_CLOSE;\r
1014       return 0;\r
1015     }\r
1016   }\r
1017   else\r
1018   {\r
1019     if ( _f_getcurrsector() )\r
1020     {\r
1021       gl_file.mode = F_FILE_CLOSE;\r
1022       return 0;\r
1023     }\r
1024   }\r
1025 \r
1026   for( ; ; )\r
1027   {\r
1028     unsigned long  wrsize = (unsigned long)size;\r
1029 \r
1030     if ( gl_file.relpos == F_SECTOR_SIZE )\r
1031     {     /*now full*/\r
1032       if ( gl_file.modified )\r
1033       {\r
1034         if ( _f_writeglsector( gl_file.pos.sector ) )\r
1035         {\r
1036           gl_file.mode = F_FILE_CLOSE;\r
1037           if ( _f_updatefileentry( 0 ) == 0 )\r
1038           {\r
1039             return retsize;\r
1040           }\r
1041           else\r
1042           {\r
1043             return 0;\r
1044           }\r
1045         }\r
1046 \r
1047         gl_file.modified = 0;\r
1048       }\r
1049 \r
1050       if ( _f_stepnextsector() )\r
1051       {\r
1052         gl_file.mode = F_FILE_CLOSE;\r
1053         if ( _f_updatefileentry( 0 ) == 0 )\r
1054         {\r
1055           return retsize;\r
1056         }\r
1057         else\r
1058         {\r
1059           return 0;\r
1060         }\r
1061       }\r
1062 \r
1063       gl_file.abspos += gl_file.relpos;\r
1064       gl_file.relpos = 0;\r
1065 \r
1066       if ( wrsize && ( wrsize < F_SECTOR_SIZE ) )\r
1067       {\r
1068         ret = _f_getcurrsector();\r
1069 \r
1070         if ( ret )\r
1071         {\r
1072           if ( ret != F_ERR_EOF )\r
1073           {\r
1074             gl_file.mode = F_FILE_CLOSE;       /*no more read allowed*/\r
1075             return retsize;\r
1076           }\r
1077         }\r
1078       }\r
1079     }\r
1080 \r
1081     if ( !size )\r
1082     {\r
1083       break;\r
1084     }\r
1085 \r
1086     if ( wrsize >= F_SECTOR_SIZE - gl_file.relpos )\r
1087     {\r
1088       wrsize = (unsigned long)( F_SECTOR_SIZE - gl_file.relpos );\r
1089     }\r
1090 \r
1091 \r
1092     psp_memcpy( gl_sector + gl_file.relpos, buffer, wrsize );\r
1093     gl_file.modified = 1;    /*sector is modified*/\r
1094 \r
1095     buffer += wrsize;\r
1096     gl_file.relpos += wrsize;\r
1097     size -= wrsize;\r
1098     retsize += wrsize;\r
1099 \r
1100     if ( gl_file.filesize < gl_file.abspos + gl_file.relpos )\r
1101     {\r
1102       gl_file.filesize = gl_file.abspos + gl_file.relpos;\r
1103     }\r
1104   }\r
1105 \r
1106   return retsize / _size_st;\r
1107 } /* fn_write */\r
1108 \r
1109 \r
1110 \r
1111 /****************************************************************************\r
1112  *\r
1113  * fn_seek\r
1114  *\r
1115  * moves position into given offset in given file\r
1116  *\r
1117  * INPUTS\r
1118  *\r
1119  * filehandle - F_FILE structure which file position needed to be modified\r
1120  * offset - relative position\r
1121  * whence - where to calculate position (F_SEEK_SET,F_SEEK_CUR,F_SEEK_END)\r
1122  *\r
1123  * RETURNS\r
1124  *\r
1125  * 0 - if successfully\r
1126  * other - if any error\r
1127  *\r
1128  ***************************************************************************/\r
1129 \r
1130 \r
1131 unsigned char fn_seek ( F_FILE * f, long offset, unsigned char whence )\r
1132 {\r
1133   unsigned char  ret;\r
1134 \r
1135   if ( !f )\r
1136   {\r
1137     return F_ERR_NOTOPEN;\r
1138   }\r
1139 \r
1140   if ( ( gl_file.mode & ( F_FILE_RD | F_FILE_WR | F_FILE_A | F_FILE_RDP | F_FILE_WRP | F_FILE_AP ) ) == 0 )\r
1141   {\r
1142     return F_ERR_NOTOPEN;\r
1143   }\r
1144 \r
1145   ret = _f_getvolume();\r
1146   if ( ret )\r
1147   {\r
1148     return ret;\r
1149   }\r
1150 \r
1151   if ( whence == F_SEEK_CUR )\r
1152   {\r
1153     return _f_fseek( (long)( gl_file.abspos + gl_file.relpos + offset ) );\r
1154   }\r
1155   else if ( whence == F_SEEK_END )\r
1156   {\r
1157     return _f_fseek( (long)( gl_file.filesize + offset ) );\r
1158   }\r
1159   else if ( whence == F_SEEK_SET )\r
1160   {\r
1161     return _f_fseek( offset );\r
1162   }\r
1163 \r
1164   return F_ERR_NOTUSEABLE;\r
1165 } /* fn_seek */\r
1166 \r
1167 \r
1168 \r
1169 /****************************************************************************\r
1170  *\r
1171  * fn_tell\r
1172  *\r
1173  * Tells the current position of opened file\r
1174  *\r
1175  * INPUTS\r
1176  *\r
1177  * filehandle - which file needs the position\r
1178  *\r
1179  * RETURNS\r
1180  *\r
1181  * position in the file from start\r
1182  *\r
1183  ***************************************************************************/\r
1184 \r
1185 long fn_tell ( F_FILE * f )\r
1186 {\r
1187   if ( !f )\r
1188   {\r
1189     return 0;\r
1190   }\r
1191 \r
1192   if ( ( gl_file.mode & ( F_FILE_RD | F_FILE_WR | F_FILE_A | F_FILE_RDP | F_FILE_WRP | F_FILE_AP ) ) == 0 )\r
1193   {\r
1194     return 0;\r
1195   }\r
1196 \r
1197   return (long)( gl_file.abspos + gl_file.relpos );\r
1198 }\r
1199 \r
1200 \r
1201 \r
1202 /****************************************************************************\r
1203  *\r
1204  * fn_eof\r
1205  *\r
1206  * Tells if the current position is end of file or not\r
1207  *\r
1208  * INPUTS\r
1209  *\r
1210  * filehandle - which file needs the checking\r
1211  *\r
1212  * RETURNS\r
1213  *\r
1214  * 0 - if not EOF\r
1215  * other - if EOF or invalid file handle\r
1216  *\r
1217  ***************************************************************************/\r
1218 \r
1219 unsigned char fn_eof ( F_FILE * f )\r
1220 {\r
1221   if ( !f )\r
1222   {\r
1223     return F_ERR_NOTOPEN;          /*if error*/\r
1224   }\r
1225 \r
1226   if ( gl_file.abspos + gl_file.relpos < gl_file.filesize )\r
1227   {\r
1228     return 0;\r
1229   }\r
1230 \r
1231   return F_ERR_EOF;  /*EOF*/\r
1232 }\r
1233 \r
1234 \r
1235 \r
1236 \r
1237 /****************************************************************************\r
1238  *\r
1239  * fn_rewind\r
1240  *\r
1241  * set the fileposition in the opened file to the begining\r
1242  *\r
1243  * INPUTS\r
1244  *\r
1245  * filehandle - which file needs to be rewinded\r
1246  *\r
1247  * RETURNS\r
1248  *\r
1249  * error code or zero if successful\r
1250  *\r
1251  ***************************************************************************/\r
1252 \r
1253 unsigned char fn_rewind ( F_FILE * filehandle )\r
1254 {\r
1255   return fn_seek( filehandle, 0L, F_SEEK_SET );\r
1256 }\r
1257 \r
1258 \r
1259 \r
1260 /****************************************************************************\r
1261  *\r
1262  * fn_putc\r
1263  *\r
1264  * write a character into file\r
1265  *\r
1266  * INPUTS\r
1267  *\r
1268  * ch - what to write into file\r
1269  * filehandle - file where to write\r
1270  *\r
1271  * RETURNS\r
1272  *\r
1273  * with the number of written bytes (1-success, 0-not successfully)\r
1274  *\r
1275  ***************************************************************************/\r
1276 \r
1277 int fn_putc ( int ch, F_FILE * filehandle )\r
1278 {\r
1279   unsigned char  tmpch = (unsigned char)ch;\r
1280 \r
1281   if ( fn_write( &tmpch, 1, 1, filehandle ) )\r
1282   {\r
1283     return ch;\r
1284   }\r
1285   else\r
1286   {\r
1287     return -1;\r
1288   }\r
1289 }\r
1290 \r
1291 \r
1292 \r
1293 /****************************************************************************\r
1294  *\r
1295  * fn_getc\r
1296  *\r
1297  * get a character from file\r
1298  *\r
1299  * INPUTS\r
1300  *\r
1301  * filehandle - file where to read from\r
1302  *\r
1303  * RETURNS\r
1304  *\r
1305  * with the read character or -1 if read was not successfully\r
1306  *\r
1307  ***************************************************************************/\r
1308 int fn_getc ( F_FILE * filehandle )\r
1309 {\r
1310   unsigned char  ch;\r
1311 \r
1312   if ( !fn_read( &ch, 1, 1, filehandle ) )\r
1313   {\r
1314     return -1;\r
1315   }\r
1316 \r
1317   return (int)ch;\r
1318 }\r
1319 \r
1320 \r
1321 \r
1322 /****************************************************************************\r
1323  *\r
1324  * fn_delete\r
1325  *\r
1326  * delete a file\r
1327  *\r
1328  * INPUTS\r
1329  *\r
1330  * filename - file which wanted to be deleted (with or without path)\r
1331  *\r
1332  * RETURNS\r
1333  *\r
1334  * error code or zero if successful\r
1335  *\r
1336  ***************************************************************************/\r
1337 unsigned char fn_delete ( const char * filename )\r
1338 {\r
1339   F_POS          pos;\r
1340   F_DIRENTRY   * de;\r
1341   F_NAME         fsname;\r
1342   unsigned char  ret;\r
1343 \r
1344   if ( _f_setfsname( filename, &fsname ) )\r
1345   {\r
1346     return F_ERR_INVALIDNAME;                                     /*invalid name*/\r
1347   }\r
1348 \r
1349   if ( _f_checknamewc( fsname.filename, fsname.fileext ) )\r
1350   {\r
1351     return F_ERR_INVALIDNAME;                                                    /*invalid name*/\r
1352   }\r
1353 \r
1354   if ( fsname.filename[0] == '.' )\r
1355   {\r
1356     return F_ERR_NOTFOUND;\r
1357   }\r
1358 \r
1359   ret = _f_getvolume();\r
1360   if ( ret )\r
1361   {\r
1362     return ret;\r
1363   }\r
1364 \r
1365   if ( !( _f_findpath( &fsname, &pos ) ) )\r
1366   {\r
1367     return F_ERR_INVALIDDIR;\r
1368   }\r
1369 \r
1370   if ( !_f_findfilewc( fsname.filename, fsname.fileext, &pos, &de, 0 ) )\r
1371   {\r
1372     return F_ERR_NOTFOUND;\r
1373   }\r
1374 \r
1375   if ( de->attr & F_ATTR_DIR )\r
1376   {\r
1377     return F_ERR_INVALIDDIR;                                /*directory*/\r
1378   }\r
1379 \r
1380   if ( de->attr & F_ATTR_READONLY )\r
1381   {\r
1382     return F_ERR_ACCESSDENIED;                                      /*readonly*/\r
1383   }\r
1384 \r
1385   if ( ( gl_file.mode != F_FILE_CLOSE ) && ( gl_file.dirpos.sector == pos.sector ) && ( gl_file.dirpos.pos == pos.pos ) )\r
1386   {\r
1387     return F_ERR_LOCKED;\r
1388   }\r
1389 \r
1390   de->name[0] = (unsigned char)0xe5; /*removes it*/\r
1391   ret = _f_writeglsector( (unsigned long)-1 );\r
1392   if ( ret )\r
1393   {\r
1394     return ret;\r
1395   }\r
1396 \r
1397   ret = _f_removechain( _f_getdecluster( de ) );\r
1398 \r
1399  #if F_FILE_CHANGED_EVENT\r
1400   if ( f_filechangedevent && !ret )\r
1401   {\r
1402     ST_FILE_CHANGED  fc;\r
1403     fc.action = FACTION_REMOVED;\r
1404     fc.flags = FFLAGS_FILE_NAME;\r
1405 \r
1406     if ( !_f_createfullname( fc.filename, sizeof( fc.filename ), fsname.path, fsname.filename, fsname.fileext ) )\r
1407     {\r
1408       f_filechangedevent( &fc );\r
1409     }\r
1410   }\r
1411 \r
1412  #endif\r
1413 \r
1414   return ret;\r
1415 } /* fn_delete */\r
1416 \r
1417 \r
1418 \r
1419 \r
1420 /****************************************************************************\r
1421  *\r
1422  * _f_seteof\r
1423  *\r
1424  * Set end of file\r
1425  *\r
1426  * INPUT:       f - file pointer\r
1427  *              filesize - required new size\r
1428  * RETURN:      F_NO_ERROR - on success\r
1429  *              other if error\r
1430  *\r
1431  ***************************************************************************/\r
1432 unsigned char _f_seteof ( F_FILE * f, long filesize )\r
1433 {\r
1434   unsigned char  rc = F_NO_ERROR;\r
1435 \r
1436   if ( !f )\r
1437   {\r
1438     return F_ERR_NOTOPEN;        /*if error*/\r
1439   }\r
1440 \r
1441   if ( ( unsigned long) filesize < gl_file.filesize )\r
1442   {\r
1443     rc = _f_fseek( filesize );\r
1444     if ( rc == F_NO_ERROR )\r
1445     {\r
1446       unsigned long  cluster;\r
1447       rc = _f_getclustervalue( gl_file.pos.cluster, &cluster );\r
1448       if ( rc == F_NO_ERROR )\r
1449       {\r
1450         if ( cluster != F_CLUSTER_LAST )\r
1451         {\r
1452           rc = _f_removechain( cluster );\r
1453           if ( rc )\r
1454           {\r
1455             return rc;\r
1456           }\r
1457 \r
1458           rc = _f_setclustervalue( gl_file.pos.cluster, F_CLUSTER_LAST );\r
1459           if ( rc )\r
1460           {\r
1461             return rc;\r
1462           }\r
1463 \r
1464           rc = _f_writefatsector();\r
1465           if ( rc )\r
1466           {\r
1467             return rc;\r
1468           }\r
1469         }\r
1470 \r
1471         gl_file.filesize = (unsigned long)filesize;\r
1472       }\r
1473     }\r
1474   }\r
1475   else if ( (unsigned long) filesize > gl_file.filesize )\r
1476   {\r
1477     rc = _f_fseek( filesize );\r
1478   }\r
1479 \r
1480   return rc;\r
1481 } /* _f_seteof */\r
1482 \r
1483 \r
1484 /****************************************************************************\r
1485  *\r
1486  * fn_seteof\r
1487  *\r
1488  * Set end of file\r
1489  *\r
1490  * INPUT:       f - file pointer\r
1491  *              filesize - required new size\r
1492  * RETURN:      F_NO_ERROR - on success\r
1493  *              other if error\r
1494  *\r
1495  ***************************************************************************/\r
1496 unsigned char fn_seteof ( F_FILE * f )\r
1497 {\r
1498   unsigned char  rc = F_NO_ERROR;\r
1499 \r
1500   rc = _f_seteof( f, ( gl_file.abspos + gl_file.relpos ) );\r
1501 \r
1502   return rc;\r
1503 } /* fn_seteof */\r
1504 \r
1505 \r
1506 \r
1507 \r
1508 /****************************************************************************\r
1509  *\r
1510  * fn_truncate\r
1511  *\r
1512  * Open a file and set end of file\r
1513  *\r
1514  * INPUT:       filename - name of the file\r
1515  *              filesize - required new size\r
1516  * RETURN:      NULL on error, otherwise file pointer\r
1517  *\r
1518  ***************************************************************************/\r
1519 F_FILE * fn_truncate ( const char * filename, long filesize )\r
1520 {\r
1521   F_FILE       * f = fn_open( filename, "r+" );\r
1522   unsigned char  rc;\r
1523 \r
1524   if ( f != NULL )\r
1525   {\r
1526     rc = _f_fseek( (long)gl_file.filesize );\r
1527     if ( rc == F_NO_ERROR )\r
1528     {\r
1529       rc = _f_seteof( f, filesize );\r
1530     }\r
1531 \r
1532     if ( rc )\r
1533     {\r
1534       fn_close( f );\r
1535       f = NULL;\r
1536     }\r
1537   }\r
1538 \r
1539   return f;\r
1540 } /* fn_truncate */\r
1541 \r