xref: /aoo4110/main/sal/osl/unx/file_stat.cxx (revision b1cdbd2c)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sal.hxx"
26 
27 #include "osl/file.h"
28 
29 #include "system.h"
30 #include <sys/types.h>
31 #include <dirent.h>
32 #include <errno.h>
33 #include <limits.h>
34 #include <unistd.h>
35 
36 #include "file_impl.hxx"
37 #include "file_error_transl.h"
38 #include "file_path_helper.hxx"
39 #include "file_url.h"
40 #include "uunxapi.hxx"
41 
42 namespace /* private */
43 {
44 
set_file_type(const struct stat & file_stat,oslFileStatus * pStat)45 	inline void set_file_type(const struct stat& file_stat, oslFileStatus* pStat)
46 	{
47 		/* links to directories state also to be a directory */
48        if (S_ISLNK(file_stat.st_mode))
49            pStat->eType = osl_File_Type_Link;
50        else if (S_ISDIR(file_stat.st_mode))
51 		   pStat->eType = osl_File_Type_Directory;
52        else if (S_ISREG(file_stat.st_mode))
53            pStat->eType = osl_File_Type_Regular;
54        else if (S_ISFIFO(file_stat.st_mode))
55            pStat->eType = osl_File_Type_Fifo;
56        else if (S_ISSOCK(file_stat.st_mode))
57            pStat->eType = osl_File_Type_Socket;
58        else if (S_ISCHR(file_stat.st_mode) || S_ISBLK(file_stat.st_mode))
59            pStat->eType = osl_File_Type_Special;
60        else
61            pStat->eType = osl_File_Type_Unknown;
62 
63        pStat->uValidFields |= osl_FileStatus_Mask_Type;
64 	}
65 
set_file_access_mask(const struct stat & file_stat,oslFileStatus * pStat)66 	inline void set_file_access_mask(const struct stat& file_stat, oslFileStatus* pStat)
67 	{
68 		// user permissions
69         if (S_IRUSR & file_stat.st_mode)
70             pStat->uAttributes |= osl_File_Attribute_OwnRead;
71 
72         if (S_IWUSR & file_stat.st_mode)
73             pStat->uAttributes |= osl_File_Attribute_OwnWrite;
74 
75         if (S_IXUSR & file_stat.st_mode)
76             pStat->uAttributes |= osl_File_Attribute_OwnExe;
77 
78         // group permissions
79         if (S_IRGRP & file_stat.st_mode)
80             pStat->uAttributes |= osl_File_Attribute_GrpRead;
81 
82         if (S_IWGRP & file_stat.st_mode)
83             pStat->uAttributes |= osl_File_Attribute_GrpWrite;
84 
85         if (S_IXGRP & file_stat.st_mode)
86             pStat->uAttributes |= osl_File_Attribute_GrpExe;
87 
88         // others permissions
89         if (S_IROTH & file_stat.st_mode)
90             pStat->uAttributes |= osl_File_Attribute_OthRead;
91 
92         if (S_IWOTH & file_stat.st_mode)
93             pStat->uAttributes |= osl_File_Attribute_OthWrite;
94 
95 	    if (S_IXOTH & file_stat.st_mode)
96     	    pStat->uAttributes |= osl_File_Attribute_OthExe;
97 
98 		pStat->uValidFields |= osl_FileStatus_Mask_Attributes;
99 	}
100 
set_file_access_rights(const struct stat & file_stat,int S_IR,int S_IW,int S_IX,oslFileStatus * pStat)101 	inline void set_file_access_rights(const struct stat& file_stat, int S_IR, int S_IW, int S_IX, oslFileStatus* pStat)
102 	{
103 		/* we cannot really map osl_File_Attribute_ReadOnly to
104 		   the Unix access rights, it's a Windows only flag
105 		   that's why the following hack. We set osl_FileStatus_Mask_Attributes
106 		   but if there is no read access for a file we clear the flag
107 		   again to signal to the caller that there are no file attributes
108 		   to read because that's better than to give them incorrect one.
109 		*/
110 		pStat->uValidFields |= osl_FileStatus_Mask_Attributes;
111 
112         if ((0 == (S_IW & file_stat.st_mode)) && (S_IR & file_stat.st_mode))
113 			pStat->uAttributes |= osl_File_Attribute_ReadOnly;
114 
115         if (S_IX & file_stat.st_mode)
116             pStat->uAttributes |= osl_File_Attribute_Executable;
117 	}
118 
119 	/* a process may belong to up to NGROUPS_MAX groups, so when
120 	   checking group access rights, we have to check all belonging
121 	   groups */
is_in_process_grouplist(const gid_t file_group)122 	inline bool is_in_process_grouplist(const gid_t file_group)
123 	{
124 		// check primary process group
125 
126 		if (getgid() == file_group)
127 			return true;
128 
129 		// check supplementary process groups
130 
131 		gid_t grplist[NGROUPS_MAX];
132 		int   grp_number = getgroups(NGROUPS_MAX, grplist);
133 
134 		for (int i = 0; i < grp_number; i++)
135 		{
136 			if (grplist[i] == file_group)
137 				return true;
138 		}
139 		return false;
140 	}
141 
142 	/* Currently we are determining the file access right based
143 	   on the real user ID not the effective user ID!
144 	   We don't use access(...) because access follows links which
145 	   may cause performance problems see #97133.
146 	*/
set_file_access_rights(const struct stat & file_stat,oslFileStatus * pStat)147 	inline void set_file_access_rights(const struct stat& file_stat, oslFileStatus* pStat)
148 	{
149 		if (getuid() == file_stat.st_uid)
150 		{
151 			set_file_access_rights(file_stat, S_IRUSR, S_IWUSR, S_IXUSR, pStat);
152 		}
153 		else if (is_in_process_grouplist(file_stat.st_gid))
154 		{
155 			set_file_access_rights(file_stat, S_IRGRP, S_IWGRP, S_IXGRP, pStat);
156 		}
157 		else
158 		{
159 			set_file_access_rights(file_stat, S_IROTH, S_IWOTH, S_IXOTH, pStat);
160 		}
161 	}
162 
set_file_hidden_status(const rtl::OUString & file_path,oslFileStatus * pStat)163 	inline void set_file_hidden_status(const rtl::OUString& file_path, oslFileStatus* pStat)
164 	{
165 		pStat->uAttributes   = osl::systemPathIsHiddenFileOrDirectoryEntry(file_path) ? osl_File_Attribute_Hidden : 0;
166         pStat->uValidFields |= osl_FileStatus_Mask_Attributes;
167 	}
168 
169 	/* the set_file_access_rights must be called after set_file_hidden_status(...) and
170 	   set_file_access_mask(...) because of the hack in set_file_access_rights(...) */
set_file_attributes(const rtl::OUString & file_path,const struct stat & file_stat,const sal_uInt32 uFieldMask,oslFileStatus * pStat)171 	inline void set_file_attributes(
172 		const rtl::OUString& file_path, const struct stat& file_stat, const sal_uInt32 uFieldMask, oslFileStatus* pStat)
173 	{
174 		set_file_hidden_status(file_path, pStat);
175 		set_file_access_mask(file_stat, pStat);
176 
177 		// we set the file access rights only on demand
178 		// because it's potentially expensive
179 		if (uFieldMask & osl_FileStatus_Mask_Attributes)
180 		   	set_file_access_rights(file_stat, pStat);
181 	}
182 
set_file_access_time(const struct stat & file_stat,oslFileStatus * pStat)183 	inline void set_file_access_time(const struct stat& file_stat, oslFileStatus* pStat)
184 	{
185 		pStat->aAccessTime.Seconds  = file_stat.st_atime;
186     	pStat->aAccessTime.Nanosec  = 0;
187        	pStat->uValidFields        |= osl_FileStatus_Mask_AccessTime;
188 	}
189 
set_file_modify_time(const struct stat & file_stat,oslFileStatus * pStat)190 	inline void set_file_modify_time(const struct stat& file_stat, oslFileStatus* pStat)
191 	{
192 	    pStat->aModifyTime.Seconds  = file_stat.st_mtime;
193     	pStat->aModifyTime.Nanosec  = 0;
194     	pStat->uValidFields        |= osl_FileStatus_Mask_ModifyTime;
195 	}
196 
set_file_size(const struct stat & file_stat,oslFileStatus * pStat)197 	inline void set_file_size(const struct stat& file_stat, oslFileStatus* pStat)
198 	{
199 		if (S_ISREG(file_stat.st_mode))
200        	{
201         	pStat->uFileSize     = file_stat.st_size;
202            	pStat->uValidFields |= osl_FileStatus_Mask_FileSize;
203        	}
204 	}
205 
206 	/* we only need to call stat or lstat if one of the
207        following flags is set */
is_stat_call_necessary(sal_uInt32 field_mask,oslFileType file_type=osl_File_Type_Unknown)208 	inline bool is_stat_call_necessary(sal_uInt32 field_mask, oslFileType file_type = osl_File_Type_Unknown)
209 	{
210 		return (
211 				((field_mask & osl_FileStatus_Mask_Type) && (file_type == osl_File_Type_Unknown)) ||
212 				(field_mask & osl_FileStatus_Mask_Attributes) ||
213 				(field_mask & osl_FileStatus_Mask_CreationTime) ||
214 				(field_mask & osl_FileStatus_Mask_AccessTime) ||
215 				(field_mask & osl_FileStatus_Mask_ModifyTime) ||
216 				(field_mask & osl_FileStatus_Mask_FileSize) ||
217 				(field_mask & osl_FileStatus_Mask_LinkTargetURL) ||
218 				(field_mask & osl_FileStatus_Mask_Validate));
219 	}
220 
set_link_target_url(const rtl::OUString & file_path,oslFileStatus * pStat)221 	inline oslFileError set_link_target_url(const rtl::OUString& file_path, oslFileStatus* pStat)
222 	{
223 		rtl::OUString link_target;
224 		if (!osl::realpath(file_path, link_target))
225 			return oslTranslateFileError(OSL_FET_ERROR, errno);
226 
227 		oslFileError osl_error = osl_getFileURLFromSystemPath(link_target.pData, &pStat->ustrLinkTargetURL);
228 		if (osl_error != osl_File_E_None)
229 			return osl_error;
230 
231 		pStat->uValidFields |= osl_FileStatus_Mask_LinkTargetURL;
232 		return osl_File_E_None;
233 	}
234 
setup_osl_getFileStatus(DirectoryItem_Impl * pImpl,oslFileStatus * pStat,rtl::OUString & file_path)235 	inline oslFileError setup_osl_getFileStatus(
236 		DirectoryItem_Impl * pImpl, oslFileStatus* pStat, rtl::OUString& file_path)
237 	{
238     	if ((NULL == pImpl) || (NULL == pStat))
239         	return osl_File_E_INVAL;
240 
241 		file_path = rtl::OUString(pImpl->m_ustrFilePath);
242 		OSL_ASSERT(file_path.getLength() > 0);
243 		if (file_path.getLength() <= 0)
244 			return osl_File_E_INVAL;
245 
246     	pStat->uValidFields = 0;
247 		return osl_File_E_None;
248 	}
249 
250 } // end namespace private
251 
252 
253 /****************************************************************************
254  *	osl_getFileStatus
255  ****************************************************************************/
256 
osl_getFileStatus(oslDirectoryItem Item,oslFileStatus * pStat,sal_uInt32 uFieldMask)257 oslFileError SAL_CALL osl_getFileStatus(oslDirectoryItem Item, oslFileStatus* pStat, sal_uInt32 uFieldMask)
258 {
259 	DirectoryItem_Impl * pImpl = static_cast< DirectoryItem_Impl* >(Item);
260 
261 	rtl::OUString file_path;
262 	oslFileError  osl_error = setup_osl_getFileStatus(pImpl, pStat, file_path);
263 	if (osl_File_E_None != osl_error)
264 		return osl_error;
265 
266 #if defined(__GNUC__) && (__GNUC__ < 3)
267 	struct ::stat file_stat;
268 #else
269 	struct stat file_stat;
270 #endif
271 
272 	bool bStatNeeded = is_stat_call_necessary(uFieldMask, pImpl->getFileType());
273 	if (bStatNeeded && (0 != osl::lstat(file_path, file_stat)))
274     	return oslTranslateFileError(OSL_FET_ERROR, errno);
275 
276 	if (bStatNeeded)
277 	{
278 		// we set all these attributes because it's cheap
279 		set_file_type(file_stat, pStat);
280 		set_file_access_time(file_stat, pStat);
281 		set_file_modify_time(file_stat, pStat);
282 		set_file_size(file_stat, pStat);
283 		set_file_attributes(file_path, file_stat, uFieldMask, pStat);
284 
285 	    // file exists semantic of osl_FileStatus_Mask_Validate
286     	if ((uFieldMask & osl_FileStatus_Mask_LinkTargetURL) && S_ISLNK(file_stat.st_mode))
287 		{
288 			osl_error = set_link_target_url(file_path, pStat);
289     		if (osl_error != osl_File_E_None)
290 				return osl_error;
291 		}
292     }
293 #ifdef _DIRENT_HAVE_D_TYPE
294     else if (uFieldMask & osl_FileStatus_Mask_Type)
295     {
296 		pStat->eType = pImpl->getFileType();
297 		pStat->uValidFields |= osl_FileStatus_Mask_Type;
298 	}
299 #endif /* _DIRENT_HAVE_D_TYPE */
300 
301     if (uFieldMask & osl_FileStatus_Mask_FileURL)
302     {
303     	if ((osl_error = osl_getFileURLFromSystemPath(file_path.pData, &pStat->ustrFileURL)) != osl_File_E_None)
304 			return osl_error;
305 
306         pStat->uValidFields |= osl_FileStatus_Mask_FileURL;
307     }
308 
309     if (uFieldMask & osl_FileStatus_Mask_FileName)
310     {
311 		osl_systemPathGetFileNameOrLastDirectoryPart(file_path.pData, &pStat->ustrFileName);
312 		pStat->uValidFields |= osl_FileStatus_Mask_FileName;
313    	}
314     return osl_File_E_None;
315 }
316 
317 /****************************************************************************/
318 /*	osl_setFileAttributes */
319 /****************************************************************************/
320 
osl_psz_setFileAttributes(const sal_Char * pszFilePath,sal_uInt64 uAttributes)321 static oslFileError osl_psz_setFileAttributes( const sal_Char* pszFilePath, sal_uInt64 uAttributes )
322 {
323 	oslFileError osl_error = osl_File_E_None;
324     mode_t 		 nNewMode  = 0;
325 
326  	OSL_ENSURE(!(osl_File_Attribute_Hidden & uAttributes), "osl_File_Attribute_Hidden doesn't work under Unix");
327 
328     if (uAttributes & osl_File_Attribute_OwnRead)
329         nNewMode |= S_IRUSR;
330 
331     if (uAttributes & osl_File_Attribute_OwnWrite)
332         nNewMode|=S_IWUSR;
333 
334     if  (uAttributes & osl_File_Attribute_OwnExe)
335         nNewMode|=S_IXUSR;
336 
337     if (uAttributes & osl_File_Attribute_GrpRead)
338         nNewMode|=S_IRGRP;
339 
340     if (uAttributes & osl_File_Attribute_GrpWrite)
341         nNewMode|=S_IWGRP;
342 
343     if (uAttributes & osl_File_Attribute_GrpExe)
344         nNewMode|=S_IXGRP;
345 
346     if (uAttributes & osl_File_Attribute_OthRead)
347         nNewMode|=S_IROTH;
348 
349     if (uAttributes & osl_File_Attribute_OthWrite)
350         nNewMode|=S_IWOTH;
351 
352     if (uAttributes & osl_File_Attribute_OthExe)
353         nNewMode|=S_IXOTH;
354 
355     if (chmod(pszFilePath, nNewMode) < 0)
356         osl_error = oslTranslateFileError(OSL_FET_ERROR, errno);
357 
358     return osl_error;
359 }
360 
osl_setFileAttributes(rtl_uString * ustrFileURL,sal_uInt64 uAttributes)361 oslFileError SAL_CALL osl_setFileAttributes( rtl_uString* ustrFileURL, sal_uInt64 uAttributes )
362 {
363     char path[PATH_MAX];
364     oslFileError eRet;
365 
366     OSL_ASSERT( ustrFileURL );
367 
368     /* convert file url to system path */
369     eRet = FileURLToPath( path, PATH_MAX, ustrFileURL );
370     if( eRet != osl_File_E_None )
371         return eRet;
372 
373 #ifdef MACOSX
374     if ( macxp_resolveAlias( path, PATH_MAX ) != 0 )
375       return oslTranslateFileError( OSL_FET_ERROR, errno );
376 #endif/* MACOSX */
377 
378     return osl_psz_setFileAttributes( path, uAttributes );
379 }
380 
381 /****************************************************************************/
382 /*	osl_setFileTime */
383 /****************************************************************************/
384 
osl_psz_setFileTime(const sal_Char * pszFilePath,const TimeValue *,const TimeValue * pLastAccessTime,const TimeValue * pLastWriteTime)385 static oslFileError osl_psz_setFileTime (
386     const sal_Char* pszFilePath,
387     const TimeValue* /*pCreationTime*/,
388     const TimeValue* pLastAccessTime,
389     const TimeValue* pLastWriteTime )
390 {
391     int nRet=0;
392     struct utimbuf aTimeBuffer;
393     struct stat aFileStat;
394 #ifdef DEBUG_OSL_FILE
395     struct tm* pTM=0;
396 #endif
397 
398     nRet = lstat(pszFilePath,&aFileStat);
399 
400     if ( nRet < 0 )
401     {
402         nRet=errno;
403         return oslTranslateFileError(OSL_FET_ERROR, nRet);
404     }
405 
406 #ifdef DEBUG_OSL_FILE
407     fprintf(stderr,"File Times are (in localtime):\n");
408     pTM=localtime(&aFileStat.st_ctime);
409     fprintf(stderr,"CreationTime is '%s'\n",asctime(pTM));
410     pTM=localtime(&aFileStat.st_atime);
411     fprintf(stderr,"AccessTime   is '%s'\n",asctime(pTM));
412     pTM=localtime(&aFileStat.st_mtime);
413     fprintf(stderr,"Modification is '%s'\n",asctime(pTM));
414 
415     fprintf(stderr,"File Times are (in UTC):\n");
416     fprintf(stderr,"CreationTime is '%s'\n",ctime(&aFileStat.st_ctime));
417     fprintf(stderr,"AccessTime   is '%s'\n",ctime(&aTimeBuffer.actime));
418     fprintf(stderr,"Modification is '%s'\n",ctime(&aTimeBuffer.modtime));
419 #endif
420 
421     if ( pLastAccessTime != 0 )
422     {
423         aTimeBuffer.actime=pLastAccessTime->Seconds;
424     }
425     else
426     {
427         aTimeBuffer.actime=aFileStat.st_atime;
428     }
429 
430     if ( pLastWriteTime != 0 )
431     {
432         aTimeBuffer.modtime=pLastWriteTime->Seconds;
433     }
434     else
435     {
436         aTimeBuffer.modtime=aFileStat.st_mtime;
437     }
438 
439     /* mfe: Creation time not used here! */
440 
441 #ifdef DEBUG_OSL_FILE
442     fprintf(stderr,"File Times are (in localtime):\n");
443     pTM=localtime(&aFileStat.st_ctime);
444     fprintf(stderr,"CreationTime now '%s'\n",asctime(pTM));
445     pTM=localtime(&aTimeBuffer.actime);
446     fprintf(stderr,"AccessTime   now '%s'\n",asctime(pTM));
447     pTM=localtime(&aTimeBuffer.modtime);
448     fprintf(stderr,"Modification now '%s'\n",asctime(pTM));
449 
450     fprintf(stderr,"File Times are (in UTC):\n");
451     fprintf(stderr,"CreationTime now '%s'\n",ctime(&aFileStat.st_ctime));
452     fprintf(stderr,"AccessTime   now '%s'\n",ctime(&aTimeBuffer.actime));
453     fprintf(stderr,"Modification now '%s'\n",ctime(&aTimeBuffer.modtime));
454 #endif
455 
456     nRet=utime(pszFilePath,&aTimeBuffer);
457     if ( nRet < 0 )
458     {
459         nRet=errno;
460         return oslTranslateFileError(OSL_FET_ERROR, nRet);
461     }
462 
463     return osl_File_E_None;
464 }
465 
osl_setFileTime(rtl_uString * ustrFileURL,const TimeValue * pCreationTime,const TimeValue * pLastAccessTime,const TimeValue * pLastWriteTime)466 oslFileError SAL_CALL osl_setFileTime (
467     rtl_uString* ustrFileURL,
468     const TimeValue* pCreationTime,
469     const TimeValue* pLastAccessTime,
470     const TimeValue* pLastWriteTime )
471 {
472     char path[PATH_MAX];
473     oslFileError eRet;
474 
475     OSL_ASSERT( ustrFileURL );
476 
477     /* convert file url to system path */
478     eRet = FileURLToPath( path, PATH_MAX, ustrFileURL );
479     if( eRet != osl_File_E_None )
480         return eRet;
481 
482 #ifdef MACOSX
483     if ( macxp_resolveAlias( path, PATH_MAX ) != 0 )
484       return oslTranslateFileError( OSL_FET_ERROR, errno );
485 #endif/* MACOSX */
486 
487     return osl_psz_setFileTime( path, pCreationTime, pLastAccessTime, pLastWriteTime );
488 }
489