xref: /trunk/main/sot/source/sdstor/stgio.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sot.hxx"
30 
31 #include "sot/stg.hxx"
32 #include "stgelem.hxx"
33 #include "stgcache.hxx"
34 #include "stgstrms.hxx"
35 #include "stgdir.hxx"
36 #include "stgio.hxx"
37 #include <rtl/instance.hxx>
38 
39 ///////////////////////////// class StgIo //////////////////////////////
40 
41 // This class holds the storage header and all internal streams.
42 
43 StgIo::StgIo() : StgCache()
44 {
45     pTOC      = NULL;
46     pDataFAT  = NULL;
47     pDataStrm = NULL;
48     pFAT      = NULL;
49 	bCopied   = sal_False;
50 }
51 
52 StgIo::~StgIo()
53 {
54     delete pTOC;
55     delete pDataFAT;
56     delete pDataStrm;
57     delete pFAT;
58 }
59 
60 // Load the header. Do not set an error code if the header is invalid.
61 
62 sal_Bool StgIo::Load()
63 {
64     if( pStrm )
65     {
66         if( aHdr.Load( *this ) )
67         {
68             if( aHdr.Check() )
69                 SetupStreams();
70             else
71 				return sal_False;
72         }
73     }
74     return Good();
75 }
76 
77 // Set up an initial, empty storage
78 
79 sal_Bool StgIo::Init()
80 {
81     aHdr.Init();
82     SetupStreams();
83     return CommitAll();
84 }
85 
86 void StgIo::SetupStreams()
87 {
88     delete pTOC;
89     delete pDataFAT;
90     delete pDataStrm;
91     delete pFAT;
92     pTOC      = NULL;
93     pDataFAT  = NULL;
94     pDataStrm = NULL;
95     pFAT      = NULL;
96     ResetError();
97     SetPhysPageSize( 1 << aHdr.GetPageSize() );
98     pFAT = new StgFATStrm( *this );
99     pTOC = new StgDirStrm( *this );
100 	if( !GetError() )
101 	{
102 		StgDirEntry* pRoot = pTOC->GetRoot();
103 		if( pRoot )
104 		{
105 			pDataFAT = new StgDataStrm( *this, aHdr.GetDataFATStart(), -1 );
106 			pDataStrm = new StgDataStrm( *this, pRoot );
107 			pDataFAT->SetIncrement( 1 << aHdr.GetPageSize() );
108 			pDataStrm->SetIncrement( GetDataPageSize() );
109 			pDataStrm->SetEntry( *pRoot );
110 		}
111 		else
112 			SetError( SVSTREAM_FILEFORMAT_ERROR );
113 	}
114 }
115 
116 // get the logical data page size
117 
118 short StgIo::GetDataPageSize()
119 {
120     return 1 << aHdr.GetDataPageSize();
121 }
122 
123 // Commit everything
124 
125 sal_Bool StgIo::CommitAll()
126 {
127 	// Store the data (all streams and the TOC)
128     if( pTOC->Store() )
129     {
130         if( Commit( NULL ) )
131         {
132             aHdr.SetDataFATStart( pDataFAT->GetStart() );
133             aHdr.SetDataFATSize( pDataFAT->GetPages() );
134             aHdr.SetTOCStart( pTOC->GetStart() );
135             if( aHdr.Store( *this ) )
136 			{
137 				pStrm->Flush();
138 				sal_uLong n = pStrm->GetError();
139 				SetError( n );
140 #ifdef DBG_UTIL
141 				if( n==0 ) ValidateFATs();
142 #endif
143 				return sal_Bool( n == 0 );
144 			}
145         }
146     }
147 	SetError( SVSTREAM_WRITE_ERROR );
148 	return sal_False;
149 }
150 
151 
152 class EasyFat
153 {
154 	sal_Int32 *pFat;
155 	sal_Bool  *pFree;
156 	sal_Int32 nPages;
157 	sal_Int32 nPageSize;
158 
159 public:
160 	EasyFat( StgIo & rIo, StgStrm *pFatStream, sal_Int32 nPSize );
161 	~EasyFat() { delete[] pFat; delete[] pFree; }
162 
163 	sal_Int32 GetPageSize() { return nPageSize; }
164 	sal_Int32 Count() { return nPages; }
165 	sal_Int32 operator[]( sal_Int32 nOffset ) { return pFat[ nOffset ]; }
166 
167 	sal_uLong Mark( sal_Int32 nPage, sal_Int32 nCount, sal_Int32 nExpect );
168 	sal_Bool HasUnrefChains();
169 };
170 
171 EasyFat::EasyFat( StgIo& rIo, StgStrm* pFatStream, sal_Int32 nPSize )
172 {
173 	nPages = pFatStream->GetSize() >> 2;
174 	nPageSize = nPSize;
175 	pFat = new sal_Int32[ nPages ];
176 	pFree = new sal_Bool[ nPages ];
177 
178 	StgPage *pPage = NULL;
179 	sal_Int32 nFatPageSize = (1 << rIo.aHdr.GetPageSize()) - 2;
180 
181 	for( sal_Int32 nPage = 0; nPage < nPages; nPage++ )
182 	{
183 		if( ! (nPage % nFatPageSize) )
184 		{
185 			pFatStream->Pos2Page( nPage << 2 );
186 			sal_Int32 nPhysPage = pFatStream->GetPage();
187 			pPage = rIo.Get( nPhysPage, sal_True );
188 		}
189 
190 		pFat[ nPage ] = pPage->GetPage( short( nPage % nFatPageSize ) );
191 		pFree[ nPage ] = sal_True;
192 	}
193 }
194 
195 sal_Bool EasyFat::HasUnrefChains()
196 {
197 	for( sal_Int32 nPage = 0; nPage < nPages; nPage++ )
198 	{
199 		if( pFree[ nPage ] && pFat[ nPage ] != -1 )
200 			return sal_True;
201 	}
202 	return sal_False;
203 }
204 
205 sal_uLong EasyFat::Mark( sal_Int32 nPage, sal_Int32 nCount, sal_Int32 nExpect )
206 {
207 	if( nCount > 0 )
208 		--nCount /= GetPageSize(), nCount++;
209 
210 	sal_Int32 nCurPage = nPage;
211 	while( nCount != 0 )
212 	{
213 		pFree[ nCurPage ] = sal_False;
214 		nCurPage = pFat[ nCurPage ];
215 		//Stream zu lang
216 		if( nCurPage != nExpect && nCount == 1 )
217 			return FAT_WRONGLENGTH;
218         //Stream zu kurz
219 		if( nCurPage == nExpect && nCount != 1 && nCount != -1 )
220 			return FAT_WRONGLENGTH;
221 		// letzter Block bei Stream ohne Laenge
222 		if( nCurPage == nExpect && nCount == -1 )
223 			nCount = 1;
224 		if( nCount != -1 )
225 			nCount--;
226 		// Naechster Block nicht in der FAT
227 		if( nCount && ( nCurPage < 0 || nCurPage >= nPages ) )
228 			return FAT_OUTOFBOUNDS;
229 	}
230 	return FAT_OK;
231 }
232 
233 class Validator
234 {
235 	sal_uLong nError;
236 
237 	EasyFat aSmallFat;
238 	EasyFat aFat;
239 
240 	StgIo &rIo;
241 
242 	sal_uLong ValidateMasterFATs();
243 	sal_uLong ValidateDirectoryEntries();
244 	sal_uLong FindUnrefedChains();
245 	sal_uLong MarkAll( StgDirEntry *pEntry );
246 
247 public:
248 
249 	Validator( StgIo &rIo );
250 	sal_Bool IsError() { return nError != 0; }
251 };
252 
253 Validator::Validator( StgIo &rIoP )
254 	: aSmallFat( rIoP, rIoP.pDataFAT, 1 << rIoP.aHdr.GetDataPageSize() ),
255 	  aFat( rIoP, rIoP.pFAT, 1 << rIoP.aHdr.GetPageSize() ),
256 	  rIo( rIoP )
257 {
258 	sal_uLong nErr = nError = FAT_OK;
259 
260 	if(	( nErr = ValidateMasterFATs() ) != FAT_OK )
261 		nError = nErr;
262 	else if(	( nErr = ValidateDirectoryEntries() ) != FAT_OK )
263 		nError = nErr;
264 	else if(	( nErr = FindUnrefedChains()) != FAT_OK )
265 		nError = nErr;
266 }
267 
268 sal_uLong Validator::ValidateMasterFATs()
269 {
270     sal_Int32 nCount = rIo.aHdr.GetFATSize();
271     sal_uLong nErr;
272     for( sal_Int32 i = 0; i < nCount; i++ )
273     {
274         if( ( nErr = aFat.Mark(rIo.pFAT->GetPage( short(i), sal_False ), aFat.GetPageSize(), -3 )) != FAT_OK )
275             return nErr;
276     }
277     if( rIo.aHdr.GetMasters() )
278         if( ( nErr = aFat.Mark(rIo.aHdr.GetFATChain( ), aFat.GetPageSize(), -4 )) != FAT_OK )
279             return nErr;
280     return FAT_OK;
281 }
282 
283 sal_uLong Validator::MarkAll( StgDirEntry *pEntry )
284 {
285 	StgIterator aIter( *pEntry );
286 	sal_uLong nErr = FAT_OK;
287 	for( StgDirEntry* p = aIter.First(); p ; p = aIter.Next() )
288 	{
289 		if( p->aEntry.GetType() == STG_STORAGE )
290 		{
291 			nErr = MarkAll( p );
292 			if( nErr != FAT_OK )
293 				return nErr;
294 		}
295 		else
296 		{
297 			sal_Int32 nSize = p->aEntry.GetSize();
298 			if( nSize < rIo.aHdr.GetThreshold()  )
299 				nErr = aSmallFat.Mark( p->aEntry.GetStartPage(),nSize, -2 );
300 			else
301 				nErr = aFat.Mark( p->aEntry.GetStartPage(),nSize, -2 );
302 			if( nErr != FAT_OK )
303 				return nErr;
304 		}
305 	}
306 	return FAT_OK;
307 }
308 
309 sal_uLong Validator::ValidateDirectoryEntries()
310 {
311 	// Normale DirEntries
312 	sal_uLong nErr = MarkAll( rIo.pTOC->GetRoot() );
313 	if( nErr != FAT_OK )
314 		return nErr;
315 	// Small Data
316 	nErr = aFat.Mark( rIo.pTOC->GetRoot()->aEntry.GetStartPage(),
317 				 rIo.pTOC->GetRoot()->aEntry.GetSize(), -2 );
318 	if( nErr != FAT_OK )
319 		return nErr;
320 	// Small Data FAT
321 	nErr = aFat.Mark(
322 		rIo.aHdr.GetDataFATStart(),
323 		rIo.aHdr.GetDataFATSize() * aFat.GetPageSize(), -2 );
324 	if( nErr != FAT_OK )
325 		return nErr;
326 	// TOC
327 	nErr = aFat.Mark(
328 		rIo.aHdr.GetTOCStart(),	-1, -2 );
329 	return nErr;
330 }
331 
332 sal_uLong Validator::FindUnrefedChains()
333 {
334 	if( aSmallFat.HasUnrefChains() ||
335 		aFat.HasUnrefChains() )
336 		return FAT_UNREFCHAIN;
337 	else
338 		return FAT_OK;
339 }
340 
341 namespace { struct ErrorLink : public rtl::Static<Link, ErrorLink > {}; }
342 
343 void StgIo::SetErrorLink( const Link& rLink )
344 {
345 	ErrorLink::get() = rLink;
346 }
347 
348 const Link& StgIo::GetErrorLink()
349 {
350     return ErrorLink::get();
351 }
352 
353 sal_uLong StgIo::ValidateFATs()
354 {
355 	if( bFile )
356 	{
357 		Validator *pV = new Validator( *this );
358 		sal_Bool bRet1 = !pV->IsError(), bRet2 = sal_True ;
359 		delete pV;
360 		SvFileStream *pFileStrm = ( SvFileStream *) GetStrm();
361 		StgIo aIo;
362 		if( aIo.Open( pFileStrm->GetFileName(),
363 					  STREAM_READ  | STREAM_SHARE_DENYNONE) &&
364 			aIo.Load() )
365 		{
366 			pV = new Validator( aIo );
367 			bRet2 = !pV->IsError();
368 			delete pV;
369 		}
370 
371 		sal_uLong nErr;
372 		if( bRet1 != bRet2 )
373 			nErr = bRet1 ? FAT_ONFILEERROR : FAT_INMEMORYERROR;
374 		else nErr = bRet1 ? FAT_OK : FAT_BOTHERROR;
375 		if( nErr != FAT_OK && !bCopied )
376 		{
377 			StgLinkArg aArg;
378 			aArg.aFile = pFileStrm->GetFileName();
379 			aArg.nErr = nErr;
380 			ErrorLink::get().Call( &aArg );
381 			bCopied = sal_True;
382 		}
383 //		DBG_ASSERT( nErr == FAT_OK ,"Storage kaputt");
384 		return nErr;
385 	}
386 //	DBG_ERROR("Validiere nicht (kein FileStorage)");
387 	return FAT_OK;
388 }
389