1*d5c9a868SElliott Hughes /* Copyright 1996-1999,2001-2003,2007-2009,2011 Alain Knaff.
2*d5c9a868SElliott Hughes * This file is part of mtools.
3*d5c9a868SElliott Hughes *
4*d5c9a868SElliott Hughes * Mtools is free software: you can redistribute it and/or modify
5*d5c9a868SElliott Hughes * it under the terms of the GNU General Public License as published by
6*d5c9a868SElliott Hughes * the Free Software Foundation, either version 3 of the License, or
7*d5c9a868SElliott Hughes * (at your option) any later version.
8*d5c9a868SElliott Hughes *
9*d5c9a868SElliott Hughes * Mtools is distributed in the hope that it will be useful,
10*d5c9a868SElliott Hughes * but WITHOUT ANY WARRANTY; without even the implied warranty of
11*d5c9a868SElliott Hughes * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12*d5c9a868SElliott Hughes * GNU General Public License for more details.
13*d5c9a868SElliott Hughes *
14*d5c9a868SElliott Hughes * You should have received a copy of the GNU General Public License
15*d5c9a868SElliott Hughes * along with Mtools. If not, see <http://www.gnu.org/licenses/>.
16*d5c9a868SElliott Hughes */
17*d5c9a868SElliott Hughes
18*d5c9a868SElliott Hughes #include "sysincludes.h"
19*d5c9a868SElliott Hughes #include "msdos.h"
20*d5c9a868SElliott Hughes #include "stream.h"
21*d5c9a868SElliott Hughes #include "mtools.h"
22*d5c9a868SElliott Hughes #include "fsP.h"
23*d5c9a868SElliott Hughes #include "file.h"
24*d5c9a868SElliott Hughes #include "htable.h"
25*d5c9a868SElliott Hughes #include "dirCache.h"
26*d5c9a868SElliott Hughes #include "buffer.h"
27*d5c9a868SElliott Hughes
28*d5c9a868SElliott Hughes typedef struct File_t {
29*d5c9a868SElliott Hughes struct Stream_t head;
30*d5c9a868SElliott Hughes
31*d5c9a868SElliott Hughes struct Stream_t *Buffer;
32*d5c9a868SElliott Hughes
33*d5c9a868SElliott Hughes int (*map)(struct File_t *this, uint32_t where, uint32_t *len, int mode,
34*d5c9a868SElliott Hughes mt_off_t *res);
35*d5c9a868SElliott Hughes uint32_t FileSize;
36*d5c9a868SElliott Hughes
37*d5c9a868SElliott Hughes /* How many bytes do we project to need for this file
38*d5c9a868SElliott Hughes (includes those already in FileSize) */
39*d5c9a868SElliott Hughes uint32_t preallocatedSize;
40*d5c9a868SElliott Hughes
41*d5c9a868SElliott Hughes /* How many clusters we have asked the lower layer to reserve
42*d5c9a868SElliott Hughes for us (only what we will need in the future, excluding already
43*d5c9a868SElliott Hughes allocated clusters in FileSize) */
44*d5c9a868SElliott Hughes uint32_t preallocatedClusters;
45*d5c9a868SElliott Hughes
46*d5c9a868SElliott Hughes /* Absolute position of first cluster of file */
47*d5c9a868SElliott Hughes unsigned int FirstAbsCluNr;
48*d5c9a868SElliott Hughes
49*d5c9a868SElliott Hughes /* Absolute position of previous cluster */
50*d5c9a868SElliott Hughes unsigned int PreviousAbsCluNr;
51*d5c9a868SElliott Hughes
52*d5c9a868SElliott Hughes /* Relative position of previous cluster */
53*d5c9a868SElliott Hughes unsigned int PreviousRelCluNr;
54*d5c9a868SElliott Hughes direntry_t direntry;
55*d5c9a868SElliott Hughes size_t hint;
56*d5c9a868SElliott Hughes struct dirCache_t *dcp;
57*d5c9a868SElliott Hughes
58*d5c9a868SElliott Hughes unsigned int loopDetectRel;
59*d5c9a868SElliott Hughes unsigned int loopDetectAbs;
60*d5c9a868SElliott Hughes
61*d5c9a868SElliott Hughes uint32_t where;
62*d5c9a868SElliott Hughes } File_t;
63*d5c9a868SElliott Hughes
64*d5c9a868SElliott Hughes static Class_t FileClass;
65*d5c9a868SElliott Hughes static T_HashTable *filehash;
66*d5c9a868SElliott Hughes
getUnbufferedFile(Stream_t * Stream)67*d5c9a868SElliott Hughes static File_t *getUnbufferedFile(Stream_t *Stream)
68*d5c9a868SElliott Hughes {
69*d5c9a868SElliott Hughes while(Stream->Class != &FileClass)
70*d5c9a868SElliott Hughes Stream = Stream->Next;
71*d5c9a868SElliott Hughes return (File_t *) Stream;
72*d5c9a868SElliott Hughes }
73*d5c9a868SElliott Hughes
_getFs(File_t * File)74*d5c9a868SElliott Hughes static inline Fs_t *_getFs(File_t *File)
75*d5c9a868SElliott Hughes {
76*d5c9a868SElliott Hughes return (Fs_t *) File->head.Next;
77*d5c9a868SElliott Hughes }
78*d5c9a868SElliott Hughes
getFs(Stream_t * Stream)79*d5c9a868SElliott Hughes Fs_t *getFs(Stream_t *Stream)
80*d5c9a868SElliott Hughes {
81*d5c9a868SElliott Hughes return (Fs_t *)getUnbufferedFile(Stream)->head.Next;
82*d5c9a868SElliott Hughes }
83*d5c9a868SElliott Hughes
getDirCacheP(Stream_t * Stream)84*d5c9a868SElliott Hughes struct dirCache_t **getDirCacheP(Stream_t *Stream)
85*d5c9a868SElliott Hughes {
86*d5c9a868SElliott Hughes return &getUnbufferedFile(Stream)->dcp;
87*d5c9a868SElliott Hughes }
88*d5c9a868SElliott Hughes
getDirentry(Stream_t * Stream)89*d5c9a868SElliott Hughes direntry_t *getDirentry(Stream_t *Stream)
90*d5c9a868SElliott Hughes {
91*d5c9a868SElliott Hughes return &getUnbufferedFile(Stream)->direntry;
92*d5c9a868SElliott Hughes }
93*d5c9a868SElliott Hughes
94*d5c9a868SElliott Hughes /**
95*d5c9a868SElliott Hughes * Overflow-safe conversion of bytes to cluster
96*d5c9a868SElliott Hughes */
filebytesToClusters(uint32_t bytes,uint32_t clus_size)97*d5c9a868SElliott Hughes static uint32_t filebytesToClusters(uint32_t bytes, uint32_t clus_size) {
98*d5c9a868SElliott Hughes uint32_t ret = bytes / clus_size;
99*d5c9a868SElliott Hughes if(bytes % clus_size)
100*d5c9a868SElliott Hughes ret++;
101*d5c9a868SElliott Hughes return ret;
102*d5c9a868SElliott Hughes }
103*d5c9a868SElliott Hughes
recalcPreallocSize(File_t * This)104*d5c9a868SElliott Hughes static int recalcPreallocSize(File_t *This)
105*d5c9a868SElliott Hughes {
106*d5c9a868SElliott Hughes uint32_t currentClusters, neededClusters;
107*d5c9a868SElliott Hughes unsigned int clus_size;
108*d5c9a868SElliott Hughes uint32_t neededPrealloc;
109*d5c9a868SElliott Hughes Fs_t *Fs = _getFs(This);
110*d5c9a868SElliott Hughes
111*d5c9a868SElliott Hughes #if 0
112*d5c9a868SElliott Hughes if(This->FileSize & 0xc0000000) {
113*d5c9a868SElliott Hughes fprintf(stderr, "Bad filesize\n");
114*d5c9a868SElliott Hughes }
115*d5c9a868SElliott Hughes if(This->preallocatedSize & 0xc0000000) {
116*d5c9a868SElliott Hughes fprintf(stderr, "Bad preallocated size %x\n",
117*d5c9a868SElliott Hughes (int) This->preallocatedSize);
118*d5c9a868SElliott Hughes }
119*d5c9a868SElliott Hughes #endif
120*d5c9a868SElliott Hughes clus_size = Fs->cluster_size * Fs->sector_size;
121*d5c9a868SElliott Hughes currentClusters = filebytesToClusters(This->FileSize, clus_size);
122*d5c9a868SElliott Hughes neededClusters = filebytesToClusters(This->preallocatedSize, clus_size);
123*d5c9a868SElliott Hughes if(neededClusters < currentClusters)
124*d5c9a868SElliott Hughes neededPrealloc = 0;
125*d5c9a868SElliott Hughes else
126*d5c9a868SElliott Hughes neededPrealloc = neededClusters - currentClusters;
127*d5c9a868SElliott Hughes if(neededPrealloc > This->preallocatedClusters) {
128*d5c9a868SElliott Hughes int r = fsPreallocateClusters(Fs, neededPrealloc-
129*d5c9a868SElliott Hughes This->preallocatedClusters);
130*d5c9a868SElliott Hughes if(r)
131*d5c9a868SElliott Hughes return r;
132*d5c9a868SElliott Hughes } else {
133*d5c9a868SElliott Hughes fsReleasePreallocateClusters(Fs, This->preallocatedClusters -
134*d5c9a868SElliott Hughes neededPrealloc);
135*d5c9a868SElliott Hughes }
136*d5c9a868SElliott Hughes This->preallocatedClusters = neededPrealloc;
137*d5c9a868SElliott Hughes return 0;
138*d5c9a868SElliott Hughes }
139*d5c9a868SElliott Hughes
_loopDetect(unsigned int * oldrel,unsigned int rel,unsigned int * oldabs,unsigned int absol)140*d5c9a868SElliott Hughes static int _loopDetect(unsigned int *oldrel, unsigned int rel,
141*d5c9a868SElliott Hughes unsigned int *oldabs, unsigned int absol)
142*d5c9a868SElliott Hughes {
143*d5c9a868SElliott Hughes if(*oldrel && rel > *oldrel && absol == *oldabs) {
144*d5c9a868SElliott Hughes fprintf(stderr, "loop detected! oldrel=%d newrel=%d abs=%d\n",
145*d5c9a868SElliott Hughes *oldrel, rel, absol);
146*d5c9a868SElliott Hughes return -1;
147*d5c9a868SElliott Hughes }
148*d5c9a868SElliott Hughes
149*d5c9a868SElliott Hughes if(rel >= 2 * *oldrel + 1) {
150*d5c9a868SElliott Hughes *oldrel = rel;
151*d5c9a868SElliott Hughes *oldabs = absol;
152*d5c9a868SElliott Hughes }
153*d5c9a868SElliott Hughes return 0;
154*d5c9a868SElliott Hughes }
155*d5c9a868SElliott Hughes
156*d5c9a868SElliott Hughes
loopDetect(File_t * This,unsigned int rel,unsigned int absol)157*d5c9a868SElliott Hughes static int loopDetect(File_t *This, unsigned int rel, unsigned int absol)
158*d5c9a868SElliott Hughes {
159*d5c9a868SElliott Hughes return _loopDetect(&This->loopDetectRel, rel, &This->loopDetectAbs, absol);
160*d5c9a868SElliott Hughes }
161*d5c9a868SElliott Hughes
_countBlocks(Fs_t * This,unsigned int block)162*d5c9a868SElliott Hughes static unsigned int _countBlocks(Fs_t *This, unsigned int block)
163*d5c9a868SElliott Hughes {
164*d5c9a868SElliott Hughes unsigned int blocks;
165*d5c9a868SElliott Hughes unsigned int rel, oldabs, oldrel;
166*d5c9a868SElliott Hughes
167*d5c9a868SElliott Hughes blocks = 0;
168*d5c9a868SElliott Hughes
169*d5c9a868SElliott Hughes oldabs = oldrel = rel = 0;
170*d5c9a868SElliott Hughes
171*d5c9a868SElliott Hughes while (block <= This->last_fat && block != 1 && block) {
172*d5c9a868SElliott Hughes blocks++;
173*d5c9a868SElliott Hughes block = fatDecode(This, block);
174*d5c9a868SElliott Hughes rel++;
175*d5c9a868SElliott Hughes if(_loopDetect(&oldrel, rel, &oldabs, block) < 0)
176*d5c9a868SElliott Hughes block = 1;
177*d5c9a868SElliott Hughes }
178*d5c9a868SElliott Hughes return blocks;
179*d5c9a868SElliott Hughes }
180*d5c9a868SElliott Hughes
countBlocks(Stream_t * Dir,unsigned int block)181*d5c9a868SElliott Hughes unsigned int countBlocks(Stream_t *Dir, unsigned int block)
182*d5c9a868SElliott Hughes {
183*d5c9a868SElliott Hughes Stream_t *Stream = GetFs(Dir);
184*d5c9a868SElliott Hughes DeclareThis(Fs_t);
185*d5c9a868SElliott Hughes
186*d5c9a868SElliott Hughes return _countBlocks(This, block);
187*d5c9a868SElliott Hughes }
188*d5c9a868SElliott Hughes
189*d5c9a868SElliott Hughes /* returns number of bytes in a directory. Represents a file size, and
190*d5c9a868SElliott Hughes * can hence be not bigger than 2^32
191*d5c9a868SElliott Hughes */
countBytes(Stream_t * Dir,unsigned int block)192*d5c9a868SElliott Hughes static uint32_t countBytes(Stream_t *Dir, unsigned int block)
193*d5c9a868SElliott Hughes {
194*d5c9a868SElliott Hughes Stream_t *Stream = GetFs(Dir);
195*d5c9a868SElliott Hughes DeclareThis(Fs_t);
196*d5c9a868SElliott Hughes
197*d5c9a868SElliott Hughes return _countBlocks(This, block) *
198*d5c9a868SElliott Hughes This->sector_size * This->cluster_size;
199*d5c9a868SElliott Hughes }
200*d5c9a868SElliott Hughes
printFat(Stream_t * Stream)201*d5c9a868SElliott Hughes void printFat(Stream_t *Stream)
202*d5c9a868SElliott Hughes {
203*d5c9a868SElliott Hughes File_t *This = getUnbufferedFile(Stream);
204*d5c9a868SElliott Hughes uint32_t n;
205*d5c9a868SElliott Hughes unsigned int rel;
206*d5c9a868SElliott Hughes unsigned long begin, end;
207*d5c9a868SElliott Hughes int first;
208*d5c9a868SElliott Hughes
209*d5c9a868SElliott Hughes n = This->FirstAbsCluNr;
210*d5c9a868SElliott Hughes if(!n) {
211*d5c9a868SElliott Hughes printf("Root directory or empty file\n");
212*d5c9a868SElliott Hughes return;
213*d5c9a868SElliott Hughes }
214*d5c9a868SElliott Hughes
215*d5c9a868SElliott Hughes rel = 0;
216*d5c9a868SElliott Hughes first = 1;
217*d5c9a868SElliott Hughes begin = end = 0;
218*d5c9a868SElliott Hughes do {
219*d5c9a868SElliott Hughes if (first || n != end+1) {
220*d5c9a868SElliott Hughes if (!first) {
221*d5c9a868SElliott Hughes if (begin != end)
222*d5c9a868SElliott Hughes printf("-%lu", end);
223*d5c9a868SElliott Hughes printf("> ");
224*d5c9a868SElliott Hughes }
225*d5c9a868SElliott Hughes begin = end = n;
226*d5c9a868SElliott Hughes printf("<%lu", begin);
227*d5c9a868SElliott Hughes } else {
228*d5c9a868SElliott Hughes end++;
229*d5c9a868SElliott Hughes }
230*d5c9a868SElliott Hughes first = 0;
231*d5c9a868SElliott Hughes n = fatDecode(_getFs(This), n);
232*d5c9a868SElliott Hughes rel++;
233*d5c9a868SElliott Hughes if(loopDetect(This, rel, n) < 0)
234*d5c9a868SElliott Hughes n = 1;
235*d5c9a868SElliott Hughes } while (n <= _getFs(This)->last_fat && n != 1);
236*d5c9a868SElliott Hughes if(!first) {
237*d5c9a868SElliott Hughes if (begin != end)
238*d5c9a868SElliott Hughes printf("-%lu", end);
239*d5c9a868SElliott Hughes printf(">");
240*d5c9a868SElliott Hughes }
241*d5c9a868SElliott Hughes }
242*d5c9a868SElliott Hughes
printFatWithOffset(Stream_t * Stream,off_t offset)243*d5c9a868SElliott Hughes void printFatWithOffset(Stream_t *Stream, off_t offset) {
244*d5c9a868SElliott Hughes File_t *This = getUnbufferedFile(Stream);
245*d5c9a868SElliott Hughes uint32_t n;
246*d5c9a868SElliott Hughes unsigned int rel;
247*d5c9a868SElliott Hughes off_t clusSize;
248*d5c9a868SElliott Hughes
249*d5c9a868SElliott Hughes n = This->FirstAbsCluNr;
250*d5c9a868SElliott Hughes if(!n) {
251*d5c9a868SElliott Hughes printf("Root directory or empty file\n");
252*d5c9a868SElliott Hughes return;
253*d5c9a868SElliott Hughes }
254*d5c9a868SElliott Hughes
255*d5c9a868SElliott Hughes clusSize = _getFs(This)->cluster_size * _getFs(This)->sector_size;
256*d5c9a868SElliott Hughes
257*d5c9a868SElliott Hughes rel = 0;
258*d5c9a868SElliott Hughes while(offset >= clusSize) {
259*d5c9a868SElliott Hughes n = fatDecode(_getFs(This), n);
260*d5c9a868SElliott Hughes rel++;
261*d5c9a868SElliott Hughes if(loopDetect(This, rel, n) < 0)
262*d5c9a868SElliott Hughes return;
263*d5c9a868SElliott Hughes if(n > _getFs(This)->last_fat)
264*d5c9a868SElliott Hughes return;
265*d5c9a868SElliott Hughes offset -= clusSize;
266*d5c9a868SElliott Hughes }
267*d5c9a868SElliott Hughes
268*d5c9a868SElliott Hughes printf("%lu", (unsigned long) n);
269*d5c9a868SElliott Hughes }
270*d5c9a868SElliott Hughes
normal_map(File_t * This,uint32_t where,uint32_t * len,int mode,mt_off_t * res)271*d5c9a868SElliott Hughes static int normal_map(File_t *This, uint32_t where, uint32_t *len, int mode,
272*d5c9a868SElliott Hughes mt_off_t *res)
273*d5c9a868SElliott Hughes {
274*d5c9a868SElliott Hughes unsigned int offset;
275*d5c9a868SElliott Hughes size_t end;
276*d5c9a868SElliott Hughes uint32_t NrClu; /* number of clusters to read */
277*d5c9a868SElliott Hughes uint32_t RelCluNr;
278*d5c9a868SElliott Hughes uint32_t CurCluNr;
279*d5c9a868SElliott Hughes uint32_t NewCluNr;
280*d5c9a868SElliott Hughes uint32_t AbsCluNr;
281*d5c9a868SElliott Hughes uint32_t clus_size;
282*d5c9a868SElliott Hughes Fs_t *Fs = _getFs(This);
283*d5c9a868SElliott Hughes
284*d5c9a868SElliott Hughes *res = 0;
285*d5c9a868SElliott Hughes clus_size = Fs->cluster_size * Fs->sector_size;
286*d5c9a868SElliott Hughes offset = where % clus_size;
287*d5c9a868SElliott Hughes
288*d5c9a868SElliott Hughes if (mode == MT_READ)
289*d5c9a868SElliott Hughes maximize(*len, This->FileSize - where);
290*d5c9a868SElliott Hughes if (*len == 0 )
291*d5c9a868SElliott Hughes return 0;
292*d5c9a868SElliott Hughes
293*d5c9a868SElliott Hughes if (This->FirstAbsCluNr < 2){
294*d5c9a868SElliott Hughes if( mode == MT_READ || *len == 0){
295*d5c9a868SElliott Hughes *len = 0;
296*d5c9a868SElliott Hughes return 0;
297*d5c9a868SElliott Hughes }
298*d5c9a868SElliott Hughes NewCluNr = get_next_free_cluster(_getFs(This), 1);
299*d5c9a868SElliott Hughes if (NewCluNr == 1 ){
300*d5c9a868SElliott Hughes errno = ENOSPC;
301*d5c9a868SElliott Hughes return -2;
302*d5c9a868SElliott Hughes }
303*d5c9a868SElliott Hughes hash_remove(filehash, (void *) This, This->hint);
304*d5c9a868SElliott Hughes This->FirstAbsCluNr = NewCluNr;
305*d5c9a868SElliott Hughes hash_add(filehash, (void *) This, &This->hint);
306*d5c9a868SElliott Hughes fatAllocate(_getFs(This), NewCluNr, Fs->end_fat);
307*d5c9a868SElliott Hughes }
308*d5c9a868SElliott Hughes
309*d5c9a868SElliott Hughes RelCluNr = where / clus_size;
310*d5c9a868SElliott Hughes
311*d5c9a868SElliott Hughes if (RelCluNr >= This->PreviousRelCluNr){
312*d5c9a868SElliott Hughes CurCluNr = This->PreviousRelCluNr;
313*d5c9a868SElliott Hughes AbsCluNr = This->PreviousAbsCluNr;
314*d5c9a868SElliott Hughes } else {
315*d5c9a868SElliott Hughes CurCluNr = 0;
316*d5c9a868SElliott Hughes AbsCluNr = This->FirstAbsCluNr;
317*d5c9a868SElliott Hughes }
318*d5c9a868SElliott Hughes
319*d5c9a868SElliott Hughes
320*d5c9a868SElliott Hughes NrClu = (offset + *len - 1) / clus_size;
321*d5c9a868SElliott Hughes while (CurCluNr <= RelCluNr + NrClu){
322*d5c9a868SElliott Hughes if (CurCluNr == RelCluNr){
323*d5c9a868SElliott Hughes /* we have reached the beginning of our zone. Save
324*d5c9a868SElliott Hughes * coordinates */
325*d5c9a868SElliott Hughes This->PreviousRelCluNr = RelCluNr;
326*d5c9a868SElliott Hughes This->PreviousAbsCluNr = AbsCluNr;
327*d5c9a868SElliott Hughes }
328*d5c9a868SElliott Hughes NewCluNr = fatDecode(_getFs(This), AbsCluNr);
329*d5c9a868SElliott Hughes if (NewCluNr == 1 || NewCluNr == 0){
330*d5c9a868SElliott Hughes fprintf(stderr,"Fat problem while decoding %d %x\n",
331*d5c9a868SElliott Hughes AbsCluNr, NewCluNr);
332*d5c9a868SElliott Hughes exit(1);
333*d5c9a868SElliott Hughes }
334*d5c9a868SElliott Hughes if(CurCluNr == RelCluNr + NrClu)
335*d5c9a868SElliott Hughes break;
336*d5c9a868SElliott Hughes if (NewCluNr > Fs->last_fat && mode == MT_WRITE){
337*d5c9a868SElliott Hughes /* if at end, and writing, extend it */
338*d5c9a868SElliott Hughes NewCluNr = get_next_free_cluster(_getFs(This), AbsCluNr);
339*d5c9a868SElliott Hughes if (NewCluNr == 1 ){ /* no more space */
340*d5c9a868SElliott Hughes errno = ENOSPC;
341*d5c9a868SElliott Hughes return -2;
342*d5c9a868SElliott Hughes }
343*d5c9a868SElliott Hughes fatAppend(_getFs(This), AbsCluNr, NewCluNr);
344*d5c9a868SElliott Hughes }
345*d5c9a868SElliott Hughes
346*d5c9a868SElliott Hughes if (CurCluNr < RelCluNr && NewCluNr > Fs->last_fat){
347*d5c9a868SElliott Hughes *len = 0;
348*d5c9a868SElliott Hughes return 0;
349*d5c9a868SElliott Hughes }
350*d5c9a868SElliott Hughes
351*d5c9a868SElliott Hughes if (CurCluNr >= RelCluNr && NewCluNr != AbsCluNr + 1)
352*d5c9a868SElliott Hughes break;
353*d5c9a868SElliott Hughes CurCluNr++;
354*d5c9a868SElliott Hughes AbsCluNr = NewCluNr;
355*d5c9a868SElliott Hughes if(loopDetect(This, CurCluNr, AbsCluNr)) {
356*d5c9a868SElliott Hughes errno = EIO;
357*d5c9a868SElliott Hughes return -2;
358*d5c9a868SElliott Hughes }
359*d5c9a868SElliott Hughes }
360*d5c9a868SElliott Hughes
361*d5c9a868SElliott Hughes maximize(*len, (1 + CurCluNr - RelCluNr) * clus_size - offset);
362*d5c9a868SElliott Hughes
363*d5c9a868SElliott Hughes end = where + *len;
364*d5c9a868SElliott Hughes if(batchmode &&
365*d5c9a868SElliott Hughes mode == MT_WRITE &&
366*d5c9a868SElliott Hughes end >= This->FileSize) {
367*d5c9a868SElliott Hughes /* In batch mode, when writing at end of file, "pad"
368*d5c9a868SElliott Hughes * to nearest cluster boundary so that we don't have
369*d5c9a868SElliott Hughes * to read that data back from disk. */
370*d5c9a868SElliott Hughes *len += ROUND_UP(end, clus_size) - end;
371*d5c9a868SElliott Hughes }
372*d5c9a868SElliott Hughes
373*d5c9a868SElliott Hughes if((*len + offset) / clus_size + This->PreviousAbsCluNr-2 >
374*d5c9a868SElliott Hughes Fs->num_clus) {
375*d5c9a868SElliott Hughes fprintf(stderr, "cluster too big\n");
376*d5c9a868SElliott Hughes exit(1);
377*d5c9a868SElliott Hughes }
378*d5c9a868SElliott Hughes
379*d5c9a868SElliott Hughes *res = sectorsToBytes(Fs,
380*d5c9a868SElliott Hughes (This->PreviousAbsCluNr-2) * Fs->cluster_size +
381*d5c9a868SElliott Hughes Fs->clus_start) + to_mt_off_t(offset);
382*d5c9a868SElliott Hughes return 1;
383*d5c9a868SElliott Hughes }
384*d5c9a868SElliott Hughes
385*d5c9a868SElliott Hughes
root_map(File_t * This,uint32_t where,uint32_t * len,int mode UNUSEDP,mt_off_t * res)386*d5c9a868SElliott Hughes static int root_map(File_t *This, uint32_t where, uint32_t *len,
387*d5c9a868SElliott Hughes int mode UNUSEDP, mt_off_t *res)
388*d5c9a868SElliott Hughes {
389*d5c9a868SElliott Hughes Fs_t *Fs = _getFs(This);
390*d5c9a868SElliott Hughes
391*d5c9a868SElliott Hughes if(Fs->dir_len * Fs->sector_size < where) {
392*d5c9a868SElliott Hughes *len = 0;
393*d5c9a868SElliott Hughes errno = ENOSPC;
394*d5c9a868SElliott Hughes return -2;
395*d5c9a868SElliott Hughes }
396*d5c9a868SElliott Hughes
397*d5c9a868SElliott Hughes maximize(*len, Fs->dir_len * Fs->sector_size - where);
398*d5c9a868SElliott Hughes if (*len == 0)
399*d5c9a868SElliott Hughes return 0;
400*d5c9a868SElliott Hughes
401*d5c9a868SElliott Hughes *res = sectorsToBytes(Fs, Fs->dir_start) +
402*d5c9a868SElliott Hughes to_mt_off_t(where);
403*d5c9a868SElliott Hughes return 1;
404*d5c9a868SElliott Hughes }
405*d5c9a868SElliott Hughes
read_file(Stream_t * Stream,char * buf,size_t ilen)406*d5c9a868SElliott Hughes static ssize_t read_file(Stream_t *Stream, char *buf, size_t ilen)
407*d5c9a868SElliott Hughes {
408*d5c9a868SElliott Hughes DeclareThis(File_t);
409*d5c9a868SElliott Hughes mt_off_t pos;
410*d5c9a868SElliott Hughes int err;
411*d5c9a868SElliott Hughes uint32_t len = truncSizeTo32u(ilen);
412*d5c9a868SElliott Hughes ssize_t ret;
413*d5c9a868SElliott Hughes
414*d5c9a868SElliott Hughes Stream_t *Disk = _getFs(This)->head.Next;
415*d5c9a868SElliott Hughes
416*d5c9a868SElliott Hughes err = This->map(This, This->where, &len, MT_READ, &pos);
417*d5c9a868SElliott Hughes if(err <= 0)
418*d5c9a868SElliott Hughes return err;
419*d5c9a868SElliott Hughes ret = PREADS(Disk, buf, pos, len);
420*d5c9a868SElliott Hughes if(ret < 0)
421*d5c9a868SElliott Hughes return ret;
422*d5c9a868SElliott Hughes This->where += (size_t) ret;
423*d5c9a868SElliott Hughes return ret;
424*d5c9a868SElliott Hughes }
425*d5c9a868SElliott Hughes
write_file(Stream_t * Stream,char * buf,size_t ilen)426*d5c9a868SElliott Hughes static ssize_t write_file(Stream_t *Stream, char *buf, size_t ilen)
427*d5c9a868SElliott Hughes {
428*d5c9a868SElliott Hughes DeclareThis(File_t);
429*d5c9a868SElliott Hughes mt_off_t pos;
430*d5c9a868SElliott Hughes ssize_t ret;
431*d5c9a868SElliott Hughes uint32_t requestedLen;
432*d5c9a868SElliott Hughes uint32_t bytesWritten;
433*d5c9a868SElliott Hughes Stream_t *Disk = _getFs(This)->head.Next;
434*d5c9a868SElliott Hughes uint32_t maxLen = UINT32_MAX-This->where;
435*d5c9a868SElliott Hughes uint32_t len;
436*d5c9a868SElliott Hughes int err;
437*d5c9a868SElliott Hughes
438*d5c9a868SElliott Hughes if(ilen > maxLen) {
439*d5c9a868SElliott Hughes len = maxLen;
440*d5c9a868SElliott Hughes } else
441*d5c9a868SElliott Hughes len = (uint32_t) ilen;
442*d5c9a868SElliott Hughes requestedLen = len;
443*d5c9a868SElliott Hughes err = This->map(This, This->where, &len, MT_WRITE, &pos);
444*d5c9a868SElliott Hughes if( err <= 0)
445*d5c9a868SElliott Hughes return err;
446*d5c9a868SElliott Hughes if(batchmode)
447*d5c9a868SElliott Hughes ret = force_pwrite(Disk, buf, pos, len);
448*d5c9a868SElliott Hughes else
449*d5c9a868SElliott Hughes ret = PWRITES(Disk, buf, pos, len);
450*d5c9a868SElliott Hughes if(ret < 0)
451*d5c9a868SElliott Hughes /* Error occured */
452*d5c9a868SElliott Hughes return ret;
453*d5c9a868SElliott Hughes if((uint32_t)ret > requestedLen)
454*d5c9a868SElliott Hughes /* More data than requested may be written to lower
455*d5c9a868SElliott Hughes * levels if batch mode is active, in order to "pad"
456*d5c9a868SElliott Hughes * the last cluster of a file, so that we don't have
457*d5c9a868SElliott Hughes * to read that back from disk */
458*d5c9a868SElliott Hughes bytesWritten = requestedLen;
459*d5c9a868SElliott Hughes else
460*d5c9a868SElliott Hughes bytesWritten = (uint32_t)ret;
461*d5c9a868SElliott Hughes This->where += bytesWritten;
462*d5c9a868SElliott Hughes if (This->where > This->FileSize )
463*d5c9a868SElliott Hughes This->FileSize = This->where;
464*d5c9a868SElliott Hughes recalcPreallocSize(This);
465*d5c9a868SElliott Hughes return (ssize_t) bytesWritten;
466*d5c9a868SElliott Hughes }
467*d5c9a868SElliott Hughes
pread_file(Stream_t * Stream,char * buf,mt_off_t where,size_t ilen)468*d5c9a868SElliott Hughes static ssize_t pread_file(Stream_t *Stream, char *buf, mt_off_t where,
469*d5c9a868SElliott Hughes size_t ilen) {
470*d5c9a868SElliott Hughes DeclareThis(File_t);
471*d5c9a868SElliott Hughes This->where = truncMtOffTo32u(where);
472*d5c9a868SElliott Hughes return read_file(Stream, buf, ilen);
473*d5c9a868SElliott Hughes }
474*d5c9a868SElliott Hughes
pwrite_file(Stream_t * Stream,char * buf,mt_off_t where,size_t ilen)475*d5c9a868SElliott Hughes static ssize_t pwrite_file(Stream_t *Stream, char *buf, mt_off_t where,
476*d5c9a868SElliott Hughes size_t ilen) {
477*d5c9a868SElliott Hughes DeclareThis(File_t);
478*d5c9a868SElliott Hughes This->where = truncMtOffTo32u(where);
479*d5c9a868SElliott Hughes return write_file(Stream, buf, ilen);
480*d5c9a868SElliott Hughes }
481*d5c9a868SElliott Hughes
482*d5c9a868SElliott Hughes /*
483*d5c9a868SElliott Hughes * Convert an MSDOS time & date stamp to the Unix time() format
484*d5c9a868SElliott Hughes */
485*d5c9a868SElliott Hughes
486*d5c9a868SElliott Hughes static int month[] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334,
487*d5c9a868SElliott Hughes 0, 0, 0 };
conv_stamp(struct directory * dir)488*d5c9a868SElliott Hughes static __inline__ time_t conv_stamp(struct directory *dir)
489*d5c9a868SElliott Hughes {
490*d5c9a868SElliott Hughes struct tm *tmbuf;
491*d5c9a868SElliott Hughes long tzone, dst;
492*d5c9a868SElliott Hughes time_t accum, tmp;
493*d5c9a868SElliott Hughes
494*d5c9a868SElliott Hughes accum = DOS_YEAR(dir) - 1970; /* years past */
495*d5c9a868SElliott Hughes
496*d5c9a868SElliott Hughes /* days passed */
497*d5c9a868SElliott Hughes accum = accum * 365L + month[DOS_MONTH(dir)-1] + DOS_DAY(dir);
498*d5c9a868SElliott Hughes
499*d5c9a868SElliott Hughes /* leap years */
500*d5c9a868SElliott Hughes accum += (DOS_YEAR(dir) - 1972) / 4L;
501*d5c9a868SElliott Hughes
502*d5c9a868SElliott Hughes /* back off 1 day if before 29 Feb */
503*d5c9a868SElliott Hughes if (!(DOS_YEAR(dir) % 4) && DOS_MONTH(dir) < 3)
504*d5c9a868SElliott Hughes accum--;
505*d5c9a868SElliott Hughes accum = accum * 24L + DOS_HOUR(dir); /* hours passed */
506*d5c9a868SElliott Hughes accum = accum * 60L + DOS_MINUTE(dir); /* minutes passed */
507*d5c9a868SElliott Hughes accum = accum * 60L + DOS_SEC(dir); /* seconds passed */
508*d5c9a868SElliott Hughes
509*d5c9a868SElliott Hughes /* correct for Time Zone */
510*d5c9a868SElliott Hughes #ifdef HAVE_GETTIMEOFDAY
511*d5c9a868SElliott Hughes {
512*d5c9a868SElliott Hughes struct timeval tv;
513*d5c9a868SElliott Hughes struct timezone tz;
514*d5c9a868SElliott Hughes
515*d5c9a868SElliott Hughes gettimeofday(&tv, &tz);
516*d5c9a868SElliott Hughes tzone = tz.tz_minuteswest * 60L;
517*d5c9a868SElliott Hughes }
518*d5c9a868SElliott Hughes #else
519*d5c9a868SElliott Hughes #if defined HAVE_TZSET && !defined OS_mingw32msvc
520*d5c9a868SElliott Hughes {
521*d5c9a868SElliott Hughes #if !defined OS_ultrix && !defined OS_cygwin
522*d5c9a868SElliott Hughes /* Ultrix defines this to be a different type */
523*d5c9a868SElliott Hughes extern long timezone;
524*d5c9a868SElliott Hughes #endif
525*d5c9a868SElliott Hughes tzset();
526*d5c9a868SElliott Hughes tzone = (long) timezone;
527*d5c9a868SElliott Hughes }
528*d5c9a868SElliott Hughes #else
529*d5c9a868SElliott Hughes tzone = 0;
530*d5c9a868SElliott Hughes #endif /* HAVE_TZSET */
531*d5c9a868SElliott Hughes #endif /* HAVE_GETTIMEOFDAY */
532*d5c9a868SElliott Hughes
533*d5c9a868SElliott Hughes accum += tzone;
534*d5c9a868SElliott Hughes
535*d5c9a868SElliott Hughes /* correct for Daylight Saving Time */
536*d5c9a868SElliott Hughes tmp = accum;
537*d5c9a868SElliott Hughes tmbuf = localtime(&tmp);
538*d5c9a868SElliott Hughes if(tmbuf) {
539*d5c9a868SElliott Hughes dst = (tmbuf->tm_isdst) ? (-60L * 60L) : 0L;
540*d5c9a868SElliott Hughes accum += dst;
541*d5c9a868SElliott Hughes }
542*d5c9a868SElliott Hughes return accum;
543*d5c9a868SElliott Hughes }
544*d5c9a868SElliott Hughes
545*d5c9a868SElliott Hughes
get_file_data(Stream_t * Stream,time_t * date,mt_off_t * size,int * type,uint32_t * address)546*d5c9a868SElliott Hughes static int get_file_data(Stream_t *Stream, time_t *date, mt_off_t *size,
547*d5c9a868SElliott Hughes int *type, uint32_t *address)
548*d5c9a868SElliott Hughes {
549*d5c9a868SElliott Hughes DeclareThis(File_t);
550*d5c9a868SElliott Hughes
551*d5c9a868SElliott Hughes if(date)
552*d5c9a868SElliott Hughes *date = conv_stamp(& This->direntry.dir);
553*d5c9a868SElliott Hughes if(size)
554*d5c9a868SElliott Hughes *size = to_mt_off_t(This->FileSize);
555*d5c9a868SElliott Hughes if(type)
556*d5c9a868SElliott Hughes *type = This->direntry.dir.attr & ATTR_DIR;
557*d5c9a868SElliott Hughes if(address)
558*d5c9a868SElliott Hughes *address = This->FirstAbsCluNr;
559*d5c9a868SElliott Hughes return 0;
560*d5c9a868SElliott Hughes }
561*d5c9a868SElliott Hughes
562*d5c9a868SElliott Hughes
free_file(Stream_t * Stream)563*d5c9a868SElliott Hughes static int free_file(Stream_t *Stream)
564*d5c9a868SElliott Hughes {
565*d5c9a868SElliott Hughes DeclareThis(File_t);
566*d5c9a868SElliott Hughes Fs_t *Fs = _getFs(This);
567*d5c9a868SElliott Hughes fsReleasePreallocateClusters(Fs, This->preallocatedClusters);
568*d5c9a868SElliott Hughes FREE(&This->direntry.Dir);
569*d5c9a868SElliott Hughes freeDirCache(Stream);
570*d5c9a868SElliott Hughes return hash_remove(filehash, (void *) Stream, This->hint);
571*d5c9a868SElliott Hughes }
572*d5c9a868SElliott Hughes
573*d5c9a868SElliott Hughes
flush_file(Stream_t * Stream)574*d5c9a868SElliott Hughes static int flush_file(Stream_t *Stream)
575*d5c9a868SElliott Hughes {
576*d5c9a868SElliott Hughes DeclareThis(File_t);
577*d5c9a868SElliott Hughes direntry_t *entry = &This->direntry;
578*d5c9a868SElliott Hughes
579*d5c9a868SElliott Hughes if(isRootDir(Stream)) {
580*d5c9a868SElliott Hughes return 0;
581*d5c9a868SElliott Hughes }
582*d5c9a868SElliott Hughes
583*d5c9a868SElliott Hughes if(This->FirstAbsCluNr != getStart(entry->Dir, &entry->dir)) {
584*d5c9a868SElliott Hughes set_word(entry->dir.start, This->FirstAbsCluNr & 0xffff);
585*d5c9a868SElliott Hughes set_word(entry->dir.startHi, This->FirstAbsCluNr >> 16);
586*d5c9a868SElliott Hughes dir_write(entry);
587*d5c9a868SElliott Hughes }
588*d5c9a868SElliott Hughes return 0;
589*d5c9a868SElliott Hughes }
590*d5c9a868SElliott Hughes
591*d5c9a868SElliott Hughes
pre_allocate_file(Stream_t * Stream,mt_off_t isize)592*d5c9a868SElliott Hughes static int pre_allocate_file(Stream_t *Stream, mt_off_t isize)
593*d5c9a868SElliott Hughes {
594*d5c9a868SElliott Hughes DeclareThis(File_t);
595*d5c9a868SElliott Hughes
596*d5c9a868SElliott Hughes uint32_t size = truncMtOffTo32u(isize);
597*d5c9a868SElliott Hughes
598*d5c9a868SElliott Hughes if(size > This->FileSize &&
599*d5c9a868SElliott Hughes size > This->preallocatedSize) {
600*d5c9a868SElliott Hughes This->preallocatedSize = size;
601*d5c9a868SElliott Hughes return recalcPreallocSize(This);
602*d5c9a868SElliott Hughes } else
603*d5c9a868SElliott Hughes return 0;
604*d5c9a868SElliott Hughes }
605*d5c9a868SElliott Hughes
606*d5c9a868SElliott Hughes static Class_t FileClass = {
607*d5c9a868SElliott Hughes read_file,
608*d5c9a868SElliott Hughes write_file,
609*d5c9a868SElliott Hughes pread_file,
610*d5c9a868SElliott Hughes pwrite_file,
611*d5c9a868SElliott Hughes flush_file, /* flush */
612*d5c9a868SElliott Hughes free_file, /* free */
613*d5c9a868SElliott Hughes 0, /* get_geom */
614*d5c9a868SElliott Hughes get_file_data,
615*d5c9a868SElliott Hughes pre_allocate_file,
616*d5c9a868SElliott Hughes get_dosConvert_pass_through,
617*d5c9a868SElliott Hughes 0 /* discard */
618*d5c9a868SElliott Hughes };
619*d5c9a868SElliott Hughes
getAbsCluNr(File_t * This)620*d5c9a868SElliott Hughes static unsigned int getAbsCluNr(File_t *This)
621*d5c9a868SElliott Hughes {
622*d5c9a868SElliott Hughes if(This->FirstAbsCluNr)
623*d5c9a868SElliott Hughes return This->FirstAbsCluNr;
624*d5c9a868SElliott Hughes if(isRootDir((Stream_t *) This))
625*d5c9a868SElliott Hughes return 0;
626*d5c9a868SElliott Hughes return 1;
627*d5c9a868SElliott Hughes }
628*d5c9a868SElliott Hughes
func1(void * Stream)629*d5c9a868SElliott Hughes static uint32_t func1(void *Stream)
630*d5c9a868SElliott Hughes {
631*d5c9a868SElliott Hughes DeclareThis(File_t);
632*d5c9a868SElliott Hughes
633*d5c9a868SElliott Hughes return getAbsCluNr(This) ^ (uint32_t) (unsigned long) This->head.Next;
634*d5c9a868SElliott Hughes }
635*d5c9a868SElliott Hughes
func2(void * Stream)636*d5c9a868SElliott Hughes static uint32_t func2(void *Stream)
637*d5c9a868SElliott Hughes {
638*d5c9a868SElliott Hughes DeclareThis(File_t);
639*d5c9a868SElliott Hughes
640*d5c9a868SElliott Hughes return getAbsCluNr(This);
641*d5c9a868SElliott Hughes }
642*d5c9a868SElliott Hughes
comp(void * Stream,void * Stream2)643*d5c9a868SElliott Hughes static int comp(void *Stream, void *Stream2)
644*d5c9a868SElliott Hughes {
645*d5c9a868SElliott Hughes DeclareThis(File_t);
646*d5c9a868SElliott Hughes
647*d5c9a868SElliott Hughes File_t *This2 = (File_t *) Stream2;
648*d5c9a868SElliott Hughes
649*d5c9a868SElliott Hughes return _getFs(This) != _getFs(This2) ||
650*d5c9a868SElliott Hughes getAbsCluNr(This) != getAbsCluNr(This2);
651*d5c9a868SElliott Hughes }
652*d5c9a868SElliott Hughes
init_hash(void)653*d5c9a868SElliott Hughes static void init_hash(void)
654*d5c9a868SElliott Hughes {
655*d5c9a868SElliott Hughes static int is_initialised=0;
656*d5c9a868SElliott Hughes
657*d5c9a868SElliott Hughes if(!is_initialised){
658*d5c9a868SElliott Hughes make_ht(func1, func2, comp, 20, &filehash);
659*d5c9a868SElliott Hughes is_initialised = 1;
660*d5c9a868SElliott Hughes }
661*d5c9a868SElliott Hughes }
662*d5c9a868SElliott Hughes
663*d5c9a868SElliott Hughes
_internalFileOpen(Stream_t * Dir,unsigned int first,uint32_t size,direntry_t * entry)664*d5c9a868SElliott Hughes static Stream_t *_internalFileOpen(Stream_t *Dir, unsigned int first,
665*d5c9a868SElliott Hughes uint32_t size, direntry_t *entry)
666*d5c9a868SElliott Hughes {
667*d5c9a868SElliott Hughes Stream_t *Stream = GetFs(Dir);
668*d5c9a868SElliott Hughes DeclareThis(Fs_t);
669*d5c9a868SElliott Hughes File_t Pattern;
670*d5c9a868SElliott Hughes File_t *File;
671*d5c9a868SElliott Hughes
672*d5c9a868SElliott Hughes init_hash();
673*d5c9a868SElliott Hughes This->head.refs++;
674*d5c9a868SElliott Hughes
675*d5c9a868SElliott Hughes if(first != 1){
676*d5c9a868SElliott Hughes /* we use the illegal cluster 1 to mark newly created files.
677*d5c9a868SElliott Hughes * do not manage those by hashtable */
678*d5c9a868SElliott Hughes init_head(&Pattern.head, &FileClass, &This->head);
679*d5c9a868SElliott Hughes if(first || (entry && !IS_DIR(entry)))
680*d5c9a868SElliott Hughes Pattern.map = normal_map;
681*d5c9a868SElliott Hughes else
682*d5c9a868SElliott Hughes Pattern.map = root_map;
683*d5c9a868SElliott Hughes Pattern.FirstAbsCluNr = first;
684*d5c9a868SElliott Hughes Pattern.loopDetectRel = 0;
685*d5c9a868SElliott Hughes Pattern.loopDetectAbs = first;
686*d5c9a868SElliott Hughes if(!hash_lookup(filehash, (T_HashTableEl) &Pattern,
687*d5c9a868SElliott Hughes (T_HashTableEl **)&File, 0)){
688*d5c9a868SElliott Hughes File->head.refs++;
689*d5c9a868SElliott Hughes This->head.refs--;
690*d5c9a868SElliott Hughes return (Stream_t *) File;
691*d5c9a868SElliott Hughes }
692*d5c9a868SElliott Hughes }
693*d5c9a868SElliott Hughes
694*d5c9a868SElliott Hughes File = New(File_t);
695*d5c9a868SElliott Hughes if (!File)
696*d5c9a868SElliott Hughes return NULL;
697*d5c9a868SElliott Hughes init_head(&File->head, &FileClass, &This->head);
698*d5c9a868SElliott Hughes File->Buffer = NULL;
699*d5c9a868SElliott Hughes File->dcp = 0;
700*d5c9a868SElliott Hughes File->preallocatedClusters = 0;
701*d5c9a868SElliott Hughes File->preallocatedSize = 0;
702*d5c9a868SElliott Hughes /* memorize dir for date and attrib */
703*d5c9a868SElliott Hughes File->direntry = *entry;
704*d5c9a868SElliott Hughes if(entry->entry == -3)
705*d5c9a868SElliott Hughes File->direntry.Dir = (Stream_t *) File; /* root directory */
706*d5c9a868SElliott Hughes else
707*d5c9a868SElliott Hughes COPY(File->direntry.Dir);
708*d5c9a868SElliott Hughes File->where = 0;
709*d5c9a868SElliott Hughes if(first || (entry && !IS_DIR(entry)))
710*d5c9a868SElliott Hughes File->map = normal_map;
711*d5c9a868SElliott Hughes else
712*d5c9a868SElliott Hughes File->map = root_map; /* FAT 12/16 root directory */
713*d5c9a868SElliott Hughes if(first == 1)
714*d5c9a868SElliott Hughes File->FirstAbsCluNr = 0;
715*d5c9a868SElliott Hughes else
716*d5c9a868SElliott Hughes File->FirstAbsCluNr = first;
717*d5c9a868SElliott Hughes
718*d5c9a868SElliott Hughes File->loopDetectRel = 0;
719*d5c9a868SElliott Hughes File->loopDetectAbs = 0;
720*d5c9a868SElliott Hughes
721*d5c9a868SElliott Hughes File->PreviousRelCluNr = 0xffff;
722*d5c9a868SElliott Hughes File->FileSize = size;
723*d5c9a868SElliott Hughes hash_add(filehash, (void *) File, &File->hint);
724*d5c9a868SElliott Hughes return (Stream_t *) File;
725*d5c9a868SElliott Hughes }
726*d5c9a868SElliott Hughes
bufferize(Stream_t ** Dir)727*d5c9a868SElliott Hughes static void bufferize(Stream_t **Dir)
728*d5c9a868SElliott Hughes {
729*d5c9a868SElliott Hughes Stream_t *BDir;
730*d5c9a868SElliott Hughes File_t *file = (File_t *) *Dir;
731*d5c9a868SElliott Hughes
732*d5c9a868SElliott Hughes if(!*Dir)
733*d5c9a868SElliott Hughes return;
734*d5c9a868SElliott Hughes
735*d5c9a868SElliott Hughes if(file->Buffer){
736*d5c9a868SElliott Hughes (*Dir)->refs--;
737*d5c9a868SElliott Hughes file->Buffer->refs++;
738*d5c9a868SElliott Hughes *Dir = file->Buffer;
739*d5c9a868SElliott Hughes return;
740*d5c9a868SElliott Hughes }
741*d5c9a868SElliott Hughes
742*d5c9a868SElliott Hughes BDir = buf_init(*Dir, 64*16384, 512, MDIR_SIZE);
743*d5c9a868SElliott Hughes if(!BDir){
744*d5c9a868SElliott Hughes FREE(Dir);
745*d5c9a868SElliott Hughes *Dir = NULL;
746*d5c9a868SElliott Hughes } else {
747*d5c9a868SElliott Hughes file->Buffer = BDir;
748*d5c9a868SElliott Hughes *Dir = BDir;
749*d5c9a868SElliott Hughes }
750*d5c9a868SElliott Hughes }
751*d5c9a868SElliott Hughes
752*d5c9a868SElliott Hughes
OpenRoot(Stream_t * Dir)753*d5c9a868SElliott Hughes Stream_t *OpenRoot(Stream_t *Dir)
754*d5c9a868SElliott Hughes {
755*d5c9a868SElliott Hughes unsigned int num;
756*d5c9a868SElliott Hughes direntry_t entry;
757*d5c9a868SElliott Hughes uint32_t size;
758*d5c9a868SElliott Hughes Stream_t *file;
759*d5c9a868SElliott Hughes
760*d5c9a868SElliott Hughes memset(&entry, 0, sizeof(direntry_t));
761*d5c9a868SElliott Hughes
762*d5c9a868SElliott Hughes num = fat32RootCluster(Dir);
763*d5c9a868SElliott Hughes
764*d5c9a868SElliott Hughes /* make the directory entry */
765*d5c9a868SElliott Hughes entry.entry = -3;
766*d5c9a868SElliott Hughes entry.name[0] = '\0';
767*d5c9a868SElliott Hughes mk_entry_from_base("/", ATTR_DIR, num, 0, 0, &entry.dir);
768*d5c9a868SElliott Hughes
769*d5c9a868SElliott Hughes if(num)
770*d5c9a868SElliott Hughes size = countBytes(Dir, num);
771*d5c9a868SElliott Hughes else {
772*d5c9a868SElliott Hughes Fs_t *Fs = (Fs_t *) GetFs(Dir);
773*d5c9a868SElliott Hughes size = Fs->dir_len * Fs->sector_size;
774*d5c9a868SElliott Hughes }
775*d5c9a868SElliott Hughes file = _internalFileOpen(Dir, num, size, &entry);
776*d5c9a868SElliott Hughes bufferize(&file);
777*d5c9a868SElliott Hughes return file;
778*d5c9a868SElliott Hughes }
779*d5c9a868SElliott Hughes
780*d5c9a868SElliott Hughes
OpenFileByDirentry(direntry_t * entry)781*d5c9a868SElliott Hughes Stream_t *OpenFileByDirentry(direntry_t *entry)
782*d5c9a868SElliott Hughes {
783*d5c9a868SElliott Hughes Stream_t *file;
784*d5c9a868SElliott Hughes unsigned int first;
785*d5c9a868SElliott Hughes uint32_t size;
786*d5c9a868SElliott Hughes
787*d5c9a868SElliott Hughes first = getStart(entry->Dir, &entry->dir);
788*d5c9a868SElliott Hughes
789*d5c9a868SElliott Hughes if(!first && IS_DIR(entry))
790*d5c9a868SElliott Hughes return OpenRoot(entry->Dir);
791*d5c9a868SElliott Hughes if (IS_DIR(entry))
792*d5c9a868SElliott Hughes size = countBytes(entry->Dir, first);
793*d5c9a868SElliott Hughes else
794*d5c9a868SElliott Hughes size = FILE_SIZE(&entry->dir);
795*d5c9a868SElliott Hughes file = _internalFileOpen(entry->Dir, first, size, entry);
796*d5c9a868SElliott Hughes if(IS_DIR(entry)) {
797*d5c9a868SElliott Hughes bufferize(&file);
798*d5c9a868SElliott Hughes if(first == 1)
799*d5c9a868SElliott Hughes dir_grow(file, 0);
800*d5c9a868SElliott Hughes }
801*d5c9a868SElliott Hughes
802*d5c9a868SElliott Hughes return file;
803*d5c9a868SElliott Hughes }
804*d5c9a868SElliott Hughes
805*d5c9a868SElliott Hughes
isRootDir(Stream_t * Stream)806*d5c9a868SElliott Hughes int isRootDir(Stream_t *Stream)
807*d5c9a868SElliott Hughes {
808*d5c9a868SElliott Hughes File_t *This = getUnbufferedFile(Stream);
809*d5c9a868SElliott Hughes
810*d5c9a868SElliott Hughes return This->map == root_map;
811*d5c9a868SElliott Hughes }
812