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