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