
/**************************************************************************
 *                                                                        *
 *                            Save Names 1.3                              *
 *                           ----------------                             *
 *                                                                        *
 *  SaveNames is freely distributable but is copyrighted by its author,   *
 * Marcin Orlowski (carlos@felix.univ.szczecin.pl). For more information  *
 * read the short documentation included in this archive. SaveNames is    *
 * written in ANSI C, so may be compiled on any machine, except for pc    *
 * (do you see any sense? :). Unfortunately small changes must be done    *
 * befor you run compiler, so look below, and select your platform.       *
 * AMIGA side was tested on A4000, UNIX side was tested on IRIS INDIGO,   *
 * HP. The LINUX side was tested... on LINUX :-).                         *
 *                                                                        *
 * Use and enjoy.                                                         *
 *                                                                        *
 * Any suggestions, bugs, mails or anything else send to:                 *
 *                                                                        *
 * Marcin Orlowski                                                        *
 * Radomska 38                                                            *
 * 71-002 Szczecin                                                        *
 * Poland                                                                 *
 *                                                                        *
 * or via net:                                                            *
 *                                                                        *
 * Internet: carlos@felix.univ.szczecin.pl                                *
 * FidoNet:       Marcin Orlowski@2:481/22.2                              *
 * GlobalNet:     Marcin Orlowski@52:4800/6                               *
 *                                                                        *
 * or try Silver Dream!'s BBS (non-stop) at +48 91 540431                 *
 *                                                                        *
 *************************************************************************/

/* Define your favourite platform (except Amiga :-) */

#define AMIGA

/*                     NOTE: LINUX automagically defines UNIX by itself,
                               so you don't need to uncomment it by hand
#define AMIGA
#define UNIX
#define LINUX
*/

/* Uncomment this only for compilers requiring C&R declaration type */
/*
#define OLD_STYLE
*/

/*************************************************************************/

#ifdef AMIGA
char __stdiowin[] = "con:0/15/500/230/W.F.M.H. SaveNames 1.3";
#define CURRENTDIR ""
#include <sys/dir.h>

#ifndef EXIT_SUCCESS
#define EXIT_SUCCESS 0
#endif
#ifndef EXIT_WARN
#define EXIT_WARN 5
#endif
#ifndef EXIT_FAILURE
#define EXIT_FAILURE 20
#endif

/* Do not touch this if you don't know what you are doing! */
/*
#ifdef MAXNAMELEN
#undef MAXNAMELEN
#endif
#define MAXNAMELEN 108
*/
#endif

/*************************************************************************/

#ifdef LINUX
#include <unistd.h>
#ifndef UNIX
#define UNIX
#endif
#endif

/*************************************************************************/

#ifdef UNIX
#ifdef CURRENTDIR
#undef CURRENTDIR
#endif
#define CURRENTDIR "."
#define PARENTDIR ".."
#include <dirent.h>
#include <sys/types.h>
#endif

/*************************************************************************/

#include <sys/stat.h>
#include <fcntl.h>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE ~TRUE
#endif

/*************************************************************************/

#define	AMI_DD_OFS  853000				/* Capacity of various floppy disks   */
#define	AMI_DD_FFS  880000        /* This values may not fit exactly,   */
#define	AMI_HD_FFS 1780000        /* but it doesn't matter so much...   */
#define	PC_DD			  725000				/* In case of big number of files,    */
#define	PC_HD			 1455000	      /* the disk space is going down, 'cos */
                                  /* of file headers and similar things */

#define	PCNAME	12 								/* 8 + . + 3 */

FILE	*FileHandle = NULL;
DIR	*dfd;											/* directory descriptor */
int	fh;												/* FileHandle */
struct	dirent	*dptr;						/* dir entry */
struct	stat		*st = NULL;				/* file information */

char	TempBuff[PCNAME+1];				/* +1 because of trailing NULL */
char	CurrentDir[MAXNAMLEN+2];

struct	Entry	*FirstEntry= NULL;	/* for queue of entrires... */
struct  Entry	*LastEntry = NULL;
struct	Entry *TempEntry = NULL;
struct  Entry *Temp2		 = NULL;

struct	Entry											/* ... like this one...  */
{
	struct	Entry *Next;						/* Successor             */
	char		INode[PCNAME+1];				/* Almost unique file ID */
	char		Name[MAXNAMLEN+1];			/* Oryginal file name    */
};

int	Index;										/* Universal counter    */
int	Count = 0, SkipCount = 0;	/* Almost universal counters :) */
unsigned long TotalSize = 0;			/* Guess yourself... */
char	ErrorHeader = TRUE;
char	DecodeResult;

/*************************************************************************/

#ifdef OLD_STYLE
void main(args, argv)
int args;
char **argv;
#else
void main(int args, char **argv)
#endif
{
	printf("SaveNames 1.3 by Marcin Orlowski\n");
	printf("E-Mail: carlos@felix.univ.szczecin.pl\n\n");

	if(args != 3)
		{
#ifdef AMIGA
		if(args == 0)
			printf("** Can't be run from Workbench.\n\n");
#endif

#ifdef	UNIX
		printf("Type 'man SaveNames'");
#else
		printf("Read file 'SaveNames.doc'");
#endif

		printf(" to get whole documentation\n\n");

		if(strlen(argv[0]))
			printf("Usage: %s ", argv[0]);
		else
			printf("Shell Usage: SaveNames ");

		printf("Command DirName\n");
		printf("Command - type 'C'  or 'CODE' to crypt names\n");
		printf("          type '-C' or '-COUNT' to count disks usage only\n");
		printf("          type 'D'  or 'DECODE' to restore names\n");
		printf("          type '-D' or '-DECODE' for expanded restore\n");
		printf("DirName - process contents of this directory\n");

		exit(EXIT_FAILURE);
		}


	getcwd(CurrentDir, sizeof(CurrentDir));
	if(chdir(argv[2]))
		{
		printf("** Can't find directory.\n");
		exit(EXIT_FAILURE);
		}



	if(argv[1][0] == 'C' || argv[1][0] == 'c' || (argv[1][0] == '-' && argv[1][1] == 'C') || (argv[1][0] == '-' && argv[1][1] == 'c'))
		{
		if((dfd = opendir(CURRENTDIR)))
			{
			char	running = TRUE;

				FileHandle = NULL;
				if((FileHandle = fopen("WFMHFile.idx", "r")) == NULL)
					if((FileHandle = fopen("wfmhfile.idx", "r")) == NULL)
						FileHandle = fopen("WFMHFILE.IDX", "r");

			if(argv[1][0] == 'C' && argv[1][0] == 'c')
				{
				if(FileHandle)
					{
					fclose(FileHandle);
					printf("** Index file found in drawer '%s'.\n", argv[2]);
					printf("** It means you have already coded filenames.\n");
					printf("** Because this operation cannot be nested\n");
					printf("** it has been aborted. Watch your moves!\n");
					chdir(CurrentDir);
					exit(EXIT_FAILURE);
					}
				}


			if(argv[1][0] == '-')
				printf("Counting floppy disks usage ...\n");
			else
				printf("Coding filenames...\n");

			Count = 0;
			if((st = malloc(sizeof(struct stat))) == NULL)
				printf(" ** No length counting. No memory for structure.\n");

				while((dptr = readdir(dfd)) && running)
					{
#ifdef UNIX
					if((strcmp(dptr->d_name, CURRENTDIR) != 0) && (strcmp(dptr->d_name, PARENTDIR) != 0))
							{
#endif
						if((TempEntry = (struct Entry *)malloc(sizeof(struct Entry))))
							{
							strcpy(TempEntry->Name, dptr->d_name);
							sprintf(TempEntry->INode, "%lx.pcp", dptr->d_ino);

							if(!(FirstEntry))
								FirstEntry = TempEntry;
							else
								LastEntry->Next = TempEntry;
							LastEntry = TempEntry;
							TempEntry->Next = NULL;

							if(st)
								if(fh = open(dptr->d_name, O_RDONLY, 0))
									{
									if(fstat(fh, st) == 0)
										TotalSize += st->st_size;
									close(fh);
									}

							Count++;
							}
						else
							{
							printf("** Out of memory. %d files scanned.\n", Count);
							printf("** Skipping the rest of files.\n");
							running = FALSE;
							}
#ifdef UNIX
						}
#endif

					}

			closedir(dfd);

			if(st)
				{
				if(TotalSize != 0)
					{
					printf("\n Disks summary for %ld files (%ld bytes, %ld KB, %ld MB)\n\n", Count, TotalSize, (TotalSize/1024), (TotalSize/1048576));
					printf(" Disk type       Cnt  Free on last\n");
					printf(" ---------------------------------\n");
					printf(" Amiga DD (OFS) %3ld   %6ld KB\n", (AMI_DD_OFS + TotalSize) / AMI_DD_OFS, (AMI_DD_OFS * ((AMI_DD_OFS + TotalSize) / AMI_DD_OFS) - TotalSize)/1024);
					printf(" Amiga DD (FFS) %3ld   %6ld KB\n", (AMI_DD_FFS + TotalSize) / AMI_DD_FFS, (AMI_DD_FFS * ((AMI_DD_FFS + TotalSize) / AMI_DD_FFS) - TotalSize)/1024);
					printf(" Amiga HD (FFS) %3ld   %6ld KB\n", (AMI_HD_FFS + TotalSize) / AMI_HD_FFS, (AMI_HD_FFS * ((AMI_HD_FFS + TotalSize) / AMI_HD_FFS) - TotalSize)/1024);
					printf(" pc    DD       %3ld   %6ld KB\n", (PC_DD + TotalSize) / PC_DD, (PC_DD * ((PC_DD + TotalSize) / PC_DD) - TotalSize)/1024);
					printf(" pc    HD       %3ld   %6ld KB\n\n", (PC_HD + TotalSize) / PC_HD, (PC_HD * ((PC_HD + TotalSize) / PC_HD) - TotalSize)/1024);
					}
				else
					printf("No files - no summary :-(...\n");
				}
	
		if(st)
				{
				free(st);
				st = NULL;
				}

			if(argv[1][0] == '-')									/* We wanted summary only */
				{
				TempEntry = FirstEntry;
				while(TempEntry)
					{
					Temp2 = TempEntry->Next;
					free(TempEntry);
					TempEntry = Temp2;
					}
				chdir(CurrentDir);
				exit(EXIT_SUCCESS);
				}

			if(FileHandle = fopen("WFMHFile.idx", "w"))
				{
				Count = 0;
				TempEntry = FirstEntry;

				while(TempEntry)
					{
					if(rename(TempEntry->Name, TempEntry->INode))
						{
#ifdef UNIX
					if((strcmp(TempEntry->Name, CURRENTDIR) != 0) && (strcmp(TempEntry->Name, PARENTDIR) != 0))
							{
#endif
							if(ErrorHeader == TRUE)
								{
								printf("I can't rename following files:\n");
								printf("-------------------------------\n");
								ErrorHeader = FALSE;
								}
							printf("'%s'\n", TempEntry->Name);
							SkipCount++;
							}
#ifdef UNIX
						}
#endif
					else
						{
						fprintf(FileHandle, "%s%c%s\n", TempEntry->INode, 0x09, TempEntry->Name);
						Count++;
						}

					Temp2 = TempEntry->Next;
					free(TempEntry);
					TempEntry = Temp2;
					}

				fclose(FileHandle);
				if(Count)
					printf("%d files processed\n", Count);
				if(SkipCount)
					printf("%d files skipped\n", SkipCount);
				if(Count)
					printf("Done.\n");
				}
			else
				{
				TempEntry = FirstEntry;
				while(TempEntry);
					{
					Temp2 = TempEntry->Next;					
					free(TempEntry);
					TempEntry = Temp2;
					}
				printf("** Can't open index file to write 'WFMHFile.idx'.\n");
				exit(EXIT_FAILURE);
				}
			}
		else
			{
			printf("** Can't open directory '%s'.\n", argv[2]);
			exit(EXIT_FAILURE);
			}
		}


/*                             ########### DECODING PART BEGINS ##############   */

	else

		if(argv[1][0] == 'D' || argv[1][0] == 'd' || (argv[1][0] == '-' && argv[1][1] == 'D') || (argv[1][0] == '-' && argv[1][1] == 'd'))
			{
			if((TempEntry = malloc(sizeof(struct Entry))))
				{
				if((FileHandle = fopen("WFMHFile.idx", "r")) == NULL)
					if((FileHandle = fopen("wfmhfile.idx", "r")) == NULL)
						FileHandle = fopen("WFMHFILE.IDX", "r");

				if(FileHandle)
					{
					if(argv[1][0] == '-')
					printf("Decoding filenames in expanded mode...\n");
						else
					printf("Decoding filenames...\n");

					Count = 0;
					while(EOF != fscanf(FileHandle, "%s", TempEntry->INode))
						{

						do
							TempEntry->Name[0] = getc(FileHandle);
						while((TempEntry->Name[0] != 0xa) && (TempEntry->Name[0] != 9));

						for(Index=0; Index<MAXNAMLEN; Index++)
							{
							TempEntry->Name[Index] = fgetc(FileHandle);
							if(((TempEntry->Name[Index]) == 0xa) || (TempEntry->Name[Index] == EOF))
									break;
							}
						TempEntry->Name[Index] = 0x00;


					if(rename(TempEntry->INode, TempEntry->Name))
						{
						DecodeResult = FALSE;

						if(argv[1][0] == '-')
							{
							Index = 0;
							while(TempEntry->INode[Index] != '\0')
								{
								TempEntry->INode[Index] = tolower((int)TempEntry->INode[Index]);
								Index++;
								}
							if(rename(TempEntry->INode, TempEntry->Name))
								{
								Index = 0;
								while(TempEntry->INode[Index] != '\0')
									{
									TempEntry->INode[Index] = toupper((int)TempEntry->INode[Index]);
									Index++;
									}
								if(rename(TempEntry->INode, TempEntry->Name) == 0)
									{
									Count++;
									DecodeResult = TRUE;
									}
								}
							}

						if(DecodeResult == FALSE)
							{
							if(ErrorHeader == TRUE)
								{
								printf("I can't restore following files:\n");
								printf("--------------------------------\n");
								ErrorHeader = FALSE;
								}
							printf("'%s'\n", TempEntry->Name);
							SkipCount++;
							}
						}
					else
						Count++;
						}

					fclose(FileHandle);
					free(TempEntry);
					if(Count)
						printf("%d files restored\n", Count);
					if(SkipCount)
						printf("%d files skipped\n", SkipCount);
					if(Count)
						printf("Done.\n");

					if(SkipCount == 0)
						{
						if(remove("WFMHFile.idx") != 0)
							if(remove("wfmhfile.idx") != 0)
								if(remove("WFMHFILE.IDX") != 0)
									{
									printf("** Can't remove index file.\n");
#ifdef AMIGA
									exit(EXIT_WARN);
#endif
									}
						}
					}
				else
					{
					free(TempEntry);
					printf("** Can't find index file!\n");
					exit(EXIT_FAILURE);
					}
				}
			else
				{
				printf("** Can't allocate work buffer!\n");
				exit(EXIT_FAILURE);
				}

			}
		else
			{
			printf("** Unknown command.\n");
			exit(EXIT_FAILURE);
			}

	chdir(CurrentDir);
	exit(EXIT_SUCCESS);
}
