Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
20 : #include "osl/file.h"
21 :
22 : #include "system.hxx"
23 : #include <sys/types.h>
24 : #include <dirent.h>
25 : #include <errno.h>
26 : #include <limits.h>
27 : #include <unistd.h>
28 :
29 : #include <osl/diagnose.h>
30 :
31 : #include "file_impl.hxx"
32 : #include "file_error_transl.hxx"
33 : #include "file_path_helper.hxx"
34 : #include "file_url.hxx"
35 : #include "uunxapi.hxx"
36 :
37 : namespace
38 : {
39 83014 : inline void set_file_type(const struct stat& file_stat, oslFileStatus* pStat)
40 : {
41 : /* links to directories state also to be a directory */
42 83014 : if (S_ISLNK(file_stat.st_mode))
43 0 : pStat->eType = osl_File_Type_Link;
44 83014 : else if (S_ISDIR(file_stat.st_mode))
45 22987 : pStat->eType = osl_File_Type_Directory;
46 60027 : else if (S_ISREG(file_stat.st_mode))
47 60027 : pStat->eType = osl_File_Type_Regular;
48 0 : else if (S_ISFIFO(file_stat.st_mode))
49 0 : pStat->eType = osl_File_Type_Fifo;
50 0 : else if (S_ISSOCK(file_stat.st_mode))
51 0 : pStat->eType = osl_File_Type_Socket;
52 0 : else if (S_ISCHR(file_stat.st_mode) || S_ISBLK(file_stat.st_mode))
53 0 : pStat->eType = osl_File_Type_Special;
54 : else
55 0 : pStat->eType = osl_File_Type_Unknown;
56 :
57 83014 : pStat->uValidFields |= osl_FileStatus_Mask_Type;
58 83014 : }
59 :
60 83014 : inline void set_file_access_mask(const struct stat& file_stat, oslFileStatus* pStat)
61 : {
62 : // user permissions
63 83014 : if (S_IRUSR & file_stat.st_mode)
64 83014 : pStat->uAttributes |= osl_File_Attribute_OwnRead;
65 :
66 83014 : if (S_IWUSR & file_stat.st_mode)
67 83014 : pStat->uAttributes |= osl_File_Attribute_OwnWrite;
68 :
69 83014 : if (S_IXUSR & file_stat.st_mode)
70 25082 : pStat->uAttributes |= osl_File_Attribute_OwnExe;
71 :
72 : // group permissions
73 83014 : if (S_IRGRP & file_stat.st_mode)
74 63565 : pStat->uAttributes |= osl_File_Attribute_GrpRead;
75 :
76 83014 : if (S_IWGRP & file_stat.st_mode)
77 2703 : pStat->uAttributes |= osl_File_Attribute_GrpWrite;
78 :
79 83014 : if (S_IXGRP & file_stat.st_mode)
80 24916 : pStat->uAttributes |= osl_File_Attribute_GrpExe;
81 :
82 : // others permissions
83 83014 : if (S_IROTH & file_stat.st_mode)
84 63565 : pStat->uAttributes |= osl_File_Attribute_OthRead;
85 :
86 83014 : if (S_IWOTH & file_stat.st_mode)
87 2701 : pStat->uAttributes |= osl_File_Attribute_OthWrite;
88 :
89 83014 : if (S_IXOTH & file_stat.st_mode)
90 22924 : pStat->uAttributes |= osl_File_Attribute_OthExe;
91 :
92 83014 : pStat->uValidFields |= osl_FileStatus_Mask_Attributes;
93 83014 : }
94 :
95 : /* This code used not to use access(...) because access follows links which
96 : may cause performance problems see #97133. (That apparently references a
97 : no-longer accessible Hamburg-internal bug-tracking system.)
98 : However, contrary to what is stated above the use of access calls is
99 : required on network file systems not using unix semantics (AFS, see
100 : fdo#43095).
101 : */
102 10420 : inline void set_file_access_rights(const rtl::OUString& file_path, oslFileStatus* pStat)
103 : {
104 10420 : pStat->uValidFields |= osl_FileStatus_Mask_Attributes;
105 :
106 10420 : if (access_u(file_path.pData, W_OK) < 0)
107 0 : pStat->uAttributes |= osl_File_Attribute_ReadOnly;
108 :
109 10420 : if (access_u(file_path.pData, X_OK) == 0)
110 18 : pStat->uAttributes |= osl_File_Attribute_Executable;
111 10420 : }
112 :
113 83014 : inline void set_file_hidden_status(const rtl::OUString& file_path, oslFileStatus* pStat)
114 : {
115 83014 : pStat->uAttributes = osl::systemPathIsHiddenFileOrDirectoryEntry(file_path) ? osl_File_Attribute_Hidden : 0;
116 83014 : pStat->uValidFields |= osl_FileStatus_Mask_Attributes;
117 83014 : }
118 :
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 83014 : inline void set_file_attributes(
122 : const rtl::OUString& file_path, const struct stat& file_stat, const sal_uInt32 uFieldMask, oslFileStatus* pStat)
123 : {
124 83014 : set_file_hidden_status(file_path, pStat);
125 83014 : set_file_access_mask(file_stat, pStat);
126 :
127 : // we set the file access rights only on demand
128 : // because it's potentially expensive
129 83014 : if (uFieldMask & osl_FileStatus_Mask_Attributes)
130 10420 : set_file_access_rights(file_path, pStat);
131 83014 : }
132 :
133 83014 : inline void set_file_access_time(const struct stat& file_stat, oslFileStatus* pStat)
134 : {
135 83014 : pStat->aAccessTime.Seconds = file_stat.st_atime;
136 83014 : pStat->aAccessTime.Nanosec = 0;
137 83014 : pStat->uValidFields |= osl_FileStatus_Mask_AccessTime;
138 83014 : }
139 :
140 83014 : inline void set_file_modify_time(const struct stat& file_stat, oslFileStatus* pStat)
141 : {
142 83014 : pStat->aModifyTime.Seconds = file_stat.st_mtime;
143 83014 : pStat->aModifyTime.Nanosec = 0;
144 83014 : pStat->uValidFields |= osl_FileStatus_Mask_ModifyTime;
145 83014 : }
146 :
147 83014 : inline void set_file_size(const struct stat& file_stat, oslFileStatus* pStat)
148 : {
149 83014 : if (S_ISREG(file_stat.st_mode))
150 : {
151 60027 : pStat->uFileSize = file_stat.st_size;
152 60027 : pStat->uValidFields |= osl_FileStatus_Mask_FileSize;
153 : }
154 83014 : }
155 :
156 : /* we only need to call stat or lstat if one of the
157 : following flags is set */
158 227408 : inline bool is_stat_call_necessary(sal_uInt32 field_mask, oslFileType file_type = osl_File_Type_Unknown)
159 : {
160 : return (
161 545494 : ((field_mask & osl_FileStatus_Mask_Type) && (file_type == osl_File_Type_Unknown)) ||
162 314942 : (field_mask & osl_FileStatus_Mask_Attributes) ||
163 304522 : (field_mask & osl_FileStatus_Mask_CreationTime) ||
164 304522 : (field_mask & osl_FileStatus_Mask_AccessTime) ||
165 302999 : (field_mask & osl_FileStatus_Mask_ModifyTime) ||
166 301416 : (field_mask & osl_FileStatus_Mask_FileSize) ||
167 522648 : (field_mask & osl_FileStatus_Mask_LinkTargetURL) ||
168 227408 : (field_mask & osl_FileStatus_Mask_Validate));
169 : }
170 :
171 0 : inline oslFileError set_link_target_url(const rtl::OUString& file_path, oslFileStatus* pStat)
172 : {
173 0 : rtl::OUString link_target;
174 0 : if (!osl::realpath(file_path, link_target))
175 0 : return oslTranslateFileError(OSL_FET_ERROR, errno);
176 :
177 0 : oslFileError osl_error = osl_getFileURLFromSystemPath(link_target.pData, &pStat->ustrLinkTargetURL);
178 0 : if (osl_error != osl_File_E_None)
179 0 : return osl_error;
180 :
181 0 : pStat->uValidFields |= osl_FileStatus_Mask_LinkTargetURL;
182 0 : return osl_File_E_None;
183 : }
184 :
185 246392 : inline oslFileError setup_osl_getFileStatus(
186 : DirectoryItem_Impl * pImpl, oslFileStatus* pStat, rtl::OUString& file_path)
187 : {
188 246392 : if ((NULL == pImpl) || (NULL == pStat))
189 18984 : return osl_File_E_INVAL;
190 :
191 227408 : file_path = rtl::OUString(pImpl->m_ustrFilePath);
192 : OSL_ASSERT(!file_path.isEmpty());
193 227408 : if (file_path.isEmpty())
194 0 : return osl_File_E_INVAL;
195 :
196 227408 : pStat->uValidFields = 0;
197 227408 : return osl_File_E_None;
198 : }
199 :
200 : }
201 :
202 246392 : oslFileError SAL_CALL osl_getFileStatus(oslDirectoryItem Item, oslFileStatus* pStat, sal_uInt32 uFieldMask)
203 : {
204 246392 : DirectoryItem_Impl * pImpl = static_cast< DirectoryItem_Impl* >(Item);
205 :
206 246392 : rtl::OUString file_path;
207 246392 : oslFileError osl_error = setup_osl_getFileStatus(pImpl, pStat, file_path);
208 246392 : if (osl_File_E_None != osl_error)
209 18984 : return osl_error;
210 :
211 : struct stat file_stat;
212 :
213 227408 : bool bStatNeeded = is_stat_call_necessary(uFieldMask, pImpl->getFileType());
214 227408 : if (bStatNeeded && (0 != osl::lstat(file_path, file_stat)))
215 0 : return oslTranslateFileError(OSL_FET_ERROR, errno);
216 :
217 227408 : if (bStatNeeded)
218 : {
219 : // we set all these attributes because it's cheap
220 83014 : set_file_type(file_stat, pStat);
221 83014 : set_file_access_time(file_stat, pStat);
222 83014 : set_file_modify_time(file_stat, pStat);
223 83014 : set_file_size(file_stat, pStat);
224 83014 : set_file_attributes(file_path, file_stat, uFieldMask, pStat);
225 :
226 : // file exists semantic of osl_FileStatus_Mask_Validate
227 83014 : if ((uFieldMask & osl_FileStatus_Mask_LinkTargetURL) && S_ISLNK(file_stat.st_mode))
228 : {
229 0 : osl_error = set_link_target_url(file_path, pStat);
230 0 : if (osl_error != osl_File_E_None)
231 0 : return osl_error;
232 : }
233 : }
234 : #ifdef _DIRENT_HAVE_D_TYPE
235 144394 : else if (uFieldMask & osl_FileStatus_Mask_Type)
236 : {
237 84562 : pStat->eType = pImpl->getFileType();
238 84562 : pStat->uValidFields |= osl_FileStatus_Mask_Type;
239 : }
240 : #endif /* _DIRENT_HAVE_D_TYPE */
241 :
242 227408 : if (uFieldMask & osl_FileStatus_Mask_FileURL)
243 : {
244 132561 : if ((osl_error = osl_getFileURLFromSystemPath(file_path.pData, &pStat->ustrFileURL)) != osl_File_E_None)
245 0 : return osl_error;
246 :
247 132561 : pStat->uValidFields |= osl_FileStatus_Mask_FileURL;
248 : }
249 :
250 227408 : if (uFieldMask & osl_FileStatus_Mask_FileName)
251 : {
252 105121 : osl_systemPathGetFileNameOrLastDirectoryPart(file_path.pData, &pStat->ustrFileName);
253 105121 : pStat->uValidFields |= osl_FileStatus_Mask_FileName;
254 : }
255 227408 : return osl_File_E_None;
256 : }
257 :
258 21746 : static oslFileError osl_psz_setFileAttributes( const sal_Char* pszFilePath, sal_uInt64 uAttributes )
259 : {
260 21746 : oslFileError osl_error = osl_File_E_None;
261 21746 : mode_t nNewMode = 0;
262 :
263 : OSL_ENSURE(!(osl_File_Attribute_Hidden & uAttributes), "osl_File_Attribute_Hidden doesn't work under Unix");
264 :
265 21746 : if (uAttributes & osl_File_Attribute_OwnRead)
266 21711 : nNewMode |= S_IRUSR;
267 :
268 21746 : if (uAttributes & osl_File_Attribute_OwnWrite)
269 21745 : nNewMode|=S_IWUSR;
270 :
271 21746 : if (uAttributes & osl_File_Attribute_OwnExe)
272 57 : nNewMode|=S_IXUSR;
273 :
274 21746 : if (uAttributes & osl_File_Attribute_GrpRead)
275 20916 : nNewMode|=S_IRGRP;
276 :
277 21746 : if (uAttributes & osl_File_Attribute_GrpWrite)
278 18960 : nNewMode|=S_IWGRP;
279 :
280 21746 : if (uAttributes & osl_File_Attribute_GrpExe)
281 3 : nNewMode|=S_IXGRP;
282 :
283 21746 : if (uAttributes & osl_File_Attribute_OthRead)
284 20916 : nNewMode|=S_IROTH;
285 :
286 21746 : if (uAttributes & osl_File_Attribute_OthWrite)
287 34 : nNewMode|=S_IWOTH;
288 :
289 21746 : if (uAttributes & osl_File_Attribute_OthExe)
290 3 : nNewMode|=S_IXOTH;
291 :
292 21746 : if (chmod(pszFilePath, nNewMode) < 0)
293 0 : osl_error = oslTranslateFileError(OSL_FET_ERROR, errno);
294 :
295 21746 : return osl_error;
296 : }
297 :
298 21746 : oslFileError SAL_CALL osl_setFileAttributes( rtl_uString* ustrFileURL, sal_uInt64 uAttributes )
299 : {
300 : char path[PATH_MAX];
301 : oslFileError eRet;
302 :
303 : OSL_ASSERT( ustrFileURL );
304 :
305 : /* convert file url to system path */
306 21746 : eRet = FileURLToPath( path, PATH_MAX, ustrFileURL );
307 21746 : if( eRet != osl_File_E_None )
308 0 : return eRet;
309 :
310 : #ifdef MACOSX
311 : if ( macxp_resolveAlias( path, PATH_MAX ) != 0 )
312 : return oslTranslateFileError( OSL_FET_ERROR, errno );
313 : #endif/* MACOSX */
314 :
315 21746 : return osl_psz_setFileAttributes( path, uAttributes );
316 : }
317 :
318 0 : static oslFileError osl_psz_setFileTime (
319 : const sal_Char* pszFilePath,
320 : const TimeValue* pLastAccessTime,
321 : const TimeValue* pLastWriteTime )
322 : {
323 0 : int nRet=0;
324 : struct utimbuf aTimeBuffer;
325 : struct stat aFileStat;
326 : #ifdef DEBUG_OSL_FILE
327 : struct tm* pTM=0;
328 : #endif
329 :
330 0 : nRet = lstat_c(pszFilePath,&aFileStat);
331 :
332 0 : if ( nRet < 0 )
333 : {
334 0 : nRet=errno;
335 0 : return oslTranslateFileError(OSL_FET_ERROR, nRet);
336 : }
337 :
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));
346 :
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
352 :
353 0 : if ( pLastAccessTime != 0 )
354 : {
355 0 : aTimeBuffer.actime=pLastAccessTime->Seconds;
356 : }
357 : else
358 : {
359 0 : aTimeBuffer.actime=aFileStat.st_atime;
360 : }
361 :
362 0 : if ( pLastWriteTime != 0 )
363 : {
364 0 : aTimeBuffer.modtime=pLastWriteTime->Seconds;
365 : }
366 : else
367 : {
368 0 : aTimeBuffer.modtime=aFileStat.st_mtime;
369 : }
370 :
371 : /* mfe: Creation time not used here! */
372 :
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));
381 :
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
387 :
388 0 : nRet = utime_c(pszFilePath,&aTimeBuffer);
389 0 : if ( nRet < 0 )
390 : {
391 0 : nRet=errno;
392 0 : return oslTranslateFileError(OSL_FET_ERROR, nRet);
393 : }
394 :
395 0 : return osl_File_E_None;
396 : }
397 :
398 0 : oslFileError SAL_CALL osl_setFileTime (
399 : rtl_uString* ustrFileURL,
400 : SAL_UNUSED_PARAMETER const TimeValue* /* pCreationTime */,
401 : const TimeValue* pLastAccessTime,
402 : const TimeValue* pLastWriteTime )
403 : {
404 : char path[PATH_MAX];
405 : oslFileError eRet;
406 :
407 : OSL_ASSERT( ustrFileURL );
408 :
409 : /* convert file url to system path */
410 0 : eRet = FileURLToPath( path, PATH_MAX, ustrFileURL );
411 0 : if( eRet != osl_File_E_None )
412 0 : return eRet;
413 :
414 : #ifdef MACOSX
415 : if ( macxp_resolveAlias( path, PATH_MAX ) != 0 )
416 : return oslTranslateFileError( OSL_FET_ERROR, errno );
417 : #endif/* MACOSX */
418 :
419 0 : return osl_psz_setFileTime( path, pLastAccessTime, pLastWriteTime );
420 : }
421 :
422 : sal_Bool
423 0 : SAL_CALL osl_identicalDirectoryItem( oslDirectoryItem a, oslDirectoryItem b)
424 : {
425 0 : DirectoryItem_Impl *pA = static_cast<DirectoryItem_Impl *>(a);
426 0 : DirectoryItem_Impl *pB = static_cast<DirectoryItem_Impl *>(b);
427 0 : if (a == b)
428 0 : return sal_True;
429 : /* same name => same item, unless renaming / moving madness has occurred */
430 0 : if (rtl_ustr_compare_WithLength(
431 : pA->m_ustrFilePath->buffer, pA->m_ustrFilePath->length,
432 0 : pB->m_ustrFilePath->buffer, pB->m_ustrFilePath->length ) == 0)
433 0 : return sal_True;
434 :
435 : struct stat a_stat, b_stat;
436 :
437 0 : if (osl::lstat(rtl::OUString(pA->m_ustrFilePath), a_stat) != 0 ||
438 0 : osl::lstat(rtl::OUString(pB->m_ustrFilePath), b_stat) != 0)
439 0 : return sal_False;
440 :
441 0 : return (a_stat.st_ino == b_stat.st_ino);
442 : }
443 :
444 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|