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 .
21 #include "osl/detail/file.h"
24 #include <sys/types.h>
30 #include "file_impl.hxx"
31 #include "file_error_transl.h"
32 #include "file_path_helper.hxx"
34 #include "uunxapi.hxx"
38 inline void set_file_type(const struct stat
& file_stat
, oslFileStatus
* pStat
)
40 /* links to directories state also to be a directory */
41 if (S_ISLNK(file_stat
.st_mode
))
42 pStat
->eType
= osl_File_Type_Link
;
43 else if (S_ISDIR(file_stat
.st_mode
))
44 pStat
->eType
= osl_File_Type_Directory
;
45 else if (S_ISREG(file_stat
.st_mode
))
46 pStat
->eType
= osl_File_Type_Regular
;
47 else if (S_ISFIFO(file_stat
.st_mode
))
48 pStat
->eType
= osl_File_Type_Fifo
;
49 else if (S_ISSOCK(file_stat
.st_mode
))
50 pStat
->eType
= osl_File_Type_Socket
;
51 else if (S_ISCHR(file_stat
.st_mode
) || S_ISBLK(file_stat
.st_mode
))
52 pStat
->eType
= osl_File_Type_Special
;
54 pStat
->eType
= osl_File_Type_Unknown
;
56 pStat
->uValidFields
|= osl_FileStatus_Mask_Type
;
59 inline void set_file_access_mask(const struct stat
& file_stat
, oslFileStatus
* pStat
)
62 if (S_IRUSR
& file_stat
.st_mode
)
63 pStat
->uAttributes
|= osl_File_Attribute_OwnRead
;
65 if (S_IWUSR
& file_stat
.st_mode
)
66 pStat
->uAttributes
|= osl_File_Attribute_OwnWrite
;
68 if (S_IXUSR
& file_stat
.st_mode
)
69 pStat
->uAttributes
|= osl_File_Attribute_OwnExe
;
72 if (S_IRGRP
& file_stat
.st_mode
)
73 pStat
->uAttributes
|= osl_File_Attribute_GrpRead
;
75 if (S_IWGRP
& file_stat
.st_mode
)
76 pStat
->uAttributes
|= osl_File_Attribute_GrpWrite
;
78 if (S_IXGRP
& file_stat
.st_mode
)
79 pStat
->uAttributes
|= osl_File_Attribute_GrpExe
;
82 if (S_IROTH
& file_stat
.st_mode
)
83 pStat
->uAttributes
|= osl_File_Attribute_OthRead
;
85 if (S_IWOTH
& file_stat
.st_mode
)
86 pStat
->uAttributes
|= osl_File_Attribute_OthWrite
;
88 if (S_IXOTH
& file_stat
.st_mode
)
89 pStat
->uAttributes
|= osl_File_Attribute_OthExe
;
91 pStat
->uValidFields
|= osl_FileStatus_Mask_Attributes
;
94 /* This code used not to use access(...) because access follows links which
95 may cause performance problems see #97133. (That apparently references a
96 no-longer accessible Hamburg-internal bug-tracking system.)
97 However, contrary to what is stated above the use of access calls is
98 required on network file systems not using unix semantics (AFS, see
101 inline void set_file_access_rights(const rtl::OUString
& file_path
, oslFileStatus
* pStat
)
103 pStat
->uValidFields
|= osl_FileStatus_Mask_Attributes
;
105 if (access_u(file_path
.pData
, W_OK
) < 0)
106 pStat
->uAttributes
|= osl_File_Attribute_ReadOnly
;
108 if (access_u(file_path
.pData
, X_OK
) == 0)
109 pStat
->uAttributes
|= osl_File_Attribute_Executable
;
113 inline void set_file_hidden_status(const rtl::OUString
& file_path
, oslFileStatus
* pStat
)
115 pStat
->uAttributes
= osl::systemPathIsHiddenFileOrDirectoryEntry(file_path
) ? osl_File_Attribute_Hidden
: 0;
116 pStat
->uValidFields
|= osl_FileStatus_Mask_Attributes
;
119 /* the set_file_access_rights must be called after set_file_hidden_status(...) and
120 set_file_access_mask(...) because of the hack in set_file_access_rights(...) */
121 inline void set_file_attributes(
122 const rtl::OUString
& file_path
, const struct stat
& file_stat
, const sal_uInt32 uFieldMask
, oslFileStatus
* pStat
)
124 set_file_hidden_status(file_path
, pStat
);
125 set_file_access_mask(file_stat
, pStat
);
127 // we set the file access rights only on demand
128 // because it's potentially expensive
129 if (uFieldMask
& osl_FileStatus_Mask_Attributes
)
130 set_file_access_rights(file_path
, pStat
);
133 inline void set_file_access_time(const struct stat
& file_stat
, oslFileStatus
* pStat
)
135 pStat
->aAccessTime
.Seconds
= file_stat
.st_atime
;
136 pStat
->aAccessTime
.Nanosec
= 0;
137 pStat
->uValidFields
|= osl_FileStatus_Mask_AccessTime
;
140 inline void set_file_modify_time(const struct stat
& file_stat
, oslFileStatus
* pStat
)
142 pStat
->aModifyTime
.Seconds
= file_stat
.st_mtime
;
143 pStat
->aModifyTime
.Nanosec
= 0;
144 pStat
->uValidFields
|= osl_FileStatus_Mask_ModifyTime
;
147 inline void set_file_size(const struct stat
& file_stat
, oslFileStatus
* pStat
)
149 if (S_ISREG(file_stat
.st_mode
))
151 pStat
->uFileSize
= file_stat
.st_size
;
152 pStat
->uValidFields
|= osl_FileStatus_Mask_FileSize
;
156 /* we only need to call stat or lstat if one of the
157 following flags is set */
158 inline bool is_stat_call_necessary(sal_uInt32 field_mask
, oslFileType file_type
= osl_File_Type_Unknown
)
161 ((field_mask
& osl_FileStatus_Mask_Type
) && (file_type
== osl_File_Type_Unknown
)) ||
162 (field_mask
& osl_FileStatus_Mask_Attributes
) ||
163 (field_mask
& osl_FileStatus_Mask_CreationTime
) ||
164 (field_mask
& osl_FileStatus_Mask_AccessTime
) ||
165 (field_mask
& osl_FileStatus_Mask_ModifyTime
) ||
166 (field_mask
& osl_FileStatus_Mask_FileSize
) ||
167 (field_mask
& osl_FileStatus_Mask_LinkTargetURL
) ||
168 (field_mask
& osl_FileStatus_Mask_Validate
));
171 inline oslFileError
set_link_target_url(const rtl::OUString
& file_path
, oslFileStatus
* pStat
)
173 rtl::OUString link_target
;
174 if (!osl::realpath(file_path
, link_target
))
175 return oslTranslateFileError(OSL_FET_ERROR
, errno
);
177 oslFileError osl_error
= osl_getFileURLFromSystemPath(link_target
.pData
, &pStat
->ustrLinkTargetURL
);
178 if (osl_error
!= osl_File_E_None
)
181 pStat
->uValidFields
|= osl_FileStatus_Mask_LinkTargetURL
;
182 return osl_File_E_None
;
185 inline oslFileError
setup_osl_getFileStatus(
186 DirectoryItem_Impl
* pImpl
, oslFileStatus
* pStat
, rtl::OUString
& file_path
)
188 if ((NULL
== pImpl
) || (NULL
== pStat
))
189 return osl_File_E_INVAL
;
191 file_path
= rtl::OUString(pImpl
->m_ustrFilePath
);
192 OSL_ASSERT(!file_path
.isEmpty());
193 if (file_path
.isEmpty())
194 return osl_File_E_INVAL
;
196 pStat
->uValidFields
= 0;
197 return osl_File_E_None
;
202 oslFileError SAL_CALL
osl_getFileStatus(oslDirectoryItem Item
, oslFileStatus
* pStat
, sal_uInt32 uFieldMask
)
204 DirectoryItem_Impl
* pImpl
= static_cast< DirectoryItem_Impl
* >(Item
);
206 rtl::OUString file_path
;
207 oslFileError osl_error
= setup_osl_getFileStatus(pImpl
, pStat
, file_path
);
208 if (osl_File_E_None
!= osl_error
)
211 struct stat file_stat
;
213 bool bStatNeeded
= is_stat_call_necessary(uFieldMask
, pImpl
->getFileType());
214 if (bStatNeeded
&& (0 != osl::lstat(file_path
, file_stat
)))
215 return oslTranslateFileError(OSL_FET_ERROR
, errno
);
219 // we set all these attributes because it's cheap
220 set_file_type(file_stat
, pStat
);
221 set_file_access_time(file_stat
, pStat
);
222 set_file_modify_time(file_stat
, pStat
);
223 set_file_size(file_stat
, pStat
);
224 set_file_attributes(file_path
, file_stat
, uFieldMask
, pStat
);
226 // file exists semantic of osl_FileStatus_Mask_Validate
227 if ((uFieldMask
& osl_FileStatus_Mask_LinkTargetURL
) && S_ISLNK(file_stat
.st_mode
))
229 osl_error
= set_link_target_url(file_path
, pStat
);
230 if (osl_error
!= osl_File_E_None
)
234 #ifdef _DIRENT_HAVE_D_TYPE
235 else if (uFieldMask
& osl_FileStatus_Mask_Type
)
237 pStat
->eType
= pImpl
->getFileType();
238 pStat
->uValidFields
|= osl_FileStatus_Mask_Type
;
240 #endif /* _DIRENT_HAVE_D_TYPE */
242 if (uFieldMask
& osl_FileStatus_Mask_FileURL
)
244 if ((osl_error
= osl_getFileURLFromSystemPath(file_path
.pData
, &pStat
->ustrFileURL
)) != osl_File_E_None
)
247 pStat
->uValidFields
|= osl_FileStatus_Mask_FileURL
;
250 if (uFieldMask
& osl_FileStatus_Mask_FileName
)
252 osl_systemPathGetFileNameOrLastDirectoryPart(file_path
.pData
, &pStat
->ustrFileName
);
253 pStat
->uValidFields
|= osl_FileStatus_Mask_FileName
;
255 return osl_File_E_None
;
258 static oslFileError
osl_psz_setFileAttributes( const sal_Char
* pszFilePath
, sal_uInt64 uAttributes
)
260 oslFileError osl_error
= osl_File_E_None
;
263 OSL_ENSURE(!(osl_File_Attribute_Hidden
& uAttributes
), "osl_File_Attribute_Hidden doesn't work under Unix");
265 if (uAttributes
& osl_File_Attribute_OwnRead
)
268 if (uAttributes
& osl_File_Attribute_OwnWrite
)
271 if (uAttributes
& osl_File_Attribute_OwnExe
)
274 if (uAttributes
& osl_File_Attribute_GrpRead
)
277 if (uAttributes
& osl_File_Attribute_GrpWrite
)
280 if (uAttributes
& osl_File_Attribute_GrpExe
)
283 if (uAttributes
& osl_File_Attribute_OthRead
)
286 if (uAttributes
& osl_File_Attribute_OthWrite
)
289 if (uAttributes
& osl_File_Attribute_OthExe
)
292 if (chmod(pszFilePath
, nNewMode
) < 0)
293 osl_error
= oslTranslateFileError(OSL_FET_ERROR
, errno
);
298 oslFileError SAL_CALL
osl_setFileAttributes( rtl_uString
* ustrFileURL
, sal_uInt64 uAttributes
)
303 OSL_ASSERT( ustrFileURL
);
305 /* convert file url to system path */
306 eRet
= FileURLToPath( path
, PATH_MAX
, ustrFileURL
);
307 if( eRet
!= osl_File_E_None
)
311 if ( macxp_resolveAlias( path
, PATH_MAX
) != 0 )
312 return oslTranslateFileError( OSL_FET_ERROR
, errno
);
315 return osl_psz_setFileAttributes( path
, uAttributes
);
318 static oslFileError
osl_psz_setFileTime (
319 const sal_Char
* pszFilePath
,
320 const TimeValue
* pLastAccessTime
,
321 const TimeValue
* pLastWriteTime
)
324 struct utimbuf aTimeBuffer
;
325 struct stat aFileStat
;
326 #ifdef DEBUG_OSL_FILE
330 nRet
= lstat_c(pszFilePath
,&aFileStat
);
335 return oslTranslateFileError(OSL_FET_ERROR
, nRet
);
338 #ifdef DEBUG_OSL_FILE
339 fprintf(stderr
,"File Times are (in localtime):\n");
340 pTM
=localtime(&aFileStat
.st_ctime
);
341 fprintf(stderr
,"CreationTime is '%s'\n",asctime(pTM
));
342 pTM
=localtime(&aFileStat
.st_atime
);
343 fprintf(stderr
,"AccessTime is '%s'\n",asctime(pTM
));
344 pTM
=localtime(&aFileStat
.st_mtime
);
345 fprintf(stderr
,"Modification is '%s'\n",asctime(pTM
));
347 fprintf(stderr
,"File Times are (in UTC):\n");
348 fprintf(stderr
,"CreationTime is '%s'\n",ctime(&aFileStat
.st_ctime
));
349 fprintf(stderr
,"AccessTime is '%s'\n",ctime(&aTimeBuffer
.actime
));
350 fprintf(stderr
,"Modification is '%s'\n",ctime(&aTimeBuffer
.modtime
));
353 if ( pLastAccessTime
!= 0 )
355 aTimeBuffer
.actime
=pLastAccessTime
->Seconds
;
359 aTimeBuffer
.actime
=aFileStat
.st_atime
;
362 if ( pLastWriteTime
!= 0 )
364 aTimeBuffer
.modtime
=pLastWriteTime
->Seconds
;
368 aTimeBuffer
.modtime
=aFileStat
.st_mtime
;
371 /* mfe: Creation time not used here! */
373 #ifdef DEBUG_OSL_FILE
374 fprintf(stderr
,"File Times are (in localtime):\n");
375 pTM
=localtime(&aFileStat
.st_ctime
);
376 fprintf(stderr
,"CreationTime now '%s'\n",asctime(pTM
));
377 pTM
=localtime(&aTimeBuffer
.actime
);
378 fprintf(stderr
,"AccessTime now '%s'\n",asctime(pTM
));
379 pTM
=localtime(&aTimeBuffer
.modtime
);
380 fprintf(stderr
,"Modification now '%s'\n",asctime(pTM
));
382 fprintf(stderr
,"File Times are (in UTC):\n");
383 fprintf(stderr
,"CreationTime now '%s'\n",ctime(&aFileStat
.st_ctime
));
384 fprintf(stderr
,"AccessTime now '%s'\n",ctime(&aTimeBuffer
.actime
));
385 fprintf(stderr
,"Modification now '%s'\n",ctime(&aTimeBuffer
.modtime
));
388 nRet
= utime_c(pszFilePath
,&aTimeBuffer
);
392 return oslTranslateFileError(OSL_FET_ERROR
, nRet
);
395 return osl_File_E_None
;
398 oslFileError SAL_CALL
osl_setFileTime (
399 rtl_uString
* ustrFileURL
,
400 SAL_UNUSED_PARAMETER
const TimeValue
* /* pCreationTime */,
401 const TimeValue
* pLastAccessTime
,
402 const TimeValue
* pLastWriteTime
)
407 OSL_ASSERT( ustrFileURL
);
409 /* convert file url to system path */
410 eRet
= FileURLToPath( path
, PATH_MAX
, ustrFileURL
);
411 if( eRet
!= osl_File_E_None
)
415 if ( macxp_resolveAlias( path
, PATH_MAX
) != 0 )
416 return oslTranslateFileError( OSL_FET_ERROR
, errno
);
419 return osl_psz_setFileTime( path
, pLastAccessTime
, pLastWriteTime
);
423 SAL_CALL
osl_identicalDirectoryItem( oslDirectoryItem a
, oslDirectoryItem b
)
425 DirectoryItem_Impl
*pA
= (DirectoryItem_Impl
*) a
;
426 DirectoryItem_Impl
*pB
= (DirectoryItem_Impl
*) b
;
429 /* same name => same item, unless renaming / moving madness has occurred */
430 if (rtl_ustr_compare_WithLength(
431 pA
->m_ustrFilePath
->buffer
, pA
->m_ustrFilePath
->length
,
432 pB
->m_ustrFilePath
->buffer
, pB
->m_ustrFilePath
->length
) == 0)
435 struct stat a_stat
, b_stat
;
437 if (osl::lstat(rtl::OUString(pA
->m_ustrFilePath
), a_stat
) != 0 ||
438 osl::lstat(rtl::OUString(pB
->m_ustrFilePath
), b_stat
) != 0)
441 return (a_stat
.st_ino
== b_stat
.st_ino
);
444 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */