Removing the BeOS specific 'ar' utility -- no longer needed,

says Chris Herborth.
This commit is contained in:
Guido van Rossum 1998-12-09 22:24:27 +00:00
parent 030d2ec16c
commit 65e164f81d
16 changed files with 0 additions and 3334 deletions

View File

@ -1,48 +0,0 @@
######################################################################
# Makefile for ar
#
# Dec. 14, 1997 Chris Herborth (chrish@kagi.com)
#
# $Id$
######################################################################
AR_VERSION=1.1
# Make variables
CC=mwcc
LD=mwcc
CFLAGS=-w9 -rostr -O3 -g
CFLAGS_O=-w9 -rostr -O7 -opt schedule604
LDFLAGS=-g -map ar.xMAP
LDFLAGS_O=
INSTALL=install -m 755
DESTINATION=/boot/home/config/bin
PARTS=main.o mwlib.o commands.o copy_attrs.o
all: ar
nodebug:
-rm -f ar $(PARTS) ar.dbg ar.xSYM
$(MAKE) CFLAGS="$(CFLAGS_O) -DNO_DEBUG" LDFLAGS="$(LDFLAGS_O)" ar
ar: $(PARTS)
$(LD) $(LDFLAGS) -o $@ $(PARTS)
install: ar
$(INSTALL) ar $(DESTINATION)
ln -sf $(DESTINATION)/ar $(DESTINATION)/ar-posix
clean:
-rm -f $(PARTS) ar ar.dbg ar.xSYM
zip:
(cd .. ; zip -9ry ar-$(AR_VERSION).zip ar-$(AR_VERSION) \
-x ar-$(AR_VERSION)/RCS -x ar-$(AR_VERSION)/docs/RCS \
-x ar-$(AR_VERSION)/RCS/\* -x ar-$(AR_VERSION)/docs/RCS/\*)
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $@

View File

@ -1 +0,0 @@
docs/ar.html

View File

@ -1,29 +0,0 @@
ar - POSIX 1003.2 interface to library files
Here's the source and PowerPC binary for a POSIX 1003.2 interface "ar"
command; this is extremely useful when you're porting complex UNIX/POSIX
software to BeOS for PowerPC (I originally wrote it to support my Python
port).
To build/install ar, do this in a Terminal:
make nodebug install
This will create ar and ar-posix (a symlink to ar) in ~/config/bin. The
ar-posix symlink is to make things a little easier if you happen to
have GeekGadgets (see www.ninemoons.com) installed; it comes with an
ar that only works on objects/libraries produced by GNU C for BeOS.
To use the POSIX ar with your port, do something like this:
AR=ar-posix ./configure ... normal configure arguments ...
and then:
make AR=ar-posix
You may need to check the Makefiles; people seem to be quite sloppy about
using just plain "ar cr libfoo.a ..." instead of "$(AR) cr libfoo.a ...".
- Chris Herborth, April 18, 1998
(chrish@kagi.com)

Binary file not shown.

View File

@ -1,461 +0,0 @@
File: 0 "/boot/src/ar-1.0/main.c"
File: 1 "/boot/src/ar-1.0/mwlib.c"
File: 2 "/boot/src/ar-1.0/commands.c"
File: 3 "/boot/src/ar-1.0/copy_attrs.c"
File: 5 "/boot/rel/src/kit/glue/common/global_destructor_chain.c"
File: 6 "/boot/rel/src/kit/glue/ppc/runtime.c"
File: 9 "/boot/rel/src/kit/glue/common/init_term_dyn.c"
File: 10 "/boot/rel/src/kit/glue/common/start_dyn.c"
File: 11 "/boot/develop/lib/ppc/libroot.so"
Files that were not referenced:
"libbe.so"
"libtracker.so"
"libmedia.so"
"libnet.so"
"libnetdev.so"
"libdevice.so"
"libmidi.so"
"libgame.so"
"libatalk.so"
"libmail.so"
Code section, size = 16672 bytes
000000 PR .__sinit file = "*Linker-Generated*"
00001C PR .usage file = "main.c"
000050 PR .version
000094 PR .check_command
000128 PR .main
0005A0 PR .load_MW_lib file = "mwlib.c"
000A1C PR .load_MWLibFile
000BAC PR .fwrite_big32
000C10 PR .fwrite_big32_seek
000CA4 PR .add_object_sizes
000DA4 PR .setfiletype
000EA8 PR .write_MW_lib
001850 PR .do_match file = "commands.c"
001958 PR .do_delete
001A84 PR .delete_lib_entry
001C5C PR .do_print
001D98 PR .print_lib_entry
001E90 PR .load_lib_file
0020F4 PR .do_replace
0023B8 PR .add_lib_entry
00256C PR .replace_lib_entry
00272C PR .do_table
002868 PR .table_lib_entry
0029E8 PR .do_extract
002B24 PR .extract_lib_entry
002E20 PR .copy_attrs file = "copy_attrs.c"
00306C PR .__destroy_global_chain file = "global_destructor_chain.c"
0030C0 PR .__RTOC file = "init_term_dyn.c"
0030C8 PR ._init_routine_
003118 PR ._term_routine_
003148 PR .__start file = "start_dyn.c"
003204 GL .__register_fragment file = "*Linker-Generated*"
00321C GL .find_thread
003234 GL .memcpy
00324C GL ._call_init_routines_
003264 GL .printf
00327C GL .exit
003294 GL .getopt
0032AC GL .malloc
0032C4 GL .__assertion_failed
0032DC GL .fprintf
0032F4 GL .fopen
00330C GL .fread
003324 GL .fseek
00333C GL .fgets
003354 GL .strdup
00336C GL .fclose
003384 GL .strrchr
00339C GL .strcmp
0033B4 GL .free
0033CC GL .memset
0033E4 GL .access
0033FC GL .stat
003414 GL ._errnop
00342C GL .strerror
003444 GL .strlen
00345C GL .sprintf
003474 GL .unlink
00348C GL .rename
0034A4 GL .fwrite
0034BC GL .ftell
0034D4 GL .chmod
0034EC GL .open
003504 GL .close
00351C GL .fs_fopen_attr_dir
003534 GL .fs_read_attr_dir
00354C GL .fs_stat_attr
003564 GL .fs_read_attr
00357C GL .fs_write_attr
003594 GL .fflush
0035AC GL .realloc
0035C4 GL .localtime
0035DC GL .strftime
0035F4 GL .getgid
00360C GL .getuid
003624 GL .utime
00363C GL ._thread_do_exit_notification
003654 GL .__unregister_fragment
00366C GL .__ptr_glue file = "runtime.c"
003680 RO @10 file = "main.c"
003690 RO @13
0036B4 RO @16
0036D8 RO @17
0036FC RO @18
003739 RO @30
003769 RO @109
00378A RO @110
0037A2 RO @111
0037BA RO @112
0037D3 RO @113
0037DD RO @114
0037FD RO @115
003815 RO @116
003829 RO @117
00383D RO @118
003871 RO @119
00388C RO @120
0038A5 RO @121
0038B9 RO @78 file = "mwlib.c"
0038C3 RO @79
0038CB RO @80
0038DA RO @81
0038DC RO @98
0038E7 RO @99
0038F5 RO @104
0038FE RO @122
003908 RO @123
003913 RO @124
00391E RO @133
003947 RO @134
003951 RO @135
00397B RO @235
003980 RO @236
0039AC RO @237
0039C3 RO @238
0039F5 RO @239
0039F9 RO @240
003A12 RO @241
003A33 RO @242
003A35 RO @243
003A56 RO @244
003A7B RO @245
003AA7 RO @246
003AD1 RO @247
003AF0 RO @248
003B14 RO @249
003B3D RO @250
003B69 RO @251
003B90 RO @252
003BBB RO @253
003BD8 RO @254
003BF1 RO @255
003C11 RO @29 file = "commands.c"
003C1B RO @30
003C26 RO @31
003C31 RO @32
003C3B RO @53
003C4E RO @54
003C65 RO @55
003C7D RO @81
003C9E RO @82
003CA6 RO @120
003CAE RO @121
003CC5 RO @142
003CD4 RO @143
003CDF RO @144
003CF6 RO @145
003D0C RO @146
003D2E RO @147
003D30 RO @148
003D47 RO @149
003D5E RO @198
003D6F RO @199
003D89 RO @200
003DAA RO @222
003DCF RO @223
003DE8 RO @224
003E12 RO @225
003E1A RO @242
003E39 RO @243
003E65 RO @244
003E6D RO @284
003E85 RO @285
003E88 RO @286
003E9F RO @287
003EBE RO @288
003EC9 RO @289
003ECD RO @343
003EE6 RO @344
003EEE RO @345
003EF0 RO @346
003F11 RO @347
003F27 RO @348
003F53 RO @349
003F7E RO @350
003F97 RO @43 file = "copy_attrs.c"
003FA6 RO @44
003FB3 RO @45
003FC4 TI @14 file = "main.c"
003FD0 TI @19
003FDC TI @32
003FE8 TI @124
003FF4 TI @82 file = "mwlib.c"
004000 TI @100
00400C TI @105
004018 TI @111
004024 TI @125
004030 TI @136
00403C TI @256
004048 TI @33 file = "commands.c"
004054 TI @56
004060 TI @83
00406C TI @110
004078 TI @122
004084 TI @150
004090 TI @201
00409C TI @226
0040A8 TI @245
0040B4 TI @272
0040C0 TI @290
0040CC TI @317
0040D8 TI @351
0040E4 TI @46 file = "copy_attrs.c"
0040F0 TI @7 file = "global_destructor_chain.c"
0040FC TI @2 file = "init_term_dyn.c"
004108 TI @4
004114 TI @17 file = "start_dyn.c"
Data section, size = 1084 bytes (TOC anchor = 000000)
000000 TC fs_write_attr file = "*Linker-Generated*"
000004 TC strftime
000008 TC fwrite
00000C TC sprintf
000010 TC open
000014 TC fread
000018 TC fs_fopen_attr_dir
00001C TC fseek
000020 TC strrchr
000024 TC free
000028 TC printf
00002C TC ftell
000030 TC exit
000034 TC strerror
000038 TC __register_fragment
00003C TC memcpy
000040 TC strcmp
000044 TC strlen
000048 TC _call_init_routines_
00004C TC strdup
000050 TC _files
000054 TC fgets
000058 TC malloc
00005C TC find_thread
000060 TC close
000064 TC memset
000068 TC chmod
00006C TC fopen
000070 TC stat
000074 TC fs_read_attr
000078 TC access
00007C TC fs_read_attr_dir
000080 TC unlink
000084 TC getopt
000088 TC getgid
00008C TC __unregister_fragment
000090 TC _errnop
000094 TC fprintf
000098 TC optind
00009C TC __assertion_failed
0000A0 TC rename
0000A4 TC utime
0000A8 TC getuid
0000AC TC fs_stat_attr
0000B0 TC fflush
0000B4 TC _thread_do_exit_notification
0000B8 TC fclose
0000BC TC localtime
0000C0 TC realloc
0000C4 TC __global_destructor_chain
0000C8 TC __exception_table_end__
0000CC TC __exception_table_start__
0000D0 TC __data_end__
0000D4 TC __data_start__
0000D8 TC __code_end__
0000DC TC __code_start__
0000E0 TC __main_thread_id
0000E4 TC environ
0000E8 TC argv_save
0000EC TC @123 file = "main.c"
0000F0 TC @122
0000F4 TC @121
0000F8 TC @120
0000FC TC @119
000100 TC @118
000104 TC @117
000108 TC @116
00010C TC @115
000110 TC @114
000114 TC @113
000118 TC @112
00011C TC @111
000120 TC @110
000124 TC @109
000128 TC @31
00012C TC @30
000130 TC @18
000134 TC @17
000138 TC @16
00013C TC @13
000140 TC @255 file = "mwlib.c"
000144 TC @254
000148 TC @253
00014C TC @252
000150 TC @251
000154 TC @250
000158 TC @249
00015C TC @248
000160 TC @247
000164 TC @246
000168 TC @245
00016C TC @244
000170 TC @243
000174 TC @242
000178 TC @241
00017C TC @240
000180 TC @239
000184 TC @238
000188 TC @237
00018C TC @236
000190 TC @235
000194 TC @135
000198 TC @134
00019C TC @133
0001A0 TC @124
0001A4 TC @123
0001A8 TC @122
0001AC TC @104
0001B0 TC @99
0001B4 TC @98
0001B8 TC @81
0001BC TC @80
0001C0 TC @79
0001C4 TC @78
0001C8 TC @350 file = "commands.c"
0001CC TC @349
0001D0 TC @348
0001D4 TC @347
0001D8 TC @346
0001DC TC @345
0001E0 TC @344
0001E4 TC @343
0001E8 TC @289
0001EC TC @288
0001F0 TC @287
0001F4 TC @286
0001F8 TC @285
0001FC TC @284
000200 TC @244
000204 TC @243
000208 TC @242
00020C TC @225
000210 TC @224
000214 TC @223
000218 TC @222
00021C TC @200
000220 TC @199
000224 TC @198
000228 TC @149
00022C TC @148
000230 TC @147
000234 TC @146
000238 TC @145
00023C TC @144
000240 TC @143
000244 TC @142
000248 TC @121
00024C TC @120
000250 TC @82
000254 TC @81
000258 TC @55
00025C TC @54
000260 TC @53
000264 TC @32
000268 TC @31
00026C TC @30
000270 TC @29
000274 TC @45 file = "copy_attrs.c"
000278 TC @44
00027C TC @43
000280 TC magic_template file = "start_dyn.c"
000284 TC default_environ
000288 TD ar_version_id file = "main.c"
00028C TD fragmentID file = "init_term_dyn.c"
000290 DS _term_routine_ file = "init_term_dyn.c"
000298 DS _init_routine_
0002A0 DS __start file = "start_dyn.c"
0002A8 RW @31 file = "main.c"
0002FC RW @123
000388 RW @122
000414 RW magic_template file = "start_dyn.c"
00041C RW @13
00042C RW default_environ
000434 RW __global_destructor_chain file = "global_destructor_chain.c"
Import container "libroot.so"
Current Version = 00000000, Old Implementation = 00000000
000000 DS fs_write_attr
000001 DS strftime
000002 DS fwrite
000003 DS sprintf
000004 DS open
000005 DS fread
000006 DS fs_fopen_attr_dir
000007 DS fseek
000008 DS strrchr
000009 DS free
00000A RW environ
00000B DS printf
00000C DS ftell
00000D DS exit
00000E DS strerror
00000F DS __register_fragment
000010 DS memcpy
000011 DS strcmp
000012 DS strlen
000013 DS _call_init_routines_
000014 DS strdup
000015 RW argv_save
000016 RW _files
000017 DS fgets
000018 DS malloc
000019 DS find_thread
00001A DS close
00001B DS memset
00001C DS chmod
00001D DS fopen
00001E DS stat
00001F DS fs_read_attr
000020 DS access
000021 DS fs_read_attr_dir
000022 DS unlink
000023 DS getopt
000024 DS getgid
000025 DS __unregister_fragment
000026 DS _errnop
000027 DS fprintf
000028 RW optind
000029 DS __assertion_failed
00002A DS rename
00002B DS utime
00002C RW __main_thread_id
00002D DS getuid
00002E DS fs_stat_attr
00002F DS fflush
000030 DS _thread_do_exit_notification
000031 DS fclose
000032 DS localtime
000033 DS realloc

View File

@ -1,809 +0,0 @@
/*
** commands.c - POSIX 1003.2 "ar" command
**
** This isn't a pure POSIX 1003.2 ar; it only manipulates Metrowerks
** Library files, not general-purpose POSIX 1003.2 format archives.
**
** Dec. 14, 1997 Chris Herborth (chrish@kagi.com)
**
** This code is donated to the PUBLIC DOMAIN. You can use, abuse, modify,
** redistribute, steal, or otherwise manipulate this code. No restrictions
** at all. If you laugh at this code, you can't use it.
**
** This "ar" was implemented using IEEE Std 1003.2-1992 as the basis for
** the interface, and Metrowerk's published docs detailing their library
** format. Look inside for clues about how reality differs from MW's
** documentation on BeOS...
*/
#include <support/Errors.h>
#include <support/byteorder.h>
#ifndef NO_DEBUG
#include <assert.h>
#define ASSERT(cond) assert(cond)
#else
#define ASSERT(cond) ((void)0)
#endif
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <limits.h>
#include <string.h>
#include <utime.h>
#include <errno.h>
#include <sys/stat.h>
#include "mwlib.h"
#include "commands.h"
#ifndef FALSE
#define FALSE (0)
#endif
#ifndef TRUE
#define TRUE (!FALSE)
#endif
static const char *rcs_version_id = "$Id$";
/* ----------------------------------------------------------------------
** Local functions
**
** do_match() - find the index of the file, if it's in the archive; return
** TRUE if found, else FALSE
**/
static int do_match( MWLib *lib, const char *file, int *idx );
static int do_match( MWLib *lib, const char *file, int *idx )
{
int which = 0;
char *name_ptr;
ASSERT( lib != NULL );
ASSERT( file != NULL );
ASSERT( idx != NULL );
/* Skip over the path, if any, so we can compare just the file name.
*/
name_ptr = strrchr( file, '/' );
if( name_ptr == NULL ) {
name_ptr = (char *)file;
} else {
name_ptr++;
}
for( which = 0; which < lib->header.num_objects; which++ ) {
if( !strcmp( name_ptr, lib->names[which] ) ) {
*idx = which;
return TRUE;
}
}
return FALSE;
}
/* ----------------------------------------------------------------------
** Delete an archive member.
**
** This isn't really optimal; you could make a more efficient version
** using a linked list instead of arrays for the data. This was easier
** to write, and speed shouldn't be that big a deal here... you're not
** likely to be dealing with thousands of files.
*/
static status_t delete_lib_entry( MWLib *lib, int idx, int verbose );
status_t do_delete( const char *archive_name, char **files, int verbose )
{
status_t retval = B_OK;
MWLib lib;
int idx = 0;
int which = 0;
ASSERT( archive_name != NULL );
if( files == NULL ) {
fprintf( stderr, "ar: %s, nothing to do\n", archive_name );
return B_ERROR;
}
retval = load_MW_lib( &lib, archive_name );
if( retval != B_OK ) {
switch( retval ) {
case B_FILE_NOT_FOUND:
fprintf( stderr, "ar: %s, file not found\n", archive_name );
return retval;
break;
default:
return retval;
break;
}
}
/* Delete the specified files.
*/
for( idx = 0; files[idx] != NULL; idx++ ) {
if( do_match( &lib, files[idx], &which ) ) {
retval = delete_lib_entry( &lib, which, verbose );
}
which = 0;
}
/* Write the new file.
*/
retval = write_MW_lib( &lib, archive_name );
return retval;
}
static status_t delete_lib_entry( MWLib *lib, int which, int verbose )
{
uint32 new_num;
MWLibFile *new_files = NULL;
char **new_names = NULL;
char **new_data = NULL;
int ctr = 0;
int idx = 0;
ASSERT( lib != NULL );
ASSERT( which <= lib->header.num_objects );
new_num = lib->header.num_objects - 1;
new_files = (MWLibFile *)malloc( new_num * ( sizeof( MWLibFile ) ) );
new_names = (char **)malloc( new_num * ( sizeof( char * ) ) );
new_data = (char **)malloc( new_num * ( sizeof( char * ) ) );
if( new_files == NULL || new_names == NULL || new_data == NULL ) {
return B_NO_MEMORY;
}
/* Copy the contents of the old lib to the new lib, skipping the one
** we want to delete.
*/
for( ctr = 0; ctr < lib->header.num_objects; ctr++ ) {
if( ctr != which ) {
memcpy( &(new_files[idx]), &(lib->files[ctr]),
sizeof( MWLibFile ) );
new_names[idx] = lib->names[ctr];
new_data[idx] = lib->data[ctr];
idx++;
} else {
/* Free up the name and data.
*/
if( verbose ) {
printf( "d - %s\n", lib->names[ctr] );
}
free( lib->names[idx] );
lib->names[idx] = NULL;
free( lib->data[idx] );
lib->data[idx] = NULL;
}
}
/* Free up the old lib's data.
*/
free( lib->files );
free( lib->names );
free( lib->data );
lib->files = new_files;
lib->names = new_names;
lib->data = new_data;
lib->header.num_objects = new_num;
return B_OK;
}
/* ----------------------------------------------------------------------
** Print an archive member to stdout.
*/
static status_t print_lib_entry( MWLib *lib, int idx, int verbose );
status_t do_print( const char *archive_name, char **files, int verbose )
{
status_t retval = B_OK;
MWLib lib;
int idx = 0;
ASSERT( archive_name != NULL );
retval = load_MW_lib( &lib, archive_name );
if( retval != B_OK ) {
switch( retval ) {
case B_FILE_NOT_FOUND:
fprintf( stderr, "ar: %s, file not found\n", archive_name );
return retval;
break;
default:
return retval;
break;
}
}
if( files == NULL ) {
/* Then we print the entire archive.
*/
for( idx = 0; idx < lib.header.num_objects; idx++ ) {
retval = print_lib_entry( &lib, idx, verbose );
}
} else {
/* Then we print the specified files.
*/
int which = 0;
for( idx = 0; files[idx] != NULL; idx++ ) {
if( do_match( &lib, files[idx], &which ) ) {
retval = print_lib_entry( &lib, which, verbose );
}
which = 0;
}
}
return retval;
}
static status_t print_lib_entry( MWLib *lib, int idx, int verbose )
{
int recs;
ASSERT( lib != NULL );
if( verbose ) {
printf( "\n<%s>\n\n", lib->names[idx] );
}
recs = fwrite( lib->data[idx], lib->files[idx].object_size, 1, stdout );
fflush( stdout );
if( recs != 1 ) {
fprintf( stderr, "error printing %s, %s\n", lib->names[idx],
strerror( errno ) );
return B_OK;
}
return B_OK;
}
/* ----------------------------------------------------------------------
** Add/replace/update files in an archive.
*/
static status_t add_lib_entry( MWLib *lib, const char *filename, int verbose );
static status_t replace_lib_entry( MWLib *lib, const char *filename,
int idx, int verbose );
static status_t load_lib_file( const char *filename,
char **data, MWLibFile *info );
static status_t load_lib_file( const char *filename,
char **data, MWLibFile *info )
{
status_t retval = B_OK;
struct stat s;
FILE *fp;
uint32 recs;
ASSERT( filename != NULL );
ASSERT( info != NULL );
/* Initialize the info area.
*/
info->m_time = (time_t)0; /* Only this... */
info->off_filename = 0;
info->off_fullpath = 0;
info->off_object = 0;
info->object_size = 0; /* ... and this will actually be updated. */
/* stat() the file to get the info we need.
*/
retval = stat( filename, &s );
if( retval != 0 ) {
fprintf( stderr, "ar: can't stat %s, %s\n", filename,
strerror( errno ) );
return B_FILE_NOT_FOUND;
}
/* Possible errors here; if you have an object that's larger
** than a size_t can hold (malloc() can only allocate a size_t size,
** not a full off_t)...
*/
if( s.st_size > (off_t)ULONG_MAX ) {
fprintf( stderr, "ar: %s is too large!\n", filename );
return B_NO_MEMORY;
}
/* Allocate enough memory to hold the file data.
*/
*data = (char *)malloc( (size_t)s.st_size );
if( *data == NULL ) {
fprintf( stderr, "ar: can't allocate memory for %s\n", filename );
return B_NO_MEMORY;
}
/* Read the file's data.
*/
fp = fopen( filename, "r" );
if( fp == NULL ) {
fprintf( stderr, "ar: can't open %s, %s\n", filename,
strerror( errno ) );
retval = B_FILE_NOT_FOUND;
goto free_data_return;
}
recs = fread( *data, (size_t)s.st_size, 1, fp );
if( recs != 1 ) {
fprintf( stderr, "ar: can't read %s, %s\n", filename,
strerror( errno ) );
retval = B_IO_ERROR;
goto close_fp_return;
}
fclose( fp );
/* Now that all the stuff that can fail has succeeded, fill in the info
** we need.
*/
info->m_time = s.st_mtime;
info->object_size = (uint32)s.st_size;
return B_OK;
/* How we should return if an error occurred.
*/
close_fp_return:
fclose( fp );
free_data_return:
free( *data );
*data = NULL;
return retval;
}
status_t do_replace( const char *archive_name, char **files, int verbose,
int create, int update )
{
status_t retval = B_OK;
MWLib lib;
int idx = 0;
int which = 0;
ASSERT( archive_name != NULL );
memset( &lib, 0, sizeof( MWLib ) );
if( files == NULL ) {
fprintf( stderr, "ar: %s, nothing to do\n", archive_name );
return B_ERROR;
}
retval = load_MW_lib( &lib, archive_name );
if( retval != B_OK ) {
switch( retval ) {
case B_FILE_NOT_FOUND:
lib.header.magicword = 'MWOB';
lib.header.magicproc = 'PPC ';
lib.header.magicflags = 0;
lib.header.version = 1;
if( lib.files != NULL ) {
free( lib.files );
lib.files = NULL;
}
if( lib.names != NULL ) {
free( lib.names );
lib.names = NULL;
}
if( lib.data != NULL ) {
lib.data = NULL;
}
if( !create ) {
fprintf( stderr, "ar: creating %s\n", archive_name );
}
if( update ) {
fprintf( stderr, "ar: nothing to do for %s\n", archive_name );
return retval;
}
break;
default:
return retval;
break;
}
}
for( idx = 0; files[idx] != NULL; idx++ ) {
if( do_match( &lib, files[idx], &which ) ) {
/* Then the file exists, and we need to replace it or update it.
*/
if( update ) {
/* Compare m_times
** then replace this entry
*/
struct stat s;
retval = stat( files[idx], &s );
if( retval != 0 ) {
fprintf( stderr, "ar: can't stat %s, %s\n", files[idx],
strerror( errno ) );
}
if( s.st_mtime >= lib.files[which].m_time ) {
retval = replace_lib_entry( &lib, files[idx], which,
verbose );
} else {
fprintf( stderr, "ar: a newer %s is already in %s\n",
files[idx], archive_name );
}
} else {
/* replace this entry
*/
retval = replace_lib_entry( &lib, files[idx], which, verbose );
}
} else {
/* add this entry
*/
retval = add_lib_entry( &lib, files[idx], verbose );
}
}
/* Write the new file.
*/
retval = write_MW_lib( &lib, archive_name );
return retval;
}
static status_t add_lib_entry( MWLib *lib, const char *filename, int verbose )
{
status_t retval = B_OK;
uint32 new_num_objects;
uint32 idx;
ASSERT( lib != NULL );
ASSERT( filename != NULL );
/* Find out how many objects we'll have after we add this one.
*/
new_num_objects = lib->header.num_objects + 1;
idx = lib->header.num_objects;
/* Attempt to reallocate the MWLib's buffers. If one of these fails,
** we could leak a little memory, but it shouldn't be a big deal in
** a short-lived app like this.
*/
lib->files = (MWLibFile *)realloc( lib->files,
sizeof(MWLibFile) * new_num_objects );
lib->names = (char **)realloc( lib->names,
sizeof(char *) * new_num_objects );
lib->data = (char **)realloc( lib->data,
sizeof(char *) * new_num_objects );
if( lib->files == NULL || lib->names == NULL || lib->data == NULL ) {
fprintf( stderr, "ar: can't allocate memory to add %s\n", filename );
return B_NO_MEMORY;
}
/* Load the file's data and info into the MWLib structure.
*/
retval = load_lib_file( filename, &(lib->data[idx]), &(lib->files[idx]) );
if( retval != B_OK ) {
fprintf( stderr, "ar: error adding %s, %s\n", filename,
strerror( errno ) );
return retval;
}
/* Save a copy of the filename. This is where we leak
** sizeof(MWLibFile) + 2 * sizeof(char *) bytes because we don't
** shrink lib->files, lib->names, and lib->data.
*/
lib->names[idx] = strdup( filename );
if( lib->names == NULL ) {
fprintf( stderr, "ar: error allocating memory for filename\n" );
return B_NO_MEMORY;
}
/* Now that everything's OK, we can update the MWLib header.
*/
lib->header.num_objects++;
/* Give a little feedback.
*/
if( verbose ) {
printf( "a - %s\n", filename );
}
return B_OK;
}
static status_t replace_lib_entry( MWLib *lib, const char *filename,
int idx, int verbose )
{
char *buff;
MWLibFile info;
char *dup_name;
status_t retval = B_OK;
ASSERT( lib != NULL );
ASSERT( filename != NULL );
ASSERT( idx <= lib->header.num_objects );
/* Load the file's data and info into the MWLib structure.
**
** We'll do it safely so we don't end up writing a bogus library in
** the event of failure.
*/
retval = load_lib_file( filename, &buff, &info );
if( retval != B_OK ) {
fprintf( stderr, "ar: error adding %s, %s\n", filename,
strerror( errno ) );
return retval;
}
/* Attempt to allocate memory for a duplicate of the file name.
*/
dup_name = strdup( filename );
if( dup_name == NULL ) {
fprintf( stderr, "ar: unable to allocate memory for filename\n",
filename );
free( buff );
return B_NO_MEMORY;
}
/* All is well, so let's update the MWLib object appropriately.
*/
lib->files[idx].m_time = info.m_time;
lib->files[idx].off_filename = 0;
lib->files[idx].off_fullpath = 0;
lib->files[idx].off_object = 0;
lib->files[idx].object_size = info.object_size;
lib->data[idx] = buff;
free( lib->names[idx] );
lib->names[idx] = dup_name;
/* Give a little feedback.
*/
if( verbose ) {
printf( "r - %s\n", filename );
}
return B_OK;
}
/* ----------------------------------------------------------------------
** Print the table for an archive.
*/
static status_t table_lib_entry( MWLib *lib, int idx, int verbose );
status_t do_table( const char *archive_name, char **files, int verbose )
{
status_t retval = B_OK;
MWLib lib;
int idx = 0;
ASSERT( archive_name != NULL );
retval = load_MW_lib( &lib, archive_name );
if( retval != B_OK ) {
switch( retval ) {
case B_FILE_NOT_FOUND:
fprintf( stderr, "ar: %s, file not found\n", archive_name );
return retval;
break;
default:
return retval;
break;
}
}
if( files == NULL ) {
/* Then we print the table for the entire archive.
*/
for( idx = 0; idx < lib.header.num_objects; idx++ ) {
retval = table_lib_entry( &lib, idx, verbose );
}
} else {
/* Then we print the table for the specified files.
*/
int which = 0;
for( idx = 0; files[idx] != NULL; idx++ ) {
if( do_match( &lib, files[idx], &which ) ) {
retval = table_lib_entry( &lib, which, verbose );
}
which = 0;
}
}
return retval;
}
static status_t table_lib_entry( MWLib *lib, int idx, int verbose )
{
struct tm *t;
char month_buff[4];
ASSERT( lib != NULL );
if( verbose ) {
t = localtime( &(lib->files[idx].m_time) );
if( t == NULL ) {
fprintf( stderr, "localtime() failed, %s\n",
strerror( errno ) );
return B_OK;
}
if( strftime( month_buff, sizeof( month_buff ),
"%b", t ) == 0 ) {
/* TODO: error message */
fprintf( stderr, "strftime() failed, %s\n",
strerror( errno ) );
return B_OK;
}
/* I wish POSIX allowed for a nicer format; even using tabs
* between some entries would be better.
*/
printf( "%s %u/%u %u %s %d %d:%d %d %s\n",
"-rw-r--r--", /* simulated mode */
getuid(), getgid(), /* simulated uid & gid */
lib->files[idx].object_size,
month_buff, /* abbreviated month */
t->tm_mon, /* day of month */
t->tm_hour, /* hour */
t->tm_min, /* minute */
t->tm_year, /* year */
lib->names[idx] );
} else {
printf( "%s\n", lib->names[idx] );
}
return B_OK;
}
/* ----------------------------------------------------------------------
** Extract one or more files from the archive.
*/
static status_t extract_lib_entry( MWLib *lib, int idx, int verbose );
status_t do_extract( const char *archive_name, char **files, int verbose )
{
status_t retval = B_OK;
MWLib lib;
int idx = 0;
ASSERT( archive_name != NULL );
retval = load_MW_lib( &lib, archive_name );
if( retval != B_OK ) {
switch( retval ) {
case B_FILE_NOT_FOUND:
fprintf( stderr, "ar: %s, file not found\n", archive_name );
return retval;
break;
default:
return retval;
break;
}
}
if( files == NULL ) {
/* Then we extract all the files.
*/
for( idx = 0; idx < lib.header.num_objects; idx++ ) {
retval = extract_lib_entry( &lib, idx, verbose );
}
} else {
/* Then we extract the specified files.
*/
int which = 0;
for( idx = 0; files[idx] != NULL; idx++ ) {
if( do_match( &lib, files[idx], &which ) ) {
retval = extract_lib_entry( &lib, which, verbose );
}
which = 0;
}
}
return retval;
}
static status_t extract_lib_entry( MWLib *lib, int idx, int verbose )
{
FILE *fp;
int recs;
status_t retval = B_OK;
struct stat s;
mode_t mode_bits = 0666; /* TODO: use user's umask() instead */
ASSERT( lib != NULL );
/* Delete the file if it already exists.
*/
retval = access( lib->names[idx], F_OK );
if( retval == 0 ) {
retval = stat( lib->names[idx], &s );
if( retval != 0 ) {
fprintf( stderr, "ar: can't stat %s, %s\n", lib->names[idx],
strerror( errno ) );
} else {
mode_bits = s.st_mode;
}
retval = unlink( lib->names[idx] );
if( retval != 0 ) {
fprintf( stderr, "ar: can't unlink %s, %s\n", lib->names[idx],
strerror( retval ) );
return B_OK;
}
}
/* Write the file.
*/
if( verbose ) {
printf( "x - %s\n", lib->names[idx] );
}
fp = fopen( lib->names[idx], "w" );
if( fp == NULL ) {
fprintf( stderr, "ar: can't open %s for write, %s\n", lib->names[idx],
strerror( errno ) );
return B_OK;
}
recs = fwrite( lib->data[idx], lib->files[idx].object_size, 1, fp );
if( recs != 1 ) {
fprintf( stderr, "error writing %s, %s\n", lib->names[idx],
strerror( errno ) );
}
retval = fclose( fp );
/* Set the newly extracted file's modification time to the time
** stored in the archive.
*/
retval = stat( lib->names[idx], &s );
if( retval != 0 ) {
fprintf( stderr, "ar: can't stat %s, %s\n", lib->names[idx],
strerror( errno ) );
} else {
struct utimbuf new_times;
new_times.actime = s.st_atime;
new_times.modtime = lib->files[idx].m_time;
retval = utime( lib->names[idx], &new_times );
if( retval != 0 ) {
fprintf( stderr, "ar: can't set modification time for %s, %s\n",
lib->names[idx], strerror( retval ) );
}
}
/* Set the newly extracted file's mode.
*/
retval = chmod( lib->names[idx], mode_bits );
if( retval != 0 ) {
fprintf( stderr, "ar: unable to change file mode for %s, %s\n",
lib->names[idx], strerror( errno ) );
}
/* Set the newly extracted file's type.
*/
setfiletype( lib->names[idx], "application/x-mw-library" );
return B_OK;
}

View File

@ -1,28 +0,0 @@
/*
** commands.h - POSIX 1003.2 "ar" command
**
** $Id$
**
** This isn't a pure POSIX 1003.2 ar; it only manipulates Metrowerks
** Library files, not general-purpose POSIX 1003.2 format archives.
**
** Dec. 14, 1997 Chris Herborth (chrish@kagi.com)
**
** This code is donated to the PUBLIC DOMAIN. You can use, abuse, modify,
** redistribute, steal, or otherwise manipulate this code. No restrictions
** at all. If you laugh at this code, you can't use it.
**
** This "ar" was implemented using IEEE Std 1003.2-1992 as the basis for
** the interface, and Metrowerk's published docs detailing their library
** format. Look inside for clues about how reality differs from MW's
** documentation on BeOS...
*/
#include <be/support/SupportDefs.h>
status_t do_delete( const char *archive_name, char **files, int verbose );
status_t do_print( const char *archive_name, char **files, int verbose );
status_t do_replace( const char *archive_name, char **files, int verbose,
int create, int update );
status_t do_table( const char *archive_name, char **files, int verbose );
status_t do_extract( const char *archive_name, char **files, int verobse );

View File

@ -1,128 +0,0 @@
/*
** copy_attrs.h - copy BeFS attributes from one file to another
**
** Jan. 11, 1998 Chris Herborth (chrish@qnx.com)
**
** This code is donated to the PUBLIC DOMAIN. You can use, abuse, modify,
** redistribute, steal, or otherwise manipulate this code. No restrictions
** at all. If you laugh at this code, you can't use it.
*/
#include <support/Errors.h>
#ifndef NO_DEBUG
#include <assert.h>
#define ASSERT(cond) assert(cond)
#else
#define ASSERT(cond) ((void)0)
#endif
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <limits.h>
#include <string.h>
#include <errno.h>
#include <kernel/fs_attr.h>
#include <fcntl.h>
#include "copy_attrs.h"
static const char *rcs_version_id = "$Id$";
/* ----------------------------------------------------------------------
** Copy file attributes from src_file to dst_file.
*/
status_t copy_attrs( const char *dst_file, const char *src_file )
{
int dst_fd, src_fd;
status_t retval = B_OK;
DIR *fa_dir = NULL;
struct dirent *fa_ent = NULL;
char *buff = NULL;
struct attr_info fa_info;
off_t read_bytes, wrote_bytes;
ASSERT( dst_file != NULL );
ASSERT( src_file != NULL );
/* Attempt to open the files.
*/
src_fd = open( src_file, O_RDONLY );
if( src_fd < 0 ) {
return B_FILE_NOT_FOUND;
}
dst_fd = open( dst_file, O_WRONLY );
if( dst_fd < 0 ) {
close( src_fd );
return B_FILE_NOT_FOUND;
}
/* Read the attributes, and write them to the destination file.
*/
fa_dir = fs_fopen_attr_dir( src_fd );
if( fa_dir == NULL ) {
retval = B_IO_ERROR;
goto close_return;
}
fa_ent = fs_read_attr_dir( fa_dir );
while( fa_ent != NULL ) {
retval = fs_stat_attr( src_fd, fa_ent->d_name, &fa_info );
if( retval != B_OK ) {
/* TODO: Print warning message?
*/
goto read_next_attr;
}
if( fa_info.size > (off_t)UINT_MAX ) {
/* TODO: That's too big. Print a warning message? You could
** copy it in chunks...
*/
goto read_next_attr;
}
if( fa_info.size > (off_t)0 ) {
buff = malloc( (size_t)fa_info.size );
if( buff == NULL ) {
/* TODO: Can't allocate memory for this attribute. Warning?
*/
goto read_next_attr;
}
read_bytes = fs_read_attr( src_fd, fa_ent->d_name, fa_info.type,
0, buff, fa_info.size );
if( read_bytes != fa_info.size ) {
/* TODO: Couldn't read entire attribute. Warning?
*/
goto free_attr_buff;
}
wrote_bytes = fs_write_attr( dst_fd, fa_ent->d_name, fa_info.type,
0, buff, fa_info.size );
if( wrote_bytes != fa_info.size ) {
/* TODO: Couldn't write entire attribute. Warning?
*/
;
}
free_attr_buff:
free( buff );
retval = B_OK;
}
/* Read the next entry.
*/
read_next_attr:
fa_ent = fs_read_attr_dir( fa_dir );
}
close_return:
close( dst_fd );
close( src_fd );
return retval;
}

View File

@ -1,24 +0,0 @@
/*
** copy_attrs.h - copy BeFS attributes from one file to another
**
** $Id$
**
** Jan. 11, 1998 Chris Herborth (chrish@qnx.com)
**
** This code is donated to the PUBLIC DOMAIN. You can use, abuse, modify,
** redistribute, steal, or otherwise manipulate this code. No restrictions
** at all. If you laugh at this code, you can't use it.
*/
/* ----------------------------------------------------------------------
** Function prototypes
**
** copy_attrs() - copy BeFS attributes from one file to another
**
** Returns:
** B_OK - all is well
** B_FILE_NOT_FOUND - can't open one of the named files
** B_IO_ERROR - can't read/write some of the file attributes
** B_NO_MEMORY - unable to allocate a buffer for the attribute data
*/
status_t copy_attrs( const char *dest_file, const char *src_file );

View File

@ -1,234 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML3.2//EN">
<!-- $Id$ -->
<html> <head>
<title>ar - create and maintain library archives</title>
</head>
<body bgcolor="#ffffcb">
<h1>ar</h1>
<h4 align="right">create and maintain library archives</h4>
<h2>Synopsis</h2>
<pre>
ar [-][dprtx][cuv] <i>archive</i> [<i>file</i> ...]
</pre>
<h2>Options</h2>
<table>
<tr>
<td valign="top"><b>-</b></td>
<td valign="top">
The <b>-</b> is optional for introducing <tt>ar</tt> command-line
arguments; this is a POSIX requirement, and I've never seen anyone
use it.</td>
</tr>
<tr>
<td valign="top"><b>c</b></td>
<td valign="top">
Don't print a diagnostic message to <i>stderr</i> when
<i>archive</i> is created.</td>
</tr>
<tr>
<td valign="top"><b>d</b></td>
<td valign="top">
Delete <i>file(s)</i> from <i>archive</i>.</td>
</tr>
<tr>
<td valign="top"><b>p</b></td>
<td valign="top">
Write the contents of the named <i>file(s)</i> to <i>stdout</i>.
If no <i>file(s)</i> are specified, all of the files in
<i>archive</i> are written in the order of the archive.</td>
</tr>
<tr>
<td valign="top"><b>r</b></td>
<td valign="top">
Replace or add <i>file(s)</i> to the <i>archive</i>. This will
create <i>archive</i> if it doesn't already exist.</td>
</tr>
<tr>
<td valign="top"><b>t</b></td>
<td valign="top">
Write the table of contents of <i>archive</i> to <i>stdout</i>.
If not <i>file(s)</i> are specified, list all of the files,
otherwise only list the specified files.</td>
</tr>
<tr>
<td valign="top"><b>u</b></td>
<td valign="top">
Update older files. When used with the <b>r</b> option, files
within the archive are only replaced if <i>file</i> has a
modification date at least as new as the <i>file</i> already in
the archive.</td>
</tr>
<tr>
<td valign="top"><b>v</b></td>
<td valign="top">Give verbose output.</td>
</tr>
<tr>
<td valign="top"><b>x</b></td>
<td valign="top">
Extract <i>file(s)</i> from the <i>archive</i>. If no
<i>file(s)</i> are specified, all of the files in <i>archive</i>
are extracted.</td>
</tr>
<tr>
<td valign="top"><i>archive</i></td>
<td valign="top">
The pathname of an archive file.</td>
</tr>
<tr>
<td valign="top"><i>file</i></td>
<td valign="top">
One more more pathnames of object files; only the file name is
used when comparing against the names of files in the
archive.</td>
</tr>
</table>
<h2>Description</h2>
<p>The <tt>ar</tt> utility creates and maintains groups of files
combined into a library. Once a library has been created, you can
add new files, and extract, delete, or replace existing files.</p>
<h2>Exit status</h2>
<p><tt>ar</tt> exits with one of the following values:</p>
<table>
<tr><td valign="top">0</td>
<td valign="top">Successful completion.</td></tr>
<tr><td valign="top">&gt; 0</td>
<td>An error occurred.</td></tr>
</table>
<h2>Bugs</h2>
<p>No known bugs, but <em>please</em> read the comments in the code if
you want to use it in another application.</p>
<h2>Comments</h2>
<p>This is a POSIX 1003.2-1992 based <tt>ar</tt> command; it's not
100% POSIX 1003.2 because POSIX specifies a file format for
<tt>ar</tt> archives. The BeOS <tt>ar</tt> produces library files
compatible (at least in theory <tt>:-)</tt>) with Metrowerks
CodeWarrior for PowerPC.</p>
<p>This <tt>ar</tt> and its source code were written as a service to
the Be developer community, to make it easier for us to port UNIX
applications and libraries. The code was written from scratch, after
reverse-engineering the Metrowerks library and object file format
(mostly because the library/object file format documentation was
incorrect).</p>
<p>If you find this useful, please
<a href="mailto:chrish@kagi.com">let me know</a>, and tell me what
you're working on. Be sure to include a URL for your homepage or your
product homepages for my
<a href="http://www.qnx.com/~chrish/Be/community/">Be Community</a>
pages.</p>
<p>If you find any bugs, please try to fix them, and send me a context
diff (use <tt>diff -c original_file fixed_file</tt>) so I can include
your fixes in the next update. I <i>have</i> tested this, but these
things have a way of slipping though.</p>
<p>If you'd like to know what other things I'm working on, take a look
at my <a href="http://www.qnx.com/~chrish/Be/software/">Be
Software</a> pages, and my
<a href="http://www.qnx.com/~chrish/Be/">Be Happy!</a> pages.</p>
<h2>License</h2>
<p>This program binary and its source code have been donated to the
BeOS Developer Community by Arcane Dragon Software free of charge.
You can do whatever you want with it.</p>
<p>If you <em>really</em> want to show your appreciation, you could
always send me a gift of some sort; cool software you wrote, nice
pictures for my desktop, ZIP drive disks, RAM, hard drives, post
cards, a pointer to a really cool/useful/interesting web site,
an MPEG audio file of an interesting band (make sure you can give me
enough information to track down their CDs if I like it!), <i>etc.</i>
Send me some <a href="mailto:chrish@kagi.com">email</a> and I'll let you
know where to send it.</p>
<p>But you don't have to do anything. Just write good BeOS software.
But you're already doing that, right?</p>
<h2>Disclaimer</h2>
<p>You use this at your own risk. I've tried to ensure that the code
is correct, but software usually has bugs. If <tt>ar</tt> destroys
your valuable data, formats your hard drive, kicks your cat, and lets
the air out of your tires, I'm not responsible for it. The code is
here, so you should feel fairly safe that there's nothing evil going
on.</p>
<p>And, as I learned once again in December 1997, you really should
keep backups of everything. I only lost a day's work, but it was
still annoying, and it could've been much, much worse.</p>
<h3>A word about the code</h3>
<p>This code isn't meant to be the ultimate in efficiency or speed,
it's intended to be fairly easy to understand and maintain
(hopefully). I was also quite keen on having something that was
correct, without jumping through a lot of unnecessary hoops.</p>
<p>If you think this code sucks, don't use it. You're already applying
this to your choice of operating system! <tt>:-)</tt></p>
<h2>Versions</h2>
<dl compact>
<dt><strong>1.1 (April 18, 1998)</strong></dt>
<dd>Changes include:
<ul>
<li>Extract option (<b>x</b>) will preserve a file's mode bits
when overwriting an existing file (this may go away if it's
not POSIX behaviour).</li>
<li>Extracted files will now have the proper file type.</li>
<li>Removed attempt to use <i>umask()</i> to set newly created
archive's mode bits; apparently, I'm not sure how it
works and my POSIX manual isn't helping.</li>
<li>Should be 100% endian-neutral now; using this on BeOS for
x86 is only useful if you're manipulating <em>PowerPC</em>
objects though. The <tt>ar</tt> in
<a href="http://www.ninemoons.com/GG/index.html">GeekGadgets</a>
should work fine for x86 objects/libraries.</li>
<li>Updated the <tt>README.txt</tt> file; now it's got useful
information about building/using the POSIX ar.</li>
</ul></dd>
<dt><strong>1.0 (January 13, 1998)</strong></dt>
<dd>Initial release.</dd>
</dl>
<hr>
<p>Chris Herborth (<a href="mailto:chrish@qnx.com">chrish@qnx.com</a>)</p>
<!-- hhmts start -->
Last modified: $Date$
<!-- hhmts end -->
</body> </html>

View File

@ -1,271 +0,0 @@
#! /bin/env python
""" Dump data about a Metrowerks archive file.
$Id$
Based on reverse-engineering the library file format.
Copyright (C) 1997 Chris Herborth (chrish@qnx.com)
"""
# ----------------------------------------------------------------------
# Standard modules
import sys
import getopt
import string
import time
# ----------------------------------------------------------------------
def usage():
""" Display a usage message and exit.
"""
print "dumpar [-v] library1 [library2 ... libraryn]"
print
print "Attempt to display some useful information about the contents"
print "of the given Metrowerks library file(s)."
print
print "-v Be verbose (displays offsets along with the data)"
raise SystemExit
# ----------------------------------------------------------------------
def mk_long( str ):
""" convert a 4-byte string into a number
Assumes big-endian!
"""
if len( str ) < 4:
raise ValueError, "str must be 4 bytes long"
num = ord( str[3] )
num = num + ord( str[2] ) * 0x100
num = num + ord( str[1] ) * 0x10000
num = num + ord( str[0] ) * 0x1000000
return num
# ----------------------------------------------------------------------
def str2hex( str ):
""" convert a string into a string of hex numbers
"""
ret = []
for c in str:
h = hex( ord( c ) )
ret.append( string.zfill( "%s" % ( h[2:] ), 2 ) )
return string.join( ret )
# ----------------------------------------------------------------------
def print_offset( offset ):
""" print the offset nicely
"""
# Turn the offset into a hex number and strip off the leading "0x".
val = "%s" % ( hex( offset ) )
val = val[2:]
out = "0x" + string.zfill( val, 8 )
print out,
# ----------------------------------------------------------------------
def get_string( data ):
""" dig a C string out of a data stream
returns the string
"""
len = 0
while data[len] != '\0':
len = len + 1
return data[:len]
# ----------------------------------------------------------------------
def dump_lib( file, verbose ):
""" dump information about a Metrowerks library file
"""
offset = 0
print "Dumping library:", file
# Attempt to read the data.
try:
data = open( file ).read()
except IOError, retval:
print "*** Unable to open file %s: %s" % ( file, retval[1] )
return
# Check the magic number.
if verbose:
print_offset( offset )
print "Magic:",
magic = data[offset:offset + 8]
print "'%s'" % ( magic )
if magic != "MWOBPPC ":
print "*** Invalid magic number!"
return
offset = offset + 8
# File flags
if verbose:
print_offset( offset )
print "file flags:",
print mk_long( data[offset:offset + 4] )
offset = offset + 4
if verbose:
print_offset( offset )
print "file version:",
print mk_long( data[offset:offset + 4] )
offset = offset + 4
# code size
if verbose:
print_offset( offset )
print "code size:", mk_long( data[offset:offset + 4] )
offset = offset + 4
# data size
if verbose:
print_offset( offset )
print "data size:", mk_long( data[offset:offset + 4] )
offset = offset + 4
# number of objects
if verbose:
print_offset( offset )
print "number of objects:",
num_objs = mk_long( data[offset:offset + 4] )
print num_objs
offset = offset + 4
print
# Now loop through the objects.
obj_sizes = [ 0, ] * num_objs
obj_data_offsets = [ 0, ] * num_objs
for obj in range( num_objs ):
# Magic?
if verbose:
print_offset( offset )
print "modification time:",
modtime = mk_long( data[offset:offset + 4] )
print "[%s]" % ( ( time.localtime( modtime ), ) )
offset = offset + 4
# Offsets?
if verbose:
print_offset( offset )
print "file name offset 1:",
file_offset1 = mk_long( data[offset:offset + 4] )
unknown = "%s" % ( hex( file_offset1 ) )
print "%s (%s)" % ( unknown, str2hex( data[offset:offset + 4] ) )
offset = offset + 4
if verbose:
print_offset( offset )
print "file name offset 2:",
file_offset2 = mk_long( data[offset:offset + 4] )
unknown = "%s" % ( hex( file_offset2 ) )
print "%s (%s)" % ( unknown, str2hex( data[offset:offset + 4] ) )
offset = offset + 4
# Extra -1 for NUL character.
print " >>>> File name should be %s characters." % \
( file_offset2 - file_offset1 - 1)
if verbose:
print_offset( offset )
print "object data offset:",
file_data_offset = mk_long( data[offset:offset + 4] )
unknown = "%s" % ( hex( file_data_offset ) )
print "%s (%s)" % ( unknown, str2hex( data[offset:offset + 4] ) )
obj_data_offsets[obj] = file_data_offset
offset = offset + 4
# object size
if verbose:
print_offset( offset )
print "object size:",
obj_sizes[obj] = mk_long( data[offset:offset + 4] )
print "%s bytes" % ( obj_sizes[obj] )
offset = offset + 4
print
# Now loop through the object names.
for obj in range( num_objs ):
# First name
if verbose:
print_offset( offset )
print "object",
print obj,
print "name 1:",
name1 = get_string( data[offset:] )
print "[%s] %s chars" % ( name1, len( name1 ) )
offset = offset + len( name1 ) + 1
# Second name
if verbose:
print_offset( offset )
print "object",
print obj,
print "name 2:",
name2 = get_string( data[offset:] )
print "[%s] %s chars" % ( name2, len( name1 ) )
offset = offset + len( name2 ) + 1
# See if we've got a magic cookie in the object data
if verbose:
print_offset( obj_data_offsets[obj] )
cookie = data[obj_data_offsets[obj]:obj_data_offsets[obj] + 8]
print "object",
print obj,
print "cookie: '%s'" % ( cookie )
print
# Now loop through the data and check for magic numbers there.
return
# ----------------------------------------------------------------------
def main():
""" mainline
"""
# Set up some defaults
be_verbose = 0
# First, check the command-line arguments
try:
opt, args = getopt.getopt( sys.argv[1:], "vh?" )
except getopt.error:
print "*** Error parsing command-line options!"
usage()
for o in opt:
if o[0] == "-h" or o[0] == "-?":
usage()
elif o[0] == "-v":
be_verbose = 1
else:
print "*** Unknown command-line option!"
usage()
# Now we can attempt to dump info about the arguments.
for lib in args:
dump_lib( lib, be_verbose )
if __name__ == "__main__":
main()

View File

@ -1,126 +0,0 @@
#! /bin/env python
""" Dump data about a Metrowerks object file.
Based on reverse-engineering the library file format, since the docs are
wrong.
Copyright (C) 1997 Chris Herborth (chrish@qnx.com)
"""
# ----------------------------------------------------------------------
# Standard modules
import sys, getopt, string, time
# ----------------------------------------------------------------------
# Extra goodies
from dumpar import mk_long, str2hex, print_offset, get_string
# ----------------------------------------------------------------------
def mk_short( str ):
""" convert a 2-byte string into a number
Assumes big-endian!
"""
if len( str ) < 2:
raise ValueError, "str must be 2 bytes long"
num = ord( str[1] )
num = num + ord( str[0] ) * 0x100
return num
# ----------------------------------------------------------------------
def usage():
""" Display a usage message and exit.
"""
print "dumpo [-v] object1 [object2 ... objectn]"
print
print "Attempt to display some useful information about the contents"
print "of the given Metrowerks object file(s)."
print
print "-v Be verbose (displays offsets along with the data)"
raise SystemExit
# ----------------------------------------------------------------------
def dump_o( file, verbose ):
""" dump information about a Metrowerks object file
Note that there is more info there, 6 more quads before the file name.
"""
offset = 0
print "Dumping object:", file
# Attempt to read the data.
try:
data = open( file ).read()
except IOError, retval:
print "*** Unable to open file %s: %s" % ( file, retval[1] )
return
# Check the magic number.
if verbose:
print_offset( offset )
print "Magic:",
magic = data[offset:offset + 8]
print "'%s'" % ( magic )
if magic != "MWOBPPC ":
print "*** Invalid magic number!"
return
offset = offset + 8
# version
if verbose:
print_offset( offset )
print "version:", mk_long( data[offset:offset + 4] )
offset = offset + 4
# flags
if verbose:
print_offset( offset )
print "flags:", str2hex( data[offset:offset + 4] )
offset = offset + 4
# code size
if verbose:
print_offset( offset )
print "code size:", mk_long( data[offset:offset + 4] )
offset = offset + 4
# data size
if verbose:
print_offset( offset )
print "data size:", mk_long( data[offset:offset + 4] )
offset = offset + 4
# ----------------------------------------------------------------------
def main():
""" mainline
"""
# Set up some defaults
be_verbose = 0
# First, check the command-line arguments
try:
opt, args = getopt.getopt( sys.argv[1:], "vh?" )
except getopt.error:
print "*** Error parsing command-line options!"
usage()
for o in opt:
if o[0] == "-h" or o[0] == "-?":
usage()
elif o[0] == "-v":
be_verbose = 1
else:
print "*** Unknown command-line option!"
usage()
# Now we can attempt to dump info about the arguments.
for obj in args:
dump_o( obj, be_verbose )
if __name__ == "__main__":
main()

View File

@ -1,34 +0,0 @@
MW library layout:
header
magic word, magic processor flag ('MWOBPPC ') - 2x 4 bytes
magic flags, version (file format version?) - 2x 4 bytes
code size - 4 bytes
data size - 4 bytes
# of objects - 4 bytes
header for file 1 - 20 bytes
- modification time - 4 bytes
- offset to filename - 4 bytes
- offset to full path - 4 bytes (NOTE: NOT a full path in reality!)
- offset to object data - 4 bytes
- size of object data - 4 bytes
...
header for file n - 20 bytes
file 1 name + NUL - variable
file 1 name + NUL - variable
file 2 name + NUL - variable
file 2 name + NUL - variable
...
file n name + NUL - variable
file n name + NUL - variable
padding to multiple of 4 bytes - 0 - 3 bytes
file 1 data - variable (padded to 4-byte boundary)
file 2 data - variable (padded to 4-byte boundary)
...
file n data - variable (padded to 4-byte boundary)

View File

@ -1,312 +0,0 @@
/*
** main.c - POSIX 1003.2 "ar" command
**
** This isn't a pure POSIX 1003.2 ar; it only manipulates Metrowerks
** Library files, not general-purpose POSIX 1003.2 format archives.
**
** Dec. 14, 1997 Chris Herborth (chrish@kagi.com)
**
** This code is donated to the PUBLIC DOMAIN. You can use, abuse, modify,
** redistribute, steal, or otherwise manipulate this code. No restrictions
** at all. If you laugh at this code, you can't use it.
**
** This "ar" was implemented using IEEE Std 1003.2-1992 as the basis for
** the interface, and Metrowerk's published docs detailing their library
** format. Look inside for clues about how reality differs from MW's
** documentation on BeOS...
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <getopt.h>
#include "commands.h"
static const char *rcs_version_id = "$Id$";
static const char *ar_version_id = "1.0 " __DATE__;
/* ---------------------------------------------------------------------- */
typedef enum {
delete_cmd,
print_cmd,
replace_cmd,
table_cmd,
extract_cmd,
no_cmd = -1 } command;
/* ----------------------------------------------------------------------
** Prototypes
*/
void usage( void );
void version( void );
void check_command( command *cmd, int arg );
/* ----------------------------------------------------------------------
** Print a usage message and exit.
*/
void usage( void )
{
printf( "ar [dprtx][cuv] archive [file ...]\n" );
exit( EXIT_FAILURE );
}
/* ----------------------------------------------------------------------
** Print a version message and exit.
*/
void version( void )
{
printf( "ar (POSIX 1003.2-1992), version %s\n", ar_version_id );
printf( "by Chris Herborth (chrish@qnx.com)\n" );
printf( "This code has been donated to the BeOS developer community.\n" );
return;
}
/* ----------------------------------------------------------------------
** Set *cmd to the appropriate command enum if it isn't already set.
*/
void check_command( command *cmd, int arg )
{
if( *cmd == no_cmd ) {
switch( arg ) {
case 'd':
*cmd = delete_cmd;
break;
case 'p':
*cmd = print_cmd;
break;
case 'r':
*cmd = replace_cmd;
break;
case 't':
*cmd = table_cmd;
break;
case 'x':
*cmd = extract_cmd;
break;
}
} else {
printf( "ar: you can only specify one command at a time\n" );
usage();
}
}
/* ----------------------------------------------------------------------
** Mainline
*/
int main( int argc, char **argv )
{
command cmd = no_cmd;
int verbose_flag = 0;
int create_flag = 0; /* these two only apply to replace_cmd */
int update_flag = 0;
int c = 0;
char *archive_name;
char **files_list;
int num_files;
int idx;
status_t retval;
/* The argument parsing is a little hairier than usual; the idea is
** to support the POSIX 1003.2 style of arguments, and the much more
** common traditional argument style.
*/
if( argc < 3 ) {
printf( "ar: invalid number of arguments\n" );
usage();
}
/* Do we have traditional or POSIX-style args? */
if( argv[1][0] == '-' ) {
while( ( c = getopt( argc, argv, "dprtxcuvV" ) ) != EOF ) {
switch( c ) {
case 'd': /* fall-through */
case 'p': /* fall-through */
case 'r': /* fall-through */
case 't': /* fall-through */
case 'x': /* fall-through */
check_command( &cmd, c );
break;
case 'v':
verbose_flag = 1;
break;
case 'c':
if( cmd != no_cmd && cmd != replace_cmd ) {
printf( "ar: invalid option, -c\n" );
usage();
} else {
create_flag = 1;
}
break;
case 'u':
if( cmd != no_cmd && cmd != replace_cmd ) {
printf( "ar: invalid option, -u\n" );
usage();
} else {
update_flag = 1;
}
break;
case 'V':
version();
break;
default:
printf( "ar: invalid option, -%c\n", c );
usage();
break;
}
idx = optind;
}
} else {
/* In the traditional way, arguments ar:
**
** argv[1] = [dprtx][cuv]
** argv[2] = archive
** argv[...] = file ...
**/
char *ptr;
idx = 1;
ptr = argv[idx++];
while( *ptr != '\0' ) {
switch( *ptr ) {
case 'd': /* fall-through */
case 'p': /* fall-through */
case 'r': /* fall-through */
case 't': /* fall-through */
case 'x': /* fall-through */
check_command( &cmd, *ptr );
break;
case 'v':
verbose_flag = 1;
break;
case 'c':
if( cmd != no_cmd && cmd != replace_cmd ) {
printf( "ar: invalid option, -c\n" );
usage();
} else {
create_flag = 1;
}
break;
case 'u':
if( cmd != no_cmd && cmd != replace_cmd ) {
printf( "ar: invalid option, -u\n" );
usage();
} else {
update_flag = 1;
}
break;
case 'V':
version();
break;
default:
printf( "ar: invalid option, -%c\n", c );
usage();
break;
}
ptr++;
}
}
/* Next arg is the archive. */
archive_name = argv[idx++];
/* Next are the files. */
num_files = argc - idx;
if( num_files == 0 ) {
files_list = NULL;
} else {
int ctr = 0;
files_list = (char **)malloc( ( num_files + 1 ) * sizeof( char * ) );
while( idx < argc ) {
files_list[ctr++] = argv[idx++];
}
files_list[idx] = NULL;
}
/* Now we can attempt to manipulate the archive. */
switch( cmd ) {
case delete_cmd:
retval = do_delete( archive_name, files_list, verbose_flag );
break;
case print_cmd:
retval = do_print( archive_name, files_list, verbose_flag );
break;
case replace_cmd:
retval = do_replace( archive_name, files_list, verbose_flag,
create_flag, update_flag );
break;
case table_cmd:
retval = do_table( archive_name, files_list, verbose_flag );
break;
case extract_cmd:
retval = do_extract( archive_name, files_list, verbose_flag );
break;
default:
printf( "ar: you must specify a command\n" );
usage();
break;
}
/* Check the return value.
*/
switch( retval ) {
case B_OK:
break;
case B_FILE_NOT_FOUND:
printf( "can't open the file %s\n", archive_name );
return EXIT_FAILURE;
break;
case B_IO_ERROR:
printf( "can't read from %s\n", archive_name );
return EXIT_FAILURE;
break;
case B_BAD_VALUE:
printf( "invalid magic word\n" );
return EXIT_FAILURE;
break;
case B_MISMATCHED_VALUES:
printf( "invalid processor value, or magicflags, or version\n" );
return EXIT_FAILURE;
break;
case B_NO_MEMORY:
printf( "unable to allocate memory\n" );
return EXIT_FAILURE;
break;
case B_ERROR:
printf( "error during processing\n" );
return EXIT_FAILURE;
default:
printf( "unknown error: %ld\n", retval );
return EXIT_FAILURE;
break;
}
return EXIT_SUCCESS;
}

View File

@ -1,711 +0,0 @@
/*
** mwlib.c - POSIX 1003.2 "ar" command
**
** This isn't a pure POSIX 1003.2 ar; it only manipulates Metrowerks
** Library files, not general-purpose POSIX 1003.2 format archives.
**
** Dec. 14, 1997 Chris Herborth (chrish@kagi.com)
**
** This code is donated to the PUBLIC DOMAIN. You can use, abuse, modify,
** redistribute, steal, or otherwise manipulate this code. No restrictions
** at all. If you laugh at this code, you can't use it.
**
** This "ar" was implemented using IEEE Std 1003.2-1992 as the basis for
** the interface, and Metrowerk's published docs detailing their library
** format. Look inside for clues about how reality differs from MW's
** documentation on BeOS...
*/
#include <support/Errors.h>
#include <support/byteorder.h>
#ifndef NO_DEBUG
#include <assert.h>
#define ASSERT(cond) assert(cond)
#else
#define ASSERT(cond) ((void)0)
#endif
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <limits.h>
#include <string.h>
#include <errno.h>
#include <kernel/fs_attr.h>
#include <fcntl.h> /* is open() really here?!? sheesh... */
#include <storage/Mime.h>
#include <sys/stat.h>
#include "mwlib.h"
#include "copy_attrs.h"
static const char *rcs_version_id = "$Id$";
/* ----------------------------------------------------------------------
** Local prototypes
*/
static status_t load_MWLibFile( FILE *file, MWLibFile *libfile );
static size_t fwrite_big32( uint32 x, FILE *fp );
static size_t fwrite_big32_seek( uint32 x, long offset, FILE *fp );
static status_t add_object_sizes( MWObject *obj, uint32 *code, uint32 *data );
/* ----------------------------------------------------------------------
** Load a Metrowerks library file into the given MWLib object.
**
** Returns:
** B_OK - all is well
** B_FILE_NOT_FOUND - can't open the given file
** B_IO_ERROR - can't read from the given file
** B_BAD_VALUE - invalid magic word in the file
** B_MISMATCHED_VALUES - invalid processor value (ie, not a PowerPC lib),
** or the magicflags member is not 0, or the file
** version number isn't 1.
** B_NO_MEMORY - unable to allocate memory while loading the lib
*/
status_t load_MW_lib( MWLib *lib, const char *filename )
{
FILE *fp = NULL;
size_t recs = 0;
status_t retval = B_OK;
uint32 tmp32 = 0;
uint32 idx = 0;
char obj_name[PATH_MAX];
ASSERT( lib != NULL );
ASSERT( filename != NULL );
fp = fopen( filename, "r" );
if( !fp ) {
return B_FILE_NOT_FOUND;
}
/* Read and check the magic number.
*/
recs = fread( &tmp32, sizeof( uint32 ), 1, fp );
lib->header.magicword = B_BENDIAN_TO_HOST_INT32( tmp32 );
if( recs != 1 ) {
retval = B_IO_ERROR;
goto close_return;
} else if( lib->header.magicword != MWLIB_MAGIC_WORD ) {
retval = B_BAD_VALUE;
goto close_return;
}
/* Read and check the processor.
*/
recs = fread( &tmp32, sizeof( uint32 ), 1, fp );
lib->header.magicproc = B_BENDIAN_TO_HOST_INT32( tmp32 );
if( recs != 1 ) {
retval = B_IO_ERROR;
goto close_return;
} else if( lib->header.magicproc != MWLIB_MAGIC_PROC ) {
retval = B_MISMATCHED_VALUES;
goto close_return;
}
/* Read and check the flags.
*/
recs = fread( &tmp32, sizeof( uint32 ), 1, fp );
lib->header.magicflags = B_BENDIAN_TO_HOST_INT32( tmp32 );
if( recs != 1 ) {
retval = B_IO_ERROR;
goto close_return;
} else if( lib->header.magicflags != 0 ) {
retval = B_MISMATCHED_VALUES;
goto close_return;
}
/* Read and check the file version.
*/
recs = fread( &tmp32, sizeof( uint32 ), 1, fp );
lib->header.version = B_BENDIAN_TO_HOST_INT32( tmp32 );
if( recs != 1 ) {
retval = B_IO_ERROR;
goto close_return;
} else if( lib->header.version != 1 ) {
retval = B_MISMATCHED_VALUES;
goto close_return;
}
/* Read the code size, data size, and number of objects.
*/
recs = fread( &tmp32, sizeof( uint32 ), 1, fp );
lib->header.code_size = B_BENDIAN_TO_HOST_INT32( tmp32 );
if( recs != 1 ) {
retval = B_IO_ERROR;
goto close_return;
}
recs = fread( &tmp32, sizeof( uint32 ), 1, fp );
lib->header.data_size = B_BENDIAN_TO_HOST_INT32( tmp32 );
if( recs != 1 ) {
retval = B_IO_ERROR;
goto close_return;
}
recs = fread( &tmp32, sizeof( uint32 ), 1, fp );
lib->header.num_objects = B_BENDIAN_TO_HOST_INT32( tmp32 );
if( recs != 1 ) {
retval = B_IO_ERROR;
goto close_return;
}
/* Load the MWLibFile objects from the lib.
*/
lib->files = (MWLibFile *)malloc( lib->header.num_objects * sizeof( MWLibFile ) );
if( lib->files == NULL ) {
retval = B_NO_MEMORY;
goto close_return;
}
for( idx = 0; idx < lib->header.num_objects; idx++ ) {
retval = load_MWLibFile( fp, &(lib->files[idx]) );
if( retval != B_OK ) {
goto close_return;
}
}
/* Load the file names and object data.
**
** The file name actually appears twice in the library file; according
** to the docs, one is the file name, the other is the "full path name".
** In all of the libraries on my system, they're the same.
*/
lib->names = (char **)malloc( lib->header.num_objects * sizeof( char * ) );
lib->data = (char **)malloc( lib->header.num_objects * sizeof( char * ) );
if( lib->names == NULL || lib->data == NULL ) {
retval = B_NO_MEMORY;
goto close_return;
}
for( idx = 0; idx < lib->header.num_objects; idx ++ ) {
/* Load the name and copy it into the right spot.
*/
retval = fseek( fp, lib->files[idx].off_filename, SEEK_SET );
if( retval ) {
retval = B_IO_ERROR;
goto close_return;
}
if( fgets( obj_name, PATH_MAX, fp ) == NULL ) {
retval = B_IO_ERROR;
goto close_return;
}
lib->names[idx] = strdup( obj_name );
if( lib->names[idx] == NULL ) {
retval = B_NO_MEMORY;
goto close_return;
}
/* Load the object data.
*/
lib->data[idx] = (char *)malloc( lib->files[idx].object_size );
if( lib->data[idx] == NULL ) {
retval = B_NO_MEMORY;
goto close_return;
}
retval = fseek( fp, lib->files[idx].off_object, SEEK_SET );
if( retval ) {
retval = B_IO_ERROR;
goto close_return;
}
recs = fread( lib->data[idx], lib->files[idx].object_size, 1, fp );
if( recs != 1 ) {
retval = B_IO_ERROR;
goto close_return;
}
}
close_return:
fclose( fp );
return retval;
}
/* ----------------------------------------------------------------------
** Load the file header from a Metrowerks library file.
**
** Returns:
** B_OK - All is well
** B_IO_ERROR - Error reading the file
*/
static status_t load_MWLibFile( FILE *file, MWLibFile *libfile )
{
size_t recs = 0;
uint32 tmp32 = 0;
ASSERT( file != NULL );
ASSERT( libfile != NULL );
/* Load the modification time.
*/
recs = fread( &tmp32, sizeof( uint32 ), 1, file );
libfile->m_time = (time_t)B_BENDIAN_TO_HOST_INT32( tmp32 );
if( recs != 1 ) {
return B_IO_ERROR;
}
/* Load the various offsets.
*/
recs = fread( &tmp32, sizeof( uint32 ), 1, file );
libfile->off_filename = B_BENDIAN_TO_HOST_INT32( tmp32 );
if( recs != 1 ) {
return B_IO_ERROR;
}
recs = fread( &tmp32, sizeof( uint32 ), 1, file );
libfile->off_fullpath = B_BENDIAN_TO_HOST_INT32( tmp32 );
if( recs != 1 ) {
return B_IO_ERROR;
}
recs = fread( &tmp32, sizeof( uint32 ), 1, file );
libfile->off_object = B_BENDIAN_TO_HOST_INT32( tmp32 );
if( recs != 1 ) {
return B_IO_ERROR;
}
/* Load the object size.
*/
recs = fread( &tmp32, sizeof( uint32 ), 1, file );
libfile->object_size = B_BENDIAN_TO_HOST_INT32( tmp32 );
if( recs != 1 ) {
return B_IO_ERROR;
}
return B_OK;
}
/* ----------------------------------------------------------------------
** Write a Metrowerks library file.
**
** Returns:
** B_OK - all is well; doesn't necessarily mean the file was written
** properly, just that you didn't lose any data
** B_NO_MEMORY - unable to allocate offset buffers
** B_ERROR - problem with backup file (can't rename existing file)
**
** Note:
** If you use this in a long-lived program, it leaks memory; the MWLib
** contents are never free()'d.
**
** Two-pass technique:
**
** pass 1 - write file header (need CODE SIZE and DATA SIZE)
** write object headers (need offsets for FILENAME, FULL PATH, DATA)
** write filenames (store offsets for object headers)
** write padding (file size % 4 bytes)
** write file data (store offset for object header; add to code/data
** size for file header; pad data size % 4 bytes)
**
** pass 2 - fill in file header CODE SIZE and DATA SIZE
** fill in object headers FILENAME, FULL PATH, DATA
**
** You could avoid this by building up the file headers in memory, but this is
** easier (?) and I'm not that concerned with speed...
**
*/
typedef struct file_header_offsets {
long codesize_offset;
long datasize_offset;
} file_header_offsets;
typedef struct obj_header_offsets {
long filename_offset;
uint32 filename_offset_value;
long fullpath_offset;
uint32 fullpath_offset_value;
long data_offset;
uint32 data_offset_value;
} obj_header_offsets;
static size_t fwrite_big32( uint32 x, FILE *fp )
{
uint32 tmp32 = B_HOST_TO_BENDIAN_INT32( x );
ASSERT( fp != NULL );
return fwrite( &tmp32, sizeof(tmp32), 1, fp );
}
static size_t fwrite_big32_seek( uint32 x, long offset, FILE *fp )
{
uint32 tmp32 = B_HOST_TO_BENDIAN_INT32( x );
ASSERT( fp != NULL );
if( fseek( fp, offset, SEEK_SET ) ) {
return 0;
}
return fwrite( &tmp32, sizeof(tmp32), 1, fp );
}
static status_t add_object_sizes( MWObject *obj, uint32 *code, uint32 *data )
{
ASSERT( obj != NULL );
ASSERT( code != NULL );
ASSERT( data != NULL );
if( B_BENDIAN_TO_HOST_INT32( obj->magic_word ) != 'MWOB' ||
B_BENDIAN_TO_HOST_INT32( obj->arch ) != 'PPC ' ) {
return B_ERROR;
}
*code += B_BENDIAN_TO_HOST_INT32( obj->code_size );
*data += B_BENDIAN_TO_HOST_INT32( obj->data_size );
return B_OK;
}
void setfiletype( const char *file, const char *type )
{
int fd;
attr_info fa;
ssize_t wrote_bytes;
fd = open( file, O_RDWR );
if( fd < 0 ) {
fprintf( stderr, "ar: can't open %s to write file type, %s",
file, strerror( errno ) );
return;
}
fa.type = B_MIME_STRING_TYPE;
fa.size = (off_t)(strlen( type ) + 1);
wrote_bytes = fs_write_attr( fd, "BEOS:TYPE", fa.type, 0,
type, fa.size );
if( wrote_bytes != (ssize_t)fa.size ) {
fprintf( stderr, "ar: couldn't write complete file type, %s",
strerror( errno ) );
}
close( fd );
}
status_t write_MW_lib( MWLib *lib, const char *filename )
{
char *padding = "\0\0\0\0";
long pad_amount;
file_header_offsets head_offs;
obj_header_offsets *obj_offs;
uint32 codesize = 0;
uint32 datasize = 0;
uint32 num_objects = 0;
FILE *fp;
char *tmp_filename = NULL;
uint32 idx = 0;
size_t recs;
status_t retval;
mode_t mode_bits = 0666;
ASSERT( lib != NULL );
ASSERT( filename != NULL );
#if 0
/* Apparently, I don't understand umask()... */
/* Find the default file creation mask. The semantics of umask() suck.
*/
mode_bits = umask( (mode_t)0 );
(void)umask( mode_bits );
#endif
/* Easier access to the number of objects.
*/
num_objects = lib->header.num_objects;
/* Allocate some storage for keeping track of the things we need to
** write out in the second pass.
*/
head_offs.codesize_offset = 0;
head_offs.datasize_offset = 0;
obj_offs = (obj_header_offsets *)malloc( sizeof(obj_header_offsets) *
num_objects );
if( obj_offs == NULL ) {
fprintf( stderr, "ar: can't allocate memory for writing file\n" );
return B_NO_MEMORY;
}
memset( obj_offs, 0, sizeof(obj_header_offsets) * num_objects );
/* If the file exists, move it somewhere so we can recover if there's
** an error.
*/
retval = access( filename, F_OK );
if( retval == 0 ) {
struct stat s;
/* Preserve the mode bits.
*/
retval = stat( filename, &s );
if( retval != 0 ) {
fprintf( stderr, "ar: can't stat %s, %s\n", filename,
strerror( errno ) );
} else {
mode_bits = s.st_mode;
}
tmp_filename = (char *)malloc( strlen( filename ) + 2 );
if( tmp_filename == NULL ) {
fprintf( stderr,
"ar: can't allocate memory for temporary filename\n" );
} else {
sprintf( tmp_filename, "%s~", filename );
retval = access( tmp_filename, F_OK );
if( retval == 0 ) {
retval = unlink( tmp_filename );
if( retval != 0 ) {
fprintf( stderr, "ar: can't unlink %s, %s\n", tmp_filename,
strerror( errno ) );
free( tmp_filename );
tmp_filename = NULL;
}
}
if( tmp_filename ) {
retval = rename( filename, tmp_filename );
if( retval != 0 ) {
fprintf( stderr, "ar: can't move %s to backup, %s\n",
filename, strerror( errno ) );
return B_ERROR;
}
}
}
}
/* Attempt to open the archive file.
*/
fp = fopen( filename, "w" );
if( fp == NULL ) {
fprintf( stderr, "ar: can't open %s for write, %s\n", filename,
strerror( errno ) );
goto error_return;
}
/* ----------------------------------------------------------------------
** Write the file. Pass 1.
*/
recs = fwrite_big32( lib->header.magicword, fp );
recs += fwrite_big32( lib->header.magicproc, fp );
recs += fwrite_big32( lib->header.magicflags, fp );
recs += fwrite_big32( lib->header.version, fp );
if( recs != 4 ) {
fprintf( stderr, "ar: error writing header for %s, %s\n", filename,
strerror( errno ) );
goto error_return;
}
/* Keep track of the code/data size offsets.
*/
head_offs.codesize_offset = ftell( fp );
recs = fwrite_big32( codesize, fp );
head_offs.datasize_offset = ftell( fp );
recs += fwrite_big32( datasize, fp );
if( recs != 2 ) {
fprintf( stderr, "ar: error writing header for %s, %s\n", filename,
strerror( errno ) );
goto error_return;
}
recs = fwrite_big32( num_objects, fp );
if( recs != 1 ) {
fprintf( stderr, "ar: error writing header for %s, %s\n", filename,
strerror( errno ) );
goto error_return;
}
/* Write the object headers.
*/
for( idx = 0; idx < num_objects; idx++ ) {
recs = fwrite_big32( lib->files[idx].m_time, fp );
/* Keep track of the offsets, and write 0 for now.
*/
obj_offs[idx].filename_offset = ftell( fp );
recs += fwrite_big32( 0, fp );
obj_offs[idx].fullpath_offset = ftell( fp );
recs += fwrite_big32( 0, fp );
obj_offs[idx].data_offset = ftell( fp );
recs += fwrite_big32( 0, fp );
recs += fwrite_big32( lib->files[idx].object_size, fp );
if( recs != 5 ) {
fprintf( stderr, "ar: error writing object header for %s, %s\n",
filename, strerror( errno ) );
goto error_return;
}
}
/* Write the file names.
*/
for( idx = 0; idx < num_objects; idx++ ) {
/* Need to make sure that all the file names we write into the
** library DO NOT HAVE PATHS IN THEM, the world might end or something.
*/
size_t name_len = 0;
char *name_ptr = strrchr( lib->names[idx], '/' );
if( name_ptr == NULL ) {
name_ptr = lib->names[idx];
} else {
name_ptr++;
}
name_len = strlen( name_ptr ) + 1;
obj_offs[idx].filename_offset_value = ftell( fp );
recs = fwrite( name_ptr, name_len, 1, fp );
obj_offs[idx].fullpath_offset_value = ftell( fp );
recs += fwrite( name_ptr, name_len, 1, fp );
if( recs != 2 ) {
fprintf( stderr, "ar: error writing object name for %s, %s\n",
filename, strerror( errno ) );
goto error_return;
}
}
/* Pad the file if necessary.
*/
pad_amount = ftell( fp ) % 4;
if( pad_amount > 0 ) {
recs = fwrite( padding, pad_amount, 1, fp );
if( recs != 1 ) {
fprintf( stderr, "ar: error padding file %s, %s\n", filename,
strerror( errno ) );
goto error_return;
}
}
/* Write the object file data.
*/
for( idx = 0; idx < num_objects; idx++ ) {
obj_offs[idx].data_offset_value = ftell( fp );
recs = fwrite( lib->data[idx], lib->files[idx].object_size, 1, fp );
if( recs != 1 ) {
fprintf( stderr, "ar: writing object data for %s, %s\n", filename,
strerror( errno ) );
goto error_return;
}
/* Add up the code/data size.
*/
retval = add_object_sizes( (MWObject *)lib->data[idx],
&codesize, &datasize );
if( retval != B_OK ) {
fprintf( stderr, "ar - warning: %s is not an object file!\n",
lib->names[idx] );
goto error_return;
}
pad_amount = ftell( fp ) % 4;
if( pad_amount > 0 ) {
recs = fwrite( padding, pad_amount, 1, fp );
if( recs != 1 ) {
fprintf( stderr, "ar: error padding file %s, %s\n", filename,
strerror( errno ) );
goto error_return;
}
}
}
/* ----------------------------------------------------------------------
** Write the offsets into the file. Pass 2.
*/
/* Write the code/data sizes.
*/
recs = fwrite_big32_seek( codesize, head_offs.codesize_offset, fp );
recs += fwrite_big32_seek( datasize, head_offs.datasize_offset, fp );
if( recs != 2 ) {
fprintf( stderr, "ar - error writing code and data sizes, %s\n",
strerror( errno ) );
goto error_return;
}
/* Write the offsets for each file.
*/
for( idx = 0; idx < num_objects; idx++ ) {
recs = fwrite_big32_seek( obj_offs[idx].filename_offset_value,
obj_offs[idx].filename_offset, fp );
recs += fwrite_big32_seek( obj_offs[idx].fullpath_offset_value,
obj_offs[idx].fullpath_offset, fp );
recs += fwrite_big32_seek( obj_offs[idx].data_offset_value,
obj_offs[idx].data_offset, fp );
if( recs != 3 ) {
fprintf( stderr, "ar - error writing object offsets, %s\n",
strerror( errno ) );
goto error_return;
}
}
/* If all is OK, close the file and get out of here after nuking the
** temp file (if any), preserving the original file mode, and preserving
** the file attributes.
*/
fclose( fp );
/* Preserve the original file mode bits.
*/
retval = chmod( filename, mode_bits );
if( retval != 0 ) {
fprintf( stderr, "ar: unable to change file mode for %s, %s\n",
filename, strerror( errno ) );
}
/* Nuke the temp file (if any), after copying over any file attributes.
*/
if( tmp_filename != NULL ) {
retval = copy_attrs( filename, tmp_filename );
retval = unlink( tmp_filename );
if( retval != 0 ) {
fprintf( stderr, "ar - error unlinking %s, %s\n", tmp_filename,
strerror( errno ) );
}
free( tmp_filename );
} else {
/* If there isn't a temp file, we should still give this new
** file a file type attribute.
*/
setfiletype( filename, "application/x-mw-library" );
}
return B_OK;
error_return:
/* Restore the original file if we had any problems.
*/
fclose( fp );
if( tmp_filename != NULL ) {
retval = unlink( filename );
retval = rename( tmp_filename, filename );
if( retval != 0 ) {
fprintf( stderr, "ar: can't restore %s to %s, %s\n",
tmp_filename, filename, strerror( errno ) );
}
}
return B_ERROR;
}

View File

@ -1,118 +0,0 @@
/*
** mwlib.h - POSIX 1003.2 "ar" command
**
** $Id$
**
** This isn't a pure POSIX 1003.2 ar; it only manipulates Metrowerks
** Library files, not general-purpose POSIX 1003.2 format archives.
**
** Dec. 14, 1997 Chris Herborth (chrish@qnx.com)
**
** This code is donated to the PUBLIC DOMAIN. You can use, abuse, modify,
** redistribute, steal, or otherwise manipulate this code. No restrictions
** at all. If you laugh at this code, you can't use it.
**
** This "ar" was implemented using IEEE Std 1003.2-1992 as the basis for
** the interface, and Metrowerk's published docs detailing their library
** format. Look inside for clues about how reality differs from MW's
** documentation on BeOS...
*/
#include <support/SupportDefs.h>
#include <time.h>
/* ----------------------------------------------------------------------
** Constants
**
*/
#define MWLIB_MAGIC_WORD 'MWOB'
#define MWLIB_MAGIC_PROC 'PPC '
/* ----------------------------------------------------------------------
** Structures
**
** This is based on the "Metrowerks CodeWarrior Library Reference
** Specification", which isn't 100% accurate for BeOS.
*/
typedef struct MWLibHeader {
uint32 magicword;
uint32 magicproc;
uint32 magicflags;
uint32 version;
uint32 code_size;
uint32 data_size;
uint32 num_objects;
} MWLibHeader;
typedef struct MWLibFile {
time_t m_time;
uint32 off_filename;
uint32 off_fullpath;
uint32 off_object;
uint32 object_size;
} MWLibFile;
typedef struct MWLib {
MWLibHeader header;
MWLibFile *files;
char **names;
char **data;
} MWLib;
/* This bears no resemblance to what's in the Metrowerks docs.
**
** Note that this is incomplete; this is all the info I needed for
** ar though.
*/
typedef struct MWObject {
uint32 magic_word; /* 'MWOB' */
uint32 arch; /* 'PPC '; this isn't in the docs */
uint32 version;
uint32 flags;
uint32 code_size;
uint32 data_size;
} MWObject;
/* ----------------------------------------------------------------------
** Function prototypes
**
** load_MW_lib() - load a Metrowerks library
**
** Returns:
** B_OK - all is well
** B_FILE_NOT_FOUND - can't open the given file
** B_IO_ERROR - can't read from the given file
** B_BAD_VALUE - invalid magic word in the file
** B_MISMATCHED_VALUES - invalid processor value (ie, not a PowerPC lib),
** or the magicflags member is not 0, or the file
** version number isn't 1.
** B_NO_MEMORY - unable to allocate memory while loading the lib
**
** write_MW_lib() - write a Metrowerks library
**
** Returns:
** B_OK - all is well
**
** write_MW_lib() - write a Metrowerks library file
**
** Returns:
** B_OK - all is well; doesn't necessarily mean the file was written
** properly, just that you didn't lose any data
** B_NO_MEMORY - unable to allocate offset buffers
** B_ERROR - problem with backup file (can't rename existing file)
**
** Note:
** If you use this in a long-lived program, it leaks memory; the MWLib
** contents are never free()'d.
*/
status_t load_MW_lib( MWLib *lib, const char *filename );
status_t write_MW_lib( MWLib *lib, const char *filename );
void setfiletype( const char *filename, const char *type );