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