Line data Source code
1 : /* -*- Mode: ObjC; 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 <config_features.h>
21 :
22 : #include "uunxapi.h"
23 : #include "system.h"
24 : #include <limits.h>
25 : #include <rtl/ustring.hxx>
26 : #include <osl/thread.h>
27 :
28 : #ifdef ANDROID
29 : #include <osl/detail/android-bootstrap.h>
30 : #endif
31 :
32 1532124 : inline rtl::OString OUStringToOString(const rtl_uString* s)
33 : {
34 : return rtl::OUStringToOString(rtl::OUString(const_cast<rtl_uString*>(s)),
35 1532124 : osl_getThreadTextEncoding());
36 : }
37 :
38 : #if defined(MACOSX) && MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 && HAVE_FEATURE_MACOSX_SANDBOX
39 :
40 : static NSUserDefaults *userDefaults = NULL;
41 :
42 : static void get_user_defaults()
43 : {
44 : userDefaults = [NSUserDefaults standardUserDefaults];
45 : }
46 :
47 : typedef struct {
48 : NSURL *scopeURL;
49 : NSAutoreleasePool *pool;
50 : } accessFilePathState;
51 :
52 : static accessFilePathState *
53 : prepare_to_access_file_path( const char *cpFilePath )
54 : {
55 : static pthread_once_t once = PTHREAD_ONCE_INIT;
56 : pthread_once(&once, &get_user_defaults);
57 : NSURL *fileURL = nil;
58 : NSData *data = nil;
59 : BOOL stale;
60 : accessFilePathState *state;
61 :
62 : // If malloc() fails we are screwed anyway
63 : state = (accessFilePathState*) malloc(sizeof(accessFilePathState));
64 :
65 : state->pool = [[NSAutoreleasePool alloc] init];
66 : state->scopeURL = nil;
67 :
68 : if (userDefaults != nil)
69 : fileURL = [NSURL fileURLWithPath:[NSString stringWithUTF8String:cpFilePath]];
70 :
71 : if (fileURL != nil)
72 : data = [userDefaults dataForKey:[@"bookmarkFor:" stringByAppendingString:[fileURL absoluteString]]];
73 :
74 : if (data != nil)
75 : state->scopeURL = [NSURL URLByResolvingBookmarkData:data
76 : options:NSURLBookmarkResolutionWithSecurityScope
77 : relativeToURL:nil
78 : bookmarkDataIsStale:&stale
79 : error:nil];
80 : if (state->scopeURL != nil)
81 : [state->scopeURL startAccessingSecurityScopedResource];
82 :
83 : return state;
84 : }
85 :
86 : static void
87 : done_accessing_file_path( const char * /*cpFilePath*/, accessFilePathState *state )
88 : {
89 : int saved_errno = errno;
90 :
91 : if (state->scopeURL != nil)
92 : [state->scopeURL stopAccessingSecurityScopedResource];
93 : [state->pool release];
94 : free(state);
95 :
96 : errno = saved_errno;
97 : }
98 :
99 : #else
100 :
101 : typedef void accessFilePathState;
102 :
103 : #define prepare_to_access_file_path( cpFilePath ) NULL
104 :
105 : #define done_accessing_file_path( cpFilePath, state ) ((void) cpFilePath, (void) state)
106 :
107 : #endif
108 :
109 : #ifdef MACOSX
110 : /*
111 : * Helper function for resolving Mac native alias files (not the same as unix alias files)
112 : * and to return the resolved alias as rtl::OString
113 : */
114 : static rtl::OString macxp_resolveAliasAndConvert(rtl::OString const & p)
115 : {
116 : sal_Char path[PATH_MAX];
117 : if (p.getLength() < PATH_MAX)
118 : {
119 : strcpy(path, p.getStr());
120 : macxp_resolveAlias(path, PATH_MAX);
121 : return rtl::OString(path);
122 : }
123 : return p;
124 : }
125 : #endif /* MACOSX */
126 :
127 1234424 : int access_u(const rtl_uString* pustrPath, int mode)
128 : {
129 1234424 : rtl::OString fn = OUStringToOString(pustrPath);
130 : #ifdef ANDROID
131 : if (fn == "/assets" || fn.startsWith("/assets/"))
132 : {
133 : struct stat stat;
134 : if (lo_apk_lstat(fn.getStr(), &stat) == -1)
135 : return -1;
136 : if (mode & W_OK)
137 : {
138 : errno = EACCES;
139 : return -1;
140 : }
141 : return 0;
142 : }
143 : #endif
144 :
145 : #ifdef MACOSX
146 : fn = macxp_resolveAliasAndConvert(fn);
147 : #endif
148 :
149 1234424 : accessFilePathState *state = prepare_to_access_file_path(fn.getStr());
150 :
151 1234424 : int result = access(fn.getStr(), mode);
152 :
153 1234424 : done_accessing_file_path(fn.getStr(), state);
154 :
155 1234424 : return result;
156 : }
157 :
158 85036 : sal_Bool realpath_u(const rtl_uString* pustrFileName, rtl_uString** ppustrResolvedName)
159 : {
160 85036 : rtl::OString fn = OUStringToOString(pustrFileName);
161 : #ifdef ANDROID
162 : if (fn == "/assets" || fn.startsWith("/assets/"))
163 : {
164 : if (access_u(pustrFileName, F_OK) == -1)
165 : return sal_False;
166 :
167 : rtl_uString silly(*pustrFileName);
168 : rtl_uString_assign(ppustrResolvedName, &silly);
169 :
170 : return sal_True;
171 : }
172 : #endif
173 :
174 : #ifdef MACOSX
175 : fn = macxp_resolveAliasAndConvert(fn);
176 : #endif
177 :
178 85036 : accessFilePathState *state = prepare_to_access_file_path(fn.getStr());
179 :
180 : char rp[PATH_MAX];
181 85036 : bool bRet = realpath(fn.getStr(), rp);
182 :
183 85036 : done_accessing_file_path(fn.getStr(), state);
184 :
185 85036 : if (bRet)
186 : {
187 : rtl::OUString resolved = rtl::OStringToOUString(rtl::OString(static_cast<sal_Char*>(rp)),
188 85036 : osl_getThreadTextEncoding());
189 :
190 85036 : rtl_uString_assign(ppustrResolvedName, resolved.pData);
191 : }
192 85036 : return bRet;
193 : }
194 :
195 0 : int stat_c(const char* cpPath, struct stat* buf)
196 : {
197 : #ifdef ANDROID
198 : if (strncmp(cpPath, "/assets", sizeof("/assets")-1) == 0 &&
199 : (cpPath[sizeof("/assets")-1] == '\0' ||
200 : cpPath[sizeof("/assets")-1] == '/'))
201 : return lo_apk_lstat(cpPath, buf);
202 : #endif
203 :
204 0 : accessFilePathState *state = prepare_to_access_file_path(cpPath);
205 :
206 0 : int result = stat(cpPath, buf);
207 :
208 : done_accessing_file_path(cpPath, state);
209 :
210 0 : return result;
211 : }
212 :
213 212656 : int lstat_c(const char* cpPath, struct stat* buf)
214 : {
215 : #ifdef ANDROID
216 : if (strncmp(cpPath, "/assets", sizeof("/assets")-1) == 0 &&
217 : (cpPath[sizeof("/assets")-1] == '\0' ||
218 : cpPath[sizeof("/assets")-1] == '/'))
219 : return lo_apk_lstat(cpPath, buf);
220 : #endif
221 :
222 212656 : accessFilePathState *state = prepare_to_access_file_path(cpPath);
223 :
224 212656 : int result = lstat(cpPath, buf);
225 :
226 : done_accessing_file_path(cpPath, state);
227 :
228 212656 : return result;
229 : }
230 :
231 212656 : int lstat_u(const rtl_uString* pustrPath, struct stat* buf)
232 : {
233 212656 : rtl::OString fn = OUStringToOString(pustrPath);
234 :
235 : #ifdef MACOSX
236 : fn = macxp_resolveAliasAndConvert(fn);
237 : #endif
238 :
239 212656 : return lstat_c(fn.getStr(), buf);
240 : }
241 :
242 4 : int mkdir_u(const rtl_uString* path, mode_t mode)
243 : {
244 4 : rtl::OString fn = OUStringToOString(path);
245 :
246 4 : accessFilePathState *state = prepare_to_access_file_path(fn.getStr());
247 :
248 4 : int result = mkdir(OUStringToOString(path).getStr(), mode);
249 :
250 4 : done_accessing_file_path(fn.getStr(), state);
251 :
252 4 : return result;
253 : }
254 :
255 255059 : int open_c(const char *cpPath, int oflag, int mode)
256 : {
257 255059 : accessFilePathState *state = prepare_to_access_file_path(cpPath);
258 :
259 255059 : int result = open(cpPath, oflag, mode);
260 :
261 : #if defined(MACOSX) && MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 && HAVE_FEATURE_MACOSX_SANDBOX
262 : if (result != -1 && (oflag & O_CREAT) && (oflag & O_EXCL))
263 : {
264 : // A new file was created. Check if it is outside the sandbox.
265 : // (In that case it must be one the user selected as export or
266 : // save destination in a file dialog, otherwise we wouldn't
267 : // have been able to crete it.) Create and store a security
268 : // scoped bookmark for it so that we can access the file in
269 : // the future, too. (For the "Recent Files" functionality.)
270 : const char *sandbox = [NSHomeDirectory() UTF8String];
271 : if (!(strncmp(sandbox, cpPath, strlen(sandbox)) == 0 &&
272 : cpPath[strlen(sandbox)] == '/'))
273 : {
274 : NSURL *url = [NSURL fileURLWithPath:[NSString stringWithUTF8String:cpPath]];
275 : NSData *data = [url bookmarkDataWithOptions:NSURLBookmarkCreationWithSecurityScope
276 : includingResourceValuesForKeys:nil
277 : relativeToURL:nil
278 : error:nil];
279 : if (data != NULL)
280 : {
281 : [userDefaults setObject:data
282 : forKey:[@"bookmarkFor:" stringByAppendingString:[url absoluteString]]];
283 : }
284 : }
285 : }
286 : #endif
287 :
288 : done_accessing_file_path(cpPath, state);
289 :
290 255059 : return result;
291 : }
292 :
293 0 : int utime_c(const char *cpPath, struct utimbuf *times)
294 : {
295 0 : accessFilePathState *state = prepare_to_access_file_path(cpPath);
296 :
297 0 : int result = utime(cpPath, times);
298 :
299 : done_accessing_file_path(cpPath, state);
300 :
301 0 : return result;
302 : }
303 :
304 0 : int ftruncate_with_name(int fd, sal_uInt64 uSize, rtl_String* path)
305 : {
306 : /* When sandboxed on OS X, ftruncate(), even if it takes an
307 : * already open file descriptor which was retuned from an open()
308 : * call already checked by the sandbox, still requires a security
309 : * scope bookmark for the file to be active in case the file is
310 : * one that the sandbox doesn't otherwise allow access to. Luckily
311 : * LibreOffice usually calls ftruncate() through the helpful C++
312 : * abstraction layer that keeps the pathname around.
313 : */
314 :
315 0 : rtl::OString fn = rtl::OString(path);
316 :
317 : #ifdef MACOSX
318 : fn = macxp_resolveAliasAndConvert(fn);
319 : #endif
320 :
321 0 : accessFilePathState *state = prepare_to_access_file_path(fn.getStr());
322 :
323 0 : int result = ftruncate(fd, uSize);
324 :
325 0 : done_accessing_file_path(fn.getStr(), state);
326 :
327 0 : return result;
328 : }
329 :
330 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|