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