update dev300-m58
[ooovba.git] / sal / osl / unx / file_stat.cxx
blob63f876ce8f11934ce3a28b9f389055d9af0eb6e9
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: file_stat.cxx,v $
10 * $Revision: 1.8 $
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"
34 #include "osl/file.h"
36 #include "system.h"
37 #include <sys/types.h>
38 #include <dirent.h>
39 #include <errno.h>
40 #include <limits.h>
41 #include <unistd.h>
43 #include "file_impl.hxx"
44 #include "file_error_transl.h"
45 #include "file_path_helper.hxx"
46 #include "file_url.h"
47 #include "uunxapi.hxx"
49 namespace /* private */
52 inline void set_file_type(const struct stat& file_stat, oslFileStatus* pStat)
54 /* links to directories state also to be a directory */
55 if (S_ISLNK(file_stat.st_mode))
56 pStat->eType = osl_File_Type_Link;
57 else if (S_ISDIR(file_stat.st_mode))
58 pStat->eType = osl_File_Type_Directory;
59 else if (S_ISREG(file_stat.st_mode))
60 pStat->eType = osl_File_Type_Regular;
61 else if (S_ISFIFO(file_stat.st_mode))
62 pStat->eType = osl_File_Type_Fifo;
63 else if (S_ISSOCK(file_stat.st_mode))
64 pStat->eType = osl_File_Type_Socket;
65 else if (S_ISCHR(file_stat.st_mode) || S_ISBLK(file_stat.st_mode))
66 pStat->eType = osl_File_Type_Special;
67 else
68 pStat->eType = osl_File_Type_Unknown;
70 pStat->uValidFields |= osl_FileStatus_Mask_Type;
73 inline void set_file_access_mask(const struct stat& file_stat, oslFileStatus* pStat)
75 // user permissions
76 if (S_IRUSR & file_stat.st_mode)
77 pStat->uAttributes |= osl_File_Attribute_OwnRead;
79 if (S_IWUSR & file_stat.st_mode)
80 pStat->uAttributes |= osl_File_Attribute_OwnWrite;
82 if (S_IXUSR & file_stat.st_mode)
83 pStat->uAttributes |= osl_File_Attribute_OwnExe;
85 // group permissions
86 if (S_IRGRP & file_stat.st_mode)
87 pStat->uAttributes |= osl_File_Attribute_GrpRead;
89 if (S_IWGRP & file_stat.st_mode)
90 pStat->uAttributes |= osl_File_Attribute_GrpWrite;
92 if (S_IXGRP & file_stat.st_mode)
93 pStat->uAttributes |= osl_File_Attribute_GrpExe;
95 // others permissions
96 if (S_IROTH & file_stat.st_mode)
97 pStat->uAttributes |= osl_File_Attribute_OthRead;
99 if (S_IWOTH & file_stat.st_mode)
100 pStat->uAttributes |= osl_File_Attribute_OthWrite;
102 if (S_IXOTH & file_stat.st_mode)
103 pStat->uAttributes |= osl_File_Attribute_OthExe;
105 pStat->uValidFields |= osl_FileStatus_Mask_Attributes;
108 inline void set_file_access_rights(const struct stat& file_stat, int S_IR, int S_IW, int S_IX, oslFileStatus* pStat)
110 /* we cannot really map osl_File_Attribute_ReadOnly to
111 the Unix access rights, it's a Windows only flag
112 that's why the following hack. We set osl_FileStatus_Mask_Attributes
113 but if there is no read access for a file we clear the flag
114 again to signal to the caller that there are no file attributes
115 to read because that's better than to give them incorrect one.
117 pStat->uValidFields |= osl_FileStatus_Mask_Attributes;
119 if ((0 == (S_IW & file_stat.st_mode)) && (S_IR & file_stat.st_mode))
120 pStat->uAttributes |= osl_File_Attribute_ReadOnly;
122 if (S_IX & file_stat.st_mode)
123 pStat->uAttributes |= osl_File_Attribute_Executable;
126 /* a process may belong to up to NGROUPS_MAX groups, so when
127 checking group access rights, we have to check all belonging
128 groups */
129 inline bool is_in_process_grouplist(const gid_t file_group)
131 // check primary process group
133 if (getgid() == file_group)
134 return true;
136 // check supplementary process groups
138 gid_t grplist[NGROUPS_MAX];
139 int grp_number = getgroups(NGROUPS_MAX, grplist);
141 for (int i = 0; i < grp_number; i++)
143 if (grplist[i] == file_group)
144 return true;
146 return false;
149 /* Currently we are determining the file access right based
150 on the real user ID not the effective user ID!
151 We don't use access(...) because access follows links which
152 may cause performance problems see #97133.
154 inline void set_file_access_rights(const struct stat& file_stat, oslFileStatus* pStat)
156 if (getuid() == file_stat.st_uid)
158 set_file_access_rights(file_stat, S_IRUSR, S_IWUSR, S_IXUSR, pStat);
160 else if (is_in_process_grouplist(file_stat.st_gid))
162 set_file_access_rights(file_stat, S_IRGRP, S_IWGRP, S_IXGRP, pStat);
164 else
166 set_file_access_rights(file_stat, S_IROTH, S_IWOTH, S_IXOTH, pStat);
170 inline void set_file_hidden_status(const rtl::OUString& file_path, oslFileStatus* pStat)
172 pStat->uAttributes = osl::systemPathIsHiddenFileOrDirectoryEntry(file_path) ? osl_File_Attribute_Hidden : 0;
173 pStat->uValidFields |= osl_FileStatus_Mask_Attributes;
176 /* the set_file_access_rights must be called after set_file_hidden_status(...) and
177 set_file_access_mask(...) because of the hack in set_file_access_rights(...) */
178 inline void set_file_attributes(
179 const rtl::OUString& file_path, const struct stat& file_stat, const sal_uInt32 uFieldMask, oslFileStatus* pStat)
181 set_file_hidden_status(file_path, pStat);
182 set_file_access_mask(file_stat, pStat);
184 // we set the file access rights only on demand
185 // because it's potentially expensive
186 if (uFieldMask & osl_FileStatus_Mask_Attributes)
187 set_file_access_rights(file_stat, pStat);
190 inline void set_file_access_time(const struct stat& file_stat, oslFileStatus* pStat)
192 pStat->aAccessTime.Seconds = file_stat.st_atime;
193 pStat->aAccessTime.Nanosec = 0;
194 pStat->uValidFields |= osl_FileStatus_Mask_AccessTime;
197 inline void set_file_modify_time(const struct stat& file_stat, oslFileStatus* pStat)
199 pStat->aModifyTime.Seconds = file_stat.st_mtime;
200 pStat->aModifyTime.Nanosec = 0;
201 pStat->uValidFields |= osl_FileStatus_Mask_ModifyTime;
204 inline void set_file_size(const struct stat& file_stat, oslFileStatus* pStat)
206 if (S_ISREG(file_stat.st_mode))
208 pStat->uFileSize = file_stat.st_size;
209 pStat->uValidFields |= osl_FileStatus_Mask_FileSize;
213 /* we only need to call stat or lstat if one of the
214 following flags is set */
215 inline bool is_stat_call_necessary(sal_uInt32 field_mask, oslFileType file_type = osl_File_Type_Unknown)
217 return (
218 ((field_mask & osl_FileStatus_Mask_Type) && (file_type == osl_File_Type_Unknown)) ||
219 (field_mask & osl_FileStatus_Mask_Attributes) ||
220 (field_mask & osl_FileStatus_Mask_CreationTime) ||
221 (field_mask & osl_FileStatus_Mask_AccessTime) ||
222 (field_mask & osl_FileStatus_Mask_ModifyTime) ||
223 (field_mask & osl_FileStatus_Mask_FileSize) ||
224 (field_mask & osl_FileStatus_Mask_LinkTargetURL) ||
225 (field_mask & osl_FileStatus_Mask_Validate));
228 inline oslFileError set_link_target_url(const rtl::OUString& file_path, oslFileStatus* pStat)
230 rtl::OUString link_target;
231 if (!osl::realpath(file_path, link_target))
232 return oslTranslateFileError(OSL_FET_ERROR, errno);
234 oslFileError osl_error = osl_getFileURLFromSystemPath(link_target.pData, &pStat->ustrLinkTargetURL);
235 if (osl_error != osl_File_E_None)
236 return osl_error;
238 pStat->uValidFields |= osl_FileStatus_Mask_LinkTargetURL;
239 return osl_File_E_None;
242 inline oslFileError setup_osl_getFileStatus(
243 DirectoryItem_Impl * pImpl, oslFileStatus* pStat, rtl::OUString& file_path)
245 if ((NULL == pImpl) || (NULL == pStat))
246 return osl_File_E_INVAL;
248 file_path = rtl::OUString(pImpl->m_ustrFilePath);
249 OSL_ASSERT(file_path.getLength() > 0);
250 if (file_path.getLength() <= 0)
251 return osl_File_E_INVAL;
253 pStat->uValidFields = 0;
254 return osl_File_E_None;
257 } // end namespace private
260 /****************************************************************************
261 * osl_getFileStatus
262 ****************************************************************************/
264 oslFileError SAL_CALL osl_getFileStatus(oslDirectoryItem Item, oslFileStatus* pStat, sal_uInt32 uFieldMask)
266 DirectoryItem_Impl * pImpl = static_cast< DirectoryItem_Impl* >(Item);
268 rtl::OUString file_path;
269 oslFileError osl_error = setup_osl_getFileStatus(pImpl, pStat, file_path);
270 if (osl_File_E_None != osl_error)
271 return osl_error;
273 #if defined(__GNUC__) && (__GNUC__ < 3)
274 struct ::stat file_stat;
275 #else
276 struct stat file_stat;
277 #endif
279 bool bStatNeeded = is_stat_call_necessary(uFieldMask, pImpl->getFileType());
280 if (bStatNeeded && (0 != osl::lstat(file_path, file_stat)))
281 return oslTranslateFileError(OSL_FET_ERROR, errno);
283 if (bStatNeeded)
285 // we set all these attributes because it's cheap
286 set_file_type(file_stat, pStat);
287 set_file_access_time(file_stat, pStat);
288 set_file_modify_time(file_stat, pStat);
289 set_file_size(file_stat, pStat);
290 set_file_attributes(file_path, file_stat, uFieldMask, pStat);
292 // file exists semantic of osl_FileStatus_Mask_Validate
293 if ((uFieldMask & osl_FileStatus_Mask_LinkTargetURL) && S_ISLNK(file_stat.st_mode))
295 osl_error = set_link_target_url(file_path, pStat);
296 if (osl_error != osl_File_E_None)
297 return osl_error;
300 #ifdef _DIRENT_HAVE_D_TYPE
301 else if (uFieldMask & osl_FileStatus_Mask_Type)
303 pStat->eType = pImpl->getFileType();
304 pStat->uValidFields |= osl_FileStatus_Mask_Type;
306 #endif /* _DIRENT_HAVE_D_TYPE */
308 if (uFieldMask & osl_FileStatus_Mask_FileURL)
310 if ((osl_error = osl_getFileURLFromSystemPath(file_path.pData, &pStat->ustrFileURL)) != osl_File_E_None)
311 return osl_error;
313 pStat->uValidFields |= osl_FileStatus_Mask_FileURL;
316 if (uFieldMask & osl_FileStatus_Mask_FileName)
318 osl_systemPathGetFileNameOrLastDirectoryPart(file_path.pData, &pStat->ustrFileName);
319 pStat->uValidFields |= osl_FileStatus_Mask_FileName;
321 return osl_File_E_None;
324 /****************************************************************************/
325 /* osl_setFileAttributes */
326 /****************************************************************************/
328 static oslFileError osl_psz_setFileAttributes( const sal_Char* pszFilePath, sal_uInt64 uAttributes )
330 oslFileError osl_error = osl_File_E_None;
331 mode_t nNewMode = 0;
333 OSL_ENSURE(!(osl_File_Attribute_Hidden & uAttributes), "osl_File_Attribute_Hidden doesn't work under Unix");
335 if (uAttributes & osl_File_Attribute_OwnRead)
336 nNewMode |= S_IRUSR;
338 if (uAttributes & osl_File_Attribute_OwnWrite)
339 nNewMode|=S_IWUSR;
341 if (uAttributes & osl_File_Attribute_OwnExe)
342 nNewMode|=S_IXUSR;
344 if (uAttributes & osl_File_Attribute_GrpRead)
345 nNewMode|=S_IRGRP;
347 if (uAttributes & osl_File_Attribute_GrpWrite)
348 nNewMode|=S_IWGRP;
350 if (uAttributes & osl_File_Attribute_GrpExe)
351 nNewMode|=S_IXGRP;
353 if (uAttributes & osl_File_Attribute_OthRead)
354 nNewMode|=S_IROTH;
356 if (uAttributes & osl_File_Attribute_OthWrite)
357 nNewMode|=S_IWOTH;
359 if (uAttributes & osl_File_Attribute_OthExe)
360 nNewMode|=S_IXOTH;
362 if (chmod(pszFilePath, nNewMode) < 0)
363 osl_error = oslTranslateFileError(OSL_FET_ERROR, errno);
365 return osl_error;
368 oslFileError SAL_CALL osl_setFileAttributes( rtl_uString* ustrFileURL, sal_uInt64 uAttributes )
370 char path[PATH_MAX];
371 oslFileError eRet;
373 OSL_ASSERT( ustrFileURL );
375 /* convert file url to system path */
376 eRet = FileURLToPath( path, PATH_MAX, ustrFileURL );
377 if( eRet != osl_File_E_None )
378 return eRet;
380 #ifdef MACOSX
381 if ( macxp_resolveAlias( path, PATH_MAX ) != 0 )
382 return oslTranslateFileError( OSL_FET_ERROR, errno );
383 #endif/* MACOSX */
385 return osl_psz_setFileAttributes( path, uAttributes );
388 /****************************************************************************/
389 /* osl_setFileTime */
390 /****************************************************************************/
392 static oslFileError osl_psz_setFileTime (
393 const sal_Char* pszFilePath,
394 const TimeValue* /*pCreationTime*/,
395 const TimeValue* pLastAccessTime,
396 const TimeValue* pLastWriteTime )
398 int nRet=0;
399 struct utimbuf aTimeBuffer;
400 struct stat aFileStat;
401 #ifdef DEBUG_OSL_FILE
402 struct tm* pTM=0;
403 #endif
405 nRet = lstat(pszFilePath,&aFileStat);
407 if ( nRet < 0 )
409 nRet=errno;
410 return oslTranslateFileError(OSL_FET_ERROR, nRet);
413 #ifdef DEBUG_OSL_FILE
414 fprintf(stderr,"File Times are (in localtime):\n");
415 pTM=localtime(&aFileStat.st_ctime);
416 fprintf(stderr,"CreationTime is '%s'\n",asctime(pTM));
417 pTM=localtime(&aFileStat.st_atime);
418 fprintf(stderr,"AccessTime is '%s'\n",asctime(pTM));
419 pTM=localtime(&aFileStat.st_mtime);
420 fprintf(stderr,"Modification is '%s'\n",asctime(pTM));
422 fprintf(stderr,"File Times are (in UTC):\n");
423 fprintf(stderr,"CreationTime is '%s'\n",ctime(&aFileStat.st_ctime));
424 fprintf(stderr,"AccessTime is '%s'\n",ctime(&aTimeBuffer.actime));
425 fprintf(stderr,"Modification is '%s'\n",ctime(&aTimeBuffer.modtime));
426 #endif
428 if ( pLastAccessTime != 0 )
430 aTimeBuffer.actime=pLastAccessTime->Seconds;
432 else
434 aTimeBuffer.actime=aFileStat.st_atime;
437 if ( pLastWriteTime != 0 )
439 aTimeBuffer.modtime=pLastWriteTime->Seconds;
441 else
443 aTimeBuffer.modtime=aFileStat.st_mtime;
446 /* mfe: Creation time not used here! */
448 #ifdef DEBUG_OSL_FILE
449 fprintf(stderr,"File Times are (in localtime):\n");
450 pTM=localtime(&aFileStat.st_ctime);
451 fprintf(stderr,"CreationTime now '%s'\n",asctime(pTM));
452 pTM=localtime(&aTimeBuffer.actime);
453 fprintf(stderr,"AccessTime now '%s'\n",asctime(pTM));
454 pTM=localtime(&aTimeBuffer.modtime);
455 fprintf(stderr,"Modification now '%s'\n",asctime(pTM));
457 fprintf(stderr,"File Times are (in UTC):\n");
458 fprintf(stderr,"CreationTime now '%s'\n",ctime(&aFileStat.st_ctime));
459 fprintf(stderr,"AccessTime now '%s'\n",ctime(&aTimeBuffer.actime));
460 fprintf(stderr,"Modification now '%s'\n",ctime(&aTimeBuffer.modtime));
461 #endif
463 nRet=utime(pszFilePath,&aTimeBuffer);
464 if ( nRet < 0 )
466 nRet=errno;
467 return oslTranslateFileError(OSL_FET_ERROR, nRet);
470 return osl_File_E_None;
473 oslFileError SAL_CALL osl_setFileTime (
474 rtl_uString* ustrFileURL,
475 const TimeValue* pCreationTime,
476 const TimeValue* pLastAccessTime,
477 const TimeValue* pLastWriteTime )
479 char path[PATH_MAX];
480 oslFileError eRet;
482 OSL_ASSERT( ustrFileURL );
484 /* convert file url to system path */
485 eRet = FileURLToPath( path, PATH_MAX, ustrFileURL );
486 if( eRet != osl_File_E_None )
487 return eRet;
489 #ifdef MACOSX
490 if ( macxp_resolveAlias( path, PATH_MAX ) != 0 )
491 return oslTranslateFileError( OSL_FET_ERROR, errno );
492 #endif/* MACOSX */
494 return osl_psz_setFileTime( path, pCreationTime, pLastAccessTime, pLastWriteTime );