1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: file_stat.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sal.hxx"
35 #include <sys/types.h>
56 #include <rtl/string.hxx>
58 #ifndef _OSL_UUNXAPI_H_
59 #include "uunxapi.hxx"
61 #include "file_path_helper.hxx"
62 #include "file_error_transl.h"
64 #ifdef _DIRENT_HAVE_D_TYPE
65 #include "file_impl.hxx"
68 namespace /* private */
71 inline void set_file_type(const struct stat
& file_stat
, oslFileStatus
* pStat
)
73 /* links to directories state also to be a directory */
74 if (S_ISLNK(file_stat
.st_mode
))
75 pStat
->eType
= osl_File_Type_Link
;
76 else if (S_ISDIR(file_stat
.st_mode
))
77 pStat
->eType
= osl_File_Type_Directory
;
78 else if (S_ISREG(file_stat
.st_mode
))
79 pStat
->eType
= osl_File_Type_Regular
;
80 else if (S_ISFIFO(file_stat
.st_mode
))
81 pStat
->eType
= osl_File_Type_Fifo
;
82 else if (S_ISSOCK(file_stat
.st_mode
))
83 pStat
->eType
= osl_File_Type_Socket
;
84 else if (S_ISCHR(file_stat
.st_mode
) || S_ISBLK(file_stat
.st_mode
))
85 pStat
->eType
= osl_File_Type_Special
;
87 pStat
->eType
= osl_File_Type_Unknown
;
89 pStat
->uValidFields
|= osl_FileStatus_Mask_Type
;
92 inline void set_file_access_mask(const struct stat
& file_stat
, oslFileStatus
* pStat
)
95 if (S_IRUSR
& file_stat
.st_mode
)
96 pStat
->uAttributes
|= osl_File_Attribute_OwnRead
;
98 if (S_IWUSR
& file_stat
.st_mode
)
99 pStat
->uAttributes
|= osl_File_Attribute_OwnWrite
;
101 if (S_IXUSR
& file_stat
.st_mode
)
102 pStat
->uAttributes
|= osl_File_Attribute_OwnExe
;
105 if (S_IRGRP
& file_stat
.st_mode
)
106 pStat
->uAttributes
|= osl_File_Attribute_GrpRead
;
108 if (S_IWGRP
& file_stat
.st_mode
)
109 pStat
->uAttributes
|= osl_File_Attribute_GrpWrite
;
111 if (S_IXGRP
& file_stat
.st_mode
)
112 pStat
->uAttributes
|= osl_File_Attribute_GrpExe
;
114 // others permissions
115 if (S_IROTH
& file_stat
.st_mode
)
116 pStat
->uAttributes
|= osl_File_Attribute_OthRead
;
118 if (S_IWOTH
& file_stat
.st_mode
)
119 pStat
->uAttributes
|= osl_File_Attribute_OthWrite
;
121 if (S_IXOTH
& file_stat
.st_mode
)
122 pStat
->uAttributes
|= osl_File_Attribute_OthExe
;
124 pStat
->uValidFields
|= osl_FileStatus_Mask_Attributes
;
127 inline void set_file_access_rights(const struct stat
& file_stat
, int S_IR
, int S_IW
, int S_IX
, oslFileStatus
* pStat
)
129 /* we cannot really map osl_File_Attribute_ReadOnly to
130 the Unix access rights, it's a Windows only flag
131 that's why the following hack. We set osl_FileStatus_Mask_Attributes
132 but if there is no read access for a file we clear the flag
133 again to signal to the caller that there are no file attributes
134 to read because that's better than to give them incorrect one.
136 pStat
->uValidFields
|= osl_FileStatus_Mask_Attributes
;
138 if ((0 == (S_IW
& file_stat
.st_mode
)) && (S_IR
& file_stat
.st_mode
))
139 pStat
->uAttributes
|= osl_File_Attribute_ReadOnly
;
141 if (S_IX
& file_stat
.st_mode
)
142 pStat
->uAttributes
|= osl_File_Attribute_Executable
;
145 /* a process may belong to up to NGROUPS_MAX groups, so when
146 checking group access rights, we have to check all belonging
148 inline bool is_in_process_grouplist(const gid_t file_group
)
150 // check primary process group
152 if (getgid() == file_group
)
155 // check supplementary process groups
157 gid_t grplist
[NGROUPS_MAX
];
158 int grp_number
= getgroups(NGROUPS_MAX
, grplist
);
160 for (int i
= 0; i
< grp_number
; i
++)
162 if (grplist
[i
] == file_group
)
168 /* Currently we are determining the file access right based
169 on the real user ID not the effective user ID!
170 We don't use access(...) because access follows links which
171 may cause performance problems see #97133.
173 inline void set_file_access_rights(const struct stat
& file_stat
, oslFileStatus
* pStat
)
175 if (getuid() == file_stat
.st_uid
)
177 set_file_access_rights(file_stat
, S_IRUSR
, S_IWUSR
, S_IXUSR
, pStat
);
179 else if (is_in_process_grouplist(file_stat
.st_gid
))
181 set_file_access_rights(file_stat
, S_IRGRP
, S_IWGRP
, S_IXGRP
, pStat
);
185 set_file_access_rights(file_stat
, S_IROTH
, S_IWOTH
, S_IXOTH
, pStat
);
189 inline void set_file_hidden_status(const rtl::OUString
& file_path
, oslFileStatus
* pStat
)
191 pStat
->uAttributes
= osl::systemPathIsHiddenFileOrDirectoryEntry(file_path
) ? osl_File_Attribute_Hidden
: 0;
192 pStat
->uValidFields
|= osl_FileStatus_Mask_Attributes
;
195 /* the set_file_access_rights must be called after set_file_hidden_status(...) and
196 set_file_access_mask(...) because of the hack in set_file_access_rights(...) */
197 inline void set_file_attributes(
198 const rtl::OUString
& file_path
, const struct stat
& file_stat
, const sal_uInt32 uFieldMask
, oslFileStatus
* pStat
)
200 set_file_hidden_status(file_path
, pStat
);
201 set_file_access_mask(file_stat
, pStat
);
203 // we set the file access rights only on demand
204 // because it's potentially expensive
205 if (uFieldMask
& osl_FileStatus_Mask_Attributes
)
206 set_file_access_rights(file_stat
, pStat
);
209 inline void set_file_access_time(const struct stat
& file_stat
, oslFileStatus
* pStat
)
211 pStat
->aAccessTime
.Seconds
= file_stat
.st_atime
;
212 pStat
->aAccessTime
.Nanosec
= 0;
213 pStat
->uValidFields
|= osl_FileStatus_Mask_AccessTime
;
216 inline void set_file_modify_time(const struct stat
& file_stat
, oslFileStatus
* pStat
)
218 pStat
->aModifyTime
.Seconds
= file_stat
.st_mtime
;
219 pStat
->aModifyTime
.Nanosec
= 0;
220 pStat
->uValidFields
|= osl_FileStatus_Mask_ModifyTime
;
223 inline void set_file_size(const struct stat
& file_stat
, oslFileStatus
* pStat
)
225 if (S_ISREG(file_stat
.st_mode
))
227 pStat
->uFileSize
= file_stat
.st_size
;
228 pStat
->uValidFields
|= osl_FileStatus_Mask_FileSize
;
232 /* we only need to call stat or lstat if one of the
233 following flags is set */
234 #ifdef _DIRENT_HAVE_D_TYPE
235 inline bool is_stat_call_necessary(sal_uInt32 field_mask
, oslDirectoryItemImpl
*pImpl
)
237 inline bool is_stat_call_necessary(sal_uInt32 field_mask
)
241 /* on linux the dirent might have d_type */
242 #ifdef _DIRENT_HAVE_D_TYPE
243 ((field_mask
& osl_FileStatus_Mask_Type
) && (!pImpl
->bHasType
|| pImpl
->DType
== DT_UNKNOWN
)) ||
245 (field_mask
& osl_FileStatus_Mask_Type
) ||
247 (field_mask
& osl_FileStatus_Mask_Attributes
) ||
248 (field_mask
& osl_FileStatus_Mask_CreationTime
) ||
249 (field_mask
& osl_FileStatus_Mask_AccessTime
) ||
250 (field_mask
& osl_FileStatus_Mask_ModifyTime
) ||
251 (field_mask
& osl_FileStatus_Mask_FileSize
) ||
252 (field_mask
& osl_FileStatus_Mask_LinkTargetURL
) ||
253 (field_mask
& osl_FileStatus_Mask_Validate
));
256 inline oslFileError
set_link_target_url(const rtl::OUString
& file_path
, oslFileStatus
* pStat
)
258 rtl::OUString link_target
;
259 if (!osl::realpath(file_path
, link_target
))
260 return oslTranslateFileError(OSL_FET_ERROR
, errno
);
262 oslFileError osl_error
= osl_getFileURLFromSystemPath(link_target
.pData
, &pStat
->ustrLinkTargetURL
);
263 if (osl_error
!= osl_File_E_None
)
266 pStat
->uValidFields
|= osl_FileStatus_Mask_LinkTargetURL
;
267 return osl_File_E_None
;
270 inline oslFileError
setup_osl_getFileStatus(oslDirectoryItem Item
, oslFileStatus
* pStat
, rtl::OUString
& file_path
)
272 if ((NULL
== Item
) || (NULL
== pStat
))
273 return osl_File_E_INVAL
;
275 #ifdef _DIRENT_HAVE_D_TYPE
276 file_path
= rtl::OUString(reinterpret_cast<rtl_uString
*>(((oslDirectoryItemImpl
* ) Item
)->ustrFilePath
));
278 file_path
= rtl::OUString(reinterpret_cast<rtl_uString
*>(Item
));
281 OSL_ASSERT(file_path
.getLength() > 0);
283 if (file_path
.getLength() <= 0)
284 return osl_File_E_INVAL
;
286 pStat
->uValidFields
= 0;
288 return osl_File_E_None
;
291 } // end namespace private
294 /****************************************************************************
296 ****************************************************************************/
298 oslFileError SAL_CALL
osl_getFileStatus(oslDirectoryItem Item
, oslFileStatus
* pStat
, sal_uInt32 uFieldMask
)
300 rtl::OUString file_path
;
301 oslFileError osl_error
= setup_osl_getFileStatus(Item
, pStat
, file_path
);
302 if (osl_File_E_None
!= osl_error
)
305 #if defined(__GNUC__) && (__GNUC__ < 3)
306 struct ::stat file_stat
;
308 struct stat file_stat
;
311 #ifdef _DIRENT_HAVE_D_TYPE
312 oslDirectoryItemImpl
* pImpl
= (oslDirectoryItemImpl
*) Item
;
313 bool bStatNeeded
= is_stat_call_necessary(uFieldMask
, pImpl
);
315 bool bStatNeeded
= is_stat_call_necessary(uFieldMask
);
318 if (bStatNeeded
&& (0 != osl::lstat(file_path
, file_stat
)))
319 return oslTranslateFileError(OSL_FET_ERROR
, errno
);
323 // we set all these attributes because it's cheap
324 set_file_type(file_stat
, pStat
);
325 set_file_access_time(file_stat
, pStat
);
326 set_file_modify_time(file_stat
, pStat
);
327 set_file_size(file_stat
, pStat
);
328 set_file_attributes(file_path
, file_stat
, uFieldMask
, pStat
);
330 // file exists semantic of osl_FileStatus_Mask_Validate
331 if ((uFieldMask
& osl_FileStatus_Mask_LinkTargetURL
) && S_ISLNK(file_stat
.st_mode
))
333 osl_error
= set_link_target_url(file_path
, pStat
);
334 if (osl_error
!= osl_File_E_None
)
338 #ifdef _DIRENT_HAVE_D_TYPE
339 else if (uFieldMask
& osl_FileStatus_Mask_Type
)
341 OSL_ASSERT(pImpl
->bHasType
);
346 pStat
->eType
= osl_File_Type_Link
;
349 pStat
->eType
= osl_File_Type_Directory
;
352 pStat
->eType
= osl_File_Type_Regular
;
355 pStat
->eType
= osl_File_Type_Fifo
;
358 pStat
->eType
= osl_File_Type_Socket
;
362 pStat
->eType
= osl_File_Type_Special
;
366 pStat
->eType
= osl_File_Type_Unknown
;
369 pStat
->uValidFields
|= osl_FileStatus_Mask_Type
;
373 if (uFieldMask
& osl_FileStatus_Mask_FileURL
)
375 if ((osl_error
= osl_getFileURLFromSystemPath(file_path
.pData
, &pStat
->ustrFileURL
)) != osl_File_E_None
)
378 pStat
->uValidFields
|= osl_FileStatus_Mask_FileURL
;
381 if (uFieldMask
& osl_FileStatus_Mask_FileName
)
383 osl_systemPathGetFileNameOrLastDirectoryPart(file_path
.pData
, &pStat
->ustrFileName
);
384 pStat
->uValidFields
|= osl_FileStatus_Mask_FileName
;
386 return osl_File_E_None
;