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