1 /* -*- Mode: ObjC; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <sal/config.h>
22 #include <string_view>
24 #include <config_features.h>
26 #include "uunxapi.hxx"
28 #include "unixerrnostring.hxx"
30 #include <rtl/ustring.hxx>
31 #include <osl/thread.h>
32 #include <sal/log.hxx>
35 #include <osl/detail/android-bootstrap.h>
38 OString
osl::OUStringToOString(std::u16string_view s
)
40 return rtl::OUStringToOString(s
, osl_getThreadTextEncoding());
43 #if HAVE_FEATURE_MACOSX_SANDBOX
45 #include <Foundation/Foundation.h>
46 #include <Security/Security.h>
47 #include <mach-o/dyld.h>
49 static NSUserDefaults
*userDefaults
= NULL
;
50 static bool isSandboxed
= false;
55 OSStatus rc
= SecCodeCopySelf(kSecCSDefaultFlags
, &code
);
57 SecStaticCodeRef staticCode
;
58 if (rc
== errSecSuccess
)
59 rc
= SecCodeCopyStaticCode(code
, kSecCSDefaultFlags
, &staticCode
);
61 CFDictionaryRef signingInformation
;
62 if (rc
== errSecSuccess
)
63 rc
= SecCodeCopySigningInformation(staticCode
, kSecCSRequirementInformation
, &signingInformation
);
65 CFDictionaryRef entitlements
= NULL
;
66 if (rc
== errSecSuccess
)
67 entitlements
= (CFDictionaryRef
) CFDictionaryGetValue(signingInformation
, kSecCodeInfoEntitlementsDict
);
69 if (entitlements
!= NULL
)
70 if (CFDictionaryGetValue(entitlements
, CFSTR("com.apple.security.app-sandbox")) != NULL
)
74 userDefaults
= [NSUserDefaults standardUserDefaults
];
79 NSAutoreleasePool
*pool
;
80 } accessFilePathState
;
82 static accessFilePathState
*
83 prepare_to_access_file_path( const char *cpFilePath
)
85 static pthread_once_t once
= PTHREAD_ONCE_INIT
;
86 pthread_once(&once
, &do_once
);
90 accessFilePathState
*state
;
95 // If malloc() fails we are screwed anyway
96 state
= (accessFilePathState
*) malloc(sizeof(accessFilePathState
));
98 state
->pool
= [[NSAutoreleasePool alloc
] init
];
99 state
->scopeURL
= nil
;
101 if (userDefaults
!= nil
)
102 fileURL
= [NSURL fileURLWithPath
:[NSString stringWithUTF8String
:cpFilePath
]];
105 data
= [userDefaults dataForKey
:[@
"bookmarkFor:" stringByAppendingString
:[fileURL absoluteString
]]];
108 state
->scopeURL
= [NSURL URLByResolvingBookmarkData
:data
109 options
:NSURLBookmarkResolutionWithSecurityScope
111 bookmarkDataIsStale
:&stale
113 if (state
->scopeURL
!= nil
)
114 [state
->scopeURL startAccessingSecurityScopedResource
];
120 done_accessing_file_path( const char * /*cpFilePath*/, accessFilePathState
*state
)
125 int saved_errno
= errno
;
127 if (state
->scopeURL
!= nil
)
128 [state
->scopeURL stopAccessingSecurityScopedResource
];
129 [state
->pool release
];
137 typedef void accessFilePathState
;
139 #define prepare_to_access_file_path( cpFilePath ) nullptr
141 #define done_accessing_file_path( cpFilePath, state ) ((void) cpFilePath, (void) state)
147 * Helper function for resolving Mac native alias files (not the same as unix alias files)
148 * and to return the resolved alias as OString
150 static OString
macxp_resolveAliasAndConvert(OString
const & p
)
153 if (p
.getLength() < PATH_MAX
)
155 strcpy(path
, p
.getStr());
156 macxp_resolveAlias(path
, PATH_MAX
);
163 int osl::access(const OString
& pstrPath
, int mode
)
165 OString fn
= pstrPath
;
167 if (fn
== "/assets" || fn
.startsWith("/assets/"))
170 if (lo_apk_lstat(fn
.getStr(), &stat
) == -1)
182 fn
= macxp_resolveAliasAndConvert(fn
);
185 accessFilePathState
*state
= prepare_to_access_file_path(fn
.getStr());
187 int result
= ::access(fn
.getStr(), mode
);
188 int saved_errno
= errno
;
190 SAL_INFO("sal.file", "access(" << fn
<< ",0" << std::oct
<< mode
<< std::dec
<< "): " << UnixErrnoString(saved_errno
));
192 SAL_INFO("sal.file", "access(" << fn
<< ",0" << std::oct
<< mode
<< std::dec
<< "): OK");
194 done_accessing_file_path(fn
.getStr(), state
);
203 OString
toOString(OString
const & s
) { return s
; }
205 OString
toOString(std::u16string_view s
) { return osl::OUStringToOString(s
); }
207 template<typename T
> T
fromOString(OString
const &) = delete;
209 template<> OString
fromOString(OString
const & s
) { return s
; }
211 template<> OUString
fromOString(OString
const & s
)
212 { return OStringToOUString(s
, osl_getThreadTextEncoding()); }
214 template<typename T
> bool realpath_(const T
& pstrFileName
, T
& ppstrResolvedName
)
216 OString fn
= toOString(pstrFileName
);
217 #if defined ANDROID || defined(EMSCRIPTEN)
219 if (fn
== "/assets" || fn
.startsWith("/assets/"))
221 if (fn
== "/instdir" || fn
.startsWith("/instdir/"))
224 if (osl::access(fn
, F_OK
) == -1)
227 ppstrResolvedName
= pstrFileName
;
231 #endif // ANDROID || EMSCRIPTEN
234 fn
= macxp_resolveAliasAndConvert(fn
);
237 accessFilePathState
*state
= prepare_to_access_file_path(fn
.getStr());
240 bool bRet
= realpath(fn
.getStr(), rp
);
241 int saved_errno
= errno
;
243 SAL_INFO("sal.file", "realpath(" << fn
<< "): " << UnixErrnoString(saved_errno
));
245 SAL_INFO("sal.file", "realpath(" << fn
<< "): OK");
247 done_accessing_file_path(fn
.getStr(), state
);
251 ppstrResolvedName
= fromOString
<T
>(OString(rp
));
261 bool osl::realpath(const OUString
& pustrFileName
, OUString
& ppustrResolvedName
)
263 return realpath_(pustrFileName
, ppustrResolvedName
);
266 bool osl::realpath(const OString
& pstrFileName
, OString
& ppstrResolvedName
)
268 return realpath_(pstrFileName
, ppstrResolvedName
);
271 int stat_c(const char* cpPath
, struct stat
* buf
)
274 if (strncmp(cpPath
, "/assets", sizeof("/assets")-1) == 0 &&
275 (cpPath
[sizeof("/assets")-1] == '\0' ||
276 cpPath
[sizeof("/assets")-1] == '/'))
277 return lo_apk_lstat(cpPath
, buf
);
280 accessFilePathState
*state
= prepare_to_access_file_path(cpPath
);
282 int result
= stat(cpPath
, buf
);
283 int saved_errno
= errno
;
285 SAL_INFO("sal.file", "stat(" << cpPath
<< "): " << UnixErrnoString(saved_errno
));
287 SAL_INFO("sal.file", "stat(" << cpPath
<< "): OK");
289 done_accessing_file_path(cpPath
, state
);
296 int lstat_c(const char* cpPath
, struct stat
* buf
)
299 if (strncmp(cpPath
, "/assets", sizeof("/assets")-1) == 0 &&
300 (cpPath
[sizeof("/assets")-1] == '\0' ||
301 cpPath
[sizeof("/assets")-1] == '/'))
302 return lo_apk_lstat(cpPath
, buf
);
305 accessFilePathState
*state
= prepare_to_access_file_path(cpPath
);
307 int result
= lstat(cpPath
, buf
);
308 int saved_errno
= errno
;
310 SAL_INFO("sal.file", "lstat(" << cpPath
<< "): " << UnixErrnoString(saved_errno
));
312 SAL_INFO("sal.file", "lstat(" << cpPath
<< "): OK");
314 done_accessing_file_path(cpPath
, state
);
323 template<typename T
> int lstat_(const T
& pstrPath
, struct stat
& buf
)
325 OString fn
= toOString(pstrPath
);
328 fn
= macxp_resolveAliasAndConvert(fn
);
331 return lstat_c(fn
.getStr(), &buf
);
336 int osl::lstat(const OUString
& pustrPath
, struct stat
& buf
)
338 return lstat_(pustrPath
, buf
);
341 int osl::lstat(const OString
& pstrPath
, struct stat
& buf
)
343 return lstat_(pstrPath
, buf
);
346 int osl::mkdir(const OString
& path
, mode_t mode
)
348 accessFilePathState
*state
= prepare_to_access_file_path(path
.getStr());
350 int result
= ::mkdir(path
.getStr(), mode
);
351 int saved_errno
= errno
;
353 SAL_INFO("sal.file", "mkdir(" << path
<< ",0" << std::oct
<< mode
<< std::dec
<< "): " << UnixErrnoString(saved_errno
));
355 SAL_INFO("sal.file", "mkdir(" << path
<< ",0" << std::oct
<< mode
<< std::dec
<< "): OK");
357 done_accessing_file_path(path
.getStr(), state
);
364 int open_c(const OString
& path
, int oflag
, int mode
)
366 accessFilePathState
*state
= prepare_to_access_file_path(path
.getStr());
368 int result
= open(path
.getStr(), oflag
, mode
);
369 int saved_errno
= errno
;
371 SAL_INFO("sal.file", "open(" << path
<< ",0" << std::oct
<< oflag
<< ",0" << mode
<< std::dec
<< "): " << UnixErrnoString(saved_errno
));
373 SAL_INFO("sal.file", "open(" << path
<< ",0" << std::oct
<< oflag
<< ",0" << mode
<< std::dec
<< ") => " << result
);
375 #if HAVE_FEATURE_MACOSX_SANDBOX
376 if (isSandboxed
&& result
!= -1 && (oflag
& O_CREAT
) && (oflag
& O_EXCL
))
378 // A new file was created. Check if it is outside the sandbox.
379 // (In that case it must be one the user selected as export or
380 // save destination in a file dialog, otherwise we wouldn't
381 // have been able to create it.) Create and store a security
382 // scoped bookmark for it so that we can access the file in
383 // the future, too. (For the "Recent Files" functionality.)
384 const char *sandbox
= [NSHomeDirectory() UTF8String
];
385 if (!(strncmp(sandbox
, path
.getStr(), strlen(sandbox
)) == 0 &&
386 path
[strlen(sandbox
)] == '/'))
388 auto cpPath
= path
.getStr();
389 NSURL
*url
= [NSURL fileURLWithPath
:[NSString stringWithUTF8String
:cpPath
]];
390 NSData
*data
= [url bookmarkDataWithOptions
:NSURLBookmarkCreationWithSecurityScope
391 includingResourceValuesForKeys
:nil
396 [userDefaults setObject
:data
397 forKey
:[@
"bookmarkFor:" stringByAppendingString
:[url absoluteString
]]];
403 done_accessing_file_path(path
.getStr(), state
);
410 int utime_c(const char *cpPath
, struct utimbuf
*times
)
412 accessFilePathState
*state
= prepare_to_access_file_path(cpPath
);
414 int result
= utime(cpPath
, times
);
416 done_accessing_file_path(cpPath
, state
);
421 int ftruncate_with_name(int fd
, sal_uInt64 uSize
, const OString
& path
)
423 /* When sandboxed on macOS, ftruncate(), even if it takes an
424 * already open file descriptor which was returned from an open()
425 * call already checked by the sandbox, still requires a security
426 * scope bookmark for the file to be active in case the file is
427 * one that the sandbox doesn't otherwise allow access to. Luckily
428 * LibreOffice usually calls ftruncate() through the helpful C++
429 * abstraction layer that keeps the pathname around.
435 fn
= macxp_resolveAliasAndConvert(fn
);
438 accessFilePathState
*state
= prepare_to_access_file_path(fn
.getStr());
440 int result
= ftruncate(fd
, uSize
);
441 int saved_errno
= errno
;
443 SAL_INFO("sal.file", "ftruncate(" << fd
<< "," << uSize
<< "): " << UnixErrnoString(saved_errno
));
445 SAL_INFO("sal.file", "ftruncate(" << fd
<< "," << uSize
<< "): OK");
447 done_accessing_file_path(fn
.getStr(), state
);
455 std::string
UnixErrnoString(int nErrno
)
457 // Errnos from <asm-generic/errno-base.h> and <asm-generic/errno.h> on Linux and <sys/errno.h>
534 return "ENAMETOOLONG";
702 return "EDESTADDRREQ";
708 return "ENOPROTOOPT";
709 case EPROTONOSUPPORT
:
710 return "EPROTONOSUPPORT";
711 #ifdef ESOCKTNOSUPPORT
712 case ESOCKTNOSUPPORT
:
713 return "ESOCKTNOSUPPORT";
720 return "EPFNOSUPPORT";
722 return "EAFNOSUPPORT";
726 return "EADDRNOTAVAIL";
730 return "ENETUNREACH";
734 return "ECONNABORTED";
749 return "ETOOMANYREFS";
754 return "ECONNREFUSED";
760 return "EHOSTUNREACH";
764 return "EINPROGRESS";
795 return "EMEDIUMTYPE";
805 return "EKEYEXPIRED";
809 return "EKEYREVOKED";
813 return "EKEYREJECTED";
819 #ifdef ENOTRECOVERABLE
820 case ENOTRECOVERABLE
:
821 return "ENOTRECOVERABLE";
841 return "ERPCMISMATCH";
845 return "EPROGUNAVAIL";
849 return "EPROGMISMATCH";
853 return "EPROCUNAVAIL";
900 char* str
= strerror(nErrno
);
901 return std::to_string(nErrno
) + " (" + std::string(str
) + ")";
905 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */