Version 4.2.0.1, tag libreoffice-4.2.0.1
[LibreOffice.git] / sal / osl / unx / file_stat.cxx
blob5d6bd109482d18fb308bd0a6aa37a8e199f127c4
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 .
20 #include "osl/file.h"
21 #include "osl/detail/file.h"
23 #include "system.h"
24 #include <sys/types.h>
25 #include <dirent.h>
26 #include <errno.h>
27 #include <limits.h>
28 #include <unistd.h>
30 #include "file_impl.hxx"
31 #include "file_error_transl.h"
32 #include "file_path_helper.hxx"
33 #include "file_url.h"
34 #include "uunxapi.hxx"
36 namespace
38 inline void set_file_type(const struct stat& file_stat, oslFileStatus* pStat)
40 /* links to directories state also to be a directory */
41 if (S_ISLNK(file_stat.st_mode))
42 pStat->eType = osl_File_Type_Link;
43 else if (S_ISDIR(file_stat.st_mode))
44 pStat->eType = osl_File_Type_Directory;
45 else if (S_ISREG(file_stat.st_mode))
46 pStat->eType = osl_File_Type_Regular;
47 else if (S_ISFIFO(file_stat.st_mode))
48 pStat->eType = osl_File_Type_Fifo;
49 else if (S_ISSOCK(file_stat.st_mode))
50 pStat->eType = osl_File_Type_Socket;
51 else if (S_ISCHR(file_stat.st_mode) || S_ISBLK(file_stat.st_mode))
52 pStat->eType = osl_File_Type_Special;
53 else
54 pStat->eType = osl_File_Type_Unknown;
56 pStat->uValidFields |= osl_FileStatus_Mask_Type;
59 inline void set_file_access_mask(const struct stat& file_stat, oslFileStatus* pStat)
61 // user permissions
62 if (S_IRUSR & file_stat.st_mode)
63 pStat->uAttributes |= osl_File_Attribute_OwnRead;
65 if (S_IWUSR & file_stat.st_mode)
66 pStat->uAttributes |= osl_File_Attribute_OwnWrite;
68 if (S_IXUSR & file_stat.st_mode)
69 pStat->uAttributes |= osl_File_Attribute_OwnExe;
71 // group permissions
72 if (S_IRGRP & file_stat.st_mode)
73 pStat->uAttributes |= osl_File_Attribute_GrpRead;
75 if (S_IWGRP & file_stat.st_mode)
76 pStat->uAttributes |= osl_File_Attribute_GrpWrite;
78 if (S_IXGRP & file_stat.st_mode)
79 pStat->uAttributes |= osl_File_Attribute_GrpExe;
81 // others permissions
82 if (S_IROTH & file_stat.st_mode)
83 pStat->uAttributes |= osl_File_Attribute_OthRead;
85 if (S_IWOTH & file_stat.st_mode)
86 pStat->uAttributes |= osl_File_Attribute_OthWrite;
88 if (S_IXOTH & file_stat.st_mode)
89 pStat->uAttributes |= osl_File_Attribute_OthExe;
91 pStat->uValidFields |= osl_FileStatus_Mask_Attributes;
94 /* This code used not to use access(...) because access follows links which
95 may cause performance problems see #97133. (That apparently references a
96 no-longer accessible Hamburg-internal bug-tracking system.)
97 However, contrary to what is stated above the use of access calls is
98 required on network file systems not using unix semantics (AFS, see
99 fdo#43095).
101 inline void set_file_access_rights(const rtl::OUString& file_path, oslFileStatus* pStat)
103 pStat->uValidFields |= osl_FileStatus_Mask_Attributes;
105 if (access_u(file_path.pData, W_OK) < 0)
106 pStat->uAttributes |= osl_File_Attribute_ReadOnly;
108 if (access_u(file_path.pData, X_OK) == 0)
109 pStat->uAttributes |= osl_File_Attribute_Executable;
113 inline void set_file_hidden_status(const rtl::OUString& file_path, oslFileStatus* pStat)
115 pStat->uAttributes = osl::systemPathIsHiddenFileOrDirectoryEntry(file_path) ? osl_File_Attribute_Hidden : 0;
116 pStat->uValidFields |= osl_FileStatus_Mask_Attributes;
119 /* the set_file_access_rights must be called after set_file_hidden_status(...) and
120 set_file_access_mask(...) because of the hack in set_file_access_rights(...) */
121 inline void set_file_attributes(
122 const rtl::OUString& file_path, const struct stat& file_stat, const sal_uInt32 uFieldMask, oslFileStatus* pStat)
124 set_file_hidden_status(file_path, pStat);
125 set_file_access_mask(file_stat, pStat);
127 // we set the file access rights only on demand
128 // because it's potentially expensive
129 if (uFieldMask & osl_FileStatus_Mask_Attributes)
130 set_file_access_rights(file_path, pStat);
133 inline void set_file_access_time(const struct stat& file_stat, oslFileStatus* pStat)
135 pStat->aAccessTime.Seconds = file_stat.st_atime;
136 pStat->aAccessTime.Nanosec = 0;
137 pStat->uValidFields |= osl_FileStatus_Mask_AccessTime;
140 inline void set_file_modify_time(const struct stat& file_stat, oslFileStatus* pStat)
142 pStat->aModifyTime.Seconds = file_stat.st_mtime;
143 pStat->aModifyTime.Nanosec = 0;
144 pStat->uValidFields |= osl_FileStatus_Mask_ModifyTime;
147 inline void set_file_size(const struct stat& file_stat, oslFileStatus* pStat)
149 if (S_ISREG(file_stat.st_mode))
151 pStat->uFileSize = file_stat.st_size;
152 pStat->uValidFields |= osl_FileStatus_Mask_FileSize;
156 /* we only need to call stat or lstat if one of the
157 following flags is set */
158 inline bool is_stat_call_necessary(sal_uInt32 field_mask, oslFileType file_type = osl_File_Type_Unknown)
160 return (
161 ((field_mask & osl_FileStatus_Mask_Type) && (file_type == osl_File_Type_Unknown)) ||
162 (field_mask & osl_FileStatus_Mask_Attributes) ||
163 (field_mask & osl_FileStatus_Mask_CreationTime) ||
164 (field_mask & osl_FileStatus_Mask_AccessTime) ||
165 (field_mask & osl_FileStatus_Mask_ModifyTime) ||
166 (field_mask & osl_FileStatus_Mask_FileSize) ||
167 (field_mask & osl_FileStatus_Mask_LinkTargetURL) ||
168 (field_mask & osl_FileStatus_Mask_Validate));
171 inline oslFileError set_link_target_url(const rtl::OUString& file_path, oslFileStatus* pStat)
173 rtl::OUString link_target;
174 if (!osl::realpath(file_path, link_target))
175 return oslTranslateFileError(OSL_FET_ERROR, errno);
177 oslFileError osl_error = osl_getFileURLFromSystemPath(link_target.pData, &pStat->ustrLinkTargetURL);
178 if (osl_error != osl_File_E_None)
179 return osl_error;
181 pStat->uValidFields |= osl_FileStatus_Mask_LinkTargetURL;
182 return osl_File_E_None;
185 inline oslFileError setup_osl_getFileStatus(
186 DirectoryItem_Impl * pImpl, oslFileStatus* pStat, rtl::OUString& file_path)
188 if ((NULL == pImpl) || (NULL == pStat))
189 return osl_File_E_INVAL;
191 file_path = rtl::OUString(pImpl->m_ustrFilePath);
192 OSL_ASSERT(!file_path.isEmpty());
193 if (file_path.isEmpty())
194 return osl_File_E_INVAL;
196 pStat->uValidFields = 0;
197 return osl_File_E_None;
202 oslFileError SAL_CALL osl_getFileStatus(oslDirectoryItem Item, oslFileStatus* pStat, sal_uInt32 uFieldMask)
204 DirectoryItem_Impl * pImpl = static_cast< DirectoryItem_Impl* >(Item);
206 rtl::OUString file_path;
207 oslFileError osl_error = setup_osl_getFileStatus(pImpl, pStat, file_path);
208 if (osl_File_E_None != osl_error)
209 return osl_error;
211 struct stat file_stat;
213 bool bStatNeeded = is_stat_call_necessary(uFieldMask, pImpl->getFileType());
214 if (bStatNeeded && (0 != osl::lstat(file_path, file_stat)))
215 return oslTranslateFileError(OSL_FET_ERROR, errno);
217 if (bStatNeeded)
219 // we set all these attributes because it's cheap
220 set_file_type(file_stat, pStat);
221 set_file_access_time(file_stat, pStat);
222 set_file_modify_time(file_stat, pStat);
223 set_file_size(file_stat, pStat);
224 set_file_attributes(file_path, file_stat, uFieldMask, pStat);
226 // file exists semantic of osl_FileStatus_Mask_Validate
227 if ((uFieldMask & osl_FileStatus_Mask_LinkTargetURL) && S_ISLNK(file_stat.st_mode))
229 osl_error = set_link_target_url(file_path, pStat);
230 if (osl_error != osl_File_E_None)
231 return osl_error;
234 #ifdef _DIRENT_HAVE_D_TYPE
235 else if (uFieldMask & osl_FileStatus_Mask_Type)
237 pStat->eType = pImpl->getFileType();
238 pStat->uValidFields |= osl_FileStatus_Mask_Type;
240 #endif /* _DIRENT_HAVE_D_TYPE */
242 if (uFieldMask & osl_FileStatus_Mask_FileURL)
244 if ((osl_error = osl_getFileURLFromSystemPath(file_path.pData, &pStat->ustrFileURL)) != osl_File_E_None)
245 return osl_error;
247 pStat->uValidFields |= osl_FileStatus_Mask_FileURL;
250 if (uFieldMask & osl_FileStatus_Mask_FileName)
252 osl_systemPathGetFileNameOrLastDirectoryPart(file_path.pData, &pStat->ustrFileName);
253 pStat->uValidFields |= osl_FileStatus_Mask_FileName;
255 return osl_File_E_None;
258 static oslFileError osl_psz_setFileAttributes( const sal_Char* pszFilePath, sal_uInt64 uAttributes )
260 oslFileError osl_error = osl_File_E_None;
261 mode_t nNewMode = 0;
263 OSL_ENSURE(!(osl_File_Attribute_Hidden & uAttributes), "osl_File_Attribute_Hidden doesn't work under Unix");
265 if (uAttributes & osl_File_Attribute_OwnRead)
266 nNewMode |= S_IRUSR;
268 if (uAttributes & osl_File_Attribute_OwnWrite)
269 nNewMode|=S_IWUSR;
271 if (uAttributes & osl_File_Attribute_OwnExe)
272 nNewMode|=S_IXUSR;
274 if (uAttributes & osl_File_Attribute_GrpRead)
275 nNewMode|=S_IRGRP;
277 if (uAttributes & osl_File_Attribute_GrpWrite)
278 nNewMode|=S_IWGRP;
280 if (uAttributes & osl_File_Attribute_GrpExe)
281 nNewMode|=S_IXGRP;
283 if (uAttributes & osl_File_Attribute_OthRead)
284 nNewMode|=S_IROTH;
286 if (uAttributes & osl_File_Attribute_OthWrite)
287 nNewMode|=S_IWOTH;
289 if (uAttributes & osl_File_Attribute_OthExe)
290 nNewMode|=S_IXOTH;
292 if (chmod(pszFilePath, nNewMode) < 0)
293 osl_error = oslTranslateFileError(OSL_FET_ERROR, errno);
295 return osl_error;
298 oslFileError SAL_CALL osl_setFileAttributes( rtl_uString* ustrFileURL, sal_uInt64 uAttributes )
300 char path[PATH_MAX];
301 oslFileError eRet;
303 OSL_ASSERT( ustrFileURL );
305 /* convert file url to system path */
306 eRet = FileURLToPath( path, PATH_MAX, ustrFileURL );
307 if( eRet != osl_File_E_None )
308 return eRet;
310 #ifdef MACOSX
311 if ( macxp_resolveAlias( path, PATH_MAX ) != 0 )
312 return oslTranslateFileError( OSL_FET_ERROR, errno );
313 #endif/* MACOSX */
315 return osl_psz_setFileAttributes( path, uAttributes );
318 static oslFileError osl_psz_setFileTime (
319 const sal_Char* pszFilePath,
320 const TimeValue* pLastAccessTime,
321 const TimeValue* pLastWriteTime )
323 int nRet=0;
324 struct utimbuf aTimeBuffer;
325 struct stat aFileStat;
326 #ifdef DEBUG_OSL_FILE
327 struct tm* pTM=0;
328 #endif
330 nRet = lstat_c(pszFilePath,&aFileStat);
332 if ( nRet < 0 )
334 nRet=errno;
335 return oslTranslateFileError(OSL_FET_ERROR, nRet);
338 #ifdef DEBUG_OSL_FILE
339 fprintf(stderr,"File Times are (in localtime):\n");
340 pTM=localtime(&aFileStat.st_ctime);
341 fprintf(stderr,"CreationTime is '%s'\n",asctime(pTM));
342 pTM=localtime(&aFileStat.st_atime);
343 fprintf(stderr,"AccessTime is '%s'\n",asctime(pTM));
344 pTM=localtime(&aFileStat.st_mtime);
345 fprintf(stderr,"Modification is '%s'\n",asctime(pTM));
347 fprintf(stderr,"File Times are (in UTC):\n");
348 fprintf(stderr,"CreationTime is '%s'\n",ctime(&aFileStat.st_ctime));
349 fprintf(stderr,"AccessTime is '%s'\n",ctime(&aTimeBuffer.actime));
350 fprintf(stderr,"Modification is '%s'\n",ctime(&aTimeBuffer.modtime));
351 #endif
353 if ( pLastAccessTime != 0 )
355 aTimeBuffer.actime=pLastAccessTime->Seconds;
357 else
359 aTimeBuffer.actime=aFileStat.st_atime;
362 if ( pLastWriteTime != 0 )
364 aTimeBuffer.modtime=pLastWriteTime->Seconds;
366 else
368 aTimeBuffer.modtime=aFileStat.st_mtime;
371 /* mfe: Creation time not used here! */
373 #ifdef DEBUG_OSL_FILE
374 fprintf(stderr,"File Times are (in localtime):\n");
375 pTM=localtime(&aFileStat.st_ctime);
376 fprintf(stderr,"CreationTime now '%s'\n",asctime(pTM));
377 pTM=localtime(&aTimeBuffer.actime);
378 fprintf(stderr,"AccessTime now '%s'\n",asctime(pTM));
379 pTM=localtime(&aTimeBuffer.modtime);
380 fprintf(stderr,"Modification now '%s'\n",asctime(pTM));
382 fprintf(stderr,"File Times are (in UTC):\n");
383 fprintf(stderr,"CreationTime now '%s'\n",ctime(&aFileStat.st_ctime));
384 fprintf(stderr,"AccessTime now '%s'\n",ctime(&aTimeBuffer.actime));
385 fprintf(stderr,"Modification now '%s'\n",ctime(&aTimeBuffer.modtime));
386 #endif
388 nRet = utime_c(pszFilePath,&aTimeBuffer);
389 if ( nRet < 0 )
391 nRet=errno;
392 return oslTranslateFileError(OSL_FET_ERROR, nRet);
395 return osl_File_E_None;
398 oslFileError SAL_CALL osl_setFileTime (
399 rtl_uString* ustrFileURL,
400 SAL_UNUSED_PARAMETER const TimeValue* /* pCreationTime */,
401 const TimeValue* pLastAccessTime,
402 const TimeValue* pLastWriteTime )
404 char path[PATH_MAX];
405 oslFileError eRet;
407 OSL_ASSERT( ustrFileURL );
409 /* convert file url to system path */
410 eRet = FileURLToPath( path, PATH_MAX, ustrFileURL );
411 if( eRet != osl_File_E_None )
412 return eRet;
414 #ifdef MACOSX
415 if ( macxp_resolveAlias( path, PATH_MAX ) != 0 )
416 return oslTranslateFileError( OSL_FET_ERROR, errno );
417 #endif/* MACOSX */
419 return osl_psz_setFileTime( path, pLastAccessTime, pLastWriteTime );
422 sal_Bool
423 SAL_CALL osl_identicalDirectoryItem( oslDirectoryItem a, oslDirectoryItem b)
425 DirectoryItem_Impl *pA = (DirectoryItem_Impl *) a;
426 DirectoryItem_Impl *pB = (DirectoryItem_Impl *) b;
427 if (a == b)
428 return sal_True;
429 /* same name => same item, unless renaming / moving madness has occurred */
430 if (rtl_ustr_compare_WithLength(
431 pA->m_ustrFilePath->buffer, pA->m_ustrFilePath->length,
432 pB->m_ustrFilePath->buffer, pB->m_ustrFilePath->length ) == 0)
433 return sal_True;
435 struct stat a_stat, b_stat;
437 if (osl::lstat(rtl::OUString(pA->m_ustrFilePath), a_stat) != 0 ||
438 osl::lstat(rtl::OUString(pB->m_ustrFilePath), b_stat) != 0)
439 return sal_False;
441 return (a_stat.st_ino == b_stat.st_ino);
444 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */