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