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 47928 : DirectoryItem_Impl::DirectoryItem_Impl(
81 : rtl_uString * ustrFilePath, unsigned char DType)
82 : : m_RefCount (1),
83 : m_ustrFilePath (ustrFilePath),
84 47928 : m_DType (DType)
85 : {
86 47928 : if (m_ustrFilePath != 0)
87 47928 : rtl_uString_acquire(m_ustrFilePath);
88 47928 : }
89 47928 : DirectoryItem_Impl::~DirectoryItem_Impl()
90 : {
91 47928 : if (m_ustrFilePath != 0)
92 47928 : rtl_uString_release(m_ustrFilePath);
93 47928 : }
94 :
95 47928 : void * DirectoryItem_Impl::operator new(size_t n)
96 : {
97 47928 : return rtl_allocateMemory(n);
98 : }
99 47928 : void DirectoryItem_Impl::operator delete(void * p)
100 : {
101 47928 : rtl_freeMemory(p);
102 47928 : }
103 :
104 0 : void DirectoryItem_Impl::acquire()
105 : {
106 0 : ++m_RefCount;
107 0 : }
108 47928 : void DirectoryItem_Impl::release()
109 : {
110 47928 : if (0 == --m_RefCount)
111 47928 : delete this;
112 47928 : }
113 :
114 72701 : oslFileType DirectoryItem_Impl::getFileType() const
115 : {
116 72701 : switch (m_DType)
117 : {
118 : #ifdef _DIRENT_HAVE_D_TYPE
119 : case DT_LNK:
120 2 : return osl_File_Type_Link;
121 : case DT_DIR:
122 1608 : return osl_File_Type_Directory;
123 : case DT_REG:
124 59214 : 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 11877 : break;
135 : }
136 11877 : 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 5921 : oslFileError SAL_CALL osl_openDirectory(rtl_uString* ustrDirectoryURL, oslDirectory* pDirectory)
153 : {
154 5921 : rtl_uString* ustrSystemPath = NULL;
155 : oslFileError eRet;
156 :
157 : char path[PATH_MAX];
158 :
159 5921 : if ((0 == ustrDirectoryURL) || (0 == ustrDirectoryURL->length) || (0 == pDirectory))
160 0 : return osl_File_E_INVAL;
161 :
162 : /* convert file URL to system path */
163 5921 : eRet = osl_getSystemPathFromFileURL_Ex(ustrDirectoryURL, &ustrSystemPath, sal_False);
164 :
165 5921 : if( osl_File_E_None != eRet )
166 3 : return eRet;
167 :
168 5918 : osl_systemPathRemoveSeparator(ustrSystemPath);
169 :
170 : /* convert unicode path to text */
171 5918 : 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 5918 : DIR *pdir = opendir( path );
207 :
208 5918 : if( pdir )
209 : {
210 : /* create and initialize impl structure */
211 5647 : oslDirectoryImpl* pDirImpl = (oslDirectoryImpl*) rtl_allocateMemory( sizeof(oslDirectoryImpl) );
212 :
213 5647 : if( pDirImpl )
214 : {
215 5647 : pDirImpl->pDirStruct = pdir;
216 5647 : pDirImpl->ustrPath = ustrSystemPath;
217 : #ifdef ANDROID
218 : pDirImpl->eKind = oslDirectoryImpl::KIND_DIRENT;
219 : #endif
220 5647 : *pDirectory = (oslDirectory) pDirImpl;
221 5647 : 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 271 : rtl_uString_release( ustrSystemPath );
239 :
240 271 : return oslTranslateFileError(OSL_FET_ERROR, errno);
241 : }
242 :
243 : /****************************************************************************/
244 : /* osl_closeDirectory */
245 : /****************************************************************************/
246 :
247 5647 : oslFileError SAL_CALL osl_closeDirectory( oslDirectory Directory )
248 : {
249 5647 : oslDirectoryImpl* pDirImpl = (oslDirectoryImpl*) Directory;
250 5647 : oslFileError err = osl_File_E_None;
251 :
252 : OSL_ASSERT( Directory );
253 :
254 5647 : 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 5647 : if( closedir( pDirImpl->pDirStruct ) )
267 0 : err = oslTranslateFileError(OSL_FET_ERROR, errno);
268 : }
269 :
270 : /* cleanup members */
271 5647 : rtl_uString_release( pDirImpl->ustrPath );
272 :
273 5647 : rtl_freeMemory( pDirImpl );
274 :
275 5647 : return err;
276 : }
277 :
278 : /**********************************************
279 : * osl_readdir_impl_
280 : *
281 : * readdir wrapper, filters out "." and ".."
282 : * on request
283 : *********************************************/
284 :
285 39665 : static struct dirent* osl_readdir_impl_(DIR* pdir, sal_Bool bFilterLocalAndParentDir)
286 : {
287 : struct dirent* pdirent;
288 :
289 87731 : while ((pdirent = readdir(pdir)) != NULL)
290 : {
291 127398 : if (bFilterLocalAndParentDir &&
292 83532 : ((0 == strcmp(pdirent->d_name, ".")) || (0 == strcmp(pdirent->d_name, ".."))))
293 8401 : continue;
294 : else
295 35465 : break;
296 : }
297 :
298 39665 : return pdirent;
299 : }
300 :
301 : /****************************************************************************
302 : * osl_getNextDirectoryItem
303 : ***************************************************************************/
304 :
305 39666 : oslFileError SAL_CALL osl_getNextDirectoryItem(oslDirectory Directory, oslDirectoryItem* pItem, SAL_UNUSED_PARAMETER sal_uInt32 /*uHint*/)
306 : {
307 39666 : oslDirectoryImpl* pDirImpl = (oslDirectoryImpl*)Directory;
308 39666 : rtl_uString* ustrFileName = NULL;
309 39666 : rtl_uString* ustrFilePath = NULL;
310 : struct dirent* pEntry;
311 :
312 : OSL_ASSERT(Directory);
313 : OSL_ASSERT(pItem);
314 :
315 39666 : 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 39665 : pEntry = osl_readdir_impl_(pDirImpl->pDirStruct, sal_True);
327 : }
328 :
329 39665 : if (NULL == pEntry)
330 4200 : 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 35465 : rtl_string2UString( &ustrFileName, pEntry->d_name, strlen( pEntry->d_name ),
348 70930 : osl_getThreadTextEncoding(), OSTRING_TO_OUSTRING_CVTFLAGS );
349 : OSL_ASSERT(ustrFileName != 0);
350 :
351 : #endif
352 :
353 35465 : osl_systemPathMakeAbsolutePath(pDirImpl->ustrPath, ustrFileName, &ustrFilePath);
354 35465 : rtl_uString_release( ustrFileName );
355 :
356 35465 : DirectoryItem_Impl * pImpl = static_cast< DirectoryItem_Impl* >(*pItem);
357 35465 : if (0 != pImpl)
358 : {
359 0 : pImpl->release(), pImpl = 0;
360 : }
361 : #ifdef _DIRENT_HAVE_D_TYPE
362 35465 : pImpl = new DirectoryItem_Impl(ustrFilePath, pEntry->d_type);
363 : #else
364 : pImpl = new DirectoryItem_Impl(ustrFilePath);
365 : #endif /* _DIRENT_HAVE_D_TYPE */
366 35465 : *pItem = pImpl;
367 35465 : rtl_uString_release( ustrFilePath );
368 :
369 35465 : return osl_File_E_None;
370 : }
371 :
372 : /****************************************************************************/
373 : /* osl_getDirectoryItem */
374 : /****************************************************************************/
375 :
376 17903 : oslFileError SAL_CALL osl_getDirectoryItem( rtl_uString* ustrFileURL, oslDirectoryItem* pItem )
377 : {
378 17903 : rtl_uString* ustrSystemPath = NULL;
379 17903 : oslFileError osl_error = osl_File_E_INVAL;
380 :
381 : OSL_ASSERT((0 != ustrFileURL) && (0 != pItem));
382 17903 : if ((0 == ustrFileURL) || (0 == ustrFileURL->length) || (0 == pItem))
383 0 : return osl_File_E_INVAL;
384 :
385 17903 : osl_error = osl_getSystemPathFromFileURL_Ex(ustrFileURL, &ustrSystemPath, sal_False);
386 17903 : if (osl_File_E_None != osl_error)
387 655 : return osl_error;
388 :
389 17248 : osl_systemPathRemoveSeparator(ustrSystemPath);
390 :
391 17248 : if (-1 == access_u(ustrSystemPath, F_OK))
392 : {
393 4785 : osl_error = oslTranslateFileError(OSL_FET_ERROR, errno);
394 : }
395 : else
396 : {
397 12463 : *pItem = new DirectoryItem_Impl(ustrSystemPath);
398 : }
399 17248 : rtl_uString_release(ustrSystemPath);
400 :
401 17248 : 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 47928 : oslFileError SAL_CALL osl_releaseDirectoryItem( oslDirectoryItem Item )
424 : {
425 47928 : DirectoryItem_Impl * pImpl = static_cast< DirectoryItem_Impl* >(Item);
426 47928 : if (0 == pImpl)
427 0 : return osl_File_E_INVAL;
428 :
429 47928 : pImpl->release();
430 47928 : return osl_File_E_None;
431 : }
432 :
433 : /****************************************************************************/
434 : /* osl_createDirectory */
435 : /****************************************************************************/
436 :
437 37 : 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 37 : eRet = FileURLToPath( path, PATH_MAX, ustrDirectoryURL );
446 37 : 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 36 : return osl_psz_createDirectory( path );
455 : }
456 :
457 : /****************************************************************************/
458 : /* osl_removeDirectory */
459 : /****************************************************************************/
460 :
461 34 : 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 34 : eRet = FileURLToPath( path, PATH_MAX, ustrDirectoryURL );
470 34 : 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 33 : return osl_psz_removeDirectory( path );
479 : }
480 :
481 : /*****************************************
482 : * osl_psz_createDirectory
483 : ****************************************/
484 :
485 36 : static oslFileError osl_psz_createDirectory( const sal_Char* pszPath )
486 : {
487 36 : int nRet=0;
488 36 : int mode = S_IRWXU | S_IRWXG | S_IRWXO;
489 :
490 36 : nRet = mkdir(pszPath,mode);
491 :
492 36 : if ( nRet < 0 )
493 : {
494 8 : nRet=errno;
495 8 : return oslTranslateFileError(OSL_FET_ERROR, nRet);
496 : }
497 :
498 28 : return osl_File_E_None;
499 : }
500 :
501 : /*****************************************
502 : * osl_psz_removeDirectory
503 : ****************************************/
504 :
505 33 : static oslFileError osl_psz_removeDirectory( const sal_Char* pszPath )
506 : {
507 33 : int nRet=0;
508 :
509 33 : nRet = rmdir(pszPath);
510 :
511 33 : if ( nRet < 0 )
512 : {
513 7 : nRet=errno;
514 7 : return oslTranslateFileError(OSL_FET_ERROR, nRet);
515 : }
516 :
517 26 : return osl_File_E_None;
518 : }
519 :
520 : /****************************************************************************/
521 : /* osl_createDirectoryPath */
522 : /****************************************************************************/
523 :
524 2 : static int path_make_parent(sal_Unicode* path)
525 : {
526 2 : int i = rtl_ustr_lastIndexOfChar(path, '/');
527 :
528 2 : if (i > 0)
529 : {
530 2 : *(path + i) = 0;
531 2 : return i;
532 : }
533 : else
534 0 : return 0;
535 : }
536 :
537 50 : static int create_dir_with_callback(
538 : sal_Unicode* directory_path,
539 : oslDirectoryCreationCallbackFunc aDirectoryCreationCallbackFunc,
540 : void* pData)
541 : {
542 50 : int mode = S_IRWXU | S_IRWXG | S_IRWXO;
543 :
544 50 : if (osl::mkdir(directory_path, mode) == 0)
545 : {
546 29 : if (aDirectoryCreationCallbackFunc)
547 : {
548 2 : rtl::OUString url;
549 2 : osl::FileBase::getFileURLFromSystemPath(directory_path, url);
550 2 : aDirectoryCreationCallbackFunc(pData, url.pData);
551 : }
552 29 : return 0;
553 : }
554 21 : return errno;
555 : }
556 :
557 50 : 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 50 : dir_path, aDirectoryCreationCallbackFunc, pData);
567 :
568 50 : if (native_err == 0)
569 29 : return osl_File_E_None;
570 :
571 21 : if (native_err != ENOENT)
572 19 : 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 2 : int pos = path_make_parent(dir_path);
579 :
580 : oslFileError osl_error = create_dir_recursively_(
581 2 : dir_path, aDirectoryCreationCallbackFunc, pData);
582 :
583 2 : if (osl_File_E_None != osl_error)
584 0 : return osl_error;
585 :
586 2 : dir_path[pos] = '/';
587 :
588 2 : return create_dir_recursively_(dir_path, aDirectoryCreationCallbackFunc, pData);
589 : }
590 :
591 48 : oslFileError SAL_CALL osl_createDirectoryPath(
592 : rtl_uString* aDirectoryUrl,
593 : oslDirectoryCreationCallbackFunc aDirectoryCreationCallbackFunc,
594 : void* pData)
595 : {
596 48 : if (aDirectoryUrl == NULL)
597 0 : return osl_File_E_INVAL;
598 :
599 48 : rtl::OUString sys_path;
600 : oslFileError osl_error = osl_getSystemPathFromFileURL_Ex(
601 48 : aDirectoryUrl, &sys_path.pData, sal_False);
602 :
603 48 : if (osl_error != osl_File_E_None)
604 2 : return osl_error;
605 :
606 46 : 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 46 : 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 10370 : 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 10370 : eRet = FileURLToPath( srcPath, PATH_MAX, ustrFileURL );
651 10370 : if( eRet != osl_File_E_None )
652 0 : return eRet;
653 :
654 : /* convert destination url to system path */
655 10370 : eRet = FileURLToPath( destPath, PATH_MAX, ustrDestURL );
656 10370 : 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 10370 : return oslDoMoveFile( srcPath, destPath );
665 : }
666 :
667 : /****************************************************************************/
668 : /* osl_copyFile */
669 : /****************************************************************************/
670 :
671 283 : 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 283 : eRet = FileURLToPath( srcPath, PATH_MAX, ustrFileURL );
682 283 : if( eRet != osl_File_E_None )
683 0 : return eRet;
684 :
685 : /* convert destination url to system path */
686 283 : eRet = FileURLToPath( destPath, PATH_MAX, ustrDestURL );
687 283 : 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 283 : return osl_psz_copyFile( srcPath, destPath );
696 : }
697 :
698 : /****************************************************************************/
699 : /* osl_removeFile */
700 : /****************************************************************************/
701 :
702 32569 : 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 32569 : eRet = FileURLToPath( path, PATH_MAX, ustrFileURL );
711 32569 : 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 32569 : return osl_psz_removeFile( path );
720 : }
721 :
722 : /******************************************************************************
723 : *
724 : * Utility Functions
725 : *
726 : *****************************************************************************/
727 :
728 : /*****************************************
729 : * oslDoMoveFile
730 : ****************************************/
731 :
732 10370 : static oslFileError oslDoMoveFile( const sal_Char* pszPath, const sal_Char* pszDestPath)
733 : {
734 10370 : oslFileError tErr=osl_File_E_invalidError;
735 :
736 10370 : tErr = osl_psz_moveFile(pszPath,pszDestPath);
737 10370 : if ( tErr == osl_File_E_None )
738 : {
739 10370 : 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 32569 : static oslFileError osl_psz_removeFile( const sal_Char* pszPath )
764 : {
765 32569 : int nRet=0;
766 : struct stat aStat;
767 :
768 32569 : nRet = lstat_c(pszPath,&aStat);
769 32569 : if ( nRet < 0 )
770 : {
771 20740 : nRet=errno;
772 20740 : return oslTranslateFileError(OSL_FET_ERROR, nRet);
773 : }
774 :
775 11829 : if ( S_ISDIR(aStat.st_mode) )
776 : {
777 0 : return osl_File_E_ISDIR;
778 : }
779 :
780 11829 : nRet = unlink(pszPath);
781 11829 : if ( nRet < 0 )
782 : {
783 0 : nRet=errno;
784 0 : return oslTranslateFileError(OSL_FET_ERROR, nRet);
785 : }
786 :
787 11829 : return osl_File_E_None;
788 : }
789 :
790 : /*****************************************
791 : * osl_psz_moveFile
792 : ****************************************/
793 :
794 10370 : static oslFileError osl_psz_moveFile(const sal_Char* pszPath, const sal_Char* pszDestPath)
795 : {
796 :
797 10370 : int nRet = 0;
798 :
799 10370 : nRet = rename(pszPath,pszDestPath);
800 :
801 10370 : if ( nRet < 0 )
802 : {
803 0 : nRet=errno;
804 0 : return oslTranslateFileError(OSL_FET_ERROR, nRet);
805 : }
806 :
807 10370 : return osl_File_E_None;
808 : }
809 :
810 : /*****************************************
811 : * osl_psz_copyFile
812 : ****************************************/
813 :
814 283 : static oslFileError osl_psz_copyFile( const sal_Char* pszPath, const sal_Char* pszDestPath )
815 : {
816 283 : time_t nAcTime=0;
817 283 : time_t nModTime=0;
818 283 : uid_t nUID=0;
819 283 : gid_t nGID=0;
820 283 : int nRet=0;
821 283 : mode_t nMode=0;
822 : struct stat aFileStat;
823 283 : oslFileError tErr=osl_File_E_invalidError;
824 283 : size_t nSourceSize=0;
825 283 : int DestFileExists=1;
826 :
827 : /* mfe: does the source file really exists? */
828 283 : nRet = lstat_c(pszPath,&aFileStat);
829 :
830 283 : 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 283 : if ( S_ISDIR(aFileStat.st_mode) )
838 : {
839 0 : return osl_File_E_ISDIR;
840 : }
841 :
842 283 : nSourceSize=(size_t)aFileStat.st_size;
843 283 : nMode=aFileStat.st_mode;
844 283 : nAcTime=aFileStat.st_atime;
845 283 : nModTime=aFileStat.st_mtime;
846 283 : nUID=aFileStat.st_uid;
847 283 : nGID=aFileStat.st_gid;
848 :
849 283 : nRet = stat(pszDestPath,&aFileStat);
850 283 : if ( nRet < 0 )
851 : {
852 283 : nRet=errno;
853 :
854 283 : if ( nRet == ENOENT )
855 : {
856 283 : DestFileExists=0;
857 : }
858 : /* return oslTranslateFileError(nRet);*/
859 : }
860 :
861 : /* mfe: the destination file must not be a directory! */
862 283 : 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 283 : tErr = oslDoCopy(pszPath,pszDestPath,nMode,nSourceSize,DestFileExists);
872 :
873 283 : 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 283 : oslChangeFileModes(pszDestPath,nMode,nAcTime,nModTime,nUID,nGID);
884 :
885 283 : 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 283 : static oslFileError oslDoCopy(const sal_Char* pszSourceFileName, const sal_Char* pszDestFileName, mode_t nMode, size_t nSourceSize, int DestFileExists)
902 : {
903 283 : int nRet=0;
904 : sal_Char pszTmpDestFile[PATH_MAX];
905 283 : 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 283 : memset(pszTmpDestFile, 0, size_tmp_dest_buff);
911 :
912 283 : 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 283 : if ( !S_ISLNK(nMode) )
928 : {
929 : /* copy SourceFile to DestFile */
930 283 : 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 283 : if ( nRet > 0 && DestFileExists == 1 )
944 : {
945 0 : unlink(pszDestFileName);
946 0 : rename(pszTmpDestFile,pszDestFileName);
947 : }
948 :
949 283 : if ( nRet > 0 )
950 : {
951 0 : return oslTranslateFileError(OSL_FET_ERROR, nRet);
952 : }
953 :
954 283 : if ( DestFileExists == 1 )
955 : {
956 0 : unlink(pszTmpDestFile);
957 : }
958 :
959 283 : return osl_File_E_None;
960 : }
961 :
962 : /*****************************************
963 : * oslChangeFileModes
964 : ****************************************/
965 :
966 283 : static oslFileError oslChangeFileModes( const sal_Char* pszFileName, mode_t nMode, time_t nAcTime, time_t nModTime, uid_t nUID, gid_t nGID)
967 : {
968 283 : int nRet=0;
969 : struct utimbuf aTimeBuffer;
970 :
971 283 : nRet = chmod(pszFileName,nMode);
972 283 : if ( nRet < 0 )
973 : {
974 0 : nRet=errno;
975 0 : return oslTranslateFileError(OSL_FET_ERROR, nRet);
976 : }
977 :
978 283 : aTimeBuffer.actime=nAcTime;
979 283 : aTimeBuffer.modtime=nModTime;
980 283 : nRet=utime(pszFileName,&aTimeBuffer);
981 283 : if ( nRet < 0 )
982 : {
983 0 : nRet=errno;
984 0 : return oslTranslateFileError(OSL_FET_ERROR, nRet);
985 : }
986 :
987 283 : if ( nUID != getuid() )
988 : {
989 0 : nUID=getuid();
990 : }
991 :
992 283 : nRet=chown(pszFileName,nUID,nGID);
993 283 : if ( nRet < 0 )
994 : {
995 0 : nRet=errno;
996 :
997 : /* mfe: do not return an error here! */
998 : /* return oslTranslateFileError(nRet);*/
999 : }
1000 :
1001 283 : 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 283 : static int oslDoCopyFile(const sal_Char* pszSourceFileName, const sal_Char* pszDestFileName, size_t nSourceSize, mode_t mode)
1044 : {
1045 283 : oslFileHandle SourceFileFH=0;
1046 283 : int DestFileFD=0;
1047 283 : int nRet=0;
1048 :
1049 283 : if (osl_openFilePath(pszSourceFileName,
1050 : &SourceFileFH,
1051 283 : 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 283 : DestFileFD=open(pszDestFileName, O_WRONLY | O_CREAT, mode);
1059 :
1060 283 : if ( DestFileFD < 0 )
1061 : {
1062 0 : nRet=errno;
1063 0 : osl_closeFile(SourceFileFH);
1064 0 : return nRet;
1065 : }
1066 :
1067 283 : size_t nRemains = nSourceSize;
1068 :
1069 283 : if ( nRemains )
1070 : {
1071 : /* mmap has problems, try the direct streaming */
1072 : char pBuffer[0x7FFF];
1073 :
1074 399 : do
1075 : {
1076 399 : size_t nToRead = std::min( sizeof(pBuffer), nRemains );
1077 : sal_uInt64 nRead;
1078 : sal_Bool succeeded;
1079 399 : if ( osl_readFile( SourceFileFH, pBuffer, nToRead, &nRead ) != osl_File_E_None || nRead > nToRead || nRead == 0 )
1080 : break;
1081 :
1082 399 : succeeded = safeWrite( DestFileFD, pBuffer, nRead );
1083 399 : if ( !succeeded )
1084 : break;
1085 :
1086 : // We know nRead <= nToRead, so it must fit in a size_t
1087 399 : nRemains -= (size_t) nRead;
1088 : }
1089 : while( nRemains );
1090 : }
1091 :
1092 283 : if ( nRemains )
1093 : {
1094 0 : if ( errno )
1095 0 : nRet = errno;
1096 : else
1097 0 : nRet = ENOSPC;
1098 : }
1099 :
1100 283 : osl_closeFile( SourceFileFH );
1101 283 : if ( close( DestFileFD ) == -1 && nRet == 0 )
1102 0 : nRet = errno;
1103 :
1104 283 : return nRet;
1105 : }
1106 :
1107 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|