LibreOffice Module comphelper (master) 1
backupfilehelper.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
10#include <sal/config.h>
11#include <rtl/ustring.hxx>
12#include <rtl/bootstrap.hxx>
13#include <sal/log.hxx>
14#include <osl/file.hxx>
17#include <rtl/crc.h>
18#include <algorithm>
19#include <deque>
20#include <memory>
21#include <string_view>
22#include <utility>
23#include <vector>
24#include <zlib.h>
25
27#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
28#include <com/sun/star/ucb/CommandAbortedException.hpp>
29#include <com/sun/star/ucb/CommandFailedException.hpp>
30#include <com/sun/star/uno/Sequence.hxx>
31#include <com/sun/star/uno/Reference.hxx>
32#include <com/sun/star/deployment/DeploymentException.hpp>
33#include <com/sun/star/deployment/ExtensionManager.hpp>
34#include <com/sun/star/xml/dom/XDocumentBuilder.hpp>
35#include <com/sun/star/xml/dom/DocumentBuilder.hpp>
36#include <com/sun/star/xml/dom/XElement.hpp>
37#include <com/sun/star/xml/dom/XNodeList.hpp>
38#include <com/sun/star/xml/dom/XText.hpp>
39#include <com/sun/star/xml/sax/XSAXSerializable.hpp>
40#include <com/sun/star/xml/sax/Writer.hpp>
41#include <com/sun/star/xml/sax/XWriter.hpp>
42#include <com/sun/star/io/XStream.hpp>
43#include <com/sun/star/io/TempFile.hpp>
44#include <com/sun/star/io/XOutputStream.hpp>
45#include <com/sun/star/beans/XPropertySet.hpp>
47
48using namespace comphelper;
49using namespace css;
50using namespace css::xml::dom;
51
52const sal_uInt32 BACKUP_FILE_HELPER_BLOCK_SIZE = 16384;
53
54namespace
55{
56 typedef std::shared_ptr< osl::File > FileSharedPtr;
57
58 sal_uInt32 createCrc32(FileSharedPtr const & rCandidate, sal_uInt32 nOffset)
59 {
60 sal_uInt32 nCrc32(0);
61
62 if (rCandidate && osl::File::E_None == rCandidate->open(osl_File_OpenFlag_Read))
63 {
65 sal_uInt64 nBytesTransfer(0);
66 sal_uInt64 nSize(0);
67
68 rCandidate->getSize(nSize);
69
70 // set offset in source file - should be zero due to crc32 should
71 // only be needed to be created for new entries, gets loaded with old
72 // ones
73 if (osl::File::E_None == rCandidate->setPos(osl_Pos_Absolut, sal_Int64(nOffset)))
74 {
75 while (nSize != 0)
76 {
77 const sal_uInt64 nToTransfer(std::min(nSize, sal_uInt64(BACKUP_FILE_HELPER_BLOCK_SIZE)));
78
79 if (osl::File::E_None == rCandidate->read(static_cast<void*>(aArray), nToTransfer, nBytesTransfer) && nBytesTransfer == nToTransfer)
80 {
81 // add to crc and reduce size
82 nCrc32 = rtl_crc32(nCrc32, static_cast<void*>(aArray), static_cast<sal_uInt32>(nBytesTransfer));
83 nSize -= nToTransfer;
84 }
85 else
86 {
87 // error - reset to zero again
88 nSize = nCrc32 = 0;
89 }
90 }
91 }
92
93 rCandidate->close();
94 }
95
96 return nCrc32;
97 }
98
99 bool read_sal_uInt32(FileSharedPtr const & rFile, sal_uInt32& rTarget)
100 {
101 sal_uInt8 aArray[4];
102 sal_uInt64 nBaseRead(0);
103
104 // read rTarget
105 if (osl::File::E_None == rFile->read(static_cast<void*>(aArray), 4, nBaseRead) && 4 == nBaseRead)
106 {
107 rTarget = (sal_uInt32(aArray[0]) << 24) + (sal_uInt32(aArray[1]) << 16) + (sal_uInt32(aArray[2]) << 8) + sal_uInt32(aArray[3]);
108 return true;
109 }
110
111 return false;
112 }
113
114 bool write_sal_uInt32(oslFileHandle& rHandle, sal_uInt32 nSource)
115 {
116 sal_uInt8 aArray[4];
117 sal_uInt64 nBaseWritten(0);
118
119 // write nSource
120 aArray[0] = sal_uInt8((nSource & 0xff000000) >> 24);
121 aArray[1] = sal_uInt8((nSource & 0x00ff0000) >> 16);
122 aArray[2] = sal_uInt8((nSource & 0x0000ff00) >> 8);
123 aArray[3] = sal_uInt8(nSource & 0x000000ff);
124
125 return osl_File_E_None == osl_writeFile(rHandle, static_cast<const void*>(aArray), 4, &nBaseWritten) && 4 == nBaseWritten;
126 }
127
128 bool read_OString(FileSharedPtr const & rFile, OString& rTarget)
129 {
130 sal_uInt32 nLength(0);
131
132 if (!read_sal_uInt32(rFile, nLength))
133 {
134 return false;
135 }
136
137 sal_uInt64 nPos;
138 if (osl::File::E_None != rFile->getPos(nPos))
139 return false;
140
141 sal_uInt64 nSize;
142 if (osl::File::E_None != rFile->getSize(nSize))
143 return false;
144
145 const auto nRemainingSize = nSize - nPos;
146 if (nLength > nRemainingSize)
147 return false;
148
149 std::vector<char> aTarget(nLength);
150 sal_uInt64 nBaseRead(0);
151
152 // read rTarget
153 if (osl::File::E_None == rFile->read(static_cast<void*>(aTarget.data()), nLength, nBaseRead) && nLength == nBaseRead)
154 {
155 rTarget = OString(aTarget.data(), static_cast<sal_Int32>(nBaseRead));
156 return true;
157 }
158
159 return false;
160 }
161
162 bool write_OString(oslFileHandle& rHandle, const OString& rSource)
163 {
164 const sal_uInt32 nLength(rSource.getLength());
165
166 if (!write_sal_uInt32(rHandle, nLength))
167 {
168 return false;
169 }
170
171 sal_uInt64 nBaseWritten(0);
172
173 return osl_File_E_None == osl_writeFile(rHandle, static_cast<const void*>(rSource.getStr()), nLength, &nBaseWritten) && nLength == nBaseWritten;
174 }
175
176 OUString createFileURL(
177 std::u16string_view rURL, std::u16string_view rName, std::u16string_view rExt)
178 {
179 OUString aRetval;
180
181 if (!rURL.empty() && !rName.empty())
182 {
183 aRetval = OUString::Concat(rURL) + "/" + rName;
184
185 if (!rExt.empty())
186 {
187 aRetval += OUString::Concat(".") + rExt;
188 }
189 }
190
191 return aRetval;
192 }
193
194 OUString createPackURL(std::u16string_view rURL, std::u16string_view rName)
195 {
196 OUString aRetval;
197
198 if (!rURL.empty() && !rName.empty())
199 {
200 aRetval = OUString::Concat(rURL) + "/" + rName + ".pack";
201 }
202
203 return aRetval;
204 }
205}
206
207namespace
208{
209 enum PackageRepository { USER, SHARED, BUNDLED };
210
211 class ExtensionInfoEntry
212 {
213 private:
214 OString maName; // extension name
215 PackageRepository maRepository; // user|shared|bundled
216 bool mbEnabled; // state
217
218 public:
219 ExtensionInfoEntry()
220 : maRepository(USER),
221 mbEnabled(false)
222 {
223 }
224
225 ExtensionInfoEntry(OString aName, bool bEnabled)
226 : maName(std::move(aName)),
227 maRepository(USER),
228 mbEnabled(bEnabled)
229 {
230 }
231
232 ExtensionInfoEntry(const uno::Reference< deployment::XPackage >& rxPackage)
233 : maName(OUStringToOString(rxPackage->getName(), RTL_TEXTENCODING_ASCII_US)),
234 maRepository(USER),
235 mbEnabled(false)
236 {
237 // check maRepository
238 const OString aRepName(OUStringToOString(rxPackage->getRepositoryName(), RTL_TEXTENCODING_ASCII_US));
239
240 if (aRepName == "shared")
241 {
242 maRepository = SHARED;
243 }
244 else if (aRepName == "bundled")
245 {
246 maRepository = BUNDLED;
247 }
248
249 // check mbEnabled
250 const beans::Optional< beans::Ambiguous< sal_Bool > > option(
251 rxPackage->isRegistered(uno::Reference< task::XAbortChannel >(),
252 uno::Reference< ucb::XCommandEnvironment >()));
253
254 if (option.IsPresent)
255 {
256 ::beans::Ambiguous< sal_Bool > const& reg = option.Value;
257
258 if (!reg.IsAmbiguous)
259 {
260 mbEnabled = reg.Value;
261 }
262 }
263 }
264
265 bool isSameExtension(const ExtensionInfoEntry& rComp) const
266 {
267 return (maRepository == rComp.maRepository && maName == rComp.maName);
268 }
269
270 bool operator<(const ExtensionInfoEntry& rComp) const
271 {
272 if (maRepository == rComp.maRepository)
273 {
274 if (maName == rComp.maName)
275 {
276 return mbEnabled < rComp.mbEnabled;
277 }
278 else
279 {
280 return 0 > maName.compareTo(rComp.maName);
281 }
282 }
283 else
284 {
285 return maRepository < rComp.maRepository;
286 }
287 }
288
289 bool read_entry(FileSharedPtr const & rFile)
290 {
291 // read maName
292 if (!read_OString(rFile, maName))
293 {
294 return false;
295 }
296
297 // read maRepository
298 sal_uInt32 nState(0);
299
300 if (read_sal_uInt32(rFile, nState))
301 {
302 maRepository = static_cast< PackageRepository >(nState);
303 }
304 else
305 {
306 return false;
307 }
308
309 // read mbEnabled
310 if (read_sal_uInt32(rFile, nState))
311 {
312 mbEnabled = static_cast< bool >(nState);
313 }
314 else
315 {
316 return false;
317 }
318
319 return true;
320 }
321
322 bool write_entry(oslFileHandle& rHandle) const
323 {
324 // write maName;
325 if (!write_OString(rHandle, maName))
326 {
327 return false;
328 }
329
330 // write maRepository
331 sal_uInt32 nState(maRepository);
332
333 if (!write_sal_uInt32(rHandle, nState))
334 {
335 return false;
336 }
337
338 // write mbEnabled
339 nState = static_cast< sal_uInt32 >(mbEnabled);
340
341 return write_sal_uInt32(rHandle, nState);
342 }
343
344 const OString& getName() const
345 {
346 return maName;
347 }
348
349 bool isEnabled() const
350 {
351 return mbEnabled;
352 }
353 };
354
355 typedef std::vector< ExtensionInfoEntry > ExtensionInfoEntryVector;
356
357 constexpr OUStringLiteral gaRegPath { u"/registry/com.sun.star.comp.deployment.bundle.PackageRegistryBackend/backenddb.xml" };
358
359 class ExtensionInfo
360 {
361 private:
362 ExtensionInfoEntryVector maEntries;
363
364 public:
365 ExtensionInfo()
366 {
367 }
368
369 const ExtensionInfoEntryVector& getExtensionInfoEntryVector() const
370 {
371 return maEntries;
372 }
373
374 void reset()
375 {
376 // clear all data
377 maEntries.clear();
378 }
379
380 void createUsingXExtensionManager()
381 {
382 // clear all data
383 reset();
384
385 // create content from current extension configuration
386 uno::Sequence< uno::Sequence< uno::Reference< deployment::XPackage > > > xAllPackages;
387 uno::Reference< uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext();
388 uno::Reference< deployment::XExtensionManager > m_xExtensionManager = deployment::ExtensionManager::get(xContext);
389
390 try
391 {
392 xAllPackages = m_xExtensionManager->getAllExtensions(uno::Reference< task::XAbortChannel >(),
393 uno::Reference< ucb::XCommandEnvironment >());
394 }
395 catch (const deployment::DeploymentException &)
396 {
397 return;
398 }
399 catch (const ucb::CommandFailedException &)
400 {
401 return;
402 }
403 catch (const ucb::CommandAbortedException &)
404 {
405 return;
406 }
407 catch (const lang::IllegalArgumentException & e)
408 {
409 css::uno::Any anyEx = cppu::getCaughtException();
410 throw css::lang::WrappedTargetRuntimeException( e.Message,
411 e.Context, anyEx );
412 }
413
414 for (const uno::Sequence< uno::Reference< deployment::XPackage > > & xPackageList : std::as_const(xAllPackages))
415 {
416 for (const uno::Reference< deployment::XPackage > & xPackage : xPackageList)
417 {
418 if (xPackage.is())
419 {
420 maEntries.emplace_back(xPackage);
421 }
422 }
423 }
424
425 if (!maEntries.empty())
426 {
427 // sort the list
428 std::sort(maEntries.begin(), maEntries.end());
429 }
430 }
431
432 private:
433 void visitNodesXMLRead(const uno::Reference< xml::dom::XElement >& rElement)
434 {
435 if (!rElement.is())
436 return;
437
438 const OUString aTagName(rElement->getTagName());
439
440 if (aTagName == "extension")
441 {
442 OUString aAttrUrl(rElement->getAttribute("url"));
443 const OUString aAttrRevoked(rElement->getAttribute("revoked"));
444
445 if (!aAttrUrl.isEmpty())
446 {
447 const sal_Int32 nIndex(aAttrUrl.lastIndexOf('/'));
448
449 if (nIndex > 0 && aAttrUrl.getLength() > nIndex + 1)
450 {
451 aAttrUrl = aAttrUrl.copy(nIndex + 1);
452 }
453
454 const bool bEnabled(aAttrRevoked.isEmpty() || !aAttrRevoked.toBoolean());
455 maEntries.emplace_back(
456 OUStringToOString(aAttrUrl, RTL_TEXTENCODING_ASCII_US),
457 bEnabled);
458 }
459 }
460 else
461 {
462 uno::Reference< xml::dom::XNodeList > aList = rElement->getChildNodes();
463
464 if (aList.is())
465 {
466 const sal_Int32 nLength(aList->getLength());
467
468 for (sal_Int32 a(0); a < nLength; a++)
469 {
470 const uno::Reference< xml::dom::XElement > aChild(aList->item(a), uno::UNO_QUERY);
471
472 if (aChild.is())
473 {
474 visitNodesXMLRead(aChild);
475 }
476 }
477 }
478 }
479 }
480
481 public:
482 void createUserExtensionRegistryEntriesFromXML(std::u16string_view rUserConfigWorkURL)
483 {
484 const OUString aPath(
485 OUString::Concat(rUserConfigWorkURL) + "/uno_packages/cache" + gaRegPath);
486 createExtensionRegistryEntriesFromXML(aPath);
487 }
488
489 void createSharedExtensionRegistryEntriesFromXML(std::u16string_view rUserConfigWorkURL)
490 {
491 const OUString aPath(
492 OUString::Concat(rUserConfigWorkURL) + "/extensions/shared" + gaRegPath);
493 createExtensionRegistryEntriesFromXML(aPath);
494 }
495
496 void createBundledExtensionRegistryEntriesFromXML(std::u16string_view rUserConfigWorkURL)
497 {
498 const OUString aPath(
499 OUString::Concat(rUserConfigWorkURL) + "/extensions/bundled" + gaRegPath);
500 createExtensionRegistryEntriesFromXML(aPath);
501 }
502
503
504 void createExtensionRegistryEntriesFromXML(const OUString& aPath)
505 {
506 if (DirectoryHelper::fileExists(aPath))
507 {
508 uno::Reference< uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext();
509 uno::Reference< xml::dom::XDocumentBuilder > xBuilder(xml::dom::DocumentBuilder::create(xContext));
510 uno::Reference< xml::dom::XDocument > aDocument = xBuilder->parseURI(aPath);
511
512 if (aDocument.is())
513 {
514 visitNodesXMLRead(aDocument->getDocumentElement());
515 }
516 }
517
518 if (!maEntries.empty())
519 {
520 // sort the list
521 std::sort(maEntries.begin(), maEntries.end());
522 }
523 }
524
525 private:
526 static bool visitNodesXMLChange(
527 const OUString& rTagToSearch,
528 const uno::Reference< xml::dom::XElement >& rElement,
529 const ExtensionInfoEntryVector& rToBeEnabled,
530 const ExtensionInfoEntryVector& rToBeDisabled)
531 {
532 bool bChanged(false);
533
534 if (rElement.is())
535 {
536 const OUString aTagName(rElement->getTagName());
537
538 if (aTagName == rTagToSearch)
539 {
540 const OString aAttrUrl(OUStringToOString(rElement->getAttribute("url"), RTL_TEXTENCODING_ASCII_US));
541 const OUString aAttrRevoked(rElement->getAttribute("revoked"));
542 const bool bEnabled(aAttrRevoked.isEmpty() || !aAttrRevoked.toBoolean());
543
544 if (!aAttrUrl.isEmpty())
545 {
546 for (const auto& enable : rToBeEnabled)
547 {
548 if (-1 != aAttrUrl.indexOf(enable.getName()))
549 {
550 if (!bEnabled)
551 {
552 // needs to be enabled
553 rElement->removeAttribute("revoked");
554 bChanged = true;
555 }
556 }
557 }
558
559 for (const auto& disable : rToBeDisabled)
560 {
561 if (-1 != aAttrUrl.indexOf(disable.getName()))
562 {
563 if (bEnabled)
564 {
565 // needs to be disabled
566 rElement->setAttribute("revoked", "true");
567 bChanged = true;
568 }
569 }
570 }
571 }
572 }
573 else
574 {
575 uno::Reference< xml::dom::XNodeList > aList = rElement->getChildNodes();
576
577 if (aList.is())
578 {
579 const sal_Int32 nLength(aList->getLength());
580
581 for (sal_Int32 a(0); a < nLength; a++)
582 {
583 const uno::Reference< xml::dom::XElement > aChild(aList->item(a), uno::UNO_QUERY);
584
585 if (aChild.is())
586 {
587 bChanged |= visitNodesXMLChange(
588 rTagToSearch,
589 aChild,
590 rToBeEnabled,
591 rToBeDisabled);
592 }
593 }
594 }
595 }
596 }
597
598 return bChanged;
599 }
600
601 static void visitNodesXMLChangeOneCase(
602 const OUString& rUnoPackagReg,
603 const OUString& rTagToSearch,
604 const ExtensionInfoEntryVector& rToBeEnabled,
605 const ExtensionInfoEntryVector& rToBeDisabled)
606 {
607 if (!DirectoryHelper::fileExists(rUnoPackagReg))
608 return;
609
610 uno::Reference< uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext();
611 uno::Reference< xml::dom::XDocumentBuilder > xBuilder = xml::dom::DocumentBuilder::create(xContext);
612 uno::Reference< xml::dom::XDocument > aDocument = xBuilder->parseURI(rUnoPackagReg);
613
614 if (!aDocument.is())
615 return;
616
617 if (!visitNodesXMLChange(
618 rTagToSearch,
619 aDocument->getDocumentElement(),
620 rToBeEnabled,
621 rToBeDisabled))
622 return;
623
624 // did change - write back
625 uno::Reference< xml::sax::XSAXSerializable > xSerializer(aDocument, uno::UNO_QUERY);
626
627 if (!xSerializer.is())
628 return;
629
630 // create a SAXWriter
631 uno::Reference< xml::sax::XWriter > const xSaxWriter = xml::sax::Writer::create(xContext);
632 uno::Reference< io::XTempFile > xTempFile = io::TempFile::create(xContext);
633 uno::Reference< io::XOutputStream > xOutStrm = xTempFile->getOutputStream();
634
635 // set output stream and do the serialization
636 xSaxWriter->setOutputStream(xOutStrm);
637 xSerializer->serialize(xSaxWriter, uno::Sequence< beans::StringPair >());
638
639 // get URL from temp file
640 OUString aTempURL = xTempFile->getUri();
641
642 // copy back file
643 if (aTempURL.isEmpty() || !DirectoryHelper::fileExists(aTempURL))
644 return;
645
646 if (DirectoryHelper::fileExists(rUnoPackagReg))
647 {
648 osl::File::remove(rUnoPackagReg);
649 }
650
651#if OSL_DEBUG_LEVEL > 1
652 SAL_WARN_IF(osl::FileBase::E_None != osl::File::move(aTempURL, rUnoPackagReg), "comphelper.backupfilehelper", "could not copy back modified Extension configuration file");
653#else
654 osl::File::move(aTempURL, rUnoPackagReg);
655#endif
656 }
657
658 public:
659 static void changeEnableDisableStateInXML(
660 std::u16string_view rUserConfigWorkURL,
661 const ExtensionInfoEntryVector& rToBeEnabled,
662 const ExtensionInfoEntryVector& rToBeDisabled)
663 {
664 static const OUStringLiteral aRegPathFront(u"/uno_packages/cache/registry/com.sun.star.comp.deployment.");
665 static const OUStringLiteral aRegPathBack(u".PackageRegistryBackend/backenddb.xml");
666 // first appearance to check
667 {
668 const OUString aUnoPackagReg(OUString::Concat(rUserConfigWorkURL) + aRegPathFront + "bundle" + aRegPathBack);
669
670 visitNodesXMLChangeOneCase(
671 aUnoPackagReg,
672 "extension",
673 rToBeEnabled,
674 rToBeDisabled);
675 }
676
677 // second appearance to check
678 {
679 const OUString aUnoPackagReg(OUString::Concat(rUserConfigWorkURL) + aRegPathFront + "configuration" + aRegPathBack);
680
681 visitNodesXMLChangeOneCase(
682 aUnoPackagReg,
683 "configuration",
684 rToBeEnabled,
685 rToBeDisabled);
686 }
687
688 // third appearance to check
689 {
690 const OUString aUnoPackagReg(OUString::Concat(rUserConfigWorkURL) + aRegPathFront + "script" + aRegPathBack);
691
692 visitNodesXMLChangeOneCase(
693 aUnoPackagReg,
694 "script",
695 rToBeEnabled,
696 rToBeDisabled);
697 }
698 }
699
700 bool read_entries(FileSharedPtr const & rFile)
701 {
702 // read NumExtensionEntries
703 sal_uInt32 nExtEntries(0);
704
705 if (!read_sal_uInt32(rFile, nExtEntries))
706 {
707 return false;
708 }
709
710 // coverity#1373663 Untrusted loop bound, check file size
711 // isn't utterly broken
712 sal_uInt64 nFileSize(0);
713 rFile->getSize(nFileSize);
714 if (nFileSize < nExtEntries)
715 return false;
716
717 for (sal_uInt32 a(0); a < nExtEntries; a++)
718 {
719 ExtensionInfoEntry aNewEntry;
720
721 if (aNewEntry.read_entry(rFile))
722 {
723 maEntries.push_back(aNewEntry);
724 }
725 else
726 {
727 return false;
728 }
729 }
730
731 return true;
732 }
733
734 bool write_entries(oslFileHandle& rHandle) const
735 {
736 const sal_uInt32 nExtEntries(maEntries.size());
737
738 if (!write_sal_uInt32(rHandle, nExtEntries))
739 {
740 return false;
741 }
742
743 for (const auto& a : maEntries)
744 {
745 if (!a.write_entry(rHandle))
746 {
747 return false;
748 }
749 }
750
751 return true;
752 }
753
754 bool createTempFile(OUString& rTempFileName)
755 {
756 oslFileHandle aHandle;
757 bool bRetval(false);
758
759 // create current configuration
760 if (maEntries.empty())
761 {
762 createUsingXExtensionManager();
763 }
764
765 // open target temp file and write current configuration to it - it exists until deleted
766 if (osl::File::E_None == osl::FileBase::createTempFile(nullptr, &aHandle, &rTempFileName))
767 {
768 bRetval = write_entries(aHandle);
769
770 // close temp file - it exists until deleted
771 osl_closeFile(aHandle);
772 }
773
774 return bRetval;
775 }
776
777 bool areThereEnabledExtensions() const
778 {
779 for (const auto& a : maEntries)
780 {
781 if (a.isEnabled())
782 {
783 return true;
784 }
785 }
786
787 return false;
788 }
789 };
790}
791
792namespace
793{
794 class PackedFileEntry
795 {
796 private:
797 sal_uInt32 mnFullFileSize; // size in bytes of unpacked original file
798 sal_uInt32 mnPackFileSize; // size in bytes in file backup package (smaller if compressed, same if not)
799 sal_uInt32 mnOffset; // offset in File (zero identifies new file)
800 sal_uInt32 mnCrc32; // checksum
801 FileSharedPtr maFile; // file where to find the data (at offset)
802 bool const mbDoCompress; // flag if this file is scheduled to be compressed when written
803
804 bool copy_content_straight(oslFileHandle& rTargetHandle)
805 {
806 if (!maFile || osl::File::E_None != maFile->open(osl_File_OpenFlag_Read))
807 return false;
808
810 sal_uInt64 nBytesTransfer(0);
811 sal_uInt64 nSize(getPackFileSize());
812
813 // set offset in source file - when this is zero, a new file is to be added
814 if (osl::File::E_None == maFile->setPos(osl_Pos_Absolut, sal_Int64(getOffset())))
815 {
816 while (nSize != 0)
817 {
818 const sal_uInt64 nToTransfer(std::min(nSize, sal_uInt64(BACKUP_FILE_HELPER_BLOCK_SIZE)));
819
820 if (osl::File::E_None != maFile->read(static_cast<void*>(aArray), nToTransfer, nBytesTransfer) || nBytesTransfer != nToTransfer)
821 {
822 break;
823 }
824
825 if (osl_File_E_None != osl_writeFile(rTargetHandle, static_cast<const void*>(aArray), nToTransfer, &nBytesTransfer) || nBytesTransfer != nToTransfer)
826 {
827 break;
828 }
829
830 nSize -= nToTransfer;
831 }
832 }
833
834 maFile->close();
835 return (0 == nSize);
836 }
837
838 bool copy_content_compress(oslFileHandle& rTargetHandle)
839 {
840 if (!maFile || osl::File::E_None != maFile->open(osl_File_OpenFlag_Read))
841 return false;
842
845 sal_uInt64 nBytesTransfer(0);
846 sal_uInt64 nSize(getPackFileSize());
847 z_stream zstream;
848 memset(&zstream, 0, sizeof(zstream));
849
850 if (Z_OK == deflateInit(&zstream, Z_BEST_COMPRESSION))
851 {
852 // set offset in source file - when this is zero, a new file is to be added
853 if (osl::File::E_None == maFile->setPos(osl_Pos_Absolut, sal_Int64(getOffset())))
854 {
855 bool bOkay(true);
856
857 while (bOkay && nSize != 0)
858 {
859 const sal_uInt64 nToTransfer(std::min(nSize, sal_uInt64(BACKUP_FILE_HELPER_BLOCK_SIZE)));
860
861 if (osl::File::E_None != maFile->read(static_cast<void*>(aArray), nToTransfer, nBytesTransfer) || nBytesTransfer != nToTransfer)
862 {
863 break;
864 }
865
866 zstream.avail_in = nToTransfer;
867 zstream.next_in = reinterpret_cast<unsigned char*>(aArray);
868
869 do {
870 zstream.avail_out = BACKUP_FILE_HELPER_BLOCK_SIZE;
871 zstream.next_out = reinterpret_cast<unsigned char*>(aBuffer);
872#if !defined Z_PREFIX
873 const sal_Int64 nRetval(deflate(&zstream, nSize == nToTransfer ? Z_FINISH : Z_NO_FLUSH));
874#else
875 const sal_Int64 nRetval(z_deflate(&zstream, nSize == nToTransfer ? Z_FINISH : Z_NO_FLUSH));
876#endif
877 if (Z_STREAM_ERROR == nRetval)
878 {
879 bOkay = false;
880 }
881 else
882 {
883 const sal_uInt64 nAvailable(BACKUP_FILE_HELPER_BLOCK_SIZE - zstream.avail_out);
884
885 if (osl_File_E_None != osl_writeFile(rTargetHandle, static_cast<const void*>(aBuffer), nAvailable, &nBytesTransfer) || nBytesTransfer != nAvailable)
886 {
887 bOkay = false;
888 }
889 }
890 } while (bOkay && 0 == zstream.avail_out);
891
892 if (!bOkay)
893 {
894 break;
895 }
896
897 nSize -= nToTransfer;
898 }
899
900#if !defined Z_PREFIX
901 deflateEnd(&zstream);
902#else
903 z_deflateEnd(&zstream);
904#endif
905 }
906 }
907
908 maFile->close();
909
910 // get compressed size and add to entry
911 if (mnFullFileSize == mnPackFileSize && mnFullFileSize == zstream.total_in)
912 {
913 mnPackFileSize = zstream.total_out;
914 }
915
916 return (0 == nSize);
917 }
918
919 bool copy_content_uncompress(oslFileHandle& rTargetHandle)
920 {
921 if (!maFile || osl::File::E_None != maFile->open(osl_File_OpenFlag_Read))
922 return false;
923
926 sal_uInt64 nBytesTransfer(0);
927 sal_uInt64 nSize(getPackFileSize());
928 z_stream zstream;
929 memset(&zstream, 0, sizeof(zstream));
930
931 if (Z_OK == inflateInit(&zstream))
932 {
933 // set offset in source file - when this is zero, a new file is to be added
934 if (osl::File::E_None == maFile->setPos(osl_Pos_Absolut, sal_Int64(getOffset())))
935 {
936 bool bOkay(true);
937
938 while (bOkay && nSize != 0)
939 {
940 const sal_uInt64 nToTransfer(std::min(nSize, sal_uInt64(BACKUP_FILE_HELPER_BLOCK_SIZE)));
941
942 if (osl::File::E_None != maFile->read(static_cast<void*>(aArray), nToTransfer, nBytesTransfer) || nBytesTransfer != nToTransfer)
943 {
944 break;
945 }
946
947 zstream.avail_in = nToTransfer;
948 zstream.next_in = reinterpret_cast<unsigned char*>(aArray);
949
950 do {
951 zstream.avail_out = BACKUP_FILE_HELPER_BLOCK_SIZE;
952 zstream.next_out = reinterpret_cast<unsigned char*>(aBuffer);
953#if !defined Z_PREFIX
954 const sal_Int64 nRetval(inflate(&zstream, Z_NO_FLUSH));
955#else
956 const sal_Int64 nRetval(z_inflate(&zstream, Z_NO_FLUSH));
957#endif
958 if (Z_STREAM_ERROR == nRetval)
959 {
960 bOkay = false;
961 }
962 else
963 {
964 const sal_uInt64 nAvailable(BACKUP_FILE_HELPER_BLOCK_SIZE - zstream.avail_out);
965
966 if (osl_File_E_None != osl_writeFile(rTargetHandle, static_cast<const void*>(aBuffer), nAvailable, &nBytesTransfer) || nBytesTransfer != nAvailable)
967 {
968 bOkay = false;
969 }
970 }
971 } while (bOkay && 0 == zstream.avail_out);
972
973 if (!bOkay)
974 {
975 break;
976 }
977
978 nSize -= nToTransfer;
979 }
980
981#if !defined Z_PREFIX
982 deflateEnd(&zstream);
983#else
984 z_deflateEnd(&zstream);
985#endif
986 }
987 }
988
989 maFile->close();
990 return (0 == nSize);
991 }
992
993
994 public:
995 // create new, uncompressed entry
996 PackedFileEntry(
997 sal_uInt32 nFullFileSize,
998 sal_uInt32 nCrc32,
999 FileSharedPtr xFile,
1000 bool bDoCompress)
1001 : mnFullFileSize(nFullFileSize),
1002 mnPackFileSize(nFullFileSize),
1003 mnOffset(0),
1004 mnCrc32(nCrc32),
1005 maFile(std::move(xFile)),
1006 mbDoCompress(bDoCompress)
1007 {
1008 }
1009
1010 // create entry to be loaded as header (read_header)
1011 PackedFileEntry()
1012 : mnFullFileSize(0),
1013 mnPackFileSize(0),
1014 mnOffset(0),
1015 mnCrc32(0),
1016 mbDoCompress(false)
1017 {
1018 }
1019
1020 sal_uInt32 getFullFileSize() const
1021 {
1022 return mnFullFileSize;
1023 }
1024
1025 sal_uInt32 getPackFileSize() const
1026 {
1027 return mnPackFileSize;
1028 }
1029
1030 sal_uInt32 getOffset() const
1031 {
1032 return mnOffset;
1033 }
1034
1035 void setOffset(sal_uInt32 nOffset)
1036 {
1037 mnOffset = nOffset;
1038 }
1039
1040 static sal_uInt32 getEntrySize()
1041 {
1042 return 12;
1043 }
1044
1045 sal_uInt32 getCrc32() const
1046 {
1047 return mnCrc32;
1048 }
1049
1050 bool read_header(FileSharedPtr const & rFile)
1051 {
1052 if (!rFile)
1053 {
1054 return false;
1055 }
1056
1057 maFile = rFile;
1058
1059 // read and compute full file size
1060 if (!read_sal_uInt32(rFile, mnFullFileSize))
1061 {
1062 return false;
1063 }
1064
1065 // read and compute entry crc32
1066 if (!read_sal_uInt32(rFile, mnCrc32))
1067 {
1068 return false;
1069 }
1070
1071 // read and compute packed size
1072 if (!read_sal_uInt32(rFile, mnPackFileSize))
1073 {
1074 return false;
1075 }
1076
1077 return true;
1078 }
1079
1080 bool write_header(oslFileHandle& rHandle) const
1081 {
1082 // write full file size
1083 if (!write_sal_uInt32(rHandle, mnFullFileSize))
1084 {
1085 return false;
1086 }
1087
1088 // write crc32
1089 if (!write_sal_uInt32(rHandle, mnCrc32))
1090 {
1091 return false;
1092 }
1093
1094 // write packed file size
1095 if (!write_sal_uInt32(rHandle, mnPackFileSize))
1096 {
1097 return false;
1098 }
1099
1100 return true;
1101 }
1102
1103 bool copy_content(oslFileHandle& rTargetHandle, bool bUncompress)
1104 {
1105 if (bUncompress)
1106 {
1107 if (getFullFileSize() == getPackFileSize())
1108 {
1109 // not compressed, just copy
1110 return copy_content_straight(rTargetHandle);
1111 }
1112 else
1113 {
1114 // compressed, need to uncompress on copy
1115 return copy_content_uncompress(rTargetHandle);
1116 }
1117 }
1118 else if (0 == getOffset())
1119 {
1120 if (mbDoCompress)
1121 {
1122 // compressed wanted, need to compress on copy
1123 return copy_content_compress(rTargetHandle);
1124 }
1125 else
1126 {
1127 // not compressed, straight copy
1128 return copy_content_straight(rTargetHandle);
1129 }
1130 }
1131 else
1132 {
1133 return copy_content_straight(rTargetHandle);
1134 }
1135 }
1136 };
1137}
1138
1139namespace
1140{
1141 class PackedFile
1142 {
1143 private:
1144 const OUString maURL;
1145 std::deque< PackedFileEntry >
1146 maPackedFileEntryVector;
1147 bool mbChanged;
1148
1149 public:
1150 PackedFile(const OUString& rURL)
1151 : maURL(rURL),
1152 mbChanged(false)
1153 {
1154 FileSharedPtr aSourceFile = std::make_shared<osl::File>(rURL);
1155
1156 if (osl::File::E_None == aSourceFile->open(osl_File_OpenFlag_Read))
1157 {
1158 sal_uInt64 nBaseLen(0);
1159 aSourceFile->getSize(nBaseLen);
1160
1161 // we need at least File_ID and num entries -> 8byte
1162 if (8 < nBaseLen)
1163 {
1164 sal_uInt8 aArray[4];
1165 sal_uInt64 nBaseRead(0);
1166
1167 // read and check File_ID
1168 if (osl::File::E_None == aSourceFile->read(static_cast< void* >(aArray), 4, nBaseRead) && 4 == nBaseRead)
1169 {
1170 if ('P' == aArray[0] && 'A' == aArray[1] && 'C' == aArray[2] && 'K' == aArray[3])
1171 {
1172 // read and compute num entries in this file
1173 if (osl::File::E_None == aSourceFile->read(static_cast<void*>(aArray), 4, nBaseRead) && 4 == nBaseRead)
1174 {
1175 sal_uInt32 nEntries((sal_uInt32(aArray[0]) << 24) + (sal_uInt32(aArray[1]) << 16) + (sal_uInt32(aArray[2]) << 8) + sal_uInt32(aArray[3]));
1176
1177 // if there are entries (and less than max), read them
1178 if (nEntries >= 1 && nEntries <= 10)
1179 {
1180 for (sal_uInt32 a(0); a < nEntries; a++)
1181 {
1182 // create new entry, read header (size, crc and PackedSize),
1183 // set offset and source file
1184 PackedFileEntry aEntry;
1185
1186 if (aEntry.read_header(aSourceFile))
1187 {
1188 // add to local data
1189 maPackedFileEntryVector.push_back(aEntry);
1190 }
1191 else
1192 {
1193 // error
1194 nEntries = 0;
1195 }
1196 }
1197
1198 if (0 == nEntries)
1199 {
1200 // on read error clear local data
1201 maPackedFileEntryVector.clear();
1202 }
1203 else
1204 {
1205 // calculate and set offsets to file binary content
1206 sal_uInt32 nHeaderSize(8);
1207
1208 nHeaderSize += maPackedFileEntryVector.size() * PackedFileEntry::getEntrySize();
1209
1210 sal_uInt32 nOffset(nHeaderSize);
1211
1212 for (auto& b : maPackedFileEntryVector)
1213 {
1214 b.setOffset(nOffset);
1215 nOffset += b.getPackFileSize();
1216 }
1217 }
1218 }
1219 }
1220 }
1221 }
1222 }
1223
1224 aSourceFile->close();
1225 }
1226
1227 if (maPackedFileEntryVector.empty())
1228 {
1229 // on error or no data get rid of pack file
1230 osl::File::remove(maURL);
1231 }
1232 }
1233
1234 void flush()
1235 {
1236 bool bRetval(true);
1237
1238 if (maPackedFileEntryVector.empty())
1239 {
1240 // get rid of (now?) empty pack file
1241 osl::File::remove(maURL);
1242 }
1243 else if (mbChanged)
1244 {
1245 // need to create a new pack file, do this in a temp file to which data
1246 // will be copied from local file (so keep it here until this is done)
1247 oslFileHandle aHandle;
1248 OUString aTempURL;
1249
1250 // open target temp file - it exists until deleted
1251 if (osl::File::E_None == osl::FileBase::createTempFile(nullptr, &aHandle, &aTempURL))
1252 {
1253 sal_uInt8 aArray[4];
1254 sal_uInt64 nBaseWritten(0);
1255
1256 aArray[0] = 'P';
1257 aArray[1] = 'A';
1258 aArray[2] = 'C';
1259 aArray[3] = 'K';
1260
1261 // write File_ID
1262 if (osl_File_E_None == osl_writeFile(aHandle, static_cast<const void*>(aArray), 4, &nBaseWritten) && 4 == nBaseWritten)
1263 {
1264 const sal_uInt32 nSize(maPackedFileEntryVector.size());
1265
1266 // write number of entries
1267 if (write_sal_uInt32(aHandle, nSize))
1268 {
1269 // write placeholder for headers. Due to the fact that
1270 // PackFileSize for newly added files gets set during
1271 // writing the content entry, write headers after content
1272 // is written. To do so, write placeholders here
1273 sal_uInt32 nWriteSize(0);
1274
1275 nWriteSize += maPackedFileEntryVector.size() * PackedFileEntry::getEntrySize();
1276
1277 aArray[0] = aArray[1] = aArray[2] = aArray[3] = 0;
1278
1279 for (sal_uInt32 a(0); bRetval && a < nWriteSize; a++)
1280 {
1281 if (osl_File_E_None != osl_writeFile(aHandle, static_cast<const void*>(aArray), 1, &nBaseWritten) || 1 != nBaseWritten)
1282 {
1283 bRetval = false;
1284 }
1285 }
1286
1287 if (bRetval)
1288 {
1289 // write contents - this may adapt PackFileSize for new
1290 // files
1291 for (auto& candidate : maPackedFileEntryVector)
1292 {
1293 if (!candidate.copy_content(aHandle, false))
1294 {
1295 bRetval = false;
1296 break;
1297 }
1298 }
1299 }
1300
1301 if (bRetval)
1302 {
1303 // seek back to header start (at position 8)
1304 if (osl_File_E_None != osl_setFilePos(aHandle, osl_Pos_Absolut, sal_Int64(8)))
1305 {
1306 bRetval = false;
1307 }
1308 }
1309
1310 if (bRetval)
1311 {
1312 // write headers
1313 for (const auto& candidate : maPackedFileEntryVector)
1314 {
1315 if (!candidate.write_header(aHandle))
1316 {
1317 // error
1318 bRetval = false;
1319 break;
1320 }
1321 }
1322 }
1323 }
1324 }
1325 }
1326
1327 // close temp file (in all cases) - it exists until deleted
1328 osl_closeFile(aHandle);
1329
1330 if (bRetval)
1331 {
1332 // copy over existing file by first deleting original
1333 // and moving the temp file to old original
1334 osl::File::remove(maURL);
1335 osl::File::move(aTempURL, maURL);
1336 }
1337
1338 // delete temp file (in all cases - it may be moved already)
1339 osl::File::remove(aTempURL);
1340 }
1341 }
1342
1343 bool tryPush(FileSharedPtr const & rFileCandidate, bool bCompress)
1344 {
1345 sal_uInt64 nFileSize(0);
1346
1347 if (rFileCandidate && osl::File::E_None == rFileCandidate->open(osl_File_OpenFlag_Read))
1348 {
1349 rFileCandidate->getSize(nFileSize);
1350 rFileCandidate->close();
1351 }
1352
1353 if (0 == nFileSize)
1354 {
1355 // empty file offered
1356 return false;
1357 }
1358
1359 bool bNeedToAdd(false);
1360 sal_uInt32 nCrc32(0);
1361
1362 if (maPackedFileEntryVector.empty())
1363 {
1364 // no backup yet, add as 1st backup
1365 bNeedToAdd = true;
1366 }
1367 else
1368 {
1369 // already backups there, check if different from last entry
1370 const PackedFileEntry& aLastEntry = maPackedFileEntryVector.back();
1371
1372 // check if file is different
1373 if (aLastEntry.getFullFileSize() != static_cast<sal_uInt32>(nFileSize))
1374 {
1375 // different size, different file
1376 bNeedToAdd = true;
1377 }
1378 else
1379 {
1380 // same size, check crc32
1381 nCrc32 = createCrc32(rFileCandidate, 0);
1382
1383 if (nCrc32 != aLastEntry.getCrc32())
1384 {
1385 // different crc, different file
1386 bNeedToAdd = true;
1387 }
1388 }
1389 }
1390
1391 if (bNeedToAdd)
1392 {
1393 // create crc32 if not yet done
1394 if (0 == nCrc32)
1395 {
1396 nCrc32 = createCrc32(rFileCandidate, 0);
1397 }
1398
1399 // create a file entry for a new file. Offset is set automatically
1400 // to 0 to mark the entry as new file entry
1401 maPackedFileEntryVector.emplace_back(
1402 static_cast< sal_uInt32 >(nFileSize),
1403 nCrc32,
1404 rFileCandidate,
1405 bCompress);
1406
1407 mbChanged = true;
1408 }
1409
1410 return bNeedToAdd;
1411 }
1412
1413 bool tryPop(oslFileHandle& rHandle)
1414 {
1415 if (maPackedFileEntryVector.empty())
1416 return false;
1417
1418 // already backups there, check if different from last entry
1419 PackedFileEntry& aLastEntry = maPackedFileEntryVector.back();
1420
1421 // here the uncompress flag has to be determined, true
1422 // means to add the file compressed, false means to add it
1423 // uncompressed
1424 bool bRetval = aLastEntry.copy_content(rHandle, true);
1425
1426 if (bRetval)
1427 {
1428 maPackedFileEntryVector.pop_back();
1429 mbChanged = true;
1430 }
1431
1432 return bRetval;
1433 }
1434
1435 void tryReduceToNumBackups(sal_uInt16 nNumBackups)
1436 {
1437 while (maPackedFileEntryVector.size() > nNumBackups)
1438 {
1439 maPackedFileEntryVector.pop_front();
1440 mbChanged = true;
1441 }
1442 }
1443
1444 bool empty() const
1445 {
1446 return maPackedFileEntryVector.empty();
1447 }
1448 };
1449}
1450
1451namespace comphelper
1452{
1460 OUString BackupFileHelper::maExt;
1461
1463 {
1464 if (maInitialBaseURL.isEmpty())
1465 {
1466 // try to access user layer configuration file URL, the one that
1467 // points to registrymodifications.xcu
1468 OUString conf("${CONFIGURATION_LAYERS}");
1469 rtl::Bootstrap::expandMacros(conf);
1470 static const OUStringLiteral aTokenUser(u"user:");
1471 sal_Int32 nStart(conf.indexOf(aTokenUser));
1472
1473 if (-1 != nStart)
1474 {
1475 nStart += aTokenUser.getLength();
1476 sal_Int32 nEnd(conf.indexOf(' ', nStart));
1477
1478 if (-1 == nEnd)
1479 {
1480 nEnd = conf.getLength();
1481 }
1482
1483 maInitialBaseURL = conf.copy(nStart, nEnd - nStart);
1484 (void)maInitialBaseURL.startsWith("!", &maInitialBaseURL);
1485 }
1486
1487 if (!maInitialBaseURL.isEmpty())
1488 {
1489 // split URL at extension and at last path separator
1492 maRegModName);
1493 }
1494
1495 if (!maUserConfigBaseURL.isEmpty())
1496 {
1497 // check if SafeModeDir exists
1499 }
1500
1502
1504 {
1505 // adapt work URL to do all repair op's in the correct directory
1507 }
1508 }
1509
1510 return maInitialBaseURL;
1511 }
1512
1514 {
1515 static const OUString aSafeMode("SafeMode");
1516
1517 return aSafeMode;
1518 }
1519
1521 : mnNumBackups(2),
1522 mnMode(1),
1523 mbActive(false),
1524 mbExtensions(true),
1525 mbCompress(true)
1526 {
1527 OUString sTokenOut;
1528
1529 // read configuration item 'SecureUserConfig' -> bool on/off
1530 if (rtl::Bootstrap::get("SecureUserConfig", sTokenOut))
1531 {
1532 mbActive = sTokenOut.toBoolean();
1533 }
1534
1535 if (mbActive)
1536 {
1537 // ensure existence
1539
1540 // if not found, we are out of business (maExt may be empty)
1541 mbActive = !maInitialBaseURL.isEmpty() && !maUserConfigBaseURL.isEmpty() && !maRegModName.isEmpty();
1542 }
1543
1544 if (mbActive && rtl::Bootstrap::get("SecureUserConfigNumCopies", sTokenOut))
1545 {
1546 const sal_uInt16 nConfigNumCopies(static_cast<sal_uInt16>(sTokenOut.toUInt32()));
1547
1548 // limit to range [1..mnMaxAllowedBackups]
1549 mnNumBackups = std::clamp(mnNumBackups, nConfigNumCopies, mnMaxAllowedBackups);
1550 }
1551
1552 if (mbActive && rtl::Bootstrap::get("SecureUserConfigMode", sTokenOut))
1553 {
1554 const sal_uInt16 nMode(static_cast<sal_uInt16>(sTokenOut.toUInt32()));
1555
1556 // limit to range [0..2]
1557 mnMode = std::min(nMode, sal_uInt16(2));
1558 }
1559
1560 if (mbActive && rtl::Bootstrap::get("SecureUserConfigExtensions", sTokenOut))
1561 {
1562 mbExtensions = sTokenOut.toBoolean();
1563 }
1564
1565 if (mbActive && rtl::Bootstrap::get("SecureUserConfigCompress", sTokenOut))
1566 {
1567 mbCompress = sTokenOut.toBoolean();
1568 }
1569 }
1570
1572 {
1573 mbExitWasCalled = true;
1574 }
1575
1577 {
1578 return mbExitWasCalled;
1579 }
1580
1582 {
1583 // ensure existence of needed paths
1585
1586 if (maUserConfigBaseURL.isEmpty())
1587 return;
1588
1589 if (bSafeMode)
1590 {
1592 {
1593 std::set< OUString > aExcludeList;
1594
1595 // do not move SafeMode directory itself
1596 aExcludeList.insert(getSafeModeName());
1597
1598 // init SafeMode by creating the 'SafeMode' directory and moving
1599 // all stuff there. All repairs will happen there. Both Dirs have to exist.
1600 // extend maUserConfigWorkURL as needed
1602
1603 osl::Directory::createPath(maUserConfigWorkURL);
1605
1606 // switch local flag, maUserConfigWorkURL is already reset
1607 mbSafeModeDirExists = true;
1608 }
1609 }
1610 else
1611 {
1613 {
1614 // SafeMode has ended, return to normal mode by moving all content
1615 // from 'SafeMode' directory back to UserDirectory and deleting it.
1616 // Both Dirs have to exist
1617 std::set< OUString > aExcludeList;
1618
1621
1622 // switch local flag and reset maUserConfigWorkURL
1623 mbSafeModeDirExists = false;
1625 }
1626 }
1627 }
1628
1630 {
1631 // no push when SafeModeDir exists, it may be Office's exit after SafeMode
1632 // where SafeMode flag is already deleted, but SafeModeDir cleanup is not
1633 // done yet (is done at next startup)
1635 return;
1636
1637 const OUString aPackURL(getPackURL());
1638
1639 // ensure dir and file vectors
1641
1642 // process all files in question recursively
1643 if (!maDirs.empty() || !maFiles.empty())
1644 {
1646 maDirs,
1647 maFiles,
1649 aPackURL);
1650 }
1651 }
1652
1654 {
1655 // no push when SafeModeDir exists, it may be Office's exit after SafeMode
1656 // where SafeMode flag is already deleted, but SafeModeDir cleanup is not
1657 // done yet (is done at next startup)
1659 {
1660 const OUString aPackURL(getPackURL());
1661
1662 tryPush_extensionInfo(aPackURL);
1663 }
1664 }
1665
1667 {
1668 bool bPopPossible(false);
1669
1670 if (mbActive)
1671 {
1672 const OUString aPackURL(getPackURL());
1673
1674 // ensure dir and file vectors
1676
1677 // process all files in question recursively
1678 if (!maDirs.empty() || !maFiles.empty())
1679 {
1680 bPopPossible = isPopPossible_files(
1681 maDirs,
1682 maFiles,
1684 aPackURL);
1685 }
1686 }
1687
1688 return bPopPossible;
1689 }
1690
1692 {
1693 if (!mbActive)
1694 return;
1695
1696 bool bDidPop(false);
1697 const OUString aPackURL(getPackURL());
1698
1699 // ensure dir and file vectors
1701
1702 // process all files in question recursively
1703 if (!maDirs.empty() || !maFiles.empty())
1704 {
1705 bDidPop = tryPop_files(
1706 maDirs,
1707 maFiles,
1709 aPackURL);
1710 }
1711
1712 if (bDidPop)
1713 {
1714 // try removal of evtl. empty directory
1715 osl::Directory::remove(aPackURL);
1716 }
1717 }
1718
1720 {
1721 bool bPopPossible(false);
1722
1723 if (mbActive && mbExtensions)
1724 {
1725 const OUString aPackURL(getPackURL());
1726
1727 bPopPossible = isPopPossible_extensionInfo(aPackURL);
1728 }
1729
1730 return bPopPossible;
1731 }
1732
1734 {
1735 if (!(mbActive && mbExtensions))
1736 return;
1737
1738 bool bDidPop(false);
1739 const OUString aPackURL(getPackURL());
1740
1741 bDidPop = tryPop_extensionInfo(aPackURL);
1742
1743 if (bDidPop)
1744 {
1745 // try removal of evtl. empty directory
1746 osl::Directory::remove(aPackURL);
1747 }
1748 }
1749
1751 {
1752 // check if there are still enabled extension which can be disabled,
1753 // but as we are now in SafeMode, use XML infos for this since the
1754 // extensions are not loaded from XExtensionManager
1755 class ExtensionInfo aExtensionInfo;
1756
1757 aExtensionInfo.createUserExtensionRegistryEntriesFromXML(maUserConfigWorkURL);
1758
1759 return aExtensionInfo.areThereEnabledExtensions();
1760 }
1761
1763 {
1764 // disable all still enabled extensions,
1765 // but as we are now in SafeMode, use XML infos for this since the
1766 // extensions are not loaded from XExtensionManager
1767 ExtensionInfo aCurrentExtensionInfo;
1768 const ExtensionInfoEntryVector aToBeEnabled{};
1769 ExtensionInfoEntryVector aToBeDisabled;
1770
1771 aCurrentExtensionInfo.createUserExtensionRegistryEntriesFromXML(maUserConfigWorkURL);
1772
1773 const ExtensionInfoEntryVector& rCurrentVector = aCurrentExtensionInfo.getExtensionInfoEntryVector();
1774
1775 for (const auto& rCurrentInfo : rCurrentVector)
1776 {
1777 if (rCurrentInfo.isEnabled())
1778 {
1779 aToBeDisabled.push_back(rCurrentInfo);
1780 }
1781 }
1782
1783 ExtensionInfo::changeEnableDisableStateInXML(maUserConfigWorkURL, aToBeEnabled, aToBeDisabled);
1784 }
1785
1787 {
1788 // check if there are User Extensions installed.
1789 class ExtensionInfo aExtensionInfo;
1790
1791 aExtensionInfo.createUserExtensionRegistryEntriesFromXML(maUserConfigWorkURL);
1792
1793 return !aExtensionInfo.getExtensionInfoEntryVector().empty();
1794 }
1795
1797 {
1798 // delete User Extension installs
1800 }
1801
1803 {
1804 // check if there are shared Extensions installed
1805 class ExtensionInfo aExtensionInfo;
1806
1807 aExtensionInfo.createSharedExtensionRegistryEntriesFromXML(maUserConfigWorkURL);
1808
1809 return !aExtensionInfo.getExtensionInfoEntryVector().empty();
1810 }
1811
1813 {
1814 // reset shared extension info
1816 }
1817
1819 {
1820 // check if there are shared Extensions installed
1821 class ExtensionInfo aExtensionInfo;
1822
1823 aExtensionInfo.createBundledExtensionRegistryEntriesFromXML(maUserConfigWorkURL);
1824
1825 return !aExtensionInfo.getExtensionInfoEntryVector().empty();
1826 }
1827
1829 {
1830 // reset shared extension info
1832 }
1833
1834 const std::vector< OUString >& BackupFileHelper::getCustomizationDirNames()
1835 {
1836 static std::vector< OUString > aDirNames =
1837 {
1838 "config", // UI config stuff
1839 "registry", // most of the registry stuff
1840 "psprint", // not really needed, can be abandoned
1841 "store", // not really needed, can be abandoned
1842 "temp", // not really needed, can be abandoned
1843 "pack" // own backup dir
1844 };
1845
1846 return aDirNames;
1847 }
1848
1849 const std::vector< OUString >& BackupFileHelper::getCustomizationFileNames()
1850 {
1851 static std::vector< OUString > aFileNames =
1852 {
1853 "registrymodifications.xcu" // personal registry stuff
1854 };
1855
1856 return aFileNames;
1857 }
1858
1859 namespace {
1860 uno::Reference<XElement> lcl_getConfigElement(const uno::Reference<XDocument>& xDocument, const OUString& rPath,
1861 const OUString& rKey, const OUString& rValue)
1862 {
1863 uno::Reference< XElement > itemElement = xDocument->createElement("item");
1864 itemElement->setAttribute("oor:path", rPath);
1865
1866 uno::Reference< XElement > propElement = xDocument->createElement("prop");
1867 propElement->setAttribute("oor:name", rKey);
1868 propElement->setAttribute("oor:op", "replace"); // Replace any other options
1869
1870 uno::Reference< XElement > valueElement = xDocument->createElement("value");
1871 uno::Reference< XText > textElement = xDocument->createTextNode(rValue);
1872
1873 valueElement->appendChild(textElement);
1874 propElement->appendChild(valueElement);
1875 itemElement->appendChild(propElement);
1876
1877 return itemElement;
1878 }
1879 }
1880
1882 {
1883 const OUString aRegistryModifications(maUserConfigWorkURL + "/registrymodifications.xcu");
1884 if (!DirectoryHelper::fileExists(aRegistryModifications))
1885 return;
1886
1887 uno::Reference< uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext();
1888 uno::Reference< XDocumentBuilder > xBuilder = DocumentBuilder::create(xContext);
1889 uno::Reference< XDocument > xDocument = xBuilder->parseURI(aRegistryModifications);
1890 uno::Reference< XElement > xRootElement = xDocument->getDocumentElement();
1891
1892 xRootElement->appendChild(lcl_getConfigElement(xDocument, "/org.openoffice.Office.Common/VCL",
1893 "DisableOpenGL", "true"));
1894 xRootElement->appendChild(lcl_getConfigElement(xDocument, "/org.openoffice.Office.Common/Misc",
1895 "UseOpenCL", "false"));
1896 // Do not disable Skia entirely, just force its CPU-based raster mode.
1897 xRootElement->appendChild(lcl_getConfigElement(xDocument, "/org.openoffice.Office.Common/VCL",
1898 "ForceSkia", "false"));
1899 xRootElement->appendChild(lcl_getConfigElement(xDocument, "/org.openoffice.Office.Common/VCL",
1900 "ForceSkiaRaster", "true"));
1901
1902 OUString aTempURL;
1903 {
1904 // use the scope to make sure that the temp file gets properly closed before move
1905
1906 // write back
1907 uno::Reference< xml::sax::XSAXSerializable > xSerializer(xDocument, uno::UNO_QUERY);
1908
1909 if (!xSerializer.is())
1910 return;
1911
1912 // create a SAXWriter
1913 uno::Reference< xml::sax::XWriter > const xSaxWriter = xml::sax::Writer::create(xContext);
1914 uno::Reference< io::XTempFile > xTempFile = io::TempFile::create(xContext);
1915 xTempFile->setRemoveFile(false); // avoid removal of tempfile when leaving the scope
1916 uno::Reference< io::XOutputStream > xOutStrm = xTempFile->getOutputStream();
1917
1918 // set output stream and do the serialization
1919 xSaxWriter->setOutputStream(xOutStrm);
1920 xSerializer->serialize(xSaxWriter, uno::Sequence< beans::StringPair >());
1921
1922 // get URL from temp file
1923 aTempURL = xTempFile->getUri();
1924 }
1925
1926 // copy back file
1927 if (aTempURL.isEmpty() || !DirectoryHelper::fileExists(aTempURL))
1928 return;
1929
1930 if (DirectoryHelper::fileExists(aRegistryModifications))
1931 {
1932 osl::File::remove(aRegistryModifications);
1933 }
1934
1935 int result = osl::File::move(aTempURL, aRegistryModifications);
1936 SAL_WARN_IF(result != osl::FileBase::E_None, "comphelper.backupfilehelper", "could not copy back modified Extension configuration file");
1937 }
1938
1940 {
1941 // return true if not all of the customization selection dirs or files are deleted
1942 const std::vector< OUString >& rDirs = getCustomizationDirNames();
1943
1944 for (const auto& a : rDirs)
1945 {
1947 {
1948 return true;
1949 }
1950 }
1951
1952 const std::vector< OUString >& rFiles = getCustomizationFileNames();
1953
1954 for (const auto& b : rFiles)
1955 {
1957 {
1958 return true;
1959 }
1960 }
1961
1962 return false;
1963 }
1964
1966 {
1967 // delete all of the customization selection dirs
1968 const std::vector< OUString >& rDirs = getCustomizationDirNames();
1969
1970 for (const auto& a : rDirs)
1971 {
1973 }
1974
1975 const std::vector< OUString >& rFiles = getCustomizationFileNames();
1976
1977 for (const auto& b : rFiles)
1978 {
1980 }
1981 }
1982
1984 {
1985 // completely delete the current UserProfile
1987 }
1988
1990 {
1991 return maUserConfigBaseURL;
1992 }
1993
1995 {
1996 return maUserConfigWorkURL;
1997 }
1998
2000
2002 {
2003 return OUString(maUserConfigWorkURL + "/pack");
2004 }
2005
2007
2009 const std::set< OUString >& rDirs,
2010 const std::set< std::pair< OUString, OUString > >& rFiles,
2011 std::u16string_view rSourceURL, // source dir without trailing '/'
2012 const OUString& rTargetURL // target dir without trailing '/'
2013 )
2014 {
2015 bool bDidPush(false);
2016 osl::Directory::createPath(rTargetURL);
2017
2018 // process files
2019 for (const auto& file : rFiles)
2020 {
2021 bDidPush |= tryPush_file(
2022 rSourceURL,
2023 rTargetURL,
2024 file.first,
2025 file.second);
2026 }
2027
2028 // process dirs
2029 for (const auto& dir : rDirs)
2030 {
2031 OUString aNewSourceURL(OUString::Concat(rSourceURL) + "/" + dir);
2032 OUString aNewTargetURL(rTargetURL + "/" + dir);
2033 std::set< OUString > aNewDirs;
2034 std::set< std::pair< OUString, OUString > > aNewFiles;
2035
2037 aNewSourceURL,
2038 aNewDirs,
2039 aNewFiles);
2040
2041 if (!aNewDirs.empty() || !aNewFiles.empty())
2042 {
2043 bDidPush |= tryPush_Files(
2044 aNewDirs,
2045 aNewFiles,
2046 aNewSourceURL,
2047 aNewTargetURL);
2048 }
2049 }
2050
2051 if (!bDidPush)
2052 {
2053 // try removal of evtl. empty directory
2054 osl::Directory::remove(rTargetURL);
2055 }
2056
2057 return bDidPush;
2058 }
2059
2061 std::u16string_view rSourceURL, // source dir without trailing '/'
2062 std::u16string_view rTargetURL, // target dir without trailing '/'
2063 std::u16string_view rName, // filename
2064 std::u16string_view rExt // extension (or empty)
2065 )
2066 {
2067 const OUString aFileURL(createFileURL(rSourceURL, rName, rExt));
2068
2069 if (DirectoryHelper::fileExists(aFileURL))
2070 {
2071 const OUString aPackURL(createPackURL(rTargetURL, rName));
2072 PackedFile aPackedFile(aPackURL);
2073 FileSharedPtr aBaseFile = std::make_shared<osl::File>(aFileURL);
2074
2075 if (aPackedFile.tryPush(aBaseFile, mbCompress))
2076 {
2077 // reduce to allowed number and flush
2078 aPackedFile.tryReduceToNumBackups(mnNumBackups);
2079 aPackedFile.flush();
2080
2081 return true;
2082 }
2083 }
2084
2085 return false;
2086 }
2087
2089
2091 const std::set< OUString >& rDirs,
2092 const std::set< std::pair< OUString, OUString > >& rFiles,
2093 std::u16string_view rSourceURL, // source dir without trailing '/'
2094 std::u16string_view rTargetURL // target dir without trailing '/'
2095 )
2096 {
2097 bool bPopPossible(false);
2098
2099 // process files
2100 for (const auto& file : rFiles)
2101 {
2102 bPopPossible |= isPopPossible_file(
2103 rSourceURL,
2104 rTargetURL,
2105 file.first,
2106 file.second);
2107 }
2108
2109 // process dirs
2110 for (const auto& dir : rDirs)
2111 {
2112 OUString aNewSourceURL(OUString::Concat(rSourceURL) + "/" + dir);
2113 OUString aNewTargetURL(OUString::Concat(rTargetURL) + "/" + dir);
2114 std::set< OUString > aNewDirs;
2115 std::set< std::pair< OUString, OUString > > aNewFiles;
2116
2118 aNewSourceURL,
2119 aNewDirs,
2120 aNewFiles);
2121
2122 if (!aNewDirs.empty() || !aNewFiles.empty())
2123 {
2124 bPopPossible |= isPopPossible_files(
2125 aNewDirs,
2126 aNewFiles,
2127 aNewSourceURL,
2128 aNewTargetURL);
2129 }
2130 }
2131
2132 return bPopPossible;
2133 }
2134
2136 std::u16string_view rSourceURL, // source dir without trailing '/'
2137 std::u16string_view rTargetURL, // target dir without trailing '/'
2138 std::u16string_view rName, // filename
2139 std::u16string_view rExt // extension (or empty)
2140 )
2141 {
2142 const OUString aFileURL(createFileURL(rSourceURL, rName, rExt));
2143
2144 if (DirectoryHelper::fileExists(aFileURL))
2145 {
2146 const OUString aPackURL(createPackURL(rTargetURL, rName));
2147 PackedFile aPackedFile(aPackURL);
2148
2149 return !aPackedFile.empty();
2150 }
2151
2152 return false;
2153 }
2154
2156
2158 const std::set< OUString >& rDirs,
2159 const std::set< std::pair< OUString, OUString > >& rFiles,
2160 std::u16string_view rSourceURL, // source dir without trailing '/'
2161 const OUString& rTargetURL // target dir without trailing '/'
2162 )
2163 {
2164 bool bDidPop(false);
2165
2166 // process files
2167 for (const auto& file : rFiles)
2168 {
2169 bDidPop |= tryPop_file(
2170 rSourceURL,
2171 rTargetURL,
2172 file.first,
2173 file.second);
2174 }
2175
2176 // process dirs
2177 for (const auto& dir : rDirs)
2178 {
2179 OUString aNewSourceURL(OUString::Concat(rSourceURL) + "/" + dir);
2180 OUString aNewTargetURL(rTargetURL + "/" + dir);
2181 std::set< OUString > aNewDirs;
2182 std::set< std::pair< OUString, OUString > > aNewFiles;
2183
2185 aNewSourceURL,
2186 aNewDirs,
2187 aNewFiles);
2188
2189 if (!aNewDirs.empty() || !aNewFiles.empty())
2190 {
2191 bDidPop |= tryPop_files(
2192 aNewDirs,
2193 aNewFiles,
2194 aNewSourceURL,
2195 aNewTargetURL);
2196 }
2197 }
2198
2199 if (bDidPop)
2200 {
2201 // try removal of evtl. empty directory
2202 osl::Directory::remove(rTargetURL);
2203 }
2204
2205 return bDidPop;
2206 }
2207
2209 std::u16string_view rSourceURL, // source dir without trailing '/'
2210 std::u16string_view rTargetURL, // target dir without trailing '/'
2211 std::u16string_view rName, // filename
2212 std::u16string_view rExt // extension (or empty)
2213 )
2214 {
2215 const OUString aFileURL(createFileURL(rSourceURL, rName, rExt));
2216
2217 if (!DirectoryHelper::fileExists(aFileURL))
2218 return false;
2219
2220 // try Pop for base file
2221 const OUString aPackURL(createPackURL(rTargetURL, rName));
2222 PackedFile aPackedFile(aPackURL);
2223
2224 if (aPackedFile.empty())
2225 return false;
2226
2227 oslFileHandle aHandle;
2228 OUString aTempURL;
2229
2230 // open target temp file - it exists until deleted
2231 if (osl::File::E_None != osl::FileBase::createTempFile(nullptr, &aHandle, &aTempURL))
2232 return false;
2233
2234 bool bRetval(aPackedFile.tryPop(aHandle));
2235
2236 // close temp file (in all cases) - it exists until deleted
2237 osl_closeFile(aHandle);
2238
2239 if (bRetval)
2240 {
2241 // copy over existing file by first deleting original
2242 // and moving the temp file to old original
2243 osl::File::remove(aFileURL);
2244 osl::File::move(aTempURL, aFileURL);
2245
2246 // reduce to allowed number and flush
2247 aPackedFile.tryReduceToNumBackups(mnNumBackups);
2248 aPackedFile.flush();
2249 }
2250
2251 // delete temp file (in all cases - it may be moved already)
2252 osl::File::remove(aTempURL);
2253
2254 return bRetval;
2255 }
2256
2258
2260 std::u16string_view rTargetURL // target dir without trailing '/'
2261 )
2262 {
2263 ExtensionInfo aExtensionInfo;
2264 OUString aTempURL;
2265 bool bRetval(false);
2266
2267 // create current configuration and write to temp file - it exists until deleted
2268 if (aExtensionInfo.createTempFile(aTempURL))
2269 {
2270 const OUString aPackURL(createPackURL(rTargetURL, u"ExtensionInfo"));
2271 PackedFile aPackedFile(aPackURL);
2272 FileSharedPtr aBaseFile = std::make_shared<osl::File>(aTempURL);
2273
2274 if (aPackedFile.tryPush(aBaseFile, mbCompress))
2275 {
2276 // reduce to allowed number and flush
2277 aPackedFile.tryReduceToNumBackups(mnNumBackups);
2278 aPackedFile.flush();
2279 bRetval = true;
2280 }
2281 }
2282
2283 // delete temp file (in all cases)
2284 osl::File::remove(aTempURL);
2285 return bRetval;
2286 }
2287
2289 std::u16string_view rTargetURL // target dir without trailing '/'
2290 )
2291 {
2292 // extensionInfo always exists internally, no test needed
2293 const OUString aPackURL(createPackURL(rTargetURL, u"ExtensionInfo"));
2294 PackedFile aPackedFile(aPackURL);
2295
2296 return !aPackedFile.empty();
2297 }
2298
2300 std::u16string_view rTargetURL // target dir without trailing '/'
2301 )
2302 {
2303 // extensionInfo always exists internally, no test needed
2304 const OUString aPackURL(createPackURL(rTargetURL, u"ExtensionInfo"));
2305 PackedFile aPackedFile(aPackURL);
2306
2307 if (aPackedFile.empty())
2308 return false;
2309
2310 oslFileHandle aHandle;
2311 OUString aTempURL;
2312
2313 // open target temp file - it exists until deleted
2314 if (osl::File::E_None != osl::FileBase::createTempFile(nullptr, &aHandle, &aTempURL))
2315 return false;
2316
2317 bool bRetval(aPackedFile.tryPop(aHandle));
2318
2319 // close temp file (in all cases) - it exists until deleted
2320 osl_closeFile(aHandle);
2321
2322 if (bRetval)
2323 {
2324 // last config is in temp file, load it to ExtensionInfo
2325 ExtensionInfo aLoadedExtensionInfo;
2326 FileSharedPtr aBaseFile = std::make_shared<osl::File>(aTempURL);
2327
2328 if (osl::File::E_None == aBaseFile->open(osl_File_OpenFlag_Read))
2329 {
2330 if (aLoadedExtensionInfo.read_entries(aBaseFile))
2331 {
2332 // get current extension info, but from XML config files
2333 ExtensionInfo aCurrentExtensionInfo;
2334
2335 aCurrentExtensionInfo.createUserExtensionRegistryEntriesFromXML(maUserConfigWorkURL);
2336
2337 // now we have loaded last_working (aLoadedExtensionInfo) and
2338 // current (aCurrentExtensionInfo) ExtensionInfo and may react on
2339 // differences by de/activating these as needed
2340 const ExtensionInfoEntryVector& aUserEntries = aCurrentExtensionInfo.getExtensionInfoEntryVector();
2341 const ExtensionInfoEntryVector& rLoadedVector = aLoadedExtensionInfo.getExtensionInfoEntryVector();
2342 ExtensionInfoEntryVector aToBeDisabled;
2343 ExtensionInfoEntryVector aToBeEnabled;
2344
2345 for (const auto& rCurrentInfo : aUserEntries)
2346 {
2347 const ExtensionInfoEntry* pLoadedInfo = nullptr;
2348
2349 for (const auto& rLoadedInfo : rLoadedVector)
2350 {
2351 if (rCurrentInfo.isSameExtension(rLoadedInfo))
2352 {
2353 pLoadedInfo = &rLoadedInfo;
2354 break;
2355 }
2356 }
2357
2358 if (nullptr != pLoadedInfo)
2359 {
2360 // loaded info contains information about the Extension rCurrentInfo
2361 const bool bCurrentEnabled(rCurrentInfo.isEnabled());
2362 const bool bLoadedEnabled(pLoadedInfo->isEnabled());
2363
2364 if (bCurrentEnabled && !bLoadedEnabled)
2365 {
2366 aToBeDisabled.push_back(rCurrentInfo);
2367 }
2368 else if (!bCurrentEnabled && bLoadedEnabled)
2369 {
2370 aToBeEnabled.push_back(rCurrentInfo);
2371 }
2372 }
2373 else
2374 {
2375 // There is no loaded info about the Extension rCurrentInfo.
2376 // It needs to be disabled
2377 if (rCurrentInfo.isEnabled())
2378 {
2379 aToBeDisabled.push_back(rCurrentInfo);
2380 }
2381 }
2382 }
2383
2384 if (!aToBeDisabled.empty() || !aToBeEnabled.empty())
2385 {
2386 ExtensionInfo::changeEnableDisableStateInXML(maUserConfigWorkURL, aToBeEnabled, aToBeDisabled);
2387 }
2388
2389 bRetval = true;
2390 }
2391 }
2392
2393 // reduce to allowed number and flush
2394 aPackedFile.tryReduceToNumBackups(mnNumBackups);
2395 aPackedFile.flush();
2396 }
2397
2398 // delete temp file (in all cases - it may be moved already)
2399 osl::File::remove(aTempURL);
2400
2401 return bRetval;
2402 }
2403
2405
2407 {
2408 if (!maDirs.empty() || !maFiles.empty())
2409 {
2410 // already done
2411 return;
2412 }
2413
2414 // Information about the configuration and the role/purpose of directories in
2415 // the UserConfiguration is taken from: https://wiki.documentfoundation.org/UserProfile
2416
2417 // fill dir and file info list to work with dependent on work mode
2418 switch (mnMode)
2419 {
2420 case 0:
2421 {
2422 // simple mode: add just registrymodifications
2423 // (the orig file in maInitialBaseURL)
2424 maFiles.insert(std::pair< OUString, OUString >(maRegModName, maExt));
2425 break;
2426 }
2427 case 1:
2428 {
2429 // defined mode: Add a selection of dirs containing User-Defined and thus
2430 // valuable configuration information.
2431 // This is clearly discussable in every single point and may be adapted/corrected
2432 // over time. Main focus is to secure User-Defined/adapted values
2433
2434 // add registrymodifications (the orig file in maInitialBaseURL)
2435 maFiles.insert(std::pair< OUString, OUString >(maRegModName, maExt));
2436
2437 // User-defined substitution table (Tools/AutoCorrect)
2438 maDirs.insert("autocorr");
2439
2440 // User-Defined AutoText (Edit/AutoText)
2441 maDirs.insert("autotext");
2442
2443 // User-defined Macros
2444 maDirs.insert("basic");
2445
2446 // User-adapted toolbars for modules
2447 maDirs.insert("config");
2448
2449 // Initial and User-defined Databases
2450 maDirs.insert("database");
2451
2452 // most part of registry files
2453 maDirs.insert("registry");
2454
2455 // User-Defined Scripts
2456 maDirs.insert("Scripts");
2457
2458 // Template files
2459 maDirs.insert("template");
2460
2461 // Custom Dictionaries
2462 maDirs.insert("wordbook");
2463
2464 // Questionable - where and how is Extension stuff held and how
2465 // does this interact with enabled/disabled states which are extra handled?
2466 // Keep out of business until deeper evaluated
2467 //
2468 // maDirs.insert("extensions");
2469 // maDirs.insert("uno-packages");
2470 break;
2471 }
2472 case 2:
2473 {
2474 // whole directory. To do so, scan directory and exclude some dirs
2475 // from which we know they do not need to be secured explicitly. This
2476 // should already include registrymodifications, too.
2479 maDirs,
2480 maFiles);
2481
2482 // should not exist, but for the case an error occurred and it got
2483 // copied somehow, avoid further recursive copying/saving
2484 maDirs.erase("SafeMode");
2485
2486 // not really needed, can be abandoned
2487 maDirs.erase("psprint");
2488
2489 // not really needed, can be abandoned
2490 maDirs.erase("store");
2491
2492 // not really needed, can be abandoned
2493 maDirs.erase("temp");
2494
2495 // exclude own backup dir to avoid recursion
2496 maDirs.erase("pack");
2497
2498 break;
2499 }
2500 }
2501 }
2502}
2503
2504/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
bool mbChanged
const sal_uInt32 BACKUP_FILE_HELPER_BLOCK_SIZE
OUString maName
ScriptDocument aDocument
void tryPush()
tries to create a new backup, if there is none yet, or if the last differs from the base file.
static bool isTryResetCustomizationsPossible()
resets User-Customizations like Settings and UserInterface modifications
static void reactOnSafeMode(bool bSafeMode)
static const OUString & getUserProfileWorkURL()
Return the url of the backed up profile (when in safe mode)
static bool isTryDisableAllExtensionsPossible()
tries to iterate the extensions and to disable all of them
static const OUString & getInitialBaseURL()
static bool isTryResetBundledExtensionsPossible()
Reset bundled Extensions.
static void tryDisableHWAcceleration()
Disables OpenGL and OpenCL.
static bool isPopPossible_extensionInfo(std::u16string_view rTargetURL)
bool tryPush_file(std::u16string_view rSourceURL, std::u16string_view rTargetURL, std::u16string_view rName, std::u16string_view rExt)
BackupFileHelper()
Constructor to handle Backups of the given file, will internally detect configuration values and URL ...
static void tryResetUserProfile()
resets the whole UserProfile
static bool isTryResetSharedExtensionsPossible()
Reset shared Extensions.
std::set< std::pair< OUString, OUString > > maFiles
bool tryPop_files(const std::set< OUString > &rDirs, const std::set< std::pair< OUString, OUString > > &rFiles, std::u16string_view rSourceURL, const OUString &rTargetURL)
bool tryPush_Files(const std::set< OUString > &rDirs, const std::set< std::pair< OUString, OUString > > &rFiles, std::u16string_view rSourceURL, const OUString &rTargetURL)
static sal_uInt16 mnMaxAllowedBackups
void tryPop()
tries to execute a restore.
static const OUString & getSafeModeName()
bool tryPush_extensionInfo(std::u16string_view rTargetURL)
static const std::vector< OUString > & getCustomizationDirNames()
static const OUString & getUserProfileURL()
Return the profile url.
static bool isTryDeinstallUserExtensionsPossible()
Deinstall all User Extensions (installed for User only)
bool tryPop_file(std::u16string_view rSourceURL, std::u16string_view rTargetURL, std::u16string_view rName, std::u16string_view rExt)
bool tryPop_extensionInfo(std::u16string_view rTargetURL)
bool isPopPossible_files(const std::set< OUString > &rDirs, const std::set< std::pair< OUString, OUString > > &rFiles, std::u16string_view rSourceURL, std::u16string_view rTargetURL)
static const std::vector< OUString > & getCustomizationFileNames()
bool isPopPossible()
finds out if a restore is possible
static bool isPopPossible_file(std::u16string_view rSourceURL, std::u16string_view rTargetURL, std::u16string_view rName, std::u16string_view rExt)
static std::u16string_view splitAtLastToken(std::u16string_view rSrc, sal_Unicode aToken, OUString &rRight)
static bool deleteDirRecursively(const OUString &rDirURL)
static bool dirExists(const OUString &rDirURL)
static void scanDirsAndFiles(const OUString &rDirURL, std::set< OUString > &rDirs, std::set< std::pair< OUString, OUString > > &rFiles)
static bool moveDirContent(const OUString &rSourceDirURL, std::u16string_view rTargetDirURL, const std::set< OUString > &rExcludeList)
static bool fileExists(const OUString &rBaseURL)
sal_Int16 mnMode
float u
sal_Int32 nState
FilterGroup & rTarget
sal_Int32 nIndex
OUString aName
uno_Any a
sal_uInt16 nPos
#define SAL_WARN_IF(condition, area, stream)
OUStringBuffer & remove(OUStringBuffer &rIn, sal_Unicode c)
Removes all occurrences of a character from within the source string.
Definition: string.hxx:49
std::shared_ptr< osl::File > FileSharedPtr
Reference< XComponentContext > getProcessComponentContext()
This function gets the process service factory's default component context.
Any SAL_CALL getCaughtException()
constexpr OUStringLiteral USER
OString OUStringToOString(std::u16string_view str, ConnectionSettings const *settings)
bool mbActive
SHARED
JCOPY_OPTION option
unsigned char sal_uInt8
Any result
std::unique_ptr< char[]> aBuffer
bool operator<(const wwFont &r1, const wwFont &r2)
sal_Int32 nLength