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