LibreOffice Module configmgr (master) 1
components.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#include <sal/config.h>
21
22#include <cassert>
23#include <chrono>
24#include <utility>
25#include <vector>
26#include <set>
27
28#include <com/sun/star/beans/Optional.hpp>
29#include <com/sun/star/beans/UnknownPropertyException.hpp>
30#include <com/sun/star/beans/XPropertySet.hpp>
31#include <com/sun/star/container/NoSuchElementException.hpp>
32#include <com/sun/star/lang/WrappedTargetException.hpp>
33#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
34#include <com/sun/star/uno/Any.hxx>
35#include <com/sun/star/uno/Exception.hpp>
36#include <com/sun/star/uno/Reference.hxx>
37#include <com/sun/star/uno/RuntimeException.hpp>
38#include <com/sun/star/uno/XComponentContext.hpp>
39#include <com/sun/star/uno/XInterface.hpp>
41#include <config_dconf.h>
42#include <config_folders.h>
43#include <osl/conditn.hxx>
44#include <osl/file.hxx>
45#include <osl/mutex.hxx>
46#include <rtl/bootstrap.hxx>
47#include <rtl/ref.hxx>
48#include <rtl/ustrbuf.hxx>
49#include <rtl/ustring.hxx>
50#include <sal/log.hxx>
51#include <sal/types.h>
52#include <salhelper/thread.hxx>
55#include <o3tl/string_view.hxx>
56
57#include "additions.hxx"
58#include "components.hxx"
59#include "data.hxx"
60#include "lock.hxx"
61#include "modifications.hxx"
62#include "node.hxx"
63#include "nodemap.hxx"
64#include "parsemanager.hxx"
65#include "partial.hxx"
66#include "rootaccess.hxx"
67#include "writemodfile.hxx"
68#include "xcdparser.hxx"
69#include "xcuparser.hxx"
70#include "xcsparser.hxx"
71
72#if ENABLE_DCONF
73#include "dconf.hxx"
74#endif
75
76#if defined(_WIN32)
77#include "winreg.hxx"
78#endif
79
80namespace configmgr {
81
82namespace {
83
84struct UnresolvedVectorItem {
85 OUString name;
87
88 UnresolvedVectorItem(
89 OUString theName,
91 name(std::move(theName)), manager(std::move(theManager)) {}
92};
93
94typedef std::vector< UnresolvedVectorItem > UnresolvedVector;
95
96void parseXcsFile(
97 OUString const & url, int layer, Data & data, Partial const * partial,
98 Modifications * modifications, Additions * additions)
99{
100 assert(partial == nullptr && modifications == nullptr && additions == nullptr);
101 (void) partial; (void) modifications; (void) additions;
103 new ParseManager(url, new XcsParser(layer, data)))->parse(nullptr);
104 assert(ok);
105 (void) ok; // avoid warnings
106}
107
108void parseXcuFile(
109 OUString const & url, int layer, Data & data, Partial const * partial,
110 Modifications * modifications, Additions * additions)
111{
113 new ParseManager(
114 url,
115 new XcuParser(layer, data, partial, modifications, additions)))->
116 parse(nullptr);
117 assert(ok);
118 (void) ok; // avoid warnings
119}
120
121OUString expand(OUString const & str) {
122 OUString s(str);
123 rtl::Bootstrap::expandMacros(s); //TODO: detect failure
124 return s;
125}
126
127bool canRemoveFromLayer(int layer, rtl::Reference< Node > const & node) {
128 assert(node.is());
129 if (node->getLayer() > layer && node->getLayer() < Data::NO_LAYER) {
130 return false;
131 }
132 switch (node->kind()) {
134 case Node::KIND_GROUP:
135 for (auto const& member : node->getMembers())
136 {
137 if (!canRemoveFromLayer(layer, member.second)) {
138 return false;
139 }
140 }
141 return true;
142 case Node::KIND_SET:
143 return node->getMembers().empty();
144 default: // Node::KIND_PROPERTY, Node::KIND_LOCALIZED_VALUE
145 return true;
146 }
147}
148
149}
150
151class Components::WriteThread: public salhelper::Thread {
152public:
154 rtl::Reference< WriteThread > * reference, Components & components,
155 OUString url, Data const & data);
156
157 void flush() { delay_.set(); }
158
159private:
160 virtual ~WriteThread() override {}
161
162 virtual void execute() override;
163
166 OUString url_;
167 Data const & data_;
168 osl::Condition delay_;
169 std::shared_ptr<osl::Mutex> lock_;
170};
171
173 rtl::Reference< WriteThread > * reference, Components & components,
174 OUString url, Data const & data):
175 Thread("configmgrWriter"), reference_(reference), components_(components),
176 url_(std::move(url)), data_(data),
177 lock_( lock() )
178{
179 assert(reference != nullptr);
180}
181
183 delay_.wait(std::chrono::seconds(1)); // must not throw; result_error is harmless and ignored
184 osl::MutexGuard g(*lock_); // must not throw
185 try {
186 try {
187 writeModFile(components_, url_, data_);
188 } catch (css::uno::RuntimeException &) {
189 // Ignore write errors, instead of aborting:
190 TOOLS_WARN_EXCEPTION("configmgr", "error writing modifications");
191 }
192 } catch (...) {
193 reference_->clear();
194 throw;
195 }
196 reference_->clear();
197}
198
200 css::uno::Reference< css::uno::XComponentContext > const & context)
201{
202 assert(context.is());
203 static Components singleton(context);
204 return singleton;
205}
206
207bool Components::allLocales(std::u16string_view locale) {
208 return locale == u"*";
209}
210
212 OUString const & pathRepresentation,
213 OUString * canonicRepresentation, std::vector<OUString> * path, int * finalizedLayer)
214 const
215{
217 pathRepresentation, canonicRepresentation, path, finalizedLayer);
218}
219
220rtl::Reference< Node > Components::getTemplate(OUString const & fullName) const
221{
222 return data_.getTemplate(Data::NO_LAYER, fullName);
223}
224
226 roots_.insert(access.get());
227}
228
230 roots_.erase(access);
231}
232
234 Modifications const & modifications,
235 rtl::Reference< RootAccess > const & exclude, Broadcaster * broadcaster)
236{
237 //TODO: Iterate only over roots w/ listeners:
238 for (auto const& elemRoot : roots_)
239 {
241 if (elemRoot->acquireCounting() > 1) {
242 root.set(elemRoot); // must not throw
243 }
244 elemRoot->releaseNondeleting();
245 if (root.is()) {
246 if (root != exclude) {
247 std::vector<OUString> path(root->getAbsolutePath());
248 Modifications::Node const * mods = &modifications.getRoot();
249 for (auto const& pathElem : path)
250 {
251 Modifications::Node::Children::const_iterator k(
252 mods->children.find(pathElem));
253 if (k == mods->children.end()) {
254 mods = nullptr;
255 break;
256 }
257 mods = &k->second;
258 }
259 //TODO: If the complete tree of which root is a part is deleted,
260 // or replaced, mods will be null, but some of the listeners
261 // from within root should probably fire nonetheless:
262 if (mods != nullptr) {
263 root->initBroadcaster(*mods, broadcaster);
264 }
265 }
266 }
267 }
268}
269
270void Components::addModification(std::vector<OUString> const & path) {
271 data_.modifications.add(path);
272}
273
275
277 return;
278
279 switch (modificationTarget_) {
280 case ModificationTarget::None:
281 break;
282 case ModificationTarget::File:
283 if (!writeThread_.is()) {
286 writeThread_->launch();
287 }
288 break;
289 case ModificationTarget::Dconf:
290#if ENABLE_DCONF
292#endif
293 break;
294 }
295}
296
299 {
300 osl::MutexGuard g(*lock_);
301 thread = writeThread_;
302 }
303 if (thread.is()) {
304 thread->flush();
305 thread->join();
306 }
307}
308
310 bool shared, OUString const & fileUri)
311{
312 int layer = getExtensionLayer(shared);
313 try {
314 parseXcsFile(fileUri, layer, data_, nullptr, nullptr, nullptr);
315 } catch (css::container::NoSuchElementException & e) {
316 throw css::uno::RuntimeException(
317 "insertExtensionXcsFile does not exist: " + e.Message);
318 }
319}
320
322 bool shared, OUString const & fileUri, Modifications * modifications)
323{
324 assert(modifications != nullptr);
325 int layer = getExtensionLayer(shared) + 1;
326 Additions * adds = data_.addExtensionXcuAdditions(fileUri, layer);
327 try {
328 parseXcuFile(fileUri, layer, data_, nullptr, modifications, adds);
329 } catch (css::container::NoSuchElementException & e) {
331 throw css::uno::RuntimeException(
332 "insertExtensionXcuFile does not exist: " + e.Message);
333 }
334}
335
337 OUString const & fileUri, Modifications * modifications)
338{
339 //TODO: Ideally, exactly the data coming from the specified xcu file would
340 // be removed. However, not enough information is recorded in the in-memory
341 // data structures to do so. So, as a workaround, all those set elements
342 // that were freshly added by the xcu and have afterwards been left
343 // unchanged or have only had their properties changed in the user layer are
344 // removed (and nothing else). The heuristic to determine
345 // whether a node has been left unchanged is to check the layer ID (as
346 // usual) and additionally to check that the node does not recursively
347 // contain any non-empty sets (multiple extension xcu files are merged into
348 // one layer, so checking layer ID alone is not enough). Since
349 // item->additions records all additions of set members in textual order,
350 // the latter check works well when iterating through item->additions in
351 // reverse order.
352 assert(modifications != nullptr);
355 if (!item.is())
356 return;
357
358 for (Additions::reverse_iterator i(item->additions.rbegin());
359 i != item->additions.rend(); ++i)
360 {
362 NodeMap const * map = &data_.getComponents();
364 for (auto const& j : *i)
365 {
366 parent = node;
367 node = map->findNode(Data::NO_LAYER, j);
368 if (!node.is()) {
369 break;
370 }
371 map = &node->getMembers();
372 }
373 if (node.is()) {
374 assert(parent.is());
375 if (parent->kind() == Node::KIND_SET) {
376 assert(
377 node->kind() == Node::KIND_GROUP ||
378 node->kind() == Node::KIND_SET);
379 if (canRemoveFromLayer(item->layer, node)) {
380 parent->getMembers().erase(i->back());
382 modifications->add(*i);
383 }
384 }
385 }
386 }
388}
389
391 OUString const & fileUri,
392 std::set< OUString > const & includedPaths,
393 std::set< OUString > const & excludedPaths,
394 Modifications * modifications)
395{
396 assert(modifications != nullptr);
398 try {
400 &parseXcuFile, fileUri, Data::NO_LAYER, &part, modifications, nullptr);
401 } catch (const css::container::NoSuchElementException &) {
403 "configmgr",
404 "error inserting non-existing \"" << fileUri << "\"");
405 }
406}
407
408css::beans::Optional< css::uno::Any > Components::getExternalValue(
409 std::u16string_view descriptor)
410{
411 size_t i = descriptor.find(' ');
412 if (i == 0 || i == std::u16string_view::npos) {
413 throw css::uno::RuntimeException(
414 OUString::Concat("bad external value descriptor ") + descriptor);
415 }
416 //TODO: Do not make calls with mutex locked:
417 OUString name(descriptor.substr(0, i));
418 ExternalServices::iterator j(externalServices_.find(name));
419 if (j == externalServices_.end()) {
420 css::uno::Reference< css::uno::XInterface > service;
421 try {
422 service = context_->getServiceManager()->createInstanceWithContext(
423 name, context_);
424 } catch (const css::uno::RuntimeException &) {
425 // Assuming these exceptions are real errors:
426 throw;
427 } catch (const css::uno::Exception &) {
428 // Assuming these exceptions indicate that the service is not
429 // installed:
431 "configmgr",
432 "createInstance(" << name << ") failed");
433 }
434 css::uno::Reference< css::beans::XPropertySet > propset;
435 if (service.is()) {
436 propset.set( service, css::uno::UNO_QUERY_THROW);
437 }
438 j = externalServices_.emplace(name, propset).first;
439 }
440 css::beans::Optional< css::uno::Any > value;
441 if (j->second.is()) {
442 try {
443 if (!(j->second->getPropertyValue(OUString(descriptor.substr(i + 1))) >>=
444 value))
445 {
446 throw css::uno::RuntimeException(
447 OUString::Concat("cannot obtain external value through ") + descriptor);
448 }
449 } catch (css::beans::UnknownPropertyException & e) {
450 throw css::uno::RuntimeException(
451 "unknown external value descriptor ID: " + e.Message);
452 } catch (css::lang::WrappedTargetException & e) {
453 css::uno::Any anyEx = cppu::getCaughtException();
454 throw css::lang::WrappedTargetRuntimeException(
455 "cannot obtain external value: " + e.Message,
456 nullptr, anyEx );
457 }
458 }
459 return value;
460}
461
463 css::uno::Reference< css::uno::XComponentContext > const & context):
466{
467 assert(context.is());
468 lock_ = lock();
469 OUString conf(expand("${CONFIGURATION_LAYERS}"));
470 int layer = 0;
471 for (sal_Int32 i = 0;;) {
472 while (i != conf.getLength() && conf[i] == ' ') {
473 ++i;
474 }
475 if (i == conf.getLength()) {
476 break;
477 }
478 if (modificationTarget_ != ModificationTarget::None) {
479 throw css::uno::RuntimeException(
480 "CONFIGURATION_LAYERS: modification target layer followed by"
481 " further layers");
482 }
483 sal_Int32 c = i;
484 for (;; ++c) {
485 if (c == conf.getLength() || conf[c] == ' ') {
486 throw css::uno::RuntimeException(
487 "CONFIGURATION_LAYERS: missing ':' in \"" + conf + "\"");
488 }
489 if (conf[c] == ':') {
490 break;
491 }
492 }
493 sal_Int32 n = conf.indexOf(' ', c + 1);
494 if (n == -1) {
495 n = conf.getLength();
496 }
497 OUString type(conf.copy(i, c - i));
498 OUString url(conf.copy(c + 1, n - c - 1));
499 if (type == "xcsxcu") {
500 sal_uInt32 nStartTime = osl_getGlobalTimer();
501 parseXcsXcuLayer(layer, url);
502 SAL_INFO("configmgr", "parseXcsXcuLayer() took " << (osl_getGlobalTimer() - nStartTime) << " ms");
503 layer += 2; //TODO: overflow
504 } else if (type == "bundledext") {
505 parseXcsXcuIniLayer(layer, url, false);
506 layer += 2; //TODO: overflow
507 } else if (type == "sharedext") {
508 if (sharedExtensionLayer_ != -1) {
509 throw css::uno::RuntimeException(
510 "CONFIGURATION_LAYERS: multiple \"sharedext\" layers");
511 }
512 sharedExtensionLayer_ = layer;
513 parseXcsXcuIniLayer(layer, url, true);
514 layer += 2; //TODO: overflow
515 } else if (type == "userext") {
516 if (userExtensionLayer_ != -1) {
517 throw css::uno::RuntimeException(
518 "CONFIGURATION_LAYERS: multiple \"userext\" layers");
519 }
520 userExtensionLayer_ = layer;
521 parseXcsXcuIniLayer(layer, url, true);
522 layer += 2; //TODO: overflow
523 } else if (type == "res") {
524 sal_uInt32 nStartTime = osl_getGlobalTimer();
525 parseResLayer(layer, url);
526 SAL_INFO("configmgr", "parseResLayer() took " << (osl_getGlobalTimer() - nStartTime) << " ms");
527 ++layer; //TODO: overflow
528#if ENABLE_DCONF
529 } else if (type == "dconf") {
530 if (url == "!") {
531 modificationTarget_ = ModificationTarget::Dconf;
533 } else if (url == "*") {
534 dconf::readLayer(data_, layer);
535 } else {
536 throw css::uno::RuntimeException(
537 "CONFIGURATION_LAYERS: unknown \"dconf\" kind \"" + url
538 + "\"");
539 }
540 ++layer; //TODO: overflow
541#endif
542#if defined(_WIN32)
543 } else if (type == "winreg") {
545 if (url == "LOCAL_MACHINE" || url.isEmpty()/*backwards comp.*/) {
547 } else if (url == "CURRENT_USER") {
549 } else {
550 throw css::uno::RuntimeException(
551 "CONFIGURATION_LAYERS: unknown \"winreg\" kind \"" + url
552 + "\"");
553 }
554 OUString aTempFileURL;
555 if (dumpWindowsRegistry(&aTempFileURL, eType)) {
556 parseFileLeniently(&parseXcuFile, aTempFileURL, layer, nullptr, nullptr, nullptr);
557 if (!getenv("SAL_CONFIG_WINREG_RETAIN_TMP"))
558 osl::File::remove(aTempFileURL);
559 }
560 ++layer; //TODO: overflow
561#endif
562 } else if (type == "user") {
563 bool write;
564 if (url.startsWith("!", &url)) {
565 write = true;
566 } else if (url.startsWith("*", &url)) {
567 write = false;
568 } else {
569 write = true; // for backwards compatibility
570 }
571 if (url.isEmpty()) {
572 throw css::uno::RuntimeException(
573 "CONFIGURATION_LAYERS: empty \"user\" URL");
574 }
575 bool ignore = false;
576#if ENABLE_DCONF
577 if (write) {
578 OUString token(
579 expand("${SYSUSERCONFIG}/libreoffice/dconfwrite"));
580 osl::DirectoryItem it;
581 osl::FileBase::RC e = osl::DirectoryItem::get(token, it);
582 ignore = e == osl::FileBase::E_None;
583 SAL_INFO(
584 "configmgr",
585 "dconf write (<" << token << "> " << +e << "): "
586 << int(ignore));
587 if (ignore) {
588 modificationTarget_ = ModificationTarget::Dconf;
589 }
590 }
591#endif
592 if (!ignore) {
593 if (write) {
594 modificationTarget_ = ModificationTarget::File;
596 }
597 parseModificationLayer(write ? Data::NO_LAYER : layer, url);
598 }
599 ++layer; //TODO: overflow
600 } else {
601 throw css::uno::RuntimeException(
602 "CONFIGURATION_LAYERS: unknown layer type \"" + type + "\"");
603 }
604 i = n;
605 }
606}
607
609{
610 // get flag if _exit was already called which is a sign to not secure user config.
611 // this is used for win only currently where calling _exit() unfortunately still
612 // calls destructors (what is not wanted). May be needed for other systems, too
613 // (unknown yet) but can do no harm
614 const bool bExitWasCalled(comphelper::BackupFileHelper::getExitWasCalled());
615
616#ifndef _WIN32
617 // we can add a SAL_WARN here for other systems where the destructor gets called after
618 // an _exit() call. Still safe - the getExitWasCalled() is used, but a hint that _exit
619 // behaves different on a system
620 SAL_WARN_IF(bExitWasCalled, "configmgr", "Components::~Components() called after _exit() call");
621#endif
622
623 if (bExitWasCalled)
624 {
625 // do not write, re-join threads
626 osl::MutexGuard g(*lock_);
627
628 if (writeThread_.is())
629 {
630 writeThread_->join();
631 }
632 }
633 else
634 {
635 // write changes
637 }
638
639 for (auto const& rootElem : roots_)
640 {
641 rootElem->setAlive(false);
642 }
643}
644
646 FileParser * parseFile, OUString const & url, int layer,
647 Partial const * partial, Modifications * modifications,
648 Additions * additions)
649{
650 assert(parseFile != nullptr);
651 try {
652 (*parseFile)(url, layer, data_, partial, modifications, additions);
653 } catch (const css::container::NoSuchElementException &) {
654 throw;
655 } catch (const css::uno::Exception &) { //TODO: more specific exception catching
656 // Ignore invalid XML files, instead of completely preventing OOo from
657 // starting:
659 "configmgr",
660 "error reading \"" << url << "\"");
661 }
662}
663
665 int layer, OUString const & extension, FileParser * parseFile,
666 OUString const & url, bool recursive)
667{
668 osl::Directory dir(url);
669 switch (dir.open()) {
670 case osl::FileBase::E_None:
671 break;
672 case osl::FileBase::E_NOENT:
673 if (!recursive) {
674 return;
675 }
676 [[fallthrough]];
677 default:
678 throw css::uno::RuntimeException(
679 "cannot open directory " + url);
680 }
681 for (;;) {
682 osl::DirectoryItem i;
683 osl::FileBase::RC rc = dir.getNextItem(i, SAL_MAX_UINT32);
684 if (rc == osl::FileBase::E_NOENT) {
685 break;
686 }
687 if (rc != osl::FileBase::E_None) {
688 throw css::uno::RuntimeException(
689 "cannot iterate directory " + url);
690 }
691 osl::FileStatus stat(
692 osl_FileStatus_Mask_Type | osl_FileStatus_Mask_FileName |
693 osl_FileStatus_Mask_FileURL);
694 if (i.getFileStatus(stat) != osl::FileBase::E_None) {
695 throw css::uno::RuntimeException(
696 "cannot stat in directory " + url);
697 }
698 if (stat.getFileType() == osl::FileStatus::Directory) { //TODO: symlinks
699 parseFiles(layer, extension, parseFile, stat.getFileURL(), true);
700 } else {
701 OUString file(stat.getFileName());
702 if (file.endsWith(extension)) {
703 try {
705 parseFile, stat.getFileURL(), layer, nullptr, nullptr, nullptr);
706 } catch (css::container::NoSuchElementException & e) {
707 if (stat.getFileType() == osl::FileStatus::Link) {
708 SAL_WARN("configmgr", "dangling link <" << stat.getFileURL() << ">");
709 continue;
710 }
711 throw css::uno::RuntimeException(
712 "stat'ed file does not exist: " + e.Message);
713 }
714 }
715 }
716 }
717}
718
720 int layer, FileParser * parseFile, std::u16string_view urls,
721 bool recordAdditions)
722{
723 for (sal_Int32 i = 0;;) {
724 OUString url(o3tl::getToken(urls, 0, ' ', i));
725 if (!url.isEmpty()) {
726 Additions * adds = nullptr;
727 if (recordAdditions) {
728 adds = data_.addExtensionXcuAdditions(url, layer);
729 }
730 try {
731 parseFileLeniently(parseFile, url, layer, nullptr, nullptr, adds);
732 } catch (const css::container::NoSuchElementException &) {
733 TOOLS_WARN_EXCEPTION("configmgr", "file does not exist");
734 if (adds != nullptr) {
736 }
737 }
738 }
739 if (i == -1) {
740 break;
741 }
742 }
743}
744
745void Components::parseXcdFiles(int layer, OUString const & url) {
746 osl::Directory dir(url);
747 switch (dir.open()) {
748 case osl::FileBase::E_None:
749 break;
750 case osl::FileBase::E_NOENT:
751 return;
752 default:
753 throw css::uno::RuntimeException(
754 "cannot open directory " + url);
755 }
756 UnresolvedVector unres;
757 std::set< OUString > existingDeps;
758 std::set< OUString > processedDeps;
759 for (;;) {
760 osl::DirectoryItem i;
761 osl::FileBase::RC rc = dir.getNextItem(i, SAL_MAX_UINT32);
762 if (rc == osl::FileBase::E_NOENT) {
763 break;
764 }
765 if (rc != osl::FileBase::E_None) {
766 throw css::uno::RuntimeException(
767 "cannot iterate directory " + url);
768 }
769 osl::FileStatus stat(
770 osl_FileStatus_Mask_Type | osl_FileStatus_Mask_FileName |
771 osl_FileStatus_Mask_FileURL);
772 if (i.getFileStatus(stat) != osl::FileBase::E_None) {
773 throw css::uno::RuntimeException(
774 "cannot stat in directory " + url);
775 }
776 if (stat.getFileType() != osl::FileStatus::Directory) { //TODO: symlinks
777 OUString file(stat.getFileName());
778 OUString name;
779 if (file.endsWith(".xcd", &name)) {
780 existingDeps.insert(name);
782 try {
783 manager = new ParseManager(
784 stat.getFileURL(),
785 new XcdParser(layer, processedDeps, data_));
786 } catch (css::container::NoSuchElementException & e) {
787 if (stat.getFileType() == osl::FileStatus::Link) {
788 SAL_WARN("configmgr", "dangling link <" << stat.getFileURL() << ">");
789 continue;
790 }
791 throw css::uno::RuntimeException(
792 "stat'ed file does not exist: " + e.Message);
793 }
794 if (manager->parse(nullptr)) {
795 processedDeps.insert(name);
796 } else {
797 unres.emplace_back(name, manager);
798 }
799 }
800 }
801 }
802 while (!unres.empty()) {
803 bool resolved = false;
804 for (UnresolvedVector::iterator i(unres.begin()); i != unres.end();) {
805 if (i->manager->parse(&existingDeps)) {
806 processedDeps.insert(i->name);
807 i = unres.erase(i);
808 resolved = true;
809 } else {
810 ++i;
811 }
812 }
813 if (!resolved) {
814 throw css::uno::RuntimeException(
815 "xcd: unresolved dependencies in " + url);
816 }
817 }
818}
819
820void Components::parseXcsXcuLayer(int layer, OUString const & url) {
821 parseXcdFiles(layer, url);
822 parseFiles(layer, ".xcs", &parseXcsFile, url + "/schema", false);
823 parseFiles(layer + 1, ".xcu", &parseXcuFile, url + "/data", false);
824}
825
827 int layer, OUString const & url, bool recordAdditions)
828{
829 // Check if ini file exists (otherwise .override would still read global
830 // SCHEMA/DATA variables, which could interfere with unrelated environment
831 // variables):
832 if (rtl::Bootstrap(url).getHandle() == nullptr) return;
833
834 OUStringBuffer prefix("${.override:");
835 for (sal_Int32 i = 0; i != url.getLength(); ++i) {
836 sal_Unicode c = url[i];
837 switch (c) {
838 case '$':
839 case ':':
840 case '\\':
841 prefix.append('\\');
842 [[fallthrough]];
843 default:
844 prefix.append(c);
845 }
846 }
847 prefix.append(':');
848 OUString urls(prefix + "SCHEMA}");
849 rtl::Bootstrap::expandMacros(urls);
850 if (!urls.isEmpty()) {
851 parseFileList(layer, &parseXcsFile, urls, false);
852 }
853 urls = prefix + "DATA}";
854 rtl::Bootstrap::expandMacros(urls);
855 if (!urls.isEmpty()) {
856 parseFileList(layer + 1, &parseXcuFile, urls, recordAdditions);
857 }
858}
859
860void Components::parseResLayer(int layer, std::u16string_view url) {
861 OUString resUrl(OUString::Concat(url) + "/res");
862 parseXcdFiles(layer, resUrl);
863 parseFiles(layer, ".xcu", &parseXcuFile, resUrl, false);
864}
865
866void Components::parseModificationLayer(int layer, OUString const & url) {
867 try {
868 parseFileLeniently(&parseXcuFile, url, layer, nullptr, nullptr, nullptr);
869 } catch (css::container::NoSuchElementException &) {
870 SAL_INFO(
871 "configmgr", "user registrymodifications.xcu does not (yet) exist");
872 // Migrate old user layer data (can be removed once migration is no
873 // longer relevant, probably OOo 4; also see hack for xsi namespace in
874 // xmlreader::XmlReader::registerNamespaceIri):
876 layer, ".xcu", &parseXcuFile,
877 expand(
878 "${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER "/" SAL_CONFIGFILE("bootstrap")
879 ":UserInstallation}/user/registry/data"),
880 false);
881 }
882}
883
884int Components::getExtensionLayer(bool shared) const {
885 int layer = shared ? sharedExtensionLayer_ : userExtensionLayer_;
886 if (layer == -1) {
887 throw css::uno::RuntimeException(
888 "insert extension xcs/xcu file into undefined layer");
889 }
890 return layer;
891}
892
893}
894
895/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
rtl::Reference< WriteThread > * reference_
Definition: components.cxx:164
virtual void execute() override
Definition: components.cxx:182
WriteThread(rtl::Reference< WriteThread > *reference, Components &components, OUString url, Data const &data)
Definition: components.cxx:172
std::shared_ptr< osl::Mutex > lock_
Definition: components.cxx:169
void parseFileList(int layer, FileParser *parseFile, std::u16string_view urls, bool recordAdditions)
Definition: components.cxx:719
void insertModificationXcuFile(OUString const &fileUri, std::set< OUString > const &includedPaths, std::set< OUString > const &excludedPaths, Modifications *modifications)
Definition: components.cxx:390
void removeRootAccess(RootAccess *access)
Definition: components.cxx:229
void initGlobalBroadcaster(Modifications const &modifications, rtl::Reference< RootAccess > const &exclude, Broadcaster *broadcaster)
Definition: components.cxx:233
Components(const Components &)=delete
static bool allLocales(std::u16string_view locale)
Definition: components.cxx:207
void removeExtensionXcuFile(OUString const &fileUri, Modifications *modifications)
Definition: components.cxx:336
void addModification(std::vector< OUString > const &path)
Definition: components.cxx:270
void parseXcdFiles(int layer, OUString const &url)
Definition: components.cxx:745
void parseResLayer(int layer, std::u16string_view url)
Definition: components.cxx:860
rtl::Reference< Node > resolvePathRepresentation(OUString const &pathRepresentation, OUString *canonicRepresentation, std::vector< OUString > *path, int *finalizedLayer) const
Definition: components.cxx:211
OUString modificationFileUrl_
Definition: components.hxx:160
std::shared_ptr< osl::Mutex > lock_
Definition: components.hxx:161
void insertExtensionXcsFile(bool shared, OUString const &fileUri)
Definition: components.cxx:309
void parseModificationLayer(int layer, OUString const &url)
Definition: components.cxx:866
css::uno::Reference< css::uno::XComponentContext > context_
Definition: components.hxx:152
int getExtensionLayer(bool shared) const
Definition: components.cxx:884
o3tl::sorted_vector< RootAccess * > roots_
Definition: components.hxx:154
void parseFileLeniently(FileParser *parseFile, OUString const &url, int layer, Partial const *partial, Modifications *modifications, Additions *additions)
Definition: components.cxx:645
rtl::Reference< WriteThread > writeThread_
Definition: components.hxx:156
void addRootAccess(rtl::Reference< RootAccess > const &access)
Definition: components.cxx:225
rtl::Reference< Node > getTemplate(OUString const &fullName) const
Definition: components.cxx:220
void parseXcsXcuIniLayer(int layer, OUString const &url, bool recordAdditions)
Definition: components.cxx:826
ModificationTarget modificationTarget_
Definition: components.hxx:159
void insertExtensionXcuFile(bool shared, OUString const &fileUri, Modifications *modifications)
Definition: components.cxx:321
void parseFiles(int layer, OUString const &extension, FileParser *parseFile, OUString const &url, bool recursive)
Definition: components.cxx:664
ExternalServices externalServices_
Definition: components.hxx:155
void parseXcsXcuLayer(int layer, OUString const &url)
Definition: components.cxx:820
css::beans::Optional< css::uno::Any > getExternalValue(std::u16string_view descriptor)
Definition: components.cxx:408
static Components & getSingleton(css::uno::Reference< css::uno::XComponentContext > const &context)
Definition: components.cxx:199
void add(std::vector< OUString > const &path)
void remove(std::vector< OUString > const &path)
Node const & getRoot() const
@ KIND_LOCALIZED_PROPERTY
Definition: node.hxx:35
Any value
rtl::Reference< ParseManager > manager
Definition: components.cxx:86
OUString name
Definition: components.cxx:85
#define SAL_CONFIGFILE(name)
std::shared_ptr< osl::Mutex > lock_
OUString url_
#define TOOLS_WARN_EXCEPTION(area, stream)
float u
DocumentType eType
sal_Int64 n
#define SAL_WARN_IF(condition, area, stream)
#define SAL_WARN(area, stream)
#define SAL_INFO(area, stream)
std::set< OUString > includedPaths
std::set< OUString > excludedPaths
ignore
void readLayer(Data &data, int layer)
Definition: dconf.cxx:1556
void writeModifications(Components &components, Data &data)
Definition: dconf.cxx:1567
@ LOCAL_MACHINE
Definition: winreg.hxx:15
@ CURRENT_USER
Definition: winreg.hxx:15
bool dumpWindowsRegistry(OUString *pFileURL, WinRegType eType)
Definition: winreg.cxx:289
std::shared_ptr< osl::Mutex > const & lock()
Definition: lock.cxx:28
std::vector< std::vector< OUString > > Additions
Definition: additions.hxx:31
void writeModFile(Components &components, OUString const &url, Data const &data)
Any SAL_CALL getCaughtException()
int i
std::basic_string_view< charT, traits > getToken(std::basic_string_view< charT, traits > sv, charT delimiter, std::size_t &position)
None
bool parse(OUString const &uri, SourceProviderScannerData *data)
std::map< OUString, rtl::Reference< Entity > > map
rtl::Reference< ExtensionXcu > removeExtensionXcuAdditions(OUString const &url)
Definition: data.cxx:313
Modifications modifications
Definition: data.hxx:51
rtl::Reference< Node > resolvePathRepresentation(OUString const &pathRepresentation, OUString *canonicRepresentation, std::vector< OUString > *path, int *finalizedLayer) const
Definition: data.cxx:181
NodeMap & getComponents() const
Definition: data.cxx:293
Additions * addExtensionXcuAdditions(OUString const &url, int layer)
Definition: data.cxx:297
rtl::Reference< Node > getTemplate(int layer, OUString const &fullName) const
Definition: data.cxx:287
sal_uInt16 sal_Unicode
#define SAL_MAX_UINT32
ResultType type