1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
22 #include "osl/detail/file.h"
25 #include <sys/types.h>
31 #include "file_impl.hxx"
32 #include "file_error_transl.h"
33 #include "file_path_helper.hxx"
35 #include "uunxapi.hxx"
37 namespace /* private */
40 inline void set_file_type(const struct stat
& file_stat
, oslFileStatus
* pStat
)
42 /* links to directories state also to be a directory */
43 if (S_ISLNK(file_stat
.st_mode
))
44 pStat
->eType
= osl_File_Type_Link
;
45 else if (S_ISDIR(file_stat
.st_mode
))
46 pStat
->eType
= osl_File_Type_Directory
;
47 else if (S_ISREG(file_stat
.st_mode
))
48 pStat
->eType
= osl_File_Type_Regular
;
49 else if (S_ISFIFO(file_stat
.st_mode
))
50 pStat
->eType
= osl_File_Type_Fifo
;
51 else if (S_ISSOCK(file_stat
.st_mode
))
52 pStat
->eType
= osl_File_Type_Socket
;
53 else if (S_ISCHR(file_stat
.st_mode
) || S_ISBLK(file_stat
.st_mode
))
54 pStat
->eType
= osl_File_Type_Special
;
56 pStat
->eType
= osl_File_Type_Unknown
;
58 pStat
->uValidFields
|= osl_FileStatus_Mask_Type
;
61 inline void set_file_access_mask(const struct stat
& file_stat
, oslFileStatus
* pStat
)
64 if (S_IRUSR
& file_stat
.st_mode
)
65 pStat
->uAttributes
|= osl_File_Attribute_OwnRead
;
67 if (S_IWUSR
& file_stat
.st_mode
)
68 pStat
->uAttributes
|= osl_File_Attribute_OwnWrite
;
70 if (S_IXUSR
& file_stat
.st_mode
)
71 pStat
->uAttributes
|= osl_File_Attribute_OwnExe
;
74 if (S_IRGRP
& file_stat
.st_mode
)
75 pStat
->uAttributes
|= osl_File_Attribute_GrpRead
;
77 if (S_IWGRP
& file_stat
.st_mode
)
78 pStat
->uAttributes
|= osl_File_Attribute_GrpWrite
;
80 if (S_IXGRP
& file_stat
.st_mode
)
81 pStat
->uAttributes
|= osl_File_Attribute_GrpExe
;
84 if (S_IROTH
& file_stat
.st_mode
)
85 pStat
->uAttributes
|= osl_File_Attribute_OthRead
;
87 if (S_IWOTH
& file_stat
.st_mode
)
88 pStat
->uAttributes
|= osl_File_Attribute_OthWrite
;
90 if (S_IXOTH
& file_stat
.st_mode
)
91 pStat
->uAttributes
|= osl_File_Attribute_OthExe
;
93 pStat
->uValidFields
|= osl_FileStatus_Mask_Attributes
;
96 /* This code used not to use access(...) because access follows links which
97 may cause performance problems see #97133. (That apparently references a
98 no-longer accessible Hamburg-internal bug-tracking system.)
99 However, contrary to what is stated above the use of access calls is
100 required on network file systems not using unix semantics (AFS, see
103 inline void set_file_access_rights(const rtl::OUString
& file_path
, oslFileStatus
* pStat
)
105 pStat
->uValidFields
|= osl_FileStatus_Mask_Attributes
;
107 if (access_u(file_path
.pData
, W_OK
) < 0)
108 pStat
->uAttributes
|= osl_File_Attribute_ReadOnly
;
110 if (access_u(file_path
.pData
, X_OK
) == 0)
111 pStat
->uAttributes
|= osl_File_Attribute_Executable
;
115 inline void set_file_hidden_status(const rtl::OUString
& file_path
, oslFileStatus
* pStat
)
117 pStat
->uAttributes
= osl::systemPathIsHiddenFileOrDirectoryEntry(file_path
) ? osl_File_Attribute_Hidden
: 0;
118 pStat
->uValidFields
|= osl_FileStatus_Mask_Attributes
;
121 /* the set_file_access_rights must be called after set_file_hidden_status(...) and
122 set_file_access_mask(...) because of the hack in set_file_access_rights(...) */
123 inline void set_file_attributes(
124 const rtl::OUString
& file_path
, const struct stat
& file_stat
, const sal_uInt32 uFieldMask
, oslFileStatus
* pStat
)
126 set_file_hidden_status(file_path
, pStat
);
127 set_file_access_mask(file_stat
, pStat
);
129 // we set the file access rights only on demand
130 // because it's potentially expensive
131 if (uFieldMask
& osl_FileStatus_Mask_Attributes
)
132 set_file_access_rights(file_path
, pStat
);
135 inline void set_file_access_time(const struct stat
& file_stat
, oslFileStatus
* pStat
)
137 pStat
->aAccessTime
.Seconds
= file_stat
.st_atime
;
138 pStat
->aAccessTime
.Nanosec
= 0;
139 pStat
->uValidFields
|= osl_FileStatus_Mask_AccessTime
;
142 inline void set_file_modify_time(const struct stat
& file_stat
, oslFileStatus
* pStat
)
144 pStat
->aModifyTime
.Seconds
= file_stat
.st_mtime
;
145 pStat
->aModifyTime
.Nanosec
= 0;
146 pStat
->uValidFields
|= osl_FileStatus_Mask_ModifyTime
;
149 inline void set_file_size(const struct stat
& file_stat
, oslFileStatus
* pStat
)
151 if (S_ISREG(file_stat
.st_mode
))
153 pStat
->uFileSize
= file_stat
.st_size
;
154 pStat
->uValidFields
|= osl_FileStatus_Mask_FileSize
;
158 /* we only need to call stat or lstat if one of the
159 following flags is set */
160 inline bool is_stat_call_necessary(sal_uInt32 field_mask
, oslFileType file_type
= osl_File_Type_Unknown
)
163 ((field_mask
& osl_FileStatus_Mask_Type
) && (file_type
== osl_File_Type_Unknown
)) ||
164 (field_mask
& osl_FileStatus_Mask_Attributes
) ||
165 (field_mask
& osl_FileStatus_Mask_CreationTime
) ||
166 (field_mask
& osl_FileStatus_Mask_AccessTime
) ||
167 (field_mask
& osl_FileStatus_Mask_ModifyTime
) ||
168 (field_mask
& osl_FileStatus_Mask_FileSize
) ||
169 (field_mask
& osl_FileStatus_Mask_LinkTargetURL
) ||
170 (field_mask
& osl_FileStatus_Mask_Validate
));
173 inline oslFileError
set_link_target_url(const rtl::OUString
& file_path
, oslFileStatus
* pStat
)
175 rtl::OUString link_target
;
176 if (!osl::realpath(file_path
, link_target
))
177 return oslTranslateFileError(OSL_FET_ERROR
, errno
);
179 oslFileError osl_error
= osl_getFileURLFromSystemPath(link_target
.pData
, &pStat
->ustrLinkTargetURL
);
180 if (osl_error
!= osl_File_E_None
)
183 pStat
->uValidFields
|= osl_FileStatus_Mask_LinkTargetURL
;
184 return osl_File_E_None
;
187 inline oslFileError
setup_osl_getFileStatus(
188 DirectoryItem_Impl
* pImpl
, oslFileStatus
* pStat
, rtl::OUString
& file_path
)
190 if ((NULL
== pImpl
) || (NULL
== pStat
))
191 return osl_File_E_INVAL
;
193 file_path
= rtl::OUString(pImpl
->m_ustrFilePath
);
194 OSL_ASSERT(!file_path
.isEmpty());
195 if (file_path
.isEmpty())
196 return osl_File_E_INVAL
;
198 pStat
->uValidFields
= 0;
199 return osl_File_E_None
;
202 } // end namespace private
205 /****************************************************************************
207 ****************************************************************************/
209 oslFileError SAL_CALL
osl_getFileStatus(oslDirectoryItem Item
, oslFileStatus
* pStat
, sal_uInt32 uFieldMask
)
211 DirectoryItem_Impl
* pImpl
= static_cast< DirectoryItem_Impl
* >(Item
);
213 rtl::OUString file_path
;
214 oslFileError osl_error
= setup_osl_getFileStatus(pImpl
, pStat
, file_path
);
215 if (osl_File_E_None
!= osl_error
)
218 struct stat file_stat
;
220 bool bStatNeeded
= is_stat_call_necessary(uFieldMask
, pImpl
->getFileType());
221 if (bStatNeeded
&& (0 != osl::lstat(file_path
, file_stat
)))
222 return oslTranslateFileError(OSL_FET_ERROR
, errno
);
226 // we set all these attributes because it's cheap
227 set_file_type(file_stat
, pStat
);
228 set_file_access_time(file_stat
, pStat
);
229 set_file_modify_time(file_stat
, pStat
);
230 set_file_size(file_stat
, pStat
);
231 set_file_attributes(file_path
, file_stat
, uFieldMask
, pStat
);
233 // file exists semantic of osl_FileStatus_Mask_Validate
234 if ((uFieldMask
& osl_FileStatus_Mask_LinkTargetURL
) && S_ISLNK(file_stat
.st_mode
))
236 osl_error
= set_link_target_url(file_path
, pStat
);
237 if (osl_error
!= osl_File_E_None
)
241 #ifdef _DIRENT_HAVE_D_TYPE
242 else if (uFieldMask
& osl_FileStatus_Mask_Type
)
244 pStat
->eType
= pImpl
->getFileType();
245 pStat
->uValidFields
|= osl_FileStatus_Mask_Type
;
247 #endif /* _DIRENT_HAVE_D_TYPE */
249 if (uFieldMask
& osl_FileStatus_Mask_FileURL
)
251 if ((osl_error
= osl_getFileURLFromSystemPath(file_path
.pData
, &pStat
->ustrFileURL
)) != osl_File_E_None
)
254 pStat
->uValidFields
|= osl_FileStatus_Mask_FileURL
;
257 if (uFieldMask
& osl_FileStatus_Mask_FileName
)
259 osl_systemPathGetFileNameOrLastDirectoryPart(file_path
.pData
, &pStat
->ustrFileName
);
260 pStat
->uValidFields
|= osl_FileStatus_Mask_FileName
;
262 return osl_File_E_None
;
265 /****************************************************************************/
266 /* osl_setFileAttributes */
267 /****************************************************************************/
269 static oslFileError
osl_psz_setFileAttributes( const sal_Char
* pszFilePath
, sal_uInt64 uAttributes
)
271 oslFileError osl_error
= osl_File_E_None
;
274 OSL_ENSURE(!(osl_File_Attribute_Hidden
& uAttributes
), "osl_File_Attribute_Hidden doesn't work under Unix");
276 if (uAttributes
& osl_File_Attribute_OwnRead
)
279 if (uAttributes
& osl_File_Attribute_OwnWrite
)
282 if (uAttributes
& osl_File_Attribute_OwnExe
)
285 if (uAttributes
& osl_File_Attribute_GrpRead
)
288 if (uAttributes
& osl_File_Attribute_GrpWrite
)
291 if (uAttributes
& osl_File_Attribute_GrpExe
)
294 if (uAttributes
& osl_File_Attribute_OthRead
)
297 if (uAttributes
& osl_File_Attribute_OthWrite
)
300 if (uAttributes
& osl_File_Attribute_OthExe
)
303 if (chmod(pszFilePath
, nNewMode
) < 0)
304 osl_error
= oslTranslateFileError(OSL_FET_ERROR
, errno
);
309 oslFileError SAL_CALL
osl_setFileAttributes( rtl_uString
* ustrFileURL
, sal_uInt64 uAttributes
)
314 OSL_ASSERT( ustrFileURL
);
316 /* convert file url to system path */
317 eRet
= FileURLToPath( path
, PATH_MAX
, ustrFileURL
);
318 if( eRet
!= osl_File_E_None
)
322 if ( macxp_resolveAlias( path
, PATH_MAX
) != 0 )
323 return oslTranslateFileError( OSL_FET_ERROR
, errno
);
326 return osl_psz_setFileAttributes( path
, uAttributes
);
329 /****************************************************************************/
330 /* osl_setFileTime */
331 /****************************************************************************/
333 static oslFileError
osl_psz_setFileTime (
334 const sal_Char
* pszFilePath
,
335 const TimeValue
* pLastAccessTime
,
336 const TimeValue
* pLastWriteTime
)
339 struct utimbuf aTimeBuffer
;
340 struct stat aFileStat
;
341 #ifdef DEBUG_OSL_FILE
345 nRet
= lstat(pszFilePath
,&aFileStat
);
350 return oslTranslateFileError(OSL_FET_ERROR
, nRet
);
353 #ifdef DEBUG_OSL_FILE
354 fprintf(stderr
,"File Times are (in localtime):\n");
355 pTM
=localtime(&aFileStat
.st_ctime
);
356 fprintf(stderr
,"CreationTime is '%s'\n",asctime(pTM
));
357 pTM
=localtime(&aFileStat
.st_atime
);
358 fprintf(stderr
,"AccessTime is '%s'\n",asctime(pTM
));
359 pTM
=localtime(&aFileStat
.st_mtime
);
360 fprintf(stderr
,"Modification is '%s'\n",asctime(pTM
));
362 fprintf(stderr
,"File Times are (in UTC):\n");
363 fprintf(stderr
,"CreationTime is '%s'\n",ctime(&aFileStat
.st_ctime
));
364 fprintf(stderr
,"AccessTime is '%s'\n",ctime(&aTimeBuffer
.actime
));
365 fprintf(stderr
,"Modification is '%s'\n",ctime(&aTimeBuffer
.modtime
));
368 if ( pLastAccessTime
!= 0 )
370 aTimeBuffer
.actime
=pLastAccessTime
->Seconds
;
374 aTimeBuffer
.actime
=aFileStat
.st_atime
;
377 if ( pLastWriteTime
!= 0 )
379 aTimeBuffer
.modtime
=pLastWriteTime
->Seconds
;
383 aTimeBuffer
.modtime
=aFileStat
.st_mtime
;
386 /* mfe: Creation time not used here! */
388 #ifdef DEBUG_OSL_FILE
389 fprintf(stderr
,"File Times are (in localtime):\n");
390 pTM
=localtime(&aFileStat
.st_ctime
);
391 fprintf(stderr
,"CreationTime now '%s'\n",asctime(pTM
));
392 pTM
=localtime(&aTimeBuffer
.actime
);
393 fprintf(stderr
,"AccessTime now '%s'\n",asctime(pTM
));
394 pTM
=localtime(&aTimeBuffer
.modtime
);
395 fprintf(stderr
,"Modification now '%s'\n",asctime(pTM
));
397 fprintf(stderr
,"File Times are (in UTC):\n");
398 fprintf(stderr
,"CreationTime now '%s'\n",ctime(&aFileStat
.st_ctime
));
399 fprintf(stderr
,"AccessTime now '%s'\n",ctime(&aTimeBuffer
.actime
));
400 fprintf(stderr
,"Modification now '%s'\n",ctime(&aTimeBuffer
.modtime
));
403 nRet
=utime(pszFilePath
,&aTimeBuffer
);
407 return oslTranslateFileError(OSL_FET_ERROR
, nRet
);
410 return osl_File_E_None
;
413 oslFileError SAL_CALL
osl_setFileTime (
414 rtl_uString
* ustrFileURL
,
415 SAL_UNUSED_PARAMETER
const TimeValue
* /* pCreationTime */,
416 const TimeValue
* pLastAccessTime
,
417 const TimeValue
* pLastWriteTime
)
422 OSL_ASSERT( ustrFileURL
);
424 /* convert file url to system path */
425 eRet
= FileURLToPath( path
, PATH_MAX
, ustrFileURL
);
426 if( eRet
!= osl_File_E_None
)
430 if ( macxp_resolveAlias( path
, PATH_MAX
) != 0 )
431 return oslTranslateFileError( OSL_FET_ERROR
, errno
);
434 return osl_psz_setFileTime( path
, pLastAccessTime
, pLastWriteTime
);
438 SAL_CALL
osl_identicalDirectoryItem( oslDirectoryItem a
, oslDirectoryItem b
)
440 DirectoryItem_Impl
*pA
= (DirectoryItem_Impl
*) a
;
441 DirectoryItem_Impl
*pB
= (DirectoryItem_Impl
*) b
;
444 /* same name => same item, unless renaming / moving madness has occurred */
445 if (rtl_ustr_compare_WithLength(
446 pA
->m_ustrFilePath
->buffer
, pA
->m_ustrFilePath
->length
,
447 pB
->m_ustrFilePath
->buffer
, pB
->m_ustrFilePath
->length
) == 0)
450 struct stat a_stat
, b_stat
;
452 if (osl::lstat(rtl::OUString(pA
->m_ustrFilePath
), a_stat
) != 0 ||
453 osl::lstat(rtl::OUString(pB
->m_ustrFilePath
), b_stat
) != 0)
456 return (a_stat
.st_ino
== b_stat
.st_ino
);
459 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */