Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 :
21 : #include "dp_misc.h"
22 : #include "dp_backend.h"
23 : #include "dp_ucb.h"
24 : #include "dp_interact.h"
25 : #include <rtl/string.hxx>
26 : #include <osl/file.hxx>
27 : #include <ucbhelper/content.hxx>
28 : #include <comphelper/servicedecl.hxx>
29 : #include <svl/inettype.hxx>
30 : #include <cppuhelper/implbase1.hxx>
31 : #include "dp_executablebackenddb.hxx"
32 :
33 : using namespace ::com::sun::star;
34 : using namespace ::com::sun::star::uno;
35 : using namespace ::com::sun::star::ucb;
36 : using namespace dp_misc;
37 :
38 : namespace dp_registry {
39 : namespace backend {
40 : namespace executable {
41 : namespace {
42 :
43 392 : class BackendImpl : public ::dp_registry::backend::PackageRegistryBackend
44 : {
45 0 : class ExecutablePackageImpl : public ::dp_registry::backend::Package
46 : {
47 : BackendImpl * getMyBackend() const;
48 :
49 : // Package
50 : virtual beans::Optional< beans::Ambiguous<sal_Bool> > isRegistered_(
51 : ::osl::ResettableMutexGuard & guard,
52 : ::rtl::Reference<dp_misc::AbortChannel> const & abortChannel,
53 : Reference<XCommandEnvironment> const & xCmdEnv ) SAL_OVERRIDE;
54 : virtual void processPackage_(
55 : ::osl::ResettableMutexGuard & guard,
56 : bool registerPackage,
57 : bool startup,
58 : ::rtl::Reference<dp_misc::AbortChannel> const & abortChannel,
59 : Reference<XCommandEnvironment> const & xCmdEnv ) SAL_OVERRIDE;
60 :
61 : bool getFileAttributes(sal_uInt64& out_Attributes);
62 : bool isUrlTargetInExtension();
63 :
64 : public:
65 0 : inline ExecutablePackageImpl(
66 : ::rtl::Reference<PackageRegistryBackend> const & myBackend,
67 : OUString const & url, OUString const & name,
68 : Reference<deployment::XPackageTypeInfo> const & xPackageType,
69 : bool bRemoved, OUString const & identifier)
70 : : Package( myBackend, url, name, name /* display-name */,
71 0 : xPackageType, bRemoved, identifier)
72 0 : {}
73 : };
74 : friend class ExecutablePackageImpl;
75 :
76 : typedef std::unordered_map< OUString, Reference<XInterface>,
77 : OUStringHash > t_string2object;
78 :
79 : // PackageRegistryBackend
80 : virtual Reference<deployment::XPackage> bindPackage_(
81 : OUString const & url, OUString const & mediaType, bool bRemoved,
82 : OUString const & identifier, Reference<XCommandEnvironment> const & xCmdEnv ) SAL_OVERRIDE;
83 :
84 : void addDataToDb(OUString const & url);
85 : bool hasActiveEntry(OUString const & url);
86 : void revokeEntryFromDb(OUString const & url);
87 :
88 : Reference<deployment::XPackageTypeInfo> m_xExecutableTypeInfo;
89 : std::unique_ptr<ExecutableBackendDb> m_backendDb;
90 : public:
91 : BackendImpl( Sequence<Any> const & args,
92 : Reference<XComponentContext> const & xComponentContext );
93 :
94 : // XPackageRegistry
95 : virtual Sequence< Reference<deployment::XPackageTypeInfo> > SAL_CALL
96 : getSupportedPackageTypes() throw (RuntimeException, std::exception) SAL_OVERRIDE;
97 : virtual void SAL_CALL packageRemoved(OUString const & url, OUString const & mediaType)
98 : throw (deployment::DeploymentException,
99 : uno::RuntimeException, std::exception) SAL_OVERRIDE;
100 :
101 : using PackageRegistryBackend::disposing;
102 : };
103 :
104 :
105 392 : BackendImpl::BackendImpl(
106 : Sequence<Any> const & args,
107 : Reference<XComponentContext> const & xComponentContext )
108 : : PackageRegistryBackend( args, xComponentContext ),
109 : m_xExecutableTypeInfo(new Package::TypeInfo(
110 : "application/vnd.sun.star.executable",
111 392 : "", "Executable", RID_IMG_COMPONENT ) )
112 : {
113 392 : if (!transientMode())
114 : {
115 392 : OUString dbFile = makeURL(getCachePath(), "backenddb.xml");
116 : m_backendDb.reset(
117 392 : new ExecutableBackendDb(getComponentContext(), dbFile));
118 : }
119 392 : }
120 :
121 0 : void BackendImpl::addDataToDb(OUString const & url)
122 : {
123 0 : if (m_backendDb.get())
124 0 : m_backendDb->addEntry(url);
125 0 : }
126 :
127 0 : void BackendImpl::revokeEntryFromDb(OUString const & url)
128 : {
129 0 : if (m_backendDb.get())
130 0 : m_backendDb->revokeEntry(url);
131 0 : }
132 :
133 0 : bool BackendImpl::hasActiveEntry(OUString const & url)
134 : {
135 0 : if (m_backendDb.get())
136 0 : return m_backendDb->hasActiveEntry(url);
137 0 : return false;
138 : }
139 :
140 :
141 : // XPackageRegistry
142 : Sequence< Reference<deployment::XPackageTypeInfo> >
143 392 : BackendImpl::getSupportedPackageTypes() throw (RuntimeException, std::exception)
144 : {
145 : return Sequence<Reference<deployment::XPackageTypeInfo> >(
146 392 : & m_xExecutableTypeInfo, 1);
147 : }
148 :
149 0 : void BackendImpl::packageRemoved(OUString const & url, OUString const & /*mediaType*/)
150 : throw (deployment::DeploymentException,
151 : uno::RuntimeException, std::exception)
152 : {
153 0 : if (m_backendDb.get())
154 0 : m_backendDb->removeEntry(url);
155 0 : }
156 :
157 : // PackageRegistryBackend
158 3 : Reference<deployment::XPackage> BackendImpl::bindPackage_(
159 : OUString const & url, OUString const & mediaType, bool bRemoved,
160 : OUString const & identifier, Reference<XCommandEnvironment> const & xCmdEnv )
161 : {
162 3 : if (mediaType.isEmpty())
163 : {
164 : throw lang::IllegalArgumentException(
165 6 : StrCannotDetectMediaType::get() + url,
166 9 : static_cast<OWeakObject *>(this), static_cast<sal_Int16>(-1) );
167 : }
168 :
169 0 : OUString type, subType;
170 0 : INetContentTypeParameterList params;
171 0 : if (INetContentTypes::parse( mediaType, type, subType, ¶ms ))
172 : {
173 0 : if (type.equalsIgnoreAsciiCase("application"))
174 : {
175 0 : OUString name;
176 0 : if (!bRemoved)
177 : {
178 : ::ucbhelper::Content ucbContent(
179 0 : url, xCmdEnv, getComponentContext() );
180 0 : name = StrTitle::getTitle( ucbContent );
181 : }
182 0 : if (subType.equalsIgnoreAsciiCase("vnd.sun.star.executable"))
183 : {
184 : return new BackendImpl::ExecutablePackageImpl(
185 : this, url, name, m_xExecutableTypeInfo, bRemoved,
186 0 : identifier);
187 0 : }
188 : }
189 : }
190 0 : return Reference<deployment::XPackage>();
191 : }
192 :
193 :
194 :
195 : // Package
196 0 : BackendImpl * BackendImpl::ExecutablePackageImpl::getMyBackend() const
197 : {
198 0 : BackendImpl * pBackend = static_cast<BackendImpl *>(m_myBackend.get());
199 0 : if (NULL == pBackend)
200 : {
201 : //May throw a DisposedException
202 0 : check();
203 : //We should never get here...
204 : throw RuntimeException( "Failed to get the BackendImpl",
205 0 : static_cast<OWeakObject*>(const_cast<ExecutablePackageImpl *>(this)));
206 : }
207 0 : return pBackend;
208 : }
209 :
210 : beans::Optional< beans::Ambiguous<sal_Bool> >
211 0 : BackendImpl::ExecutablePackageImpl::isRegistered_(
212 : ::osl::ResettableMutexGuard &,
213 : ::rtl::Reference<dp_misc::AbortChannel> const &,
214 : Reference<XCommandEnvironment> const & )
215 : {
216 0 : bool registered = getMyBackend()->hasActiveEntry(getURL());
217 : return beans::Optional< beans::Ambiguous<sal_Bool> >(
218 : sal_True /* IsPresent */,
219 : beans::Ambiguous<sal_Bool>(
220 0 : registered, sal_False /* IsAmbiguous */ ) );
221 : }
222 :
223 0 : void BackendImpl::ExecutablePackageImpl::processPackage_(
224 : ::osl::ResettableMutexGuard &,
225 : bool doRegisterPackage,
226 : bool /*startup*/,
227 : ::rtl::Reference<dp_misc::AbortChannel> const & abortChannel,
228 : Reference<XCommandEnvironment> const & /*xCmdEnv*/ )
229 : {
230 0 : checkAborted(abortChannel);
231 0 : if (doRegisterPackage)
232 : {
233 0 : if (!isUrlTargetInExtension())
234 : {
235 : OSL_ASSERT(false);
236 0 : return;
237 : }
238 0 : sal_uInt64 attributes = 0;
239 : //Setting the executable attribute does not affect executables on Windows
240 0 : if (getFileAttributes(attributes))
241 : {
242 0 : if(getMyBackend()->m_context == "user")
243 0 : attributes |= osl_File_Attribute_OwnExe;
244 0 : else if (getMyBackend()->m_context == "shared")
245 : attributes |= (osl_File_Attribute_OwnExe | osl_File_Attribute_GrpExe
246 0 : | osl_File_Attribute_OthExe);
247 0 : else if (!(getMyBackend()->m_context == "bundled"))
248 : //Bundled extension are required to be in the properly
249 : //installed. That is an executable must have the right flags
250 : OSL_ASSERT(false);
251 :
252 : //This won't have affect on Windows
253 : osl::File::setAttributes(
254 0 : dp_misc::expandUnoRcUrl(m_url), attributes);
255 : }
256 0 : getMyBackend()->addDataToDb(getURL());
257 : }
258 : else
259 : {
260 0 : getMyBackend()->revokeEntryFromDb(getURL());
261 : }
262 : }
263 :
264 : //We currently cannot check if this XPackage represents a content of a particular extension
265 : //But we can check if we are within $UNO_USER_PACKAGES_CACHE etc.
266 : //Done for security reasons. For example an extension manifest could contain a path to
267 : //an executable outside the extension.
268 0 : bool BackendImpl::ExecutablePackageImpl::isUrlTargetInExtension()
269 : {
270 0 : bool bSuccess = false;
271 0 : OUString sExtensionDir;
272 0 : if(getMyBackend()->m_context == "user")
273 0 : sExtensionDir = dp_misc::expandUnoRcTerm("$UNO_USER_PACKAGES_CACHE");
274 0 : else if (getMyBackend()->m_context == "shared")
275 0 : sExtensionDir = dp_misc::expandUnoRcTerm("$UNO_SHARED_PACKAGES_CACHE");
276 0 : else if (getMyBackend()->m_context == "bundled")
277 0 : sExtensionDir = dp_misc::expandUnoRcTerm("$BUNDLED_EXTENSIONS");
278 : else
279 : OSL_ASSERT(false);
280 : //remove file ellipses
281 0 : if (osl::File::E_None == osl::File::getAbsoluteFileURL(OUString(), sExtensionDir, sExtensionDir))
282 : {
283 0 : OUString sFile;
284 0 : if (osl::File::E_None == osl::File::getAbsoluteFileURL(
285 0 : OUString(), dp_misc::expandUnoRcUrl(m_url), sFile))
286 : {
287 0 : if (sFile.match(sExtensionDir, 0))
288 0 : bSuccess = true;
289 0 : }
290 : }
291 0 : return bSuccess;
292 : }
293 :
294 0 : bool BackendImpl::ExecutablePackageImpl::getFileAttributes(sal_uInt64& out_Attributes)
295 : {
296 0 : bool bSuccess = false;
297 0 : const OUString url(dp_misc::expandUnoRcUrl(m_url));
298 0 : osl::DirectoryItem item;
299 0 : if (osl::FileBase::E_None == osl::DirectoryItem::get(url, item))
300 : {
301 0 : osl::FileStatus aStatus(osl_FileStatus_Mask_Attributes);
302 0 : if( osl::FileBase::E_None == item.getFileStatus(aStatus))
303 : {
304 0 : out_Attributes = aStatus.getAttributes();
305 0 : bSuccess = true;
306 0 : }
307 : }
308 0 : return bSuccess;
309 : }
310 :
311 :
312 :
313 : } // anon namespace
314 :
315 : namespace sdecl = comphelper::service_decl;
316 111 : sdecl::class_<BackendImpl, sdecl::with_args<true> > serviceBI;
317 111 : extern sdecl::ServiceDecl const serviceDecl(
318 : serviceBI,
319 : "com.sun.star.comp.deployment.executable.PackageRegistryBackend",
320 : BACKEND_SERVICE_NAME );
321 :
322 : } // namespace component
323 : } // namespace backend
324 333 : } // namespace dp_registry
325 :
326 :
327 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|