imgtools/romtools/rofsbuild/fsnode.cpp
changeset 605 122d2b873fd1
child 617 3a747a240983
equal deleted inserted replaced
604:b33dd54aaa52 605:122d2b873fd1
       
     1 /*
       
     2 * Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of the License "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description: 
       
    15 *
       
    16 */
       
    17 #include "fsnode.h"
       
    18 #include "fatdefines.h"
       
    19 #include "utf16string.h"
       
    20 #include <stdio.h> 
       
    21 #include <iostream>
       
    22 #include <iomanip>
       
    23 #include <stdio.h> 
       
    24 #include <stdlib.h> 
       
    25  
       
    26 #include <ctype.h> 
       
    27  
       
    28 
       
    29 #ifdef __LINUX__
       
    30 #include <dirent.h> 
       
    31 #include <sys/stat.h>
       
    32 #include <unistd.h>
       
    33 #define SPLIT_CHAR '/'
       
    34 #else
       
    35 #include <io.h> 
       
    36 #include <direct.h> //TODO: check under MinGW4 + stlport 5.2
       
    37 #include <conio.h> 
       
    38 #define SPLIT_CHAR '\\'
       
    39 #endif
       
    40  
       
    41 using namespace std;
       
    42 
       
    43 const TUint KBytesPerEntry = 13 ;
       
    44 //
       
    45 TFSNode::TFSNode(TFSNode* aParent, const char* aFileName, TUint8 aAttrs, const char* aPCSideName)  :
       
    46 iParent(aParent),iFirstChild(0),iSibling(0),iAttrs(aAttrs), iPCSideName(0), iWideName(0){
       
    47 	
       
    48   // According to the FAT specification, short name should be inited with empty string (' ' string)
       
    49 	memset(iShortName,0x20,11);  
       
    50 	iShortName[11] = 0 ; 
       
    51 	if(aFileName) {
       
    52 		iFileName = strdup(aFileName);
       
    53 		GenerateBasicName() ;	
       
    54 	} 
       
    55 	if(aPCSideName) {
       
    56 		iPCSideName = strdup(aPCSideName);
       
    57 	}
       
    58 	iFATEntry = 0;
       
    59 	iCrtTimeTenth  = 0;
       
    60 	iCrtTime.iImageTime = 0 ;
       
    61 	iCrtDate.iImageDate = 0 ;
       
    62 	iLstAccDate.iImageDate = 0  ;
       
    63 	iWrtTime.iImageTime = 0 ;
       
    64 	iWrtDate.iImageDate = 0  ;
       
    65 	iFileSize = 0;
       
    66 	if(!iParent) return ;
       
    67 	
       
    68 	if(!iParent->iFirstChild)
       
    69 	    iParent->iFirstChild = this ;
       
    70     else {
       
    71         TFSNode* sibling = iParent->iFirstChild;
       
    72         while(sibling->iSibling)
       
    73             sibling = sibling->iSibling ;
       
    74         sibling->iSibling = this ;
       
    75     } 
       
    76 
       
    77 }
       
    78 TFSNode::~TFSNode(){
       
    79 	if(iFirstChild)
       
    80 		delete iFirstChild ;
       
    81 	if(iSibling)
       
    82 		delete iSibling ;
       
    83 	if(iFileName)
       
    84 		free(iFileName) ;
       
    85 	if(iWideName)
       
    86 		delete iWideName;
       
    87 }
       
    88 TFSNode* TFSNode::CreateFromFolder(const char* aPath,TFSNode* aParent) { 
       
    89 	static char fileName[2048];
       
    90 	int len = strlen(aPath);  
       
    91 #ifdef __LINUX__
       
    92 	DIR* dir = opendir(aPath);
       
    93 	if(dir == NULL) {
       
    94 		cout << aPath << " does not contain any subfolder/file.\n";     
       
    95 			return aParent;
       
    96 	}
       
    97 	if(!aParent)
       
    98 		aParent = new TFSNode(NULL,"/",ATTR_VOLUME_ID);
       
    99 	dirent*  entry; 
       
   100 	struct stat statbuf ;
       
   101 	while ((entry = readdir(dir)) != NULL)  {
       
   102 		if(entry->d_name[0] == '.') continue ; 
       
   103 			memcpy(fileName,aPath,len); 
       
   104 			fileName[len] = SPLIT_CHAR;
       
   105 			strcpy(&fileName[len+1],entry->d_name);             
       
   106 			stat(fileName , &statbuf);         
       
   107 			TFSNode* pNewItem = new TFSNode(aParent,fileName,S_ISDIR(statbuf.st_mode) ? ATTR_DIRECTORY : 0);
       
   108 			pNewItem->Init(statbuf.st_ctime,statbuf.st_atime,statbuf.st_mtime,statbuf.st_size);         
       
   109 			if(S_ISDIR(statbuf.st_mode)){ 
       
   110 				CreateFromFolder(fileName,pNewItem);
       
   111 			}  
       
   112 	}
       
   113 	closedir(dir);
       
   114 #else
       
   115 	struct _finddata_t data ;
       
   116 	memset(&data, 0, sizeof(data)); 	
       
   117 	char* pattern = new char[len + 4] ;
       
   118 	memcpy(pattern,aPath,len);
       
   119 	pattern[len] = SPLIT_CHAR;
       
   120 	pattern[len+1] = '*';
       
   121 	pattern[len+2] = 0;
       
   122 
       
   123 	intptr_t hFind =  _findfirst(pattern,&data);
       
   124 	delete []pattern ;
       
   125  
       
   126 	if(hFind == (intptr_t)-1 ) {
       
   127 		cout << aPath << " does not contain any subfolder/file.\n";		
       
   128 		return aParent;
       
   129 	}
       
   130 	if(!aParent)
       
   131 	    aParent = new TFSNode(NULL,"/",ATTR_VOLUME_ID);
       
   132 	do {        
       
   133         if(data.name[0] == '.') 
       
   134             continue ; 
       
   135         memcpy(fileName,aPath,len); 
       
   136         fileName[len] = SPLIT_CHAR;
       
   137         strcpy(&fileName[len+1],data.name); 
       
   138         TUint8 attr = 0;
       
   139         if(data.attrib & _A_SUBDIR)  
       
   140             attr |= ATTR_DIRECTORY;
       
   141         if(data.attrib & _A_RDONLY)
       
   142             attr |= ATTR_READ_ONLY ;
       
   143         if(data.attrib &  _A_HIDDEN)
       
   144             attr |= ATTR_HIDDEN ;
       
   145         if(data.attrib & _A_SYSTEM)
       
   146             attr |= ATTR_SYSTEM ;
       
   147         if(data.attrib & _A_ARCH)
       
   148             attr |= ATTR_ARCHIVE;      
       
   149         TFSNode* pNewItem = new TFSNode(aParent,fileName,attr);        
       
   150         pNewItem->Init(data.time_create,data.time_access,data.time_write,data.size);            
       
   151         if(data.attrib & _A_SUBDIR){ 
       
   152             CreateFromFolder(fileName,pNewItem);
       
   153         }  
       
   154  
       
   155     } while(-1 != _findnext(hFind, &data));
       
   156     _findclose(hFind);
       
   157 #endif
       
   158  
       
   159 	return aParent;
       
   160 }
       
   161  	
       
   162 
       
   163 
       
   164 static const char* lbasename(const char* aFullName) {
       
   165 	const char* retval = aFullName ;
       
   166 	while(*aFullName) {
       
   167 		if('\\' == *aFullName || '/' == *aFullName )
       
   168 			retval = ++aFullName ;
       
   169 		else
       
   170 			aFullName ++ ;
       
   171 	}
       
   172 	return retval ;
       
   173 }
       
   174 /** GenerateBasicName : Generate the short name according to long name 
       
   175 	* 
       
   176 	* algorithm :
       
   177 	* 
       
   178 	* 1.	The UNICODE name passed to the file system is converted to upper case.
       
   179 	* 2.	The upper cased UNICODE name is converted to OEM.
       
   180 	*     if (the uppercased UNICODE glyph does not exist as an OEM glyph in the OEM code page)
       
   181 	*				or	(the OEM glyph is invalid in an 8.3 name)
       
   182 	*			{
       
   183 	*				Replace the glyph to an OEM '_' (underscore) character.
       
   184 	*				Set a "lossy conversion" flag.
       
   185 	*			}
       
   186 	* 3.	Strip all leading and embedded spaces from the long name.
       
   187 	* 4.	Strip all leading periods from the long name.
       
   188 	* 5.	While		(not at end of the long name)
       
   189 	*					and	(char is not a period)
       
   190 	*					and	(total chars copied < 8)
       
   191 	*			{
       
   192 	*				Copy characters into primary portion of the basis name
       
   193 	*			}
       
   194 	*	6.	Insert a dot at the end of the primary components of the basis-name 
       
   195 	*     if the basis name has an extension after the last period in the name.
       
   196 	*
       
   197 	* 7.	Scan for the last embedded period in the long name.
       
   198 	*     If	(the last embedded period was found)
       
   199 	*     {
       
   200 	*     	While		(not at end of the long name) and	(total chars copied < 3)
       
   201 	*     	{
       
   202 	*     		Copy characters into extension portion of the basis name
       
   203 	*     	}
       
   204 	*     }
       
   205   *
       
   206   */
       
   207 void TFSNode::GenerateBasicName() { 
       
   208 	const char* filename = lbasename(iFileName);	 
       
   209 	TUint length = strlen(filename);
       
   210 	if(0 == length)
       
   211 	    return ;
       
   212 	if(0 == strcmp(filename,".")){
       
   213         iShortName[0] = '.' ;
       
   214         return ;
       
   215 	}
       
   216 	if(0 == strcmp(filename,"..")){
       
   217         iShortName[0] = '.' ;
       
   218         iShortName[1] = '.' ;
       
   219         return ;
       
   220 	}	
       
   221 #ifdef _DEBUG
       
   222 		cout << "GenericBasicName: \"" << filename ;
       
   223 #endif	
       
   224 	iWideName = new UTF16String(filename,length); // The unicode string
       
   225 	char base[10];
       
   226 	const char* ext = filename + length;
       
   227 	
       
   228 	//Strip all leading periods and spaces from the long name.
       
   229 	while(*filename == '.' || *filename == ' ' || *filename == '\t') {
       
   230 		filename ++ ;
       
   231 		length -- ;
       
   232 	}
       
   233 	//find the extension
       
   234 	while(ext > filename && *ext != '.')
       
   235 		ext -- ;
       
   236 	if(ext == filename){
       
   237 		ext = "" ; 
       
   238 	}
       
   239 	else {
       
   240 		length = ext - filename;
       
   241 		ext ++ ;
       
   242 	} 
       
   243 	bool lossyConv = false ;
       
   244 	TUint bl = 0;
       
   245 	for(TUint i = 0 ; i < length ; i++) {
       
   246 		if(filename[i] >= 'a' && filename[i] <= 'z')
       
   247 			base[bl++] = filename[i] + 'A' - 'a';
       
   248 		else if(filename[i] >= 'A' && filename[i] <= 'Z')
       
   249 			base[bl++] = filename[i];
       
   250 		else if(filename[i] == '$' || filename[i] == '%' ||
       
   251 			filename[i] == '-' || filename[i] == '_' || filename[i] == '@' ||
       
   252 			filename[i] == '~' || filename[i] == '`' || filename[i] == '!' ||
       
   253 			filename[i] == '(' || filename[i] == ')' || filename[i] == '{' ||
       
   254 			filename[i] == '}' || filename[i] == '^' || filename[i] == '#' ||
       
   255 			filename[i] == '&' ||filename[i] == '\'')
       
   256 			base[bl++] = filename[i];
       
   257 		else if(filename[i] != ' ' && filename[i] != '.'){
       
   258 			base[bl++] = '_';
       
   259 			lossyConv = true ;
       
   260 		}
       
   261 		if(bl > 8){
       
   262 			bl -- ;
       
   263 			lossyConv = true ;
       
   264 			break ;
       
   265 		}		
       
   266 	}
       
   267 	if(lossyConv){
       
   268 		if(bl > 6) bl = 6 ;		
       
   269 		iShortName[bl] = '~';
       
   270 		iShortName[bl+1] = '1';		
       
   271 	}
       
   272 	memcpy(iShortName,base,bl);
       
   273 
       
   274 	//Copy the extension part.	
       
   275 	TUint ei = 8;
       
   276 	for(TUint e = 0; ei < 11 && ext[e] != 0 ; e++){
       
   277 		if(ext[e] >= 'a' && ext[e] <= 'z')
       
   278 			iShortName[ei++] = ext[e] + 'A' - 'a';
       
   279 		else if(ext[e] >= 'A' && ext[e] <= 'Z')
       
   280 			iShortName[ei++] = ext[e] ;
       
   281 		else if(ext[e] == '$' || ext[e] == '%' || ext[e] == '-' || ext[e] == '_' || 
       
   282 			ext[e] == '@' || ext[e] == '~' || ext[e] == '`' || ext[e] == '!' || 
       
   283 			ext[e] == '(' || ext[e] == ')' || ext[e] == '{' || ext[e] == '}' || 
       
   284 			ext[e] == '^' || ext[e] == '#' || ext[e] == '&' ||ext[e] == '\'')
       
   285 			iShortName[ei++] = ext[e] ;
       
   286 	}
       
   287  
       
   288 	if(iParent) 
       
   289 		iParent->MakeUniqueShortName(iShortName,bl);
       
   290 #ifdef _DEBUG
       
   291 		cout << "\" => \"" << iShortName << "\"\n";
       
   292 #endif	
       
   293 }
       
   294 
       
   295 #ifdef _DEBUG
       
   296 void TFSNode::PrintTree(int nTab) {
       
   297 	for( int i = 0 ; i < nTab ; i++ )
       
   298 		cout << " " ;
       
   299 	cout << (iFileName ? iFileName : "") << " [" << hex << setw(2) << setfill('0') << (unsigned short)iAttrs << "] \n" ;
       
   300 	if(iFirstChild)
       
   301 		iFirstChild->PrintTree(nTab + 2);
       
   302 	if(iSibling)
       
   303 		iSibling->PrintTree(nTab);
       
   304 }
       
   305 #endif
       
   306 bool TFSNode::IsDirectory() const {
       
   307 	return 0 != (iAttrs & ATTR_DIRECTORY);
       
   308 }
       
   309 int TFSNode::GetWideNameLength() const {
       
   310 	if(!iWideName)
       
   311 		return 0 ;
       
   312 	return iWideName->length() ;
       
   313 }
       
   314 TUint TFSNode::GetSize() const {
       
   315 	
       
   316 	if(  0 == (iAttrs & ATTR_DIRECTORY))
       
   317 		return iFileSize ;
       
   318 	TUint retVal = sizeof(TShortDirEntry) ; // the tailed entry 
       
   319 	if(iParent)
       
   320 		retVal += sizeof(TShortDirEntry) * 2 ;
       
   321 	TFSNode* child = iFirstChild ;
       
   322 	while(child) {
       
   323 		TUint longNameEntries =  (child->GetWideNameLength() + KBytesPerEntry) / KBytesPerEntry  ;
       
   324 		retVal += longNameEntries * sizeof(TLongDirEntry) ;
       
   325 		retVal += sizeof(TShortDirEntry);
       
   326 		child = child->iSibling ;
       
   327 	}
       
   328 	return retVal ;
       
   329 }
       
   330  
       
   331 void TFSNode::Init(time_t aCreateTime, time_t aAccessTime, time_t aWriteTime, TUint aSize ) {
       
   332 	
       
   333 	struct tm* temp = localtime(&aCreateTime);
       
   334 	iCrtDate.iCurrentDate.Day = temp->tm_mday;
       
   335 	iCrtDate.iCurrentDate.Month = temp->tm_mon+1; //As per FAT spec
       
   336 	iCrtDate.iCurrentDate.Year = temp->tm_year - 80;//As per FAT spec
       
   337 	iCrtTime.iCurrentTime.Hour = temp->tm_hour;
       
   338 	iCrtTime.iCurrentTime.Minute = temp->tm_min;
       
   339 	iCrtTime.iCurrentTime.Seconds = temp->tm_sec / 2;//As per FAT spec
       
   340 	iCrtTimeTenth = 0;
       
   341 	
       
   342 	temp = localtime(&aAccessTime);	
       
   343 	iLstAccDate.iCurrentDate.Day = temp->tm_mday;
       
   344 	iLstAccDate.iCurrentDate.Month = temp->tm_mon+1; //As per FAT spec
       
   345 	iLstAccDate.iCurrentDate.Year = temp->tm_year - 80;//As per FAT spec
       
   346 	
       
   347 	temp = localtime(&aWriteTime);
       
   348 	iWrtDate.iCurrentDate.Day = temp->tm_mday;
       
   349 	iWrtDate.iCurrentDate.Month = temp->tm_mon+1; //As per FAT spec
       
   350 	iWrtDate.iCurrentDate.Year = temp->tm_year - 80;//As per FAT spec
       
   351 	iWrtTime.iCurrentTime.Hour = temp->tm_hour;
       
   352 	iWrtTime.iCurrentTime.Minute = temp->tm_min;
       
   353 	iWrtTime.iCurrentTime.Seconds = temp->tm_sec / 2;//As per FAT spec 
       
   354 	
       
   355 	iFileSize = aSize ; 
       
   356 }
       
   357 /** WriteDirEntries : Write FAT information for this node to a cluster buffer
       
   358 	* aStartIndex : [in],the beginning index of the outputed cluster  
       
   359   * aClusterData : [in,out] the cluster buffer
       
   360   * 
       
   361   * notice, aClusterData is only required if node is a directory node.
       
   362   * for a file node, no data will be written out.
       
   363   * in this case, only corresponding cluster index information is updated.
       
   364   */ 
       
   365 void TFSNode::WriteDirEntries(TUint aStartIndex,TUint8* aClusterData){
       
   366 	if(iFATEntry){
       
   367 		*((TUint16*)iFATEntry->DIR_FstClusHI) = (aStartIndex >> 16) ;
       
   368 		*((TUint16*)iFATEntry->DIR_FstClusLO) = (aStartIndex & 0xFFFF) ;
       
   369 	}
       
   370 	 
       
   371 	if(iAttrs & ATTR_DIRECTORY) { // Directory , write dir entries ; 
       
   372 		TShortDirEntry* entry = reinterpret_cast<TShortDirEntry*>(aClusterData);
       
   373 		if(iParent != NULL) {
       
   374 			//Make 
       
   375 			GetShortEntry(entry); 
       
   376 			//TODO: Add comments to avoid mistaken deleting.			
       
   377 			memcpy(entry->DIR_Name,".            ",sizeof(entry->DIR_Name));
       
   378 			entry ++ ;
       
   379 			iParent->GetShortEntry(entry);
       
   380 			memcpy(entry->DIR_Name,"..           ",sizeof(entry->DIR_Name));
       
   381 			entry ++ ; 
       
   382 		}		 
       
   383 		TFSNode* child = iFirstChild ;
       
   384 		while(child){			
       
   385 			int items = child->GetLongEntries(reinterpret_cast<TLongDirEntry*>(entry));
       
   386 			entry += items ;
       
   387 			child->GetShortEntry(entry);
       
   388 			child->iFATEntry = entry ;
       
   389 			entry ++ ;
       
   390 			child = child->iSibling ; 
       
   391 			
       
   392 		}
       
   393 
       
   394 	}
       
   395 }
       
   396 /** GetShortEntry : Make a short directory entry (FAT16/32 conception)
       
   397   * aEntry : the entry buffer   
       
   398   */ 
       
   399 void TFSNode::GetShortEntry(TShortDirEntry* aEntry) {
       
   400   if(!aEntry) return ;
       
   401 	if(iFATEntry){
       
   402 		if(iFATEntry != aEntry)
       
   403 			memcpy(aEntry,iFATEntry,sizeof(TShortDirEntry));
       
   404 		return ;
       
   405 	}
       
   406 	memcpy(aEntry->DIR_Name,iShortName,sizeof(aEntry->DIR_Name)); 
       
   407 	aEntry->DIR_Attr = iAttrs;
       
   408 	aEntry->DIR_NTRes = 0 ;
       
   409 	aEntry->DIR_CrtTimeTenth = 0 ;        
       
   410 	memcpy(aEntry->DIR_CrtTime,&iCrtTime,sizeof(aEntry->DIR_CrtTime)); 
       
   411 	memcpy(aEntry->DIR_CrtDate,&iCrtDate,sizeof(aEntry->DIR_CrtDate));
       
   412 	memcpy(aEntry->DIR_LstAccDate,&iLstAccDate,sizeof(aEntry->DIR_LstAccDate));
       
   413 	memset(aEntry->DIR_FstClusHI,0,sizeof(aEntry->DIR_FstClusHI));
       
   414 	memcpy(aEntry->DIR_WrtTime,&iWrtTime,sizeof(aEntry->DIR_WrtTime)); 
       
   415 	memcpy(aEntry->DIR_WrtDate,&iWrtDate,sizeof(aEntry->DIR_WrtDate)); 
       
   416 	memset(aEntry->DIR_FstClusLO,0,sizeof(aEntry->DIR_FstClusLO)); 
       
   417 	memcpy(aEntry->DIR_FileSize,&iFileSize,sizeof(aEntry->DIR_FileSize));  
       
   418 }
       
   419 TUint8 FATChkSum(const char* pFcbName) {
       
   420     short fcbNameLen ;
       
   421     TUint8 sum = 0 ;
       
   422     for(fcbNameLen = 11 ; fcbNameLen != 0 ; fcbNameLen --) {
       
   423         sum = ((sum & 1) ? 0x80 : 0 ) + (sum >> 1 ) + *pFcbName++ ; 
       
   424     }
       
   425     return sum ;        
       
   426 }
       
   427 /** GetLongEntries : Make a series of long directory entries (FAT16/32 conception)
       
   428   * aEntries : the start addr of the long directory entries buffer
       
   429   *
       
   430   * return value : actual entris count.   
       
   431   */ 
       
   432 int TFSNode::GetLongEntries(TLongDirEntry* aEntries) {
       
   433   
       
   434   if(!aEntries) return 0;
       
   435 	int packs = (GetWideNameLength() + KBytesPerEntry) / KBytesPerEntry  ;
       
   436 	
       
   437 	TUint buflen = packs * KBytesPerEntry;
       
   438 	TUint16* buffer = new(std::nothrow) TUint16[buflen];
       
   439 	if(!buffer)
       
   440 	return 0 ;
       
   441 	memset(buffer,0xff,(buflen << 1));    
       
   442 	if(iWideName) {
       
   443 	    memcpy(buffer,iWideName->c_str(),iWideName->bytes()); 
       
   444 	    buffer[iWideName->length()] = 0;
       
   445 	}
       
   446 	TUint8 chkSum = FATChkSum(iShortName);;
       
   447     
       
   448 	TUint16* ptr = buffer ;
       
   449 	TLongDirEntry* entry = aEntries +(packs - 1);
       
   450   for(int i = 1 ; i <= packs ; i++, entry--) {		
       
   451 		entry->LDIR_Ord = i ;
       
   452 		entry->LDIR_Chksum = chkSum ;
       
   453 		entry->LDIR_Attr = (TUint8)ATTR_LONG_NAME;    
       
   454 		*((TUint16*)(entry->LDIR_FstClusLO)) = 0;
       
   455 		entry->LDIR_Type = 0;         
       
   456 		memcpy(entry->LDIR_Name1,ptr,10); 
       
   457 		memcpy(entry->LDIR_Name2,&ptr[5],12); 
       
   458 		memcpy(entry->LDIR_Name3,&ptr[11],4);
       
   459 		ptr += 13; 
       
   460   }
       
   461 	aEntries->LDIR_Ord |= 0x40 ;
       
   462     
       
   463 	delete []buffer ;
       
   464 	return packs ; 
       
   465 }
       
   466 /** Make a unique name for a new child which has not been added.
       
   467   * to avoid same short names under a directory
       
   468   * rShortName : [in,out] , The new short name to be checked and changed.
       
   469   * baseNameLength: [in], the length of the base part of the short name 
       
   470   * not including the "~n"
       
   471   * for example, 
       
   472   *  "ABC.LOG" => baseNameLength == 3 ("ABC")
       
   473   *  "AB~1.TXT" => baseNameLength == 2 ("AB")
       
   474   *
       
   475   *
       
   476   *The Numeric-Tail Generation Algorithm
       
   477 
       
   478   * If (a "lossy conversion" was not flagged)
       
   479   * 		and	(the long name fits within the 8.3 naming conventions)
       
   480   * 		and	(the basis-name does not collide with any existing short name)
       
   481   * {
       
   482   * 	The short name is only the basis-name without the numeric tail.
       
   483   * }
       
   484   * else {
       
   485   * 	Insert a numeric-tail "~n" to the end of the primary name such that the value of 
       
   486   *		the "~n" is chosen so that the name thus formed does not collide with 
       
   487   *		any existing short name and that the primary name does not exceed eight
       
   488   *		characters in length.
       
   489   * }
       
   490   * The "~n" string can range from "~1" to "~999999". 
       
   491   *
       
   492   */
       
   493 
       
   494 void TFSNode::MakeUniqueShortName(char rShortName[12],TUint baseNameLength) const { 
       
   495 	bool dup ;
       
   496 	char nstring[10];
       
   497 	int n = 0 ;	
       
   498 	do {
       
   499 		TFSNode* child = iFirstChild ; 
       
   500 		dup = false ;
       
   501 		while(child){		 
       
   502 			if(0 == memcmp(rShortName,child->iShortName,11)) {
       
   503 				dup = true ;
       
   504 				break ;
       
   505 			}
       
   506 			child = child->iSibling ;
       
   507 		}
       
   508 		if(dup){ //duplex , increase the index , make a new name 
       
   509 			int nlen = sprintf(nstring,"~%u",++n);
       
   510 			while((baseNameLength + nlen > 8) && baseNameLength > 1)
       
   511 				baseNameLength -- ;
       
   512 			memcpy(&rShortName[baseNameLength],nstring,nlen);
       
   513 			
       
   514 		}
       
   515 	}while(dup) ;
       
   516 		 
       
   517 }
       
   518