LibreOffice Module ucb (master)  1
gio_content.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 <utility>
23 
24 #include <string.h>
25 #include <sys/types.h>
26 #include <sal/macros.h>
27 #include <osl/time.h>
28 #include <sal/log.hxx>
29 
30 #include <com/sun/star/beans/IllegalTypeException.hpp>
31 #include <com/sun/star/beans/PropertyValue.hpp>
32 #include <com/sun/star/beans/PropertyAttribute.hpp>
33 #include <com/sun/star/beans/XPropertySetInfo.hpp>
34 #include <com/sun/star/io/IOException.hpp>
35 #include <com/sun/star/io/XActiveDataSink.hpp>
36 #include <com/sun/star/io/XOutputStream.hpp>
37 #include <com/sun/star/lang/IllegalAccessException.hpp>
38 #include <com/sun/star/lang/IllegalArgumentException.hpp>
39 #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
40 #include <com/sun/star/ucb/ContentInfoAttribute.hpp>
41 #include <com/sun/star/ucb/InsertCommandArgument.hpp>
42 #include <com/sun/star/ucb/InteractiveAugmentedIOException.hpp>
43 #include <com/sun/star/ucb/InteractiveNetworkGeneralException.hpp>
44 #include <com/sun/star/ucb/InteractiveNetworkResolveNameException.hpp>
45 #include <com/sun/star/ucb/NameClashException.hpp>
46 #include <com/sun/star/ucb/OpenMode.hpp>
47 #include <com/sun/star/ucb/XCommandInfo.hpp>
48 #include <com/sun/star/ucb/MissingInputStreamException.hpp>
49 #include <com/sun/star/ucb/UnsupportedCommandException.hpp>
50 #include <com/sun/star/ucb/UnsupportedDataSinkException.hpp>
51 #include <com/sun/star/ucb/UnsupportedOpenModeException.hpp>
52 #include <com/sun/star/ucb/XDynamicResultSet.hpp>
53 #include <com/sun/star/ucb/XContentCreator.hpp>
54 
56 #include <cppuhelper/exc_hlp.hxx>
61 #include <ucbhelper/macros.hxx>
62 #include <vcl/svapp.hxx>
63 
64 #include "gio_content.hxx"
65 #include "gio_provider.hxx"
66 #include "gio_resultset.hxx"
67 #include "gio_inputstream.hxx"
68 #include "gio_outputstream.hxx"
69 #include "gio_mount.hxx"
70 
71 namespace gio
72 {
73 
75  const css::uno::Reference< css::uno::XComponentContext >& rxContext,
76  ContentProvider* pProvider,
77  const css::uno::Reference< css::ucb::XContentIdentifier >& Identifier)
78  : ContentImplHelper( rxContext, pProvider, Identifier ),
79  m_pProvider( pProvider ), mpFile (nullptr), mpInfo( nullptr ), mbTransient(false)
80 {
81  SAL_INFO("ucb.ucp.gio", "New Content ('" << m_xIdentifier->getContentIdentifier() << "')");
82 }
83 
85  const css::uno::Reference< css::uno::XComponentContext >& rxContext,
86  ContentProvider* pProvider,
87  const css::uno::Reference< css::ucb::XContentIdentifier >& Identifier,
88  bool bIsFolder)
89  : ContentImplHelper( rxContext, pProvider, Identifier ),
90  m_pProvider( pProvider ), mpFile (nullptr), mpInfo( nullptr ), mbTransient(true)
91 {
92  SAL_INFO("ucb.ucp.gio", "Create Content ('" << m_xIdentifier->getContentIdentifier() << "')");
93  mpInfo = g_file_info_new();
94  g_file_info_set_file_type(mpInfo, bIsFolder ? G_FILE_TYPE_DIRECTORY : G_FILE_TYPE_REGULAR);
95 }
96 
98 {
99  if (mpInfo) g_object_unref(mpInfo);
100  if (mpFile) g_object_unref(mpFile);
101 }
102 
104 {
105  OUString sURL;
106  if (GFile* pFile = g_file_get_parent(getGFile()))
107  {
108  char* pPath = g_file_get_uri(pFile);
109  g_object_unref(pFile);
110  sURL = OUString::createFromAscii(pPath);
111  g_free(pPath);
112  }
113  return sURL;
114 }
115 
116 void SAL_CALL Content::abort( sal_Int32 /*CommandId*/ )
117 {
118  //TODO
119  //stick a map from each CommandId to a new GCancellable and propagate
120  //it throughout the g_file_* calls
121 }
122 
123 OUString SAL_CALL Content::getContentType()
124 {
125  return isFolder(css::uno::Reference< css::ucb::XCommandEnvironment >())
126  ? OUString( GIO_FOLDER_TYPE )
127  : OUString( GIO_FILE_TYPE );
128 }
129 
130 #define EXCEPT(aExcept) \
131 do { \
132  if (bThrow) throw aExcept;\
133  aRet <<= aExcept;\
134 } while(false)
135 
136 css::uno::Any convertToException(GError *pError, const css::uno::Reference< css::uno::XInterface >& rContext, bool bThrow)
137 {
138  css::uno::Any aRet;
139 
140  gint eCode = pError->code;
141  OUString sMessage(pError->message, strlen(pError->message), RTL_TEXTENCODING_UTF8);
142  g_error_free(pError);
143 
144  OUString sName;
145 
146  css::uno::Sequence< css::uno::Any > aArgs( 1 );
147  aArgs[ 0 ] <<= sName;
148 
149  switch (eCode)
150  {
151  case G_IO_ERROR_FAILED:
152  { css::io::IOException aExcept(sMessage, rContext);
153  EXCEPT(aExcept); }
154  break;
155  case G_IO_ERROR_NOT_MOUNTED:
156  { css::ucb::InteractiveAugmentedIOException aExcept(sMessage, rContext,
157  css::task::InteractionClassification_ERROR, css::ucb::IOErrorCode_NOT_EXISTING_PATH, aArgs);
158  EXCEPT(aExcept); }
159  break;
160  case G_IO_ERROR_NOT_FOUND:
161  { css::ucb::InteractiveAugmentedIOException aExcept(sMessage, rContext,
162  css::task::InteractionClassification_ERROR, css::ucb::IOErrorCode_NOT_EXISTING, aArgs);
163  EXCEPT(aExcept); }
164  break;
165  case G_IO_ERROR_EXISTS:
166  { css::ucb::NameClashException aExcept(sMessage, rContext,
167  css::task::InteractionClassification_ERROR, sName);
168  EXCEPT(aExcept); }
169  break;
170  case G_IO_ERROR_INVALID_ARGUMENT:
171  { css::lang::IllegalArgumentException aExcept(sMessage, rContext, -1 );
172  EXCEPT(aExcept); }
173  break;
174  case G_IO_ERROR_PERMISSION_DENIED:
175  { css::ucb::InteractiveAugmentedIOException aExcept(sMessage, rContext,
176  css::task::InteractionClassification_ERROR, css::ucb::IOErrorCode_ACCESS_DENIED, aArgs);
177  EXCEPT(aExcept); }
178  break;
179  case G_IO_ERROR_IS_DIRECTORY:
180  { css::ucb::InteractiveAugmentedIOException aExcept(sMessage, rContext,
181  css::task::InteractionClassification_ERROR, css::ucb::IOErrorCode_NO_FILE, aArgs);
182  EXCEPT(aExcept); }
183  break;
184  case G_IO_ERROR_NOT_REGULAR_FILE:
185  { css::ucb::InteractiveAugmentedIOException aExcept(sMessage, rContext,
186  css::task::InteractionClassification_ERROR, css::ucb::IOErrorCode_NO_FILE, aArgs);
187  EXCEPT(aExcept); }
188  break;
189  case G_IO_ERROR_NOT_DIRECTORY:
190  { css::ucb::InteractiveAugmentedIOException aExcept(sMessage, rContext,
191  css::task::InteractionClassification_ERROR, css::ucb::IOErrorCode_NO_DIRECTORY, aArgs);
192  EXCEPT(aExcept); }
193  break;
194  case G_IO_ERROR_FILENAME_TOO_LONG:
195  { css::ucb::InteractiveAugmentedIOException aExcept(sMessage, rContext,
196  css::task::InteractionClassification_ERROR, css::ucb::IOErrorCode_NAME_TOO_LONG, aArgs);
197  EXCEPT(aExcept); }
198  break;
199  case G_IO_ERROR_PENDING:
200  { css::ucb::InteractiveAugmentedIOException aExcept(sMessage, rContext,
201  css::task::InteractionClassification_ERROR, css::ucb::IOErrorCode_PENDING, aArgs);
202  EXCEPT(aExcept); }
203  break;
204  case G_IO_ERROR_CLOSED:
205  case G_IO_ERROR_CANCELLED:
206  case G_IO_ERROR_TOO_MANY_LINKS:
207  case G_IO_ERROR_WRONG_ETAG:
208  { css::ucb::InteractiveAugmentedIOException aExcept(sMessage, rContext,
209  css::task::InteractionClassification_ERROR, css::ucb::IOErrorCode_GENERAL, aArgs);
210  EXCEPT(aExcept); }
211  break;
212  case G_IO_ERROR_NOT_SUPPORTED:
213  case G_IO_ERROR_CANT_CREATE_BACKUP:
214  case G_IO_ERROR_WOULD_MERGE:
215  { css::ucb::InteractiveAugmentedIOException aExcept(sMessage, rContext,
216  css::task::InteractionClassification_ERROR, css::ucb::IOErrorCode_NOT_SUPPORTED, aArgs);
217  EXCEPT(aExcept); }
218  break;
219  case G_IO_ERROR_NO_SPACE:
220  { css::ucb::InteractiveAugmentedIOException aExcept(sMessage, rContext,
221  css::task::InteractionClassification_ERROR, css::ucb::IOErrorCode_OUT_OF_DISK_SPACE, aArgs);
222  EXCEPT(aExcept); }
223  break;
224  case G_IO_ERROR_INVALID_FILENAME:
225  { css::ucb::InteractiveAugmentedIOException aExcept(sMessage, rContext,
226  css::task::InteractionClassification_ERROR, css::ucb::IOErrorCode_INVALID_CHARACTER, aArgs);
227  EXCEPT(aExcept); }
228  break;
229  case G_IO_ERROR_READ_ONLY:
230  { css::ucb::InteractiveAugmentedIOException aExcept(sMessage, rContext,
231  css::task::InteractionClassification_ERROR, css::ucb::IOErrorCode_WRITE_PROTECTED, aArgs);
232  EXCEPT(aExcept); }
233  break;
234  case G_IO_ERROR_TIMED_OUT:
235  { css::ucb::InteractiveAugmentedIOException aExcept(sMessage, rContext,
236  css::task::InteractionClassification_ERROR, css::ucb::IOErrorCode_DEVICE_NOT_READY, aArgs);
237  EXCEPT(aExcept); }
238  break;
239  case G_IO_ERROR_WOULD_RECURSE:
240  { css::ucb::InteractiveAugmentedIOException aExcept(sMessage, rContext,
241  css::task::InteractionClassification_ERROR, css::ucb::IOErrorCode_RECURSIVE, aArgs);
242  EXCEPT(aExcept); }
243  break;
244  case G_IO_ERROR_BUSY:
245  case G_IO_ERROR_WOULD_BLOCK:
246  { css::ucb::InteractiveAugmentedIOException aExcept(sMessage, rContext,
247  css::task::InteractionClassification_ERROR, css::ucb::IOErrorCode_LOCKING_VIOLATION, aArgs);
248  EXCEPT(aExcept); }
249  break;
250  case G_IO_ERROR_HOST_NOT_FOUND:
251  { css::ucb::InteractiveNetworkResolveNameException aExcept(sMessage, rContext,
252  css::task::InteractionClassification_ERROR, OUString());
253  EXCEPT(aExcept);}
254  break;
255  default:
256  case G_IO_ERROR_ALREADY_MOUNTED:
257  case G_IO_ERROR_NOT_EMPTY:
258  case G_IO_ERROR_NOT_SYMBOLIC_LINK:
259  case G_IO_ERROR_NOT_MOUNTABLE_FILE:
260  case G_IO_ERROR_FAILED_HANDLED:
261  { css::ucb::InteractiveNetworkGeneralException aExcept(sMessage, rContext,
262  css::task::InteractionClassification_ERROR);
263  EXCEPT(aExcept);}
264  break;
265  }
266  return aRet;
267 }
268 
269 void convertToIOException(GError *pError, const css::uno::Reference< css::uno::XInterface >& rContext)
270 {
271  try
272  {
273  convertToException(pError, rContext);
274  }
275  catch (const css::io::IOException&)
276  {
277  throw;
278  }
279  catch (const css::uno::RuntimeException&)
280  {
281  throw;
282  }
283  catch (const css::uno::Exception& e)
284  {
285  css::uno::Any a(cppu::getCaughtException());
286  throw css::lang::WrappedTargetRuntimeException(
287  "wrapped Exception " + e.Message,
288  css::uno::Reference<css::uno::XInterface>(), a);
289  }
290 }
291 
292 css::uno::Any Content::mapGIOError( GError *pError )
293 {
294  if (!pError)
295  return getBadArgExcept();
296 
297  return convertToException(pError, static_cast< cppu::OWeakObject * >(this), false);
298 }
299 
301 {
302  return css::uno::makeAny( css::lang::IllegalArgumentException(
303  "Wrong argument type!",
304  static_cast< cppu::OWeakObject * >( this ), -1) );
305 }
306 
307 namespace {
308 
309 class MountOperation
310 {
312  GMainLoop *mpLoop;
313  GMountOperation *mpAuthentication;
314  GError *mpError;
315  static void Completed(GObject *source, GAsyncResult *res, gpointer user_data);
316 public:
317  explicit MountOperation(const css::uno::Reference< css::ucb::XCommandEnvironment >& xEnv);
318  ~MountOperation();
319  GError *Mount(GFile *pFile);
320 };
321 
322 }
323 
324 MountOperation::MountOperation(const css::uno::Reference< css::ucb::XCommandEnvironment >& xEnv) : mpError(nullptr)
325 {
326  ucb::ucp::gio::glib::MainContextRef oldContext(g_main_context_ref_thread_default());
327  mContext.reset(g_main_context_new());
328  mpLoop = g_main_loop_new(mContext.get(), FALSE);
329  g_main_context_push_thread_default(mContext.get());
330  mpAuthentication = ooo_mount_operation_new(std::move(oldContext), xEnv);
331 }
332 
333 void MountOperation::Completed(GObject *source, GAsyncResult *res, gpointer user_data)
334 {
335  MountOperation *pThis = static_cast<MountOperation*>(user_data);
336  g_file_mount_enclosing_volume_finish(G_FILE(source), res, &(pThis->mpError));
337  g_main_loop_quit(pThis->mpLoop);
338 }
339 
340 GError *MountOperation::Mount(GFile *pFile)
341 {
342  g_file_mount_enclosing_volume(pFile, G_MOUNT_MOUNT_NONE, mpAuthentication, nullptr, MountOperation::Completed, this);
343  {
344  //HACK: At least the gdk_threads_set_lock_functions(GdkThreadsEnter,
345  // GdkThreadsLeave) call in vcl/unx/gtk/app/gtkinst.cxx will lead to
346  // GdkThreadsLeave unlock the SolarMutex down to zero at the end of
347  // g_main_loop_run, so we need ~SolarMutexReleaser to raise it back to
348  // the original value again:
349  if (comphelper::SolarMutex::get()->IsCurrentThread())
350  {
351  SolarMutexReleaser rel;
352  g_main_loop_run(mpLoop);
353  }
354  else
355  {
356  g_main_loop_run(mpLoop);
357  }
358  }
359  return mpError;
360 }
361 
362 MountOperation::~MountOperation()
363 {
364  g_object_unref(mpAuthentication);
365  g_main_context_pop_thread_default(mContext.get());
366  g_main_loop_unref(mpLoop);
367 }
368 
369 GFileInfo* Content::getGFileInfo(const css::uno::Reference< css::ucb::XCommandEnvironment >& xEnv, GError **ppError)
370 {
371  GError * err = nullptr;
372  if (mpInfo == nullptr && !mbTransient) {
373  for (bool retried = false;; retried = true) {
374  mpInfo = g_file_query_info(
375  getGFile(), "*", G_FILE_QUERY_INFO_NONE, nullptr, &err);
376  if (mpInfo != nullptr) {
377  break;
378  }
379  assert(err != nullptr);
380  if (err->code != G_IO_ERROR_NOT_MOUNTED || retried) {
381  break;
382  }
383  SAL_INFO(
384  "ucb.ucp.gio",
385  "G_IO_ERROR_NOT_MOUNTED \"" << err->message
386  << "\", trying to mount");
387  g_error_free(err);
388  err = MountOperation(xEnv).Mount(getGFile());
389  if (err != nullptr) {
390  break;
391  }
392  }
393  }
394  if (ppError != nullptr) {
395  *ppError = err;
396  } else if (err != nullptr) {
397  SAL_WARN(
398  "ucb.ucp.gio",
399  "ignoring GError \"" << err->message << "\" for <"
400  << m_xIdentifier->getContentIdentifier() << ">");
401  g_error_free(err);
402  }
403  return mpInfo;
404 }
405 
407 {
408  if (!mpFile)
409  mpFile = g_file_new_for_uri(OUStringToOString(m_xIdentifier->getContentIdentifier(), RTL_TEXTENCODING_UTF8).getStr());
410  return mpFile;
411 }
412 
413 bool Content::isFolder(const css::uno::Reference< css::ucb::XCommandEnvironment >& xEnv)
414 {
415  GFileInfo *pInfo = getGFileInfo(xEnv);
416  return pInfo && (g_file_info_get_file_type(pInfo) == G_FILE_TYPE_DIRECTORY);
417 }
418 
419 static css::util::DateTime getDateFromUnix (time_t t)
420 {
421  TimeValue tv;
422  tv.Nanosec = 0;
423  tv.Seconds = t;
424  oslDateTime dt;
425 
426  if ( osl_getDateTimeFromTimeValue( &tv, &dt ) )
427  return css::util::DateTime( 0, dt.Seconds, dt.Minutes, dt.Hours,
428  dt.Day, dt.Month, dt.Year, false);
429  else
430  return css::util::DateTime();
431 }
432 
433 css::uno::Reference< css::sdbc::XRow > Content::getPropertyValues(
434  const css::uno::Sequence< css::beans::Property >& rProperties,
435  const css::uno::Reference< css::ucb::XCommandEnvironment >& xEnv )
436 {
437  rtl::Reference< ::ucbhelper::PropertyValueSet > xRow = new ::ucbhelper::PropertyValueSet( m_xContext );
438 
439  GFileInfo *pInfo = nullptr;
440  for( const css::beans::Property& rProp : rProperties )
441  {
442  if ( rProp.Name == "IsDocument" )
443  {
444  getFileInfo(xEnv, &pInfo, true);
445  if (pInfo != nullptr && g_file_info_has_attribute(pInfo, G_FILE_ATTRIBUTE_STANDARD_TYPE))
446  xRow->appendBoolean( rProp, ( g_file_info_get_file_type( pInfo ) == G_FILE_TYPE_REGULAR ||
447  g_file_info_get_file_type( pInfo ) == G_FILE_TYPE_UNKNOWN ) );
448  else
449  xRow->appendVoid( rProp );
450  }
451  else if ( rProp.Name == "IsFolder" )
452  {
453  getFileInfo(xEnv, &pInfo, true);
454  if (pInfo != nullptr && g_file_info_has_attribute( pInfo, G_FILE_ATTRIBUTE_STANDARD_TYPE) )
455  xRow->appendBoolean( rProp, ( g_file_info_get_file_type( pInfo ) == G_FILE_TYPE_DIRECTORY ));
456  else
457  xRow->appendVoid( rProp );
458  }
459  else if ( rProp.Name == "Title" )
460  {
461  getFileInfo(xEnv, &pInfo, false);
462  if (pInfo != nullptr && g_file_info_has_attribute(pInfo, G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME))
463  {
464  const char *pName = g_file_info_get_display_name(pInfo);
465  xRow->appendString( rProp, OUString(pName, strlen(pName), RTL_TEXTENCODING_UTF8) );
466  }
467  else
468  xRow->appendVoid(rProp);
469  }
470  else if ( rProp.Name == "IsReadOnly" )
471  {
472  getFileInfo(xEnv, &pInfo, true);
473  if (pInfo != nullptr && g_file_info_has_attribute( pInfo, G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE ) )
474  xRow->appendBoolean( rProp, !g_file_info_get_attribute_boolean( pInfo, G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE) );
475  else
476  xRow->appendVoid( rProp );
477  }
478  else if ( rProp.Name == "DateCreated" )
479  {
480  getFileInfo(xEnv, &pInfo, true);
481  if (pInfo != nullptr && g_file_info_has_attribute( pInfo, G_FILE_ATTRIBUTE_TIME_CREATED ) )
482  xRow->appendTimestamp( rProp, getDateFromUnix(g_file_info_get_attribute_uint64(pInfo, G_FILE_ATTRIBUTE_TIME_CREATED)) );
483  else
484  xRow->appendVoid( rProp );
485  }
486  else if ( rProp.Name == "DateModified" )
487  {
488  getFileInfo(xEnv, &pInfo, true);
489  if (pInfo != nullptr && g_file_info_has_attribute( pInfo, G_FILE_ATTRIBUTE_TIME_CHANGED ) )
490  xRow->appendTimestamp( rProp, getDateFromUnix(g_file_info_get_attribute_uint64(pInfo, G_FILE_ATTRIBUTE_TIME_CHANGED)) );
491  else
492  xRow->appendVoid( rProp );
493  }
494  else if ( rProp.Name == "Size" )
495  {
496  getFileInfo(xEnv, &pInfo, true);
497  if (pInfo != nullptr && g_file_info_has_attribute( pInfo, G_FILE_ATTRIBUTE_STANDARD_SIZE) )
498  xRow->appendLong( rProp, ( g_file_info_get_size( pInfo ) ));
499  else
500  xRow->appendVoid( rProp );
501  }
502  else if ( rProp.Name == "IsVolume" )
503  {
504  //What do we use this for ?
505  xRow->appendBoolean( rProp, false );
506  }
507  else if ( rProp.Name == "IsCompactDisc" )
508  {
509  getFileInfo(xEnv, &pInfo, true);
510  if (pInfo != nullptr && g_file_info_has_attribute( pInfo, G_FILE_ATTRIBUTE_MOUNTABLE_CAN_EJECT ) )
511  xRow->appendBoolean( rProp, g_file_info_get_attribute_boolean(pInfo, G_FILE_ATTRIBUTE_MOUNTABLE_CAN_EJECT) );
512  else
513  xRow->appendVoid( rProp );
514  }
515  else if ( rProp.Name == "IsRemoveable" )
516  {
517  getFileInfo(xEnv, &pInfo, true);
518  if (pInfo != nullptr && g_file_info_has_attribute( pInfo, G_FILE_ATTRIBUTE_MOUNTABLE_CAN_UNMOUNT ) )
519  xRow->appendBoolean( rProp, g_file_info_get_attribute_boolean(pInfo, G_FILE_ATTRIBUTE_MOUNTABLE_CAN_UNMOUNT ) );
520  else
521  xRow->appendVoid( rProp );
522  }
523  else if ( rProp.Name == "IsFloppy" )
524  {
525  xRow->appendBoolean( rProp, false );
526  }
527  else if ( rProp.Name == "IsHidden" )
528  {
529  getFileInfo(xEnv, &pInfo, true);
530  if (pInfo != nullptr && g_file_info_has_attribute( pInfo, G_FILE_ATTRIBUTE_STANDARD_IS_HIDDEN) )
531  xRow->appendBoolean( rProp, ( g_file_info_get_is_hidden ( pInfo ) ) );
532  else
533  xRow->appendVoid( rProp );
534  }
535  else if ( rProp.Name == "CreatableContentsInfo" )
536  {
537  xRow->appendObject( rProp, css::uno::makeAny( queryCreatableContentsInfo( xEnv ) ) );
538  }
539  else
540  {
541  SAL_WARN(
542  "ucb.ucp.gio",
543  "Looking for unsupported property " << rProp.Name);
544  }
545  }
546 
547  return css::uno::Reference< css::sdbc::XRow >( xRow.get() );
548 }
549 
550 static css::lang::IllegalAccessException
551 getReadOnlyException( const css::uno::Reference< css::uno::XInterface >& rContext )
552 {
553  return css::lang::IllegalAccessException ("Property is read-only!", rContext );
554 }
555 
557 {
558  // Obtain a list with a snapshot of all currently instantiated contents
559  // from provider and extract the contents which are direct children
560  // of this content.
561 
562  ucbhelper::ContentRefList aAllContents;
563  m_xProvider->queryExistingContents( aAllContents );
564 
565  OUString aURL = m_xIdentifier->getContentIdentifier();
566  sal_Int32 nURLPos = aURL.lastIndexOf( '/' );
567 
568  if ( nURLPos != ( aURL.getLength() - 1 ) )
569  aURL += "/";
570 
571  sal_Int32 nLen = aURL.getLength();
572 
573  for ( const auto& rContent : aAllContents )
574  {
575  ucbhelper::ContentImplHelperRef xChild = rContent;
576  OUString aChildURL = xChild->getIdentifier()->getContentIdentifier();
577 
578  // Is aURL a prefix of aChildURL?
579  if ( ( aChildURL.getLength() > nLen ) && aChildURL.startsWith( aURL ) )
580  {
581  sal_Int32 nPos = aChildURL.indexOf( '/', nLen );
582 
583  if ( ( nPos == -1 ) || ( nPos == ( aChildURL.getLength() - 1 ) ) )
584  {
585  // No further slashes / only a final slash. It's a child!
586  rChildren.emplace_back(static_cast< ::gio::Content * >(xChild.get() ) );
587  }
588  }
589  }
590 }
591 
592 bool Content::exchangeIdentity( const css::uno::Reference< css::ucb::XContentIdentifier >& xNewId )
593 {
594  if ( !xNewId.is() )
595  return false;
596 
597  css::uno::Reference< css::ucb::XContent > xThis = this;
598 
599  if ( mbTransient )
600  {
601  m_xIdentifier = xNewId;
602  return false;
603  }
604 
605  OUString aOldURL = m_xIdentifier->getContentIdentifier();
606 
607  // Exchange own identitity.
608  if ( exchange( xNewId ) )
609  {
610  // Process instantiated children...
611  ContentRefList aChildren;
612  queryChildren( aChildren );
613 
614  for ( const auto& rChild : aChildren )
615  {
616  ContentRef xChild = rChild;
617 
618  // Create new content identifier for the child...
619  css::uno::Reference< css::ucb::XContentIdentifier > xOldChildId = xChild->getIdentifier();
620  OUString aOldChildURL = xOldChildId->getContentIdentifier();
621  OUString aNewChildURL = aOldChildURL.replaceAt(
622  0, aOldURL.getLength(), xNewId->getContentIdentifier() );
623 
624  css::uno::Reference< css::ucb::XContentIdentifier > xNewChildId
625  = new ::ucbhelper::ContentIdentifier( aNewChildURL );
626 
627  if ( !xChild->exchangeIdentity( xNewChildId ) )
628  return false;
629  }
630  return true;
631  }
632 
633  return false;
634 }
635 
637  css::uno::Reference<css::ucb::XCommandEnvironment> const & env, GFileInfo ** info, bool fail)
638 {
639  assert(info != nullptr);
640  if (*info == nullptr)
641  {
642  GError * err = nullptr;
643  *info = getGFileInfo(env, &err);
644  if (*info == nullptr && !mbTransient && fail)
645  {
647  }
648  else if (err != nullptr)
649  {
650  g_error_free(err);
651  }
652  }
653 }
654 
655 css::uno::Sequence< css::uno::Any > Content::setPropertyValues(
656  const css::uno::Sequence< css::beans::PropertyValue >& rValues,
657  const css::uno::Reference< css::ucb::XCommandEnvironment >& xEnv )
658 {
659  GError *pError=nullptr;
660  GFileInfo *pNewInfo=nullptr;
661  GFileInfo *pInfo = getGFileInfo(xEnv, &pError);
662  if (pInfo)
663  pNewInfo = g_file_info_dup(pInfo);
664  else
665  {
666  if (!mbTransient)
668  else
669  {
670  if (pError)
671  g_error_free(pError);
672  pNewInfo = g_file_info_new();
673  }
674  }
675 
676  sal_Int32 nCount = rValues.getLength();
677 
678  css::beans::PropertyChangeEvent aEvent;
679  aEvent.Source = static_cast< cppu::OWeakObject * >( this );
680  aEvent.Further = false;
681  aEvent.PropertyHandle = -1;
682 
683  sal_Int32 nChanged = 0, nTitlePos = -1;
684  const char *newName = nullptr;
685  css::uno::Sequence< css::beans::PropertyChangeEvent > aChanges(nCount);
686 
687  css::uno::Sequence< css::uno::Any > aRet( nCount );
688  const css::beans::PropertyValue* pValues = rValues.getConstArray();
689  for ( sal_Int32 n = 0; n < nCount; ++n )
690  {
691  const css::beans::PropertyValue& rValue = pValues[ n ];
692  SAL_INFO("ucb.ucp.gio", "Set prop '" << rValue.Name << "'");
693  if ( rValue.Name == "ContentType" ||
694  rValue.Name == "MediaType" ||
695  rValue.Name == "IsDocument" ||
696  rValue.Name == "IsFolder" ||
697  rValue.Name == "Size" ||
698  rValue.Name == "CreatableContentsInfo" )
699  {
700  aRet[ n ] <<= getReadOnlyException( static_cast< cppu::OWeakObject * >(this) );
701  }
702  else if ( rValue.Name == "Title" )
703  {
704  OUString aNewTitle;
705  if (!( rValue.Value >>= aNewTitle ))
706  {
707  aRet[ n ] <<= css::beans::IllegalTypeException
708  ( "Property value has wrong type!",
709  static_cast< cppu::OWeakObject * >( this ) );
710  continue;
711  }
712 
713  if ( aNewTitle.getLength() <= 0 )
714  {
715  aRet[ n ] <<= css::lang::IllegalArgumentException
716  ( "Empty title not allowed!",
717  static_cast< cppu::OWeakObject * >( this ), -1 );
718  continue;
719 
720  }
721 
722  OString sNewTitle = OUStringToOString(aNewTitle, RTL_TEXTENCODING_UTF8);
723  newName = sNewTitle.getStr();
724  const char *oldName = g_file_info_get_name( pInfo);
725 
726  if (!newName || !oldName || strcmp(newName, oldName))
727  {
728  SAL_INFO("ucb.ucp.gio", "Set new name to '" << newName << "'");
729 
730  aEvent.PropertyName = "Title";
731  if (oldName)
732  aEvent.OldValue <<= OUString(oldName, strlen(oldName), RTL_TEXTENCODING_UTF8);
733  aEvent.NewValue <<= aNewTitle;
734  aChanges.getArray()[ nChanged ] = aEvent;
735  nTitlePos = nChanged++;
736 
737  g_file_info_set_name(pNewInfo, newName);
738  }
739  }
740  else
741  {
742  SAL_WARN("ucb.ucp.gio", "Unknown property " << rValue.Name);
743  aRet[ n ] <<= getReadOnlyException( static_cast< cppu::OWeakObject * >(this) );
744  //TODO
745  }
746  }
747 
748  if (nChanged)
749  {
750  bool bOk = true;
751  if (!mbTransient)
752  {
753  if ((bOk = doSetFileInfo(pNewInfo)))
754  {
755  for (sal_Int32 i = 0; i < nChanged; ++i)
756  aRet[ i ] = getBadArgExcept();
757  }
758  }
759 
760  if (bOk)
761  {
762  if (nTitlePos > -1)
763  {
764  OUString aNewURL = getParentURL() +
765  OUString( newName, strlen(newName), RTL_TEXTENCODING_UTF8 );
766  css::uno::Reference< css::ucb::XContentIdentifier > xNewId
767  = new ::ucbhelper::ContentIdentifier( aNewURL );
768 
769  if (!exchangeIdentity( xNewId ) )
770  {
771  aRet[ nTitlePos ] <<= css::uno::Exception
772  ( "Exchange failed!",
773  static_cast< cppu::OWeakObject * >( this ) );
774  }
775  }
776 
777  if (!mbTransient) //Discard and refetch
778  {
779  g_object_unref(mpInfo);
780  mpInfo = nullptr;
781  }
782 
783  if (mpInfo)
784  {
785  g_file_info_copy_into(pNewInfo, mpInfo);
786  g_object_unref(pNewInfo);
787  }
788  else
789  mpInfo = pNewInfo;
790 
791  if (mpFile) //Discard and refetch
792  {
793  g_object_unref(mpFile);
794  mpFile = nullptr;
795  }
796  }
797 
798  aChanges.realloc( nChanged );
799  notifyPropertiesChange( aChanges );
800  }
801 
802  return aRet;
803 }
804 
805 bool Content::doSetFileInfo(GFileInfo *pNewInfo)
806 {
807  g_assert (!mbTransient);
808 
809  bool bOk = true;
810  GFile *pFile = getGFile();
811  if(!g_file_set_attributes_from_info(pFile, pNewInfo, G_FILE_QUERY_INFO_NONE, nullptr, nullptr))
812  bOk = false;
813  return bOk;
814 }
815 
816 const int TRANSFER_BUFFER_SIZE = 65536;
817 
818 void Content::copyData( const css::uno::Reference< css::io::XInputStream >& xIn,
819  const css::uno::Reference< css::io::XOutputStream >& xOut )
820 {
821  css::uno::Sequence< sal_Int8 > theData( TRANSFER_BUFFER_SIZE );
822 
823  g_return_if_fail( xIn.is() && xOut.is() );
824 
825  while ( xIn->readBytes( theData, TRANSFER_BUFFER_SIZE ) > 0 )
826  xOut->writeBytes( theData );
827 
828  xOut->closeOutput();
829 }
830 
831 bool Content::feedSink( const css::uno::Reference< css::uno::XInterface >& xSink )
832 {
833  if ( !xSink.is() )
834  return false;
835 
836  css::uno::Reference< css::io::XOutputStream > xOut(xSink, css::uno::UNO_QUERY );
837  css::uno::Reference< css::io::XActiveDataSink > xDataSink(xSink, css::uno::UNO_QUERY );
838 
839  if ( !xOut.is() && !xDataSink.is() )
840  return false;
841 
842  GError *pError=nullptr;
843  GFileInputStream *pStream = g_file_read(getGFile(), nullptr, &pError);
844  if (!pStream)
845  convertToException(pError, static_cast< cppu::OWeakObject * >(this));
846 
847  css::uno::Reference< css::io::XInputStream > xIn(
849  new ::gio::InputStream(pStream), m_xContext));
850 
851  if ( xOut.is() )
852  copyData( xIn, xOut );
853 
854  if ( xDataSink.is() )
855  xDataSink->setInputStream( xIn );
856 
857  return true;
858 }
859 
860 css::uno::Any Content::open(const css::ucb::OpenCommandArgument2 & rOpenCommand,
861  const css::uno::Reference< css::ucb::XCommandEnvironment > & xEnv )
862 {
863  bool bIsFolder = isFolder(xEnv);
864 
865  if (!g_file_query_exists(getGFile(), nullptr))
866  {
867  css::uno::Sequence< css::uno::Any > aArgs( 1 );
868  aArgs[ 0 ] <<= m_xIdentifier->getContentIdentifier();
869  css::uno::Any aErr = css::uno::makeAny(
870  css::ucb::InteractiveAugmentedIOException(OUString(), static_cast< cppu::OWeakObject * >( this ),
871  css::task::InteractionClassification_ERROR,
872  bIsFolder ? css::ucb::IOErrorCode_NOT_EXISTING_PATH : css::ucb::IOErrorCode_NOT_EXISTING, aArgs)
873  );
874 
876  }
877 
878  css::uno::Any aRet;
879 
880  bool bOpenFolder = (
881  ( rOpenCommand.Mode == css::ucb::OpenMode::ALL ) ||
882  ( rOpenCommand.Mode == css::ucb::OpenMode::FOLDERS ) ||
883  ( rOpenCommand.Mode == css::ucb::OpenMode::DOCUMENTS )
884  );
885 
886  if ( bOpenFolder && bIsFolder )
887  {
888  css::uno::Reference< css::ucb::XDynamicResultSet > xSet
889  = new DynamicResultSet( m_xContext, this, rOpenCommand, xEnv );
890  aRet <<= xSet;
891  }
892  else if ( rOpenCommand.Sink.is() )
893  {
894  if (
895  ( rOpenCommand.Mode == css::ucb::OpenMode::DOCUMENT_SHARE_DENY_NONE ) ||
896  ( rOpenCommand.Mode == css::ucb::OpenMode::DOCUMENT_SHARE_DENY_WRITE )
897  )
898  {
900  css::uno::makeAny ( css::ucb::UnsupportedOpenModeException
901  ( OUString(), static_cast< cppu::OWeakObject * >( this ),
902  sal_Int16( rOpenCommand.Mode ) ) ),
903  xEnv );
904  }
905 
906  if ( !feedSink( rOpenCommand.Sink ) )
907  {
908  // Note: rOpenCommand.Sink may contain an XStream
909  // implementation. Support for this type of
910  // sink is optional...
911  SAL_WARN("ucb.ucp.gio", "Failed to load data from '" << m_xIdentifier->getContentIdentifier() << "'");
912 
914  css::uno::makeAny (css::ucb::UnsupportedDataSinkException
915  ( OUString(), static_cast< cppu::OWeakObject * >( this ),
916  rOpenCommand.Sink ) ),
917  xEnv );
918  }
919  }
920  else
921  SAL_INFO("ucb.ucp.gio", "Open falling through ...");
922  return aRet;
923 }
924 
925 css::uno::Any SAL_CALL Content::execute(
926  const css::ucb::Command& aCommand,
927  sal_Int32 /*CommandId*/,
928  const css::uno::Reference< css::ucb::XCommandEnvironment >& xEnv )
929 {
930  SAL_INFO("ucb.ucp.gio", "Content::execute " << aCommand.Name);
931  css::uno::Any aRet;
932 
933  if ( aCommand.Name == "getPropertyValues" )
934  {
935  css::uno::Sequence< css::beans::Property > Properties;
936  if ( !( aCommand.Argument >>= Properties ) )
938  aRet <<= getPropertyValues( Properties, xEnv );
939  }
940  else if ( aCommand.Name == "getPropertySetInfo" )
941  aRet <<= getPropertySetInfo( xEnv, false );
942  else if ( aCommand.Name == "getCommandInfo" )
943  aRet <<= getCommandInfo( xEnv, false );
944  else if ( aCommand.Name == "open" )
945  {
946  css::ucb::OpenCommandArgument2 aOpenCommand;
947  if ( !( aCommand.Argument >>= aOpenCommand ) )
949  aRet = open( aOpenCommand, xEnv );
950  }
951  else if ( aCommand.Name == "transfer" )
952  {
953  css::ucb::TransferInfo transferArgs;
954  if ( !( aCommand.Argument >>= transferArgs ) )
956  transfer( transferArgs, xEnv );
957  }
958  else if ( aCommand.Name == "setPropertyValues" )
959  {
960  css::uno::Sequence< css::beans::PropertyValue > aProperties;
961  if ( !( aCommand.Argument >>= aProperties ) || !aProperties.hasElements() )
963  aRet <<= setPropertyValues( aProperties, xEnv );
964  }
965  else if (aCommand.Name == "createNewContent"
966  && isFolder( xEnv ) )
967  {
968  css::ucb::ContentInfo arg;
969  if ( !( aCommand.Argument >>= arg ) )
971  aRet <<= createNewContent( arg );
972  }
973  else if ( aCommand.Name == "insert" )
974  {
975  css::ucb::InsertCommandArgument arg;
976  if ( !( aCommand.Argument >>= arg ) )
978  insert( arg.Data, arg.ReplaceExisting, xEnv );
979  }
980  else if ( aCommand.Name == "delete" )
981  {
982  bool bDeletePhysical = false;
983  aCommand.Argument >>= bDeletePhysical;
984 
985  //If no delete physical, try and trashcan it, if that doesn't work go
986  //ahead and try and delete it anyway
987  if (!bDeletePhysical && !g_file_trash(getGFile(), nullptr, nullptr))
988  bDeletePhysical = true;
989 
990  if (bDeletePhysical)
991  {
992  GError *pError = nullptr;
993  if (!g_file_delete( getGFile(), nullptr, &pError))
995  }
996 
997  destroy( bDeletePhysical );
998  }
999  else
1000  {
1001  SAL_WARN("ucb.ucp.gio", "Unknown command " << aCommand.Name);
1002 
1004  ( css::uno::makeAny( css::ucb::UnsupportedCommandException
1005  ( OUString(),
1006  static_cast< cppu::OWeakObject * >( this ) ) ),
1007  xEnv );
1008  }
1009 
1010  return aRet;
1011 }
1012 
1013 void Content::destroy( bool bDeletePhysical )
1014 {
1015  css::uno::Reference< css::ucb::XContent > xThis = this;
1016 
1017  deleted();
1018 
1020  queryChildren( aChildren );
1021 
1022  for ( auto& rChild : aChildren )
1023  {
1024  rChild->destroy( bDeletePhysical );
1025  }
1026 }
1027 
1028 void Content::insert(const css::uno::Reference< css::io::XInputStream > &xInputStream,
1029  bool bReplaceExisting, const css::uno::Reference< css::ucb::XCommandEnvironment > &xEnv )
1030 {
1031  GError *pError = nullptr;
1032  GFileInfo *pInfo = getGFileInfo(xEnv);
1033 
1034  if ( pInfo &&
1035  g_file_info_has_attribute(pInfo, G_FILE_ATTRIBUTE_STANDARD_TYPE) &&
1036  g_file_info_get_file_type(pInfo) == G_FILE_TYPE_DIRECTORY )
1037  {
1038  SAL_INFO("ucb.ucp.gio", "Make directory");
1039  if( !g_file_make_directory( getGFile(), nullptr, &pError))
1041  return;
1042  }
1043 
1044  if ( !xInputStream.is() )
1045  {
1046  ucbhelper::cancelCommandExecution( css::uno::makeAny
1047  ( css::ucb::MissingInputStreamException
1048  ( OUString(), static_cast< cppu::OWeakObject * >( this ) ) ),
1049  xEnv );
1050  }
1051 
1052  GFileOutputStream* pOutStream = nullptr;
1053  if ( bReplaceExisting )
1054  {
1055  if (!(pOutStream = g_file_replace(getGFile(), nullptr, false, G_FILE_CREATE_PRIVATE, nullptr, &pError)))
1057  }
1058  else
1059  {
1060  if (!(pOutStream = g_file_create (getGFile(), G_FILE_CREATE_PRIVATE, nullptr, &pError)))
1062  }
1063 
1064  css::uno::Reference < css::io::XOutputStream > xOutput = new ::gio::OutputStream(pOutStream);
1065  copyData( xInputStream, xOutput );
1066 
1067  if (mbTransient)
1068  {
1069  mbTransient = false;
1070  inserted();
1071  }
1072 }
1073 
1074 const GFileCopyFlags DEFAULT_COPYDATA_FLAGS =
1075  static_cast<GFileCopyFlags>(G_FILE_COPY_OVERWRITE|G_FILE_COPY_TARGET_DEFAULT_PERMS);
1076 
1077 void Content::transfer( const css::ucb::TransferInfo& aTransferInfo, const css::uno::Reference< css::ucb::XCommandEnvironment >& xEnv )
1078 {
1079  OUString sDest = m_xIdentifier->getContentIdentifier();
1080  if (!sDest.endsWith("/")) {
1081  sDest += "/";
1082  }
1083  if (aTransferInfo.NewTitle.getLength())
1084  sDest += aTransferInfo.NewTitle;
1085  else
1086  sDest += OUString::createFromAscii(g_file_get_basename(getGFile()));
1087 
1088  GFile *pDest = g_file_new_for_uri(OUStringToOString(sDest, RTL_TEXTENCODING_UTF8).getStr());
1089  GFile *pSource = g_file_new_for_uri(OUStringToOString(aTransferInfo.SourceURL, RTL_TEXTENCODING_UTF8).getStr());
1090 
1091  bool bSuccess = false;
1092  GError *pError = nullptr;
1093  if (aTransferInfo.MoveData)
1094  bSuccess = g_file_move(pSource, pDest, G_FILE_COPY_OVERWRITE, nullptr, nullptr, nullptr, &pError);
1095  else
1096  bSuccess = g_file_copy(pSource, pDest, DEFAULT_COPYDATA_FLAGS, nullptr, nullptr, nullptr, &pError);
1097  g_object_unref(pSource);
1098  g_object_unref(pDest);
1099  if (!bSuccess)
1101 }
1102 
1103 css::uno::Sequence< css::ucb::ContentInfo > Content::queryCreatableContentsInfo(
1104  const css::uno::Reference< css::ucb::XCommandEnvironment >& xEnv)
1105 {
1106  if ( isFolder( xEnv ) )
1107  {
1108  css::uno::Sequence< css::ucb::ContentInfo > seq(2);
1109 
1110  // Minimum set of props we really need
1111  css::uno::Sequence< css::beans::Property > props( 1 );
1112  props[0] = css::beans::Property(
1113  "Title",
1114  -1,
1116  css::beans::PropertyAttribute::MAYBEVOID | css::beans::PropertyAttribute::BOUND );
1117 
1118  // file
1119  seq[0].Type = GIO_FILE_TYPE;
1120  seq[0].Attributes = ( css::ucb::ContentInfoAttribute::INSERT_WITH_INPUTSTREAM |
1121  css::ucb::ContentInfoAttribute::KIND_DOCUMENT );
1122  seq[0].Properties = props;
1123 
1124  // folder
1125  seq[1].Type = GIO_FOLDER_TYPE;
1126  seq[1].Attributes = css::ucb::ContentInfoAttribute::KIND_FOLDER;
1127  seq[1].Properties = props;
1128 
1129  return seq;
1130  }
1131  else
1132  {
1133  return css::uno::Sequence< css::ucb::ContentInfo >();
1134  }
1135 }
1136 
1137 css::uno::Sequence< css::ucb::ContentInfo > SAL_CALL Content::queryCreatableContentsInfo()
1138 {
1139  return queryCreatableContentsInfo( css::uno::Reference< css::ucb::XCommandEnvironment >() );
1140 }
1141 
1142 css::uno::Reference< css::ucb::XContent >
1143  SAL_CALL Content::createNewContent( const css::ucb::ContentInfo& Info )
1144 {
1145  bool create_document;
1146  const char *name;
1147 
1148  if ( Info.Type == GIO_FILE_TYPE )
1149  create_document = true;
1150  else if ( Info.Type == GIO_FOLDER_TYPE )
1151  create_document = false;
1152  else
1153  {
1154  SAL_WARN("ucb.ucp.gio", "Failed to create new content '" << Info.Type << "'");
1155  return css::uno::Reference< css::ucb::XContent >();
1156  }
1157 
1158  SAL_INFO("ucb.ucp.gio", "createNewContent (" << create_document << ")");
1159  OUString aURL = m_xIdentifier->getContentIdentifier();
1160 
1161  if ( ( aURL.lastIndexOf( '/' ) + 1 ) != aURL.getLength() )
1162  aURL += "/";
1163 
1164  name = create_document ? "[New_Content]" : "[New_Collection]";
1165  aURL += OUString::createFromAscii( name );
1166 
1167  css::uno::Reference< css::ucb::XContentIdentifier > xId(new ::ucbhelper::ContentIdentifier(aURL));
1168 
1169  try
1170  {
1171  return new ::gio::Content( m_xContext, m_pProvider, xId, !create_document );
1172  } catch ( css::ucb::ContentCreationException & )
1173  {
1174  return css::uno::Reference< css::ucb::XContent >();
1175  }
1176 }
1177 
1178 css::uno::Sequence< css::uno::Type > SAL_CALL Content::getTypes()
1179 {
1180  if ( isFolder( css::uno::Reference< css::ucb::XCommandEnvironment >() ) )
1181  {
1182  static cppu::OTypeCollection s_aFolderCollection
1183  (CPPU_TYPE_REF( css::lang::XTypeProvider ),
1184  CPPU_TYPE_REF( css::lang::XServiceInfo ),
1185  CPPU_TYPE_REF( css::lang::XComponent ),
1186  CPPU_TYPE_REF( css::ucb::XContent ),
1187  CPPU_TYPE_REF( css::ucb::XCommandProcessor ),
1188  CPPU_TYPE_REF( css::beans::XPropertiesChangeNotifier ),
1189  CPPU_TYPE_REF( css::ucb::XCommandInfoChangeNotifier ),
1190  CPPU_TYPE_REF( css::beans::XPropertyContainer ),
1191  CPPU_TYPE_REF( css::beans::XPropertySetInfoChangeNotifier ),
1192  CPPU_TYPE_REF( css::container::XChild ),
1193  CPPU_TYPE_REF( css::ucb::XContentCreator ) );
1194  return s_aFolderCollection.getTypes();
1195  }
1196  else
1197  {
1198  static cppu::OTypeCollection s_aFileCollection
1199  (CPPU_TYPE_REF( css::lang::XTypeProvider ),
1200  CPPU_TYPE_REF( css::lang::XServiceInfo ),
1201  CPPU_TYPE_REF( css::lang::XComponent ),
1202  CPPU_TYPE_REF( css::ucb::XContent ),
1203  CPPU_TYPE_REF( css::ucb::XCommandProcessor ),
1204  CPPU_TYPE_REF( css::beans::XPropertiesChangeNotifier ),
1205  CPPU_TYPE_REF( css::ucb::XCommandInfoChangeNotifier ),
1206  CPPU_TYPE_REF( css::beans::XPropertyContainer ),
1207  CPPU_TYPE_REF( css::beans::XPropertySetInfoChangeNotifier ),
1208  CPPU_TYPE_REF( css::container::XChild ) );
1209 
1210  return s_aFileCollection.getTypes();
1211  }
1212 }
1213 
1214 css::uno::Sequence< css::beans::Property > Content::getProperties(
1215  const css::uno::Reference< css::ucb::XCommandEnvironment > & /*xEnv*/ )
1216 {
1217  static const css::beans::Property aGenericProperties[] =
1218  {
1219  css::beans::Property( "IsDocument",
1221  css::beans::PropertyAttribute::BOUND | css::beans::PropertyAttribute::READONLY ),
1222  css::beans::Property( "IsFolder",
1224  css::beans::PropertyAttribute::BOUND | css::beans::PropertyAttribute::READONLY ),
1225  css::beans::Property( "Title",
1227  css::beans::PropertyAttribute::BOUND ),
1228  css::beans::Property( "IsReadOnly",
1230  css::beans::PropertyAttribute::BOUND | css::beans::PropertyAttribute::READONLY ),
1231  css::beans::Property( "DateCreated",
1233  css::beans::PropertyAttribute::BOUND | css::beans::PropertyAttribute::READONLY ),
1234  css::beans::Property( "DateModified",
1236  css::beans::PropertyAttribute::BOUND | css::beans::PropertyAttribute::READONLY ),
1237  css::beans::Property( "Size",
1239  css::beans::PropertyAttribute::BOUND | css::beans::PropertyAttribute::READONLY ),
1240  css::beans::Property( "IsVolume",
1242  css::beans::PropertyAttribute::BOUND | css::beans::PropertyAttribute::READONLY ),
1243  css::beans::Property( "IsCompactDisc",
1245  css::beans::PropertyAttribute::BOUND | css::beans::PropertyAttribute::READONLY ),
1246  css::beans::Property( "IsRemoveable",
1248  css::beans::PropertyAttribute::BOUND | css::beans::PropertyAttribute::READONLY ),
1249  css::beans::Property( "IsHidden",
1251  css::beans::PropertyAttribute::BOUND | css::beans::PropertyAttribute::READONLY ),
1252  css::beans::Property( "CreatableContentsInfo",
1253  -1, cppu::UnoType<css::uno::Sequence< css::ucb::ContentInfo >>::get(),
1254  css::beans::PropertyAttribute::BOUND | css::beans::PropertyAttribute::READONLY )
1255  };
1256 
1257  const int nProps = SAL_N_ELEMENTS(aGenericProperties);
1258  return css::uno::Sequence< css::beans::Property > ( aGenericProperties, nProps );
1259 }
1260 
1261 css::uno::Sequence< css::ucb::CommandInfo > Content::getCommands( const css::uno::Reference< css::ucb::XCommandEnvironment > & xEnv)
1262 {
1263  static const css::ucb::CommandInfo aCommandInfoTable[] =
1264  {
1265  // Required commands
1266  css::ucb::CommandInfo
1267  ( "getCommandInfo",
1268  -1, cppu::UnoType<void>::get() ),
1269  css::ucb::CommandInfo
1270  ( "getPropertySetInfo",
1271  -1, cppu::UnoType<void>::get() ),
1272  css::ucb::CommandInfo
1273  ( "getPropertyValues",
1274  -1, cppu::UnoType<css::uno::Sequence< css::beans::Property >>::get() ),
1275  css::ucb::CommandInfo
1276  ( "setPropertyValues",
1277  -1, cppu::UnoType<css::uno::Sequence< css::beans::PropertyValue >>::get() ),
1278 
1279  // Optional standard commands
1280  css::ucb::CommandInfo
1281  ( "delete",
1282  -1, cppu::UnoType<bool>::get() ),
1283  css::ucb::CommandInfo
1284  ( "insert",
1286  css::ucb::CommandInfo
1287  ( "open",
1289 
1290  // Folder Only, omitted if not a folder
1291  css::ucb::CommandInfo
1292  ( "transfer",
1294  css::ucb::CommandInfo
1295  ( "createNewContent",
1297  };
1298 
1299  const int nProps = SAL_N_ELEMENTS(aCommandInfoTable);
1300  return css::uno::Sequence< css::ucb::CommandInfo >(aCommandInfoTable, isFolder(xEnv) ? nProps : nProps - 2);
1301 }
1302 
1304 
1305 void SAL_CALL Content::acquire() throw()
1306 {
1307  ContentImplHelper::acquire();
1308 }
1309 
1310 void SAL_CALL Content::release() throw()
1311 {
1312  ContentImplHelper::release();
1313 }
1314 
1315 css::uno::Any SAL_CALL Content::queryInterface( const css::uno::Type & rType )
1316 {
1317  css::uno::Any aRet = cppu::queryInterface( rType, static_cast< css::ucb::XContentCreator * >( this ) );
1318  return aRet.hasValue() ? aRet : ContentImplHelper::queryInterface(rType);
1319 }
1320 
1322 {
1323  return "com.sun.star.comp.GIOContent";
1324 }
1325 
1326 css::uno::Sequence< OUString > SAL_CALL Content::getSupportedServiceNames()
1327 {
1328  css::uno::Sequence<OUString> aSNS { "com.sun.star.ucb.GIOContent" };
1329  return aSNS;
1330 }
1331 
1332 }
1333 
1334 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
virtual ~Content() override
Definition: gio_content.cxx:97
css::uno::Any getBadArgExcept()
css::uno::Reference< css::uno::XComponentContext > m_xContext
OUString sMessage
std::vector< ContentImplHelperRef > ContentRefList
GFile * mpFile
Definition: gio_content.hxx:68
void destroy(bool bDeletePhysical)
static css::lang::IllegalAccessException getReadOnlyException(const css::uno::Reference< css::uno::XInterface > &rContext)
sal_Int64 n
virtual css::uno::Sequence< css::ucb::CommandInfo > getCommands(const css::uno::Reference< css::ucb::XCommandEnvironment > &xEnv) override
virtual css::uno::Sequence< css::ucb::ContentInfo > SAL_CALL queryCreatableContentsInfo() override
css::uno::Any mapGIOError(GError *error)
virtual void SAL_CALL release() override
void getFileInfo(css::uno::Reference< css::ucb::XCommandEnvironment > const &env, GFileInfo **info, bool fail)
virtual void SAL_CALL acquire() override
GFile * getGFile()
void convertToIOException(GError *pError, const css::uno::Reference< css::uno::XInterface > &rContext)
css::uno::Any const & rValue
Reference< XRow > xRow
PropertiesInfo aProperties
Any SAL_CALL getCaughtException()
int nCount
static css::util::DateTime getDateFromUnix(time_t t)
virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override
void notifyPropertiesChange(const css::uno::Sequence< css::beans::PropertyChangeEvent > &evt) const
ContentProvider * m_pProvider
Definition: gio_content.hxx:67
bool isFolder(const css::uno::Reference< css::ucb::XCommandEnvironment > &xEnv)
const char * sName
XTYPEPROVIDER_COMMON_IMPL(Content)
std::unique_ptr< GMainContext, detail::MainContextUnref > MainContextRef
Definition: gio_mount.hxx:53
bool exchangeIdentity(const css::uno::Reference< css::ucb::XContentIdentifier > &xNewId)
#define SAL_N_ELEMENTS(arr)
virtual OUString SAL_CALL getContentType() override
err
GFileInfo * mpInfo
Definition: gio_content.hxx:69
sal_uInt16 char * pName
bool feedSink(const css::uno::Reference< css::uno::XInterface > &aSink)
void cancelCommandExecution(const uno::Any &rException, const uno::Reference< ucb::XCommandEnvironment > &xEnv)
Content(const css::uno::Reference< css::uno::XComponentContext > &rxContext, ContentProvider *pProvider, const css::uno::Reference< css::ucb::XContentIdentifier > &Identifier)
Definition: gio_content.cxx:74
int i
uno_Any a
css::uno::Reference< css::ucb::XContentIdentifier > m_xIdentifier
static void copyData(const css::uno::Reference< css::io::XInputStream > &xIn, const css::uno::Reference< css::io::XOutputStream > &xOut)
const GFileCopyFlags DEFAULT_COPYDATA_FLAGS
css::uno::Reference< css::beans::XPropertySetInfo > getPropertySetInfo(const css::uno::Reference< css::ucb::XCommandEnvironment > &xEnv, bool bCache=true)
css::uno::Reference< css::ucb::XCommandInfo > getCommandInfo(const css::uno::Reference< css::ucb::XCommandEnvironment > &xEnv, bool bCache=true)
dictionary props
virtual OUString getParentURL() override
OUString aURL
OUString newName(const OUString &aNewPrefix, const OUString &aOldPrefix, const OUString &old_Name)
Definition: filglob.cxx:170
GMountOperation * ooo_mount_operation_new(ucb::ucp::gio::glib::MainContextRef &&context, const css::uno::Reference< css::ucb::XCommandEnvironment > &rEnv)
Definition: gio_mount.cxx:202
void transfer(const css::ucb::TransferInfo &rTransferInfo, const css::uno::Reference< css::ucb::XCommandEnvironment > &xEnv)
virtual OUString SAL_CALL getImplementationName() override
virtual css::uno::Sequence< css::beans::Property > getProperties(const css::uno::Reference< css::ucb::XCommandEnvironment > &xEnv) override
#define GIO_FILE_TYPE
Definition: gio_content.hxx:53
virtual css::uno::Any SAL_CALL queryInterface(const css::uno::Type &rType) override
std::vector< ContentRef > ContentRefList
Definition: gio_content.hxx:85
rtl::Reference< ContentProviderImplHelper > m_xProvider
OString OUStringToOString(const OUString &str, ConnectionSettings const *settings)
css::uno::Reference< css::sdbc::XRow > getPropertyValues(const css::uno::Sequence< css::beans::Property > &rProperties, const css::uno::Reference< css::ucb::XCommandEnvironment > &xEnv)
const PropertyValue * pValues
GFileInfo * getGFileInfo(const css::uno::Reference< css::ucb::XCommandEnvironment > &xEnv, GError **ppError=nullptr)
void queryChildren(ContentRefList &rChildren)
const int TRANSFER_BUFFER_SIZE
virtual css::uno::Reference< css::ucb::XContent > SAL_CALL createNewContent(const css::ucb::ContentInfo &Info) override
#define CPPU_TYPE_REF(T)
#define SAL_INFO(area, stream)
static SolarMutex * get()
const char * name
virtual css::uno::Any SAL_CALL execute(const css::ucb::Command &aCommand, sal_Int32 CommandId, const css::uno::Reference< css::ucb::XCommandEnvironment > &Environment) override
css::uno::Sequence< css::uno::Type > SAL_CALL getTypes()
Reference< XContentIdentifier > xId
#define FALSE
#define GIO_FOLDER_TYPE
Definition: gio_content.hxx:54
css::uno::Any convertToException(GError *pError, const css::uno::Reference< css::uno::XInterface > &rContext, bool bThrow)
#define SAL_WARN(area, stream)
bool exchange(const css::uno::Reference< css::ucb::XContentIdentifier > &rNewId)
#define EXCEPT(aExcept)
virtual void SAL_CALL abort(sal_Int32 CommandId) override
bool doSetFileInfo(GFileInfo *pNewInfo)
css::uno::Any SAL_CALL queryInterface(const css::uno::Type &rType, Interface1 *p1)
AnyEventRef aEvent
css::uno::Any open(const css::ucb::OpenCommandArgument2 &rArg, const css::uno::Reference< css::ucb::XCommandEnvironment > &xEnv)
sal_uInt16 nPos
css::uno::Sequence< css::uno::Any > setPropertyValues(const css::uno::Sequence< css::beans::PropertyValue > &rValues, const css::uno::Reference< css::ucb::XCommandEnvironment > &xEnv)
void insert(const css::uno::Reference< css::io::XInputStream > &xInputStream, bool bReplaceExisting, const css::uno::Reference< css::ucb::XCommandEnvironment > &xEnv)
virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override