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