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