//	CDirectoryPro.c

#include "MemUtils.h"
#include "ADFS_LogFile.h"
#include "ADFS_Strings.h"
#include "CDialogCopy.h"
#include "CDialogDeleteFile.h"
#include "CDiskMapWindow.h"
#include "Pro_Utils.h"
#include "ProFileTypes.h"
#include "IC_FileIO.h"
#include "IC_Errors.h"
#include "CDesktop.h"
#include "CFilePro.h"
#include "CDiskPro.h"
#include "CFolderPro.h"

OSErr	CFolderPro::IFolderPro(
	CDiskPro			*cDiskPro, 
	CFolderPro			*cParentFolderPro, 
	Pro_BlockNum		block, 					//	of parent folder, if any, else 2
	Pro_EntryIndex		diskLocDirEntryIndex,	//	relative to cur dir sector
	Pro_EntryIndex		directoryIndex			//	relative to entire directory
) {
	OSErr				err = noErr;
	DiskLocSpecUnion	locSpec;
	
	i_myEntryCachedB	= FALSE;

	locSpec.pro = SetRboShort(block);

	err = _inherited::IFolder(
		cDiskPro, cParentFolderPro, locSpec, diskLocDirEntryIndex, directoryIndex);
	
	if (!err) err = AddEntries(TRUE, cDiskPro->i_show_deletedB);
	
	return err;
}

void			CFolderPro::Dispose(void)
{
	_inherited::Dispose();
}

DateTimeRec		*CFolderPro::GetCreatedTime(DateTimeRec *dt)
{
	Pro_DirEntry		*dirEntry = GetMyEntry();
	
	if (dirEntry) {
		Pro_DateTime		dateTime;

		dateTime = dirEntry->createdTime;
		Pro_GetDateTime(&dateTime, dt);
	} else {
		_inherited::GetCreatedTime(dt);
	}
	
	return dt;
}

DateTimeRec		*CFolderPro::GetModifiedTime(DateTimeRec *dt)
{
	Pro_DirEntry		*dirEntry = GetMyEntry();
	
	if (dirEntry) {
		Pro_DateTime		dateTime;

		dateTime = dirEntry->modifiedTime;
		Pro_GetDateTime(&dateTime, dt);
	} else {
		_inherited::GetModifiedTime(dt);
	}
	
	return dt;
}

void			CFolderPro::SetCreatedTime(DateTimeRec *dt)
{
	Pro_DateTime		dateTime;
	Pro_DirEntry		*dirEntry = GetMyEntry();
	Pro_DirHeader		*myHeader;

	Pro_SetDateTime(dt, &dateTime);
	
	if (dirEntry) {
		dirEntry->createdTime = dateTime;
		FlushEntry();
	}

	myHeader = GetMyHeader();
	if (myHeader) {
		myHeader->createdTime = dateTime;
		(void)FlushHeader();
	}
}

void			CFolderPro::SetModifiedTime(DateTimeRec *dt)
{
	Pro_DateTime		dateTime;
	Pro_DirEntry		*dirEntry = GetMyEntry();
	Pro_DirHeader		*myHeader;

	Pro_SetDateTime(dt, &dateTime);
	
	if (dirEntry) {
		dirEntry->modifiedTime = dateTime;
		FlushEntry();
	}

	myHeader = GetMyHeader();
	if (myHeader) {
		myHeader->modifiedTime = dateTime;
		(void)FlushHeader();
	}
}

Pro_BlockNum	CFolderPro::GetLastDirBlock(void)
{
	Pro_BlockNum		lastBlock = 0, block = GetDirKeyBlock();
	Pro_DirBlock		*dirBlock;
	Boolean				done = FALSE;
	OSErr				err;
	
	err = i_cDisk.pro->PushBlock();
	
	if (block) do {
		err = i_cDisk.pro->GetBlock(block, (Pro_Block **)&dirBlock);
		
		if (!err) {
			if (dirBlock) {
				lastBlock	= block;
				block		= GetRboShort(dirBlock->list.next);
				done		= block == 0;
			} else {
				lastBlock	= 0;
				done		= TRUE;
			}
		} else {
			done = TRUE;
		}
	} while (!done);
	
	return lastBlock;
}

OSErr			CFolderPro::AddEntries(Boolean normalB, Boolean deletedB)
{
	OSErr				err		= noErr;
	Gen_MakeEntryData	data;
	
	data.dirIndexS			= 0;	//	relative to entire directory
	data.normalB			= normalB;
	data.deletedB			= deletedB;
	data.blocksInVolumeL	= i_cDisk.pro->GetTotalBlocks();
	data.headerBlockS		= GetDirKeyBlock();

	if (!err) err = ForEachEntry(MakeNewEntryCB, &data);
	if (!err) err = _inherited::AddEntries(normalB, deletedB);
	
	return err;
}

OSErr	ZeroEntryCB(
	CFolderPro			*thiz, 
	Pro_DirEntry		*entry, 
	Pro_BlockNum		block, 
	Pro_EntryIndex		entryIndex, 
	Boolean				*done, 
	void				*data);

OSErr			CFolderPro::ForEachEntry(Pro_ForEachEntryCB Pro_ForEachUserCB, void *data)
{
	OSErr				err			= noErr;
	
	err = i_cDisk.pro->PushBlock();
	
	if (!err) {
		OSErr				err2;
		Pro_BlockNum		block	= GetDirKeyBlock();
		
		if (block < i_cDisk.pro->GetVolumeSize()) {
			Pro_DirHeader	*headerP = GetMyHeader();
			
			if (headerP) {
				Boolean				keyBlock	= TRUE;
				Boolean				done		= FALSE;	
				Pro_EntryIndex		entryIndex;
				Pro_EntryIndex		maxEntries	= 0, foundEntries	= 0;
				Pro_DirEntry		*entry;
				O_CTopic			*topicP	= NULL;

				topicP = GetEntryTopic(this);
				maxEntries = GetRboShort(headerP->fileCount);

				do {
					for (
						entryIndex = 0; 
						!done && entryIndex < (Pro_kMaxEntriesPerBlock - keyBlock); 
						(entryIndex)++
					) {
						entry = GetEntry(block, entryIndex);
						
						if (!entry) {
							err = IC_Err_CANT_READ_PRODOS_BLOCK;
						} else {
							if (!Pro_IsEmptyEntry(entry)) {
								foundEntries++;
							}
						
							err = i_cDisk.pro->PushBlock();
							
							if (!err) err = topicP->O_SetRecent();

							if (!err) {
								err		= (*Pro_ForEachUserCB)(
									this, entry, block, entryIndex, &done, data);
								
								if (done) {
									//	only correct max entries if we've gone thru
									//	the entire directory
									foundEntries = maxEntries;
								}
								
								err2	= i_cDisk.pro->PopBlock();
								if (!err) err = err2;
							}
						}
						
						if (!done) {
							done = err != noErr;
						}
					}
					
					if (Pro_ForEachUserCB == ZeroEntryCB) {
						i_cDisk.pro->SetBlock();
					}
					
					if (!done) {
						Pro_DirBlock	*dirBlock;
						
						err = i_cDisk.pro->GetBlock(block, (Pro_Block **)&dirBlock);
						
						if (err) {
							done		= TRUE;
						} else {
							keyBlock	= FALSE;
							block		= GetRboShort(dirBlock->list.next);
							done		= block == 0;
						}
					}
				} while (!done);
				
				if (maxEntries != foundEntries) {
					headerP	= GetMyHeader();
					err = ASSERT(headerP);
					
					if (headerP) {
						char		whereAC[256];
						char		bufAC[256];

						headerP->fileCount	= SetRboShort(foundEntries);
						(void)FlushHeader();
						
						if (GetParentFolder()) {
							GetWhereString(whereAC);
						} else {
							i_cDisk.pro->GetWhereString(whereAC);
						}

						sprintf(bufAC, "The directory '%s' indicated the incorrect number of "
							"files (%d).  This has been fixed to indicate the correct number (%d).", 
							whereAC, (int)maxEntries, (int)foundEntries);
						AlertID(bufAC, -1);						
					}
				}
			}
		}
		
		err2 = i_cDisk.pro->PopBlock();
		if (!err) err = err2;
	}
	
	return err;
}

//	static
OSErr	CFolderPro::MakeNewEntryCB(
	CFolderPro			*thiz, 
	Pro_DirEntry		*entry, 
	Pro_BlockNum		block, 
	Pro_EntryIndex		entryIndex, 
	Boolean				*done, 
	void				*data
) {
	OSErr				err			= noErr;
	Gen_MakeEntryData	*dataP		= (Gen_MakeEntryData *)data;

	err	= thiz->MakeNewEntry(
		entry, block, entryIndex, dataP, NULL);

	return err;
}

OSErr			CFolderPro::MakeNewEntry(
	Pro_DirEntry		*entry, 
	Pro_BlockNum		block, 
	Pro_EntryIndex		diskLocDirEntryIndex, 
	Gen_MakeEntryData	*dataP, 
	CEntry				**newEntry0, 
	Boolean				verifyB
) {
	OSErr		err			= noErr;
	Boolean		validB		= TRUE;
	Boolean		deletedB	= FALSE;
	
	if (verifyB) {
		validB		= i_cDisk.pro->IsValidEntry(
			entry, dataP->blocksInVolumeL, dataP->headerBlockS);
			
		deletedB	= validB && Pro_IsEmptyEntry(entry);
	}
	
	(dataP->dirIndexS)++;	
	
	if (newEntry0) {
		*newEntry0 = NULL;
	}
	
	if (validB) {

		if (
			(!deletedB && dataP->normalB)
			|| (deletedB && dataP->deletedB)
		) {
			if (entry->fileType == Pro_FileType_DIR) {
				CFolderPro		*cFolder;

				if (NewObject(cFolder, CFolderPro, err)) {
					O_CTopic		*topic;
					
					err = i_cDisk.pro->i_desktop->i_cOutline->O_GetRecent(&topic);
					
					if (!err) err = cFolder->IFolderPro(
						i_cDisk.pro, this, block, diskLocDirEntryIndex, dataP->dirIndexS);
					
					if (!err) err = topic->O_SetRecent();
					
					if (err) {
						cFolder->Dispose();
					} else {
						if (newEntry0) {
							*newEntry0 = cFolder;
						}
					}
				}
			} else {
				CFilePro	*cFile;
				
				if (NewObject(cFile, CFilePro, err)) {
				
					err = cFile->IFilePro(
						i_cDisk.pro, this, block, 
						diskLocDirEntryIndex, dataP->dirIndexS);

					if (err) {
						cFile->Dispose();
					} else {
						if (newEntry0) {
							*newEntry0 = cFile;
						}
					}
				}
			}
		} else {
			if (
				entry->fileType == Pro_FileType_DIR
				&& (!deletedB && dataP->deletedB)
			) {
				CFolderPro		*folderP = (CFolderPro *)GetFileFromEntry(entry);
				
				ASSERT(folderP->i_type == FSObject_FOLDER);
				err = folderP->AddEntries(FALSE, TRUE);
			}
		}
	}
		
	return err;
}

char			*CFolderPro::GetDescription(char *buf)
{
	strcpy(buf, "Folder");
	return buf;
}

char			*CFolderPro::GetName(char *buf)
{
	if (!GetParentFolder()) {
		i_cDisk.pro->GetName(buf);
	} else {
		_inherited::GetName(buf);
	}
	
	if (buf[0] == 0) {
		if (GetParentFolder()) {
			Pro_DirEntry	*dirEntry = GetMyEntry();
			
			if (!dirEntry) {
				buf[0] = 0;
			} else {
				Pro_GetFileName(dirEntry, buf);
			}
		} else {
			ReportError(IC_Err_NOT_REALLY_A_FOLDER);
		}
	}

	return buf;
}

OSErr			CFolderPro::IsKeyBlock(Pro_BlockNum block, Boolean *isKeyB)
{
	OSErr			err		= noErr;

#if 0
	//	can't do this cuz then it's recursive!	
	Pro_DirEntry	*entryP = GetMyEntry();
	
	if (entryP == NULL) err = IC_Err_ENTRY_NOT_FOUND;
	
	if (!err) {
		*isKeyB = entryP->typeName.stnl.storageType == Pro_Storage_SUBDIR_HEADER;
	}
#else
//	Boolean			isKeyBlock	= FALSE;
	Pro_DirBlock	*dirBlock;
	
	err = i_cDisk.pro->PushBlock();
	
	if (!err) {
		OSErr		err2;
		
		err = i_cDisk.pro->GetBlock(block, (Pro_Block **)&dirBlock);
		
		if (!err) {
			*isKeyB = (
				(unsigned char)dirBlock->blockType.typeName.stnl.storageType 
				& Pro_Storage_SUBDIR_HEADER
			) == Pro_Storage_SUBDIR_HEADER;
		}

		err2 = i_cDisk.pro->PopBlock();
		if (!err) err = err2;
	}
#endif
		
	return err;
}

Pro_DirEntry	*CFolderPro::GetEntry(Pro_BlockNum block, Pro_EntryIndex entryIndex)
{
	Pro_DirBlock	*dirBlock;
	Pro_DirEntry	*dirEntry = NULL;
	OSErr			err = i_cDisk.pro->GetBlock(block, (Pro_Block **)&dirBlock);
	
	if (!err) {
		Boolean		isKeyB;
		
		err = IsKeyBlock(block, &isKeyB);
		
		if (!err) {
			dirEntry = &(dirBlock->blockType.standard.entry[entryIndex + isKeyB]);
		}
	}
	
	return dirEntry;
}

Pro_DirEntry	*CFolderPro::GetMyEntry(void)
{
	Pro_DirEntry		*entryP = NULL;
	
	if (!i_myEntryCachedB) {
		OSErr			err = noErr;
		
		if (!err) err = i_cDisk.pro->PushBlock();
		if (!err) {
			OSErr		err2;
			
			entryP = GetEntry(GetRboShort(i_diskLoc.pro), i_diskLocDirEntryIndex);
			if (entryP == NULL) err = IC_Err_ENTRY_NOT_FOUND;
			
			if (!err) {
				i_myEntry			= *entryP;
				i_myEntryCachedB	= TRUE;
				entryP				= &i_myEntry;
			}

			err2 = i_cDisk.pro->PopBlock();
			if (!err) err = err2;
		}
	} else {
		entryP = &i_myEntry;
	}
	
	return entryP;
}

Pro_BlockNum	CFolderPro::GetDirKeyBlock(void)
{
	Pro_BlockNum		block = 0;

	if (i_type == FSObject_DISK_ROOT_FOLDER) {
		block = Pro_kDirStartBlock;
	} else {
		Pro_DirEntry	*entry = GetMyEntry();
		
		if (entry) {
			block = GetRboShort(entry->key);
		}
	}

	return block;
}

Pro_DirBlock	*CFolderPro::GetMyDirBlock(void)
{
	Pro_BlockNum	myKeyBlock	= GetDirKeyBlock();
	Pro_DirBlock	*dirBlockP	= NULL;
	
	if (myKeyBlock) {
		i_cDisk.pro->GetBlock(myKeyBlock, (Pro_Block **)&dirBlockP);
	}
	
	return dirBlockP;
}

Pro_DirHeader	*CFolderPro::GetMyHeader(void)
{
	Pro_DirHeader	*dirHeaderP	= NULL;

	if (i_type == FSObject_DISK_ROOT_FOLDER) {
		dirHeaderP = i_cDisk.pro->GetMyEntry();
	} else {
		Pro_DirBlock	*dirBlockP	= GetMyDirBlock();

		if (dirBlockP) {
			dirHeaderP = &dirBlockP->blockType.key.header;

			if (!Pro_IsValidDirHeader(dirHeaderP)) {
				dirHeaderP = NULL;
			}
		}
	}
	
	return dirHeaderP;
}

OSErr			CFolderPro::FlushHeader(void)
{
	OSErr		err = noErr;
	
	if (i_type == FSObject_DISK_ROOT_FOLDER) {
		err = i_cDisk.pro->FlushEntry();
	} else {
		err = i_cDisk.pro->SetBlock();
	}
	
	return err;
}

OSErr			CFolderPro::FlushEntry(void)
{
	OSErr		err = noErr;
	
	if (i_myEntryCachedB) {
		if (!err) err = i_cDisk.pro->PushBlock();
						
		if (!err) {
			OSErr				err2;
			Pro_DirEntry		*entryP = NULL;
			
			entryP = GetEntry(GetRboShort(i_diskLoc.pro), i_diskLocDirEntryIndex);
			if (entryP == NULL) err = IC_Err_ENTRY_NOT_FOUND;
			
			if (!err) {
				*entryP = i_myEntry;
				err = i_cDisk.pro->SetBlock();
			}

			err2 = i_cDisk.pro->PopBlock();
			if (!err) err = err2;
		}
	}
	
	return err;
}

OSErr			CFolderPro::ZeroDirectory(Boolean isKeyB, Pro_BlockNum block)
{
	OSErr			err = noErr;
	
	err = i_cDisk.pro->PushBlock();
	
	if (!err) {
		OSErr			err2;
		Pro_DirBlock	*dirBlock;
		
		err = i_cDisk.pro->GetBlock(block, (Pro_Block **)&dirBlock);

		if (!err) {
			Pro_EntryIndex		entryIndex;
			Pro_DirEntry		*dirEntryP;
			
			dirEntryP = &dirBlock->blockType.standard.entry[isKeyB];
			
			for (
				entryIndex = 0; 
				entryIndex < (Pro_kMaxEntriesPerBlock - isKeyB); 
				entryIndex++
			) {
				memclr(dirEntryP, sizeof(Pro_DirEntry));
				dirEntryP++;
			}
			
			err = i_cDisk.pro->SetBlock();
		}

		err2 = i_cDisk.pro->PopBlock();
		if (!err) err = err2;
	}
	
	return err;
}


OSErr			CFolderPro::ExtendDirectory(void)
{
	Pro_BlockNum	block		= GetDirKeyBlock();
	Pro_DirBlock	*dirBlock;
	OSErr			err = i_cDisk.pro->GetBlock(block, (Pro_Block **)&dirBlock);
	Pro_BlockNum	newBlock, lastBlock;
	
	if (block == 0 || err) {
		err = IC_Err_CANT_READ_PRODOS_BLOCK;
		goto handleErr;
	}

	if (dirBlock->blockType.typeName.stnl.storageType == Pro_Storage_VOL_HEADER) {
		ReportError(err = IC_Err_DIRECTORY_FULL);
		goto handleErr;
	}
		
	err = i_cDisk.pro->GetFreeBlock(&newBlock);
	if (err) goto handleErr;
	
	if (newBlock == 0) {
		ReportError(err = IC_Err_DISK_FULL);
		err = -1;
		goto handleErr;
	}

	err = i_cDisk.pro->ReserveBlock(newBlock);
	if (err) goto handleErr;

	lastBlock = GetLastDirBlock();
	
	if (lastBlock == 0) {
		err = IC_Err_CANT_READ_PRODOS_BLOCK;
		goto handleErr;
	}
	
	err = i_cDisk.pro->GetBlock(lastBlock, (Pro_Block **)&dirBlock);
	if (err) {
		goto handleErr;
	}

	dirBlock->list.next = SetRboShort(newBlock);
	err = i_cDisk.pro->SetBlock();
	if (err) goto handleErr;

	err = i_cDisk.pro->GetBlock(newBlock, (Pro_Block **)&dirBlock);
	if (err) {
		goto handleErr;
	}
	
	dirBlock->list.previous	= SetRboShort(lastBlock);
	dirBlock->list.next		= SetRboShort(0);

	#if Pro_kUseOldTwirlDown
		dirBlock->twirledDownB		= 0;
	#else
		dirBlock->unused			= 0;
	#endif
	
	err = i_cDisk.pro->SetBlock();
	if (err) goto handleErr;

	err = i_cDisk.pro->GetBlock(block, (Pro_Block **)&dirBlock);
	
	Pro_DirEntry	*entryP = GetMyEntry();
	
	if (entryP == NULL) {
		err = IC_Err_CANT_READ_PRODOS_BLOCK;
		goto handleErr;
	} else {
		entryP->eof			= SetRbo3Bytes(GetRbo3Bytes(entryP->eof) + sizeof(Pro_Block));
		entryP->blocksUsed	= SetRboShort(GetRboShort(entryP->blocksUsed) + 1);
		FlushEntry();
	}

	err = ZeroDirectory(FALSE, newBlock);

	handleErr:
	return err;
}


static	OSErr	GetEmptyEntryCB(
	CFolderPro			*thiz, 
	Pro_DirEntry		*entry, 
	Pro_BlockNum		block, 
	Pro_EntryIndex		entryIndex, 
	Boolean				*done, 
	void				*data
) {
	Pro_EntryLocSpec	*entryLoc = (Pro_EntryLocSpec *)data;

	entryLoc->dirIndex++;
	
	if (Pro_IsEmptyEntry(entry)) {
		entryLoc->block			= block;
		entryLoc->entryIndex	= entryIndex;
		*done					= TRUE;
	}

	return noErr;
}

Boolean			CFolderPro::GetEmptyEntry(Pro_EntryLocSpec *entryLoc)
{
	OSErr		err = noErr;

	entryLoc->block			= 0;
	entryLoc->entryIndex	= 0;
	entryLoc->dirIndex		= 0;
	
	err	= ForEachEntry(GetEmptyEntryCB, entryLoc);
	
	return err == noErr && entryLoc->block != 0;
}

typedef struct {
	char		*name;
	Boolean		unique;
} GetUniqueNameRec;

static	OSErr	GetUniqueNameCB(
	CFolderPro			*thiz, 
	Pro_DirEntry		*entry, 
	Pro_BlockNum		block, 
	Pro_EntryIndex		entryIndex, 
	Boolean				*done, 
	void				*data
) {
	if (!Pro_IsEmptyEntry(entry)) {
		GetUniqueNameRec	*nameRec = (GetUniqueNameRec *)data;
		Pro_FileNameStr		entryName;
		
		Pro_GetFileName(entry, entryName);

		if (strcmp(entryName, nameRec->name) == 0) {
			nameRec->unique	= FALSE;
			*done			= TRUE;
		}
	}

	return noErr;
}

Boolean			CFolderPro::GetUniqueName(char *fileName)
{
	OSErr				err		= noErr;
	Boolean				done	= FALSE;
	Pro_FileNameStr		newName;
	GetUniqueNameRec	nameRec;
	short				loop;
	
	nameRec.name	= newName;
	nameRec.unique	= TRUE;
	
	strcpy(newName, fileName);
	err	= ForEachEntry(GetUniqueNameCB, &nameRec);
	
	if (err) {
		nameRec.unique	= FALSE;
	} else if (!nameRec.unique) {
		for (loop = 1; !done && loop <= 99; loop++) {
			nameRec.unique	= TRUE;
			sprintf(newName, "%s %d", fileName, loop);
			err	= ForEachEntry(GetUniqueNameCB, &nameRec);

			if (err) {
				done			= TRUE;
				nameRec.unique	= FALSE;
			} else if (nameRec.unique) {
				done = TRUE;
				strcpy(fileName, newName);
			}
		}
	}
	
	return nameRec.unique;
}

static	Pro_DateTime	Pro_GetCurDate(void)
{
	DateTimeRec		dt;
	Pro_DateTime	dateTime;
	
	GetTime(&dt);
	Pro_SetDateTime(&dt, &dateTime);
	return dateTime;
}

OSErr		CFolderPro::NewFolder(CEntry **newFolderH)
{
	OSErr		err					= noErr;
	Boolean		was_show_deletedB	= i_cDisk.pro->i_show_deletedB;
	
	if (was_show_deletedB) {
		i_cDisk.pro->ToggleDeletedFiles();
	}

	err = NewFile(TRUE, newFolderH);

	if (was_show_deletedB) {
		i_cDisk.pro->ToggleDeletedFiles();
	}

	return err;
}

OSErr			CFolderPro::NewFile(Boolean isFolderB, CEntry **entryH)
{
	OSErr				err			= noErr;
	O_CTopic			*topic		= NULL;
	CEntry				*newEntry	= NULL;
	Pro_BlockNum		keyBlock	= GetDirKeyBlock();
	Pro_BlockNum		newBlock	= 0;
	Pro_DirBlock		*dirBlockP;
	Pro_DirEntry		*dirEntryP;
	Pro_DateTime		curDate;
	Pro_EntryLocSpec	entryLoc;
	Pro_FileNameStr		fileName;
//	RboShort			*fileCountP;
	Boolean				dec_dir_countB = FALSE;

	*entryH = NULL;
	
	if (keyBlock == 0) {
		ReportError(err = IC_Err_NO_DIR_ENTRY);
		goto new_file_done;
	}

	if (isFolderB) {
		strcpy(fileName, Pro_kUntitledFolderStr);
	} else {
		strcpy(fileName, Pro_kUntitledFileStr);
	}
	
	if (!GetUniqueName(fileName)) {
		ReportError(err = IC_Err_FILE_ALREADY_EXISTS);
		goto new_file_done;
	}
	
	if (!GetEmptyEntry(&entryLoc)) {
		err = ExtendDirectory();
		
		if (err) {
			ReportError(err = IC_Err_DIRECTORY_FULL);
			goto new_file_done;
		} else {
			if (!GetEmptyEntry(&entryLoc)) {
				ReportError(err = IC_Err_NO_DIR_ENTRY);
				goto new_file_done;
			}
		}
	}
	
	if (isFolderB) {
		err = i_cDisk.pro->ReserveNextFreeBlock(&newBlock);
		if (err) goto new_file_done;
	}

	dirEntryP = GetEntry(entryLoc.block, entryLoc.entryIndex);
	if (!dirEntryP) goto new_file_error;
		
	curDate = Pro_GetCurDate();
	
	if (isFolderB) {
		dirEntryP->typeName.stnl.storageType	= Pro_Storage_SUBDIR_FILE;
		dirEntryP->fileType						= Pro_FileType_DIR;
	} else {
		dirEntryP->typeName.stnl.storageType	= Pro_Storage_INACTIVE;
		dirEntryP->fileType						= Pro_FileType_BINA;
	}

	Pro_SetFileName(dirEntryP, fileName);
	
	dirEntryP->key				= SetRboShort(newBlock);
	dirEntryP->blocksUsed		= SetRboShort(isFolderB ? 1 : 0);
	dirEntryP->eof				= SetRbo3Bytes(isFolderB ? sizeof(Pro_Block) : 0);
	dirEntryP->createdTime		= curDate;
	dirEntryP->access			= Pro_kAccess_UNLOCKED;
	dirEntryP->auxType			= SetRboShort(0x0000);
	dirEntryP->modifiedTime		= curDate;
	dirEntryP->header			= SetRboShort(keyBlock);
	
	err = i_cDisk.pro->SetBlock();	//	block of dirEntryP
	if (err) goto new_file_error;
	
	if (isFolderB) {
		Pro_DirHeader		*headerP;	//	points into dirBlockP;

		err = i_cDisk.pro->GetBlock(newBlock, (Pro_Block **)&dirBlockP);
		if (err) goto new_file_error;
		
		dirBlockP->list.previous	= SetRboShort(0);
		dirBlockP->list.next		= SetRboShort(0);
		
		#if Pro_kUseOldTwirlDown
			dirBlockP->twirledDownB		= 0;
		#else
			dirBlockP->unused			= 0;
		#endif
		
		headerP = &dirBlockP->blockType.key.header;
		Pro_SetDirName(headerP, fileName);
		
		headerP->headerType.directory.parent				= SetRboShort(entryLoc.block);

		headerP->headerType.directory.parentEntryNum		= entryLoc.entryIndex;

		//	i personally index from 0, but ProDOS indexes from 1, so add one
		headerP->headerType.directory.parentEntryNum++;

		//	in a key block, remember the 1st index is taken by the dir header, so add one if it's a key block
		headerP->headerType.directory.parentEntryNum += (entryLoc.dirIndex < Pro_kMaxEntriesPerBlock);

		headerP->headerType.directory.parentEntryLength		= Pro_kEntryLen;
		headerP->typeName.stnl.storageType					= Pro_Storage_SUBDIR_HEADER;
		
		headerP->unknown			= SetRboShort(0x76);	//	GS/OS uses this value
		headerP->modifiedTime		= curDate;
		headerP->createdTime		= curDate;
		headerP->version			= 0x05;					//	GS/OS uses this value
		headerP->minVersion			= 0;
		headerP->access				= Pro_kAccess_FOLDER;
		headerP->entryLen			= Pro_kEntryLen;
		headerP->entriesPerBlock	= Pro_kMaxEntriesPerBlock;
		headerP->fileCount			= SetRboShort(0);
		
		err = ZeroDirectory(TRUE, newBlock);
		if (err) goto new_file_error;
		
		err = i_cDisk.pro->SetBlock();	//	headerP == dirBlockP
		if (err) goto new_file_error;
	}
	
	//	inc the directory's file count
	err = IncrementDirCount(1);
	if (err) goto new_file_error;
	dec_dir_countB = TRUE;

	dirEntryP = GetEntry(entryLoc.block, entryLoc.entryIndex);
	if (!dirEntryP) goto new_file_error;
	
	topic = GetEntryTopic(this);
		
	err = topic->O_SetRecent();
	if (err) goto new_file_error;

	//	not necessariy *this*!  (could be CDisk)
	newEntry = GetTopicEntry(topic);
	if (!newEntry) goto new_file_error;
	
	newEntry->i_addTopicIndex = entryLoc.dirIndex - 1;

	Gen_MakeEntryData		data;
	
	memclr(&data, sizeof(data));
	data.dirIndexS			= newEntry->i_addTopicIndex;
	data.normalB			= TRUE;
	
	err = MakeNewEntry(
		dirEntryP, 
		entryLoc.block, 
		entryLoc.entryIndex, 
		&data, 
		&newEntry, 
		FALSE);
		
	if (err) goto new_file_error;
	
	goto new_file_done;

	//	if error, try to back out, ignore any other errors
	new_file_error:
	newEntry = NULL;

	dirEntryP = GetEntry(entryLoc.block, entryLoc.entryIndex);
	if (dirEntryP) {
		dirEntryP->typeName.stnl.storageType = Pro_Storage_INACTIVE;
		(void)i_cDisk.pro->SetBlock();
		
		if (isFolderB && newBlock != 0) {
			(void)i_cDisk.pro->FreeBlock(newBlock);
		}
	}

	if (dec_dir_countB) {
		(void)IncrementDirCount(-1);
	}
	
	new_file_done:
	*entryH = newEntry;
	
	i_myEntryCachedB = FALSE;
	
	return err;
}

void			CFolderPro::ConformStrLen(char* nameStr)
{
	short	lengthS = strlen(nameStr);
	
	if (lengthS > Pro_kNameLength) {
		nameStr[lengthS] = Pro_kNameLength;
	}
}


static	OSErr	GetEntryLocCB(
	CFolderPro			*thiz, 
	Pro_DirEntry		*entry, 
	Pro_BlockNum		block, 
	Pro_EntryIndex		entryIndex, 
	Boolean				*done, 
	void				*data
) {
	Pro_EntryLocSpec	*entryLoc = (Pro_EntryLocSpec *)data;

	entryLoc->dirIndex--;
	
	if (entryLoc->dirIndex == 0) {
		entryLoc->block			= block;
		entryLoc->entryIndex	= entryIndex;
		*done					= TRUE;
	}

	return noErr;
}

OSErr		CFolderPro::GetEntryLoc(Pro_EntryIndex dirIndex, Pro_EntryLocSpec *entryLoc)
{
	OSErr		err = noErr;

	entryLoc->block			= 0;
	entryLoc->entryIndex	= 0;
	entryLoc->dirIndex		= dirIndex;
	
	err	= ForEachEntry(GetEntryLocCB, entryLoc);
	
	if (entryLoc->block == 0) {
		err = IC_Err_ENTRY_NOT_FOUND;
		ReportError(err);
	} else {
		entryLoc->dirIndex = dirIndex;
	}

	return err;
}

OSErr		CFolderPro::Pro_DeleteEntryR(
	Pro_StorageType		storageType,
	Pro_BlockNum		index_blockS)
{
	OSErr		err = noErr;
	OSErr		err2 = noErr;
	
	switch (storageType) {
	
		default: {
			ReportError(err = IC_Err_READ_ILLEGAL_PRO_STORAGE_TYPE);
			break;
		}

		case Pro_Storage_SEEDLING: {
			if (index_blockS) {
				err = i_cDisk.pro->FreeBlock(index_blockS);
			}
			break;
		}

		case Pro_Storage_SAPLING:
		case Pro_Storage_TREE: {
			Pro_IndexBlock		*index_blockP;
			Pro_BlockNum		index_loopS, blockNum;
			
			err = ASSERT(index_blockS != 0);
			
			if (!err) err = i_cDisk.pro->GetBlock(index_blockS, (Pro_Block **)&index_blockP);
			
			if (!err) err = i_cDisk.pro->PushBlock();
			if (!err) {
				for (
					index_loopS = 0; 
					!err && index_loopS < Pro_kShortsPerBlock; 
					index_loopS++
				) {
					blockNum = Pro_GetIndexBlockShort(index_blockP, index_loopS);
					
					if (blockNum != 0) {
						err = Pro_DeleteEntryR(storageType - 1, blockNum);
					}
				}

				err2 = i_cDisk.pro->PopBlock();
				if (!err) err = err2;
			}
			
			if (!err) {
				//	and swap the index block so undelete works
				//	see Apple II Tech Notes : ProDOS : #23
				//	under 8.1.3, paragraph 2
				//	http://www.gno.org/pub/apple2/doc/apple/technotes/pdos/tn.pdos.023
				//	http://web.pdx.edu/~heiss/technotes/pdos/tn.pdos.23.html
				Pro_HalfBlock	temp_half;

				if (!err) {
					temp_half			= index_blockP->low;
					index_blockP->low	= index_blockP->high;
					index_blockP->high	= temp_half;
					err = i_cDisk.pro->SetBlock();
				}
			}

			if (!err) err = i_cDisk.pro->FreeBlock(index_blockS);
			break;
		}
	}

	return err;
}

OSErr		CFolderPro::IncrementDirCount(short numIncS)
{
	OSErr				err = 0;

	err = i_cDisk.pro->PushBlock();
	if (!err) {
		OSErr				err2;
		Pro_DirHeader		*dirHeaderP = GetMyHeader();
		short				fileCount;
		
		if (!dirHeaderP) ReportError(err = IC_Err_ENTRY_NOT_FOUND);

		if (!err) {
			fileCount = GetRboShort(dirHeaderP->fileCount);
			
			if (fileCount + numIncS < 0) {
				ReportError(err = IC_Err_DIR_ALREADY_EMPTY);
			}
		}
		
		if (!err) {
			//	decrement the directory 'active files' count
			dirHeaderP->fileCount = SetRboShort(fileCount + numIncS);
			err = FlushHeader();
		}

		err2 = i_cDisk.pro->PopBlock();
		if (!err) err = err2;
	}
	
	return err;
}

OSErr		CFolderPro::Pro_DeleteEntry(Pro_EntryIndex dirIndex)
{
	OSErr				err = 0;
	Pro_StorTypNamLen	stnl;
	Pro_StorTypNamLen	*stnlP;
	Pro_EntryLocSpec	entryLoc;
	Pro_DirEntry		*dirEntryP;
		
	i_cDisk.pro->FlushMemDisk(FALSE);
	
	err = GetEntryLoc(dirIndex, &entryLoc);

	if (!err) dirEntryP = GetEntry(entryLoc.block, entryLoc.entryIndex);
	if (dirEntryP == NULL) err = IC_Err_ENTRY_NOT_FOUND;
	
	if (!err) {
		stnlP	= &dirEntryP->typeName.stnl;
		stnl	= *stnlP;
		
		if (stnlP->storageType == Pro_Storage_INACTIVE) {
			ReportError(err = IC_Err_FILE_ALREADY_DELETED);
		} else {
			//	set storage type to Inactive, name length to 0
			stnlP->storageType	= Pro_Storage_INACTIVE;
			stnlP->nameLength	= 0;
			memclr(
				&dirEntryP->typeName.name[stnl.nameLength], 
				Pro_kNameLength - stnl.nameLength);

			if (!err) err = i_cDisk.pro->SetBlock();
		}
	}
	
	if (!err) err = IncrementDirCount(-1);
	
	if (!err) err = i_cDisk.pro->PushBlock();
	if (!err) {
		OSErr				err2;
		Pro_BlockNum		index_blockS = GetRboShort(dirEntryP->key);

		//	free the volume bitmap
		switch (stnl.storageType) {
		
			default: {
				ReportError(err = IC_Err_READ_ILLEGAL_PRO_STORAGE_TYPE);
				break;
			}

			case Pro_Storage_INACTIVE: {
				ReportError(err = IC_Err_FILE_ALREADY_DELETED);
				break;
			}

			case Pro_Storage_PASCAL: {
				ReportError(err = IC_Err_READ_ILLEGAL_PRO_STORAGE_PASCAL_TYPE);
				break;
			}

			case Pro_Storage_SUBDIR_FILE: {
				Pro_DirBlock		*dirBlockP;
				
				while (!err && index_blockS) {
					err = i_cDisk.pro->GetBlock(
						index_blockS, (Pro_Block **)&dirBlockP);
					
					if (!err) err = i_cDisk.pro->FreeBlock(index_blockS);
					if (!err) {
						index_blockS = GetRboShort(dirBlockP->list.next);
					}
				}
				break;
			}
			
			case Pro_Storage_SEEDLING: {
				if (index_blockS) {
					err = i_cDisk.pro->FreeBlock(index_blockS);
				}
				break;
			}

			case Pro_Storage_FORKED:
			case Pro_Storage_SAPLING:
			case Pro_Storage_TREE: {				
				if (!err) err = i_cDisk.pro->CacheBitmapBlocks();
				if (!err) {
					
					if (stnl.storageType == Pro_Storage_FORKED) {
						Pro_ExtendedIndexBlock		*extIndBlockP;
							
						err = i_cDisk.pro->GetBlock(
							index_blockS, (Pro_Block **)&extIndBlockP);
							
						err = i_cDisk.pro->PushBlock();
						if (!err) {
							err = Pro_DeleteEntryR(
								extIndBlockP->data.lowStorType.storageType, 
								GetRboShort(extIndBlockP->data.key));

							if (!err) err = Pro_DeleteEntryR(
								extIndBlockP->resource.lowStorType.storageType, 
								GetRboShort(extIndBlockP->resource.key));
							
							err2 = i_cDisk.pro->PopBlock();
							if (!err) err = err2;
						}

						if (!err) err = i_cDisk.pro->FreeBlock(index_blockS);
					} else {
						err = Pro_DeleteEntryR(stnl.storageType, index_blockS);
					}

					err2 = i_cDisk.pro->UnCacheBitmapBlocks();
					if (!err) err = err2;
				}
				break;
			}
		}

		err2 = i_cDisk.pro->PopBlock();
		if (!err) err = err2;

		if (!err) err = i_cDisk.pro->SetBlock();
	}
	
	i_cDisk.pro->FlushMemDisk(TRUE);

	UnCacheFolderSizes();

	return err;
}

void			CFolderPro::GetAccessBits(Gen_AccessBits *bits)
{
	Pro_DirEntry	*dirEntry = GetMyEntry();
	
	if (dirEntry) {
		*bits = *(Gen_AccessBits *)&dirEntry->access;
	}
}

void			CFolderPro::SetAccessBits(Gen_AccessBits *bits)
{
	Pro_DirEntry	*dirEntry = GetMyEntry();
	
	if (dirEntry) {
		dirEntry->access = *(Pro_AccessPriv *)bits;
		FlushEntry();
	}

	_inherited::SetAccessBits(bits);
}

void			CFolderPro::SetTwirled(Boolean twirledB)
{
	Pro_DirBlock	*dirBlockP	= GetMyDirBlock();

	if (dirBlockP) {
		#if Pro_kUseOldTwirlDown
			dirBlockP->twirledDownB = twirledB;
		#else
			dirBlockP->blockType.key.header.access.twirledDownB = twirledB;
		#endif

		if (!i_cDisk.pro->IsLocked()) {
			(void)i_cDisk.pro->SetBlock();
		}
	}
	
	_inherited::SetTwirled(twirledB);
}

Boolean			CFolderPro::GetTwirled(void)
{
	Pro_DirBlock	*dirBlockP	= GetMyDirBlock();
	Boolean			twirledB	= FALSE;

	if (dirBlockP) {
	
		#if Pro_kUseOldTwirlDown
			twirledB = dirBlockP->twirledDownB;
		#else
			twirledB = dirBlockP->blockType.key.header.access.twirledDownB;
		#endif
	}
	
	return twirledB;
}

CEntry			*CFolderPro::GetFileFromEntry(Pro_DirEntry *dirEntryP)
{
	Pro_EntryIndex		maxIndex = CountEntries();
	Pro_EntryIndex		curIndex;
	CEntry				*fileP = NULL, *curFileP;
	Pro_DirEntry		*curEntryP;
	
	for (curIndex = 0; curIndex < maxIndex; curIndex++) {
		curFileP = GetIndEntry(curIndex);
		
		if (curFileP) {
			if (curFileP->i_type == FSObject_FOLDER) {
				curEntryP = ((CFolderPro *)curFileP)->GetMyEntry();
			} else {
				curEntryP = ((CFilePro *)curFileP)->GetMyEntry();
			}
			
			//	if I had real disk caching like in my DOS 3.3 implementation, 
			//	then the pointers would match.  as it is, i must compare contents
			if (GetRboShort(curEntryP->key) == GetRboShort(dirEntryP->key)) {
				fileP = curFileP;
				break;
			}
		}
	}
	
	return fileP;
}

OSErr			CFolderPro::PutFileNewEntry(Handle fileH)
{
	OSErr		err = noErr;

	return err;
}

void			CFolderPro::SetName(char *buf)
{
	Pro_DirEntry		*dirEntry = GetMyEntry();
	Pro_DirHeader		*myHeader;
	
	if (dirEntry) {
		Pro_SetFileName(dirEntry, buf);
		Pro_GetFileName(dirEntry, buf);
		FlushEntry();
	}

	myHeader = GetMyHeader();
	if (myHeader) {
		Pro_SetDirName(myHeader, buf);
		(void)FlushHeader();
	}
	
	_inherited::SetName(buf);
}

OSErr		CFolderPro::GetGetFolderBlocks(
	Pro_BlockNum *blockA0, 
	Pro_BlockNum *numBlocksSP0)
{
	OSErr			err			= noErr;
	Pro_BlockNum	curBlockInd	= GetDirKeyBlock(), curBlockS = 0;
	Pro_DirBlock	*dirBlockP	= NULL;
	
	if (curBlockInd) {
		
		do {
			if (blockA0) {
				blockA0[curBlockS++] = curBlockInd;
			} else {
				(*numBlocksSP0)++;
			}
			
			err = i_cDisk.pro->GetBlock(
				curBlockInd, (Pro_Block **)&dirBlockP);
			
			if (!err) {
				curBlockInd = GetRboShort(dirBlockP->list.next);
			}
		} while (!err && curBlockInd);
	
	} else {
		err = IC_Err_ENTRY_NOT_FOUND;
	}
	
	return err;
}

OSErr		CFolderPro::GetEntryAlloc(
	Boolean			getAsBlocksB, 
	Gen_EntryAlloc	**sectorListH)
{
	OSErr		err = noErr;
	
	*sectorListH	= (Gen_EntryAlloc *)TrackNewPtrClear(
		"entry sectors, for a folder", sizeof(Gen_EntryAlloc));
	
	if (*sectorListH == NULL) err = memFullErr;
	
	if (!err) {
		(**sectorListH).allocSize = getAsBlocksB ? Gen_AllocSize_SHORT : Gen_AllocSize_SECTORS;
	}
	
	if (!err && !IsDeleted()) {
		Pro_BlockNum	numBlocksS = 0;
		
		err = GetGetFolderBlocks(NULL, &numBlocksS);

		//	suppress illegal block access
		if (err == IC_Err_READ_ILLEGAL_FILE_BLOCK) err = noErr;
		
		if (!err && numBlocksS) {
			Pro_BlockNum	*blockNumP = (Pro_BlockNum *)TrackNewPtrClear(
				"entry sectors, folder blocks", 
				sizeof(Pro_BlockNum) * numBlocksS);
			
			if (blockNumP == NULL) err = memFullErr;
			
			if (!err) {
				(*sectorListH)->type[Gen_Alloc_DIRECTORY].totalS			= numBlocksS;
				(*sectorListH)->type[Gen_Alloc_DIRECTORY].u.short_blocksA	= blockNumP;

				err = GetGetFolderBlocks(blockNumP, NULL);

				//	suppress illegal block access
				if (err == IC_Err_READ_ILLEGAL_FILE_BLOCK) err = noErr;
			}
		}
	}
	
	if (!err && !getAsBlocksB) {
		err = i_cDisk.pro->EntryBlocksToSectors(*sectorListH);
	}
	
	if (err) {
		DisposeEntryAlloc(*sectorListH);
		*sectorListH = NULL;
	}
	
	return err;
}

OSErr			CFolderPro::MoveFile(CEntry *srcEntryP, CEntry *dstEntryP)
{
	OSErr	err	= noErr;
	
	err = ASSERT(
		(srcEntryP->i_type == FSObject_FILE && dstEntryP->i_type == FSObject_FILE)
		|| (srcEntryP->i_type == FSObject_FOLDER && dstEntryP->i_type == FSObject_FOLDER));
		
	if (!err) {
		Pro_DirEntry	*destDirEntry = dstEntryP->i_type == FSObject_FILE
			? ((CFilePro *)dstEntryP)->GetMyEntry()
			: ((CFolderPro *)dstEntryP)->GetMyEntry();
		
		if (destDirEntry == NULL) err = IC_Err_ENTRY_NOT_FOUND;
		
		if (!err) {
			OSErr			err2			= noErr;
			Pro_DirEntry	*srcDirEntry	= srcEntryP->i_type == FSObject_FILE
				? ((CFilePro *)srcEntryP)->GetMyEntry()
				: ((CFolderPro *)srcEntryP)->GetMyEntry();
			
			if (srcDirEntry == NULL) err = IC_Err_ENTRY_NOT_FOUND;
			
			if (!err) {
				Pro_BlockNum	keyBlockS = GetRboShort(destDirEntry->key);
				
				if (keyBlockS != 0) {
					ASSERT(srcEntryP->i_type == FSObject_FOLDER);
					
					if (!err) err = i_cDisk.pro->PushBlock();
					if (!err) {
						Pro_DirBlock		*dirBlockP;
						Pro_DirHeader		*dirHeaderP;
						Pro_BlockSpec		parent;
						Byte				parentEntryNum;
						
						dirBlockP	= ((CFolderPro *)dstEntryP)->GetMyDirBlock();
						if (dirBlockP == NULL) err = IC_Err_ENTRY_NOT_FOUND;
						
						if (!err) {
							dirHeaderP		= &dirBlockP->blockType.key.header;
							parent			= dirHeaderP->headerType.directory.parent;
							parentEntryNum	= dirHeaderP->headerType.directory.parentEntryNum;
							err = i_cDisk.pro->FreeBlock(keyBlockS);
						}
						
						if (!err) dirBlockP = ((CFolderPro *)srcEntryP)->GetMyDirBlock();
						if (dirBlockP == NULL) err = IC_Err_ENTRY_NOT_FOUND;

						if (!err) {
							dirHeaderP		= &dirBlockP->blockType.key.header;

							dirHeaderP->headerType.directory.parent			= parent;
							dirHeaderP->headerType.directory.parentEntryNum	= parentEntryNum;
							err = i_cDisk.pro->SetBlock();
						}
						
						err2 = i_cDisk.pro->PopBlock();
						if (!err) err = err2;
						
						{
							#if Pro_kUseOldTwirlDown
								Boolean		twirledB = dirBlockP->twirledDownB;
							#else
								Boolean		twirledB = dirBlockP->blockType.key.header.access.twirledDownB;
							#endif
							
							GetEntryTopic(dstEntryP)->O_IsTwirledDown(NULL, &twirledB);
						}
					}
				}
			}
			
			if (!err) {
				destDirEntry->key			= srcDirEntry->key;
				destDirEntry->eof			= srcDirEntry->eof;
				destDirEntry->blocksUsed	= srcDirEntry->blocksUsed;
				destDirEntry->typeName.stnl.storageType = srcDirEntry->typeName.stnl.storageType;

				srcDirEntry->key			= SetRboShort(0);
				srcDirEntry->eof			= SetRbo3Bytes(0);
				srcDirEntry->blocksUsed		= SetRboShort(0);
				srcDirEntry->typeName.stnl.storageType = Pro_Storage_SEEDLING;

				if (srcEntryP->i_type == FSObject_FILE) {
					err = ((CFilePro *)srcEntryP)->FlushEntry();
				} else {
					err = ((CFolderPro *)srcEntryP)->FlushEntry();
				}
			}
			
			if (srcEntryP->i_type == FSObject_FOLDER) {
				if (!err) err = _inherited::MoveFile(srcEntryP, dstEntryP);
			}
			
			if (dstEntryP->i_type == FSObject_FILE) {
				err2 = ((CFilePro *)dstEntryP)->FlushEntry();
			} else {
				err2 = ((CFolderPro *)dstEntryP)->FlushEntry();
			}
			
			if (!err) err = err2;
		}

		if (!err) {
			CFolderPro	*folderP;
			
			folderP = (CFolderPro *)srcEntryP->GetParentFolder();
			U_ASSERT(folderP);
			if (folderP) {
				folderP->UnCacheFolderSizes();
			}

			folderP = (CFolderPro *)dstEntryP->GetParentFolder();
			U_ASSERT(folderP);
			if (folderP) {
				folderP->UpdateSort(FALSE);
				folderP->UnCacheFolderSizes();
			}
		}

		/*
			at this point:
			if FILE:
				file is empty, so deleting will only remove the directory ref
			if FOLDER:
				all relevant info copied from dest to src, and dest key block deleted
				and src ptr is empty so deleting will only remove the directory ref
		*/
		if (!err) err = srcEntryP->Delete();
		
	}
	
	return err;
}

ulong		CFolderPro::GetPhysicalSize(void)
{
	if (i_physical_sizeL == 0) {
		long			curEntryL, numEntriesL = CountEntries();
		
		for (curEntryL = 0; curEntryL < numEntriesL; curEntryL++) {
			CEntry		*entryP = GetIndEntry(curEntryL);
			
			if (!entryP->IsDeleted()) {
				i_physical_sizeL += entryP->GetPhysicalSize();
			}
		}
	}
	
	return i_physical_sizeL;
}

ulong		CFolderPro::GetLogicalSize(void)
{
	if (i_logical_sizeL == 0) {
		long			curEntryL, numEntriesL = CountEntries();
		
		for (curEntryL = 0; curEntryL < numEntriesL; curEntryL++) {
			CEntry		*entryP = GetIndEntry(curEntryL);
			
			if (!entryP->IsDeleted()) {
				i_logical_sizeL += entryP->GetLogicalSize();
			}
		}
	}
	
	return i_logical_sizeL;
}

Boolean		CFolderPro::IsDeleted(void)
{
	Boolean		deletedB	= _inherited::IsDeleted();
	
	if (!deletedB && i_type != FSObject_DISK_ROOT_FOLDER) {
		Pro_DirEntry 	*entryP		= GetMyEntry();
		
		if (entryP) {
			CFolderPro	*parentP = (CFolderPro *)GetParentFolder();
			
			deletedB = i_cDisk.pro->IsDeletedEntry(
				entryP, 
				i_cDisk.pro->GetVolumeSize(), 
				parentP->GetDirKeyBlock());
		}
	}

	return deletedB;
}

OSErr			CFolderPro::Delete(Boolean warnB, CDialogCopy *copyP0)
{
	OSErr		err				= noErr;
	CFolderPro	*folderP		= (CFolderPro *)GetParentFolder();
	
	err = DeleteFolderContents(warnB, copyP0);
	
	if (folderP) {
		if (!err) err = _inherited::Delete(warnB, copyP0);
		if (!err) err = folderP->Pro_DeleteEntry(i_directoryIndex);
	}
	
	return err;
}

OSErr			CFolderPro::UnDelete(Boolean recursiveB, CDialogCopy *copyP0)
{
	OSErr	err = noErr;
	
	if (IsDeleted()) {
		CFolderPro		*parentFolderP = (CFolderPro *)GetParentFolder();
		
		if (parentFolderP && parentFolderP->IsDeleted()) {
			err = parentFolderP->UnDelete();
		}
	}
	
	if (!err) {
		char				errorAC[1024], whereAC[256];
		Pro_DirEntry 		*entryP		= GetMyEntry();
		
		if (entryP) {
			if (GetRboShort(entryP->blocksUsed) == 0) {
				sprintf(
					errorAC, 
					ADFS_Str(ADFS_Str_TOTALLY_OVERWRITTEN), 
					GetWhereString(whereAC));

				entryP = NULL;
				ReportErrorStr(-1, errorAC);
			}
		}
		
		if (entryP) {
			i_cDisk.pro->FlushMemDisk(FALSE);

			if (!err) err = i_cDisk.pro->CacheBitmapBlocks();
			
			if (err) entryP = NULL;
		}
			
		if (entryP) {
			OSErr				err2;
			Gen_EntryAlloc		*blockListP;
			Boolean				successB = FALSE;

			entryP->typeName.stnl.storageType	= Pro_Storage_SUBDIR_FILE;
			FlushEntry();
			
			err = GetEntryAlloc(TRUE, &blockListP);

			entryP->typeName.stnl.nameLength	= Pro_GetNameLength(&entryP->typeName);
			FlushEntry();

			if (!err) {
				Pro_BlockNum		blockIndexS;
				Pro_BlockNum		curBlockS;
				Boolean				isFreeB;

				successB = TRUE;
				
				for (
					blockIndexS = 0;
					!err & blockIndexS < blockListP->type[Gen_Alloc_DIRECTORY].totalS;
					blockIndexS++
				) {
					curBlockS = blockListP->type[Gen_Alloc_DIRECTORY].u.short_blocksA[blockIndexS];
					
					err = i_cDisk.pro->IsBlockFree(curBlockS, &isFreeB);
					if (!isFreeB) {
						goto bad_bail;
					}
				}

				for (
					blockIndexS = 0;
					!err & blockIndexS < blockListP->type[Gen_Alloc_DIRECTORY].totalS;
					blockIndexS++
				) {
					curBlockS = blockListP->type[Gen_Alloc_DIRECTORY].u.short_blocksA[blockIndexS];
					
					err = i_cDisk.pro->ReserveBlock(curBlockS);
				}
					
				if (!err) err = ((CFolderPro *)GetParentFolder())->IncrementDirCount(1);
							
				goto good_done;
				bad_bail:

				entryP->typeName.stnl.storageType	= 0;
				entryP->typeName.stnl.nameLength	= 0;
				FlushEntry();

				sprintf(
					errorAC, 
					ADFS_Str(ADFS_Str_DIRECTORY_OVERWRITTEN), 
					GetWhereString(whereAC));
				
				successB = FALSE;
				ReportErrorStr(-1, errorAC);				
				
				good_done:
				DisposeEntryAlloc(blockListP);
				
				if (recursiveB) {
					if (!err) err = UnDeleteFolderContents(recursiveB, copyP0);
				}
			}
			
			err2 = i_cDisk.pro->UnCacheBitmapBlocks();
			if (!err) err = err2;

			i_cDisk.pro->FlushMemDisk(TRUE);
		}
	}

	if (!err) err = _inherited::UnDelete(recursiveB, copyP0);

	return err;
}


static	OSErr	DumpFolderCB(
	CFolderPro			*thiz, 
	Pro_DirEntry		*entry, 
	Pro_BlockNum		block, 
	Pro_EntryIndex		entryIndex, 
	Boolean				*done, 
	void				*data
) {
	Pro_DumpFolderRec		*dumpP = (Pro_DumpFolderRec *)data;
	
	return thiz->DumpFolder_Self(entry, block, entryIndex, dumpP);
}

OSErr			CFolderPro::DumpFolder(Pro_DumpFolderRec *dumpP)
{
	Pro_DirBlock	*dirBlockP	= GetMyDirBlock();
	Pro_DirHeader	*headerP	= &dirBlockP->blockType.key.header;
	Boolean			volB		= headerP->typeName.stnl.storageType == Pro_Storage_VOL_HEADER;
	char			bufAC[256];

	ADFS_Log_Tabs(dumpP->levelS);
	
	if (volB) {
		ADFS_Log("------------ VOLUME HEADER -----------\n");	
	} else {
		ADFS_Log("-------------- DIR HEADER ------------\n");	
	}
	
	ADFS_Log("Prev Dir Block: ");	
	ADFS_Log_Number(GetRboShort(dirBlockP->list.previous));
	ADFS_Log("\n");

	ADFS_Log("Next Dir Block: ");	
	ADFS_Log_Number(GetRboShort(dirBlockP->list.next));
	ADFS_Log("\n");

	ADFS_Log("Twirled: ");	
	ADFS_Log_Number((short)dirBlockP->twirledDownB);
	ADFS_Log("\n");

	ADFS_Log("Name: ");	
	ADFS_Log(Pro_GetEntryName(&headerP->typeName, GetRboShort(headerP->locaseBits), bufAC));
	ADFS_Log("\n");
	
	ADFS_Log("Unknown: ");	
	ADFS_Log_Hex(GetRboShort(headerP->unknown));
	ADFS_Log("\n");

	ADFS_Log("Version: ");	
	ADFS_Log_Hex((ushort)headerP->version);
	ADFS_Log("\n");

	ADFS_Log("Min Version: ");	
	ADFS_Log_Hex((ushort)headerP->minVersion);
	ADFS_Log("\n");

	ADFS_Log("Access: ");
	ADFS_Log_Number((short)headerP->access.destroyEnable);
	ADFS_Log(" ");
	ADFS_Log_Number((short)headerP->access.renameEnable);
	ADFS_Log(" ");
	ADFS_Log_Number((short)headerP->access.backup);
	ADFS_Log(" ");
	ADFS_Log_Number((short)headerP->access.writeEnable);
	ADFS_Log(" ");
	ADFS_Log_Number((short)headerP->access.readEnable);
	ADFS_Log("\n");

	ADFS_Log("Number of Files: ");	
	ADFS_Log_Number(GetRboShort(headerP->fileCount));
	ADFS_Log("\n");
	
	if (volB) {
		ADFS_Log("Volume Bitmap: ");	
		ADFS_Log_Number(GetRboShort(headerP->headerType.volume.bitMap));
		ADFS_Log("\n");

		ADFS_Log("Total Blocks: ");	
		ADFS_Log_Number(GetRboShort(headerP->headerType.volume.totalBlocks));
		ADFS_Log("\n");
	} else {
		ADFS_Log("Parent Block: ");	
		ADFS_Log_Number(GetRboShort(headerP->headerType.directory.parent));
		ADFS_Log("\n");

		ADFS_Log("Parent Entry Number: ");	
		ADFS_Log_Number((short)headerP->headerType.directory.parentEntryNum);
		ADFS_Log("\n");
	}

	ADFS_Log("--------------------------------\n\n");	

	return ForEachEntry(DumpFolderCB, dumpP);
}

OSErr			CFolderPro::DumpFolder_Self(
	Pro_DirEntry		*entry, 
	Pro_BlockNum		block, 
	Pro_EntryIndex		diskLocDirEntryIndex, 
	Pro_DumpFolderRec	*dumpP
) {
	OSErr		err			= noErr;
		
	ADFS_Log_Tabs(dumpP->levelS);

//	if (!Pro_IsEmptyEntry(entry)) {

		if (entry->fileType == Pro_FileType_DIR) {
			CFolderPro		*subP = (CFolderPro *)GetFileFromEntry(entry);
			char			bufAC[256];
			
			ADFS_Log("Entry Index: ");
			ADFS_Log_Number(diskLocDirEntryIndex);
			ADFS_Log("\n");

			ADFS_Log("BlockNum: ");
			ADFS_Log_Number(block);
			ADFS_Log("\n");

			ADFS_Log("Name: ");
			ADFS_Log(subP->GetName(bufAC));
			ADFS_Log("\n");

			ADFS_Log("Key Block: ");
			ADFS_Log_Number(GetRboShort(entry->key));
			ADFS_Log("\n");

			ADFS_Log("Blocks Used: ");
			ADFS_Log_Number(GetRboShort(entry->blocksUsed));
			ADFS_Log("\n");

			ADFS_Log("eof: ");
			ADFS_Log_Number(GetRbo3Bytes(entry->eof));
			ADFS_Log("\n");

			ADFS_Log("Access: ");
			ADFS_Log_Number((short)entry->access.destroyEnable);
			ADFS_Log(" ");
			ADFS_Log_Number((short)entry->access.renameEnable);
			ADFS_Log(" ");
			ADFS_Log_Number((short)entry->access.backup);
			ADFS_Log(" ");
			ADFS_Log_Number((short)entry->access.writeEnable);
			ADFS_Log(" ");
			ADFS_Log_Number((short)entry->access.readEnable);
			ADFS_Log("\n");

			ADFS_Log("Header's Key Block: ");
			ADFS_Log_Hex(GetRboShort(entry->header));
			ADFS_Log("\n");

			ADFS_Log("\n");

			dumpP->levelS++;
			subP->DumpFolder(dumpP);
			dumpP->levelS--;
		} else {
		}
//	}
		
	return err;
}

