xref: /AOO41X/main/sot/source/sdstor/stgio.cxx (revision 8809db7a87f97847b57a57f4cd2b0104b2b83182)
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 
39 StgIo::StgIo() : StgCache()
40 {
41     pTOC      = NULL;
42     pDataFAT  = NULL;
43     pDataStrm = NULL;
44     pFAT      = NULL;
45     bCopied   = sal_False;
46 }
47 
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 
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     }
70     return Good();
71 }
72 
73 // Set up an initial, empty storage
74 
75 sal_Bool StgIo::Init()
76 {
77     aHdr.Init();
78     SetupStreams();
79     return CommitAll();
80 }
81 
82 void StgIo::SetupStreams()
83 {
84     delete pTOC;
85     delete pDataFAT;
86     delete pDataStrm;
87     delete pFAT;
88     pTOC      = NULL;
89     pDataFAT  = NULL;
90     pDataStrm = NULL;
91     pFAT      = NULL;
92     ResetError();
93     SetPhysPageSize( 1 << aHdr.GetPageSize() );
94     pFAT = new StgFATStrm( *this );
95     pTOC = new StgDirStrm( *this );
96     if( !GetError() )
97     {
98         StgDirEntry* pRoot = pTOC->GetRoot();
99         if( pRoot )
100         {
101             pDataFAT = new StgDataStrm( *this, aHdr.GetDataFATStart(), -1 );
102             pDataStrm = new StgDataStrm( *this, pRoot );
103             pDataFAT->SetIncrement( 1 << aHdr.GetPageSize() );
104             pDataStrm->SetIncrement( GetDataPageSize() );
105             pDataStrm->SetEntry( *pRoot );
106         }
107         else
108             SetError( SVSTREAM_FILEFORMAT_ERROR );
109     }
110 }
111 
112 // get the logical data page size
113 
114 short StgIo::GetDataPageSize()
115 {
116     return 1 << aHdr.GetDataPageSize();
117 }
118 
119 // Commit everything
120 
121 sal_Bool StgIo::CommitAll()
122 {
123     // Store the data (all streams and the TOC)
124     if( pTOC->Store() )
125     {
126         if( Commit( NULL ) )
127         {
128             aHdr.SetDataFATStart( pDataFAT->GetStart() );
129             aHdr.SetDataFATSize( pDataFAT->GetPages() );
130             aHdr.SetTOCStart( pTOC->GetStart() );
131             if( aHdr.Store( *this ) )
132             {
133                 pStrm->Flush();
134                 sal_uLong n = pStrm->GetError();
135                 SetError( n );
136 #ifdef DBG_UTIL
137                 if( n==0 ) ValidateFATs();
138 #endif
139                 return sal_Bool( n == 0 );
140             }
141         }
142     }
143     SetError( SVSTREAM_WRITE_ERROR );
144     return sal_False;
145 }
146 
147 
148 class EasyFat
149 {
150     sal_Int32 *pFat;
151     sal_Bool  *pFree;
152     sal_Int32 nPages;
153     sal_Int32 nPageSize;
154 
155 public:
156     EasyFat( StgIo & rIo, StgStrm *pFatStream, sal_Int32 nPSize );
157     ~EasyFat() { delete[] pFat; delete[] pFree; }
158 
159     sal_Int32 GetPageSize() { return nPageSize; }
160     sal_Int32 Count() { return nPages; }
161     sal_Int32 operator[]( sal_Int32 nOffset ) { return pFat[ nOffset ]; }
162 
163     sal_uLong Mark( sal_Int32 nPage, sal_Int32 nCount, sal_Int32 nExpect );
164     sal_Bool HasUnrefChains();
165 };
166 
167 EasyFat::EasyFat( StgIo& rIo, StgStrm* pFatStream, sal_Int32 nPSize )
168 {
169     nPages = pFatStream->GetSize() >> 2;
170     nPageSize = nPSize;
171     pFat = new sal_Int32[ nPages ];
172     pFree = new sal_Bool[ nPages ];
173 
174     StgPage *pPage = NULL;
175     sal_Int32 nFatPageSize = (1 << rIo.aHdr.GetPageSize()) - 2;
176 
177     for( sal_Int32 nPage = 0; nPage < nPages; nPage++ )
178     {
179         if( ! (nPage % nFatPageSize) )
180         {
181             pFatStream->Pos2Page( nPage << 2 );
182             sal_Int32 nPhysPage = pFatStream->GetPage();
183             pPage = rIo.Get( nPhysPage, sal_True );
184         }
185 
186         pFat[ nPage ] = pPage->GetPage( short( nPage % nFatPageSize ) );
187         pFree[ nPage ] = sal_True;
188     }
189 }
190 
191 sal_Bool EasyFat::HasUnrefChains()
192 {
193     for( sal_Int32 nPage = 0; nPage < nPages; nPage++ )
194     {
195         if( pFree[ nPage ] && pFat[ nPage ] != -1 )
196             return sal_True;
197     }
198     return sal_False;
199 }
200 
201 sal_uLong EasyFat::Mark( sal_Int32 nPage, sal_Int32 nCount, sal_Int32 nExpect )
202 {
203     if( nCount > 0 )
204         --nCount /= GetPageSize(), nCount++;
205 
206     sal_Int32 nCurPage = nPage;
207     while( nCount != 0 )
208     {
209         pFree[ nCurPage ] = sal_False;
210         nCurPage = pFat[ nCurPage ];
211         //Stream zu lang
212         if( nCurPage != nExpect && nCount == 1 )
213             return FAT_WRONGLENGTH;
214         //Stream zu kurz
215         if( nCurPage == nExpect && nCount != 1 && nCount != -1 )
216             return FAT_WRONGLENGTH;
217         // letzter Block bei Stream ohne Laenge
218         if( nCurPage == nExpect && nCount == -1 )
219             nCount = 1;
220         if( nCount != -1 )
221             nCount--;
222         // Naechster Block nicht in der FAT
223         if( nCount && ( nCurPage < 0 || nCurPage >= nPages ) )
224             return FAT_OUTOFBOUNDS;
225     }
226     return FAT_OK;
227 }
228 
229 class Validator
230 {
231     sal_uLong nError;
232 
233     EasyFat aSmallFat;
234     EasyFat aFat;
235 
236     StgIo &rIo;
237 
238     sal_uLong ValidateMasterFATs();
239     sal_uLong ValidateDirectoryEntries();
240     sal_uLong FindUnrefedChains();
241     sal_uLong MarkAll( StgDirEntry *pEntry );
242 
243 public:
244 
245     Validator( StgIo &rIo );
246     sal_Bool IsError() { return nError != 0; }
247 };
248 
249 Validator::Validator( StgIo &rIoP )
250     : aSmallFat( rIoP, rIoP.pDataFAT, 1 << rIoP.aHdr.GetDataPageSize() ),
251       aFat( rIoP, rIoP.pFAT, 1 << rIoP.aHdr.GetPageSize() ),
252       rIo( rIoP )
253 {
254     sal_uLong nErr = nError = FAT_OK;
255 
256     if( ( nErr = ValidateMasterFATs() ) != FAT_OK )
257         nError = nErr;
258     else if(    ( nErr = ValidateDirectoryEntries() ) != FAT_OK )
259         nError = nErr;
260     else if(    ( nErr = FindUnrefedChains()) != FAT_OK )
261         nError = nErr;
262 }
263 
264 sal_uLong Validator::ValidateMasterFATs()
265 {
266     sal_Int32 nCount = rIo.aHdr.GetFATSize();
267     sal_uLong nErr;
268     for( sal_Int32 i = 0; i < nCount; i++ )
269     {
270         if( ( nErr = aFat.Mark(rIo.pFAT->GetPage( short(i), sal_False ), aFat.GetPageSize(), -3 )) != FAT_OK )
271             return nErr;
272     }
273     if( rIo.aHdr.GetMasters() )
274         if( ( nErr = aFat.Mark(rIo.aHdr.GetFATChain( ), aFat.GetPageSize(), -4 )) != FAT_OK )
275             return nErr;
276     return FAT_OK;
277 }
278 
279 sal_uLong Validator::MarkAll( StgDirEntry *pEntry )
280 {
281     StgIterator aIter( *pEntry );
282     sal_uLong nErr = FAT_OK;
283     for( StgDirEntry* p = aIter.First(); p ; p = aIter.Next() )
284     {
285         if( p->aEntry.GetType() == STG_STORAGE )
286         {
287             nErr = MarkAll( p );
288             if( nErr != FAT_OK )
289                 return nErr;
290         }
291         else
292         {
293             sal_Int32 nSize = p->aEntry.GetSize();
294             if( nSize < rIo.aHdr.GetThreshold()  )
295                 nErr = aSmallFat.Mark( p->aEntry.GetStartPage(),nSize, -2 );
296             else
297                 nErr = aFat.Mark( p->aEntry.GetStartPage(),nSize, -2 );
298             if( nErr != FAT_OK )
299                 return nErr;
300         }
301     }
302     return FAT_OK;
303 }
304 
305 sal_uLong Validator::ValidateDirectoryEntries()
306 {
307     // Normale DirEntries
308     sal_uLong nErr = MarkAll( rIo.pTOC->GetRoot() );
309     if( nErr != FAT_OK )
310         return nErr;
311     // Small Data
312     nErr = aFat.Mark( rIo.pTOC->GetRoot()->aEntry.GetStartPage(),
313                  rIo.pTOC->GetRoot()->aEntry.GetSize(), -2 );
314     if( nErr != FAT_OK )
315         return nErr;
316     // Small Data FAT
317     nErr = aFat.Mark(
318         rIo.aHdr.GetDataFATStart(),
319         rIo.aHdr.GetDataFATSize() * aFat.GetPageSize(), -2 );
320     if( nErr != FAT_OK )
321         return nErr;
322     // TOC
323     nErr = aFat.Mark(
324         rIo.aHdr.GetTOCStart(), -1, -2 );
325     return nErr;
326 }
327 
328 sal_uLong Validator::FindUnrefedChains()
329 {
330     if( aSmallFat.HasUnrefChains() ||
331         aFat.HasUnrefChains() )
332         return FAT_UNREFCHAIN;
333     else
334         return FAT_OK;
335 }
336 
337 namespace { struct ErrorLink : public rtl::Static<Link, ErrorLink > {}; }
338 
339 void StgIo::SetErrorLink( const Link& rLink )
340 {
341     ErrorLink::get() = rLink;
342 }
343 
344 const Link& StgIo::GetErrorLink()
345 {
346     return ErrorLink::get();
347 }
348 
349 sal_uLong StgIo::ValidateFATs()
350 {
351     if( bFile )
352     {
353         Validator *pV = new Validator( *this );
354         sal_Bool bRet1 = !pV->IsError(), bRet2 = sal_True ;
355         delete pV;
356         SvFileStream *pFileStrm = ( SvFileStream *) GetStrm();
357         StgIo aIo;
358         if( aIo.Open( pFileStrm->GetFileName(),
359                       STREAM_READ  | STREAM_SHARE_DENYNONE) &&
360             aIo.Load() )
361         {
362             pV = new Validator( aIo );
363             bRet2 = !pV->IsError();
364             delete pV;
365         }
366 
367         sal_uLong nErr;
368         if( bRet1 != bRet2 )
369             nErr = bRet1 ? FAT_ONFILEERROR : FAT_INMEMORYERROR;
370         else nErr = bRet1 ? FAT_OK : FAT_BOTHERROR;
371         if( nErr != FAT_OK && !bCopied )
372         {
373             StgLinkArg aArg;
374             aArg.aFile = pFileStrm->GetFileName();
375             aArg.nErr = nErr;
376             ErrorLink::get().Call( &aArg );
377             bCopied = sal_True;
378         }
379 //      DBG_ASSERT( nErr == FAT_OK ,"Storage kaputt");
380         return nErr;
381     }
382 //  DBG_ERROR("Validiere nicht (kein FileStorage)");
383     return FAT_OK;
384 }
385