
/**************************************************************************
 *                                                                        *
 *                            Save Names 1.4                              *
 *                           ----------------                             *
 *                                                                        *
 *  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                     Tadek Knapik                       *
 * Radomska 38                         Duza Gora 35/88                    *
 * 71-002 Szczecin                     30-857 Krakow                      *
 * Poland                              Poland                             *
 *                                                                        *
 * or via net:                                                            *
 *                                                                        *
 * carlos@dedal.man.szczecin.pl        tadek@student.uci.agh.edu.pl       *
 * http://www.szczecin.pl/~carlos                                         *
 *                                                                        *
 * 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.4";
#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>
#include <math.h>         /* Tadek was here */

#ifndef RC_OK
#define RC_OK         0
#endif
#define RC_SPLITERROR 1
#define RC_CRAZY      2
#define RC_CRAZY_COOL 3
#ifndef RC_FAIL
#define RC_FAIL       4
#endif

#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 */
/* Tadek: 3 next #defines */

#define PC_HD_FIT 1440000      /* this is for max file sizes -  a little bit */
#define PC_DD_FIT 720000       /* lower, so it fits on disk for sure */

#define DISKS_MAX 999          /* you can't have more.. */

#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];      /* Original 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;

/* Tadek - declarations */

int splitname(char s[], char t[], int splitsize);
int rejoinname(char s[], char t[]);
int namecount(char s[], char t[], int diskcount);

FILE *SpareIdx = NULL;
char newname[MAXNAMLEN];
int rc = NULL;
int splitsize = NULL;
int SplitCount = NULL;

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

#ifdef OLD_STYLE
void main(args, argv)
int args;
char **argv;
#else
void main(int args, char **argv)
#endif
{
	printf("\n");
	printf("SaveNames 1.4 by Marcin Orlowski & Tadek Knapik\n");
	printf("E-Mail: carlos@dedal.man.szczecin.pl\n");
	printf("    or:  tadek@student.uci.agh.edu.pl\n\n");

	if((args < 3) || (args > 4))
		{
#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 <SplitSize>\n");
		printf("Command   - type 'C'  or 'CODE' to crypt names (and optionally split files) \n");
		printf("            type '-C' or '-COUNT' to count disks usage only\n");
		printf("            type 'D'  or 'DECODE' to restore names and rejoin files\n");
		printf("            type '-D' or '-DECODE' for expanded restore (also with rejoin)\n");
		printf("DirName   - process contents of this directory\n");
		printf("SplitSize - (optional) maximum size of output files (larger files will\n");
		printf("            be splitted) or just 'DD'/'HD' (default PC sizes)\n\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);
					}
				}


/*
** Tadek: <SplitSize> handling
*/
				if (args == 4)
					{
					if (((strcmp(argv[3],"DD")) == 0) || ((strcmp(argv[3],"dd")) == 0) || ((strcmp(argv[3],"Dd")) == 0) || ((strcmp(argv[3],"dD")) == 0))
						splitsize = PC_DD_FIT;
					else if (((strcmp(argv[3],"HD")) == 0) || ((strcmp(argv[3],"hd")) == 0) || ((strcmp(argv[3],"Hd")) == 0) || ((strcmp(argv[3],"hD")) == 0))
						splitsize = PC_HD_FIT;
					else
						splitsize = atoi(argv[3]);

						}
/*
** end of splitsize handling
*/

			if(argv[1][0] == '-')
				printf("Counting floppy disks usage ...\n");
			else
				{
				printf("Coding filenames");
				if (splitsize)          /* Tadek was here */
					printf(" (with splitsize %d bytes)", splitsize);
				printf("...\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)
					{
                    int KB = (TotalSize/1024);
                    int MB = (TotalSize/1048576);

					printf("\n Disks summary for %ld files (%ld bytes", Count, TotalSize);
					if(KB)  printf(", %d KB", KB);
					if(MB)  printf(", %d MB", MB);

					printf(")\n\n");
					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;

/*
**  Tadek: my function is put instead of rename(), and I messed a little
**         bit with the error handling
*/

				while(TempEntry)
					{
					if((rc = splitname(TempEntry->Name, TempEntry->INode, splitsize)) != RC_OK)
						{
#ifdef UNIX
					if((strcmp(TempEntry->Name, CURRENTDIR) != 0) && (strcmp(TempEntry->Name, PARENTDIR) != 0))
							{
#endif
							if(ErrorHeader == TRUE)
								{
								printf("I had troubles with following files:\n");
								printf("-------------------------------------\n");
								ErrorHeader = FALSE;
								}
							if (rc == RC_FAIL)
								{
								printf("Can't rename '%s'\n", TempEntry->Name);
								SkipCount++;
								}
							else
								{
								if ((rc == RC_SPLITERROR) || (rc == RC_CRAZY_COOL))
									{
									fprintf(FileHandle, "%s%c%s\n", TempEntry->INode, 0x09, TempEntry->Name);
									Count++;
									}
								if (rc == RC_SPLITERROR)
									{
									printf("Can't split '%s'\n", TempEntry->Name);
									}
								else if ((rc == RC_CRAZY) || (rc == RC_CRAZY_COOL))
									printf("Splitsize too small for '%s'\n", TempEntry->Name);
								}
							}
#ifdef UNIX
						}
#endif
					else
						{
						fprintf(FileHandle, "%s%c%s\n", TempEntry->INode, 0x09, TempEntry->Name);
						Count++;
						}

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

/*
**  Tadek: Processed files report - changed a little bit
*/

				fclose(FileHandle);
				if(Count)
					if(SplitCount)
						printf("%d files processed (%d of them splitted)\n", Count, SplitCount);
					else
						{
						printf("%d files processed", Count);
						if (splitsize)
							printf(" (none splitted)");
						printf("\n");
						}
				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");
				chdir(CurrentDir);
				exit(EXIT_FAILURE);
				}
			}
		else
			{
			printf("** Can't open directory '%s'.\n", argv[2]);
					chdir(CurrentDir);
			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;

/*
** Tadek: again my function instead of rename()
*/


					if(rejoinname(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(rejoinname(TempEntry->INode, TempEntry->Name))
								{
								Index = 0;
								while(TempEntry->INode[Index] != '\0')
									{
									TempEntry->INode[Index] = toupper((int)TempEntry->INode[Index]);
									Index++;
									}
								if(rejoinname(TempEntry->INode, TempEntry->Name) == 0)
									{
									Count++;
									DecodeResult = TRUE;
									}
								}
							}

						if(DecodeResult == FALSE)
							{
							if(ErrorHeader == TRUE)
								{
								printf("I can't restore following files:\n");
								printf("--------------------------------\n");
								SpareIdx = fopen("WFMHFil2.idx", "w");
								ErrorHeader = FALSE;
								}
							printf("'%s'\n", TempEntry->Name);
							SkipCount++;
							if (SpareIdx)
								fprintf(SpareIdx, "%s%c%s\n", TempEntry->INode, 0x09, TempEntry->Name);
							}
						}
					else
						Count++;
						}

					fclose(FileHandle);
					free(TempEntry);
					if(Count)
						{
						printf("%d files restored", Count);
						if (SplitCount)
							printf(" (%d of them rejoined)", SplitCount);
						printf("\n");
						}
					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");
									chdir(CurrentDir);
#ifdef AMIGA
									exit(EXIT_WARN);
#endif
									}
						}
					else
						{
						if (SpareIdx)
							{
							if(remove("WFMHFile.idx") != 0)
								if(remove("wfmhfile.idx") != 0)
									if(remove("WFMHFILE.IDX") != 0)
										{
										printf("** Can't remove old index file.\n");
										chdir(CurrentDir);
#ifdef AMIGA
										exit(EXIT_WARN);
#endif
										}
							fclose(SpareIdx);
							SpareIdx = NULL;
							if ((rename("WFMHFil2.idx", "WFMHFile.idx")) != 0)
								{
								printf("** Can't rename new index.\n");
								chdir(CurrentDir);
#ifdef AMIGA
								exit(EXIT_WARN);
#endif
								}
							}
						}
					}
				else
					{
					free(TempEntry);
					printf("** Can't find index file!\n");
					chdir(CurrentDir);
					exit(EXIT_FAILURE);
					}
				}
			else
				{
				printf("** Can't allocate work buffer!\n");
				chdir(CurrentDir);
				exit(EXIT_FAILURE);
				}

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

	chdir(CurrentDir);
	exit(EXIT_SUCCESS);
}

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

/*
** Tadek - functions
**
** return 0 for success
*/

#ifdef OLD_STYLE
int splitname(readname, basename, splitsize)
char readname[];
char basename[];
int splitsize;
#else
int splitname(char readname[], char basename[], int splitsize)
#endif
{

	FILE *RHandle = NULL;
	FILE *WHandle = NULL;

	int c, i, j, disks, diskcount;
	div_t d;

	i = RC_FAIL;
	if (splitsize != 0)
		{
		if((st = malloc(sizeof(struct stat))) == NULL)
			{
			if ((rename(readname, basename)) == 0)
				i = RC_SPLITERROR;
			return i;
			}
		if(((stat(readname, st)) == 0) && (st->st_size > splitsize))
			{
			if((RHandle = fopen(readname, "r")) != 0)
				{
				d = div(st->st_size, splitsize);
				if(st)
					{
					free(st);
					st = NULL;
					}
				disks = d.quot;
				if (d.rem != 0)
					++disks;
				if (disks > DISKS_MAX)
					{
					fclose(RHandle);
					i = RC_CRAZY;
					if ((rename(readname, basename)) == 0)
						i = RC_CRAZY_COOL;
					return i;
					}
				for (diskcount = 0; diskcount < disks; ++diskcount)
					{
					if ((namecount(basename, newname, diskcount) == 0) || ((WHandle = fopen(newname, "w")) == 0))
						{
						fclose(RHandle);
						if ((rename(readname, basename)) == 0)
							i = RC_SPLITERROR;
						return i;
						}
					for (j = 0; (j < splitsize) && ((c=fgetc(RHandle)) != EOF); ++j)
						{
						if ((fputc(c, WHandle)) == EOF)
							{
							fclose(RHandle);
							fclose(WHandle);
							remove(newname);
							if ((rename(readname, basename)) == 0)
								i = RC_SPLITERROR;
							return i;
							}
						}   
					fclose(WHandle);
					if (c == EOF)
						{
						fclose(RHandle);
						if (diskcount == disks-1)
							{
							remove(readname);
							i = RC_OK;
							SplitCount++;
							}
						else
							{
							remove(newname);
							if ((rename(readname, basename)) == 0)
								i = RC_SPLITERROR;
							}
						return i;
						}
					}
				fclose(RHandle);
				remove(readname);
				}
			if(st)
				{
				free(st);
				st = NULL;
				}
			if ((rename(readname, basename)) == 0)
				i = RC_SPLITERROR;
			return i;
			}
		if(st)
			{
			free(st);
			st = NULL;
			}
		}
	if ((rename(readname, basename)) == 0)
		i = RC_OK;
	return i;
}


/*
**  now, let's join files (if needed)
*/

#ifdef OLD_STYLE
int rejoinname(basename, realname)
char basename[];
char realname[];
#else
int rejoinname(char basename[], char realname[])
#endif
{

	int i, c, diskcount;
	FILE *RHandle = NULL;
	FILE *WHandle = NULL;

	i = RC_FAIL;

	if ((rename(basename, realname)) == 0)
		{
		i = RC_OK;
		return i;
		}
	for (diskcount = 0; ((namecount(basename, newname, diskcount)) != 0) && ((RHandle = fopen(newname, "r")) !=0); ++diskcount)
		{
		if (WHandle == NULL)
			if ((WHandle = fopen(realname, "w")) == 0)
				{
				fclose(RHandle);
				return i;
				}
		while ((c=fgetc(RHandle)) != EOF)
			fputc(c, WHandle);
		fclose(RHandle);
		remove(newname);
		}
	if (WHandle)
		{
		fclose(WHandle);
		SplitCount++;
		i = RC_OK;
		}
	return i;

}


/*
**  This is for constructing numbered file names
*/

#ifdef OLD_STYLE
int namecount(base, newname, suffix)
char base[];
char newname[];
int suffix;
#else
int namecount(char base[], char newname[], int suffix)
#endif
{

	int i;

	strcpy(newname, base);

	for (i = 0; newname[i] != 0; ++i)
		;
	--i;
	if (suffix > 9)
		--i;
	if (suffix > 99)
		--i;
	if (suffix > DISKS_MAX)
		return 0;

	if ((sprintf(&newname[i],"%d", suffix)) > 3)
		return 0;
	return i;

}

