os/kernelhwsrv/userlibandfileserver/fileserver/sfat/sl_vfat.cpp
changeset 0 bde4ae8d615e
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/os/kernelhwsrv/userlibandfileserver/fileserver/sfat/sl_vfat.cpp	Fri Jun 15 03:10:57 2012 +0200
     1.3 @@ -0,0 +1,726 @@
     1.4 +// Copyright (c) 1996-2009 Nokia Corporation and/or its subsidiary(-ies).
     1.5 +// All rights reserved.
     1.6 +// This component and the accompanying materials are made available
     1.7 +// under the terms of the License "Eclipse Public License v1.0"
     1.8 +// which accompanies this distribution, and is available
     1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
    1.10 +//
    1.11 +// Initial Contributors:
    1.12 +// Nokia Corporation - initial contribution.
    1.13 +//
    1.14 +// Contributors:
    1.15 +//
    1.16 +// Description:
    1.17 +// f32\sfat\sl_vfat.cpp
    1.18 +// 
    1.19 +//
    1.20 +
    1.21 +//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    1.22 +//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    1.23 +//!!
    1.24 +//!! WARNING!! DO NOT edit this file !! '\sfat' component is obsolete and is not being used. '\sfat32'replaces it
    1.25 +//!!
    1.26 +//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    1.27 +//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    1.28 +
    1.29 +
    1.30 +#include "sl_std.h"
    1.31 +#include "sl_cache.h"
    1.32 +#include <e32svr.h>
    1.33 +#include <e32math.h>
    1.34 +
    1.35 +
    1.36 +IMPORT_C const TFatUtilityFunctions* GetFatUtilityFunctions();
    1.37 +
    1.38 +const TInt KMaxLengthWithoutTilde = 8;
    1.39 +const TUint8 KLeadingE5Replacement = 0x05;
    1.40 +
    1.41 +// use second half of ISO Latin 1 character set for extended chars
    1.42 +const TUint KExtendedCharStart=0x80;
    1.43 +const TUint KExtendedCharEnd=0xff;
    1.44 +
    1.45 +LOCAL_C TBool IsLegalChar(TChar aCharacter,TBool aAllowWildChars,TBool aUseExtendedChars=EFalse,TBool aInScanDrive=EFalse)
    1.46 +//
    1.47 +// Returns ETrue if aCharacter is legal inside a dos filename
    1.48 +//
    1.49 +    {
    1.50 +    if ((aCharacter==KMatchOne) || (aCharacter==KMatchAny))
    1.51 +        return(aAllowWildChars);
    1.52 +    if ((TUint)aCharacter < 0x20)
    1.53 +        return EFalse;
    1.54 +    // Don't check illegal ascii char because some non-English char value may
    1.55 +    // fall in this area
    1.56 +    if (aInScanDrive)
    1.57 +        return ETrue;
    1.58 +    return LocaleUtils::IsLegalShortNameCharacter(aCharacter,aUseExtendedChars);
    1.59 +    }
    1.60 +
    1.61 +LOCAL_C void ReplaceFirstCharacterIfClashesWithE5L(TDes8& aShortName)
    1.62 +    {
    1.63 +    if (0 < aShortName.Length() && aShortName[0] == KEntryErasedMarker)
    1.64 +        {
    1.65 +        aShortName[0] = KLeadingE5Replacement;
    1.66 +        }
    1.67 +    }
    1.68 +
    1.69 +LOCAL_C void ReplaceIllegalCharactersL(TDes& aLongName, TUint aCharacterToReplaceWith)
    1.70 +    {
    1.71 +    TBool alreadyFoundExtensionDelimiter=EFalse;
    1.72 +
    1.73 +    TInt LongNameLen = aLongName.Length();
    1.74 +    TInt extDelimiterIndex = aLongName.LocateReverse(KExtDelimiter);
    1.75 +
    1.76 +    for (TInt i=LongNameLen-1; i>=0; --i) // iterate backwards as aLongName may change length during the loop, and also because we want to leave the *right-most* occurrence of KExtDelimiter unchanged
    1.77 +        {
    1.78 +        TUint character=aLongName[i];
    1.79 +        if (character==(TUint)KExtDelimiter)
    1.80 +            {
    1.81 +            if (alreadyFoundExtensionDelimiter)
    1.82 +                {
    1.83 +                aLongName[i]=(TText)aCharacterToReplaceWith; // A.B.C becomes A_B.C
    1.84 +                }
    1.85 +            alreadyFoundExtensionDelimiter=ETrue;
    1.86 +            }
    1.87 +        else
    1.88 +            {
    1.89 +            // the code below doesn't need any #if defined(_UNICODE) stuff as a narrow-build aLongName would not contain values above 0xff (which is well below the surrogates area in Unicode 0xd800-0xdfff)
    1.90 +            TBool isSurrogatePair=EFalse;
    1.91 +
    1.92 +            // LAST character in file name or file ext CAN NOT be HIGH surrogate
    1.93 +            if (i==LongNameLen-1 || i==extDelimiterIndex-1)
    1.94 +                {
    1.95 +                if (IsHighSurrogate((TText16)character))
    1.96 +                    {
    1.97 +                    // Corrupt surrogate
    1.98 +                    User::Leave(KErrBadName);
    1.99 +                    }
   1.100 +                }
   1.101 +            // FIRST character in file name or file ext CAN NOT be LOW surrogate
   1.102 +            if (i==0 || i==extDelimiterIndex+1)
   1.103 +                {
   1.104 +                if (IsLowSurrogate((TText16)character))
   1.105 +                    {
   1.106 +                    // Corrupt surrogate
   1.107 +                    User::Leave(KErrBadName);
   1.108 +                    }
   1.109 +                }
   1.110 +            // if LOW Surrogate
   1.111 +            if (IsLowSurrogate((TText16)character))
   1.112 +                {
   1.113 +                // check for HIGH surrogate
   1.114 +                if (!IsHighSurrogate(aLongName[--i]))
   1.115 +                    {
   1.116 +                    // Corrupt surrogate
   1.117 +                    User::Leave(KErrBadName);
   1.118 +                    }
   1.119 +                // surrogate pair found
   1.120 +                character&=~0xdc00;
   1.121 +                character|=((aLongName[i]&~0xd800)<<10);
   1.122 +                character+=0x00010000; // this must be added - it cannot be bitwise-"or"-ed
   1.123 +                isSurrogatePair=ETrue;
   1.124 +                }
   1.125 +
   1.126 +            // if High Surrogate
   1.127 +            if (!isSurrogatePair && IsHighSurrogate((TText16)character))
   1.128 +                {
   1.129 +                // Corrupt surrogate
   1.130 +                User::Leave(KErrBadName);
   1.131 +                }
   1.132 +
   1.133 +            if (!IsLegalChar(character, EFalse))
   1.134 +                {
   1.135 +                if (isSurrogatePair)
   1.136 +                    {
   1.137 +                    aLongName.Delete(i+1, 1);
   1.138 +                    }
   1.139 +                aLongName[i]=(TText)aCharacterToReplaceWith;
   1.140 +                }
   1.141 +            }
   1.142 +        }
   1.143 +    }
   1.144 +
   1.145 +TShortName DoGenerateShortNameL(const TDesC& aLongName,TInt& aNum,TBool aUseTildeSelectively)
   1.146 +//
   1.147 +// Create a legal shortname from aLongName
   1.148 +//
   1.149 +    {
   1.150 +
   1.151 +    TFileName longName(aLongName);
   1.152 +    longName.UpperCase();
   1.153 +    ReplaceIllegalCharactersL(longName, '_');
   1.154 +    TPtrC longNameWithoutExtension(longName);
   1.155 +    TPtrC longNameExtension(KNullDesC);
   1.156 +    const TInt positionOfExtension=longName.LocateReverse(KExtDelimiter);
   1.157 +    if (positionOfExtension==0)
   1.158 +        {
   1.159 +        // No filename specified, so use the extension as the basis of the shortname.
   1.160 +        // Make sure we always append a tilde+number in this case to avoid generating the same 
   1.161 +        // short filename as one of the protected folders ("\SYS", "\RESOURCE","\PRIVATE")
   1.162 +        longNameWithoutExtension.Set(longName.Mid(positionOfExtension+1));
   1.163 +        aUseTildeSelectively = EFalse;
   1.164 +        if (aNum < 0)
   1.165 +            aNum = 1;
   1.166 +        }
   1.167 +    else if (positionOfExtension!=KErrNotFound)
   1.168 +        {
   1.169 +        longNameWithoutExtension.Set(longName.Left(positionOfExtension));
   1.170 +        longNameExtension.Set(longName.Mid(positionOfExtension+1));
   1.171 +        }
   1.172 +    
   1.173 +    // Converts the original file name main part into 8-bit character string
   1.174 +    TShortName tempShortName(0);
   1.175 +
   1.176 +    LocaleUtils::ConvertFromUnicodeL(tempShortName, longNameWithoutExtension);
   1.177 +    const TInt originalNameLength = tempShortName.Length();
   1.178 +
   1.179 +    // Converts the original file name extension part into 8-bit character string
   1.180 +    TShortName tempShortNameExt(0);
   1.181 +    
   1.182 +    LocaleUtils::ConvertFromUnicodeL(tempShortNameExt, longNameExtension);
   1.183 +    const TInt extensionNameLength = tempShortNameExt.Length();
   1.184 +    // // const TInt extensionNameLength = tempShortNameExt.Length();
   1.185 +
   1.186 +    // Checks the length of both original file name main part and original file name extension part
   1.187 +    if(aUseTildeSelectively)
   1.188 +        {
   1.189 +        // don't append ~<aNum>
   1.190 +        if(originalNameLength<=KMaxLengthWithoutTilde && extensionNameLength<=KMaxFatFileNameExt)
   1.191 +            aNum=-1;
   1.192 +        }
   1.193 +
   1.194 +    // Applies tilde and number if necessary
   1.195 +    TBuf8<5> tildeAndNumber;
   1.196 +    if (aNum>=0)
   1.197 +        {
   1.198 +        tildeAndNumber.Append('~');
   1.199 +        tildeAndNumber.AppendNumUC(aNum,EHex);
   1.200 +        }
   1.201 +    const TInt lengthOfTildeAndNumber=tildeAndNumber.Length();
   1.202 +
   1.203 +    // Creates actual shortname from longname of the original file
   1.204 +    TShortName shortName(11);
   1.205 +#if defined(_DEBUG)
   1.206 +    shortName.Fill(0x01); // fill shortName with garbage to ensure that every byte is written to by this function
   1.207 +#endif
   1.208 +
   1.209 +    // Fills the main part of the shortname of the original file
   1.210 +    const TInt numberOfBytesFreeBeforeTilde=KMaxFatFileNameWithoutExt-lengthOfTildeAndNumber;
   1.211 +
   1.212 +    TPtr8 portionOfShortNameBeforeTilde((TUint8*)shortName.Ptr(), 0, numberOfBytesFreeBeforeTilde);
   1.213 +    TInt lengthOfPortionOfShortNameBeforeTilde = 
   1.214 +                (originalNameLength < numberOfBytesFreeBeforeTilde) ? originalNameLength : numberOfBytesFreeBeforeTilde;
   1.215 +
   1.216 +    portionOfShortNameBeforeTilde.Copy((TUint8*)tempShortName.Ptr(), lengthOfPortionOfShortNameBeforeTilde);
   1.217 +    if( lengthOfPortionOfShortNameBeforeTilde != originalNameLength)
   1.218 +        {
   1.219 +        for( int i = 0; i<lengthOfPortionOfShortNameBeforeTilde; i++)
   1.220 +            {
   1.221 +            if(portionOfShortNameBeforeTilde[i] >= 0x80) //leading byte found
   1.222 +                {
   1.223 +                if( i == lengthOfPortionOfShortNameBeforeTilde - 1) //leading byte found on the edge
   1.224 +                    {
   1.225 +                    lengthOfPortionOfShortNameBeforeTilde -= 1;
   1.226 +                    break;
   1.227 +                    }
   1.228 +                else
   1.229 +                    {
   1.230 +                    i++;
   1.231 +                    }
   1.232 +                }
   1.233 +            }
   1.234 +        }
   1.235 +    Mem::Copy(((TUint8*)shortName.Ptr())+lengthOfPortionOfShortNameBeforeTilde, tildeAndNumber.Ptr(), lengthOfTildeAndNumber);
   1.236 +    TInt i;
   1.237 +    for (i=lengthOfPortionOfShortNameBeforeTilde+lengthOfTildeAndNumber; i<KMaxFatFileNameWithoutExt; ++i)
   1.238 +        {
   1.239 +        shortName[i]=' ';
   1.240 +        }
   1.241 +
   1.242 +    // Fills the extension part of the shortname of the original file
   1.243 +    TInt lengthOfExt = 
   1.244 +                (extensionNameLength < KMaxFatFileNameExt) ? extensionNameLength : KMaxFatFileNameExt;
   1.245 +    
   1.246 +    if( lengthOfExt != extensionNameLength)
   1.247 +        {
   1.248 +        for( int i = 0; i<lengthOfExt; i++)
   1.249 +            {
   1.250 +            if(tempShortNameExt[i] >= 0x80)
   1.251 +                {
   1.252 +                if( i == lengthOfExt - 1)
   1.253 +                    {
   1.254 +                    lengthOfExt -= 1;
   1.255 +                    break;
   1.256 +                    }
   1.257 +                else
   1.258 +                    {
   1.259 +                    i++;
   1.260 +                    }
   1.261 +                }
   1.262 +            }
   1.263 +        }           
   1.264 +    Mem::Copy(((TUint8*)shortName.Ptr()) + KMaxFatFileNameWithoutExt, tempShortNameExt.Ptr(), lengthOfExt);
   1.265 +    for (i = KMaxFatFileNameWithoutExt + lengthOfExt; i<KMaxFatFileNameWithoutExt+KMaxFatFileNameExt; ++i)
   1.266 +        {
   1.267 +        shortName[i]=' ';
   1.268 +        }
   1.269 +    
   1.270 +    ReplaceFirstCharacterIfClashesWithE5L(shortName);       
   1.271 +    return shortName;
   1.272 +    }
   1.273 +
   1.274 +
   1.275 +/**
   1.276 +Check whether a Dos name is legal or not.
   1.277 +
   1.278 +@param aName                The entry name to be analysed (may be represented as TDes16& or TDes8&)
   1.279 +@param anAllowWildCards     Flag to indicate whether to allow wildcards in name or not
   1.280 +@param aUseExtendedChars    Flag to indicate if extended characters are allowed
   1.281 +@param aInScanDrive         Flag to indicate whether called when scanning drive
   1.282 +@param aAllowLowerCase      ETrue to allow lower case in the analysed DOS name
   1.283 +
   1.284 +@return ETrue if the name is a legal DOS one.
   1.285 +*/
   1.286 +
   1.287 +static TBool DoCheckLegalDosName(const TDesC& aName, TBool anAllowWildCards, TBool aUseExtendedChars, TBool aInScanDrive, TBool aAllowLowerCase, TBool aIsForFileCreation)
   1.288 +    {
   1.289 +    const TInt count=aName.Length();
   1.290 +    if (count==0)
   1.291 +        return EFalse;
   1.292 +
   1.293 +    TInt valid=0;
   1.294 +    TInt i=0;
   1.295 +    
   1.296 +    //-- check the entry name
   1.297 +    while (i<count)
   1.298 +        {
   1.299 +        TChar c=aName[i++];
   1.300 +        if (c==KExtDelimiter)
   1.301 +            {
   1.302 +            // DOS entry names must contain at least one valid character before the extension
   1.303 +            if (i == 1)
   1.304 +                return EFalse;
   1.305 +            break;
   1.306 +            }
   1.307 +        
   1.308 +          if(!aAllowLowerCase && c.IsLower())
   1.309 +            return EFalse; //-- low case is not allowed
   1.310 +
   1.311 +        if (!IsLegalChar(c,anAllowWildCards,aUseExtendedChars,aInScanDrive))
   1.312 +            {
   1.313 +            return EFalse;
   1.314 +            }
   1.315 +        
   1.316 +        if (aIsForFileCreation)
   1.317 +            {
   1.318 +            if ((aUseExtendedChars && (TUint) c > KExtendedCharEnd) || 
   1.319 +                    (!aUseExtendedChars && (TUint) c > KExtendedCharStart))
   1.320 +                {
   1.321 +                return EFalse;
   1.322 +                }
   1.323 +            }
   1.324 +
   1.325 +        if (c!=KMatchAny)
   1.326 +            if (++valid>KMaxFatFileNameWithoutExt)
   1.327 +                return EFalse;
   1.328 +        }
   1.329 +    
   1.330 +    //-- check entry extension
   1.331 +    valid=0;
   1.332 +    while (i<count)
   1.333 +        {
   1.334 +        TChar c=aName[i++];
   1.335 +        if (c==KExtDelimiter)
   1.336 +            return EFalse;
   1.337 +        
   1.338 +        if(!aAllowLowerCase && c.IsLower())
   1.339 +            return EFalse; //-- low case is not allowed
   1.340 +
   1.341 +        if (!IsLegalChar(c,anAllowWildCards,aUseExtendedChars,aInScanDrive))
   1.342 +            return EFalse;
   1.343 +        
   1.344 +        if (aIsForFileCreation)
   1.345 +            {
   1.346 +            if ((aUseExtendedChars && (TUint) c > KExtendedCharEnd) || 
   1.347 +                    (!aUseExtendedChars && (TUint) c > KExtendedCharStart))
   1.348 +                {
   1.349 +                return EFalse;
   1.350 +                }
   1.351 +            }
   1.352 +
   1.353 +        if (c!=KMatchAny)
   1.354 +            if (++valid>KMaxFatFileNameExt)
   1.355 +                return EFalse;
   1.356 +        }
   1.357 +    
   1.358 +    // Unicode file name checking for file opening.
   1.359 +    if (!aIsForFileCreation && GetFatUtilityFunctions())
   1.360 +        {
   1.361 +        TBuf8<KMaxFileName*2> convertedName8;
   1.362 +        TRAPD(err, LocaleUtils::ConvertFromUnicodeL(convertedName8, aName, TFatUtilityFunctions::EOverflowActionLeave));
   1.363 +        if (err != KErrNone)
   1.364 +            return EFalse;
   1.365 +        
   1.366 +        const TInt len8 = convertedName8.Length();
   1.367 +        TInt j = 0; 
   1.368 +        TInt nonWildChar = 0;
   1.369 +        while (j < len8)
   1.370 +            {
   1.371 +            const TUint8 c8 = convertedName8[j++];
   1.372 +            if (c8 == KExtDelimiter)
   1.373 +                break;
   1.374 +            if (c8 == '*' && !anAllowWildCards)
   1.375 +                return EFalse;
   1.376 +            if (c8 == '*' && anAllowWildCards)
   1.377 +                continue;
   1.378 +            
   1.379 +            if (++nonWildChar > KMaxFatFileNameWithoutExt)
   1.380 +                return EFalse;
   1.381 +            }
   1.382 +        
   1.383 +        // check extension part
   1.384 +        nonWildChar = 0;
   1.385 +        while (j < len8)
   1.386 +            {
   1.387 +            const TUint8 c8 = convertedName8[j++];
   1.388 +            if (c8 == KExtDelimiter)
   1.389 +                return EFalse;
   1.390 +            if (c8 == '*' && !anAllowWildCards)
   1.391 +                return EFalse;
   1.392 +            if (c8 == '*' && anAllowWildCards)
   1.393 +                continue;
   1.394 +            
   1.395 +            if (++nonWildChar > KMaxFatFileNameExt)
   1.396 +                return EFalse;
   1.397 +            }
   1.398 +        }
   1.399 +
   1.400 +    return ETrue;
   1.401 +    }
   1.402 +
   1.403 +/**
   1.404 +    Check whether a Dos name is legal or not. Unicode version
   1.405 +    parameters and return value absolutely the same as in DoCheckLegalDosName()
   1.406 +*/
   1.407 +TBool IsLegalDosName(const TDesC16& aName, TBool anAllowWildCards, TBool aUseExtendedChars, TBool aInScanDrive, TBool aAllowLowerCase, TBool aIsForFileCreation)
   1.408 +    {
   1.409 +
   1.410 +    __PRINT(_L("IsLegalDosName 16"));
   1.411 +
   1.412 +    return DoCheckLegalDosName(aName, anAllowWildCards, aUseExtendedChars, aInScanDrive, aAllowLowerCase, aIsForFileCreation);  
   1.413 +    }
   1.414 +
   1.415 +TBool CFatMountCB::FindShortNameL(const TShortName& aName,TEntryPos& anEntryPos)
   1.416 +//
   1.417 +// Returns ETrue and the entryPos of aName if found or EFalse
   1.418 +//
   1.419 +    {
   1.420 +    
   1.421 +    __PRINT(_L("VFAT::CFatMountCB::FindShortNameL"));   
   1.422 +    TFatDirEntry fatEntry;
   1.423 +    TInt count=0;
   1.424 +    FOREVER
   1.425 +        {
   1.426 +        count++;
   1.427 +        ReadDirEntryL(anEntryPos,fatEntry);
   1.428 +        MoveToDosEntryL(anEntryPos,fatEntry);
   1.429 +        if (fatEntry.IsEndOfDirectory())
   1.430 +            break;
   1.431 +        if (IsRootDir(anEntryPos)&&(anEntryPos.iPos+StartOfRootDirInBytes()==(RootDirEnd()-KSizeOfFatDirEntry)))    
   1.432 +            if (fatEntry.IsErased())
   1.433 +                break;//Allows maximum number of entries in root directory
   1.434 +        if (fatEntry.Name()==aName)
   1.435 +            return ETrue;
   1.436 +        MoveToNextEntryL(anEntryPos);
   1.437 +        if (IsRootDir(anEntryPos)&&(StartOfRootDirInBytes()+anEntryPos.iPos==RootDirEnd()))
   1.438 +            break;//Allows maximum number of entries in root directory
   1.439 +        }
   1.440 +    return EFalse;
   1.441 +    }
   1.442 +    
   1.443 +TBool CFatMountCB::IsUniqueNameL(const TShortName& aName,TInt aDirCluster)
   1.444 +//
   1.445 +// Returns ETrue if aName is unique, EFalse if a matching name is found.
   1.446 +//
   1.447 +    {
   1.448 +
   1.449 +    __PRINT(_L("VFAT::CFatMountCB::IsUniqueNameL"));    
   1.450 +    TEntryPos entryPos(aDirCluster,0);
   1.451 +    if (FindShortNameL(aName,entryPos))
   1.452 +        return(EFalse);
   1.453 +    return(ETrue);
   1.454 +    }
   1.455 +
   1.456 +void CFatMountCB::ReplaceClashingNameL(const TShortName& aNewName,const TEntryPos& anEntryPos)
   1.457 +//
   1.458 +// A legal dos name has been typed that clashes with a computer generated shortname
   1.459 +// Change the shortname to something else.
   1.460 +//
   1.461 +    {
   1.462 +
   1.463 +    __PRINT(_L("VFAT::CFatMountCB::ReplaceClashingNameL")); 
   1.464 +    TFatDirEntry entry;
   1.465 +    ReadDirEntryL(anEntryPos,entry);
   1.466 +    __ASSERT_ALWAYS(entry.IsEndOfDirectory()==EFalse,User::Leave(KErrCorrupt));
   1.467 +    entry.SetName(aNewName);
   1.468 +    WriteDirEntryL(anEntryPos,entry);
   1.469 +//  We now need to fix up VFAT entries with a new checksum reflecting new shortname
   1.470 +//  Calculate new checksum
   1.471 +    TUint8 checksum=CalculateShortNameCheckSum(aNewName);
   1.472 +//  Now go back and adjust all VFAT entries corresponding to this shortname
   1.473 +    TEntryPos entryPos=anEntryPos;
   1.474 +    FOREVER
   1.475 +        {
   1.476 +        entryPos.iPos-=KSizeOfFatDirEntry;  
   1.477 +        ReadDirEntryL(entryPos,entry);
   1.478 +        entry.iData[0x0D]=checksum;
   1.479 +        if (entry.iData[0]&0x40)
   1.480 +            break;
   1.481 +        }
   1.482 +    }
   1.483 +
   1.484 +TBool CFatMountCB::GenerateShortNameL(TInt aDirCluster,const TDesC& aName,TShortName& aGeneratedName, TBool aForceRandomize)
   1.485 +//
   1.486 +// Generate a legal dos filename as an alias for aName.
   1.487 +// Returns ETrue if aName is a legal dos name.
   1.488 +//
   1.489 +    {
   1.490 +
   1.491 +    __PRINT(_L("VFAT::CFatMountCB::GenerateShortNameL"));
   1.492 +    // Given the long file-name "ABCDEFGHI.TXT", EPOC used to generate short 
   1.493 +    // file-names in the following pecking order:
   1.494 +    //     "ABCDEFGH.TXT",
   1.495 +    //     "ABCDEF~0.TXT",
   1.496 +    //     "ABCDEF~1.TXT",
   1.497 +    //     "ABCDEF~2.TXT",
   1.498 +    //     etc.
   1.499 +    // Now, however, EPOC behaves in a more Windows-like manner and 
   1.500 +    // generates short file-names in this pecking order:
   1.501 +    //     "ABCDEF~1.TXT",
   1.502 +    //     "ABCDEF~2.TXT",
   1.503 +    //     "ABCDEF~3.TXT",
   1.504 +    //     "ABCDEF~4.TXT",
   1.505 +    // After failing to find an unused short name 4 times in a row, 
   1.506 +    // a random number is used to speed up the process. So subsequent
   1.507 +    // short-file names become
   1.508 +    //     "ABC~nnnn.TXT"   where nnnn is a random number
   1.509 +    //    
   1.510 +    TBool useTildeSelectively = ETrue;
   1.511 +    TInt endNum = KMaxDuplicateShortName;   //  0xFFFF
   1.512 +    const TInt KMaxNonRandomShortFileNames = 4;
   1.513 +
   1.514 +    TInt i = 1;
   1.515 +
   1.516 +    TBool randomize = aForceRandomize;
   1.517 +    if (randomize)
   1.518 +        {
   1.519 +        i = (TInt) (Math::Random() & KMaxDuplicateShortName);
   1.520 +        endNum = (i - 1) & KMaxDuplicateShortName;
   1.521 +        }
   1.522 +
   1.523 +    while(i != endNum)
   1.524 +        {
   1.525 +        aGeneratedName=DoGenerateShortNameL(aName,i,useTildeSelectively);
   1.526 +
   1.527 +        if (IsUniqueNameL(aGeneratedName,aDirCluster))
   1.528 +            break;
   1.529 +
   1.530 +        if (i == KMaxNonRandomShortFileNames && !randomize)
   1.531 +            {
   1.532 +            randomize = ETrue;
   1.533 +            i = (TInt) (Math::Random() & KMaxDuplicateShortName);
   1.534 +            endNum = (i - 1) & KMaxDuplicateShortName;
   1.535 +            }
   1.536 +        else if (i == -1)
   1.537 +            {
   1.538 +            useTildeSelectively=EFalse;
   1.539 +            i = 1;
   1.540 +            }
   1.541 +        else
   1.542 +            i = (i + 1) & KMaxDuplicateShortName;
   1.543 +        }
   1.544 +
   1.545 +    if (i == endNum)
   1.546 +        User::Leave(KErrAlreadyExists);
   1.547 +
   1.548 +    if((i == -1) && IsLegalDosName(aName,EFalse,EFalse,EFalse,EFalse,ETrue))
   1.549 +        {
   1.550 +        // Original file name is a legal 8.3 name
   1.551 +        return(ETrue);
   1.552 +        }
   1.553 +    else
   1.554 +        {
   1.555 +        return(EFalse);
   1.556 +        }
   1.557 +
   1.558 +
   1.559 +    }
   1.560 +
   1.561 +void TFatDirEntry::InitializeAsVFat(TUint8 aCheckSum)
   1.562 +//
   1.563 +// Initialize a FAT entry as a VFAT filename
   1.564 +//
   1.565 +    {
   1.566 +
   1.567 +    Mem::Fill(this,sizeof(SFatDirEntry),0xFF);
   1.568 +    iData[0x0B]=0x0F;
   1.569 +    iData[0x0C]=0x00; iData[0x0D]=aCheckSum;
   1.570 +    iData[0x1A]=0x00; iData[0x1B]=0x00;
   1.571 +    }
   1.572 +
   1.573 +void TFatDirEntry::SetVFatEntry(const TDesC& aName,TInt aLen)
   1.574 +//
   1.575 +// Write up to KMaxVFatEntryName unicode chars from aName to the entry
   1.576 +//
   1.577 +    {
   1.578 +
   1.579 +    TInt rem=aName.Length()-aLen;
   1.580 +    TPtrC section(aName.Ptr()+aLen,Min(rem,KMaxVFatEntryName));
   1.581 +    TBuf16<KMaxVFatEntryName> buf16;
   1.582 +    buf16.Copy(section);
   1.583 +    if (rem<KMaxVFatEntryName)
   1.584 +        {
   1.585 +        rem++;
   1.586 +        buf16.ZeroTerminate();
   1.587 +        buf16.SetLength(rem); // Zero termination doesn't increase the buf length
   1.588 +        }
   1.589 +    TUint8 orderNo=(TUint8)(aLen/KMaxVFatEntryName+1);
   1.590 +    TInt s=Min(rem,5);
   1.591 +    Mem::Copy(&iData[0x01],buf16.Ptr(),s*2);//Copy up to 10 bytes of buf16 into iData
   1.592 +    TInt offset=s;
   1.593 +    rem-=s;
   1.594 +    s=Min(rem,6);
   1.595 +    Mem::Copy(&iData[0x0E],buf16.Ptr()+offset,s*2);
   1.596 +    offset+=s;
   1.597 +    rem-=s;
   1.598 +    s=Min(rem,2);
   1.599 +    Mem::Copy(&iData[0x1C],buf16.Ptr()+offset,s*2);
   1.600 +    rem-=s;
   1.601 +    if (rem==0)
   1.602 +        orderNo|=0x40;
   1.603 +    iData[0]=orderNo;
   1.604 +    }
   1.605 +
   1.606 +void TFatDirEntry::ReadVFatEntry(TDes16& aBuf) const
   1.607 +//
   1.608 +// Read KMaxVFatEntryName unicode chars from the entry
   1.609 +//
   1.610 +    {
   1.611 +
   1.612 +    aBuf.SetLength(KMaxVFatEntryName);
   1.613 +    Mem::Copy(&aBuf[0],&iData[0x01],5*2);
   1.614 +    Mem::Copy(&aBuf[5],&iData[0x0E],6*2);
   1.615 +    Mem::Copy(&aBuf[11],&iData[0x1C],2*2);
   1.616 +    }
   1.617 +
   1.618 +void CFatMountCB::WriteDirEntryL(TEntryPos& aPos,const TFatDirEntry& aFatDirEntry,const TDesC& aLongName)
   1.619 +//
   1.620 +// Write a VFAT directory entry to disk at position aPos - leave aPos refering to the dos entry
   1.621 +// Assumes sufficient space has been created for it by AddDirEntry.
   1.622 +//
   1.623 +    {
   1.624 +
   1.625 +    __PRINT(_L("VFAT::CFatMountCB::WriteDirEntryL"));   
   1.626 +    __ASSERT_DEBUG(aLongName.Length(),Fault(EVFatNoLongName));
   1.627 +    TEntryPos startPos(aPos.iCluster,aPos.iPos);
   1.628 +    TUint8  localBuf[KDefaultSectorSize];
   1.629 +    TUint8 cksum=CalculateShortNameCheckSum(aFatDirEntry.Name());
   1.630 +    TInt numEntries=NumberOfVFatEntries(aLongName.Length())-1; // Excluding dos entry
   1.631 +    // see if all entries written to one sector
   1.632 +    // single sector writes not supported if sector size>default size 
   1.633 +    TInt dosOffset=numEntries<<KSizeOfFatDirEntryLog2;
   1.634 +    TInt absolutePos=(aPos.iCluster<<ClusterSizeLog2())+ClusterRelativePos(aPos.iPos);
   1.635 +    TBool isSameSector=(((absolutePos^(absolutePos+dosOffset))>>SectorSizeLog2())==0 && ((TUint)(1<<SectorSizeLog2())<=KDefaultSectorSize));
   1.636 +    TFatDirEntry vFatEntry;
   1.637 +    vFatEntry.InitializeAsVFat(cksum);
   1.638 +    TInt offset=0;
   1.639 +    while (numEntries--)
   1.640 +        {
   1.641 +        vFatEntry.SetVFatEntry(aLongName,KMaxVFatEntryName*numEntries);//   KMaxVFatEntryName=13
   1.642 +        if(isSameSector)
   1.643 +            {
   1.644 +            Mem::Copy(&localBuf[offset],&vFatEntry,KSizeOfFatDirEntry);
   1.645 +            offset+=KSizeOfFatDirEntry;
   1.646 +            MoveToNextEntryL(aPos);
   1.647 +            }
   1.648 +        else
   1.649 +            {
   1.650 +            WriteDirEntryL(aPos,vFatEntry);
   1.651 +            MoveToNextEntryL(aPos);
   1.652 +            }
   1.653 +        }
   1.654 +    if(isSameSector)
   1.655 +        {
   1.656 +        Mem::Copy(&localBuf[offset],&aFatDirEntry,KSizeOfFatDirEntry);
   1.657 +        
   1.658 +        //-- use special interface to access FAT directory file
   1.659 +        DirWriteL(startPos,TPtrC8(&localBuf[0],dosOffset+KSizeOfFatDirEntry));
   1.660 +        }
   1.661 +    else
   1.662 +        WriteDirEntryL(aPos,aFatDirEntry);
   1.663 +    }
   1.664 +
   1.665 +void CFatMountCB::EraseDirEntryL(TEntryPos aPos,const TFatDirEntry& aFirstEntry)
   1.666 +//
   1.667 +// Mark all entries in a VFat directory entry as erased
   1.668 +//
   1.669 +    {
   1.670 +    __PRINT(_L("VFAT::CFatMountCB::EraseDirEntryL"));
   1.671 +    TInt numEntries=0;
   1.672 +    if (aFirstEntry.IsVFatEntry())
   1.673 +        numEntries=aFirstEntry.NumFollowing();
   1.674 +    if(IsRuggedFSys()&&numEntries)
   1.675 +        {
   1.676 +        TInt count=numEntries;
   1.677 +        TEntryPos pos=aPos;
   1.678 +        while(count--)
   1.679 +            MoveToNextEntryL(pos);
   1.680 +        EraseDirEntryL(pos);
   1.681 +        numEntries--;
   1.682 +        }
   1.683 +    FOREVER
   1.684 +        {
   1.685 +        EraseDirEntryL(aPos);
   1.686 +        if (!numEntries--)
   1.687 +            break;
   1.688 +        MoveToNextEntryL(aPos);
   1.689 +        }
   1.690 +    }
   1.691 +
   1.692 +
   1.693 +void  LocaleUtils::ConvertFromUnicodeL(TDes8& aForeign, const TDesC16& aUnicode, TFatUtilityFunctions::TOverflowAction aOverflowAction)
   1.694 +//
   1.695 +// Convert the volume label using the algorithm specified in the current locale-DLL.
   1.696 +//
   1.697 +    {
   1.698 +    if(aOverflowAction == TFatUtilityFunctions::EOverflowActionLeave)
   1.699 +        {
   1.700 +        GetCodePage().ConvertFromUnicodeL(aForeign, aUnicode, TCodePageUtils::EOverflowActionLeave);
   1.701 +        }
   1.702 +    else
   1.703 +        {
   1.704 +        GetCodePage().ConvertFromUnicodeL(aForeign, aUnicode, TCodePageUtils::EOverflowActionTruncate);
   1.705 +        }
   1.706 +    }
   1.707 +
   1.708 +void  LocaleUtils::ConvertToUnicodeL(TDes16& aUnicode, const TDesC8& aForeign, TFatUtilityFunctions::TOverflowAction aOverflowAction)
   1.709 +//
   1.710 +// Convert the volume label using the algorithm specified in the current locale-DLL.
   1.711 +//
   1.712 +    {
   1.713 +    if(aOverflowAction == TFatUtilityFunctions::EOverflowActionLeave)
   1.714 +        {
   1.715 +        GetCodePage().ConvertToUnicodeL(aUnicode, aForeign, TCodePageUtils::EOverflowActionLeave);
   1.716 +        }
   1.717 +    else
   1.718 +        {
   1.719 +        GetCodePage().ConvertToUnicodeL(aUnicode, aForeign, TCodePageUtils::EOverflowActionTruncate);
   1.720 +        }
   1.721 +    }
   1.722 +
   1.723 +TBool LocaleUtils::IsLegalShortNameCharacter(TUint aCharacter,TBool aUseExtendedChars)
   1.724 +//
   1.725 +// Convert the volume label using the algorithm specified in the current locale-DLL.
   1.726 +//
   1.727 +    {
   1.728 +    return GetCodePage().IsLegalShortNameCharacter(aCharacter, aUseExtendedChars);
   1.729 +    }