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 else 70 return sal_False; 71 } 72 return Good(); 73 } 74 75 // Set up an initial, empty storage 76 77 sal_Bool StgIo::Init() 78 { 79 aHdr.Init(); 80 SetupStreams(); 81 return CommitAll(); 82 } 83 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 116 short StgIo::GetDataPageSize() 117 { 118 return 1 << aHdr.GetDataPageSize(); 119 } 120 121 // Commit everything 122 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 ); 159 ~EasyFat() { delete[] pFat; delete[] pFree; } 160 161 sal_Int32 GetPageSize() { return nPageSize; } 162 sal_Int32 Count() { return nPages; } 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 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 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 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 ); 251 sal_Bool IsError() { return nError != 0; } 252 }; 253 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 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 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 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 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 354 void StgIo::SetErrorLink( const Link& rLink ) 355 { 356 ErrorLink::get() = rLink; 357 } 358 359 const Link& StgIo::GetErrorLink() 360 { 361 return ErrorLink::get(); 362 } 363 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