xref: /aoo41x/main/tools/source/fsys/os2.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 #define INCL_DOSEXCEPTIONS
29 
30 #include <stdlib.h>
31 
32 #ifdef __BORLANDC__
33 #include <alloc.h>
34 #else
35 #include <malloc.h>
36 #endif
37 #include <tools/debug.hxx>
38 #include <tools/list.hxx>
39 #include <tools/bigint.hxx>
40 #include <tools/fsys.hxx>
41 #include "comdep.hxx"
42 
43 #ifdef OS2
44 #ifndef _VOS_MUTEX_HXX //autogen
45 #include <vos/mutex.hxx>
46 #endif
47 #endif
48 
49 int Sys2SolarError_Impl( int nSysErr );
50 
51 DECLARE_LIST( DirEntryList, DirEntry* );
52 DECLARE_LIST( FSysSortList, FSysSort* );
53 DECLARE_LIST( FileStatList, FileStat* );
54 
55 static char sCaseMap[256];
56 static BOOL bCaseMap = FALSE;
57 static BOOL bDriveMap = FALSE;
58 
59 struct DriveMapItem
60 {
61     DirEntryKind    nKind;
62     char            cName;
63     FSysPathStyle   nStyle;
64 };
65 
66 void CreateCaseMapImpl();
67 void CreateDriveMapImpl();
68 
69 static DriveMapItem aDriveMap[26];
70 
71 static BOOL   bLastCaseSensitive    = FALSE;
72 
73 //====================================================================
74 
75 int ApiRet2ToSolarError_Impl( int nApiRet )
76 {
77     switch ( nApiRet )
78     {
79         case NO_ERROR:                      return ERRCODE_NONE;
80         case ERROR_FILE_NOT_FOUND:          return ERRCODE_IO_NOTEXISTS;
81         case ERROR_PATH_NOT_FOUND:          return ERRCODE_IO_NOTEXISTSPATH;
82         case ERROR_TOO_MANY_OPEN_FILES:     return ERRCODE_IO_TOOMANYOPENFILES;
83         case ERROR_ACCESS_DENIED:           return ERRCODE_IO_ACCESSDENIED;
84         case ERROR_NOT_ENOUGH_MEMORY:       return ERRCODE_IO_OUTOFMEMORY;
85         case ERROR_BAD_FORMAT:              return ERRCODE_IO_WRONGFORMAT;
86         case ERROR_NOT_SAME_DEVICE:         return ERRCODE_IO_INVALIDDEVICE;
87         case ERROR_WRITE_PROTECT:           return ERRCODE_IO_INVALIDDEVICE;
88         case ERROR_BAD_UNIT:                return ERRCODE_IO_INVALIDDEVICE;
89         case ERROR_CRC:                     return ERRCODE_IO_INVALIDDEVICE;
90         case ERROR_NOT_DOS_DISK:            return ERRCODE_IO_INVALIDDEVICE;
91         case ERROR_WRITE_FAULT:             return ERRCODE_IO_CANTWRITE;
92         case ERROR_READ_FAULT:              return ERRCODE_IO_CANTREAD;
93         case ERROR_SHARING_VIOLATION:       return ERRCODE_IO_LOCKVIOLATION;
94         case ERROR_LOCK_VIOLATION:          return ERRCODE_IO_LOCKVIOLATION;
95         case ERROR_WRONG_DISK:              return ERRCODE_IO_LOCKVIOLATION;
96         case ERROR_HANDLE_DISK_FULL:        return ERRCODE_IO_OUTOFSPACE;
97         case ERROR_NOT_SUPPORTED:           return ERRCODE_IO_NOTSUPPORTED;
98         case ERROR_DUP_NAME:                return ERRCODE_IO_ALREADYEXISTS;
99         case ERROR_BAD_NETPATH:             return ERRCODE_IO_NOTEXISTSPATH;
100         case ERROR_DEV_NOT_EXIST:           return ERRCODE_IO_NOTEXISTS;
101         case ERROR_NETWORK_ACCESS_DENIED:   return ERRCODE_IO_ACCESSDENIED;
102         case ERROR_INVALID_PARAMETER:       return ERRCODE_IO_INVALIDPARAMETER;
103         case ERROR_NET_WRITE_FAULT:         return ERRCODE_IO_CANTWRITE;
104         case ERROR_DEVICE_IN_USE:           return ERRCODE_IO_INVALIDPARAMETER;
105         case ERROR_DISK_FULL:               return ERRCODE_IO_OUTOFSPACE;
106         case ERROR_BAD_ARGUMENTS:           return ERRCODE_IO_INVALIDPARAMETER;
107         case ERROR_BAD_PATHNAME:            return ERRCODE_IO_NOTEXISTSPATH;
108         case ERROR_LOCK_FAILED:             return ERRCODE_IO_LOCKVIOLATION;
109         case ERROR_LOCKED:                  return ERRCODE_IO_LOCKVIOLATION;
110         case ERROR_DUPLICATE_NAME:          return ERRCODE_IO_ALREADYEXISTS;
111         case ERROR_DIRECTORY_IN_CDS:        return ERRCODE_IO_LOCKVIOLATION;
112         case ERROR_CURRENT_DIRECTORY:       return ERRCODE_IO_LOCKVIOLATION;
113         case ERROR_FILENAME_EXCED_RANGE:    return ERRCODE_IO_NAMETOOLONG;
114     }
115 
116     DBG_TRACE1( "FSys: unknown apiret error %d occured", nApiRet );
117     return FSYS_ERR_UNKNOWN;
118 }
119 
120 //--------------------------------------------------------------------
121 
122 char* volumeid( const char* pPfad )
123 {
124     static FSINFO   aFSInfoBuf;
125     ULONG           ulFSInfoLevel = FSIL_VOLSER;
126     ULONG           nDriveNumber;
127 
128     nDriveNumber = toupper(*pPfad) - 'A' + 1;
129 
130     if ( nDriveNumber >= 3 )
131     {
132         APIRET rc = DosQueryFSInfo(
133             nDriveNumber, ulFSInfoLevel, &aFSInfoBuf, sizeof(FSINFO) );
134         if ( rc )
135             return 0;
136         return (char*) aFSInfoBuf.vol.szVolLabel;
137     }
138     return 0;
139 }
140 
141 //--------------------------------------------------------------------
142 
143 /*************************************************************************
144 |*
145 |*    DirEntry::ToAbs()
146 |*
147 |*    Beschreibung      FSYS.SDW
148 |*    Ersterstellung    MI 26.04.91
149 |*    Letzte Aenderung  MA 02.12.91 13:30
150 |*
151 *************************************************************************/
152 
153 BOOL DirEntry::ToAbs()
154 {
155     DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
156 
157     if ( FSYS_FLAG_VOLUME == eFlag )
158     {
159         eFlag = FSYS_FLAG_ABSROOT;
160         return TRUE;
161     }
162 
163     if ( IsAbs() )
164         return TRUE;
165 
166 	char sBuf[_MAX_PATH + 1];
167 	*this = DirEntry( String( getcwd( sBuf, _MAX_PATH ), osl_getThreadTextEncoding() ) ) + *this;
168 
169     return IsAbs();
170 }
171 
172 /*************************************************************************
173 |*
174 |*    DirEntry::GetVolume()
175 |*
176 |*    Beschreibung      FSYS.SDW
177 |*    Ersterstellung    MI 04.03.92
178 |*    Letzte Aenderung  MI 04.03.92
179 |*
180 *************************************************************************/
181 
182 String DirEntry::GetVolume() const
183 {
184     DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
185 
186     String aRet;
187     const DirEntry *pTop = ImpGetTopPtr();
188     ByteString aName = ByteString( pTop->aName ).ToLowerAscii();
189 
190     if ( ( pTop->eFlag == FSYS_FLAG_ABSROOT ||
191            pTop->eFlag == FSYS_FLAG_RELROOT ||
192            pTop->eFlag == FSYS_FLAG_VOLUME )
193          && aName != "a:" && aName != "b:" && Exists() )
194     {
195         const char *pVol;
196         pVol = volumeid( (char*) pTop->aName.GetBuffer() );
197 		if (pVol)
198 			aRet = String( pVol, osl_getThreadTextEncoding());
199     }
200 
201     return aRet;
202 }
203 
204 /*************************************************************************
205 |*
206 |*    DirEntry::SetCWD()
207 |*
208 |*    Beschreibung      FSYS.SDW
209 |*    Ersterstellung    MI 26.04.91
210 |*    Letzte Aenderung  MI 21.05.92
211 |*
212 *************************************************************************/
213 
214 BOOL DirEntry::SetCWD( BOOL bSloppy ) const
215 {
216     DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
217 
218     if ( eFlag == FSYS_FLAG_CURRENT && !aName.Len() )
219         return TRUE;
220 
221     if ( !chdir(ByteString(GetFull(), osl_getThreadTextEncoding()).GetBuffer()) )
222     {
223         //nError = FSYS_ERR_OK;
224         return TRUE;
225     }
226 
227     if ( bSloppy && pParent &&
228          !chdir(ByteString(pParent->GetFull(), osl_getThreadTextEncoding()).GetBuffer()) )
229     {
230         //nError = FSYS_ERR_OK;
231         return TRUE;
232     }
233 
234     //nError = FSYS_ERR_NOTADIRECTORY;
235     return FALSE;
236 }
237 
238 /*************************************************************************
239 |*
240 |*    DirEntry::MoveTo()
241 |*
242 |*    Beschreibung      FSYS.SDW
243 |*    Ersterstellung    MI 26.04.91
244 |*    Letzte Aenderung  MA 02.12.91 14:07
245 |*
246 *************************************************************************/
247 
248 #if 0 // YD see dirent.cxx
249 BOOL createLongNameEA( const PCSZ pszPath, ULONG ulAttributes, const String& aLongName );
250 
251 FSysError DirEntry::MoveTo( const DirEntry& rDest ) const
252 {
253     DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
254 
255     DirEntry aTmpDest(rDest);
256     FileStat aTmpStat(aTmpDest);
257     if ( aTmpStat.IsKind(FSYS_KIND_DIR) )
258         aTmpDest += DirEntry( GetName() );
259 
260     String aSource( GetFull() );
261     String aDest( aTmpDest.GetFull() );
262     String aShortSource("");
263     String aShortDest("");
264 
265     if (Folder::IsAvailable())
266     {
267         if  (IsLongNameOnFAT())
268         {
269             // in kurzen Pfad wandeln
270             ItemIDPath      aItemIDPath(aSource);
271             aShortSource = aItemIDPath.GetHostNotationPath();
272         }
273         if  (rDest.IsLongNameOnFAT())
274         {
275             // in kurzen Pfad wandeln
276             ItemIDPath      aItemIDPath(aDest);
277             aShortDest = aItemIDPath.GetHostNotationPath();
278         }
279     }
280 
281     APIRET nRet = DosMove( aShortSource.Len()>0?(PSZ)aShortSource.GetStr():(PSZ)aSource.GetStr(),
282                            aShortDest.Len()>0?(PSZ)aShortDest.GetStr():(PSZ)aDest.GetStr());
283 
284     if ( nRet == ERROR_DIRECTORY_IN_CDS ||
285          nRet == ERROR_CURRENT_DIRECTORY )
286     {
287         // 2nd chance with modified CWD
288         DosSetCurrentDir( (PSZ) "\\" );
289         nRet = DosMove( aShortSource.Len()>0?(PSZ)aShortSource.GetStr():(PSZ)aSource.GetStr(),
290                         aShortDest.Len()>0?(PSZ)aShortDest.GetStr():(PSZ)aDest.GetStr());
291     }
292     else if ( nRet == ERROR_NOT_SAME_DEVICE )
293     {
294         // other volume => copy+delete
295         FileCopier aMover( *this, rDest );
296         nRet = aMover.Execute( FSYS_ACTION_MOVE|FSYS_ACTION_RECURSIVE );
297         return nRet;
298     }
299 
300     if ( (nRet==NO_ERROR) && aShortDest.Len()>0)
301     {
302 	createLongNameEA((const char*)aShortDest,  FILE_NORMAL, rDest.GetName());
303     }
304 
305     return ApiRet2ToSolarError_Impl( nRet );
306 }
307 #endif // 0
308 
309 //-------------------------------------------------------------------------
310 
311 USHORT DirReader_Impl::Init()
312 {
313     // Block-Devices auflisten?
314     if ( pDir->eAttrMask & FSYS_KIND_BLOCK )
315     {
316         CreateDriveMapImpl();
317         // CWD merken
318         DirEntry aCurrentDir;
319         aCurrentDir.ToAbs();
320 
321         // einzeln auf Existenz und Masken-konformit"at pr"ufen
322         USHORT nRead = 0;
323         char sDrive[3] = { '?', ':', 0 };
324         char sRoot[4] = { '?', ':', '\\', 0 };
325         for ( char c = 'a'; c <= 'z'; c++ )
326         {
327             sDrive[0] = c;
328             sRoot[0] = c;
329             DirEntry* pDrive = new DirEntry( sDrive, FSYS_FLAG_VOLUME, FSYS_STYLE_HOST );
330             if ( pDir->aNameMask.Matches( String( ByteString(sDrive), osl_getThreadTextEncoding()))
331 				&& aDriveMap[c-'a'].nKind != FSYS_KIND_UNKNOWN )
332             {
333                 if ( pDir->pStatLst ) //Status fuer Sort gewuenscht?
334                 {
335                     FileStat *pNewStat = new FileStat( *pDrive );
336                     pDir->ImpSortedInsert( pDrive, pNewStat );
337                 }
338                 else
339                     pDir->ImpSortedInsert( pDrive, NULL );
340                 ++nRead;
341             }
342             else
343                 delete pDrive;
344         }
345 
346         // CWD restaurieren
347         aCurrentDir.SetCWD();
348         return nRead;
349     }
350 
351     return 0;
352 }
353 
354 //-------------------------------------------------------------------------
355 
356 USHORT DirReader_Impl::Read()
357 {
358 	if (!pDosDir)
359 	{
360 		pDosDir = opendir( (char*) ByteString(aPath, osl_getThreadTextEncoding()).GetBuffer() );
361 	}
362 
363 	if (!pDosDir)
364 	{
365 		bReady = TRUE;
366 		return 0;
367 	}
368 
369     // Directories und Files auflisten?
370 	if ( ( pDir->eAttrMask & FSYS_KIND_DIR || pDir->eAttrMask & FSYS_KIND_FILE ) &&
371 		 ( ( pDosEntry = readdir( pDosDir ) ) != NULL ) )
372 	{
373 		String aD_Name(pDosEntry->d_name, osl_getThreadTextEncoding());
374         if ( pDir->aNameMask.Matches( aD_Name  ) )
375         {
376 			DirEntryFlag eFlag =
377 					0 == strcmp( pDosEntry->d_name, "." ) ? FSYS_FLAG_CURRENT
378 				:	0 == strcmp( pDosEntry->d_name, ".." ) ? FSYS_FLAG_PARENT
379 				:	FSYS_FLAG_NORMAL;
380             DirEntry *pTemp = new DirEntry( ByteString(pDosEntry->d_name), eFlag, FSYS_STYLE_UNX );
381             if ( pParent )
382                 pTemp->ImpChangeParent( new DirEntry( *pParent ), FALSE);
383             FileStat aStat( *pTemp );
384             if ( ( ( ( pDir->eAttrMask & FSYS_KIND_DIR ) &&
385 					 ( aStat.IsKind( FSYS_KIND_DIR ) ) ) ||
386 				   ( ( pDir->eAttrMask & FSYS_KIND_FILE ) &&
387 					 !( aStat.IsKind( FSYS_KIND_DIR ) ) ) ) &&
388 				 !( pDir->eAttrMask & FSYS_KIND_VISIBLE &&
389 					pDosEntry->d_name[0] == '.' ) )
390             {
391                 if ( pDir->pStatLst ) //Status fuer Sort gewuenscht?
392                     pDir->ImpSortedInsert( pTemp, new FileStat( aStat ) );
393                 else
394                     pDir->ImpSortedInsert( pTemp, NULL );;
395 				return 1;
396             }
397             else
398                 delete pTemp;
399         }
400 	}
401 	else
402 		bReady = TRUE;
403 	return 0;
404 }
405 
406 /*************************************************************************
407 |*
408 |*    FileStat::FileStat()
409 |*
410 |*    Beschreibung      FSYS.SDW
411 |*    Ersterstellung    MA 05.11.91
412 |*    Letzte Aenderung  MA 07.11.91
413 |*
414 *************************************************************************/
415 
416 FileStat::FileStat( const void *pInfo,      // struct dirent
417                     const void * ):         // dummy
418         aDateCreated(0),
419         aTimeCreated(0),
420         aDateModified(0),
421         aTimeModified(0),
422         aDateAccessed(0),
423         aTimeAccessed(0)
424 {
425     struct dirent *pDirent = (struct dirent*) pInfo;
426 
427     nSize = pDirent->d_size;
428 
429     aDateCreated  = MsDos2Date( (FDATE*) &pDirent->d_date );
430     aTimeCreated  = MsDos2Time( (FTIME*) &pDirent->d_time );
431     aDateModified = aDateModified;
432     aTimeModified = aTimeModified;
433     aDateAccessed = aDateModified;
434     aTimeAccessed = aTimeModified;
435 
436     nKindFlags = FSYS_KIND_FILE;
437     if ( pDirent->d_type & DOS_DIRECT )
438         nKindFlags = FSYS_KIND_DIR;
439 }
440 
441 /*************************************************************************
442 |*
443 |*    FileStat::Update()
444 |*
445 |*    Beschreibung      FSYS.SDW
446 |*    Ersterstellung    MI 11.06.91
447 |*    Letzte Aenderung  MA 07.11.91
448 |*
449 *************************************************************************/
450 
451 struct _FSYS_FSQBUFFER
452 {
453     FSQBUFFER2  aBuf;
454     UCHAR       sBuf[256];
455 };
456 
457 BOOL FileStat::Update( const DirEntry& rDirEntry, BOOL bAccessRemovableDevice )
458 {
459     nSize = 0;
460     FSysPathStyle eStyle = FSYS_STYLE_UNKNOWN;
461     aCreator.Erase();
462     aType.Erase();
463     aDateCreated = Date(0);
464     aTimeCreated = Time(0);
465     aDateModified = Date(0);
466     aTimeModified = Time(0);
467     aDateAccessed = Date(0);
468     aTimeAccessed = Time(0);
469 
470 	if ( !rDirEntry.IsValid() )
471 	{
472 		nError = FSYS_ERR_NOTEXISTS;
473 		return FALSE;
474 	}
475 
476 	// Sonderbehandlung falls es sich um eine Root ohne Laufwerk handelt
477 	if ( !rDirEntry.aName.Len() && rDirEntry.eFlag == FSYS_FLAG_ABSROOT )
478 	{
479 		nKindFlags = FSYS_KIND_DIR;
480 		nError = FSYS_ERR_OK;
481 		return TRUE;
482 	}
483 
484     // Sonderbehandlung falls es sich um eine Wildcard handelt
485     ByteString aTempName( rDirEntry.GetName(), osl_getThreadTextEncoding() );
486     if ( strchr( aTempName.GetBuffer(), '?' ) ||
487          strchr( aTempName.GetBuffer(), '*' ) ||
488          strchr( aTempName.GetBuffer(), ';' ) )
489     {
490         nKindFlags = FSYS_KIND_WILD;
491         nError = FSYS_ERR_OK;
492         return TRUE;
493     }
494 
495     // Sonderbehandlung falls es sich um eine Root handelt
496     if ( rDirEntry.eFlag == FSYS_FLAG_VOLUME ||
497          rDirEntry.eFlag == FSYS_FLAG_ABSROOT )
498     {
499         if ( rDirEntry.eFlag == FSYS_FLAG_VOLUME )
500             nKindFlags = FSYS_KIND_DEV;
501         else
502             nKindFlags = FSYS_KIND_DIR;
503 
504         if ( rDirEntry.aName.Len() == 2 )
505         {
506             if ( !bDriveMap )
507                 CreateDriveMapImpl();
508 
509 			ByteString rDirEntryUpperCase = ByteString( rDirEntry.aName ).ToUpperAscii();
510             DriveMapItem &rItem = aDriveMap[rDirEntryUpperCase.GetChar(0) - 'A'];
511             if ( !rItem.nKind )
512             {
513                 nError = ERRCODE_IO_INVALIDDEVICE;
514                                 nKindFlags = FSYS_KIND_UNKNOWN;
515                 return FALSE;
516             }
517             else
518             {
519                 if ( rDirEntry.eFlag == FSYS_FLAG_VOLUME )
520                     nKindFlags |= FSYS_KIND_BLOCK | rItem.nKind;
521                 eStyle = rItem.nStyle;
522             }
523         }
524 
525         nError = FSYS_ERR_OK;
526         return TRUE;
527     }
528 
529     // disable error-boxes for hard-errors
530     DosError(FERR_DISABLEHARDERR);
531 
532     // Statusinformation vom Betriebssystem holen
533     DirEntry    aTempDirEntry( rDirEntry );
534     char*       p;
535 
536     aTempDirEntry.ToAbs();
537     ByteString aFullName( aTempDirEntry.GetFull(), osl_getThreadTextEncoding() );
538 
539 #if 0 // YD
540 	if (Folder::IsAvailable() && aTempDirEntry.IsLongNameOnFAT())
541 	{
542 		// in String mit kurzem Pfad wandeln
543 		ItemIDPath aItemIDPath(aTempDirEntry.GetFull());
544 		aFullName = ByteString( aItemIDPath.GetHostNotationPath(), osl_getThreadTextEncoding() );
545 	}
546 #endif
547 
548     p = (char *) aFullName.GetBuffer();
549 
550     FILESTATUS3 filestat;
551     memset( &filestat, 0, sizeof( filestat ) );
552     if( DosQueryPathInfo( (PSZ)p, 1, &filestat, sizeof( filestat ) ) )
553     {
554         nError = FSYS_ERR_NOTEXISTS;
555         nKindFlags = FSYS_KIND_UNKNOWN;
556         return FALSE;
557     }
558 
559     nError = FSYS_ERR_OK;
560     nSize = filestat.cbFile;
561 
562     nKindFlags = FSYS_KIND_UNKNOWN;
563     if( filestat.attrFile & FILE_DIRECTORY )
564         nKindFlags |= FSYS_KIND_DIR;
565     if ( nKindFlags == FSYS_KIND_UNKNOWN )
566         nKindFlags = nKindFlags | FSYS_KIND_FILE;
567 
568     aDateModified = Date( filestat.fdateLastWrite.day,
569                           filestat.fdateLastWrite.month,
570                           filestat.fdateLastWrite.year + 1980 );
571 
572     aTimeModified = Time( filestat.ftimeLastWrite.hours,
573                           filestat.ftimeLastWrite.minutes,
574                           filestat.ftimeLastWrite.twosecs*2 );
575 
576     if ( filestat.fdateCreation.day )
577     {
578         aDateCreated  = Date( filestat.fdateCreation.day,
579                               filestat.fdateCreation.month,
580                               filestat.fdateCreation.year + 1980 );
581 
582         aTimeCreated  = Time( filestat.ftimeCreation.hours,
583                               filestat.ftimeCreation.minutes,
584                               filestat.ftimeCreation.twosecs*2 );
585     }
586     else
587     {
588         aDateCreated = aDateModified;
589         aTimeCreated = aTimeModified;
590     }
591 
592     if ( filestat.fdateLastAccess.day > 0 )
593     {
594         aDateAccessed = Date( filestat.fdateLastAccess.day,
595                               filestat.fdateLastAccess.month,
596                               filestat.fdateLastAccess.year + 1980 );
597 
598         aTimeAccessed = Time( filestat.ftimeLastAccess.hours,
599                                 filestat.ftimeLastAccess.minutes,
600                                 filestat.ftimeLastAccess.twosecs*2 );
601     }
602     else
603     {
604         aDateAccessed = aDateModified;
605         aTimeAccessed = aTimeModified;
606     }
607 
608     return TRUE;
609 }
610 
611 BOOL IsRedirectable_Impl( const ByteString &rPath )
612 {
613     if ( rPath.Len() >= 3 && ':' == rPath.GetBuffer()[1] )
614     {
615         ByteString aVolume = rPath.Copy( 0, 3 );
616         DriveMapItem &rItem = aDriveMap[toupper(aVolume.GetChar(0)) - 'A'];
617         return FSYS_KIND_FIXED != rItem.nKind;
618     }
619     return FALSE;
620 }
621 
622 #if 0
623 BOOL IsRedirectable_Impl( const String &rPath )
624 {
625     if ( rPath.Len() >= 3 && ':' == rPath.GetStr()[1] )
626     {
627         DriveMapItem &rItem = aDriveMap[toupper(rPath[0]) - 'A'];
628         return FSYS_KIND_FIXED != rItem.nKind;
629     }
630     return FALSE;
631 }
632 #endif
633 
634 
635 /*************************************************************************
636 |*
637 |*    TempDirImpl()
638 |*
639 |*    Beschreibung      liefert den Namens des Directories fuer temporaere
640 |*                      Dateien
641 |*    Ersterstellung    MI 16.03.94
642 |*    Letzte Aenderung  MI 16.03.94
643 |*
644 *************************************************************************/
645 
646 const char* TempDirImpl( char *pBuf )
647 {
648     PSZ         pVar;
649     USHORT      nRet;
650     BOOL        bAppendTemp = FALSE; // mu\s noch \\temp angeh"angt werden
651 
652     // Erstmal sehen, ob TEMP oder TMP gesetzt sind
653     nRet = DosScanEnv( (PSZ)"TEMP", &pVar );
654     if( nRet )
655         nRet = DosScanEnv( (PSZ)"temp", &pVar );
656     if( nRet )
657         nRet = DosScanEnv( (PSZ)"TMP", &pVar );
658     if( nRet )
659         nRet = DosScanEnv( (PSZ)"tmp", &pVar );
660     if( nRet )
661         nRet = DosScanEnv( (PSZ)"TMPDIR", &pVar );
662 
663     // falls das geklappt hat, und ein Backslash dranhaengt,
664     // oder falls es bisher nicht geklappt hat,
665     // muessen wir nachher einen Backslash entfernen
666     BOOL bRemoveBS = nRet || *(pVar+strlen(pVar)-1) == '\\';
667 
668     // Keine temp-Variable gefunden, dann gehen wir mal auf die Suche
669     // nach dem System-Laufwerk
670     if( nRet )
671     {
672         nRet = DosScanEnv( (PSZ)"USER_INI",&pVar );
673         bAppendTemp = (0 == nRet);
674     }
675     if( nRet )
676     {
677         nRet = DosScanEnv( (PSZ)"SYSTEM_INI", &pVar );
678         bAppendTemp = (0 == nRet);
679     }
680     if( nRet )
681         // Wenn das immer noch nicht reicht nehmen wir eben die Root von C:
682 #ifdef __BORLANDC__
683         pVar = (PSZ)"c:\\temp\\";
684 #else
685         pVar = (PCSZ)"c:\\temp\\";
686 #endif
687     strcpy( pBuf, (const char*)pVar );
688 
689     // jetzt haengt ggf. ein Backlash dran, den wir abschneiden,
690     // ggf. inklusive dahinter haengendem Dateinamen
691     if ( bRemoveBS )
692     {
693         char *pTail = pBuf + strlen(pBuf) - 1;
694         for ( char cLast = *pTail; cLast != '\\'; cLast = *(--pTail) )
695             *pTail = 0;
696     }
697 
698     if ( bAppendTemp )
699         strcat( pBuf, "\\temp" );
700     DirEntry( pBuf ).MakeDir();
701 
702     return pBuf;
703 }
704 
705 #define CURRENT_COUNTRY 0
706 #define NLS_CODEPAGE 850
707 
708 /*====================================================================
709  * CreateCaseMapImpl()
710  * creates a map of each character to convert to lower
711  *--------------------------------------------------------------------*/
712 
713 #if 0
714 void CreateCaseMapImpl()
715 {
716     // build a string starting with code 0 as first character upto 255
717     char sTemp[256];
718 	USHORT n;
719 
720     for ( n = 0; n < 256; ++n )
721         sTemp[n] = (char) n;
722 
723     // convert string to upper case
724     COUNTRYCODE aCountry;
725     aCountry.country = CURRENT_COUNTRY;   /* Country code */
726     aCountry.codepage = NLS_CODEPAGE;     /* Code page */
727     DosMapCase( 255, &aCountry, sTemp+1 );
728 
729     // fill a global buffer starting with code 0 as first character upto 255
730     for ( n = 0; n < 256; ++n )
731         sCaseMap[n] = (char) n;
732 
733     // reorder by upper-code and store in a global buffer
734     for ( n = 255; n > 0; --n )
735         // was this character converted?
736         if ( sTemp[n] != (char) n )
737             // we found a convertion from upper to lower
738             sCaseMap[ (unsigned char) sTemp[n] ] = (char) n;
739 
740     bCaseMap = TRUE;
741 }
742 
743 String ToLowerImpl( const String& rSource )
744 {
745     if ( !bCaseMap )
746         CreateCaseMapImpl();
747 
748     // TH sagt: International ist zu langsam, also mit einer eigenen Map
749     ByteString aLower( rSource );
750     for ( USHORT n = 0; n < aLower.Len(); ++n )
751         aLower[n] = sCaseMap[ (unsigned char) aLower[n] ];
752     return aLower;
753 }
754 #endif // 0
755 
756 /*====================================================================
757  * CreateDriveMapImpl()
758  * creates a map of drive-infos like FileSystem (style) and Kind (remote)
759  *--------------------------------------------------------------------*/
760 typedef struct _FSQBUFFER_
761 {
762     FSQBUFFER2  aBuf;
763     UCHAR       sBuf[64];
764 } FSQBUFFER_;
765 
766 void CreateDriveMapImpl()
767 {
768 #ifdef POWERPC
769     // !!!!! Hack, da der untere Teil mit Beta 2 noch abstuertzt !!!!!
770     BYTE nFloppies = 1;
771     for ( USHORT nDrive = 0; nDrive < 26; ++nDrive )
772     {
773         if ( nDrive < nFloppies )
774         {
775             aDriveMap[nDrive].nKind = FSYS_KIND_REMOVEABLE;
776             aDriveMap[nDrive].nStyle = FSYS_STYLE_FAT;
777         }
778         else
779         {
780             aDriveMap[nDrive].nKind = FSYS_KIND_UNKNOWN;
781             aDriveMap[nDrive].nStyle = FSYS_STYLE_UNKNOWN;
782         }
783     }
784 
785     aDriveMap[2].nKind = FSYS_KIND_FIXED;
786     aDriveMap[2].nStyle = FSYS_STYLE_FAT;
787 #else
788     FSQBUFFER_	aBuf;
789     ULONG       nBufLen;
790     APIRET      nRet;
791 	USHORT 		nDrive;
792 
793     // disable error-boxes for hard-errors
794     DosError(FERR_DISABLEHARDERR);
795 
796     // determine number of floppy-drives
797     BYTE nFloppies;
798     nRet = DosDevConfig( (void*) &nFloppies, DEVINFO_FLOPPY );
799 
800     // reset the map
801     for ( nDrive = 0; nDrive < 26; ++nDrive )
802     {
803         if ( nDrive < nFloppies )
804         {
805             aDriveMap[nDrive].nKind = FSYS_KIND_REMOVEABLE;
806             aDriveMap[nDrive].nStyle = FSYS_STYLE_FAT;
807         }
808         else
809         {
810             aDriveMap[nDrive].nKind = FSYS_KIND_UNKNOWN;
811             aDriveMap[nDrive].nStyle = FSYS_STYLE_UNKNOWN;
812         }
813     }
814 
815     // determine file-system via DosOpen/DocDevIOCtrl
816     for ( nDrive = 2; nDrive < 26; ++nDrive )
817     {
818         // open drive
819         BOOL bFixed;
820         HFILE nDevHandle;
821         char pDriveName[3] = "#:";
822         pDriveName[0] = nDrive+'a';
823         ULONG nAction;
824         nRet = DosOpen( (PSZ) pDriveName, &nDevHandle,
825             &nAction, 0, 0, OPEN_ACTION_OPEN_IF_EXISTS,
826             OPEN_FLAGS_DASD|OPEN_SHARE_DENYNONE|OPEN_ACCESS_READONLY,
827             0 );
828 
829         // exists?
830         if ( !nRet )
831         {
832             // removeable?
833             BYTE nDriveId = nDrive;
834             ULONG nParaOutLen, nDataOutLen;
835             nRet = DosDevIOCtl(nDevHandle, 8, 0x20,
836                 &nDriveId, sizeof(nDriveId), &nParaOutLen,
837                 &bFixed, sizeof(bFixed), &nDataOutLen );
838 
839             // prepare the drive-map
840             if ( !nRet && !bFixed )
841                 aDriveMap[nDrive].nKind = FSYS_KIND_REMOVEABLE;
842 
843             // close drive
844             DosClose(nDevHandle);
845         }
846         else if ( nRet == ERROR_NOT_READY )
847             aDriveMap[nDrive].nKind = FSYS_KIND_REMOVEABLE | FSYS_KIND_CDROM;
848     }
849 
850     // determine file-system via FSAttach
851     nRet = 0;
852     for ( USHORT n = 3; nRet != ERROR_NO_MORE_ITEMS; ++n )
853     {
854         nBufLen = sizeof( aBuf );
855         nRet = DosQueryFSAttach( 0, n, FSAIL_DRVNUMBER,
856             (_FSQBUFFER2*) &aBuf, &nBufLen );
857         if ( !nRet )
858         {
859             nDrive = toupper(aBuf.aBuf.szName[0]) - 'A';
860 
861             if ( aDriveMap[nDrive].nKind == FSYS_KIND_UNKNOWN )
862                 aDriveMap[nDrive].nKind =
863                     aBuf.aBuf.iType == 3 ? FSYS_KIND_FIXED :
864                     aBuf.aBuf.iType == 4 ? FSYS_KIND_REMOTE :
865                     FSYS_KIND_UNKNOWN;
866 
867             char *pType = (char*)(aBuf.aBuf.szName + aBuf.aBuf.cbName + 1);
868             aDriveMap[nDrive].nStyle =
869                 strcmp( pType, "FAT" ) == 0 ? FSYS_STYLE_FAT :
870                 strcmp( pType, "FAT32" ) == 0 ? FSYS_STYLE_VFAT :
871                 strcmp( pType, "NTFS" ) == 0 ? FSYS_STYLE_NTFS :
872                 strcmp( pType, "HPFS" ) == 0 ? FSYS_STYLE_HPFS :
873                 strcmp( pType, "JFS" ) == 0 ? FSYS_STYLE_HPFS :
874                 strcmp( pType, "RAMFS" ) == 0 ? FSYS_STYLE_HPFS :
875                 strcmp( pType, "NDFS32" ) == 0 ? FSYS_STYLE_HPFS :
876                 strcmp( pType, "NWFS" ) == 0 ? FSYS_STYLE_NWFS :
877 				strcmp( pType, "EXT2" ) == 0 ? FSYS_STYLE_UNX :
878 				strcmp( pType, "NFS" ) == 0 ? FSYS_STYLE_UNX :
879                 FSYS_STYLE_UNKNOWN;
880             if ( strcmp( pType, "CDFS" ) == 0 )
881                 aDriveMap[nDrive].nKind = FSYS_KIND_CDROM|FSYS_KIND_REMOVEABLE;
882         }
883     }
884 #endif
885 
886     bDriveMap = TRUE;
887 }
888 
889 Time MsDos2Time( const time_t *pTimeT )
890 {
891     tm *pTm = localtime( pTimeT );
892     if ( pTm )
893         return Time( pTm->tm_hour, pTm->tm_min, pTm->tm_sec );
894     else
895         return Time(0);
896 }
897 
898 Date MsDos2Date( const time_t *pTimeT )
899 {
900     tm *pTm = localtime( pTimeT );
901     if ( pTm )
902         return Date( pTm->tm_mday, pTm->tm_mon + 1, pTm->tm_year );
903     else
904         return Date(0);
905 }
906 
907 /*************************************************************************
908 |*
909 |*    DirEntry::GetPathStyle() const
910 |*
911 |*    Beschreibung
912 |*    Ersterstellung    MI 11.05.95
913 |*    Letzte Aenderung  MI 11.05.95
914 |*
915 *************************************************************************/
916 
917 FSysPathStyle DirEntry::GetPathStyle( const String &rDevice )
918 {
919     ByteString aRootDir(rDevice, osl_getThreadTextEncoding());
920     // UNC-Pathname?
921     if ( aRootDir.Len()==0 || ( aRootDir.Len() > 1 && aRootDir.GetChar(1) != ':' ) )
922         return FSYS_STYLE_UNKNOWN;
923 
924     if ( !bDriveMap )
925         CreateDriveMapImpl();
926     return aDriveMap[toupper(aRootDir.GetChar(0)) - 'A'].nStyle;
927 }
928 
929 /*************************************************************************
930 |*
931 |*    DirEntry::IsCaseSensitive() const
932 |*
933 |*    Beschreibung
934 |*    Ersterstellung    TPF 26.02.1999
935 |*    Letzte Aenderung
936 |*
937 *************************************************************************/
938 
939 BOOL DirEntry::IsCaseSensitive( FSysPathStyle eFormatter ) const
940 {
941 	if (eFormatter==FSYS_STYLE_HOST)
942 	{
943 		if 	(GetPathStyle(GetDevice().GetName()) == FSYS_STYLE_UNX)
944 		{
945 			return TRUE;
946 		}
947 		else
948 		{
949 			return FALSE;
950 		}
951 	}
952 	else
953 	{
954 		BOOL isCaseSensitive = FALSE;			// ich bin unter OS2, also ist der default im Zweifelsfall case insensitiv
955 		switch ( eFormatter )
956 		{
957 			case FSYS_STYLE_MAC:
958 			case FSYS_STYLE_FAT:
959 			case FSYS_STYLE_VFAT:
960 			case FSYS_STYLE_NTFS:
961 			case FSYS_STYLE_NWFS:
962 			case FSYS_STYLE_HPFS:
963 			case FSYS_STYLE_DETECT:
964 				{
965 					isCaseSensitive = FALSE;
966 					break;
967 				}
968 			case FSYS_STYLE_SYSV:
969 			case FSYS_STYLE_BSD:
970 				{
971 					isCaseSensitive = TRUE;
972 					break;
973 				}
974 			default:
975 				{
976 					isCaseSensitive = FALSE;	// ich bin unter OS2, also ist der default im Zweifelsfall case insensitiv
977 					break;
978 				}
979 		}
980 		return isCaseSensitive;
981 	}
982 }
983 
984 
985 
986 
987 //=========================================================================
988 
989 ErrCode FileStat::QueryDiskSpace( const String &rPath,
990                                   BigInt &rFreeBytes, BigInt &rTotalBytes )
991 {
992     FSALLOCATE aFSInfoBuf;
993     ByteString aVol( DirEntry(rPath).ImpGetTopPtr()->GetName(), osl_getThreadTextEncoding());
994     ULONG nDriveNumber = toupper( aVol.GetChar(0) ) - 'A' + 1;
995 
996     APIRET rc = DosQueryFSInfo( nDriveNumber, FSIL_ALLOC,
997                                 &aFSInfoBuf, sizeof(aFSInfoBuf) );
998     if ( rc )
999         return Sys2SolarError_Impl( rc );
1000 
1001     BigInt aBytesPerCluster( BigInt(aFSInfoBuf.cbSector) *
1002                              BigInt(aFSInfoBuf.cSectorUnit) );
1003     rFreeBytes = aBytesPerCluster * BigInt(aFSInfoBuf.cUnitAvail);
1004     rTotalBytes = aBytesPerCluster * BigInt(aFSInfoBuf.cUnit);
1005     return 0;
1006 }
1007 
1008 //=========================================================================
1009 
1010 void FSysEnableSysErrorBox( BOOL bEnable )
1011 {
1012     DosError( bEnable ? 0 : FERR_DISABLEHARDERR );
1013 }
1014 
1015