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