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 122799 : DirectoryItem_Impl::DirectoryItem_Impl(
81 : rtl_uString * ustrFilePath, unsigned char DType)
82 : : m_RefCount (1),
83 : m_ustrFilePath (ustrFilePath),
84 122799 : m_DType (DType)
85 : {
86 122799 : if (m_ustrFilePath != 0)
87 122799 : rtl_uString_acquire(m_ustrFilePath);
88 122799 : }
89 122799 : DirectoryItem_Impl::~DirectoryItem_Impl()
90 : {
91 122799 : if (m_ustrFilePath != 0)
92 122799 : rtl_uString_release(m_ustrFilePath);
93 122799 : }
94 :
95 122799 : void * DirectoryItem_Impl::operator new(size_t n)
96 : {
97 122799 : return rtl_allocateMemory(n);
98 : }
99 122799 : void DirectoryItem_Impl::operator delete(void * p)
100 : {
101 122799 : rtl_freeMemory(p);
102 122799 : }
103 :
104 0 : void DirectoryItem_Impl::acquire()
105 : {
106 0 : ++m_RefCount;
107 0 : }
108 122799 : void DirectoryItem_Impl::release()
109 : {
110 122799 : if (0 == --m_RefCount)
111 122799 : delete this;
112 122799 : }
113 :
114 142839 : oslFileType DirectoryItem_Impl::getFileType() const
115 : {
116 142839 : switch (m_DType)
117 : {
118 : #ifdef _DIRENT_HAVE_D_TYPE
119 : case DT_LNK:
120 10964 : return osl_File_Type_Link;
121 : case DT_DIR:
122 4598 : return osl_File_Type_Directory;
123 : case DT_REG:
124 46613 : 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 80664 : break;
135 : }
136 80664 : 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 33015 : oslFileError SAL_CALL osl_openDirectory(rtl_uString* ustrDirectoryURL, oslDirectory* pDirectory)
153 : {
154 33015 : rtl_uString* ustrSystemPath = NULL;
155 : oslFileError eRet;
156 :
157 : char path[PATH_MAX];
158 :
159 33015 : if ((0 == ustrDirectoryURL) || (0 == ustrDirectoryURL->length) || (0 == pDirectory))
160 0 : return osl_File_E_INVAL;
161 :
162 : /* convert file URL to system path */
163 33015 : eRet = osl_getSystemPathFromFileURL_Ex(ustrDirectoryURL, &ustrSystemPath, sal_False);
164 :
165 33015 : if( osl_File_E_None != eRet )
166 48 : return eRet;
167 :
168 32967 : osl_systemPathRemoveSeparator(ustrSystemPath);
169 :
170 : /* convert unicode path to text */
171 32967 : 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 32967 : DIR *pdir = opendir( path );
207 :
208 32967 : if( pdir )
209 : {
210 : /* create and initialize impl structure */
211 28292 : oslDirectoryImpl* pDirImpl = (oslDirectoryImpl*) rtl_allocateMemory( sizeof(oslDirectoryImpl) );
212 :
213 28292 : if( pDirImpl )
214 : {
215 28292 : pDirImpl->pDirStruct = pdir;
216 28292 : pDirImpl->ustrPath = ustrSystemPath;
217 : #ifdef ANDROID
218 : pDirImpl->eKind = oslDirectoryImpl::KIND_DIRENT;
219 : #endif
220 28292 : *pDirectory = (oslDirectory) pDirImpl;
221 28292 : 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 4675 : rtl_uString_release( ustrSystemPath );
239 :
240 4675 : return oslTranslateFileError(OSL_FET_ERROR, errno);
241 : }
242 :
243 : /****************************************************************************/
244 : /* osl_closeDirectory */
245 : /****************************************************************************/
246 :
247 28292 : oslFileError SAL_CALL osl_closeDirectory( oslDirectory Directory )
248 : {
249 28292 : oslDirectoryImpl* pDirImpl = (oslDirectoryImpl*) Directory;
250 28292 : oslFileError err = osl_File_E_None;
251 :
252 : OSL_ASSERT( Directory );
253 :
254 28292 : 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 28292 : if( closedir( pDirImpl->pDirStruct ) )
267 0 : err = oslTranslateFileError(OSL_FET_ERROR, errno);
268 : }
269 :
270 : /* cleanup members */
271 28292 : rtl_uString_release( pDirImpl->ustrPath );
272 :
273 28292 : rtl_freeMemory( pDirImpl );
274 :
275 28292 : return err;
276 : }
277 :
278 : /**********************************************
279 : * osl_readdir_impl_
280 : *
281 : * readdir wrapper, filters out "." and ".."
282 : * on request
283 : *********************************************/
284 :
285 58937 : static struct dirent* osl_readdir_impl_(DIR* pdir, sal_Bool bFilterLocalAndParentDir)
286 : {
287 : struct dirent* pdirent;
288 :
289 156570 : while ((pdirent = readdir(pdir)) != NULL)
290 : {
291 156618 : if (bFilterLocalAndParentDir &&
292 137280 : ((0 == strcmp(pdirent->d_name, ".")) || (0 == strcmp(pdirent->d_name, ".."))))
293 38696 : continue;
294 : else
295 : break;
296 : }
297 :
298 58937 : return pdirent;
299 : }
300 :
301 : /****************************************************************************
302 : * osl_getNextDirectoryItem
303 : ***************************************************************************/
304 :
305 58938 : oslFileError SAL_CALL osl_getNextDirectoryItem(oslDirectory Directory, oslDirectoryItem* pItem, SAL_UNUSED_PARAMETER sal_uInt32 /*uHint*/)
306 : {
307 58938 : oslDirectoryImpl* pDirImpl = (oslDirectoryImpl*)Directory;
308 58938 : rtl_uString* ustrFileName = NULL;
309 58938 : rtl_uString* ustrFilePath = NULL;
310 : struct dirent* pEntry;
311 :
312 : OSL_ASSERT(Directory);
313 : OSL_ASSERT(pItem);
314 :
315 58938 : if ((NULL == Directory) || (NULL == pItem))
316 1 : 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 58937 : pEntry = osl_readdir_impl_(pDirImpl->pDirStruct, sal_True);
327 : }
328 :
329 58937 : if (NULL == pEntry)
330 19324 : 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 39613 : rtl_string2UString( &ustrFileName, pEntry->d_name, strlen( pEntry->d_name ),
348 79226 : osl_getThreadTextEncoding(), OSTRING_TO_OUSTRING_CVTFLAGS );
349 : OSL_ASSERT(ustrFileName != 0);
350 :
351 : #endif
352 :
353 39613 : osl_systemPathMakeAbsolutePath(pDirImpl->ustrPath, ustrFileName, &ustrFilePath);
354 39613 : rtl_uString_release( ustrFileName );
355 :
356 39613 : DirectoryItem_Impl * pImpl = static_cast< DirectoryItem_Impl* >(*pItem);
357 39613 : if (0 != pImpl)
358 : {
359 0 : pImpl->release(), pImpl = 0;
360 : }
361 : #ifdef _DIRENT_HAVE_D_TYPE
362 39613 : pImpl = new DirectoryItem_Impl(ustrFilePath, pEntry->d_type);
363 : #else
364 : pImpl = new DirectoryItem_Impl(ustrFilePath);
365 : #endif /* _DIRENT_HAVE_D_TYPE */
366 39613 : *pItem = pImpl;
367 39613 : rtl_uString_release( ustrFilePath );
368 :
369 39613 : return osl_File_E_None;
370 : }
371 :
372 : /****************************************************************************/
373 : /* osl_getDirectoryItem */
374 : /****************************************************************************/
375 :
376 306727 : oslFileError SAL_CALL osl_getDirectoryItem( rtl_uString* ustrFileURL, oslDirectoryItem* pItem )
377 : {
378 306727 : rtl_uString* ustrSystemPath = NULL;
379 306727 : oslFileError osl_error = osl_File_E_INVAL;
380 :
381 : OSL_ASSERT((0 != ustrFileURL) && (0 != pItem));
382 306727 : if ((0 == ustrFileURL) || (0 == ustrFileURL->length) || (0 == pItem))
383 32 : return osl_File_E_INVAL;
384 :
385 306695 : osl_error = osl_getSystemPathFromFileURL_Ex(ustrFileURL, &ustrSystemPath, sal_False);
386 306695 : if (osl_File_E_None != osl_error)
387 152 : return osl_error;
388 :
389 306543 : osl_systemPathRemoveSeparator(ustrSystemPath);
390 :
391 306543 : if (-1 == access_u(ustrSystemPath, F_OK))
392 : {
393 223357 : osl_error = oslTranslateFileError(OSL_FET_ERROR, errno);
394 : }
395 : else
396 : {
397 83186 : *pItem = new DirectoryItem_Impl(ustrSystemPath);
398 : }
399 306543 : rtl_uString_release(ustrSystemPath);
400 :
401 306543 : 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 122799 : oslFileError SAL_CALL osl_releaseDirectoryItem( oslDirectoryItem Item )
424 : {
425 122799 : DirectoryItem_Impl * pImpl = static_cast< DirectoryItem_Impl* >(Item);
426 122799 : if (0 == pImpl)
427 0 : return osl_File_E_INVAL;
428 :
429 122799 : pImpl->release();
430 122799 : return osl_File_E_None;
431 : }
432 :
433 : /****************************************************************************/
434 : /* osl_createDirectory */
435 : /****************************************************************************/
436 :
437 2687 : 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 2687 : eRet = FileURLToPath( path, PATH_MAX, ustrDirectoryURL );
446 2687 : if( eRet != osl_File_E_None )
447 1 : 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 2686 : return osl_psz_createDirectory( path );
455 : }
456 :
457 : /****************************************************************************/
458 : /* osl_removeDirectory */
459 : /****************************************************************************/
460 :
461 479 : 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 479 : eRet = FileURLToPath( path, PATH_MAX, ustrDirectoryURL );
470 479 : if( eRet != osl_File_E_None )
471 1 : 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 478 : return osl_psz_removeDirectory( path );
479 : }
480 :
481 : /*****************************************
482 : * osl_psz_createDirectory
483 : ****************************************/
484 :
485 2686 : static oslFileError osl_psz_createDirectory( const sal_Char* pszPath )
486 : {
487 2686 : int nRet=0;
488 2686 : int mode = S_IRWXU | S_IRWXG | S_IRWXO;
489 :
490 2686 : nRet = mkdir(pszPath,mode);
491 :
492 2686 : if ( nRet < 0 )
493 : {
494 373 : nRet=errno;
495 373 : return oslTranslateFileError(OSL_FET_ERROR, nRet);
496 : }
497 :
498 2313 : return osl_File_E_None;
499 : }
500 :
501 : /*****************************************
502 : * osl_psz_removeDirectory
503 : ****************************************/
504 :
505 478 : static oslFileError osl_psz_removeDirectory( const sal_Char* pszPath )
506 : {
507 478 : int nRet=0;
508 :
509 478 : nRet = rmdir(pszPath);
510 :
511 478 : if ( nRet < 0 )
512 : {
513 7 : nRet=errno;
514 7 : return oslTranslateFileError(OSL_FET_ERROR, nRet);
515 : }
516 :
517 471 : return osl_File_E_None;
518 : }
519 :
520 : /****************************************************************************/
521 : /* osl_createDirectoryPath */
522 : /****************************************************************************/
523 :
524 36 : static int path_make_parent(sal_Unicode* path)
525 : {
526 36 : int i = rtl_ustr_lastIndexOfChar(path, '/');
527 :
528 36 : if (i > 0)
529 : {
530 36 : *(path + i) = 0;
531 36 : return i;
532 : }
533 : else
534 0 : return 0;
535 : }
536 :
537 1662 : static int create_dir_with_callback(
538 : sal_Unicode* directory_path,
539 : oslDirectoryCreationCallbackFunc aDirectoryCreationCallbackFunc,
540 : void* pData)
541 : {
542 1662 : int mode = S_IRWXU | S_IRWXG | S_IRWXO;
543 :
544 1662 : if (osl::mkdir(directory_path, mode) == 0)
545 : {
546 71 : if (aDirectoryCreationCallbackFunc)
547 : {
548 2 : rtl::OUString url;
549 2 : osl::FileBase::getFileURLFromSystemPath(directory_path, url);
550 2 : aDirectoryCreationCallbackFunc(pData, url.pData);
551 : }
552 71 : return 0;
553 : }
554 1591 : return errno;
555 : }
556 :
557 1662 : 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 1662 : dir_path, aDirectoryCreationCallbackFunc, pData);
567 :
568 1662 : if (native_err == 0)
569 71 : return osl_File_E_None;
570 :
571 1591 : if (native_err != ENOENT)
572 1555 : 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 36 : int pos = path_make_parent(dir_path);
579 :
580 : oslFileError osl_error = create_dir_recursively_(
581 36 : dir_path, aDirectoryCreationCallbackFunc, pData);
582 :
583 36 : if (osl_File_E_None != osl_error)
584 0 : return osl_error;
585 :
586 36 : dir_path[pos] = '/';
587 :
588 36 : return create_dir_recursively_(dir_path, aDirectoryCreationCallbackFunc, pData);
589 : }
590 :
591 1592 : oslFileError SAL_CALL osl_createDirectoryPath(
592 : rtl_uString* aDirectoryUrl,
593 : oslDirectoryCreationCallbackFunc aDirectoryCreationCallbackFunc,
594 : void* pData)
595 : {
596 1592 : if (aDirectoryUrl == NULL)
597 0 : return osl_File_E_INVAL;
598 :
599 1592 : rtl::OUString sys_path;
600 : oslFileError osl_error = osl_getSystemPathFromFileURL_Ex(
601 1592 : aDirectoryUrl, &sys_path.pData, sal_False);
602 :
603 1592 : if (osl_error != osl_File_E_None)
604 2 : return osl_error;
605 :
606 1590 : 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 1590 : 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 12158 : 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 12158 : eRet = FileURLToPath( srcPath, PATH_MAX, ustrFileURL );
651 12158 : if( eRet != osl_File_E_None )
652 0 : return eRet;
653 :
654 : /* convert destination url to system path */
655 12158 : eRet = FileURLToPath( destPath, PATH_MAX, ustrDestURL );
656 12158 : 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 12158 : return oslDoMoveFile( srcPath, destPath );
665 : }
666 :
667 : /****************************************************************************/
668 : /* osl_copyFile */
669 : /****************************************************************************/
670 :
671 2266 : 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 2266 : eRet = FileURLToPath( srcPath, PATH_MAX, ustrFileURL );
682 2266 : if( eRet != osl_File_E_None )
683 0 : return eRet;
684 :
685 : /* convert destination url to system path */
686 2266 : eRet = FileURLToPath( destPath, PATH_MAX, ustrDestURL );
687 2266 : 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 2266 : return osl_psz_copyFile( srcPath, destPath );
696 : }
697 :
698 : /****************************************************************************/
699 : /* osl_removeFile */
700 : /****************************************************************************/
701 :
702 40356 : 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 40356 : eRet = FileURLToPath( path, PATH_MAX, ustrFileURL );
711 40356 : 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 40356 : return osl_psz_removeFile( path );
720 : }
721 :
722 : /******************************************************************************
723 : *
724 : * Utility Functions
725 : *
726 : *****************************************************************************/
727 :
728 : /*****************************************
729 : * oslDoMoveFile
730 : ****************************************/
731 :
732 12158 : static oslFileError oslDoMoveFile( const sal_Char* pszPath, const sal_Char* pszDestPath)
733 : {
734 12158 : oslFileError tErr = osl_psz_moveFile(pszPath,pszDestPath);
735 12158 : if ( tErr == osl_File_E_None )
736 : {
737 12158 : return tErr;
738 : }
739 :
740 0 : if ( tErr != osl_File_E_XDEV )
741 : {
742 0 : return tErr;
743 : }
744 :
745 0 : tErr=osl_psz_copyFile(pszPath,pszDestPath);
746 :
747 0 : if ( tErr != osl_File_E_None )
748 : {
749 0 : osl_psz_removeFile(pszDestPath);
750 0 : return tErr;
751 : }
752 :
753 0 : tErr=osl_psz_removeFile(pszPath);
754 :
755 0 : return tErr;
756 : }
757 :
758 : /*****************************************
759 : * osl_psz_removeFile
760 : ****************************************/
761 40356 : static oslFileError osl_psz_removeFile( const sal_Char* pszPath )
762 : {
763 40356 : int nRet=0;
764 : struct stat aStat;
765 :
766 40356 : nRet = lstat_c(pszPath,&aStat);
767 40356 : if ( nRet < 0 )
768 : {
769 21658 : nRet=errno;
770 21658 : return oslTranslateFileError(OSL_FET_ERROR, nRet);
771 : }
772 :
773 18698 : if ( S_ISDIR(aStat.st_mode) )
774 : {
775 0 : return osl_File_E_ISDIR;
776 : }
777 :
778 18698 : nRet = unlink(pszPath);
779 18698 : if ( nRet < 0 )
780 : {
781 0 : nRet=errno;
782 0 : return oslTranslateFileError(OSL_FET_ERROR, nRet);
783 : }
784 :
785 18698 : return osl_File_E_None;
786 : }
787 :
788 : /*****************************************
789 : * osl_psz_moveFile
790 : ****************************************/
791 :
792 12158 : static oslFileError osl_psz_moveFile(const sal_Char* pszPath, const sal_Char* pszDestPath)
793 : {
794 :
795 12158 : int nRet = 0;
796 :
797 12158 : nRet = rename(pszPath,pszDestPath);
798 :
799 12158 : if ( nRet < 0 )
800 : {
801 0 : nRet=errno;
802 0 : return oslTranslateFileError(OSL_FET_ERROR, nRet);
803 : }
804 :
805 12158 : return osl_File_E_None;
806 : }
807 :
808 : /*****************************************
809 : * osl_psz_copyFile
810 : ****************************************/
811 :
812 2266 : static oslFileError osl_psz_copyFile( const sal_Char* pszPath, const sal_Char* pszDestPath )
813 : {
814 2266 : time_t nAcTime=0;
815 2266 : time_t nModTime=0;
816 2266 : uid_t nUID=0;
817 2266 : gid_t nGID=0;
818 2266 : int nRet=0;
819 2266 : mode_t nMode=0;
820 : struct stat aFileStat;
821 2266 : oslFileError tErr=osl_File_E_invalidError;
822 2266 : size_t nSourceSize=0;
823 2266 : int DestFileExists=1;
824 :
825 : /* mfe: does the source file really exists? */
826 2266 : nRet = lstat_c(pszPath,&aFileStat);
827 :
828 2266 : if ( nRet < 0 )
829 : {
830 2 : nRet=errno;
831 2 : return oslTranslateFileError(OSL_FET_ERROR, nRet);
832 : }
833 :
834 : /* mfe: we do only copy files here! */
835 2264 : if ( S_ISDIR(aFileStat.st_mode) )
836 : {
837 0 : return osl_File_E_ISDIR;
838 : }
839 :
840 2264 : nSourceSize=(size_t)aFileStat.st_size;
841 2264 : nMode=aFileStat.st_mode;
842 2264 : nAcTime=aFileStat.st_atime;
843 2264 : nModTime=aFileStat.st_mtime;
844 2264 : nUID=aFileStat.st_uid;
845 2264 : nGID=aFileStat.st_gid;
846 :
847 2264 : nRet = stat(pszDestPath,&aFileStat);
848 2264 : if ( nRet < 0 )
849 : {
850 1697 : nRet=errno;
851 :
852 1697 : if ( nRet == ENOENT )
853 : {
854 1697 : DestFileExists=0;
855 : }
856 : /* return oslTranslateFileError(nRet);*/
857 : }
858 :
859 : /* mfe: the destination file must not be a directory! */
860 2264 : if ( nRet == 0 && S_ISDIR(aFileStat.st_mode) )
861 : {
862 0 : return osl_File_E_ISDIR;
863 : }
864 : else
865 : {
866 : /* mfe: file does not exists or is no dir */
867 : }
868 :
869 2264 : tErr = oslDoCopy(pszPath,pszDestPath,nMode,nSourceSize,DestFileExists);
870 :
871 2264 : if ( tErr != osl_File_E_None )
872 : {
873 0 : return tErr;
874 : }
875 :
876 : /*
877 : * mfe: ignore return code
878 : * since only the success of the copy is
879 : * important
880 : */
881 2264 : oslChangeFileModes(pszDestPath,nMode,nAcTime,nModTime,nUID,nGID);
882 :
883 2264 : return tErr;
884 : }
885 :
886 :
887 : /******************************************************************************
888 : *
889 : * Utility Functions
890 : *
891 : *****************************************************************************/
892 :
893 : /*****************************************
894 : * oslDoCopy
895 : ****************************************/
896 :
897 : #define TMP_DEST_FILE_EXTENSION ".osl-tmp"
898 :
899 2264 : static oslFileError oslDoCopy(const sal_Char* pszSourceFileName, const sal_Char* pszDestFileName, mode_t nMode, size_t nSourceSize, int DestFileExists)
900 : {
901 2264 : int nRet=0;
902 : sal_Char pszTmpDestFile[PATH_MAX];
903 2264 : size_t size_tmp_dest_buff = sizeof(pszTmpDestFile);
904 :
905 : /* Quick fix for #106048, the whole copy file function seems
906 : to be erroneous anyway and needs to be rewritten.
907 : */
908 2264 : memset(pszTmpDestFile, 0, size_tmp_dest_buff);
909 :
910 2264 : if ( DestFileExists )
911 : {
912 567 : strncpy(pszTmpDestFile, pszDestFileName, size_tmp_dest_buff - 1);
913 :
914 567 : if ((strlen(pszTmpDestFile) + strlen(TMP_DEST_FILE_EXTENSION)) >= size_tmp_dest_buff)
915 0 : return osl_File_E_NAMETOOLONG;
916 :
917 567 : strncat(pszTmpDestFile, TMP_DEST_FILE_EXTENSION, strlen(TMP_DEST_FILE_EXTENSION));
918 :
919 : /* FIXME: what if pszTmpDestFile already exists? */
920 : /* with getcanonical??? */
921 567 : nRet=rename(pszDestFileName,pszTmpDestFile);
922 : }
923 :
924 : /* mfe: should be S_ISREG */
925 2264 : if ( !S_ISLNK(nMode) )
926 : {
927 : /* copy SourceFile to DestFile */
928 2264 : nRet = oslDoCopyFile(pszSourceFileName,pszDestFileName,nSourceSize, nMode);
929 : }
930 : /* mfe: OK redundant at the moment */
931 0 : else if ( S_ISLNK(nMode) )
932 : {
933 0 : nRet = oslDoCopyLink(pszSourceFileName,pszDestFileName);
934 : }
935 : else
936 : {
937 : /* mfe: what to do here? */
938 0 : nRet=ENOSYS;
939 : }
940 :
941 2264 : if ( nRet > 0 && DestFileExists == 1 )
942 : {
943 0 : unlink(pszDestFileName);
944 0 : rename(pszTmpDestFile,pszDestFileName);
945 : }
946 :
947 2264 : if ( nRet > 0 )
948 : {
949 0 : return oslTranslateFileError(OSL_FET_ERROR, nRet);
950 : }
951 :
952 2264 : if ( DestFileExists == 1 )
953 : {
954 567 : unlink(pszTmpDestFile);
955 : }
956 :
957 2264 : return osl_File_E_None;
958 : }
959 :
960 : /*****************************************
961 : * oslChangeFileModes
962 : ****************************************/
963 :
964 2264 : static oslFileError oslChangeFileModes( const sal_Char* pszFileName, mode_t nMode, time_t nAcTime, time_t nModTime, uid_t nUID, gid_t nGID)
965 : {
966 2264 : int nRet=0;
967 : struct utimbuf aTimeBuffer;
968 :
969 2264 : nRet = chmod(pszFileName,nMode);
970 2264 : if ( nRet < 0 )
971 : {
972 0 : nRet=errno;
973 0 : return oslTranslateFileError(OSL_FET_ERROR, nRet);
974 : }
975 :
976 2264 : aTimeBuffer.actime=nAcTime;
977 2264 : aTimeBuffer.modtime=nModTime;
978 2264 : nRet=utime(pszFileName,&aTimeBuffer);
979 2264 : if ( nRet < 0 )
980 : {
981 0 : nRet=errno;
982 0 : return oslTranslateFileError(OSL_FET_ERROR, nRet);
983 : }
984 :
985 2264 : if ( nUID != getuid() )
986 : {
987 0 : nUID=getuid();
988 : }
989 :
990 2264 : nRet=chown(pszFileName,nUID,nGID);
991 2264 : if ( nRet < 0 )
992 : {
993 0 : nRet=errno;
994 :
995 : /* mfe: do not return an error here! */
996 : /* return oslTranslateFileError(nRet);*/
997 : }
998 :
999 2264 : return osl_File_E_None;
1000 : }
1001 :
1002 : /*****************************************
1003 : * oslDoCopyLink
1004 : ****************************************/
1005 :
1006 0 : static int oslDoCopyLink(const sal_Char* pszSourceFileName, const sal_Char* pszDestFileName)
1007 : {
1008 0 : int nRet=0;
1009 :
1010 : /* mfe: if dest file is symbolic link remove the link and place the file instead (hro says so) */
1011 : /* mfe: if source is a link copy the link and not the file it points to (hro says so) */
1012 : sal_Char pszLinkContent[PATH_MAX+1];
1013 :
1014 0 : pszLinkContent[0] = '\0';
1015 :
1016 0 : nRet = readlink(pszSourceFileName,pszLinkContent,PATH_MAX);
1017 :
1018 0 : if ( nRet < 0 )
1019 : {
1020 0 : nRet=errno;
1021 0 : return nRet;
1022 : }
1023 : else
1024 0 : pszLinkContent[ nRet ] = 0;
1025 :
1026 0 : nRet = symlink(pszLinkContent,pszDestFileName);
1027 :
1028 0 : if ( nRet < 0 )
1029 : {
1030 0 : nRet=errno;
1031 0 : return nRet;
1032 : }
1033 :
1034 0 : return 0;
1035 : }
1036 :
1037 : /*****************************************
1038 : * oslDoCopyFile
1039 : ****************************************/
1040 :
1041 2264 : static int oslDoCopyFile(const sal_Char* pszSourceFileName, const sal_Char* pszDestFileName, size_t nSourceSize, mode_t mode)
1042 : {
1043 2264 : oslFileHandle SourceFileFH=0;
1044 2264 : int DestFileFD=0;
1045 2264 : int nRet=0;
1046 :
1047 2264 : if (osl_openFilePath(pszSourceFileName,
1048 : &SourceFileFH,
1049 2264 : osl_File_OpenFlag_Read|osl_File_OpenFlag_NoLock|osl_File_OpenFlag_NoExcl) != osl_File_E_None)
1050 : {
1051 : // Let's hope errno is still set relevantly after osl_openFilePath...
1052 0 : nRet=errno;
1053 0 : return nRet;
1054 : }
1055 :
1056 2264 : DestFileFD=open(pszDestFileName, O_WRONLY | O_CREAT, mode);
1057 :
1058 2264 : if ( DestFileFD < 0 )
1059 : {
1060 0 : nRet=errno;
1061 0 : osl_closeFile(SourceFileFH);
1062 0 : return nRet;
1063 : }
1064 :
1065 2264 : size_t nRemains = nSourceSize;
1066 :
1067 2264 : if ( nRemains )
1068 : {
1069 : /* mmap has problems, try the direct streaming */
1070 : char pBuffer[0x7FFF];
1071 :
1072 3538 : do
1073 : {
1074 3538 : size_t nToRead = std::min( sizeof(pBuffer), nRemains );
1075 : sal_uInt64 nRead;
1076 : sal_Bool succeeded;
1077 3538 : if ( osl_readFile( SourceFileFH, pBuffer, nToRead, &nRead ) != osl_File_E_None || nRead > nToRead || nRead == 0 )
1078 0 : break;
1079 :
1080 3538 : succeeded = safeWrite( DestFileFD, pBuffer, nRead );
1081 3538 : if ( !succeeded )
1082 0 : break;
1083 :
1084 : // We know nRead <= nToRead, so it must fit in a size_t
1085 3538 : nRemains -= (size_t) nRead;
1086 : }
1087 : while( nRemains );
1088 : }
1089 :
1090 2264 : if ( nRemains )
1091 : {
1092 0 : if ( errno )
1093 0 : nRet = errno;
1094 : else
1095 0 : nRet = ENOSPC;
1096 : }
1097 :
1098 2264 : osl_closeFile( SourceFileFH );
1099 2264 : if ( close( DestFileFD ) == -1 && nRet == 0 )
1100 0 : nRet = errno;
1101 :
1102 2264 : return nRet;
1103 : }
1104 :
1105 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|