xref: /trunk/main/sot/source/sdstor/stgio.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sot.hxx"
30 
31 #include "sot/stg.hxx"
32 #include "stgelem.hxx"
33 #include "stgcache.hxx"
34 #include "stgstrms.hxx"
35 #include "stgdir.hxx"
36 #include "stgio.hxx"
37 #include <rtl/instance.hxx>
38 
39 ///////////////////////////// class StgIo //////////////////////////////
40 
41 // This class holds the storage header and all internal streams.
42 
43 StgIo::StgIo() : StgCache()
44 {
45     pTOC      = NULL;
46     pDataFAT  = NULL;
47     pDataStrm = NULL;
48     pFAT      = NULL;
49     bCopied   = sal_False;
50 }
51 
52 StgIo::~StgIo()
53 {
54     delete pTOC;
55     delete pDataFAT;
56     delete pDataStrm;
57     delete pFAT;
58 }
59 
60 // Load the header. Do not set an error code if the header is invalid.
61 
62 sal_Bool StgIo::Load()
63 {
64     if( pStrm )
65     {
66         if( aHdr.Load( *this ) )
67         {
68             if( aHdr.Check() )
69                 SetupStreams();
70             else
71                 return sal_False;
72         }
73     }
74     return Good();
75 }
76 
77 // Set up an initial, empty storage
78 
79 sal_Bool StgIo::Init()
80 {
81     aHdr.Init();
82     SetupStreams();
83     return CommitAll();
84 }
85 
86 void StgIo::SetupStreams()
87 {
88     delete pTOC;
89     delete pDataFAT;
90     delete pDataStrm;
91     delete pFAT;
92     pTOC      = NULL;
93     pDataFAT  = NULL;
94     pDataStrm = NULL;
95     pFAT      = NULL;
96     ResetError();
97     SetPhysPageSize( 1 << aHdr.GetPageSize() );
98     pFAT = new StgFATStrm( *this );
99     pTOC = new StgDirStrm( *this );
100     if( !GetError() )
101     {
102         StgDirEntry* pRoot = pTOC->GetRoot();
103         if( pRoot )
104         {
105             pDataFAT = new StgDataStrm( *this, aHdr.GetDataFATStart(), -1 );
106             pDataStrm = new StgDataStrm( *this, pRoot );
107             pDataFAT->SetIncrement( 1 << aHdr.GetPageSize() );
108             pDataStrm->SetIncrement( GetDataPageSize() );
109             pDataStrm->SetEntry( *pRoot );
110         }
111         else
112             SetError( SVSTREAM_FILEFORMAT_ERROR );
113     }
114 }
115 
116 // get the logical data page size
117 
118 short StgIo::GetDataPageSize()
119 {
120     return 1 << aHdr.GetDataPageSize();
121 }
122 
123 // Commit everything
124 
125 sal_Bool StgIo::CommitAll()
126 {
127     // Store the data (all streams and the TOC)
128     if( pTOC->Store() )
129     {
130         if( Commit( NULL ) )
131         {
132             aHdr.SetDataFATStart( pDataFAT->GetStart() );
133             aHdr.SetDataFATSize( pDataFAT->GetPages() );
134             aHdr.SetTOCStart( pTOC->GetStart() );
135             if( aHdr.Store( *this ) )
136             {
137                 pStrm->Flush();
138                 sal_uLong n = pStrm->GetError();
139                 SetError( n );
140 #ifdef DBG_UTIL
141                 if( n==0 ) ValidateFATs();
142 #endif
143                 return sal_Bool( n == 0 );
144             }
145         }
146     }
147     SetError( SVSTREAM_WRITE_ERROR );
148     return sal_False;
149 }
150 
151 
152 class EasyFat
153 {
154     sal_Int32 *pFat;
155     sal_Bool  *pFree;
156     sal_Int32 nPages;
157     sal_Int32 nPageSize;
158 
159 public:
160     EasyFat( StgIo & rIo, StgStrm *pFatStream, sal_Int32 nPSize );
161     ~EasyFat() { delete[] pFat; delete[] pFree; }
162 
163     sal_Int32 GetPageSize() { return nPageSize; }
164     sal_Int32 Count() { return nPages; }
165     sal_Int32 operator[]( sal_Int32 nOffset ) { return pFat[ nOffset ]; }
166 
167     sal_uLong Mark( sal_Int32 nPage, sal_Int32 nCount, sal_Int32 nExpect );
168     sal_Bool HasUnrefChains();
169 };
170 
171 EasyFat::EasyFat( StgIo& rIo, StgStrm* pFatStream, sal_Int32 nPSize )
172 {
173     nPages = pFatStream->GetSize() >> 2;
174     nPageSize = nPSize;
175     pFat = new sal_Int32[ nPages ];
176     pFree = new sal_Bool[ nPages ];
177 
178     StgPage *pPage = NULL;
179     sal_Int32 nFatPageSize = (1 << rIo.aHdr.GetPageSize()) - 2;
180 
181     for( sal_Int32 nPage = 0; nPage < nPages; nPage++ )
182     {
183         if( ! (nPage % nFatPageSize) )
184         {
185             pFatStream->Pos2Page( nPage << 2 );
186             sal_Int32 nPhysPage = pFatStream->GetPage();
187             pPage = rIo.Get( nPhysPage, sal_True );
188         }
189 
190         pFat[ nPage ] = pPage->GetPage( short( nPage % nFatPageSize ) );
191         pFree[ nPage ] = sal_True;
192     }
193 }
194 
195 sal_Bool EasyFat::HasUnrefChains()
196 {
197     for( sal_Int32 nPage = 0; nPage < nPages; nPage++ )
198     {
199         if( pFree[ nPage ] && pFat[ nPage ] != -1 )
200             return sal_True;
201     }
202     return sal_False;
203 }
204 
205 sal_uLong EasyFat::Mark( sal_Int32 nPage, sal_Int32 nCount, sal_Int32 nExpect )
206 {
207     if( nCount > 0 )
208         --nCount /= GetPageSize(), nCount++;
209 
210     sal_Int32 nCurPage = nPage;
211     while( nCount != 0 )
212     {
213         pFree[ nCurPage ] = sal_False;
214         nCurPage = pFat[ nCurPage ];
215         //Stream zu lang
216         if( nCurPage != nExpect && nCount == 1 )
217             return FAT_WRONGLENGTH;
218         //Stream zu kurz
219         if( nCurPage == nExpect && nCount != 1 && nCount != -1 )
220             return FAT_WRONGLENGTH;
221         // letzter Block bei Stream ohne Laenge
222         if( nCurPage == nExpect && nCount == -1 )
223             nCount = 1;
224         if( nCount != -1 )
225             nCount--;
226         // Naechster Block nicht in der FAT
227         if( nCount && ( nCurPage < 0 || nCurPage >= nPages ) )
228             return FAT_OUTOFBOUNDS;
229     }
230     return FAT_OK;
231 }
232 
233 class Validator
234 {
235     sal_uLong nError;
236 
237     EasyFat aSmallFat;
238     EasyFat aFat;
239 
240     StgIo &rIo;
241 
242     sal_uLong ValidateMasterFATs();
243     sal_uLong ValidateDirectoryEntries();
244     sal_uLong FindUnrefedChains();
245     sal_uLong MarkAll( StgDirEntry *pEntry );
246 
247 public:
248 
249     Validator( StgIo &rIo );
250     sal_Bool IsError() { return nError != 0; }
251 };
252 
253 Validator::Validator( StgIo &rIoP )
254     : aSmallFat( rIoP, rIoP.pDataFAT, 1 << rIoP.aHdr.GetDataPageSize() ),
255       aFat( rIoP, rIoP.pFAT, 1 << rIoP.aHdr.GetPageSize() ),
256       rIo( rIoP )
257 {
258     sal_uLong nErr = nError = FAT_OK;
259 
260     if( ( nErr = ValidateMasterFATs() ) != FAT_OK )
261         nError = nErr;
262     else if(    ( nErr = ValidateDirectoryEntries() ) != FAT_OK )
263         nError = nErr;
264     else if(    ( nErr = FindUnrefedChains()) != FAT_OK )
265         nError = nErr;
266 }
267 
268 sal_uLong Validator::ValidateMasterFATs()
269 {
270     sal_Int32 nCount = rIo.aHdr.GetFATSize();
271     sal_uLong nErr;
272     for( sal_Int32 i = 0; i < nCount; i++ )
273     {
274         if( ( nErr = aFat.Mark(rIo.pFAT->GetPage( short(i), sal_False ), aFat.GetPageSize(), -3 )) != FAT_OK )
275             return nErr;
276     }
277     if( rIo.aHdr.GetMasters() )
278         if( ( nErr = aFat.Mark(rIo.aHdr.GetFATChain( ), aFat.GetPageSize(), -4 )) != FAT_OK )
279             return nErr;
280     return FAT_OK;
281 }
282 
283 sal_uLong Validator::MarkAll( StgDirEntry *pEntry )
284 {
285     StgIterator aIter( *pEntry );
286     sal_uLong nErr = FAT_OK;
287     for( StgDirEntry* p = aIter.First(); p ; p = aIter.Next() )
288     {
289         if( p->aEntry.GetType() == STG_STORAGE )
290         {
291             nErr = MarkAll( p );
292             if( nErr != FAT_OK )
293                 return nErr;
294         }
295         else
296         {
297             sal_Int32 nSize = p->aEntry.GetSize();
298             if( nSize < rIo.aHdr.GetThreshold()  )
299                 nErr = aSmallFat.Mark( p->aEntry.GetStartPage(),nSize, -2 );
300             else
301                 nErr = aFat.Mark( p->aEntry.GetStartPage(),nSize, -2 );
302             if( nErr != FAT_OK )
303                 return nErr;
304         }
305     }
306     return FAT_OK;
307 }
308 
309 sal_uLong Validator::ValidateDirectoryEntries()
310 {
311     // Normale DirEntries
312     sal_uLong nErr = MarkAll( rIo.pTOC->GetRoot() );
313     if( nErr != FAT_OK )
314         return nErr;
315     // Small Data
316     nErr = aFat.Mark( rIo.pTOC->GetRoot()->aEntry.GetStartPage(),
317                  rIo.pTOC->GetRoot()->aEntry.GetSize(), -2 );
318     if( nErr != FAT_OK )
319         return nErr;
320     // Small Data FAT
321     nErr = aFat.Mark(
322         rIo.aHdr.GetDataFATStart(),
323         rIo.aHdr.GetDataFATSize() * aFat.GetPageSize(), -2 );
324     if( nErr != FAT_OK )
325         return nErr;
326     // TOC
327     nErr = aFat.Mark(
328         rIo.aHdr.GetTOCStart(), -1, -2 );
329     return nErr;
330 }
331 
332 sal_uLong Validator::FindUnrefedChains()
333 {
334     if( aSmallFat.HasUnrefChains() ||
335         aFat.HasUnrefChains() )
336         return FAT_UNREFCHAIN;
337     else
338         return FAT_OK;
339 }
340 
341 namespace { struct ErrorLink : public rtl::Static<Link, ErrorLink > {}; }
342 
343 void StgIo::SetErrorLink( const Link& rLink )
344 {
345     ErrorLink::get() = rLink;
346 }
347 
348 const Link& StgIo::GetErrorLink()
349 {
350     return ErrorLink::get();
351 }
352 
353 sal_uLong StgIo::ValidateFATs()
354 {
355     if( bFile )
356     {
357         Validator *pV = new Validator( *this );
358         sal_Bool bRet1 = !pV->IsError(), bRet2 = sal_True ;
359         delete pV;
360         SvFileStream *pFileStrm = ( SvFileStream *) GetStrm();
361         StgIo aIo;
362         if( aIo.Open( pFileStrm->GetFileName(),
363                       STREAM_READ  | STREAM_SHARE_DENYNONE) &&
364             aIo.Load() )
365         {
366             pV = new Validator( aIo );
367             bRet2 = !pV->IsError();
368             delete pV;
369         }
370 
371         sal_uLong nErr;
372         if( bRet1 != bRet2 )
373             nErr = bRet1 ? FAT_ONFILEERROR : FAT_INMEMORYERROR;
374         else nErr = bRet1 ? FAT_OK : FAT_BOTHERROR;
375         if( nErr != FAT_OK && !bCopied )
376         {
377             StgLinkArg aArg;
378             aArg.aFile = pFileStrm->GetFileName();
379             aArg.nErr = nErr;
380             ErrorLink::get().Call( &aArg );
381             bCopied = sal_True;
382         }
383 //      DBG_ASSERT( nErr == FAT_OK ,"Storage kaputt");
384         return nErr;
385     }
386 //  DBG_ERROR("Validiere nicht (kein FileStorage)");
387     return FAT_OK;
388 }
389