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 .
29 #include <osl/diagnose.h>
30 #include <osl/thread.h>
33 #include "file_impl.hxx"
34 #include "file_error_transl.hxx"
35 #include "file_path_helper.hxx"
36 #include "file_url.hxx"
37 #include "uunxapi.hxx"
41 void set_file_type(const struct stat
& file_stat
, oslFileStatus
* pStat
)
43 /* links to directories state also to be a directory */
44 if (S_ISLNK(file_stat
.st_mode
))
45 pStat
->eType
= osl_File_Type_Link
;
46 else if (S_ISDIR(file_stat
.st_mode
))
47 pStat
->eType
= osl_File_Type_Directory
;
48 else if (S_ISREG(file_stat
.st_mode
))
49 pStat
->eType
= osl_File_Type_Regular
;
50 else if (S_ISFIFO(file_stat
.st_mode
))
51 pStat
->eType
= osl_File_Type_Fifo
;
52 else if (S_ISSOCK(file_stat
.st_mode
))
53 pStat
->eType
= osl_File_Type_Socket
;
54 else if (S_ISCHR(file_stat
.st_mode
) || S_ISBLK(file_stat
.st_mode
))
55 pStat
->eType
= osl_File_Type_Special
;
57 pStat
->eType
= osl_File_Type_Unknown
;
59 pStat
->uValidFields
|= osl_FileStatus_Mask_Type
;
62 void set_file_access_mask(const struct stat
& file_stat
, oslFileStatus
* pStat
)
65 if (S_IRUSR
& file_stat
.st_mode
)
66 pStat
->uAttributes
|= osl_File_Attribute_OwnRead
;
68 if (S_IWUSR
& file_stat
.st_mode
)
69 pStat
->uAttributes
|= osl_File_Attribute_OwnWrite
;
71 if (S_IXUSR
& file_stat
.st_mode
)
72 pStat
->uAttributes
|= osl_File_Attribute_OwnExe
;
75 if (S_IRGRP
& file_stat
.st_mode
)
76 pStat
->uAttributes
|= osl_File_Attribute_GrpRead
;
78 if (S_IWGRP
& file_stat
.st_mode
)
79 pStat
->uAttributes
|= osl_File_Attribute_GrpWrite
;
81 if (S_IXGRP
& file_stat
.st_mode
)
82 pStat
->uAttributes
|= osl_File_Attribute_GrpExe
;
85 if (S_IROTH
& file_stat
.st_mode
)
86 pStat
->uAttributes
|= osl_File_Attribute_OthRead
;
88 if (S_IWOTH
& file_stat
.st_mode
)
89 pStat
->uAttributes
|= osl_File_Attribute_OthWrite
;
91 if (S_IXOTH
& file_stat
.st_mode
)
92 pStat
->uAttributes
|= osl_File_Attribute_OthExe
;
94 pStat
->uValidFields
|= osl_FileStatus_Mask_Attributes
;
97 /* This code used not to use access(...) because access follows links which
98 may cause performance problems see #97133. (That apparently references a
99 no-longer accessible Hamburg-internal bug-tracking system.)
100 However, contrary to what is stated above the use of access calls is
101 required on network file systems not using unix semantics (AFS, see
104 void set_file_access_rights(const OString
& file_path
, oslFileStatus
* pStat
)
106 pStat
->uValidFields
|= osl_FileStatus_Mask_Attributes
;
108 if (osl::access(file_path
, W_OK
) < 0)
109 pStat
->uAttributes
|= osl_File_Attribute_ReadOnly
;
111 if (osl::access(file_path
, X_OK
) == 0)
112 pStat
->uAttributes
|= osl_File_Attribute_Executable
;
115 void set_file_hidden_status(const OString
& 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 void set_file_attributes(
124 const OString
& 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 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 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 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 bool is_stat_call_necessary(sal_uInt32 field_mask
, oslFileType file_type
)
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 oslFileError
set_link_target_url(const OString
& file_path
, oslFileStatus
* pStat
)
176 if (!osl::realpath(file_path
, link_target
))
177 return oslTranslateFileError(errno
);
180 oslFileError osl_error
= osl::detail::convertPathnameToUrl(link_target
, &url
);
181 if (osl_error
!= osl_File_E_None
)
183 rtl_uString_assign(&pStat
->ustrLinkTargetURL
, url
.pData
);
185 pStat
->uValidFields
|= osl_FileStatus_Mask_LinkTargetURL
;
186 return osl_File_E_None
;
189 oslFileError
setup_osl_getFileStatus(
190 DirectoryItem_Impl
* pImpl
, oslFileStatus
* pStat
, OString
& file_path
)
192 if ((pImpl
== nullptr) || (pStat
== nullptr))
193 return osl_File_E_INVAL
;
195 file_path
= pImpl
->m_strFilePath
;
196 OSL_ASSERT(!file_path
.isEmpty());
197 if (file_path
.isEmpty())
198 return osl_File_E_INVAL
;
200 pStat
->uValidFields
= 0;
201 return osl_File_E_None
;
206 oslFileError SAL_CALL
osl_getFileStatus(oslDirectoryItem Item
, oslFileStatus
* pStat
, sal_uInt32 uFieldMask
)
208 DirectoryItem_Impl
* pImpl
= static_cast< DirectoryItem_Impl
* >(Item
);
211 oslFileError osl_error
= setup_osl_getFileStatus(pImpl
, pStat
, file_path
);
212 if (osl_error
!= osl_File_E_None
)
215 struct stat file_stat
;
217 bool bStatNeeded
= is_stat_call_necessary(uFieldMask
, pImpl
->getFileType());
218 if (bStatNeeded
&& (osl::lstat(file_path
, file_stat
) != 0))
219 return oslTranslateFileError(errno
);
223 // we set all these attributes because it's cheap
224 set_file_type(file_stat
, pStat
);
225 set_file_access_time(file_stat
, pStat
);
226 set_file_modify_time(file_stat
, pStat
);
227 set_file_size(file_stat
, pStat
);
228 set_file_attributes(file_path
, file_stat
, uFieldMask
, pStat
);
230 // file exists semantic of osl_FileStatus_Mask_Validate
231 if ((uFieldMask
& osl_FileStatus_Mask_LinkTargetURL
) && S_ISLNK(file_stat
.st_mode
))
233 osl_error
= set_link_target_url(file_path
, pStat
);
234 if (osl_error
!= osl_File_E_None
)
238 #ifdef _DIRENT_HAVE_D_TYPE
239 else if (uFieldMask
& osl_FileStatus_Mask_Type
)
241 pStat
->eType
= pImpl
->getFileType();
242 pStat
->uValidFields
|= osl_FileStatus_Mask_Type
;
244 #endif /* _DIRENT_HAVE_D_TYPE */
246 if (uFieldMask
& osl_FileStatus_Mask_FileURL
)
249 if ((osl_error
= osl::detail::convertPathnameToUrl(file_path
, &url
)) != osl_File_E_None
)
251 rtl_uString_assign(&pStat
->ustrFileURL
, url
.pData
);
253 pStat
->uValidFields
|= osl_FileStatus_Mask_FileURL
;
256 if (uFieldMask
& osl_FileStatus_Mask_FileName
)
259 osl_systemPathGetFileNameOrLastDirectoryPart(file_path
.pData
, &name
.pData
);
260 bool ok
= rtl_convertStringToUString(
261 &pStat
->ustrFileName
, name
.getStr(), name
.getLength(), osl_getThreadTextEncoding(),
262 (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_DEFAULT
| RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_DEFAULT
263 | RTL_TEXTTOUNICODE_FLAGS_INVALID_DEFAULT
));
264 assert(ok
); (void)ok
;
265 pStat
->uValidFields
|= osl_FileStatus_Mask_FileName
;
267 return osl_File_E_None
;
270 static oslFileError
osl_psz_setFileAttributes( const char* pszFilePath
, sal_uInt64 uAttributes
)
272 oslFileError osl_error
= osl_File_E_None
;
275 OSL_ENSURE(!(osl_File_Attribute_Hidden
& uAttributes
), "osl_File_Attribute_Hidden doesn't work under Unix");
277 if (isForbidden(pszFilePath
, osl_File_OpenFlag_Write
))
278 return osl_File_E_ACCES
;
280 if (uAttributes
& osl_File_Attribute_OwnRead
)
283 if (uAttributes
& osl_File_Attribute_OwnWrite
)
286 if (uAttributes
& osl_File_Attribute_OwnExe
)
289 if (uAttributes
& osl_File_Attribute_GrpRead
)
292 if (uAttributes
& osl_File_Attribute_GrpWrite
)
295 if (uAttributes
& osl_File_Attribute_GrpExe
)
298 if (uAttributes
& osl_File_Attribute_OthRead
)
301 if (uAttributes
& osl_File_Attribute_OthWrite
)
304 if (uAttributes
& osl_File_Attribute_OthExe
)
307 if (chmod(pszFilePath
, nNewMode
) < 0)
308 osl_error
= oslTranslateFileError(errno
);
313 oslFileError SAL_CALL
osl_setFileAttributes( rtl_uString
* ustrFileURL
, sal_uInt64 uAttributes
)
318 OSL_ASSERT( ustrFileURL
);
320 /* convert file url to system path */
321 eRet
= FileURLToPath( path
, PATH_MAX
, ustrFileURL
);
322 if( eRet
!= osl_File_E_None
)
326 if ( macxp_resolveAlias( path
, PATH_MAX
) != 0 )
327 return oslTranslateFileError( errno
);
330 return osl_psz_setFileAttributes( path
, uAttributes
);
333 static oslFileError
osl_psz_setFileTime (
334 const char* pszFilePath
,
335 const TimeValue
* pLastAccessTime
,
336 const TimeValue
* pLastWriteTime
)
339 struct utimbuf aTimeBuffer
;
340 struct stat aFileStat
;
341 #ifdef DEBUG_OSL_FILE
345 if (isForbidden(pszFilePath
, osl_File_OpenFlag_Write
))
346 return osl_File_E_ACCES
;
348 nRet
= lstat_c(pszFilePath
,&aFileStat
);
353 return oslTranslateFileError(nRet
);
356 #ifdef DEBUG_OSL_FILE
357 fprintf(stderr
,"File Times are (in localtime):\n");
358 pTM
=localtime(&aFileStat
.st_ctime
);
359 fprintf(stderr
,"CreationTime is '%s'\n",asctime(pTM
));
360 pTM
=localtime(&aFileStat
.st_atime
);
361 fprintf(stderr
,"AccessTime is '%s'\n",asctime(pTM
));
362 pTM
=localtime(&aFileStat
.st_mtime
);
363 fprintf(stderr
,"Modification is '%s'\n",asctime(pTM
));
365 fprintf(stderr
,"File Times are (in UTC):\n");
366 fprintf(stderr
,"CreationTime is '%s'\n",ctime(&aFileStat
.st_ctime
));
367 fprintf(stderr
,"AccessTime is '%s'\n",ctime(&aTimeBuffer
.actime
));
368 fprintf(stderr
,"Modification is '%s'\n",ctime(&aTimeBuffer
.modtime
));
371 if ( pLastAccessTime
!= nullptr )
373 aTimeBuffer
.actime
=pLastAccessTime
->Seconds
;
377 aTimeBuffer
.actime
=aFileStat
.st_atime
;
380 if ( pLastWriteTime
!= nullptr )
382 aTimeBuffer
.modtime
=pLastWriteTime
->Seconds
;
386 aTimeBuffer
.modtime
=aFileStat
.st_mtime
;
389 /* mfe: Creation time not used here! */
391 #ifdef DEBUG_OSL_FILE
392 fprintf(stderr
,"File Times are (in localtime):\n");
393 pTM
=localtime(&aFileStat
.st_ctime
);
394 fprintf(stderr
,"CreationTime now '%s'\n",asctime(pTM
));
395 pTM
=localtime(&aTimeBuffer
.actime
);
396 fprintf(stderr
,"AccessTime now '%s'\n",asctime(pTM
));
397 pTM
=localtime(&aTimeBuffer
.modtime
);
398 fprintf(stderr
,"Modification now '%s'\n",asctime(pTM
));
400 fprintf(stderr
,"File Times are (in UTC):\n");
401 fprintf(stderr
,"CreationTime now '%s'\n",ctime(&aFileStat
.st_ctime
));
402 fprintf(stderr
,"AccessTime now '%s'\n",ctime(&aTimeBuffer
.actime
));
403 fprintf(stderr
,"Modification now '%s'\n",ctime(&aTimeBuffer
.modtime
));
406 nRet
= utime_c(pszFilePath
,&aTimeBuffer
);
410 return oslTranslateFileError(nRet
);
413 return osl_File_E_None
;
416 oslFileError SAL_CALL
osl_setFileTime (
417 rtl_uString
* ustrFileURL
,
418 SAL_UNUSED_PARAMETER
const TimeValue
* /* pCreationTime */,
419 const TimeValue
* pLastAccessTime
,
420 const TimeValue
* pLastWriteTime
)
425 OSL_ASSERT( ustrFileURL
);
427 /* convert file url to system path */
428 eRet
= FileURLToPath( path
, PATH_MAX
, ustrFileURL
);
429 if( eRet
!= osl_File_E_None
)
433 if ( macxp_resolveAlias( path
, PATH_MAX
) != 0 )
434 return oslTranslateFileError( errno
);
437 return osl_psz_setFileTime( path
, pLastAccessTime
, pLastWriteTime
);
441 SAL_CALL
osl_identicalDirectoryItem( oslDirectoryItem a
, oslDirectoryItem b
)
443 DirectoryItem_Impl
*pA
= static_cast<DirectoryItem_Impl
*>(a
);
444 DirectoryItem_Impl
*pB
= static_cast<DirectoryItem_Impl
*>(b
);
447 /* same name => same item, unless renaming / moving madness has occurred */
448 if (pA
->m_strFilePath
== pB
->m_strFilePath
)
451 struct stat a_stat
, b_stat
;
453 if (osl::lstat(pA
->m_strFilePath
, a_stat
) != 0 ||
454 osl::lstat(pB
->m_strFilePath
, b_stat
) != 0)
457 return (a_stat
.st_ino
== b_stat
.st_ino
);
460 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */