xref: /aoo41x/main/tools/source/fsys/unx.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_tools.hxx"
30 
31 #include <stdio.h>
32 #include <ctype.h>
33 #include <stdlib.h>
34 #include <unistd.h>
35 #include <utime.h>
36 #if defined HPUX || defined LINUX
37 #include <mntent.h>
38 #define mnttab mntent
39 #elif defined SCO
40 #include <mnttab.h>
41 #elif defined AIX
42 #include <sys/mntctl.h>
43 #include <sys/vmount.h>
44 extern "C" int mntctl( int cmd, size_t size, char* buf );
45 #elif defined(NETBSD)
46 #include <sys/mount.h>
47 #elif defined(FREEBSD) || defined(MACOSX)
48 #elif defined DECUNIX
49 struct mnttab
50 {
51   char *mnt_dir;
52   char *mnt_fsname;
53 };
54 #else
55 #include <sys/mnttab.h>
56 #endif
57 
58 #ifndef MAXPATHLEN
59 #define MAXPATHLEN 1024
60 #endif
61 
62 #include <tools/debug.hxx>
63 #include <tools/list.hxx>
64 #include <tools/fsys.hxx>
65 #include "comdep.hxx"
66 #include <rtl/instance.hxx>
67 
68 DECLARE_LIST( DirEntryList, DirEntry* )
69 DECLARE_LIST( FSysSortList, FSysSort* )
70 DECLARE_LIST( FileStatList, FileStat* )
71 
72 #if defined SOLARIS || defined SINIX
73 #define MOUNTSPECIAL mnt_special
74 #define MOUNTPOINT 	 mnt_mountp
75 #define MOUNTOPTS    mnt_mntopts
76 #define MOUNTFS      mnt_fstype
77 #elif defined SCO
78 #define MNTTAB 		 "/etc/mnttab"
79 #define MOUNTSPECIAL mt_dev
80 #define MOUNTPOINT   mt_filsys
81 #else
82 #define MOUNTSPECIAL mnt_fsname
83 #define MOUNTPOINT   mnt_dir
84 #define MOUNTFS      mnt_type
85 #endif
86 
87 struct mymnttab
88 {
89 	dev_t mountdevice;
90 	ByteString mountspecial;
91 	ByteString mountpoint;
92 	ByteString mymnttab_filesystem;
93 	mymnttab() { mountdevice = (dev_t) -1; }
94 };
95 
96 
97 #if defined(NETBSD) || defined(FREEBSD) || defined(MACOSX)
98 sal_Bool GetMountEntry(dev_t /* dev */, struct mymnttab * /* mytab */ )
99 {
100 	DBG_WARNING( "Sorry, not implemented: GetMountEntry" );
101 	return sal_False;
102 }
103 
104 #elif defined AIX
105 sal_Bool GetMountEntry(dev_t dev, struct mymnttab *mytab)
106 {
107 	int bufsize;
108 	if (mntctl (MCTL_QUERY, sizeof bufsize, (char*) &bufsize))
109 		return sal_False;
110 
111 	char* buffer = (char *)malloc( bufsize * sizeof(char) );
112 	if (mntctl (MCTL_QUERY, bufsize, buffer) != -1)
113 		for ( char* vmt = buffer;
114 					vmt < buffer + bufsize;
115 					vmt += ((struct vmount*)vmt)->vmt_length)
116 		{
117 			struct stat buf;
118 			char *mountp = vmt2dataptr((struct vmount*)vmt, VMT_STUB);
119 			if ((stat (mountp, &buf) != -1) && (buf.st_dev == dev))
120 			{
121 				mytab->mountpoint = mountp;
122 				mytab->mountspecial
123 						= vmt2dataptr((struct vmount*)vmt, VMT_HOSTNAME);
124 				if (mytab->mountspecial.Len())
125 					mytab->mountspecial += ':';
126 				mytab->mountspecial
127 						+= vmt2dataptr((struct vmount*)vmt, VMT_OBJECT);
128 				mytab->mountdevice = dev;
129 				free( buffer );
130 				return sal_True;
131 			}
132 		}
133 	free( buffer );
134 	return sal_False;
135 }
136 
137 #else
138 
139 
140 static sal_Bool GetMountEntry(dev_t dev, struct mymnttab *mytab)
141 {
142 #if defined SOLARIS || defined SINIX
143 	FILE *fp = fopen (MNTTAB, "r");
144 	if (! fp)
145 		return sal_False;
146 	struct mnttab mnt[1];
147 	while (getmntent (fp, mnt) != -1)
148 #elif defined SCO
149 	FILE *fp = fopen (MNTTAB, "r");
150 	if (! fp)
151 		return sal_False;
152 	struct mnttab mnt[1];
153 	while (fread (&mnt, sizeof mnt, 1, fp) > 0)
154 #elif defined DECUNIX || defined AIX
155 	FILE *fp = NULL;
156 	if (! fp)
157 		return sal_False;
158 	struct mnttab mnt[1];
159 	while ( 0 )
160 #else
161 	FILE *fp = setmntent (MOUNTED, "r");
162 	if (! fp)
163 		return sal_False;
164 	struct mnttab *mnt;
165 	while ((mnt = getmntent (fp)) != NULL)
166 #endif
167 	{
168 #ifdef SOLARIS
169 		char *devopt = NULL;
170 		if ( mnt->MOUNTOPTS != NULL )
171 			devopt = strstr (mnt->MOUNTOPTS, "dev=");
172 		if (devopt)
173 		{
174 			if (dev != (dev_t) strtoul (devopt+4, NULL, 16))
175 				continue;
176 		}
177 		else
178 #endif
179 		{
180 			struct stat buf;
181 			if ((stat (mnt->MOUNTPOINT, &buf) == -1) || (buf.st_dev != dev))
182 				continue;
183 		}
184 #		ifdef LINUX
185 		/* #61624# File mit setmntent oeffnen und mit fclose schliessen stoesst
186 		   bei der glibc-2.1 auf wenig Gegenliebe */
187 		endmntent( fp );
188 #		else
189 		fclose (fp);
190 #		endif
191 		mytab->mountspecial = mnt->MOUNTSPECIAL;
192 		mytab->mountpoint 	= mnt->MOUNTPOINT;
193 		mytab->mountdevice 	= dev;
194 #ifndef SCO
195 		mytab->mymnttab_filesystem = mnt->MOUNTFS;
196 #else
197 		mytab->mymnttab_filesystem = "ext2";		//default ist case sensitiv unter unix
198 #endif
199 		return sal_True;
200 	}
201 #	ifdef LINUX
202 	/* #61624# dito */
203 	endmntent( fp );
204 #	else
205 	fclose (fp);
206 #	endif
207 	return sal_False;
208 }
209 
210 #endif
211 
212 /************************************************************************
213 |*
214 |*    DirEntry::IsCaseSensitive()
215 |*
216 |*    Beschreibung
217 |*    Ersterstellung    TPF 25.02.1999
218 |*    Letzte Aenderung  TPF 25.02.1999
219 |*
220 *************************************************************************/
221 
222 sal_Bool DirEntry::IsCaseSensitive( FSysPathStyle eFormatter ) const
223 {
224 
225 	if (eFormatter==FSYS_STYLE_HOST)
226 	{
227 #ifdef NETBSD
228 		return sal_True;
229 #else
230 		struct stat buf;
231 		DirEntry aPath(*this);
232 		aPath.ToAbs();
233 
234 		while (stat (ByteString(aPath.GetFull(), osl_getThreadTextEncoding()).GetBuffer(), &buf))
235 		{
236 			if (aPath.Level() == 1)
237 			{
238 				return sal_True;	// ich bin unter UNIX, also ist der default im Zweifelsfall case sensitiv
239 			}
240 			aPath = aPath [1];
241 		}
242 
243 		struct mymnttab fsmnt;
244 		GetMountEntry(buf.st_dev, &fsmnt);
245 		if ((fsmnt.mymnttab_filesystem.CompareTo("msdos")==COMPARE_EQUAL) ||
246 		    (fsmnt.mymnttab_filesystem.CompareTo("umsdos")==COMPARE_EQUAL) ||
247 		    (fsmnt.mymnttab_filesystem.CompareTo("vfat")==COMPARE_EQUAL) ||
248 		    (fsmnt.mymnttab_filesystem.CompareTo("hpfs")==COMPARE_EQUAL) ||
249 		    (fsmnt.mymnttab_filesystem.CompareTo("smb")	==COMPARE_EQUAL) ||
250 		    (fsmnt.mymnttab_filesystem.CompareTo("ncpfs")==COMPARE_EQUAL))
251 		{
252 			return sal_False;
253 		}
254 		else
255 		{
256 			return sal_True;
257 		}
258 #endif
259 	}
260 	else
261 	{
262 		sal_Bool isCaseSensitive = sal_True;	// ich bin unter UNIX, also ist der default im Zweifelsfall case sensitiv
263 		switch ( eFormatter )
264 		{
265 			case FSYS_STYLE_MAC:
266 			case FSYS_STYLE_FAT:
267 			case FSYS_STYLE_VFAT:
268 			case FSYS_STYLE_NTFS:
269 			case FSYS_STYLE_NWFS:
270 			case FSYS_STYLE_HPFS:
271 				{
272 					isCaseSensitive = sal_False;
273 					break;
274 				}
275 			case FSYS_STYLE_SYSV:
276 			case FSYS_STYLE_BSD:
277 			case FSYS_STYLE_DETECT:
278 				{
279 					isCaseSensitive = sal_True;
280 					break;
281 				}
282 			default:
283 				{
284 					isCaseSensitive = sal_True;	// ich bin unter UNIX, also ist der default im Zweifelsfall case sensitiv
285 					break;
286 				}
287 		}
288 		return isCaseSensitive;
289 	}
290 }
291 
292 /************************************************************************
293 |*
294 |*    DirEntry::ToAbs()
295 |*
296 |*    Beschreibung      FSYS.SDW
297 |*    Ersterstellung    MI 26.04.91
298 |*    Letzte Aenderung  MA 02.12.91 13:30
299 |*
300 *************************************************************************/
301 
302 sal_Bool DirEntry::ToAbs()
303 {
304 	if ( FSYS_FLAG_VOLUME == eFlag )
305 	{
306 		eFlag = FSYS_FLAG_ABSROOT;
307 		return sal_True;
308 	}
309 
310 	if ( IsAbs() )
311 	  return sal_True;
312 
313 	char sBuf[MAXPATHLEN + 1];
314 	*this = DirEntry( String( getcwd( sBuf, MAXPATHLEN ), osl_getThreadTextEncoding() ) ) + *this;
315 	return IsAbs();
316 }
317 
318 /*************************************************************************
319 |*
320 |*    DirEntry::GetVolume()
321 |*
322 |*    Beschreibung      FSYS.SDW
323 |*    Ersterstellung    MI 04.03.92
324 |*    Letzte Aenderung
325 |*
326 *************************************************************************/
327 
328 namespace { struct mymnt : public rtl::Static< mymnttab, mymnt > {}; }
329 
330 String DirEntry::GetVolume() const
331 {
332   DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
333 
334 	DirEntry aPath( *this );
335 	aPath.ToAbs();
336 
337 	struct stat buf;
338 	while (stat (ByteString(aPath.GetFull(), osl_getThreadTextEncoding()).GetBuffer(), &buf))
339 	{
340 		if (aPath.Level() <= 1)
341 			return String();
342 		aPath = aPath [1];
343 	}
344 	mymnttab &rMnt = mymnt::get();
345 	return ((buf.st_dev == rMnt.mountdevice ||
346 				GetMountEntry(buf.st_dev, &rMnt)) ?
347 				    String(rMnt.mountspecial, osl_getThreadTextEncoding()) :
348 					String());
349 }
350 
351 DirEntry DirEntry::GetDevice() const
352 {
353   DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
354 
355 	DirEntry aPath( *this );
356 	aPath.ToAbs();
357 
358 	struct stat buf;
359 	while (stat (ByteString(aPath.GetFull(), osl_getThreadTextEncoding()).GetBuffer(), &buf))
360 	{
361 		if (aPath.Level() <= 1)
362 			return String();
363 		aPath = aPath [1];
364 	}
365 	mymnttab &rMnt = mymnt::get();
366 	return ((buf.st_dev == rMnt.mountdevice ||
367 				GetMountEntry(buf.st_dev, &rMnt)) ?
368 				    String( rMnt.mountpoint, osl_getThreadTextEncoding()) :
369 					String());
370 }
371 
372 /*************************************************************************
373 |*
374 |*    DirEntry::SetCWD()
375 |*
376 |*    Beschreibung      FSYS.SDW
377 |*    Ersterstellung    MI 26.04.91
378 |*    Letzte Aenderung  DV 04.11.92
379 |*
380 *************************************************************************/
381 
382 sal_Bool DirEntry::SetCWD( sal_Bool bSloppy ) const
383 {
384     DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
385 
386 
387 	ByteString aPath( GetFull(), osl_getThreadTextEncoding());
388 	if ( !chdir( aPath.GetBuffer() ) )
389 	{
390 		return sal_True;
391 	}
392 	else
393 	{
394 		if ( bSloppy && !chdir(aPath.GetBuffer()) )
395 		{
396 			return sal_True;
397 		}
398 		else
399 		{
400 			return sal_False;
401 		}
402 	}
403 }
404 
405 //-------------------------------------------------------------------------
406 
407 sal_uInt16 DirReader_Impl::Init()
408 {
409 	return 0;
410 }
411 
412 //-------------------------------------------------------------------------
413 
414 sal_uInt16 DirReader_Impl::Read()
415 {
416 	if (!pDosDir)
417 	{
418 		pDosDir = opendir( (char*) ByteString(aPath, osl_getThreadTextEncoding()).GetBuffer() );
419 	}
420 
421 	if (!pDosDir)
422 	{
423 		bReady = sal_True;
424 		return 0;
425 	}
426 
427     // Directories und Files auflisten?
428 	if ( ( pDir->eAttrMask & FSYS_KIND_DIR || pDir->eAttrMask & FSYS_KIND_FILE ) &&
429 		 ( ( pDosEntry = readdir( pDosDir ) ) != NULL ) )
430 	{
431 	String aD_Name(pDosEntry->d_name, osl_getThreadTextEncoding());
432         if ( pDir->aNameMask.Matches( aD_Name  ) )
433         {
434 			DirEntryFlag eFlag =
435 					0 == strcmp( pDosEntry->d_name, "." ) ? FSYS_FLAG_CURRENT
436 				:	0 == strcmp( pDosEntry->d_name, ".." ) ? FSYS_FLAG_PARENT
437 				:	FSYS_FLAG_NORMAL;
438             DirEntry *pTemp = new DirEntry( ByteString(pDosEntry->d_name), eFlag, FSYS_STYLE_UNX );
439             if ( pParent )
440                 pTemp->ImpChangeParent( new DirEntry( *pParent ), sal_False);
441             FileStat aStat( *pTemp );
442             if ( ( ( ( pDir->eAttrMask & FSYS_KIND_DIR ) &&
443 					 ( aStat.IsKind( FSYS_KIND_DIR ) ) ) ||
444 				   ( ( pDir->eAttrMask & FSYS_KIND_FILE ) &&
445 					 !( aStat.IsKind( FSYS_KIND_DIR ) ) ) ) &&
446 				 !( pDir->eAttrMask & FSYS_KIND_VISIBLE &&
447 					pDosEntry->d_name[0] == '.' ) )
448             {
449                 if ( pDir->pStatLst ) //Status fuer Sort gewuenscht?
450                     pDir->ImpSortedInsert( pTemp, new FileStat( aStat ) );
451                 else
452                     pDir->ImpSortedInsert( pTemp, NULL );;
453 				return 1;
454             }
455             else
456                 delete pTemp;
457         }
458 	}
459 	else
460 		bReady = sal_True;
461 	return 0;
462 }
463 
464 /*************************************************************************
465 |*
466 |*    FileStat::FileStat()
467 |*
468 |*    Beschreibung      FSYS.SDW
469 |*    Ersterstellung    MA 05.11.91
470 |*    Letzte Aenderung  MA 07.11.91
471 |*
472 *************************************************************************/
473 
474 FileStat::FileStat( const void *, const void * ):
475 	aDateCreated(0),
476 	aTimeCreated(0),
477 	aDateModified(0),
478 	aTimeModified(0),
479 	aDateAccessed(0),
480 	aTimeAccessed(0)
481 {
482 }
483 
484 /*************************************************************************
485 |*
486 |*    FileStat::Update()
487 |*
488 |*    Beschreibung      FSYS.SDW
489 |*    Ersterstellung    MI 11.06.91
490 |*    Letzte Aenderung  MA 07.11.91
491 |*
492 *************************************************************************/
493 sal_Bool FileStat::Update( const DirEntry& rDirEntry, sal_Bool )
494 {
495 
496 	nSize = 0;
497 	nKindFlags = 0;
498 	aCreator.Erase();
499 	aType.Erase();
500 	aDateCreated = Date(0);
501 	aTimeCreated = Time(0);
502 	aDateModified = Date(0);
503 	aTimeModified = Time(0);
504 	aDateAccessed = Date(0);
505 	aTimeAccessed = Time(0);
506 
507 	if ( !rDirEntry.IsValid() )
508 	{
509 		nError = FSYS_ERR_NOTEXISTS;
510 		return sal_False;
511 	}
512 
513 	// Sonderbehandlung falls es sich um eine Root handelt
514 	if ( rDirEntry.eFlag == FSYS_FLAG_ABSROOT )
515 	{
516 		nKindFlags = FSYS_KIND_DIR;
517 		nError = FSYS_ERR_OK;
518 		return sal_True;
519 	}
520 
521 	struct stat aStat;
522 	ByteString aPath( rDirEntry.GetFull(), osl_getThreadTextEncoding() );
523 	if ( stat( (char*) aPath.GetBuffer(), &aStat ) )
524 	{
525 		// pl: #67851#
526 		// do this here, because an existing filename containing "wildcards"
527 		// should be handled as a file, not a wildcard
528 		// note that this is not a solution, since filenames containing special characters
529 		// are handled badly across the whole Office
530 
531 		// Sonderbehandlung falls es sich um eine Wildcard handelt
532 		ByteString aTempName( rDirEntry.GetName(), osl_getThreadTextEncoding() );
533 		if ( strchr( (char*) aTempName.GetBuffer(), '?' ) ||
534 			 strchr( (char*) aTempName.GetBuffer(), '*' ) ||
535 			 strchr( (char*) aTempName.GetBuffer(), ';' ) )
536 		{
537 			nKindFlags = FSYS_KIND_WILD;
538 			nError = FSYS_ERR_OK;
539 			return sal_True;
540 		}
541 
542 		nError = FSYS_ERR_NOTEXISTS;
543 		return sal_False;
544 	}
545 
546 	nError = FSYS_ERR_OK;
547 	nSize = aStat.st_size;
548 
549 	nKindFlags = FSYS_KIND_UNKNOWN;
550 	if ( ( aStat.st_mode & S_IFDIR ) == S_IFDIR )
551 		nKindFlags = nKindFlags | FSYS_KIND_DIR;
552 	if ( ( aStat.st_mode & S_IFREG ) == S_IFREG )
553 		nKindFlags = nKindFlags | FSYS_KIND_FILE;
554 	if ( ( aStat.st_mode & S_IFCHR ) == S_IFCHR )
555 		nKindFlags = nKindFlags | FSYS_KIND_DEV | FSYS_KIND_CHAR;
556 	if ( ( aStat.st_mode & S_IFBLK ) == S_IFBLK )
557 		nKindFlags = nKindFlags | FSYS_KIND_DEV | FSYS_KIND_BLOCK;
558 	if ( nKindFlags == FSYS_KIND_UNKNOWN )
559 		nKindFlags = nKindFlags | FSYS_KIND_FILE;
560 
561 	Unx2DateAndTime( aStat.st_ctime, aTimeCreated, aDateCreated );
562 	Unx2DateAndTime( aStat.st_mtime, aTimeModified, aDateModified );
563 	Unx2DateAndTime( aStat.st_atime, aTimeAccessed, aDateAccessed );
564 
565 	return sal_True;
566 }
567 
568 //====================================================================
569 
570 const char *TempDirImpl( char *pBuf )
571 {
572 #ifdef MACOSX
573     // P_tmpdir is /var/tmp on Mac OS X, and it is not cleaned up on system
574     // startup
575     strcpy( pBuf, "/tmp" );
576 #else
577     const char *pValue = getenv( "TEMP" );
578     if ( !pValue )
579         pValue = getenv( "TMP" );
580     if ( pValue )
581         strcpy( pBuf, pValue );
582     else
583 		// auf Solaris und Linux ist P_tmpdir vorgesehen
584         strcpy( pBuf, P_tmpdir );
585 		// hart auf "/tmp"  sollte wohl nur im Notfall verwendet werden
586         //strcpy( pBuf, "/tmp" );
587 #endif /* MACOSX */
588 
589     return pBuf;
590 }
591 
592 /*************************************************************************
593 |*
594 |*    DirEntry::GetPathStyle() const
595 |*
596 |*    Beschreibung
597 |*    Ersterstellung    MI 11.05.95
598 |*    Letzte Aenderung  MI 11.05.95
599 |*
600 *************************************************************************/
601 
602 FSysPathStyle DirEntry::GetPathStyle( const String & )
603 {
604     return FSYS_STYLE_UNX;
605 }
606 
607 /*************************************************************************
608 |*
609 |*    FileStat::SetDateTime
610 |*
611 |*    Ersterstellung	PB  27.06.97
612 |*    Letzte Aenderung
613 |*
614 *************************************************************************/
615 
616 void FileStat::SetDateTime( const String& rFileName,
617 			    const DateTime& rNewDateTime )
618 {
619 	tm times;
620 
621 	times.tm_year = rNewDateTime.GetYear()  - 1900;  	// 1997 -> 97
622 	times.tm_mon  = rNewDateTime.GetMonth() - 1;		// 0 == Januar!
623 	times.tm_mday = rNewDateTime.GetDay();
624 
625 	times.tm_hour = rNewDateTime.GetHour();
626 	times.tm_min  = rNewDateTime.GetMin();
627 	times.tm_sec  = rNewDateTime.GetSec();
628 
629 	times.tm_wday  = 0;
630 	times.tm_yday  = 0;
631 #ifdef SOLARIS
632 	times.tm_isdst = -1;
633 #else
634 	times.tm_isdst = 0;
635 #endif
636 
637 	time_t time = mktime (&times);
638 
639 	if (time != (time_t) -1)
640 	{
641 		struct utimbuf u_time;
642 		u_time.actime = time;
643 		u_time.modtime = time;
644 		utime (ByteString(rFileName, osl_getThreadTextEncoding()).GetBuffer(), &u_time);
645 	}
646 }
647 
648 //=========================================================================
649 
650 ErrCode FileStat::QueryDiskSpace( const String &, BigInt &, BigInt & )
651 {
652 	return ERRCODE_IO_NOTSUPPORTED;
653 }
654 
655 //=========================================================================
656 
657 void FSysEnableSysErrorBox( sal_Bool )
658 {
659 }
660 
661