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