// // hfstools - a Macintosh filesystem access tool // (C) Copyright 1993 by Equivalence // // This file part of hfs. // // hfs is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2, or (at your option) // any later version. // // hfs is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with hfs; see the file COPYING. If not, write to // the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. // // $Id: main.cxx,v 1.20 1994/08/19 10:48:09 craigs Exp $ // $Log: main.cxx,v $ // Revision 1.20 1994/08/19 10:48:09 craigs // Changed version number to 0.37 // // Revision 1.19 1994/07/20 12:38:27 craigs // Changed version number to 0.36 // // Revision 1.18 1994/07/10 03:16:18 craigs // Changed version to 0.35 // // Revision 1.17 1994/07/08 12:00:59 craigs // Fixed problem with displaying misleading error messages // Changed part command to display drive name rather than partition name // // Revision 1.16 1994/07/04 10:23:55 craigs // Changed version number to 0.33 // // Revision 1.15 1994/07/02 05:36:44 craigs // Fixed problems after NT/MSDOS port // // Revision 1.14 1994/07/02 05:04:21 craigs // Added support for CDROM drives under MSDOS // // Revision 1.13 1994/06/30 14:39:24 craigs // Changes for bigger blocks and partitions // // Revision 1.12 1994/01/11 02:29:25 craigs // Fixed warning when compiling at O6 level // // Revision 1.11 1994/01/11 00:44:13 craigs // Improved cat function and added options // Changed to accept any executable name starting with hfs // // Revision 1.10 1994/01/06 03:05:08 craigs // Final checkin to include GNU header // // Revision 1.9 1993/12/30 07:56:51 craigs // Changed to validate command before attempting to access the // HFS disk // // Revision 1.8 1993/12/23 22:43:56 craigs // Removed redundant error message on pwd // // Revision 1.7 1993/12/23 15:18:05 craigs // Completely re-organised to handle new args object, and moved // Ls and Copy functions to separate files // // Revision 1.6 1993/11/25 22:04:24 craigs // Added hpwd command and ability to print the version number // // Revision 1.5 1993/11/24 21:36:05 craigs // Various changes remove warnings under MSDOS/NT // by robertj // // Revision 1.4 1993/11/23 22:21:48 craigs // Fixed problem with volume name being corrupted in .macdir file // // Revision 1.3 1993/11/23 20:22:45 craigs // Added MSDOS/Windows compatibility // robertj // // Revision 1.1 1993/11/22 22:25:55 craigs // Initial revision // // // #include "config.h" #include #include #include #include "args.h" #include "btree.h" #include "error.h" #include "catalog.h" #include "fs.h" #include "paranoid.h" #include "status.h" #include "file.h" #include "cmd.h" #include "ls.h" #include "copy.h" #define VERSION_MSG "0.37" struct FunctionTableElement { char * name; CommandPtr function; }; StatusFile * status_file; ////////////////////////////////////////////// // // this routine is never called - it is just a correctly formed // function that can be used a placeholder for the command dispatcher // int PartitionFunction (ArgList &, Filesystem &) { return 0; } int RealPartitionFunction (ArgList & args, Volume & volume) { int err = volume.EnumeratePartitions(args.OptionSpecified('a') != 0); if (err != E_OK) { display_error ("error: partition table cannot be displayed", err); exit (1); } return 0; } ////////////////////////////////////////////// // // output a file to stdout // int CatFunction (ArgList & args, Filesystem & fs) { int flags; // // there can be only only argument // if (args.argc() != 1) { cout << "usage: hcat file\n"; return 0; } flags = 0; if (args.OptionSpecified('x')) flags |= MacFile::HexDump; if (args.OptionSpecified('t')) flags |= MacFile::ConvertToText; if (args.OptionSpecified('R')) flags |= MacFile::ResourceFork; // // find the file // FileBuffer fb; if (!fs.FindFile(fb, status_file->GetDir(), args[0])) { cerr << args[0] << ": file not found\n"; exit (1); } // // dump the file // MacFile file(fs); file.Open(fb, flags); file.CopyToOS(stdout); file.Close(); return 0; } ////////////////////////////////////////////// // // change directory // int CdFunction (ArgList & args, Filesystem & fs) { // // there can be only only argument // if (args.argc() != 1) { cout << "usage: hcd dir\n"; return 0; } // resolve the argument to a directory FileBuffer fb; if (!fs.ResolvePath(fb, args[0], status_file->GetDir())) exit (1); // set the current directory status_file->SetDir(fb.id); return 0; } ////////////////////////////////////////////// // // print current directory // int PwdFunction (ArgList & args, Filesystem & fs) { char * path; // // no arguments // if (args.argc() != 0) { cout << "usage: hpwd\n"; return 0; } // // get the current directory name, and print it // FileBuffer fb; fs.FindDir(fb, status_file->GetDir(), &path); cout << path << "\n"; return 0; } ////////////////////////////////////////////// // // table of possible commands vs procedures. This table must include // synonyms for argv[0] as well as argv[1] type commands // static FunctionTableElement function_table[] = { { "cd", CdFunction }, { "read", GetFunction }, { "ls", LsFunction }, { "cat", CatFunction }, { "dir", DirFunction }, { "pwd", PwdFunction }, { "part", PartitionFunction }, // empty routine!! { "hcd", CdFunction }, { "hread", GetFunction }, { "hls", LsFunction }, { "hcat", CatFunction }, { "hdir", DirFunction }, { "hpwd", PwdFunction }, { "hpart", PartitionFunction }, // empty routine!! { NULL, NULL } }; ////////////////////////////////////////////// // // main entry point // int main (int argc, char *argv[]) { ArgList args (argv[0]); Volume * volume; Filesystem fs; int err; char * disk_device; char * funcName; CommandPtr function = NULL; // // if the program is invoked by it's full name, do the correct thing // if (strncmp(args.GetProgname(), "hfs", 3) == 0) { if (argc == 1) { cout << "HFSTools v" << VERSION_MSG << "\n" << "(C) Copyright 1993 by Equivalence\n"; return 0; } else { funcName = argv[1]; argc -= 2; argv += 2; } } else { funcName = args.GetProgname(); argc--; argv++; } args.Parse(argc, argv, "ad:lp:txMR"); // // get ptr to the function to handle the command // for (int i = 0; function_table[i].function != NULL; i++) if (strcmp(funcName, function_table[i].name) == 0) { function = function_table[i].function; break; } // // give error message if no command found // if (function == NULL) { cerr << "error: unknown function \"" << funcName << "\"\n"; return 0; } // // get name of disk device from environment, or use default // if ((disk_device = args.GetOption('d')) == NULL) if ((disk_device = getenv(DISK_DEVICE_ENV)) == NULL) disk_device = DEFAULT_DISK_DEVICE; // // open the device we are about to mount // if (DeviceVolume::IsDeviceName(disk_device)) volume = new DeviceVolume(disk_device); else volume = new FileVolume(disk_device); // // HACK ALERT!!!!! // As the partition display program needs to access the raw device // without mounting, we dispatch the "part" command here. Notice that // the function pointed to by the dispatch table is not used - there is // another "real" partition display function that takes the volume rather // than the useless (at this stage) fs // if (function == PartitionFunction) return RealPartitionFunction(args, *volume); // // get number of partition from parameter or environment // char * part_str = NULL; int partition; if ((part_str = args.GetOption('p')) != NULL) { if ((partition = atoi(part_str)) <= 0) { cout << "error: argument to -p is not a valid partition number\n"; exit(2); } } else if ((part_str = getenv(PARTITION_ENV)) != NULL) { if ((partition = atoi(part_str)) <= 0) { cout << "error: " << PARTITION_ENV << " set to invalid partition number\n"; exit(2); } } else partition = -1; // // mount the filesystem // if ((err = fs.Mount (volume, partition)) != E_OK) { display_error("error: mount failed", err); exit(1); } // // read status file (if we have one) and get the // current directory name // status_file = new StatusFile(args.GetProgPath()); status_file->Read(); // // if the volume name has changed, then reset the current directory // { char * volume_name = fs.GetVolumeName(); if ((status_file->GetVolumeName() == NULL) || (strcmp(status_file->GetVolumeName(), volume_name) != 0)) { cerr << "Disk change detected - resetting current directory\n"; status_file->SetVolumeName(volume_name); status_file->SetDir(CatKeyRec::Root); } else delete volume_name; } // // ensure the current directory exists // { FileBuffer fb; if (!fs.FindDir(fb, status_file->GetDir())) { cerr << "Cannot change to current directory - resetting to root directory\n"; status_file->SetDir(CatKeyRec::Root); } } // // dispatch the function // int retval = (*function)(args, fs); status_file->Write(); return retval; }