Line data Source code
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 "osl/file.hxx"
21 : #include "osl/detail/file.h"
22 :
23 : #include "osl/diagnose.h"
24 : #include "osl/thread.h"
25 : #include <osl/signal.h>
26 : #include "rtl/alloc.h"
27 :
28 : #include "system.h"
29 : #include "file_impl.hxx"
30 : #include "file_error_transl.h"
31 : #include "file_path_helper.hxx"
32 : #include "file_url.h"
33 : #include "uunxapi.hxx"
34 : #include "readwrite_helper.h"
35 :
36 : #include <sys/types.h>
37 : #include <errno.h>
38 : #include <dirent.h>
39 : #include <limits.h>
40 : #include <stdio.h>
41 : #include <string.h>
42 : #include <unistd.h>
43 : #include <sys/stat.h>
44 : #include <sys/mman.h>
45 :
46 : #include <algorithm>
47 :
48 : #ifdef ANDROID
49 : #include <osl/detail/android-bootstrap.h>
50 : #endif
51 :
52 : /************************************************************************
53 : * TODO
54 : *
55 : * - Fix: check for corresponding struct sizes in exported functions
56 : * - check size/use of oslDirectory
57 : * - check size/use of oslDirectoryItem
58 : ***********************************************************************/
59 :
60 : typedef struct
61 : {
62 : rtl_uString* ustrPath; /* holds native directory path */
63 : DIR* pDirStruct;
64 : #ifdef ANDROID
65 : enum Kind
66 : {
67 : KIND_DIRENT = 1,
68 : KIND_ASSETS = 2
69 : };
70 : int eKind;
71 : lo_apk_dir* pApkDirStruct;
72 : #endif
73 : } oslDirectoryImpl;
74 :
75 1105389 : DirectoryItem_Impl::DirectoryItem_Impl(
76 : rtl_uString * ustrFilePath, unsigned char DType)
77 : : m_RefCount (1),
78 : m_ustrFilePath (ustrFilePath),
79 1105389 : m_DType (DType)
80 : {
81 1105389 : if (m_ustrFilePath != 0)
82 1105389 : rtl_uString_acquire(m_ustrFilePath);
83 1105389 : }
84 1105389 : DirectoryItem_Impl::~DirectoryItem_Impl()
85 : {
86 1105389 : if (m_ustrFilePath != 0)
87 1105389 : rtl_uString_release(m_ustrFilePath);
88 1105389 : }
89 :
90 1105389 : void * DirectoryItem_Impl::operator new(size_t n)
91 : {
92 1105389 : return rtl_allocateMemory(n);
93 : }
94 1105389 : void DirectoryItem_Impl::operator delete(void * p)
95 : {
96 1105389 : rtl_freeMemory(p);
97 1105389 : }
98 :
99 0 : void DirectoryItem_Impl::acquire()
100 : {
101 0 : ++m_RefCount;
102 0 : }
103 1105389 : void DirectoryItem_Impl::release()
104 : {
105 1105389 : if (0 == --m_RefCount)
106 1105389 : delete this;
107 1105389 : }
108 :
109 1062870 : oslFileType DirectoryItem_Impl::getFileType() const
110 : {
111 1062870 : switch (m_DType)
112 : {
113 : #ifdef _DIRENT_HAVE_D_TYPE
114 : case DT_LNK:
115 18 : return osl_File_Type_Link;
116 : case DT_DIR:
117 6 : return osl_File_Type_Directory;
118 : case DT_REG:
119 40 : return osl_File_Type_Regular;
120 : case DT_FIFO:
121 0 : return osl_File_Type_Fifo;
122 : case DT_SOCK:
123 0 : return osl_File_Type_Socket;
124 : case DT_CHR:
125 : case DT_BLK:
126 0 : return osl_File_Type_Special;
127 : #endif /* _DIRENT_HAVE_D_TYPE */
128 : default:
129 1062806 : break;
130 : }
131 1062806 : return osl_File_Type_Unknown;
132 : }
133 :
134 : static oslFileError osl_psz_createDirectory(const sal_Char* pszPath);
135 : static oslFileError osl_psz_removeDirectory(const sal_Char* pszPath);
136 :
137 81 : oslFileError SAL_CALL osl_openDirectory(rtl_uString* ustrDirectoryURL, oslDirectory* pDirectory)
138 : {
139 81 : rtl_uString* ustrSystemPath = NULL;
140 : oslFileError eRet;
141 :
142 : char path[PATH_MAX];
143 :
144 81 : if ((0 == ustrDirectoryURL) || (0 == ustrDirectoryURL->length) || (0 == pDirectory))
145 0 : return osl_File_E_INVAL;
146 :
147 : /* convert file URL to system path */
148 81 : eRet = osl_getSystemPathFromFileURL_Ex(ustrDirectoryURL, &ustrSystemPath);
149 :
150 81 : if( osl_File_E_None != eRet )
151 0 : return eRet;
152 :
153 81 : osl_systemPathRemoveSeparator(ustrSystemPath);
154 :
155 : /* convert unicode path to text */
156 81 : if ( UnicodeToText( path, PATH_MAX, ustrSystemPath->buffer, ustrSystemPath->length )
157 : #ifdef MACOSX
158 : && macxp_resolveAlias( path, PATH_MAX ) == 0
159 : #endif /* MACOSX */
160 : )
161 : {
162 : #ifdef ANDROID
163 : if( strncmp( path, "/assets/", sizeof( "/assets/" ) - 1) == 0 )
164 : {
165 : lo_apk_dir *pdir = lo_apk_opendir( path );
166 :
167 : if( pdir )
168 : {
169 : oslDirectoryImpl* pDirImpl = (oslDirectoryImpl*) rtl_allocateMemory( sizeof(oslDirectoryImpl) );
170 :
171 : if( pDirImpl )
172 : {
173 : pDirImpl->eKind = oslDirectoryImpl::KIND_ASSETS;
174 : pDirImpl->pApkDirStruct = pdir;
175 : pDirImpl->ustrPath = ustrSystemPath;
176 :
177 : *pDirectory = (oslDirectory) pDirImpl;
178 : return osl_File_E_None;
179 : }
180 : else
181 : {
182 : errno = ENOMEM;
183 : lo_apk_closedir( pdir );
184 : }
185 : }
186 : }
187 : else
188 : #endif
189 : {
190 : /* open directory */
191 81 : DIR *pdir = opendir( path );
192 :
193 81 : if( pdir )
194 : {
195 : /* create and initialize impl structure */
196 9 : oslDirectoryImpl* pDirImpl = (oslDirectoryImpl*) rtl_allocateMemory( sizeof(oslDirectoryImpl) );
197 :
198 9 : if( pDirImpl )
199 : {
200 9 : pDirImpl->pDirStruct = pdir;
201 9 : pDirImpl->ustrPath = ustrSystemPath;
202 : #ifdef ANDROID
203 : pDirImpl->eKind = oslDirectoryImpl::KIND_DIRENT;
204 : #endif
205 9 : *pDirectory = (oslDirectory) pDirImpl;
206 9 : return osl_File_E_None;
207 : }
208 : else
209 : {
210 0 : errno = ENOMEM;
211 0 : closedir( pdir );
212 : }
213 : }
214 : else
215 : {
216 : #ifdef DEBUG_OSL_FILE
217 : perror ("osl_openDirectory"); fprintf (stderr, path);
218 : #endif
219 : }
220 : }
221 : }
222 :
223 72 : rtl_uString_release( ustrSystemPath );
224 :
225 72 : return oslTranslateFileError(OSL_FET_ERROR, errno);
226 : }
227 :
228 9 : oslFileError SAL_CALL osl_closeDirectory( oslDirectory Directory )
229 : {
230 9 : oslDirectoryImpl* pDirImpl = (oslDirectoryImpl*) Directory;
231 9 : oslFileError err = osl_File_E_None;
232 :
233 : OSL_ASSERT( Directory );
234 :
235 9 : if( NULL == pDirImpl )
236 0 : return osl_File_E_INVAL;
237 :
238 : #ifdef ANDROID
239 : if( pDirImpl->eKind == oslDirectoryImpl::KIND_ASSETS )
240 : {
241 : if (lo_apk_closedir( pDirImpl->pApkDirStruct ))
242 : err = osl_File_E_IO;
243 : }
244 : else
245 : #endif
246 : {
247 9 : if( closedir( pDirImpl->pDirStruct ) )
248 0 : err = oslTranslateFileError(OSL_FET_ERROR, errno);
249 : }
250 :
251 : /* cleanup members */
252 9 : rtl_uString_release( pDirImpl->ustrPath );
253 :
254 9 : rtl_freeMemory( pDirImpl );
255 :
256 9 : return err;
257 : }
258 :
259 : /**********************************************
260 : * osl_readdir_impl_
261 : *
262 : * readdir wrapper, filters out "." and ".."
263 : * on request
264 : *********************************************/
265 :
266 52 : static struct dirent* osl_readdir_impl_(DIR* pdir, bool bFilterLocalAndParentDir)
267 : {
268 : struct dirent* pdirent;
269 :
270 122 : while ((pdirent = readdir(pdir)) != NULL)
271 : {
272 122 : if (bFilterLocalAndParentDir &&
273 113 : ((0 == strcmp(pdirent->d_name, ".")) || (0 == strcmp(pdirent->d_name, ".."))))
274 18 : continue;
275 : else
276 : break;
277 : }
278 :
279 52 : return pdirent;
280 : }
281 :
282 52 : oslFileError SAL_CALL osl_getNextDirectoryItem(oslDirectory Directory, oslDirectoryItem* pItem, SAL_UNUSED_PARAMETER sal_uInt32 /*uHint*/)
283 : {
284 52 : oslDirectoryImpl* pDirImpl = (oslDirectoryImpl*)Directory;
285 52 : rtl_uString* ustrFileName = NULL;
286 52 : rtl_uString* ustrFilePath = NULL;
287 : struct dirent* pEntry;
288 :
289 : OSL_ASSERT(Directory);
290 : OSL_ASSERT(pItem);
291 :
292 52 : if ((NULL == Directory) || (NULL == pItem))
293 0 : return osl_File_E_INVAL;
294 :
295 : #ifdef ANDROID
296 : if( pDirImpl->eKind == oslDirectoryImpl::KIND_ASSETS )
297 : {
298 : pEntry = lo_apk_readdir(pDirImpl->pApkDirStruct);
299 : }
300 : else
301 : #endif
302 : {
303 52 : pEntry = osl_readdir_impl_(pDirImpl->pDirStruct, true);
304 : }
305 :
306 52 : if (NULL == pEntry)
307 9 : return osl_File_E_NOENT;
308 :
309 : #if defined(MACOSX)
310 :
311 : // convert decomposed filename to precomposed unicode
312 : char composed_name[BUFSIZ];
313 : CFMutableStringRef strRef = CFStringCreateMutable (NULL, 0 );
314 : CFStringAppendCString( strRef, pEntry->d_name, kCFStringEncodingUTF8 ); //UTF8 is default on Mac OSX
315 : CFStringNormalize( strRef, kCFStringNormalizationFormC );
316 : CFStringGetCString( strRef, composed_name, BUFSIZ, kCFStringEncodingUTF8 );
317 : CFRelease( strRef );
318 : rtl_string2UString( &ustrFileName, composed_name, strlen( composed_name),
319 : osl_getThreadTextEncoding(), OSTRING_TO_OUSTRING_CVTFLAGS );
320 :
321 : #else // not MACOSX
322 : /* convert file name to unicode */
323 43 : rtl_string2UString( &ustrFileName, pEntry->d_name, strlen( pEntry->d_name ),
324 86 : osl_getThreadTextEncoding(), OSTRING_TO_OUSTRING_CVTFLAGS );
325 : OSL_ASSERT(ustrFileName != 0);
326 :
327 : #endif
328 :
329 43 : osl_systemPathMakeAbsolutePath(pDirImpl->ustrPath, ustrFileName, &ustrFilePath);
330 43 : rtl_uString_release( ustrFileName );
331 :
332 43 : DirectoryItem_Impl * pImpl = static_cast< DirectoryItem_Impl* >(*pItem);
333 43 : if (0 != pImpl)
334 : {
335 0 : pImpl->release(), pImpl = 0;
336 : }
337 : #ifdef _DIRENT_HAVE_D_TYPE
338 43 : pImpl = new DirectoryItem_Impl(ustrFilePath, pEntry->d_type);
339 : #else
340 : pImpl = new DirectoryItem_Impl(ustrFilePath);
341 : #endif /* _DIRENT_HAVE_D_TYPE */
342 43 : *pItem = pImpl;
343 43 : rtl_uString_release( ustrFilePath );
344 :
345 43 : return osl_File_E_None;
346 : }
347 :
348 1234496 : oslFileError SAL_CALL osl_getDirectoryItem( rtl_uString* ustrFileURL, oslDirectoryItem* pItem )
349 : {
350 1234496 : rtl_uString* ustrSystemPath = NULL;
351 1234496 : oslFileError osl_error = osl_File_E_INVAL;
352 :
353 : OSL_ASSERT((0 != ustrFileURL) && (0 != pItem));
354 1234496 : if ((0 == ustrFileURL) || (0 == ustrFileURL->length) || (0 == pItem))
355 0 : return osl_File_E_INVAL;
356 :
357 1234496 : osl_error = osl_getSystemPathFromFileURL_Ex(ustrFileURL, &ustrSystemPath);
358 1234496 : if (osl_File_E_None != osl_error)
359 72 : return osl_error;
360 :
361 1234424 : osl_systemPathRemoveSeparator(ustrSystemPath);
362 :
363 1234424 : if (-1 == access_u(ustrSystemPath, F_OK))
364 : {
365 129078 : osl_error = oslTranslateFileError(OSL_FET_ERROR, errno);
366 : }
367 : else
368 : {
369 1105346 : *pItem = new DirectoryItem_Impl(ustrSystemPath);
370 : }
371 1234424 : rtl_uString_release(ustrSystemPath);
372 :
373 1234424 : return osl_error;
374 : }
375 :
376 0 : oslFileError SAL_CALL osl_acquireDirectoryItem( oslDirectoryItem Item )
377 : {
378 0 : DirectoryItem_Impl * pImpl = static_cast< DirectoryItem_Impl* >(Item);
379 0 : if (0 == pImpl)
380 0 : return osl_File_E_INVAL;
381 :
382 0 : pImpl->acquire();
383 0 : return osl_File_E_None;
384 : }
385 :
386 1105389 : oslFileError SAL_CALL osl_releaseDirectoryItem( oslDirectoryItem Item )
387 : {
388 1105389 : DirectoryItem_Impl * pImpl = static_cast< DirectoryItem_Impl* >(Item);
389 1105389 : if (0 == pImpl)
390 0 : return osl_File_E_INVAL;
391 :
392 1105389 : pImpl->release();
393 1105389 : return osl_File_E_None;
394 : }
395 :
396 0 : oslFileError SAL_CALL osl_createDirectory( rtl_uString* ustrDirectoryURL )
397 : {
398 : char path[PATH_MAX];
399 : oslFileError eRet;
400 :
401 : OSL_ASSERT( ustrDirectoryURL );
402 :
403 : /* convert directory url to system path */
404 0 : eRet = FileURLToPath( path, PATH_MAX, ustrDirectoryURL );
405 0 : if( eRet != osl_File_E_None )
406 0 : return eRet;
407 :
408 : #ifdef MACOSX
409 : if ( macxp_resolveAlias( path, PATH_MAX ) != 0 )
410 : return oslTranslateFileError( OSL_FET_ERROR, errno );
411 : #endif/* MACOSX */
412 :
413 0 : return osl_psz_createDirectory( path );
414 : }
415 :
416 0 : oslFileError SAL_CALL osl_removeDirectory( rtl_uString* ustrDirectoryURL )
417 : {
418 : char path[PATH_MAX];
419 : oslFileError eRet;
420 :
421 : OSL_ASSERT( ustrDirectoryURL );
422 :
423 : /* convert directory url to system path */
424 0 : eRet = FileURLToPath( path, PATH_MAX, ustrDirectoryURL );
425 0 : if( eRet != osl_File_E_None )
426 0 : return eRet;
427 :
428 : #ifdef MACOSX
429 : if ( macxp_resolveAlias( path, PATH_MAX ) != 0 )
430 : return oslTranslateFileError( OSL_FET_ERROR, errno );
431 : #endif/* MACOSX */
432 :
433 0 : return osl_psz_removeDirectory( path );
434 : }
435 :
436 0 : static oslFileError osl_psz_createDirectory( const sal_Char* pszPath )
437 : {
438 0 : int nRet=0;
439 0 : int mode = S_IRWXU | S_IRWXG | S_IRWXO;
440 :
441 0 : nRet = mkdir(pszPath,mode);
442 :
443 0 : if ( nRet < 0 )
444 : {
445 0 : nRet=errno;
446 0 : return oslTranslateFileError(OSL_FET_ERROR, nRet);
447 : }
448 :
449 0 : return osl_File_E_None;
450 : }
451 :
452 0 : static oslFileError osl_psz_removeDirectory( const sal_Char* pszPath )
453 : {
454 0 : int nRet=0;
455 :
456 0 : nRet = rmdir(pszPath);
457 :
458 0 : if ( nRet < 0 )
459 : {
460 0 : nRet=errno;
461 0 : return oslTranslateFileError(OSL_FET_ERROR, nRet);
462 : }
463 :
464 0 : return osl_File_E_None;
465 : }
466 :
467 1 : static int path_make_parent(sal_Unicode* path)
468 : {
469 1 : int i = rtl_ustr_lastIndexOfChar(path, '/');
470 :
471 1 : if (i > 0)
472 : {
473 1 : *(path + i) = 0;
474 1 : return i;
475 : }
476 : else
477 0 : return 0;
478 : }
479 :
480 4 : static int create_dir_with_callback(
481 : sal_Unicode* directory_path,
482 : oslDirectoryCreationCallbackFunc aDirectoryCreationCallbackFunc,
483 : void* pData)
484 : {
485 4 : int mode = S_IRWXU | S_IRWXG | S_IRWXO;
486 :
487 4 : if (osl::mkdir(directory_path, mode) == 0)
488 : {
489 2 : if (aDirectoryCreationCallbackFunc)
490 : {
491 0 : rtl::OUString url;
492 0 : osl::FileBase::getFileURLFromSystemPath(directory_path, url);
493 0 : aDirectoryCreationCallbackFunc(pData, url.pData);
494 : }
495 2 : return 0;
496 : }
497 2 : return errno;
498 : }
499 :
500 4 : static oslFileError create_dir_recursively_(
501 : sal_Unicode* dir_path,
502 : oslDirectoryCreationCallbackFunc aDirectoryCreationCallbackFunc,
503 : void* pData)
504 : {
505 : OSL_PRECOND((rtl_ustr_getLength(dir_path) > 0) && ((dir_path + (rtl_ustr_getLength(dir_path) - 1)) != (dir_path + rtl_ustr_lastIndexOfChar(dir_path, '/'))), \
506 : "Path must not end with a slash");
507 :
508 : int native_err = create_dir_with_callback(
509 4 : dir_path, aDirectoryCreationCallbackFunc, pData);
510 :
511 4 : if (native_err == 0)
512 2 : return osl_File_E_None;
513 :
514 2 : if (native_err != ENOENT)
515 1 : return oslTranslateFileError(OSL_FET_ERROR, native_err);
516 :
517 : // we step back until '/a_dir' at maximum because
518 : // we should get an error unequal ENOENT when
519 : // we try to create 'a_dir' at '/' and would so
520 : // return before
521 1 : int pos = path_make_parent(dir_path);
522 :
523 : oslFileError osl_error = create_dir_recursively_(
524 1 : dir_path, aDirectoryCreationCallbackFunc, pData);
525 :
526 1 : if (osl_File_E_None != osl_error)
527 0 : return osl_error;
528 :
529 1 : dir_path[pos] = '/';
530 :
531 1 : return create_dir_recursively_(dir_path, aDirectoryCreationCallbackFunc, pData);
532 : }
533 :
534 2 : oslFileError SAL_CALL osl_createDirectoryPath(
535 : rtl_uString* aDirectoryUrl,
536 : oslDirectoryCreationCallbackFunc aDirectoryCreationCallbackFunc,
537 : void* pData)
538 : {
539 2 : if (aDirectoryUrl == NULL)
540 0 : return osl_File_E_INVAL;
541 :
542 2 : rtl::OUString sys_path;
543 2 : oslFileError osl_error = osl_getSystemPathFromFileURL_Ex(aDirectoryUrl, &sys_path.pData);
544 :
545 2 : if (osl_error != osl_File_E_None)
546 0 : return osl_error;
547 :
548 2 : osl::systemPathRemoveSeparator(sys_path);
549 :
550 : // const_cast because sys_path is a local copy which we want to modify inplace instead of
551 : // coyp it into another buffer on the heap again
552 2 : return create_dir_recursively_(sys_path.pData->buffer, aDirectoryCreationCallbackFunc, pData);
553 : }
554 :
555 : static oslFileError osl_psz_removeFile(const sal_Char* pszPath);
556 : static oslFileError osl_psz_copyFile(const sal_Char* pszPath, const sal_Char* pszDestPath);
557 : static oslFileError osl_psz_moveFile(const sal_Char* pszPath, const sal_Char* pszDestPath);
558 :
559 : static oslFileError oslDoCopy(const sal_Char* pszSourceFileName, const sal_Char* pszDestFileName, mode_t nMode, size_t nSourceSize, int DestFileExists);
560 : static oslFileError oslChangeFileModes(const sal_Char* pszFileName, mode_t nMode, time_t nAcTime, time_t nModTime, uid_t nUID, gid_t nGID);
561 : static int oslDoCopyLink(const sal_Char* pszSourceFileName, const sal_Char* pszDestFileName);
562 : static int oslDoCopyFile(const sal_Char* pszSourceFileName, const sal_Char* pszDestFileName, size_t nSourceSize, mode_t mode);
563 : static oslFileError oslDoMoveFile(const sal_Char* pszPath, const sal_Char* pszDestPath);
564 :
565 1 : oslFileError SAL_CALL osl_moveFile( rtl_uString* ustrFileURL, rtl_uString* ustrDestURL )
566 : {
567 : char srcPath[PATH_MAX];
568 : char destPath[PATH_MAX];
569 : oslFileError eRet;
570 :
571 : OSL_ASSERT( ustrFileURL );
572 : OSL_ASSERT( ustrDestURL );
573 :
574 : /* convert source url to system path */
575 1 : eRet = FileURLToPath( srcPath, PATH_MAX, ustrFileURL );
576 1 : if( eRet != osl_File_E_None )
577 0 : return eRet;
578 :
579 : /* convert destination url to system path */
580 1 : eRet = FileURLToPath( destPath, PATH_MAX, ustrDestURL );
581 1 : if( eRet != osl_File_E_None )
582 0 : return eRet;
583 :
584 : #ifdef MACOSX
585 : if ( macxp_resolveAlias( srcPath, PATH_MAX ) != 0 || macxp_resolveAlias( destPath, PATH_MAX ) != 0 )
586 : return oslTranslateFileError( OSL_FET_ERROR, errno );
587 : #endif/* MACOSX */
588 :
589 1 : return oslDoMoveFile( srcPath, destPath );
590 : }
591 :
592 0 : oslFileError SAL_CALL osl_copyFile( rtl_uString* ustrFileURL, rtl_uString* ustrDestURL )
593 : {
594 : char srcPath[PATH_MAX];
595 : char destPath[PATH_MAX];
596 : oslFileError eRet;
597 :
598 : OSL_ASSERT( ustrFileURL );
599 : OSL_ASSERT( ustrDestURL );
600 :
601 : /* convert source url to system path */
602 0 : eRet = FileURLToPath( srcPath, PATH_MAX, ustrFileURL );
603 0 : if( eRet != osl_File_E_None )
604 0 : return eRet;
605 :
606 : /* convert destination url to system path */
607 0 : eRet = FileURLToPath( destPath, PATH_MAX, ustrDestURL );
608 0 : if( eRet != osl_File_E_None )
609 0 : return eRet;
610 :
611 : #ifdef MACOSX
612 : if ( macxp_resolveAlias( srcPath, PATH_MAX ) != 0 || macxp_resolveAlias( destPath, PATH_MAX ) != 0 )
613 : return oslTranslateFileError( OSL_FET_ERROR, errno );
614 : #endif/* MACOSX */
615 :
616 0 : return osl_psz_copyFile( srcPath, destPath );
617 : }
618 :
619 0 : oslFileError SAL_CALL osl_removeFile( rtl_uString* ustrFileURL )
620 : {
621 : char path[PATH_MAX];
622 : oslFileError eRet;
623 :
624 : OSL_ASSERT( ustrFileURL );
625 :
626 : /* convert file url to system path */
627 0 : eRet = FileURLToPath( path, PATH_MAX, ustrFileURL );
628 0 : if( eRet != osl_File_E_None )
629 0 : return eRet;
630 :
631 : #ifdef MACOSX
632 : if ( macxp_resolveAlias( path, PATH_MAX ) != 0 )
633 : return oslTranslateFileError( OSL_FET_ERROR, errno );
634 : #endif/* MACOSX */
635 :
636 0 : return osl_psz_removeFile( path );
637 : }
638 :
639 1 : static oslFileError oslDoMoveFile( const sal_Char* pszPath, const sal_Char* pszDestPath)
640 : {
641 1 : oslFileError tErr = osl_psz_moveFile(pszPath,pszDestPath);
642 1 : if ( tErr == osl_File_E_None )
643 : {
644 1 : return tErr;
645 : }
646 :
647 0 : if ( tErr != osl_File_E_XDEV )
648 : {
649 0 : return tErr;
650 : }
651 :
652 0 : tErr=osl_psz_copyFile(pszPath,pszDestPath);
653 :
654 0 : if ( tErr != osl_File_E_None )
655 : {
656 0 : osl_psz_removeFile(pszDestPath);
657 0 : return tErr;
658 : }
659 :
660 0 : tErr=osl_psz_removeFile(pszPath);
661 :
662 0 : return tErr;
663 : }
664 :
665 0 : static oslFileError osl_psz_removeFile( const sal_Char* pszPath )
666 : {
667 0 : int nRet=0;
668 : struct stat aStat;
669 :
670 0 : nRet = lstat_c(pszPath,&aStat);
671 0 : if ( nRet < 0 )
672 : {
673 0 : nRet=errno;
674 0 : return oslTranslateFileError(OSL_FET_ERROR, nRet);
675 : }
676 :
677 0 : if ( S_ISDIR(aStat.st_mode) )
678 : {
679 0 : return osl_File_E_ISDIR;
680 : }
681 :
682 0 : nRet = unlink(pszPath);
683 0 : if ( nRet < 0 )
684 : {
685 0 : nRet=errno;
686 0 : return oslTranslateFileError(OSL_FET_ERROR, nRet);
687 : }
688 :
689 0 : return osl_File_E_None;
690 : }
691 :
692 1 : static oslFileError osl_psz_moveFile(const sal_Char* pszPath, const sal_Char* pszDestPath)
693 : {
694 1 : int nRet = 0;
695 :
696 1 : nRet = rename(pszPath,pszDestPath);
697 :
698 1 : if ( nRet < 0 )
699 : {
700 0 : nRet=errno;
701 0 : return oslTranslateFileError(OSL_FET_ERROR, nRet);
702 : }
703 :
704 1 : return osl_File_E_None;
705 : }
706 :
707 0 : static oslFileError osl_psz_copyFile( const sal_Char* pszPath, const sal_Char* pszDestPath )
708 : {
709 0 : time_t nAcTime=0;
710 0 : time_t nModTime=0;
711 0 : uid_t nUID=0;
712 0 : gid_t nGID=0;
713 0 : int nRet=0;
714 0 : mode_t nMode=0;
715 : struct stat aFileStat;
716 0 : oslFileError tErr=osl_File_E_invalidError;
717 0 : size_t nSourceSize=0;
718 0 : int DestFileExists=1;
719 :
720 : /* mfe: does the source file really exists? */
721 0 : nRet = lstat_c(pszPath,&aFileStat);
722 :
723 0 : if ( nRet < 0 )
724 : {
725 0 : nRet=errno;
726 0 : return oslTranslateFileError(OSL_FET_ERROR, nRet);
727 : }
728 :
729 : /* mfe: we do only copy files here! */
730 0 : if ( S_ISDIR(aFileStat.st_mode) )
731 : {
732 0 : return osl_File_E_ISDIR;
733 : }
734 :
735 0 : nSourceSize=(size_t)aFileStat.st_size;
736 0 : nMode=aFileStat.st_mode;
737 0 : nAcTime=aFileStat.st_atime;
738 0 : nModTime=aFileStat.st_mtime;
739 0 : nUID=aFileStat.st_uid;
740 0 : nGID=aFileStat.st_gid;
741 :
742 0 : nRet = stat_c(pszDestPath,&aFileStat);
743 0 : if ( nRet < 0 )
744 : {
745 0 : nRet=errno;
746 :
747 0 : if ( nRet == ENOENT )
748 : {
749 0 : DestFileExists=0;
750 : }
751 : }
752 :
753 : /* mfe: the destination file must not be a directory! */
754 0 : if ( nRet == 0 && S_ISDIR(aFileStat.st_mode) )
755 : {
756 0 : return osl_File_E_ISDIR;
757 : }
758 : else
759 : {
760 : /* mfe: file does not exists or is no dir */
761 : }
762 :
763 0 : tErr = oslDoCopy(pszPath,pszDestPath,nMode,nSourceSize,DestFileExists);
764 :
765 0 : if ( tErr != osl_File_E_None )
766 : {
767 0 : return tErr;
768 : }
769 :
770 : /*
771 : * mfe: ignore return code
772 : * since only the success of the copy is
773 : * important
774 : */
775 0 : oslChangeFileModes(pszDestPath,nMode,nAcTime,nModTime,nUID,nGID);
776 :
777 0 : return tErr;
778 : }
779 :
780 : #define TMP_DEST_FILE_EXTENSION ".osl-tmp"
781 :
782 0 : static oslFileError oslDoCopy(const sal_Char* pszSourceFileName, const sal_Char* pszDestFileName, mode_t nMode, size_t nSourceSize, int DestFileExists)
783 : {
784 0 : int nRet=0;
785 : sal_Char pszTmpDestFile[PATH_MAX];
786 0 : size_t size_tmp_dest_buff = sizeof(pszTmpDestFile);
787 :
788 : /* Quick fix for #106048, the whole copy file function seems
789 : to be erroneous anyway and needs to be rewritten.
790 : */
791 0 : memset(pszTmpDestFile, 0, size_tmp_dest_buff);
792 :
793 0 : if ( DestFileExists )
794 : {
795 0 : strncpy(pszTmpDestFile, pszDestFileName, size_tmp_dest_buff - 1);
796 :
797 0 : if ((strlen(pszTmpDestFile) + strlen(TMP_DEST_FILE_EXTENSION)) >= size_tmp_dest_buff)
798 0 : return osl_File_E_NAMETOOLONG;
799 :
800 0 : strncat(pszTmpDestFile, TMP_DEST_FILE_EXTENSION, strlen(TMP_DEST_FILE_EXTENSION));
801 :
802 : /* FIXME: what if pszTmpDestFile already exists? */
803 : /* with getcanonical??? */
804 0 : nRet=rename(pszDestFileName,pszTmpDestFile);
805 : }
806 :
807 : /* mfe: should be S_ISREG */
808 0 : if ( !S_ISLNK(nMode) )
809 : {
810 : /* copy SourceFile to DestFile */
811 0 : nRet = oslDoCopyFile(pszSourceFileName,pszDestFileName,nSourceSize, nMode);
812 : }
813 : /* mfe: OK redundant at the moment */
814 0 : else if ( S_ISLNK(nMode) )
815 : {
816 0 : nRet = oslDoCopyLink(pszSourceFileName,pszDestFileName);
817 : }
818 : else
819 : {
820 : /* mfe: what to do here? */
821 0 : nRet=ENOSYS;
822 : }
823 :
824 0 : if ( nRet > 0 && DestFileExists == 1 )
825 : {
826 0 : unlink(pszDestFileName);
827 0 : rename(pszTmpDestFile,pszDestFileName);
828 : }
829 :
830 0 : if ( nRet > 0 )
831 : {
832 0 : return oslTranslateFileError(OSL_FET_ERROR, nRet);
833 : }
834 :
835 0 : if ( DestFileExists == 1 )
836 : {
837 0 : unlink(pszTmpDestFile);
838 : }
839 :
840 0 : return osl_File_E_None;
841 : }
842 :
843 0 : static oslFileError oslChangeFileModes( const sal_Char* pszFileName, mode_t nMode, time_t nAcTime, time_t nModTime, uid_t nUID, gid_t nGID)
844 : {
845 0 : int nRet=0;
846 : struct utimbuf aTimeBuffer;
847 :
848 0 : nRet = chmod(pszFileName,nMode);
849 0 : if ( nRet < 0 )
850 : {
851 0 : nRet=errno;
852 0 : return oslTranslateFileError(OSL_FET_ERROR, nRet);
853 : }
854 :
855 0 : aTimeBuffer.actime=nAcTime;
856 0 : aTimeBuffer.modtime=nModTime;
857 0 : nRet=utime(pszFileName,&aTimeBuffer);
858 0 : if ( nRet < 0 )
859 : {
860 0 : nRet=errno;
861 0 : return oslTranslateFileError(OSL_FET_ERROR, nRet);
862 : }
863 :
864 0 : if ( nUID != getuid() )
865 : {
866 0 : nUID=getuid();
867 : }
868 :
869 0 : nRet=chown(pszFileName,nUID,nGID);
870 0 : if ( nRet < 0 )
871 : {
872 0 : nRet=errno;
873 :
874 : /* mfe: do not return an error here! */
875 : /* return oslTranslateFileError(nRet);*/
876 : }
877 :
878 0 : return osl_File_E_None;
879 : }
880 :
881 0 : static int oslDoCopyLink(const sal_Char* pszSourceFileName, const sal_Char* pszDestFileName)
882 : {
883 0 : int nRet=0;
884 :
885 : /* mfe: if dest file is symbolic link remove the link and place the file instead (hro says so) */
886 : /* mfe: if source is a link copy the link and not the file it points to (hro says so) */
887 : sal_Char pszLinkContent[PATH_MAX+1];
888 :
889 0 : pszLinkContent[0] = '\0';
890 :
891 0 : nRet = readlink(pszSourceFileName,pszLinkContent,PATH_MAX);
892 :
893 0 : if ( nRet < 0 )
894 : {
895 0 : nRet=errno;
896 0 : return nRet;
897 : }
898 : else
899 0 : pszLinkContent[ nRet ] = 0;
900 :
901 0 : nRet = symlink(pszLinkContent,pszDestFileName);
902 :
903 0 : if ( nRet < 0 )
904 : {
905 0 : nRet=errno;
906 0 : return nRet;
907 : }
908 :
909 0 : return 0;
910 : }
911 :
912 0 : static int oslDoCopyFile(const sal_Char* pszSourceFileName, const sal_Char* pszDestFileName, size_t nSourceSize, mode_t mode)
913 : {
914 0 : oslFileHandle SourceFileFH=0;
915 0 : int DestFileFD=0;
916 0 : int nRet=0;
917 :
918 0 : if (osl_openFilePath(pszSourceFileName,
919 : &SourceFileFH,
920 0 : osl_File_OpenFlag_Read|osl_File_OpenFlag_NoLock|osl_File_OpenFlag_NoExcl) != osl_File_E_None)
921 : {
922 : // Let's hope errno is still set relevantly after osl_openFilePath...
923 0 : nRet=errno;
924 0 : return nRet;
925 : }
926 :
927 0 : DestFileFD=open(pszDestFileName, O_WRONLY | O_CREAT, mode);
928 :
929 0 : if ( DestFileFD < 0 )
930 : {
931 0 : nRet=errno;
932 0 : osl_closeFile(SourceFileFH);
933 0 : return nRet;
934 : }
935 :
936 0 : size_t nRemains = nSourceSize;
937 :
938 0 : if ( nRemains )
939 : {
940 : /* mmap has problems, try the direct streaming */
941 : char pBuffer[0x7FFF];
942 :
943 0 : do
944 : {
945 0 : size_t nToRead = std::min( sizeof(pBuffer), nRemains );
946 : sal_uInt64 nRead;
947 : bool succeeded;
948 0 : if ( osl_readFile( SourceFileFH, pBuffer, nToRead, &nRead ) != osl_File_E_None || nRead > nToRead || nRead == 0 )
949 0 : break;
950 :
951 0 : succeeded = safeWrite( DestFileFD, pBuffer, nRead );
952 0 : if ( !succeeded )
953 0 : break;
954 :
955 : // We know nRead <= nToRead, so it must fit in a size_t
956 0 : nRemains -= (size_t) nRead;
957 : }
958 : while( nRemains );
959 : }
960 :
961 0 : if ( nRemains )
962 : {
963 0 : if ( errno )
964 0 : nRet = errno;
965 : else
966 0 : nRet = ENOSPC;
967 : }
968 :
969 0 : osl_closeFile( SourceFileFH );
970 0 : if ( close( DestFileFD ) == -1 && nRet == 0 )
971 0 : nRet = errno;
972 :
973 0 : return nRet;
974 : }
975 :
976 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|