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 : #include "osl/detail/file.h"
22 :
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>
29 :
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"
35 :
36 : namespace
37 : {
38 212656 : inline void set_file_type(const struct stat& file_stat, oslFileStatus* pStat)
39 : {
40 : /* links to directories state also to be a directory */
41 212656 : if (S_ISLNK(file_stat.st_mode))
42 25 : pStat->eType = osl_File_Type_Link;
43 212631 : else if (S_ISDIR(file_stat.st_mode))
44 88 : pStat->eType = osl_File_Type_Directory;
45 212543 : else if (S_ISREG(file_stat.st_mode))
46 212543 : pStat->eType = osl_File_Type_Regular;
47 0 : else if (S_ISFIFO(file_stat.st_mode))
48 0 : pStat->eType = osl_File_Type_Fifo;
49 0 : else if (S_ISSOCK(file_stat.st_mode))
50 0 : pStat->eType = osl_File_Type_Socket;
51 0 : else if (S_ISCHR(file_stat.st_mode) || S_ISBLK(file_stat.st_mode))
52 0 : pStat->eType = osl_File_Type_Special;
53 : else
54 0 : pStat->eType = osl_File_Type_Unknown;
55 :
56 212656 : pStat->uValidFields |= osl_FileStatus_Mask_Type;
57 212656 : }
58 :
59 212656 : inline void set_file_access_mask(const struct stat& file_stat, oslFileStatus* pStat)
60 : {
61 : // user permissions
62 212656 : if (S_IRUSR & file_stat.st_mode)
63 212656 : pStat->uAttributes |= osl_File_Attribute_OwnRead;
64 :
65 212656 : if (S_IWUSR & file_stat.st_mode)
66 212642 : pStat->uAttributes |= osl_File_Attribute_OwnWrite;
67 :
68 212656 : if (S_IXUSR & file_stat.st_mode)
69 42633 : pStat->uAttributes |= osl_File_Attribute_OwnExe;
70 :
71 : // group permissions
72 212656 : if (S_IRGRP & file_stat.st_mode)
73 212656 : pStat->uAttributes |= osl_File_Attribute_GrpRead;
74 :
75 212656 : if (S_IWGRP & file_stat.st_mode)
76 25 : pStat->uAttributes |= osl_File_Attribute_GrpWrite;
77 :
78 212656 : if (S_IXGRP & file_stat.st_mode)
79 42633 : pStat->uAttributes |= osl_File_Attribute_GrpExe;
80 :
81 : // others permissions
82 212656 : if (S_IROTH & file_stat.st_mode)
83 212656 : pStat->uAttributes |= osl_File_Attribute_OthRead;
84 :
85 212656 : if (S_IWOTH & file_stat.st_mode)
86 25 : pStat->uAttributes |= osl_File_Attribute_OthWrite;
87 :
88 212656 : if (S_IXOTH & file_stat.st_mode)
89 42633 : pStat->uAttributes |= osl_File_Attribute_OthExe;
90 :
91 212656 : pStat->uValidFields |= osl_FileStatus_Mask_Attributes;
92 212656 : }
93 :
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).
100 : */
101 0 : inline void set_file_access_rights(const rtl::OUString& file_path, oslFileStatus* pStat)
102 : {
103 0 : pStat->uValidFields |= osl_FileStatus_Mask_Attributes;
104 :
105 0 : if (access_u(file_path.pData, W_OK) < 0)
106 0 : pStat->uAttributes |= osl_File_Attribute_ReadOnly;
107 :
108 0 : if (access_u(file_path.pData, X_OK) == 0)
109 0 : pStat->uAttributes |= osl_File_Attribute_Executable;
110 0 : }
111 :
112 212656 : inline void set_file_hidden_status(const rtl::OUString& file_path, oslFileStatus* pStat)
113 : {
114 212656 : pStat->uAttributes = osl::systemPathIsHiddenFileOrDirectoryEntry(file_path) ? osl_File_Attribute_Hidden : 0;
115 212656 : pStat->uValidFields |= osl_FileStatus_Mask_Attributes;
116 212656 : }
117 :
118 : /* the set_file_access_rights must be called after set_file_hidden_status(...) and
119 : set_file_access_mask(...) because of the hack in set_file_access_rights(...) */
120 212656 : inline void set_file_attributes(
121 : const rtl::OUString& file_path, const struct stat& file_stat, const sal_uInt32 uFieldMask, oslFileStatus* pStat)
122 : {
123 212656 : set_file_hidden_status(file_path, pStat);
124 212656 : set_file_access_mask(file_stat, pStat);
125 :
126 : // we set the file access rights only on demand
127 : // because it's potentially expensive
128 212656 : if (uFieldMask & osl_FileStatus_Mask_Attributes)
129 0 : set_file_access_rights(file_path, pStat);
130 212656 : }
131 :
132 212656 : inline void set_file_access_time(const struct stat& file_stat, oslFileStatus* pStat)
133 : {
134 212656 : pStat->aAccessTime.Seconds = file_stat.st_atime;
135 212656 : pStat->aAccessTime.Nanosec = 0;
136 212656 : pStat->uValidFields |= osl_FileStatus_Mask_AccessTime;
137 212656 : }
138 :
139 212656 : inline void set_file_modify_time(const struct stat& file_stat, oslFileStatus* pStat)
140 : {
141 212656 : pStat->aModifyTime.Seconds = file_stat.st_mtime;
142 212656 : pStat->aModifyTime.Nanosec = 0;
143 212656 : pStat->uValidFields |= osl_FileStatus_Mask_ModifyTime;
144 212656 : }
145 :
146 212656 : inline void set_file_size(const struct stat& file_stat, oslFileStatus* pStat)
147 : {
148 212656 : if (S_ISREG(file_stat.st_mode))
149 : {
150 212543 : pStat->uFileSize = file_stat.st_size;
151 212543 : pStat->uValidFields |= osl_FileStatus_Mask_FileSize;
152 : }
153 212656 : }
154 :
155 : /* we only need to call stat or lstat if one of the
156 : following flags is set */
157 1062849 : inline bool is_stat_call_necessary(sal_uInt32 field_mask, oslFileType file_type = osl_File_Type_Unknown)
158 : {
159 : return (
160 2125719 : ((field_mask & osl_FileStatus_Mask_Type) && (file_type == osl_File_Type_Unknown)) ||
161 2125446 : (field_mask & osl_FileStatus_Mask_Attributes) ||
162 2125446 : (field_mask & osl_FileStatus_Mask_CreationTime) ||
163 2125446 : (field_mask & osl_FileStatus_Mask_AccessTime) ||
164 2125446 : (field_mask & osl_FileStatus_Mask_ModifyTime) ||
165 2125446 : (field_mask & osl_FileStatus_Mask_FileSize) ||
166 3188295 : (field_mask & osl_FileStatus_Mask_LinkTargetURL) ||
167 1062849 : (field_mask & osl_FileStatus_Mask_Validate));
168 : }
169 :
170 25 : inline oslFileError set_link_target_url(const rtl::OUString& file_path, oslFileStatus* pStat)
171 : {
172 25 : rtl::OUString link_target;
173 25 : if (!osl::realpath(file_path, link_target))
174 0 : return oslTranslateFileError(OSL_FET_ERROR, errno);
175 :
176 25 : oslFileError osl_error = osl_getFileURLFromSystemPath(link_target.pData, &pStat->ustrLinkTargetURL);
177 25 : if (osl_error != osl_File_E_None)
178 0 : return osl_error;
179 :
180 25 : pStat->uValidFields |= osl_FileStatus_Mask_LinkTargetURL;
181 25 : return osl_File_E_None;
182 : }
183 :
184 1062849 : inline oslFileError setup_osl_getFileStatus(
185 : DirectoryItem_Impl * pImpl, oslFileStatus* pStat, rtl::OUString& file_path)
186 : {
187 1062849 : if ((NULL == pImpl) || (NULL == pStat))
188 0 : return osl_File_E_INVAL;
189 :
190 1062849 : file_path = rtl::OUString(pImpl->m_ustrFilePath);
191 : OSL_ASSERT(!file_path.isEmpty());
192 1062849 : if (file_path.isEmpty())
193 0 : return osl_File_E_INVAL;
194 :
195 1062849 : pStat->uValidFields = 0;
196 1062849 : return osl_File_E_None;
197 : }
198 :
199 : }
200 :
201 1062849 : oslFileError SAL_CALL osl_getFileStatus(oslDirectoryItem Item, oslFileStatus* pStat, sal_uInt32 uFieldMask)
202 : {
203 1062849 : DirectoryItem_Impl * pImpl = static_cast< DirectoryItem_Impl* >(Item);
204 :
205 1062849 : rtl::OUString file_path;
206 1062849 : oslFileError osl_error = setup_osl_getFileStatus(pImpl, pStat, file_path);
207 1062849 : if (osl_File_E_None != osl_error)
208 0 : return osl_error;
209 :
210 : struct stat file_stat;
211 :
212 1062849 : bool bStatNeeded = is_stat_call_necessary(uFieldMask, pImpl->getFileType());
213 1062849 : if (bStatNeeded && (0 != osl::lstat(file_path, file_stat)))
214 0 : return oslTranslateFileError(OSL_FET_ERROR, errno);
215 :
216 1062849 : if (bStatNeeded)
217 : {
218 : // we set all these attributes because it's cheap
219 212656 : set_file_type(file_stat, pStat);
220 212656 : set_file_access_time(file_stat, pStat);
221 212656 : set_file_modify_time(file_stat, pStat);
222 212656 : set_file_size(file_stat, pStat);
223 212656 : set_file_attributes(file_path, file_stat, uFieldMask, pStat);
224 :
225 : // file exists semantic of osl_FileStatus_Mask_Validate
226 212656 : if ((uFieldMask & osl_FileStatus_Mask_LinkTargetURL) && S_ISLNK(file_stat.st_mode))
227 : {
228 25 : osl_error = set_link_target_url(file_path, pStat);
229 25 : if (osl_error != osl_File_E_None)
230 0 : return osl_error;
231 : }
232 : }
233 : #ifdef _DIRENT_HAVE_D_TYPE
234 850193 : else if (uFieldMask & osl_FileStatus_Mask_Type)
235 : {
236 21 : pStat->eType = pImpl->getFileType();
237 21 : pStat->uValidFields |= osl_FileStatus_Mask_Type;
238 : }
239 : #endif /* _DIRENT_HAVE_D_TYPE */
240 :
241 1062849 : if (uFieldMask & osl_FileStatus_Mask_FileURL)
242 : {
243 850316 : if ((osl_error = osl_getFileURLFromSystemPath(file_path.pData, &pStat->ustrFileURL)) != osl_File_E_None)
244 0 : return osl_error;
245 :
246 850316 : pStat->uValidFields |= osl_FileStatus_Mask_FileURL;
247 : }
248 :
249 1062849 : if (uFieldMask & osl_FileStatus_Mask_FileName)
250 : {
251 21 : osl_systemPathGetFileNameOrLastDirectoryPart(file_path.pData, &pStat->ustrFileName);
252 21 : pStat->uValidFields |= osl_FileStatus_Mask_FileName;
253 : }
254 1062849 : return osl_File_E_None;
255 : }
256 :
257 0 : static oslFileError osl_psz_setFileAttributes( const sal_Char* pszFilePath, sal_uInt64 uAttributes )
258 : {
259 0 : oslFileError osl_error = osl_File_E_None;
260 0 : mode_t nNewMode = 0;
261 :
262 : OSL_ENSURE(!(osl_File_Attribute_Hidden & uAttributes), "osl_File_Attribute_Hidden doesn't work under Unix");
263 :
264 0 : if (uAttributes & osl_File_Attribute_OwnRead)
265 0 : nNewMode |= S_IRUSR;
266 :
267 0 : if (uAttributes & osl_File_Attribute_OwnWrite)
268 0 : nNewMode|=S_IWUSR;
269 :
270 0 : if (uAttributes & osl_File_Attribute_OwnExe)
271 0 : nNewMode|=S_IXUSR;
272 :
273 0 : if (uAttributes & osl_File_Attribute_GrpRead)
274 0 : nNewMode|=S_IRGRP;
275 :
276 0 : if (uAttributes & osl_File_Attribute_GrpWrite)
277 0 : nNewMode|=S_IWGRP;
278 :
279 0 : if (uAttributes & osl_File_Attribute_GrpExe)
280 0 : nNewMode|=S_IXGRP;
281 :
282 0 : if (uAttributes & osl_File_Attribute_OthRead)
283 0 : nNewMode|=S_IROTH;
284 :
285 0 : if (uAttributes & osl_File_Attribute_OthWrite)
286 0 : nNewMode|=S_IWOTH;
287 :
288 0 : if (uAttributes & osl_File_Attribute_OthExe)
289 0 : nNewMode|=S_IXOTH;
290 :
291 0 : if (chmod(pszFilePath, nNewMode) < 0)
292 0 : osl_error = oslTranslateFileError(OSL_FET_ERROR, errno);
293 :
294 0 : return osl_error;
295 : }
296 :
297 0 : oslFileError SAL_CALL osl_setFileAttributes( rtl_uString* ustrFileURL, sal_uInt64 uAttributes )
298 : {
299 : char path[PATH_MAX];
300 : oslFileError eRet;
301 :
302 : OSL_ASSERT( ustrFileURL );
303 :
304 : /* convert file url to system path */
305 0 : eRet = FileURLToPath( path, PATH_MAX, ustrFileURL );
306 0 : if( eRet != osl_File_E_None )
307 0 : return eRet;
308 :
309 : #ifdef MACOSX
310 : if ( macxp_resolveAlias( path, PATH_MAX ) != 0 )
311 : return oslTranslateFileError( OSL_FET_ERROR, errno );
312 : #endif/* MACOSX */
313 :
314 0 : return osl_psz_setFileAttributes( path, uAttributes );
315 : }
316 :
317 0 : static oslFileError osl_psz_setFileTime (
318 : const sal_Char* pszFilePath,
319 : const TimeValue* pLastAccessTime,
320 : const TimeValue* pLastWriteTime )
321 : {
322 0 : int nRet=0;
323 : struct utimbuf aTimeBuffer;
324 : struct stat aFileStat;
325 : #ifdef DEBUG_OSL_FILE
326 : struct tm* pTM=0;
327 : #endif
328 :
329 0 : nRet = lstat_c(pszFilePath,&aFileStat);
330 :
331 0 : if ( nRet < 0 )
332 : {
333 0 : nRet=errno;
334 0 : return oslTranslateFileError(OSL_FET_ERROR, nRet);
335 : }
336 :
337 : #ifdef DEBUG_OSL_FILE
338 : fprintf(stderr,"File Times are (in localtime):\n");
339 : pTM=localtime(&aFileStat.st_ctime);
340 : fprintf(stderr,"CreationTime is '%s'\n",asctime(pTM));
341 : pTM=localtime(&aFileStat.st_atime);
342 : fprintf(stderr,"AccessTime is '%s'\n",asctime(pTM));
343 : pTM=localtime(&aFileStat.st_mtime);
344 : fprintf(stderr,"Modification is '%s'\n",asctime(pTM));
345 :
346 : fprintf(stderr,"File Times are (in UTC):\n");
347 : fprintf(stderr,"CreationTime is '%s'\n",ctime(&aFileStat.st_ctime));
348 : fprintf(stderr,"AccessTime is '%s'\n",ctime(&aTimeBuffer.actime));
349 : fprintf(stderr,"Modification is '%s'\n",ctime(&aTimeBuffer.modtime));
350 : #endif
351 :
352 0 : if ( pLastAccessTime != 0 )
353 : {
354 0 : aTimeBuffer.actime=pLastAccessTime->Seconds;
355 : }
356 : else
357 : {
358 0 : aTimeBuffer.actime=aFileStat.st_atime;
359 : }
360 :
361 0 : if ( pLastWriteTime != 0 )
362 : {
363 0 : aTimeBuffer.modtime=pLastWriteTime->Seconds;
364 : }
365 : else
366 : {
367 0 : aTimeBuffer.modtime=aFileStat.st_mtime;
368 : }
369 :
370 : /* mfe: Creation time not used here! */
371 :
372 : #ifdef DEBUG_OSL_FILE
373 : fprintf(stderr,"File Times are (in localtime):\n");
374 : pTM=localtime(&aFileStat.st_ctime);
375 : fprintf(stderr,"CreationTime now '%s'\n",asctime(pTM));
376 : pTM=localtime(&aTimeBuffer.actime);
377 : fprintf(stderr,"AccessTime now '%s'\n",asctime(pTM));
378 : pTM=localtime(&aTimeBuffer.modtime);
379 : fprintf(stderr,"Modification now '%s'\n",asctime(pTM));
380 :
381 : fprintf(stderr,"File Times are (in UTC):\n");
382 : fprintf(stderr,"CreationTime now '%s'\n",ctime(&aFileStat.st_ctime));
383 : fprintf(stderr,"AccessTime now '%s'\n",ctime(&aTimeBuffer.actime));
384 : fprintf(stderr,"Modification now '%s'\n",ctime(&aTimeBuffer.modtime));
385 : #endif
386 :
387 0 : nRet = utime_c(pszFilePath,&aTimeBuffer);
388 0 : if ( nRet < 0 )
389 : {
390 0 : nRet=errno;
391 0 : return oslTranslateFileError(OSL_FET_ERROR, nRet);
392 : }
393 :
394 0 : return osl_File_E_None;
395 : }
396 :
397 0 : oslFileError SAL_CALL osl_setFileTime (
398 : rtl_uString* ustrFileURL,
399 : SAL_UNUSED_PARAMETER const TimeValue* /* pCreationTime */,
400 : const TimeValue* pLastAccessTime,
401 : const TimeValue* pLastWriteTime )
402 : {
403 : char path[PATH_MAX];
404 : oslFileError eRet;
405 :
406 : OSL_ASSERT( ustrFileURL );
407 :
408 : /* convert file url to system path */
409 0 : eRet = FileURLToPath( path, PATH_MAX, ustrFileURL );
410 0 : if( eRet != osl_File_E_None )
411 0 : return eRet;
412 :
413 : #ifdef MACOSX
414 : if ( macxp_resolveAlias( path, PATH_MAX ) != 0 )
415 : return oslTranslateFileError( OSL_FET_ERROR, errno );
416 : #endif/* MACOSX */
417 :
418 0 : return osl_psz_setFileTime( path, pLastAccessTime, pLastWriteTime );
419 : }
420 :
421 : sal_Bool
422 0 : SAL_CALL osl_identicalDirectoryItem( oslDirectoryItem a, oslDirectoryItem b)
423 : {
424 0 : DirectoryItem_Impl *pA = (DirectoryItem_Impl *) a;
425 0 : DirectoryItem_Impl *pB = (DirectoryItem_Impl *) b;
426 0 : if (a == b)
427 0 : return sal_True;
428 : /* same name => same item, unless renaming / moving madness has occurred */
429 0 : if (rtl_ustr_compare_WithLength(
430 : pA->m_ustrFilePath->buffer, pA->m_ustrFilePath->length,
431 0 : pB->m_ustrFilePath->buffer, pB->m_ustrFilePath->length ) == 0)
432 0 : return sal_True;
433 :
434 : struct stat a_stat, b_stat;
435 :
436 0 : if (osl::lstat(rtl::OUString(pA->m_ustrFilePath), a_stat) != 0 ||
437 0 : osl::lstat(rtl::OUString(pB->m_ustrFilePath), b_stat) != 0)
438 0 : return sal_False;
439 :
440 0 : return (a_stat.st_ino == b_stat.st_ino);
441 : }
442 :
443 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|