LibreOffice Module sot (master) 1
stgio.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20
21#include "stgelem.hxx"
22#include "stgcache.hxx"
23#include "stgstrms.hxx"
24#include "stgdir.hxx"
25#include "stgio.hxx"
26#include <o3tl/safeint.hxx>
27#include <sal/log.hxx>
28
29#include <memory>
30#include <optional>
31
33
34// This class holds the storage header and all internal streams.
35
37{
38 m_pTOC = nullptr;
39 m_pDataFAT = nullptr;
40 m_pDataStrm = nullptr;
41 m_pFAT = nullptr;
42 m_bCopied = false;
43}
44
46{
47 delete m_pTOC;
48 delete m_pDataFAT;
49 delete m_pDataStrm;
50 delete m_pFAT;
51}
52
53// Load the header. Do not set an error code if the header is invalid.
54
56{
57 if( GetStrm() )
58 {
59 if( m_aHdr.Load( *this ) )
60 {
61 if( m_aHdr.Check() )
63 else
64 return false;
65 }
66 else
67 return false;
68 }
69 return Good();
70}
71
72// Set up an initial, empty storage
73
75{
76 m_aHdr.Init();
78 return CommitAll();
79}
80
82{
83 delete m_pTOC;
84 delete m_pDataFAT;
85 delete m_pDataStrm;
86 delete m_pFAT;
87 m_pTOC = nullptr;
88 m_pDataFAT = nullptr;
89 m_pDataStrm = nullptr;
90 m_pFAT = nullptr;
91 ResetError();
92
93 short nPhysPageSize = 1 << m_aHdr.GetPageSize();
94 SetPhysPageSize(nPhysPageSize);
95 sal_Int32 nFatStrmSize;
96 if (o3tl::checked_multiply<sal_Int32>(m_aHdr.GetFATSize(), nPhysPageSize, nFatStrmSize))
97 {
98 SAL_WARN("sot", "Error: " << m_aHdr.GetFATSize() << " * " << nPhysPageSize << " would overflow");
100 m_pFAT = nullptr;
101 m_pTOC = nullptr;
102 return;
103 }
104
105 m_pFAT = new StgFATStrm(*this, nFatStrmSize);
106 m_pTOC = new StgDirStrm(*this);
107 if( GetError() )
108 return;
109
110 StgDirEntry* pRoot = m_pTOC->GetRoot();
111 if( pRoot )
112 {
113 m_pDataFAT = new StgDataStrm( *this, m_aHdr.GetDataFATStart(), -1 );
114 m_pDataStrm = new StgDataStrm( *this, *pRoot );
117 m_pDataStrm->SetEntry( *pRoot );
118 }
119 else
121}
122
123// get the logical data page size
124
126{
127 return 1 << m_aHdr.GetDataPageSize();
128}
129
130// Commit everything
131
133{
134 // Store the data (all streams and the TOC)
135 if( m_pTOC && m_pTOC->Store() && m_pDataFAT )
136 {
137 if( Commit() )
138 {
142 if( m_aHdr.Store( *this ) )
143 {
144 GetStrm()->Flush();
145 const ErrCode n = GetStrm()->GetError();
146 SetError( n );
147#ifdef DBG_UTIL
148 if( n==ERRCODE_NONE ) ValidateFATs();
149#endif
150 return n == ERRCODE_NONE;
151 }
152 }
153 }
155 return false;
156}
157
158namespace {
159
160class EasyFat
161{
162 std::unique_ptr<sal_Int32[]> pFat;
163 std::unique_ptr<bool[]> pFree;
164 sal_Int32 nPages;
165 sal_Int32 nPageSize;
166
167public:
168 EasyFat( StgIo & rIo, StgStrm *pFatStream, sal_Int32 nPSize );
169
170 sal_Int32 GetPageSize() const { return nPageSize; }
171
172 FatError Mark( sal_Int32 nPage, sal_Int32 nCount, sal_Int32 nExpect );
173 bool HasUnrefChains() const;
174};
175
176}
177
178EasyFat::EasyFat( StgIo& rIo, StgStrm* pFatStream, sal_Int32 nPSize )
179 : nPages(pFatStream->GetSize() >> 2), nPageSize(nPSize)
180{
181 pFat.reset( new sal_Int32[ nPages ] );
182 pFree.reset( new bool[ nPages ] );
183
185 sal_Int32 nFatPageSize = (1 << rIo.m_aHdr.GetPageSize()) - 2;
186
187 for( sal_Int32 nPage = 0; nPage < nPages; nPage++ )
188 {
189 if( ! (nPage % nFatPageSize) )
190 {
191 pFatStream->Pos2Page( nPage << 2 );
192 sal_Int32 nPhysPage = pFatStream->GetPage();
193 pPage = rIo.Get( nPhysPage, true );
194 }
195
196 pFat[ nPage ] = StgCache::GetFromPage( pPage, short( nPage % nFatPageSize ) );
197 pFree[ nPage ] = true;
198 }
199}
200
201bool EasyFat::HasUnrefChains() const
202{
203 for( sal_Int32 nPage = 0; nPage < nPages; nPage++ )
204 {
205 if( pFree[ nPage ] && pFat[ nPage ] != -1 )
206 return true;
207 }
208 return false;
209}
210
211FatError EasyFat::Mark( sal_Int32 nPage, sal_Int32 nCount, sal_Int32 nExpect )
212{
213 if( nCount > 0 )
214 {
215 --nCount;
216 nCount /= GetPageSize();
217 ++nCount;
218 }
219
220 sal_Int32 nCurPage = nPage;
221 while( nCount != 0 )
222 {
223 if( nCurPage < 0 || nCurPage >= nPages )
225 pFree[ nCurPage ] = false;
226 nCurPage = pFat[ nCurPage ];
227 // stream too long
228 if( nCurPage != nExpect && nCount == 1 )
230 // stream too short
231 if( nCurPage == nExpect && nCount != 1 && nCount != -1 )
233 // last block for stream without length
234 if( nCurPage == nExpect && nCount == -1 )
235 nCount = 1;
236 if( nCount != -1 )
237 nCount--;
238 }
239 return FatError::Ok;
240}
241
242namespace {
243
244class Validator
245{
246 FatError nError;
247
248 EasyFat aSmallFat;
249 EasyFat aFat;
250
251 StgIo &rIo;
252
253 FatError ValidateMasterFATs();
254 FatError ValidateDirectoryEntries();
255 FatError FindUnrefedChains() const;
256 FatError MarkAll( StgDirEntry *pEntry );
257
258public:
259 explicit Validator( StgIo &rIo );
260 bool IsError() const { return nError != FatError::Ok; }
261};
262
263}
264
265Validator::Validator( StgIo &rIoP )
266 : aSmallFat( rIoP, rIoP.m_pDataFAT, 1 << rIoP.m_aHdr.GetDataPageSize() ),
267 aFat( rIoP, rIoP.m_pFAT, 1 << rIoP.m_aHdr.GetPageSize() ),
268 rIo( rIoP )
269{
270 FatError nErr = nError = FatError::Ok;
271
272 if( ( nErr = ValidateMasterFATs() ) != FatError::Ok )
273 nError = nErr;
274 else if( ( nErr = ValidateDirectoryEntries() ) != FatError::Ok )
275 nError = nErr;
276 else if( ( nErr = FindUnrefedChains()) != FatError::Ok )
277 nError = nErr;
278}
279
280FatError Validator::ValidateMasterFATs()
281{
282 sal_Int32 nCount = rIo.m_aHdr.GetFATSize();
283 FatError nErr;
284 if ( !rIo.m_pFAT )
286
287 for( sal_Int32 i = 0; i < nCount; i++ )
288 {
289 if( ( nErr = aFat.Mark(rIo.m_pFAT->GetPage(i, false), aFat.GetPageSize(), -3 )) != FatError::Ok)
290 return nErr;
291 }
292 if( rIo.m_aHdr.GetMasters() )
293 if( ( nErr = aFat.Mark(rIo.m_aHdr.GetFATChain( ), aFat.GetPageSize(), -4 )) != FatError::Ok )
294 return nErr;
295
296 return FatError::Ok;
297}
298
299FatError Validator::MarkAll( StgDirEntry *pEntry )
300{
301 if ( !pEntry )
303
304 StgIterator aIter( *pEntry );
305 FatError nErr = FatError::Ok;
306 for( StgDirEntry* p = aIter.First(); p ; p = aIter.Next() )
307 {
308 if( p->m_aEntry.GetType() == STG_STORAGE )
309 {
310 nErr = MarkAll( p );
311 if( nErr != FatError::Ok )
312 return nErr;
313 }
314 else
315 {
316 sal_Int32 nSize = p->m_aEntry.GetSize();
317 if( nSize < rIo.m_aHdr.GetThreshold() )
318 nErr = aSmallFat.Mark( p->m_aEntry.GetStartPage(),nSize, -2 );
319 else
320 nErr = aFat.Mark( p->m_aEntry.GetStartPage(),nSize, -2 );
321 if( nErr != FatError::Ok )
322 return nErr;
323 }
324 }
325 return FatError::Ok;
326}
327
328FatError Validator::ValidateDirectoryEntries()
329{
330 if ( !rIo.m_pTOC )
332
333 // Normal DirEntries
334 FatError nErr = MarkAll( rIo.m_pTOC->GetRoot() );
335 if( nErr != FatError::Ok )
336 return nErr;
337 // Small Data
338 nErr = aFat.Mark( rIo.m_pTOC->GetRoot()->m_aEntry.GetStartPage(),
339 rIo.m_pTOC->GetRoot()->m_aEntry.GetSize(), -2 );
340 if( nErr != FatError::Ok )
341 return nErr;
342 // Small Data FAT
343 nErr = aFat.Mark(
345 rIo.m_aHdr.GetDataFATSize() * aFat.GetPageSize(), -2 );
346 if( nErr != FatError::Ok )
347 return nErr;
348 // TOC
349 nErr = aFat.Mark(
350 rIo.m_aHdr.GetTOCStart(), -1, -2 );
351 return nErr;
352}
353
354FatError Validator::FindUnrefedChains() const
355{
356 if( aSmallFat.HasUnrefChains() ||
357 aFat.HasUnrefChains() )
359 else
360 return FatError::Ok;
361}
362
364{
365 if( m_bFile )
366 {
367 std::optional<Validator> pV( *this );
368 bool bRet1 = !pV->IsError(), bRet2 = true ;
369 pV.reset();
370
371 SvFileStream *pFileStrm = static_cast<SvFileStream *>( GetStrm() );
372 if ( !pFileStrm )
374
375 StgIo aIo;
376 if( aIo.Open( pFileStrm->GetFileName(),
377 StreamMode::READ | StreamMode::SHARE_DENYNONE) &&
378 aIo.Load() )
379 {
380 pV.emplace( aIo );
381 bRet2 = !pV->IsError();
382 pV.reset();
383 }
384
385 FatError nErr;
386 if( bRet1 != bRet2 )
388 else nErr = bRet1 ? FatError::Ok : FatError::BothError;
389 if( nErr != FatError::Ok && !m_bCopied )
390 {
391 m_bCopied = true;
392 }
393// DBG_ASSERT( nErr == FatError::Ok ,"Storage broken");
394 return nErr;
395 }
396// OSL_FAIL("Do not validate (no FileStorage)");
397 return FatError::Ok;
398}
399
400/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
bool Open(const OUString &rName, StreamMode)
Definition: stgcache.cxx:274
SvStream * GetStrm()
Definition: stgcache.hxx:70
static sal_Int32 GetFromPage(const rtl::Reference< StgPage > &rPage, short nOff)
Definition: stgcache.hxx:117
void ResetError()
Definition: stgcache.cxx:407
ErrCode const & GetError() const
Definition: stgcache.hxx:74
rtl::Reference< StgPage > Get(sal_Int32, bool)
Definition: stgcache.cxx:162
void SetPhysPageSize(short)
Definition: stgcache.cxx:104
bool Good() const
Definition: stgcache.hxx:73
bool m_bFile
Definition: stgcache.hxx:60
bool Commit()
Definition: stgcache.cxx:204
void SetError(ErrCode)
Definition: stgcache.cxx:401
void SetIncrement(short n)
Definition: stgstrms.hxx:125
StgEntry m_aEntry
Definition: stgdir.hxx:53
bool Store()
Definition: stgdir.cxx:815
StgDirEntry * GetRoot()
Definition: stgdir.hxx:96
sal_Int32 GetSize() const
Definition: stgelem.hxx:130
sal_Int32 GetStartPage() const
Definition: stgelem.hxx:128
sal_Int32 GetPage(sal_Int32, bool, sal_uInt16 *pnMasterAlloc=nullptr)
Definition: stgstrms.cxx:600
void SetTOCStart(sal_Int32 n)
Definition: stgelem.cxx:229
sal_Int32 GetDataFATSize() const
Definition: stgelem.hxx:69
void SetDataFATSize(sal_Int32 n)
Definition: stgelem.cxx:247
void SetDataFATStart(sal_Int32 n)
Definition: stgelem.cxx:238
sal_Int32 GetFATSize() const
Definition: stgelem.hxx:74
sal_Int32 GetDataFATStart() const
Definition: stgelem.hxx:67
bool Check()
Definition: stgelem.cxx:194
sal_Int32 GetFATChain() const
Definition: stgelem.hxx:76
sal_Int32 GetThreshold() const
Definition: stgelem.hxx:71
bool Load(StgIo &)
Definition: stgelem.cxx:112
short GetDataPageSize() const
Definition: stgelem.hxx:73
sal_Int32 GetTOCStart() const
Definition: stgelem.hxx:65
sal_Int32 GetMasters() const
Definition: stgelem.hxx:78
bool Store(StgIo &)
Definition: stgelem.cxx:152
short GetPageSize() const
Definition: stgelem.hxx:72
void Init()
Definition: stgelem.cxx:88
Definition: stgio.hxx:42
short GetDataPageSize() const
Definition: stgio.cxx:125
FatError ValidateFATs()
Definition: stgio.cxx:363
bool m_bCopied
Definition: stgio.hxx:44
~StgIo()
Definition: stgio.cxx:45
StgDataStrm * m_pDataFAT
Definition: stgio.hxx:51
bool CommitAll()
Definition: stgio.cxx:132
void SetupStreams()
Definition: stgio.cxx:81
bool Load()
Definition: stgio.cxx:55
StgIo()
Definition: stgio.cxx:36
StgDataStrm * m_pDataStrm
Definition: stgio.hxx:52
bool Init()
Definition: stgio.cxx:74
StgDirStrm * m_pTOC
Definition: stgio.hxx:50
StgFATStrm * m_pFAT
Definition: stgio.hxx:49
StgHeader m_aHdr
Definition: stgio.hxx:48
void SetEntry(StgDirEntry &)
Definition: stgstrms.cxx:341
sal_Int32 GetStart() const
Definition: stgstrms.hxx:87
sal_Int32 GetPages() const
Definition: stgstrms.hxx:90
sal_Int32 GetPage() const
Definition: stgstrms.hxx:89
virtual bool Pos2Page(sal_Int32 nBytePos)
Definition: stgstrms.cxx:396
const OUString & GetFileName() const
void Flush()
ErrCode GetError() const
int nCount
#define SVSTREAM_WRITE_ERROR
#define SVSTREAM_FILEFORMAT_ERROR
#define ERRCODE_NONE
void * p
sal_Int64 n
#define SAL_WARN(area, stream)
int i
@ STG_STORAGE
Definition: stgelem.hxx:87
FatError
Definition: stgio.hxx:31