xref: /trunk/main/sot/source/sdstor/stgio.cxx (revision 297a844a)
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