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 .
23 #include <sys/types.h>
29 #include <osl/diagnose.h>
30 #include <osl/thread.h>
32 #include "file_impl.hxx"
33 #include "file_error_transl.hxx"
34 #include "file_path_helper.hxx"
35 #include "file_url.hxx"
36 #include "uunxapi.hxx"
40 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 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 void set_file_access_rights(const OString
& file_path
, oslFileStatus
* pStat
)
105 pStat
->uValidFields
|= osl_FileStatus_Mask_Attributes
;
107 if (osl::access(file_path
, W_OK
) < 0)
108 pStat
->uAttributes
|= osl_File_Attribute_ReadOnly
;
110 if (osl::access(file_path
, X_OK
) == 0)
111 pStat
->uAttributes
|= osl_File_Attribute_Executable
;
114 void set_file_hidden_status(const OString
& file_path
, oslFileStatus
* pStat
)
116 pStat
->uAttributes
= osl::systemPathIsHiddenFileOrDirectoryEntry(file_path
) ? osl_File_Attribute_Hidden
: 0;
117 pStat
->uValidFields
|= osl_FileStatus_Mask_Attributes
;
120 /* the set_file_access_rights must be called after set_file_hidden_status(...) and
121 set_file_access_mask(...) because of the hack in set_file_access_rights(...) */
122 void set_file_attributes(
123 const OString
& file_path
, const struct stat
& file_stat
, const sal_uInt32 uFieldMask
, oslFileStatus
* pStat
)
125 set_file_hidden_status(file_path
, pStat
);
126 set_file_access_mask(file_stat
, pStat
);
128 // we set the file access rights only on demand
129 // because it's potentially expensive
130 if (uFieldMask
& osl_FileStatus_Mask_Attributes
)
131 set_file_access_rights(file_path
, pStat
);
134 void set_file_access_time(const struct stat
& file_stat
, oslFileStatus
* pStat
)
136 pStat
->aAccessTime
.Seconds
= file_stat
.st_atime
;
137 pStat
->aAccessTime
.Nanosec
= 0;
138 pStat
->uValidFields
|= osl_FileStatus_Mask_AccessTime
;
141 void set_file_modify_time(const struct stat
& file_stat
, oslFileStatus
* pStat
)
143 pStat
->aModifyTime
.Seconds
= file_stat
.st_mtime
;
144 pStat
->aModifyTime
.Nanosec
= 0;
145 pStat
->uValidFields
|= osl_FileStatus_Mask_ModifyTime
;
148 void set_file_size(const struct stat
& file_stat
, oslFileStatus
* pStat
)
150 if (S_ISREG(file_stat
.st_mode
))
152 pStat
->uFileSize
= file_stat
.st_size
;
153 pStat
->uValidFields
|= osl_FileStatus_Mask_FileSize
;
157 /* we only need to call stat or lstat if one of the
158 following flags is set */
159 bool is_stat_call_necessary(sal_uInt32 field_mask
, oslFileType file_type
)
162 ((field_mask
& osl_FileStatus_Mask_Type
) && (file_type
== osl_File_Type_Unknown
)) ||
163 (field_mask
& osl_FileStatus_Mask_Attributes
) ||
164 (field_mask
& osl_FileStatus_Mask_CreationTime
) ||
165 (field_mask
& osl_FileStatus_Mask_AccessTime
) ||
166 (field_mask
& osl_FileStatus_Mask_ModifyTime
) ||
167 (field_mask
& osl_FileStatus_Mask_FileSize
) ||
168 (field_mask
& osl_FileStatus_Mask_LinkTargetURL
) ||
169 (field_mask
& osl_FileStatus_Mask_Validate
));
172 oslFileError
set_link_target_url(const OString
& file_path
, oslFileStatus
* pStat
)
175 if (!osl::realpath(file_path
, link_target
))
176 return oslTranslateFileError(errno
);
179 oslFileError osl_error
= osl::detail::convertPathnameToUrl(link_target
, &url
);
180 if (osl_error
!= osl_File_E_None
)
182 rtl_uString_assign(&pStat
->ustrLinkTargetURL
, url
.pData
);
184 pStat
->uValidFields
|= osl_FileStatus_Mask_LinkTargetURL
;
185 return osl_File_E_None
;
188 oslFileError
setup_osl_getFileStatus(
189 DirectoryItem_Impl
* pImpl
, oslFileStatus
* pStat
, OString
& file_path
)
191 if ((pImpl
== nullptr) || (pStat
== nullptr))
192 return osl_File_E_INVAL
;
194 file_path
= pImpl
->m_strFilePath
;
195 OSL_ASSERT(!file_path
.isEmpty());
196 if (file_path
.isEmpty())
197 return osl_File_E_INVAL
;
199 pStat
->uValidFields
= 0;
200 return osl_File_E_None
;
205 oslFileError SAL_CALL
osl_getFileStatus(oslDirectoryItem Item
, oslFileStatus
* pStat
, sal_uInt32 uFieldMask
)
207 DirectoryItem_Impl
* pImpl
= static_cast< DirectoryItem_Impl
* >(Item
);
210 oslFileError osl_error
= setup_osl_getFileStatus(pImpl
, pStat
, file_path
);
211 if (osl_error
!= osl_File_E_None
)
214 struct stat file_stat
;
216 bool bStatNeeded
= is_stat_call_necessary(uFieldMask
, pImpl
->getFileType());
217 if (bStatNeeded
&& (osl::lstat(file_path
, file_stat
) != 0))
218 return oslTranslateFileError(errno
);
222 // we set all these attributes because it's cheap
223 set_file_type(file_stat
, pStat
);
224 set_file_access_time(file_stat
, pStat
);
225 set_file_modify_time(file_stat
, pStat
);
226 set_file_size(file_stat
, pStat
);
227 set_file_attributes(file_path
, file_stat
, uFieldMask
, pStat
);
229 // file exists semantic of osl_FileStatus_Mask_Validate
230 if ((uFieldMask
& osl_FileStatus_Mask_LinkTargetURL
) && S_ISLNK(file_stat
.st_mode
))
232 osl_error
= set_link_target_url(file_path
, pStat
);
233 if (osl_error
!= osl_File_E_None
)
237 #ifdef _DIRENT_HAVE_D_TYPE
238 else if (uFieldMask
& osl_FileStatus_Mask_Type
)
240 pStat
->eType
= pImpl
->getFileType();
241 pStat
->uValidFields
|= osl_FileStatus_Mask_Type
;
243 #endif /* _DIRENT_HAVE_D_TYPE */
245 if (uFieldMask
& osl_FileStatus_Mask_FileURL
)
248 if ((osl_error
= osl::detail::convertPathnameToUrl(file_path
, &url
)) != osl_File_E_None
)
250 rtl_uString_assign(&pStat
->ustrFileURL
, url
.pData
);
252 pStat
->uValidFields
|= osl_FileStatus_Mask_FileURL
;
255 if (uFieldMask
& osl_FileStatus_Mask_FileName
)
258 osl_systemPathGetFileNameOrLastDirectoryPart(file_path
.pData
, &name
.pData
);
259 bool ok
= rtl_convertStringToUString(
260 &pStat
->ustrFileName
, name
.getStr(), name
.getLength(), osl_getThreadTextEncoding(),
261 (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_DEFAULT
| RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_DEFAULT
262 | RTL_TEXTTOUNICODE_FLAGS_INVALID_DEFAULT
));
263 assert(ok
); (void)ok
;
264 pStat
->uValidFields
|= osl_FileStatus_Mask_FileName
;
266 return osl_File_E_None
;
269 static oslFileError
osl_psz_setFileAttributes( const 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(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( errno
);
326 return osl_psz_setFileAttributes( path
, uAttributes
);
329 static oslFileError
osl_psz_setFileTime (
330 const char* pszFilePath
,
331 const TimeValue
* pLastAccessTime
,
332 const TimeValue
* pLastWriteTime
)
335 struct utimbuf aTimeBuffer
;
336 struct stat aFileStat
;
337 #ifdef DEBUG_OSL_FILE
341 nRet
= lstat_c(pszFilePath
,&aFileStat
);
346 return oslTranslateFileError(nRet
);
349 #ifdef DEBUG_OSL_FILE
350 fprintf(stderr
,"File Times are (in localtime):\n");
351 pTM
=localtime(&aFileStat
.st_ctime
);
352 fprintf(stderr
,"CreationTime is '%s'\n",asctime(pTM
));
353 pTM
=localtime(&aFileStat
.st_atime
);
354 fprintf(stderr
,"AccessTime is '%s'\n",asctime(pTM
));
355 pTM
=localtime(&aFileStat
.st_mtime
);
356 fprintf(stderr
,"Modification is '%s'\n",asctime(pTM
));
358 fprintf(stderr
,"File Times are (in UTC):\n");
359 fprintf(stderr
,"CreationTime is '%s'\n",ctime(&aFileStat
.st_ctime
));
360 fprintf(stderr
,"AccessTime is '%s'\n",ctime(&aTimeBuffer
.actime
));
361 fprintf(stderr
,"Modification is '%s'\n",ctime(&aTimeBuffer
.modtime
));
364 if ( pLastAccessTime
!= nullptr )
366 aTimeBuffer
.actime
=pLastAccessTime
->Seconds
;
370 aTimeBuffer
.actime
=aFileStat
.st_atime
;
373 if ( pLastWriteTime
!= nullptr )
375 aTimeBuffer
.modtime
=pLastWriteTime
->Seconds
;
379 aTimeBuffer
.modtime
=aFileStat
.st_mtime
;
382 /* mfe: Creation time not used here! */
384 #ifdef DEBUG_OSL_FILE
385 fprintf(stderr
,"File Times are (in localtime):\n");
386 pTM
=localtime(&aFileStat
.st_ctime
);
387 fprintf(stderr
,"CreationTime now '%s'\n",asctime(pTM
));
388 pTM
=localtime(&aTimeBuffer
.actime
);
389 fprintf(stderr
,"AccessTime now '%s'\n",asctime(pTM
));
390 pTM
=localtime(&aTimeBuffer
.modtime
);
391 fprintf(stderr
,"Modification now '%s'\n",asctime(pTM
));
393 fprintf(stderr
,"File Times are (in UTC):\n");
394 fprintf(stderr
,"CreationTime now '%s'\n",ctime(&aFileStat
.st_ctime
));
395 fprintf(stderr
,"AccessTime now '%s'\n",ctime(&aTimeBuffer
.actime
));
396 fprintf(stderr
,"Modification now '%s'\n",ctime(&aTimeBuffer
.modtime
));
399 nRet
= utime_c(pszFilePath
,&aTimeBuffer
);
403 return oslTranslateFileError(nRet
);
406 return osl_File_E_None
;
409 oslFileError SAL_CALL
osl_setFileTime (
410 rtl_uString
* ustrFileURL
,
411 SAL_UNUSED_PARAMETER
const TimeValue
* /* pCreationTime */,
412 const TimeValue
* pLastAccessTime
,
413 const TimeValue
* pLastWriteTime
)
418 OSL_ASSERT( ustrFileURL
);
420 /* convert file url to system path */
421 eRet
= FileURLToPath( path
, PATH_MAX
, ustrFileURL
);
422 if( eRet
!= osl_File_E_None
)
426 if ( macxp_resolveAlias( path
, PATH_MAX
) != 0 )
427 return oslTranslateFileError( errno
);
430 return osl_psz_setFileTime( path
, pLastAccessTime
, pLastWriteTime
);
434 SAL_CALL
osl_identicalDirectoryItem( oslDirectoryItem a
, oslDirectoryItem b
)
436 DirectoryItem_Impl
*pA
= static_cast<DirectoryItem_Impl
*>(a
);
437 DirectoryItem_Impl
*pB
= static_cast<DirectoryItem_Impl
*>(b
);
440 /* same name => same item, unless renaming / moving madness has occurred */
441 if (pA
->m_strFilePath
== pB
->m_strFilePath
)
444 struct stat a_stat
, b_stat
;
446 if (osl::lstat(pA
->m_strFilePath
, a_stat
) != 0 ||
447 osl::lstat(pB
->m_strFilePath
, b_stat
) != 0)
450 return (a_stat
.st_ino
== b_stat
.st_ino
);
453 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */