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>
40 #include <osl/detail/android-bootstrap.h>
43 OString
osl::OUStringToOString(std::u16string_view s
)
45 return rtl::OUStringToOString(s
, osl_getThreadTextEncoding());
48 #if HAVE_FEATURE_MACOSX_SANDBOX
50 #include <Foundation/Foundation.h>
51 #include <Security/Security.h>
52 #include <mach-o/dyld.h>
54 static NSUserDefaults
*userDefaults
= NULL
;
55 static bool isSandboxed
= false;
60 OSStatus rc
= SecCodeCopySelf(kSecCSDefaultFlags
, &code
);
62 SecStaticCodeRef staticCode
;
63 if (rc
== errSecSuccess
)
64 rc
= SecCodeCopyStaticCode(code
, kSecCSDefaultFlags
, &staticCode
);
66 CFDictionaryRef signingInformation
;
67 if (rc
== errSecSuccess
)
68 rc
= SecCodeCopySigningInformation(staticCode
, kSecCSRequirementInformation
, &signingInformation
);
70 CFDictionaryRef entitlements
= NULL
;
71 if (rc
== errSecSuccess
)
72 entitlements
= (CFDictionaryRef
) CFDictionaryGetValue(signingInformation
, kSecCodeInfoEntitlementsDict
);
74 if (entitlements
!= NULL
)
75 if (CFDictionaryGetValue(entitlements
, CFSTR("com.apple.security.app-sandbox")) != NULL
)
79 userDefaults
= [NSUserDefaults standardUserDefaults
];
84 NSAutoreleasePool
*pool
;
85 } accessFilePathState
;
87 static accessFilePathState
*
88 prepare_to_access_file_path( const char *cpFilePath
)
90 static pthread_once_t once
= PTHREAD_ONCE_INIT
;
91 pthread_once(&once
, &do_once
);
95 accessFilePathState
*state
;
100 // If malloc() fails we are screwed anyway
101 state
= (accessFilePathState
*) malloc(sizeof(accessFilePathState
));
103 state
->pool
= [[NSAutoreleasePool alloc
] init
];
104 state
->scopeURL
= nil
;
106 if (userDefaults
!= nil
)
107 fileURL
= [NSURL fileURLWithPath
:[NSString stringWithUTF8String
:cpFilePath
]];
110 data
= [userDefaults dataForKey
:[@
"bookmarkFor:" stringByAppendingString
:[fileURL absoluteString
]]];
113 state
->scopeURL
= [NSURL URLByResolvingBookmarkData
:data
114 options
:NSURLBookmarkResolutionWithSecurityScope
116 bookmarkDataIsStale
:&stale
118 if (state
->scopeURL
!= nil
)
119 [state
->scopeURL startAccessingSecurityScopedResource
];
125 done_accessing_file_path( const char * /*cpFilePath*/, accessFilePathState
*state
)
130 int saved_errno
= errno
;
132 if (state
->scopeURL
!= nil
)
133 [state
->scopeURL stopAccessingSecurityScopedResource
];
134 [state
->pool release
];
142 typedef void accessFilePathState
;
144 #define prepare_to_access_file_path( cpFilePath ) nullptr
146 #define done_accessing_file_path( cpFilePath, state ) ((void) cpFilePath, (void) state)
152 * Helper function for resolving Mac native alias files (not the same as unix alias files)
153 * and to return the resolved alias as OString
155 static OString
macxp_resolveAliasAndConvert(OString
const & p
)
158 if (p
.getLength() < PATH_MAX
)
160 strcpy(path
, p
.getStr());
161 macxp_resolveAlias(path
, PATH_MAX
);
168 int osl::access(const OString
& pstrPath
, int mode
)
170 OString fn
= pstrPath
;
172 if (fn
== "/assets" || fn
.startsWith("/assets/"))
175 if (lo_apk_lstat(fn
.getStr(), &stat
) == -1)
187 fn
= macxp_resolveAliasAndConvert(fn
);
190 accessFilePathState
*state
= prepare_to_access_file_path(fn
.getStr());
192 int result
= ::access(fn
.getStr(), mode
);
193 int saved_errno
= errno
;
195 SAL_INFO("sal.file", "access(" << fn
<< ",0" << std::oct
<< mode
<< std::dec
<< "): " << UnixErrnoString(saved_errno
));
197 SAL_INFO("sal.file", "access(" << fn
<< ",0" << std::oct
<< mode
<< std::dec
<< "): OK");
199 done_accessing_file_path(fn
.getStr(), state
);
208 OString
toOString(OString
const & s
) { return s
; }
210 OString
toOString(std::u16string_view s
) { return osl::OUStringToOString(s
); }
212 template<typename T
> T
fromOString(OString
const &) = delete;
214 template<> OString
fromOString(OString
const & s
) { return s
; }
216 template<> OUString
fromOString(OString
const & s
)
217 { return OStringToOUString(s
, osl_getThreadTextEncoding()); }
219 template<typename T
> bool realpath_(const T
& pstrFileName
, T
& ppstrResolvedName
)
221 OString fn
= toOString(pstrFileName
);
222 #if defined ANDROID || defined(EMSCRIPTEN)
224 if (fn
== "/assets" || fn
.startsWith("/assets/"))
226 if (fn
== "/instdir" || fn
.startsWith("/instdir/"))
229 if (osl::access(fn
, F_OK
) == -1)
232 ppstrResolvedName
= pstrFileName
;
236 #endif // ANDROID || EMSCRIPTEN
239 fn
= macxp_resolveAliasAndConvert(fn
);
242 accessFilePathState
*state
= prepare_to_access_file_path(fn
.getStr());
245 bool bRet
= realpath(fn
.getStr(), rp
);
246 int saved_errno
= errno
;
248 SAL_INFO("sal.file", "realpath(" << fn
<< "): " << UnixErrnoString(saved_errno
));
250 SAL_INFO("sal.file", "realpath(" << fn
<< "): OK");
252 done_accessing_file_path(fn
.getStr(), state
);
256 ppstrResolvedName
= fromOString
<T
>(OString(rp
));
266 bool osl::realpath(const OUString
& pustrFileName
, OUString
& ppustrResolvedName
)
268 return realpath_(pustrFileName
, ppustrResolvedName
);
271 bool osl::realpath(const OString
& pstrFileName
, OString
& ppstrResolvedName
)
273 return realpath_(pstrFileName
, ppstrResolvedName
);
276 int stat_c(const char* cpPath
, struct stat
* buf
)
279 if (strncmp(cpPath
, "/assets", sizeof("/assets")-1) == 0 &&
280 (cpPath
[sizeof("/assets")-1] == '\0' ||
281 cpPath
[sizeof("/assets")-1] == '/'))
282 return lo_apk_lstat(cpPath
, buf
);
285 accessFilePathState
*state
= prepare_to_access_file_path(cpPath
);
287 int result
= stat(cpPath
, buf
);
288 int saved_errno
= errno
;
290 SAL_INFO("sal.file", "stat(" << cpPath
<< "): " << UnixErrnoString(saved_errno
));
292 SAL_INFO("sal.file", "stat(" << cpPath
<< "): OK");
294 done_accessing_file_path(cpPath
, state
);
301 int lstat_c(const char* cpPath
, struct stat
* buf
)
304 if (strncmp(cpPath
, "/assets", sizeof("/assets")-1) == 0 &&
305 (cpPath
[sizeof("/assets")-1] == '\0' ||
306 cpPath
[sizeof("/assets")-1] == '/'))
307 return lo_apk_lstat(cpPath
, buf
);
310 accessFilePathState
*state
= prepare_to_access_file_path(cpPath
);
312 int result
= lstat(cpPath
, buf
);
313 int saved_errno
= errno
;
315 SAL_INFO("sal.file", "lstat(" << cpPath
<< "): " << UnixErrnoString(saved_errno
));
317 SAL_INFO("sal.file", "lstat(" << cpPath
<< "): OK");
319 done_accessing_file_path(cpPath
, state
);
328 template<typename T
> int lstat_(const T
& pstrPath
, struct stat
& buf
)
330 OString fn
= toOString(pstrPath
);
333 fn
= macxp_resolveAliasAndConvert(fn
);
336 return lstat_c(fn
.getStr(), &buf
);
341 int osl::lstat(const OUString
& pustrPath
, struct stat
& buf
)
343 return lstat_(pustrPath
, buf
);
346 int osl::lstat(const OString
& pstrPath
, struct stat
& buf
)
348 return lstat_(pstrPath
, buf
);
351 int osl::mkdir(const OString
& path
, mode_t mode
)
353 accessFilePathState
*state
= prepare_to_access_file_path(path
.getStr());
355 int result
= ::mkdir(path
.getStr(), mode
);
356 int saved_errno
= errno
;
358 SAL_INFO("sal.file", "mkdir(" << path
<< ",0" << std::oct
<< mode
<< std::dec
<< "): " << UnixErrnoString(saved_errno
));
360 SAL_INFO("sal.file", "mkdir(" << path
<< ",0" << std::oct
<< mode
<< std::dec
<< "): OK");
362 done_accessing_file_path(path
.getStr(), state
);
369 int open_c(const OString
& path
, int oflag
, int mode
)
371 accessFilePathState
*state
= prepare_to_access_file_path(path
.getStr());
373 int result
= open(path
.getStr(), oflag
, mode
);
374 int saved_errno
= errno
;
376 SAL_INFO("sal.file", "open(" << path
<< ",0" << std::oct
<< oflag
<< ",0" << mode
<< std::dec
<< "): " << UnixErrnoString(saved_errno
));
378 SAL_INFO("sal.file", "open(" << path
<< ",0" << std::oct
<< oflag
<< ",0" << mode
<< std::dec
<< ") => " << result
);
380 #if HAVE_FEATURE_MACOSX_SANDBOX
381 if (isSandboxed
&& result
!= -1 && (oflag
& O_CREAT
) && (oflag
& O_EXCL
))
383 // A new file was created. Check if it is outside the sandbox.
384 // (In that case it must be one the user selected as export or
385 // save destination in a file dialog, otherwise we wouldn't
386 // have been able to create it.) Create and store a security
387 // scoped bookmark for it so that we can access the file in
388 // the future, too. (For the "Recent Files" functionality.)
389 const char *sandbox
= [NSHomeDirectory() UTF8String
];
390 if (!(strncmp(sandbox
, path
.getStr(), strlen(sandbox
)) == 0 &&
391 path
[strlen(sandbox
)] == '/'))
393 auto cpPath
= path
.getStr();
394 NSURL
*url
= [NSURL fileURLWithPath
:[NSString stringWithUTF8String
:cpPath
]];
395 NSData
*data
= [url bookmarkDataWithOptions
:NSURLBookmarkCreationWithSecurityScope
396 includingResourceValuesForKeys
:nil
401 [userDefaults setObject
:data
402 forKey
:[@
"bookmarkFor:" stringByAppendingString
:[url absoluteString
]]];
408 done_accessing_file_path(path
.getStr(), state
);
415 int utime_c(const char *cpPath
, struct utimbuf
*times
)
417 accessFilePathState
*state
= prepare_to_access_file_path(cpPath
);
419 int result
= utime(cpPath
, times
);
421 done_accessing_file_path(cpPath
, state
);
426 int ftruncate_with_name(int fd
, sal_uInt64 uSize
, const OString
& path
)
428 /* When sandboxed on macOS, ftruncate(), even if it takes an
429 * already open file descriptor which was returned from an open()
430 * call already checked by the sandbox, still requires a security
431 * scope bookmark for the file to be active in case the file is
432 * one that the sandbox doesn't otherwise allow access to. Luckily
433 * LibreOffice usually calls ftruncate() through the helpful C++
434 * abstraction layer that keeps the pathname around.
440 fn
= macxp_resolveAliasAndConvert(fn
);
443 accessFilePathState
*state
= prepare_to_access_file_path(fn
.getStr());
445 int result
= ftruncate(fd
, uSize
);
446 int saved_errno
= errno
;
448 SAL_INFO("sal.file", "ftruncate(" << fd
<< "," << uSize
<< "): " << UnixErrnoString(saved_errno
));
450 SAL_INFO("sal.file", "ftruncate(" << fd
<< "," << uSize
<< "): OK");
452 done_accessing_file_path(fn
.getStr(), state
);
460 std::string
UnixErrnoString(int nErrno
)
462 // Errnos from <asm-generic/errno-base.h> and <asm-generic/errno.h> on Linux and <sys/errno.h>
539 return "ENAMETOOLONG";
707 return "EDESTADDRREQ";
713 return "ENOPROTOOPT";
714 case EPROTONOSUPPORT
:
715 return "EPROTONOSUPPORT";
716 #ifdef ESOCKTNOSUPPORT
717 case ESOCKTNOSUPPORT
:
718 return "ESOCKTNOSUPPORT";
725 return "EPFNOSUPPORT";
727 return "EAFNOSUPPORT";
731 return "EADDRNOTAVAIL";
735 return "ENETUNREACH";
739 return "ECONNABORTED";
754 return "ETOOMANYREFS";
759 return "ECONNREFUSED";
765 return "EHOSTUNREACH";
769 return "EINPROGRESS";
800 return "EMEDIUMTYPE";
810 return "EKEYEXPIRED";
814 return "EKEYREVOKED";
818 return "EKEYREJECTED";
824 #ifdef ENOTRECOVERABLE
825 case ENOTRECOVERABLE
:
826 return "ENOTRECOVERABLE";
846 return "ERPCMISMATCH";
850 return "EPROGUNAVAIL";
854 return "EPROGMISMATCH";
858 return "EPROCUNAVAIL";
905 char* str
= strerror(nErrno
);
906 return std::to_string(nErrno
) + " (" + std::string(str
) + ")";
910 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */