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 (uAttributes
& osl_File_Attribute_OwnRead
)
280 if (uAttributes
& osl_File_Attribute_OwnWrite
)
283 if (uAttributes
& osl_File_Attribute_OwnExe
)
286 if (uAttributes
& osl_File_Attribute_GrpRead
)
289 if (uAttributes
& osl_File_Attribute_GrpWrite
)
292 if (uAttributes
& osl_File_Attribute_GrpExe
)
295 if (uAttributes
& osl_File_Attribute_OthRead
)
298 if (uAttributes
& osl_File_Attribute_OthWrite
)
301 if (uAttributes
& osl_File_Attribute_OthExe
)
304 if (chmod(pszFilePath
, nNewMode
) < 0)
305 osl_error
= oslTranslateFileError(errno
);
310 oslFileError SAL_CALL
osl_setFileAttributes( rtl_uString
* ustrFileURL
, sal_uInt64 uAttributes
)
315 OSL_ASSERT( ustrFileURL
);
317 /* convert file url to system path */
318 eRet
= FileURLToPath( path
, PATH_MAX
, ustrFileURL
);
319 if( eRet
!= osl_File_E_None
)
323 if ( macxp_resolveAlias( path
, PATH_MAX
) != 0 )
324 return oslTranslateFileError( errno
);
327 return osl_psz_setFileAttributes( path
, uAttributes
);
330 static oslFileError
osl_psz_setFileTime (
331 const char* pszFilePath
,
332 const TimeValue
* pLastAccessTime
,
333 const TimeValue
* pLastWriteTime
)
336 struct utimbuf aTimeBuffer
;
337 struct stat aFileStat
;
338 #ifdef DEBUG_OSL_FILE
342 nRet
= lstat_c(pszFilePath
,&aFileStat
);
347 return oslTranslateFileError(nRet
);
350 #ifdef DEBUG_OSL_FILE
351 fprintf(stderr
,"File Times are (in localtime):\n");
352 pTM
=localtime(&aFileStat
.st_ctime
);
353 fprintf(stderr
,"CreationTime is '%s'\n",asctime(pTM
));
354 pTM
=localtime(&aFileStat
.st_atime
);
355 fprintf(stderr
,"AccessTime is '%s'\n",asctime(pTM
));
356 pTM
=localtime(&aFileStat
.st_mtime
);
357 fprintf(stderr
,"Modification is '%s'\n",asctime(pTM
));
359 fprintf(stderr
,"File Times are (in UTC):\n");
360 fprintf(stderr
,"CreationTime is '%s'\n",ctime(&aFileStat
.st_ctime
));
361 fprintf(stderr
,"AccessTime is '%s'\n",ctime(&aTimeBuffer
.actime
));
362 fprintf(stderr
,"Modification is '%s'\n",ctime(&aTimeBuffer
.modtime
));
365 if ( pLastAccessTime
!= nullptr )
367 aTimeBuffer
.actime
=pLastAccessTime
->Seconds
;
371 aTimeBuffer
.actime
=aFileStat
.st_atime
;
374 if ( pLastWriteTime
!= nullptr )
376 aTimeBuffer
.modtime
=pLastWriteTime
->Seconds
;
380 aTimeBuffer
.modtime
=aFileStat
.st_mtime
;
383 /* mfe: Creation time not used here! */
385 #ifdef DEBUG_OSL_FILE
386 fprintf(stderr
,"File Times are (in localtime):\n");
387 pTM
=localtime(&aFileStat
.st_ctime
);
388 fprintf(stderr
,"CreationTime now '%s'\n",asctime(pTM
));
389 pTM
=localtime(&aTimeBuffer
.actime
);
390 fprintf(stderr
,"AccessTime now '%s'\n",asctime(pTM
));
391 pTM
=localtime(&aTimeBuffer
.modtime
);
392 fprintf(stderr
,"Modification now '%s'\n",asctime(pTM
));
394 fprintf(stderr
,"File Times are (in UTC):\n");
395 fprintf(stderr
,"CreationTime now '%s'\n",ctime(&aFileStat
.st_ctime
));
396 fprintf(stderr
,"AccessTime now '%s'\n",ctime(&aTimeBuffer
.actime
));
397 fprintf(stderr
,"Modification now '%s'\n",ctime(&aTimeBuffer
.modtime
));
400 nRet
= utime_c(pszFilePath
,&aTimeBuffer
);
404 return oslTranslateFileError(nRet
);
407 return osl_File_E_None
;
410 oslFileError SAL_CALL
osl_setFileTime (
411 rtl_uString
* ustrFileURL
,
412 SAL_UNUSED_PARAMETER
const TimeValue
* /* pCreationTime */,
413 const TimeValue
* pLastAccessTime
,
414 const TimeValue
* pLastWriteTime
)
419 OSL_ASSERT( ustrFileURL
);
421 /* convert file url to system path */
422 eRet
= FileURLToPath( path
, PATH_MAX
, ustrFileURL
);
423 if( eRet
!= osl_File_E_None
)
427 if ( macxp_resolveAlias( path
, PATH_MAX
) != 0 )
428 return oslTranslateFileError( errno
);
431 return osl_psz_setFileTime( path
, pLastAccessTime
, pLastWriteTime
);
435 SAL_CALL
osl_identicalDirectoryItem( oslDirectoryItem a
, oslDirectoryItem b
)
437 DirectoryItem_Impl
*pA
= static_cast<DirectoryItem_Impl
*>(a
);
438 DirectoryItem_Impl
*pB
= static_cast<DirectoryItem_Impl
*>(b
);
441 /* same name => same item, unless renaming / moving madness has occurred */
442 if (pA
->m_strFilePath
== pB
->m_strFilePath
)
445 struct stat a_stat
, b_stat
;
447 if (osl::lstat(pA
->m_strFilePath
, a_stat
) != 0 ||
448 osl::lstat(pB
->m_strFilePath
, b_stat
) != 0)
451 return (a_stat
.st_ino
== b_stat
.st_ino
);
454 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */