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