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