
#define NEWCODE 
#include <stdio.h>
#include <sys/param.h>
#if (RDSIGNAL & hpux)
#define signal sigset
#endif
#ifdef BSD42
#define memcpy(a,b,c) bcopy(b,a,c)
#define memset(a,b,c) bzero(a,c)
#define strchr index
#define strrchr rindex
#endif
#ifdef USING_PPL
#define NO_BACKUP
#endif
#ifndef SYSTEM5
#define getcwd(a,b) getwd(a)
#endif
#define MAX_FILENAME 255
#define SUCCESS 0
#define FAIL -1
#define YES 1
#define NO 0
#define TRUE 1
#define FALSE 0
#ifdef MSB
#undef MSB
#endif
#define MSB(x) (((x) >> 8) & 0xff)
#define LSB(x) ((x) & 0xff)
typedef unsigned char BYTE;
typedef unsigned short WORD;
typedef unsigned long ULONG;
typedef long LONG;
typedef unsigned char BOOL;
struct date_time {
BYTE day;
BYTE month;
BYTE year; 
BYTE second;
BYTE minute;
BYTE hour;
};
#define DATE_TIME_SIZE 6
#define MAX_USR_DATA (2048+sizeof(long))
#define X_INACTIVE (1<<0) 
#define X_SEND_DELV (1<<1) 
#define X_DEL_ANS_SEND (1<<2) 
#define X_DEL_A_ANS_SEND (1<<3) 
#define X_SEND (1<<4) 
#define X_RECV (1<<5) 
#define X_RECV_A (1<<6) 
#define X_EOF (1<<7) 
#define X_PENDING (1<<8) 
#define X_EXIT (1<<9) 
#define X_ABORT (1<<10) 
#define X_EOT (1<<11) 
#define X_DIR_EOT (1<<12) 
#define X_SEND_ATT (1<<13) 
#define X_BKUP_START (1<<14) 
#define X_BKUP (1<<15) 
#define X_RST_START (1<<16) 
#define X_RST (1<<17) 
#define X_EOF_RST (1<<18) 
#define X_EOT_RST (1<<19) 
#define X_SEND_DIR (1<<20) 
#define X_SEND_DIR_INFO (1<<21) 
#define X_DIR_EOF (1<<22) 
#define X_DIR_CONTINUE (1<<23) 
#define X_LAST_STATE 24 
enum xfer_return_type {
xfer_success,
xfer_eof,
xfer_no_memory,
xfer_improper_state,
xfer_rms_error,
xfer_failure,
xfer_nofile,
xfer_bad_packet
};
struct unix_record {
BYTE unix_rec_type;
BYTE unix_ret_code;
WORD unix_data_len;
WORD unix_pass_back;
BYTE unix_usr_data[MAX_USR_DATA];
};
#define UX_REC_OVHD 6
#define UX_REC_LEN (UX_REC_OVHD+MAX_USR_DATA)
struct xfer_context_block {
BYTE xfer_token; 
ULONG xfer_state; 
WORD xfer_type; 
struct unix_record *read_buffer; 
WORD read_length; 
struct unix_record *write_buffer; 
WORD write_length; 
struct unix_record *ack_buffer; 
WORD ack_length; 
BOOL read_ready; 
int sys_status; 
BYTE compression_type; 
BYTE disposition; 
char *attr_buffer; 
char *attr_pointer; 
BYTE directory_info; 
int directory_offset;
WORD directory_flag;
};
#define MESS_CONT 3
#define VERS_CHECK 0
#define VERS_REPLY 1
#define DEATH 2
#define TOUSER_DATA 3
#define FROMUSER_DATA 4
#define ACK_USER_DATA 5
#define HIPRI_DATA 8
#define DEFAULT_FILESPEC "*"
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>

enum xfer_return_type filesys_error();
enum xfer_return_type xfer_restore_start();
enum xfer_return_type xfer_rfile ();
enum xfer_return_type xfer_sfile ();
enum xfer_return_type xfer_start ();
enum xfer_return_type xfer_done ();
enum xfer_return_type xfer_abort ();
enum xfer_return_type xfer_ratt ();
enum xfer_return_type xfer_recv ();
enum xfer_return_type send_eof ();
enum xfer_return_type send_eot ();
enum xfer_return_type xfer_sclose ();
enum xfer_return_type xfer_get_directory();
enum xfer_return_type xfer_start_directory();
enum xfer_return_type xfer_send_directory();
enum xfer_return_type xfer_change_default();
enum xfer_return_type xfer_delete_files();
enum xfer_return_type xfer_qualify_file();
enum xfer_return_type xfer_continue_dir();
enum xfer_return_type check_cont ();
enum xfer_return_type check_err ();
enum xfer_return_type xfer_send ();
void initiate_send ();
int fill_rms_buffer ();
int open_next_file ();
int open_output ();
int search_for_file ();
enum xfer_return_type open_existing_file();
unsigned char host_file_newer ();
int fill_attribute_buffer ();
int parse_attributes ();
int parse_selection ();
void xfer_ready_error_packet ();
int get_msg_text ();
enum xfer_return_type xfer_rbackup ();
enum xfer_return_type init_backup ();
enum xfer_return_type xfer_backup ();
enum xfer_return_type xfer_bkup_restore_close ();
void init_restore ();
enum xfer_return_type xfer_rrestore ();
int fill_directory_restore ();
unsigned char next_restore_path ();
int fill_restore_buffer ();
enum xfer_return_type xfer_directory ();
enum xfer_return_type send_directory ();
BOOL Binit ();
void crit_initiate();
int Bterm();
void Bcreate();
void Bdelete ();
void crit_delete();
void Binstall ();
void crit_install();
unsigned char Bopenf ();
unsigned char Bopenn();
unsigned char Bread();
void Bwrite ();
unsigned char Badvance ();
unsigned short Bhash ();
unsigned char Blookup ();
unsigned char Bposition ();
void Add_to_free ();
void data_write ();
void Set_prior ();
void add_chr ();
unsigned char Bcompile ();
unsigned char Bmatch ();
BYTE bgchar();
void bgstr ();
unsigned short bgword();
long bglong();
long bglink();
void bpchar ();
void bpstr ();
void bpword ();
void bplong ();
void bplink ();
void bpfill();
void hdr_read();
void hdr_write();
void checkpoint ();
void info_restore();
BOOL hash_read ();
void hash_write ();
void dir_read ();
void dir_write ();
int file_open ();
int file_create ();
int file_read ();
int file_write ();
int file_close();
int file_delete ();
int RF_create ();
int RF_open ();
int RF_read ();
int RF_write ();
int RF_close();
int RF_position ();
int fl_open ();
int fl_create ();
int fl_close ();
int fl_read ();
int fl_write ();
void pshutdown ();
long get_file_size( ); 
int return_owner_attributes();
int return_group_attributes();
int return_protection_attributes();
enum xfer_return_type rd_ascii_data ();
enum xfer_return_type rd_binary_data ();
enum xfer_return_type rd_h_ascii_data ();
enum xfer_return_type rd_h_binary_data ();
enum xfer_return_type wr_binary_data ();
enum xfer_return_type wr_ascii_data ();
enum xfer_return_type wr_h_binary_data ();
enum xfer_return_type wr_h_ascii_data ();
unsigned char decomp_binary ();
unsigned char decomp_ascii ();
unsigned char decmph_binary ();
unsigned char decmph_ascii ();
#define MAX_ATTRIBUTE_SIZE 1024
#define MAX_ERROR_STRING_LENGTH 255
#define MAX_FILE_SPEC_LENGTH 255
#define MAX_DATA_LENGTH (MAX_USR_DATA - sizeof(long) - 3)
#define END_OF_RECORD 0xff
#define SPACE_COMPRESS_ESCAPE 0xfe 
#define ASCII_SPACE ' '
#define MAX_SELECTION_LENGTH 100
#define DEFAULT_RMS_RECORD_SIZE 1024
#define ATTRIBUTES_BUFFER_SIZE 1024
#define TOKEN_REQ '0'
#define SEND_FILE '1'
#define ANS_SEND '2'
#define GET_FILE '3'
#define DATA_MSG '4'
#define EOF_MSG '5'
#define EOT_MSG '6'
#define ABORT_XFER '7'
#define CONT_MSG '8'
#define ERR_MSG '9'
#define GET_DIR 'C'
#define SEND_DIR 'D'
#define ANSWER_DIR 'E'
#define CHANGE_DIR 'F'
#define ANSWER_CHANGE 'G'
#define DELETE_FILE 'H'
#define ANSWER_DELETE 'I'
#define QUALIFY_NAME 'J'
#define ANSWER_QUALIFY 'K'
#define COMPRESS '~' 
#define MIN_DUPS 4 
#define CS_NONE 0 
#define CS_START 1 
#define CS_STABLE 2
#define CS_ESCAPE 3
#define CS_DUPLICATE 4
#define CS_WRTDUP 5
#define CS_COUNT 6
#define CS_WRTREP 7
#define CS_CHAR 8
#define CS_ASCII_8 9 
#define COMP_NONE 0
#define COMP_REPEATED_RUN 1
#define COMP_HUFFMAN 2
#define TT_ASCII_MASK 1 
#define TT_ATTRIBUTE_MASK 2 
#define TT_IMAGE_MASK 4 
#define TT_BACKUP_MASK 16 
#define TT_RESTORE_MASK 32 
#define TT_ONLY_MASK 128 
#define TT_WILD_MASK 512 
#define TT_LEVEL_PATTERN 1024 
#define TT_ONEBYTE_EOR 2048 
#define DF_PURGE_MASK 1 
#define DF_APPEND_MASK 2 
#define DF_OVERWRITE_MASK 4 
#define DF_DELETE_MASK 8 
#define DF_UPDATE_MASK 64 
#define RESPONSE_OK 0
#define RESPONSE_ERROR 67
struct cstate {
int comp_state; 
int comp_type; 
WORD count; 
BYTE bcount; 
BYTE repeat; 
BYTE *buffer_ptr; 
int buffer_count; 
BOOL ascii_transfer; 
BOOL eof_pending; 
BYTE old, new; 
BOOL new_dir; 
BOOL restore_in_progress; 
};
struct generic_packet {
BYTE packet_type;
};
struct token_req_packet {
BYTE packet_type;
};
struct send_file_packet {
BYTE packet_type; 
WORD transfer_type; 
BYTE ascii_flags; 
BYTE compression_type;
BYTE disposition_flags; 
struct date_time creation_date;
struct date_time revision_date;
ULONG file_size;
BYTE file_sp_length;
BYTE pattern_length;
char file_spec[MAX_FILE_SPEC_LENGTH*2];
};
struct answer_send_packet {
BYTE packet_type;
BYTE start_code;
BYTE compression_type;
BYTE string_length; 
BYTE file_spec_length;
ULONG host_error; 
char error_string[MAX_ERROR_STRING_LENGTH+MAX_FILE_SPEC_LENGTH];
};
struct get_file_packet {
BYTE packet_type;
WORD transfer_type;
BYTE compression_type;
WORD file_sp_length;
WORD selection_length;
char file_spec[MAX_FILE_SPEC_LENGTH*2]; 
};
struct data_packet {
BYTE packet_type;
WORD count;
BYTE data[MAX_DATA_LENGTH];
};
struct eof_packet {
BYTE packet_type;
};
#define EOF_PACKET_SIZE 1
struct eot_packet {
BYTE packet_type;
};
#define EOT_PACKET_SIZE 1
struct abort_packet {
BYTE packet_type;
BYTE abort_code;
};
struct cont_msg_packet {
BYTE packet_type;
};
#define CONT_MSG_PACKET_SIZE 1
struct error_packet {
BYTE packet_type;
BYTE reflection_error_code; 
WORD string_length; 
ULONG host_error; 
char error_string[MAX_ERROR_STRING_LENGTH];
};
#define DIR_INFO_DEFAULT (1<<0) 
#define DIR_INFO_TREE (1<<1) 
#define DIR_INFO_FILES (1<<2) 
#define DIR_INFO_PATTERN (1<<3) 
#define DIR_SHOW_HIDDEN (1<<0) 
#define DIR_NOSHOW_ROOT (1<<1) 
struct get_dir_packet {
BYTE packet_type; 
BYTE compression; 
BYTE info; 
WORD flag; 
};
struct send_dir_packet {
BYTE packet_type;
BYTE content;
WORD flag; 
};
struct answer_dir_packet {
BYTE packet_type;
BYTE start_code;
WORD flag; 
};
struct change_dir_packet {
BYTE packet_type; 
BYTE level_number; 
WORD flag; 
BYTE length; 
BYTE string[MAX_FILENAME]; 
};
struct answer_change_packet {
BYTE packet_type; 
BYTE result; 
WORD flag; 
union {
struct {
BYTE update_info; 
BYTE level; 
BYTE default_length; 
BYTE pattern_length; 
BYTE string[MAX_FILENAME*2]; 
} update;
struct {
BYTE error_length; 
ULONG host_error; 
BYTE error_string[MAX_FILENAME]; 
} error;
} info;
};
struct delete_file_packet {
BYTE packet_type; 
WORD flag; 
BYTE length; 
BYTE name[MAX_FILENAME]; 
};
struct answer_delete_packet {
BYTE packet_type; 
BYTE result; 
WORD flag; 
BYTE error_length; 
ULONG host_error; 
BYTE string[MAX_FILENAME]; 
};
#define QUALIFY_LEVEL_PATTERN 0x0001
struct qualify_packet {
BYTE packet_type; 
WORD flag; 
BYTE local_length; 
BYTE host_length; 
BYTE buffer[MAX_FILENAME*2]; 
};
struct answer_qualify_packet {
BYTE packet_type; 
BYTE start_code; 
BYTE host_length; 
BYTE buffer[MAX_FILENAME]; 
};
#define X_PPL_OK 0
#define X_EOFiles ' '
#define X_MoreFiles '!'
#define X_BAD_PACKET 8 
#define X_FILESYS_ERROR 9 
#define X_NOUPDATE 66 
#define X_ERR 67
#define HIS 0
#define MINE 1
typedef struct 
{
unsigned char *space; 
unsigned char *curr_add; 
unsigned char *end; 
unsigned char *curr_next; 
int size; 
int inc; 
int n; 
int curr_n; 
} List;
List *NewList();
int AddList();
void FreeList();
unsigned char *NextList();
int ForeachList();
void FirstList();
void free();
#define NumberofList(l) (l->n)
#ifndef NO_BACKUP

#define LONG long
#define INIT = {0}
#define BU_FILENM ".*.*.* /WRQ BACKUP\\ *.*.*." 
#define RE_FILENM ".*.*.* /WRQ RESTORE\\ *.*.*." 
#define DEF_BURECSZ 256 
#define DEF_BUHASH 128 
#define BU_FNSZ 72 
#define BU_MAXRSZ 256 
#define BU_VERSZ 4 
#define BU_MAXBUCK 1024 
#define BU_DEFBUCK 256 
#define DUMMY_TIMEOUT 5 
#define BU_DIRSZ 97 
#define BU_HDRSZ 154 
#define WRQPATHSIZE 80 
#define FNAMESZ 42 
#define SPECIAL_RST_FILE "wrq_restor.tmp"
#define BKUP_FNAME 1 
#define BKUP_FSIZE 2 
#define BKUP_DATE 3 
#define BKUP_FATTR 4 
#define BKUP_FDATA 5 
#define RST_BACKUP_FILE 1 
#define RST_F_PATHNAME 2 
#define RST_SUBDIR 3 
#define RST_PATHNAME 4 
#define RST_F_FILE 1
#define RST_FDIR 2
#define RST_FDATA 3
#define RST_NEXT_FILE 4
#define RST_EOF 5
#define RST_BUFFER_SIZE 0x100
#define CKPT_OKAY 0 
#define CKPT_INITIATE 1 
#define CKPT_DELETE 2 
#define CKPT_INSTALL 3 
#define SD_CHAR '\\' 
#define AUTOSIZE 300
#define SUBDIR '\001'
#define FCHAR 'C'
#define FDOT 'D'
#define FANY 'A'
#define FSUBDIR 'S'
#define FSUCCEED 'Y'
#define FFAIL 'F'
#define YES 1
#define NO 0
#define NO_TIMEOUT -1 
typedef struct { 
LONG syn_next; 
LONG dfirst; 
LONG dlast; 
WORD fdate; 
WORD ftime; 
LONG fsize; 
WORD ddate; 
WORD dtime; 
BYTE dattr; 
BYTE fname[BU_FNSZ]; 
} VAXDIR;
typedef struct { 
BYTE version[BU_VERSZ]; 
WORD recsize; 
WORD buckets; 
BYTE hrec_count; 
WORD hblocking; 
LONG free_first; 
LONG free_last; 
LONG file_last; 
WORD bu_date; 
WORD bu_time; 
BYTE c_status; 
BYTE c_dupname; 
LONG c_prior; 
LONG c_current; 
LONG c_bucket; 
LONG c_nfirst; 
LONG c_newdir; 
LONG c_odfirst; 
LONG c_odlast; 
VAXDIR c_dir; 
} HDR;
#endif
#define swap(X,Y) {(X)=(X)^(Y); (Y)=(X)^(Y); (X)=(X)^(Y);}
#define min(a,b) (((a) < (b)) ? (a) : (b))
extern int errno;
void put_byte(), put_word(), put_nbyte(), put_long();
unsigned char get_byte();
WORD get_word();
ULONG get_long();
void get_nbyte();
char *NextDir(), *FullName();
ULONG GetUnixDate();
BOOL msg_cont = FALSE;
int xfer_fd = -1;
struct stat statbuf;
int first_file = TRUE;
unsigned char badselection_message[] = "Bad selection string";
unsigned char badattr_message[] = "Invalid attribute string";
unsigned char noupdate_message[] = "Host file has newer date";
unsigned char nofile_message[] = "Host file does not exist";
unsigned char sys_error_message[] = "Host file system error";
unsigned char improper_state_message[] = "Transfer in improper state";
unsigned char bad_packet_message[] = "Unknown packet received";
unsigned char bkup_fail_message[] = "Terminating - backup process failed";
unsigned char rst_close_message[] = "Failed creating temp restore file";
unsigned char rst_invalid_message[] = "Invalid restore file";
unsigned char bkup_invalid_message[] = "Invalid backup file";
unsigned char no_rst_message[] = "No matching files to restore";
unsigned char no_backup_message[] = "Backup/restore not supported";
unsigned char *rms_buffer = (unsigned char *) NULL;
unsigned char *end_rms_buffer= (unsigned char *) 0;
WORD rms_bsize; 
char init_file_spec[MAX_FILENAME+1]; 
ULONG file_size; 
WORD rec_size; 
char file_specification[MAX_FILENAME+1]; 
struct date_time creation_date; 
struct date_time revision_date; 
extern char currentDirectory[MAX_FILENAME+1]; 
extern char currentFilespec[MAX_FILENAME+1];
char att_buffer[MAX_ATTRIBUTE_SIZE]; 
char current_file[MAX_FILENAME+1];
int is_selection = FALSE;
#define RETURNED_ATTRIBUTES 3
int (*returned_attribute_routine[])() = {
return_owner_attributes,
return_group_attributes,
return_protection_attributes };
BOOL (*decompress)();
enum xfer_return_type (*write_rms_data)();
enum xfer_return_type (*read_rms_data)();
BOOL (*decomp_routine[2][2])() =
{{ decomp_binary, decomp_ascii},
{decmph_binary, decmph_ascii }};
enum xfer_return_type (*wr_data_routine[2][2])() =
{{ wr_binary_data, wr_ascii_data} ,
{ wr_h_binary_data, wr_h_ascii_data }};
enum xfer_return_type (*rd_data_routine[2][2])() =
{{ rd_binary_data, rd_ascii_data},
{ rd_h_binary_data, rd_h_ascii_data }};
struct cstate c_state;
#define NO_RESTORE -2
#ifndef NO_BACKUP
int bkup_state; 
long bkup_byte_count; 
char bkup_filespec[WRQPATHSIZE]; 
int bkup_f_offset;
long bkup_f_size; 
ULONG bkup_dt_time; 
WORD bkup_date;
WORD bkup_time;
unsigned char bkup_f_attr; 
WORD bkup_new_date;
WORD bkup_new_time;
char rst_file_name[FNAMESZ+1]; 
int rst_state; 
char rst_path[WRQPATHSIZE+1]; 
unsigned char subdir_flag[2]; 
BOOL subs_ok; 
BOOL rst_more; 
int rst_count; 
int rst_dir_size; 
unsigned char rst_dir[BU_FNSZ+4+2+2+1]; 
LONG htab[BU_MAXBUCK] INIT; 
unsigned char bu_rec[BU_MAXRSZ] INIT; 
unsigned char bu_rec2[BU_MAXRSZ] INIT; 
unsigned char *bu_ptr INIT; 
LONG bu_link INIT; 
LONG file_lrec INIT; 
LONG bkup_eof INIT; 
unsigned char autotab[AUTOSIZE+1] = {0};
unsigned char *autoix = NULL;
VAXDIR dir INIT; 
HDR hdr INIT; 
unsigned char dupname INIT; 
LONG prior INIT; 
LONG current INIT; 
LONG bucket INIT; 
LONG nfirst INIT; 
LONG newdir INIT; 
LONG odfirst INIT; 
LONG odlast INIT; 
WORD ferrno INIT; 
char *ferrtx INIT; 
char file_switch = ' '; 
int bkup_closed = YES; 
int u_fd = -1; 
int u_eof = NO; 
int temp_fd;
int rest_fd;
int RF_rsize = 0;
int RF_eof = 0;
FILE *RF_ptr;
#endif
extern void send_rr();
extern int choke_circ(), send_credit_frame();
struct send_file_packet sfp;
struct answer_send_packet asp;
struct get_file_packet gfp;
struct data_packet dp;
struct error_packet ep;
int rms_status;
#undef MSB
#define MSB(x) (((x) >> 8) & 0xff)
#undef LSB
#define LSB(x) ((x) & 0xff)
#define SPACE_INIT 0
#define SPACE_PROCESSOLD 1
#define SPACE_WRITEOLD 2
#define V_ERROR -2
#define MAX_SPACE_COUNT 125
#define MAX_RLE_COUNT 250
#define BITSPERBYTE 8
#define TOKEN_COUNT(i) LSB(token_cnt_ptrs[i])
#define TOKEN_PTR(i) MSB(token_cnt_ptrs[i])
static unsigned short token_table[] =
{
(0+0)*0x1000, (0+1)*0x1000, (2+0)*0x1000, (2+1)*0x1000,
(8+0)*0x800, (8+1)*0x800, (8+2)*0x800, (8+3)*0x800,
(24+0)*0x400, (24+1)*0x400, (24+2)*0x400, (24+3)*0x400,
(24+4)*0x400, (24+5)*0x400, (24+6)*0x400, (24+7)*0x400,
(64+0)*0x200, (64+1)*0x200, (64+2)*0x200, (64+3)*0x200,
(64+4)*0x200, (64+5)*0x200, (64+6)*0x200, (64+7)*0x200,
(64+8)*0x200, (64+9)*0x200, (64+10)*0x200, (64+11)*0x200,
(64+12)*0x200, (64+13)*0x200, (64+14)*0x200, (64+15)*0x200,
(160+0)*0x100, (160+1)*0x100, (160+2)*0x100, (160+3)*0x100,
(160+4)*0x100, (160+5)*0x100, (160+6)*0x100, (160+7)*0x100,
(160+8)*0x100, (160+9)*0x100, (160+10)*0x100, (160+11)*0x100,
(160+12)*0x100, (160+13)*0x100, (160+14)*0x100, (160+15)*0x100,
(160+16)*0x100, (160+17)*0x100, (160+18)*0x100, (160+19)*0x100,
(160+20)*0x100, (160+21)*0x100, (160+22)*0x100, (160+23)*0x100,
(160+24)*0x100, (160+25)*0x100, (160+26)*0x100, (160+27)*0x100,
(160+28)*0x100, (160+29)*0x100, (160+30)*0x100, (160+31)*0x100,
(384+0)*0x80, (384+1)*0x80, (384+2)*0x80, (384+3)*0x80,
(384+4)*0x80, (384+5)*0x80, (384+6)*0x80, (384+7)*0x80,
(384+8)*0x80, (384+9)*0x80, (384+10)*0x80, (384+11)*0x80,
(384+12)*0x80, (384+13)*0x80, (384+14)*0x80, (384+15)*0x80,
(384+16)*0x80, (384+17)*0x80, (384+18)*0x80, (384+19)*0x80,
(384+20)*0x80, (384+21)*0x80, (384+22)*0x80, (384+23)*0x80,
(384+24)*0x80, (384+25)*0x80, (384+26)*0x80, (384+27)*0x80,
(384+28)*0x80, (384+29)*0x80, (384+30)*0x80, (384+31)*0x80,
(384+32)*0x80, (384+33)*0x80, (384+34)*0x80, (384+35)*0x80,
(384+36)*0x80, (384+37)*0x80, (384+38)*0x80, (384+39)*0x80,
(384+40)*0x80, (384+41)*0x80, (384+42)*0x80, (384+43)*0x80,
(384+44)*0x80, (384+45)*0x80, (384+46)*0x80, (384+47)*0x80,
(384+48)*0x80, (384+49)*0x80, (384+50)*0x80, (384+51)*0x80,
(384+52)*0x80, (384+53)*0x80, (384+54)*0x80, (384+55)*0x80,
(384+56)*0x80, (384+57)*0x80, (384+58)*0x80, (384+59)*0x80,
(384+60)*0x80, (384+61)*0x80, (384+62)*0x80, (384+63)*0x80,
(896+0)*0x40, (896+1)*0x40, (896+2)*0x40, (896+3)*0x40,
(896+4)*0x40, (896+5)*0x40, (896+6)*0x40, (896+7)*0x40,
(896+8)*0x40, (896+9)*0x40, (896+10)*0x40, (896+11)*0x40,
(896+12)*0x40, (896+13)*0x40, (896+14)*0x40, (896+15)*0x40,
(896+16)*0x40, (896+17)*0x40, (896+18)*0x40, (896+19)*0x40,
(896+20)*0x40, (896+21)*0x40, (896+22)*0x40, (896+23)*0x40,
(896+24)*0x40, (896+25)*0x40, (896+26)*0x40, (896+27)*0x40,
(896+28)*0x40, (896+29)*0x40, (896+30)*0x40, (896+31)*0x40,
(896+32)*0x40, (896+33)*0x40, (896+34)*0x40, (896+35)*0x40,
(896+36)*0x40, (896+37)*0x40, (896+38)*0x40, (896+39)*0x40,
(896+40)*0x40, (896+41)*0x40, (896+42)*0x40, (896+43)*0x40,
(896+44)*0x40, (896+45)*0x40, (896+46)*0x40, (896+47)*0x40,
(896+48)*0x40, (896+49)*0x40, (896+50)*0x40, (896+51)*0x40,
(896+52)*0x40, (896+53)*0x40, (896+54)*0x40, (896+55)*0x40,
(896+56)*0x40, (896+57)*0x40, (896+58)*0x40, (896+59)*0x40,
(896+60)*0x40, (896+61)*0x40, (896+62)*0x40, (896+63)*0x40,
(896+64)*0x40, (896+65)*0x40, (896+66)*0x40, (896+67)*0x40,
(896+68)*0x40, (896+69)*0x40, (896+70)*0x40, (896+71)*0x40,
(896+72)*0x40, (896+73)*0x40, (896+74)*0x40, (896+75)*0x40,
(896+76)*0x40, (896+77)*0x40, (896+78)*0x40, (896+79)*0x40,
(896+80)*0x40, (896+81)*0x40, (896+82)*0x40, (896+83)*0x40,
(896+84)*0x40, (896+85)*0x40, (896+86)*0x40, (896+87)*0x40,
(896+88)*0x40, (896+89)*0x40, (896+90)*0x40, (896+91)*0x40,
(896+92)*0x40, (896+93)*0x40, (896+94)*0x40, (896+95)*0x40,
(896+96)*0x40, (896+97)*0x40, (896+98)*0x40, (896+99)*0x40,
(896+100)*0x40, (896+101)*0x40, (896+102)*0x40, (896+103)*0x40,
(896+104)*0x40, (896+105)*0x40, (896+106)*0x40, (896+107)*0x40,
(896+108)*0x40, (896+109)*0x40, (896+110)*0x40, (896+111)*0x40,
(896+112)*0x40, (896+113)*0x40, (896+114)*0x40, (896+115)*0x40,
(896+116)*0x40, (896+117)*0x40, (896+118)*0x40, (896+119)*0x40,
(896+120)*0x40, (896+121)*0x40, (896+122)*0x40, (896+123)*0x40,
(896+124)*0x40, (896+125)*0x40, (896+126)*0x40, (896+127)*0x40
};
static unsigned char token_lengths[] =
{
4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11
};
static unsigned short token_cnt_ptrs[] =
{
0*0x100,1*0x100,2*0x100,3*0x100,4*0x100,
5*0x100,6*0x100,7*0x100,8*0x100,9*0x100,
10*0x100,11*0x100,12*0x100,13*0x100,14*0x100,
15*0x100,16*0x100,17*0x100,18*0x100,19*0x100,
20*0x100,21*0x100,22*0x100,23*0x100,24*0x100,
25*0x100,26*0x100,27*0x100,28*0x100,29*0x100,
30*0x100,31*0x100,32*0x100,33*0x100,34*0x100,
35*0x100,36*0x100,37*0x100,38*0x100,39*0x100,
40*0x100,41*0x100,42*0x100,43*0x100,44*0x100,
45*0x100,46*0x100,47*0x100,48*0x100,49*0x100,
50*0x100,51*0x100,52*0x100,53*0x100,54*0x100,
55*0x100,56*0x100,57*0x100,58*0x100,59*0x100,
60*0x100,61*0x100,62*0x100,63*0x100,64*0x100,
65*0x100,66*0x100,67*0x100,68*0x100,69*0x100,
70*0x100,71*0x100,72*0x100,73*0x100,74*0x100,
75*0x100,76*0x100,77*0x100,78*0x100,79*0x100,
80*0x100,81*0x100,82*0x100,83*0x100,84*0x100,
85*0x100,86*0x100,87*0x100,88*0x100,89*0x100,
90*0x100,91*0x100,92*0x100,93*0x100,94*0x100,
95*0x100,96*0x100,97*0x100,98*0x100,99*0x100,
100*0x100,101*0x100,102*0x100,103*0x100,104*0x100,
105*0x100,106*0x100,107*0x100,108*0x100,109*0x100,
110*0x100,111*0x100,112*0x100,113*0x100,114*0x100,
115*0x100,116*0x100,117*0x100,118*0x100,119*0x100,
120*0x100,121*0x100,122*0x100,123*0x100,124*0x100,
125*0x100,126*0x100,127*0x100,128*0x100,129*0x100,
130*0x100,131*0x100,132*0x100,133*0x100,134*0x100,
135*0x100,136*0x100,137*0x100,138*0x100,139*0x100,
140*0x100,141*0x100,142*0x100,143*0x100,144*0x100,
145*0x100,146*0x100,147*0x100,148*0x100,149*0x100,
150*0x100,151*0x100,152*0x100,153*0x100,154*0x100,
155*0x100,156*0x100,157*0x100,158*0x100,159*0x100,
160*0x100,161*0x100,162*0x100,163*0x100,164*0x100,
165*0x100,166*0x100,167*0x100,168*0x100,169*0x100,
170*0x100,171*0x100,172*0x100,173*0x100,174*0x100,
175*0x100,176*0x100,177*0x100,178*0x100,179*0x100,
180*0x100,181*0x100,182*0x100,183*0x100,184*0x100,
185*0x100,186*0x100,187*0x100,188*0x100,189*0x100,
190*0x100,191*0x100,192*0x100,193*0x100,194*0x100,
195*0x100,196*0x100,197*0x100,198*0x100,199*0x100,
200*0x100,201*0x100,202*0x100,203*0x100,204*0x100,
205*0x100,206*0x100,207*0x100,208*0x100,209*0x100,
210*0x100,211*0x100,212*0x100,213*0x100,214*0x100,
215*0x100,216*0x100,217*0x100,218*0x100,219*0x100,
220*0x100,221*0x100,222*0x100,223*0x100,224*0x100,
225*0x100,226*0x100,227*0x100,228*0x100,229*0x100,
230*0x100,231*0x100,232*0x100,233*0x100,234*0x100,
235*0x100,236*0x100,237*0x100,238*0x100,239*0x100,
240*0x100,241*0x100,242*0x100,243*0x100,244*0x100,
245*0x100,246*0x100,247*0x100,248*0x100,249*0x100,
250*0x100,251*0x100,252*0x100,253*0x100,254*0x100,
255*0x100
};
static unsigned char ptrs[] =
{
0,1,2,3,4,5,6,7,8,9,
10,11,12,13,14,15,16,17,18,19,
20,21,22,23,24,25,26,27,28,29,
30,31,32,33,34,35,36,37,38,39,
40,41,42,43,44,45,46,47,48,49,
50,51,52,53,54,55,56,57,58,59,
60,61,62,63,64,65,66,67,68,69,
70,71,72,73,74,75,76,77,78,79,
80,81,82,83,84,85,86,87,88,89,
90,91,92,93,94,95,96,97,98,99,
100,101,102,103,104,105,106,107,108,109,
110,111,112,113,114,115,116,117,118,119,
120,121,122,123,124,125,126,127,128,129,
130,131,132,133,134,135,136,137,138,139,
140,141,142,143,144,145,146,147,148,149,
150,151,152,153,154,155,156,157,158,159,
160,161,162,163,164,165,166,167,168,169,
170,171,172,173,174,175,176,177,178,179,
180,181,182,183,184,185,186,187,188,189,
190,191,192,193,194,195,196,197,198,199,
200,201,202,203,204,205,206,207,208,209,
210,211,212,213,214,215,216,217,218,219,
220,221,222,223,224,225,226,227,228,229,
230,231,232,233,234,235,236,237,238,239,
240,241,242,243,244,245,246,247,248,249,
250,251,252,253,254,255
};
char token_base[] =
{
0,2,4,8,16,32,64,128
};
#ifdef NEWCODE
unsigned char token_indexes[256];
#endif
#define END_TOK 0xffe0 
#define END_TOK_LENGTH 11
#define RLE_INIT_STATE 0
#define RLE_STABLE_STATE 1
#define RLE_TWO_STATE 2
#define RLE_THREE_STATE 3
#define RLE_PUSH_STATE 4
#define RLE_EOF_STATE 5
#define RLE_FLUSH_STATE 6
#define INIT_STATE 0
#define LEN_STATE 1
#define TOKEN_STATE 2
#define CHECK_END_STATE 3
#define COUNT_STATE 4
#define SPACE_STATE 5
static struct compression
{
unsigned long token; 
int tokenlen; 
unsigned char state; 
int save_char; 
unsigned char numbits; 
unsigned char len; 
unsigned char bitsleft; 
unsigned short byte; 
unsigned short count; 
unsigned char rle_state;
unsigned short space; 
unsigned char escape; 
unsigned char new_state;
unsigned char comp_state;
int old;
} compress;
#ifdef NO_MACROS
void urle_byte(c)
unsigned char c;
{
switch(compress.rle_state)
{
case RLE_INIT_STATE:
compress.rle_state = RLE_STABLE_STATE;
compress.save_char = c;
break;
case RLE_STABLE_STATE:
if (c != compress.save_char)
compress.save_char = c;
else
compress.rle_state = RLE_TWO_STATE;
break;
case RLE_TWO_STATE:
if (c != compress.save_char)
{
compress.save_char = c;
compress.rle_state = RLE_STABLE_STATE;
}
else
compress.rle_state = RLE_THREE_STATE;
break;
case RLE_THREE_STATE:
compress.rle_state = RLE_INIT_STATE;
break;
}
}
int readByte(xfer_context, byte_count)
struct xfer_context_block *xfer_context;
int *byte_count;
{
return (c_state.buffer_ptr < end_rms_buffer ? *(c_state.buffer_ptr++) : 
fill_h_rms_buffer(&c_state, xfer_context, byte_count));
}
#else
#define readByte(xfer_context, byte_count) \
(c_state.buffer_ptr < end_rms_buffer ? \
*(c_state.buffer_ptr++) : \
fill_h_rms_buffer(&c_state, xfer_context, byte_count))
#define urle_byte(c) \
{ \
switch(compress.rle_state) \
{ \
case RLE_INIT_STATE: \
compress.rle_state = RLE_STABLE_STATE; \
compress.save_char = c; \
break; \
case RLE_STABLE_STATE: \
if (c != compress.save_char) \
compress.save_char = c; \
else \
compress.rle_state = RLE_TWO_STATE; \
break; \
case RLE_TWO_STATE: \
if (c != compress.save_char) \
{ \
compress.save_char = c; \
compress.rle_state = RLE_STABLE_STATE; \
} \
else \
compress.rle_state = RLE_THREE_STATE; \
break; \
case RLE_THREE_STATE: \
compress.rle_state = RLE_INIT_STATE; \
break; \
} \
}
#endif
enum xfer_return_type rd_h_binary_data(b, len, xfer_context, byte_count)
struct xfer_context_block *xfer_context;
unsigned char *b;
int *len, *byte_count;
{
int c, bitsleft;
unsigned char *bptr, *end, i;
unsigned long token;
int tokenlen;
unsigned char j;
*byte_count = 0;
token = compress.token;
tokenlen = compress.tokenlen;
bptr = b;
end = b + MAX_DATA_LENGTH;
bitsleft = BITSPERBYTE;
while (bptr < end)
{
if (bitsleft > tokenlen)
{
token <<= tokenlen;
bitsleft -= tokenlen;
switch(compress.state)
{
case RLE_INIT_STATE:
compress.state = RLE_STABLE_STATE;
if (c_state.buffer_ptr < end_rms_buffer)
c = compress.save_char =
*(c_state.buffer_ptr++);
else if ((c = compress.save_char =
fill_h_rms_buffer(&c_state, xfer_context, 
byte_count)) < 0)
goto abnormal;
break;
case RLE_STABLE_STATE:
if (c_state.buffer_ptr < end_rms_buffer)
c = *(c_state.buffer_ptr++);
else if ((c = fill_h_rms_buffer(&c_state, 
xfer_context, byte_count)) < 0)
goto abnormal;
if (c != compress.save_char)
compress.save_char = c;
else
compress.state = RLE_TWO_STATE;
break;
case RLE_TWO_STATE:
if (c_state.buffer_ptr < end_rms_buffer)
c = *(c_state.buffer_ptr++);
else if ((c = fill_h_rms_buffer(&c_state, 
xfer_context, byte_count)) < 0)
goto abnormal;
if (c != compress.save_char)
{
compress.state = RLE_STABLE_STATE;
compress.save_char = c;
}
else
compress.state = RLE_THREE_STATE;
break;
case RLE_THREE_STATE:
{
int save;
compress.state = RLE_PUSH_STATE;
c = -1;
do
{
c++;
if (c_state.buffer_ptr < end_rms_buffer)
save = *(c_state.buffer_ptr++);
else if ((save = fill_h_rms_buffer(&c_state, 
xfer_context, byte_count)) == V_ERROR)
goto abnormal;
} while (save == compress.save_char && save != EOF &&
c < MAX_RLE_COUNT);
compress.save_char = save;
break;
}
case RLE_PUSH_STATE:
compress.state = RLE_STABLE_STATE;
if ((c = compress.save_char) < 0)
goto abnormal;
break;
case RLE_FLUSH_STATE:
case RLE_EOF_STATE:
goto abnormal;
}
i = ptrs[c];
tokenlen = token_lengths[i];
token = ((token&0x00ff0000) | token_table[i]);
#ifdef NEWCODE
token_indexes[TOKEN_COUNT(i)]++;
#endif
token_cnt_ptrs[i]++;
if (!i)
{
if (TOKEN_COUNT(0) == 0xff)
halve_counts();
}
else if (TOKEN_COUNT(i) > TOKEN_COUNT(i-1))
{
unsigned short temp;
unsigned short newcount;
newcount = TOKEN_COUNT(i);
#ifdef NEWCODE
j = token_indexes[newcount-1] - 1;
#else
for (j=i-1; j>0 && newcount > TOKEN_COUNT(j-1); j--)
;
#endif
temp = token_cnt_ptrs[j];
token_cnt_ptrs[j] = token_cnt_ptrs[i];
token_cnt_ptrs[i] = temp;
ptrs[TOKEN_PTR(j)] = j;
ptrs[TOKEN_PTR(i)] = i;
if (newcount == 0xff)
halve_counts();
}
continue;
abnormal:
if (compress.state == RLE_EOF_STATE)
{
*len = bptr - b;
return xfer_eof;
}
else if (compress.state == RLE_FLUSH_STATE)
{
if (bitsleft != BITSPERBYTE)
{
compress.state = RLE_EOF_STATE;
tokenlen = bitsleft;
token = ((token&0x00ff0000) | END_TOK);
}
else
{
*len = bptr - b;
return xfer_eof;
}
}
else if (c == EOF)
{
if (bitsleft != BITSPERBYTE)
{
tokenlen = END_TOK_LENGTH;
token = ((token&0x00ff0000) | END_TOK);
compress.state = RLE_FLUSH_STATE;
}
else
{
*len = bptr - b;
return xfer_eof;
}
}
else if (c == V_ERROR)
{
xfer_context->sys_status = rms_status;
*len = bptr - b;
return xfer_rms_error;
}
}
else
{
token <<= bitsleft;
tokenlen -= bitsleft;
*bptr++ = ((token>>16) & 0x000000ff);
bitsleft = BITSPERBYTE;
}
}
*len = MAX_DATA_LENGTH;
compress.token = token;
compress.tokenlen = tokenlen;
return xfer_success;
}
enum xfer_return_type rd_h_ascii_data(b, len, xfer_context, byte_count)
struct xfer_context_block *xfer_context;
unsigned char *b;
int *len, *byte_count;
{
int c, bitsleft;
unsigned char *bptr, *end, i;
unsigned long token;
int tokenlen;
*byte_count = 0;
token = compress.token;
tokenlen = compress.tokenlen;
bptr = b;
end = b + MAX_DATA_LENGTH;
bitsleft = BITSPERBYTE;
while (bptr < end)
{
if (bitsleft > tokenlen)
{
token <<= tokenlen;
bitsleft -= tokenlen;
switch(compress.state)
{
case RLE_INIT_STATE:
compress.state = RLE_STABLE_STATE;
c = compress.save_char = next_space_byte(xfer_context,
byte_count);
break;
case RLE_STABLE_STATE:
if ((c = next_space_byte(xfer_context, byte_count)) != 
compress.save_char)
compress.save_char = c;
else
compress.state = RLE_TWO_STATE;
break;
case RLE_TWO_STATE:
if ((c = next_space_byte(xfer_context, byte_count)) != 
compress.save_char)
{
compress.state = RLE_STABLE_STATE;
compress.save_char = c;
}
else
compress.state = RLE_THREE_STATE;
break;
case RLE_THREE_STATE:
{
int save;
compress.state = RLE_PUSH_STATE;
c = 0;
while ((save = next_space_byte(xfer_context, byte_count)) ==
compress.save_char &&
save != EOF && c < MAX_RLE_COUNT)
c++;
compress.save_char = save;
break;
}
case RLE_PUSH_STATE:
compress.state = RLE_STABLE_STATE;
c = compress.save_char;
break;
case RLE_FLUSH_STATE:
case RLE_EOF_STATE:
c = EOF;
break;
}
if (c >= 0)
{
i = ptrs[c];
tokenlen = token_lengths[i];
token = ((token&0x00ff0000) | token_table[i]);
#ifdef NEWCODE
token_indexes[TOKEN_COUNT(i)]++;
#endif
token_cnt_ptrs[i]++;
if (!i)
{
if (TOKEN_COUNT(0) == 0xff)
halve_counts();
}
else if (TOKEN_COUNT(i) > TOKEN_COUNT(i-1))
{
unsigned short temp;
unsigned char j;
unsigned short newcount;
newcount = TOKEN_COUNT(i);
#ifdef NEWCODE
j = token_indexes[newcount-1] - 1;
#else
for (j=i-1; j>0 && newcount > TOKEN_COUNT(j-1); j--)
;
#endif
temp = token_cnt_ptrs[j];
token_cnt_ptrs[j] = token_cnt_ptrs[i];
token_cnt_ptrs[i] = temp;
ptrs[TOKEN_PTR(j)] = j;
ptrs[TOKEN_PTR(i)] = i;
if (newcount == 0xff)
halve_counts();
}
}
else if (compress.state == RLE_EOF_STATE)
{
*len = bptr - b;
return xfer_eof;
}
else if (compress.state == RLE_FLUSH_STATE)
{
if (bitsleft != BITSPERBYTE)
{
compress.state = RLE_EOF_STATE;
tokenlen = bitsleft;
token = ((token&0x00ff0000) | END_TOK);
}
else
{
*len = bptr - b;
return xfer_eof;
}
}
else if (c == EOF)
{
if (bitsleft != BITSPERBYTE)
{
tokenlen = END_TOK_LENGTH;
token = ((token&0x00ff0000) | END_TOK);
compress.state = RLE_FLUSH_STATE;
}
else
{
*len = bptr - b;
return xfer_eof;
}
}
else if (c == V_ERROR)
{
xfer_context->sys_status = rms_status;
*len = bptr - b;
return xfer_rms_error;
}
}
else
{
token <<= bitsleft;
tokenlen -= bitsleft;
*bptr++ = ((token>>16) & 0x000000ff);
bitsleft = BITSPERBYTE;
}
}
*len = MAX_DATA_LENGTH;
compress.token = token;
compress.tokenlen = tokenlen;
return xfer_success;
}
InitCompression()
{
int i;
compress.token = 0L;
compress.tokenlen = 0;
compress.state = RLE_INIT_STATE;
compress.comp_state = SPACE_INIT;
for (i=0; i<256; i++)
{
ptrs[i] = i;
token_cnt_ptrs[i] = i << 8;
#ifdef NEWCODE
token_indexes[i] = 0;
#endif
}
}
halve_counts()
{
int i;
for (i=0; i<256; i++)
{
token_cnt_ptrs[i] = (token_cnt_ptrs[i] & 0xff00) | (TOKEN_COUNT(i)>>1);
#ifdef NEWCODE
token_indexes[i] = (i < 128 ? token_indexes[(i*2)+1] : 0);
#endif
}
}
next_space_byte(xfer_context, byte_count)
struct xfer_context_block *xfer_context;
int *byte_count;
{
int c, count;
switch(compress.comp_state)
{
case SPACE_INIT:
if ((c = readByte(xfer_context, byte_count)) == EOF)
return EOF;
else if (c == ASCII_SPACE)
{
count = 1;
while ((c=readByte(xfer_context, byte_count)) == ASCII_SPACE && 
count < MAX_SPACE_COUNT)
count++;
compress.old = c;
compress.comp_state = SPACE_PROCESSOLD;
return (count | 0x80);
}
else if (c == '\n')
return END_OF_RECORD;
else if (!(c & 0x80))
return c;
else
{
compress.old = c & 0x7f;
compress.comp_state = SPACE_WRITEOLD;
return SPACE_COMPRESS_ESCAPE;
}
case SPACE_PROCESSOLD:
if ((c = compress.old) == EOF)
return EOF;
else if (c == ASCII_SPACE)
{
count = 1;
while ((c=readByte(xfer_context, byte_count)) == ASCII_SPACE && 
count < MAX_SPACE_COUNT)
count++;
compress.old = c;
return (count | 0x80);
}
else if (c == '\n')
{
compress.comp_state = SPACE_INIT;
return END_OF_RECORD;
}
else if (!(c & 0x80))
{
compress.comp_state = SPACE_INIT;
return c;
}
else
{
compress.old = c & 0x7f;
compress.comp_state = SPACE_WRITEOLD;
return SPACE_COMPRESS_ESCAPE;
}
case SPACE_WRITEOLD:
compress.comp_state = SPACE_INIT;
return compress.old;
}
return EOF;
}
InitDecompress()
{
int i;
compress.state = INIT_STATE;
compress.new_state = INIT_STATE;
compress.rle_state = RLE_INIT_STATE;
compress.comp_state = SPACE_INIT;
compress.numbits = 0;
compress.bitsleft = 0;
compress.byte = 0;
for (i=0; i<256; i++)
{
token_cnt_ptrs[i] = i << 8;
#ifdef NEWCODE
token_indexes[i] = 0;
#endif
}
}
ResetDecompress()
{
compress.state = INIT_STATE;
compress.new_state = INIT_STATE;
compress.numbits = 0;
compress.bitsleft = 0;
compress.byte = 0;
}
BOOL decmph_binary(buffer, state, ch)
unsigned char **buffer, *ch;
struct cstate *state;
{
int token, i, j;
unsigned char newcount;
unsigned short temp;
if (compress.state == COUNT_STATE)
{
*ch = compress.save_char;
if (!--compress.count)
compress.state = INIT_STATE;
return 1;
}
if (!compress.bitsleft)
{
compress.bitsleft = BITSPERBYTE;
compress.byte = (compress.byte & 0xff00) | (**buffer & 0x00ff);
(*buffer)++;
}
if (compress.state == INIT_STATE)
{
compress.numbits = 3;
compress.byte &= 0x00ff;
compress.state = LEN_STATE;
}
again:
if (compress.bitsleft < compress.numbits)
{
compress.byte <<= compress.bitsleft;
compress.numbits -= compress.bitsleft;
compress.bitsleft = 0;
}
else
{
compress.byte <<= compress.numbits;
compress.bitsleft -= compress.numbits;
compress.numbits = 0;
}
if (compress.state == CHECK_END_STATE && compress.byte & 0x100)
{
ResetDecompress();
return 0; 
}
if (!compress.bitsleft && compress.numbits)
return 0;
switch(compress.state)
{
case LEN_STATE:
compress.state = TOKEN_STATE;
compress.numbits = (!(compress.len = MSB(compress.byte)) ? 1 :
compress.len);
compress.byte &= 0x00ff;
goto again;
case TOKEN_STATE:
token = MSB(compress.byte);
if (compress.len == 7 && token == 0x7f)
{
compress.state = CHECK_END_STATE;
compress.numbits = 1;
compress.byte &= 0x00ff;
goto again;
}
break;
case CHECK_END_STATE:
token = 0x7f;
compress.len = 7;
break;
}
i = (token+token_base[compress.len]) & 0xff;
compress.state = INIT_STATE;
#ifdef NEWCODE
token_indexes[TOKEN_COUNT(i)]++;
#endif
token_cnt_ptrs[i]++;
if (!i)
{
if (TOKEN_COUNT(0) == 0xff)
halve_counts();
*ch = TOKEN_PTR(0);
}
else if (TOKEN_COUNT(i) <= TOKEN_COUNT(i-1))
{
*ch = TOKEN_PTR(i);
}
else
{
newcount = TOKEN_COUNT(i);
*ch = TOKEN_PTR(i);
#ifdef NEWCODE
j = token_indexes[newcount-1] - 1;
#else
for (j=i-1; j>0 && newcount > TOKEN_COUNT(j-1); j--)
;
#endif
temp = token_cnt_ptrs[j];
token_cnt_ptrs[j] = token_cnt_ptrs[i];
token_cnt_ptrs[i] = temp;
if (newcount == 0xff)
halve_counts();
}
if (compress.rle_state != RLE_THREE_STATE)
{
urle_byte(*ch);
return 1;
}
urle_byte(*ch);
if (*ch)
{
compress.state = COUNT_STATE;
compress.count = *ch;
}
return 0;
}
BOOL decmph_ascii(buffer, state, ch)
unsigned char **buffer, *ch;
struct cstate *state;
{
int token, i, j;
unsigned char newcount;
unsigned short temp;
int c;
BOOL ff_is_eor;
if (compress.state >= COUNT_STATE)
{
if (compress.state == COUNT_STATE)
{
*ch = compress.save_char;
if (!--compress.count)
compress.state = INIT_STATE;
compress.new_state = compress.state;
return (((c = unspace_byte(*ch, &ff_is_eor)) >= 0) ? 
(*ch = c, 1) : 0);
}
else if (compress.state == SPACE_STATE)
{
if (!--compress.space)
{
compress.state = compress.new_state;
compress.new_state = INIT_STATE;
}
*ch = ASCII_SPACE;
return 1;
}
}
if (!compress.bitsleft)
{
compress.bitsleft = BITSPERBYTE;
compress.byte = (compress.byte & 0xff00) | (**buffer & 0x00ff);
(*buffer)++;
}
if (compress.state == INIT_STATE)
{
compress.numbits = 3;
compress.byte &= 0x00ff;
compress.state = LEN_STATE;
}
again:
if (compress.bitsleft < compress.numbits)
{
compress.byte <<= compress.bitsleft;
compress.numbits -= compress.bitsleft;
compress.bitsleft = 0;
}
else
{
compress.byte <<= compress.numbits;
compress.bitsleft -= compress.numbits;
compress.numbits = 0;
}
if (compress.state == CHECK_END_STATE && compress.byte & 0x100)
{
ResetDecompress();
return 0; 
}
if (!compress.bitsleft && compress.numbits)
return 0;
switch(compress.state)
{
case LEN_STATE:
compress.state = TOKEN_STATE;
compress.numbits = (!(compress.len = MSB(compress.byte)) ? 1 :
compress.len);
compress.byte &= 0x00ff;
goto again;
case TOKEN_STATE:
token = MSB(compress.byte);
if (compress.len == 7 && token == 0x7f)
{
compress.state = CHECK_END_STATE;
compress.numbits = 1;
compress.byte &= 0x00ff;
goto again;
}
break;
case CHECK_END_STATE:
token = 0x7f;
compress.len = 7;
break;
}
i = (token+token_base[compress.len]) & 0xff;
compress.state = INIT_STATE;
#ifdef NEWCODE
token_indexes[TOKEN_COUNT(i)]++;
#endif
token_cnt_ptrs[i]++;
if (!i)
{
if (TOKEN_COUNT(0) == 0xff)
halve_counts();
*ch = TOKEN_PTR(0);
}
else if (TOKEN_COUNT(i) <= TOKEN_COUNT(i-1))
{
*ch = TOKEN_PTR(i);
}
else
{
newcount = TOKEN_COUNT(i);
*ch = TOKEN_PTR(i);
#ifdef NEWCODE
j = token_indexes[newcount-1] - 1;
#else
for (j=i-1; j>0 && newcount > TOKEN_COUNT(j-1); j--)
;
#endif
temp = token_cnt_ptrs[j];
token_cnt_ptrs[j] = token_cnt_ptrs[i];
token_cnt_ptrs[i] = temp;
if (newcount == 0xff)
halve_counts();
}
if (compress.rle_state != RLE_THREE_STATE)
{
urle_byte(*ch);
return (((c = unspace_byte(*ch, &ff_is_eor)) >= 0) ? (*ch = c, 1) : 0);
}
urle_byte(*ch);
if (*ch)
{
compress.state = COUNT_STATE;
compress.count = *ch;
}
return 0;
}
unspace_byte(c, ff)
int c;
BOOL *ff;
{
*ff = TRUE;
if (compress.escape)
{
compress.escape = 0;
*ff = FALSE;
return c|0x80;
}
else if (!(c&0x80) || c == END_OF_RECORD)
{
return c;
}
else if (c == SPACE_COMPRESS_ESCAPE)
{
compress.escape++;
return -1;
}
else
{
compress.space = c & 0x7f;
compress.state = SPACE_STATE;
return -1;
}
}
fill_h_rms_buffer(state, xfer_context, byte_count)
struct cstate *state;
struct xfer_context_block *xfer_context;
int *byte_count;
{
int status;
status = fill_rms_buffer(state, xfer_context, byte_count);
end_rms_buffer = rms_buffer + c_state.buffer_count;
if (status == 0)
return *(c_state.buffer_ptr++);
else if (status == EOF)
return (EOF);
else
{
rms_status = status;
return (V_ERROR);
}
}
unsigned char get_byte(s)
unsigned char **s;
{
return *(*s)++;
}
WORD get_word(s)
unsigned char **s;
{
unsigned char c;
c = get_byte(s);
return((get_byte(s) << 8) + c); 
}
ULONG get_long(s)
unsigned char **s;
{
WORD w;
w = get_word(s);
return((get_word(s) << 16) + w);
}
void get_nbyte(s, b, n)
unsigned char **s, *b;
int n;
{
memcpy(b, *s, n);
(*s) += n; 
}
void put_byte(s, b)
unsigned char **s, b;
{
**s = b;
(*s)++;
}
void put_word(s, w)
unsigned char **s;
WORD w;
{
put_byte(s, w & 0xff);
put_byte(s, (w>>8)&0xff);
}
void put_long(s, l)
unsigned char **s;
ULONG l;
{
put_word(s, l & 0xffff);
put_word(s, (l>>16)&0xffff);
}
void put_nbyte(s, b, n)
unsigned char **s, *b;
int n;
{
if (n < 0) n = 0;
memcpy(*s, b, n);
(*s) += n; 
}
enum xfer_return_type xfer__initialize (xfer_context)
struct xfer_context_block **xfer_context;
{
char *getcwd();
if ( (*xfer_context =
(struct xfer_context_block *)
malloc(sizeof(struct xfer_context_block))) == NULL )
return(xfer_no_memory);
if ( ((*xfer_context)->read_buffer =
(struct unix_record *)malloc(UX_REC_LEN)) == NULL )
return(xfer_no_memory);
if ( ((*xfer_context)->write_buffer =
(struct unix_record *)malloc(UX_REC_LEN)) == NULL )
return(xfer_no_memory);
if ( ((*xfer_context)->ack_buffer =
(struct unix_record *)malloc(UX_REC_LEN)) == NULL )
return(xfer_no_memory);
if ( ((*xfer_context)->attr_buffer =
(char *)malloc(ATTRIBUTES_BUFFER_SIZE)) == NULL )
return(xfer_no_memory);
(*xfer_context)->xfer_token = HIS;
(*xfer_context)->xfer_state = X_INACTIVE;
if (xfer_fd != -1)
{
close(xfer_fd);
xfer_fd = -1;
}
msg_cont = FALSE;
(*xfer_context)->read_buffer->unix_rec_type = FROMUSER_DATA;
InitTime();
if (getcwd(currentDirectory, MAX_FILENAME+1) == NULL)
return(xfer_failure);
getCurrentLevel(); 
return(xfer_success);
}
enum xfer_return_type xfer__shutdown (xfer_context)
struct xfer_context_block *xfer_context;
{
if (xfer_fd != -1)
{
close(xfer_fd);
xfer_fd = -1;
}
free(xfer_context->read_buffer);
free(xfer_context->write_buffer);
free(xfer_context->ack_buffer);
free(xfer_context->attr_buffer);
free(xfer_context);
return(xfer_success);
}
enum xfer_return_type xfer__read_record (xfer_context)
struct xfer_context_block *xfer_context;
{
xfer_context->read_ready = FALSE;
return(xfer_success);
}
enum xfer_return_type xfer__write_record (xfer_context)
struct xfer_context_block *xfer_context;
{
enum xfer_return_type status;
static unsigned char msg_state = 0;
if (!(msg_cont))
{
msg_state = ((struct generic_packet *)
xfer_context->write_buffer->unix_usr_data)->packet_type;
}
switch (msg_state)
{
case DATA_MSG:
if (choke_circ(0))
send_credit_frame(0); 
else 
send_rr();
switch (xfer_context->xfer_state)
{
case X_RECV_A:
status = xfer_ratt(xfer_context);
break;
#ifndef NO_BACKUP
case X_BKUP:
case X_BKUP_START:
status = xfer_rbackup(xfer_context);
break;
case X_RST_START:
status = xfer_rrestore(xfer_context, 0);
break;
#endif
case X_RECV:
status = xfer_recv(xfer_context);
break;
default:
status = xfer_success;
break;
}
break;
case SEND_FILE:
status = xfer_rfile(xfer_context);
break;
case ANS_SEND:
status = xfer_start(xfer_context);
break;
case GET_FILE:
status = xfer_sfile(xfer_context);
break; 
case EOF_MSG:
#ifndef NO_BACKUP
if (xfer_context->xfer_state & (X_BKUP | X_RST_START) )
status = xfer_bkup_restore_close(xfer_context);
else
#endif
status = xfer_sclose(xfer_context);
break;
case EOT_MSG:
status = xfer_done(xfer_context);
break; 
case ABORT_XFER:
status = xfer_abort(xfer_context);
break;
case CONT_MSG:
if (xfer_context->xfer_state == X_EOT_RST)
status = send_eot(xfer_context);
else if (xfer_context->xfer_state == X_DIR_CONTINUE)
status = xfer_continue_dir(xfer_context);
else
{
first_file = FALSE;
status = check_cont(xfer_context);
}
break;
case ERR_MSG:
status = check_err(xfer_context);
break;
case GET_DIR:
status = xfer_get_directory(xfer_context);
break;
case ANSWER_DIR:
status = xfer_start_directory(xfer_context);
break;
case CHANGE_DIR:
status = xfer_change_default(xfer_context);
break;
case DELETE_FILE:
status = xfer_delete_files(xfer_context);
break;
case QUALIFY_NAME:
status = xfer_qualify_file(xfer_context);
break;
default:
xfer_ready_error_packet(xfer_context,ERR_MSG,X_BAD_PACKET,
bad_packet_message,0);
return(xfer_bad_packet);
} 
msg_cont = (xfer_context->write_buffer->unix_ret_code == MESS_CONT);
if (status == xfer_improper_state)
{
xfer_ready_error_packet(xfer_context,ERR_MSG,X_BAD_PACKET,
improper_state_message,0);
}
return(status);
}
enum xfer_return_type xfer__ack(xfer_context)
struct xfer_context_block *xfer_context;
{
enum xfer_return_type status = xfer_success;
switch (xfer_context->xfer_state)
{
case X_EXIT:
xfer_context->xfer_state = X_INACTIVE;
break;
case X_DEL_ANS_SEND:
xfer_context->xfer_state = X_RECV;
break;
case X_DEL_A_ANS_SEND:
xfer_context->xfer_state = X_RECV_A;
break;
case X_SEND:
case X_RST:
status = xfer_send(xfer_context);
break;
case X_EOF:
case X_EOF_RST:
status = send_eof(xfer_context);
break;
case X_EOT:
status = send_eot(xfer_context);
break;
case X_SEND_DIR_INFO:
status = xfer_send_directory(xfer_context);
break;
case X_DIR_EOF:
status = send_eof(xfer_context);
break;
case X_DIR_EOT:
status = send_eot(xfer_context);
break;
}
return(status); 
} 
char *merge_file_spec(merge_spec, pattern_spec)
char *merge_spec, *pattern_spec;
{
static char reg_file[MAX_FILENAME+1];
if (strlen(pattern_spec) == 0)
return merge_spec;
if (isdirectory(pattern_spec))
{
strcpy(reg_file, pattern_spec);
if (pattern_spec[strlen(pattern_spec)-1] != '/')
strcat(reg_file, "/");
strcat(reg_file, merge_spec);
return reg_file;
}
return pattern_spec;
}
enum xfer_return_type xfer_rfile (xfer_context)
struct xfer_context_block *xfer_context;
{
struct send_file_packet *packet;
struct answer_send_packet *answer;
unsigned char *b;
BOOL new_file;
enum xfer_return_type result;
char pattern_spec[MAX_FILENAME+1], merge_spec[MAX_FILENAME+1];
extern BOOL upper_case;
packet = &sfp;
answer = &asp;
b = (unsigned char *) xfer_context->write_buffer->unix_usr_data;
packet->packet_type = get_byte(&b);
packet->transfer_type = get_word(&b);
packet->ascii_flags = get_byte(&b);
packet->compression_type= get_byte(&b);
packet->disposition_flags = get_byte(&b);
get_nbyte(&b, &packet->creation_date, DATE_TIME_SIZE);
get_nbyte(&b, &packet->revision_date, DATE_TIME_SIZE);
packet->file_size = get_long(&b);
if ((packet->file_sp_length = get_byte(&b)) >= MAX_FILE_SPEC_LENGTH)
packet->file_sp_length = MAX_FILE_SPEC_LENGTH;
if ((packet->pattern_length = get_byte(&b)) >= MAX_FILE_SPEC_LENGTH)
packet->pattern_length = MAX_FILE_SPEC_LENGTH;
get_nbyte(&b, packet->file_spec, 
packet->file_sp_length+packet->pattern_length);
if (xfer_context->xfer_state != X_INACTIVE)
return(xfer_improper_state);
answer->string_length = 0;
answer->start_code = X_PPL_OK;
xfer_context->xfer_type = packet->transfer_type;
xfer_context->compression_type = packet->compression_type;
xfer_context->disposition = packet->disposition_flags;
c_state.ascii_transfer =(xfer_context->xfer_type & TT_ASCII_MASK);
write_rms_data = wr_data_routine
[xfer_context->compression_type == COMP_HUFFMAN ? 1 : 0]
[c_state.ascii_transfer];
decompress = decomp_routine
[xfer_context->compression_type == COMP_HUFFMAN ? 1 : 0]
[c_state.ascii_transfer];
#ifdef NO_BACKUP
if (packet->transfer_type & (TT_BACKUP_MASK | TT_RESTORE_MASK))
{
answer->start_code = X_FILESYS_ERROR;
answer->string_length = strlen(no_backup_message)+4;
answer->file_spec_length = strlen(file_specification);
strcpy(answer->error_string,no_backup_message);
memcpy(answer->error_string+answer->string_length-4,
file_specification, strlen(file_specification));
xfer_context->xfer_state = X_INACTIVE;
goto send_answer_send;
}
#endif
#ifndef NO_BACKUP
if (packet->transfer_type & TT_BACKUP_MASK)
{ 
decompress = decomp_routine
[xfer_context->compression_type == COMP_HUFFMAN ? 1 : 0]
[FALSE];
xfer_context->xfer_state = X_BKUP_START;
c_state.comp_state = 
(xfer_context->compression_type == COMP_NONE ? CS_NONE : CS_STABLE);
InitDecompress();
goto send_answer_send;
}
if (packet->transfer_type & TT_RESTORE_MASK)
{
init_restore(xfer_context);
goto send_answer_send;
}
#endif
creation_date = packet->creation_date;
revision_date = packet->revision_date;
file_size = packet->file_size;
(void)memcpy(merge_spec,packet->file_spec,packet->file_sp_length);
merge_spec[packet->file_sp_length] = '\0';
if (!upper_case && (xfer_context->xfer_type & TT_WILD_MASK))
lowcase(merge_spec);
(void)memcpy(pattern_spec,packet->file_spec+packet->file_sp_length, 
packet->pattern_length);
pattern_spec[packet->pattern_length] = '\0';
if (xfer_context->xfer_type & TT_LEVEL_PATTERN)
{
extern BYTE thisLevel;
extern BYTE thisName[MAX_FILENAME+1];
extern BYTE thisCD[MAX_FILENAME+1];
extern BYTE currentLevel;
thisLevel = *pattern_spec;
if (thisLevel == currentLevel-1)
*pattern_spec = (char)NULL;
else
{
strcpy(thisName, pattern_spec+1);
buildDirectoryName();
strcpy(pattern_spec, thisCD);
}
}
strcpy(file_specification, merge_file_spec(merge_spec, pattern_spec));
if ( xfer_context->disposition & DF_UPDATE_MASK )
{
if ( host_file_newer(&(packet->revision_date), &new_file) )
{
answer->start_code = X_NOUPDATE;
answer->string_length = strlen(noupdate_message)+4;
answer->file_spec_length = strlen(file_specification);
strcpy(answer->error_string,noupdate_message);
memcpy(answer->error_string+answer->string_length-4,
file_specification, strlen(file_specification));
goto send_answer_send;
}
else if (new_file)
{
answer->start_code = X_NOUPDATE;
answer->string_length = strlen(nofile_message)+4;
answer->file_spec_length = strlen(file_specification);
answer->host_error = ENOENT;
strcpy(answer->error_string,nofile_message);
memcpy(answer->error_string+answer->string_length-4,
file_specification, strlen(file_specification));
goto send_answer_send;
}
}
if (xfer_context->disposition & (DF_PURGE_MASK | DF_DELETE_MASK))
if (unlink(file_specification) != 0)
{
if (errno != ENOENT)
{
filesys_error(xfer_context, errno);
xfer_context->xfer_state = X_INACTIVE;
goto send_answer_send;
}
}
if ( xfer_context->disposition & (DF_APPEND_MASK | DF_OVERWRITE_MASK) )
{
if ((result = open_existing_file(xfer_context)) != xfer_nofile)
{
if (result != xfer_success)
{ 
xfer_context->xfer_state = X_INACTIVE;
goto send_answer_send;
}
else
{
if (xfer_context->xfer_type & TT_ATTRIBUTE_MASK)
{
xfer_context->xfer_state = X_DEL_A_ANS_SEND;
att_buffer[0] = '\0';
}
else
xfer_context->xfer_state = X_DEL_ANS_SEND;
goto init_comp_state;
}
}
}
xfer_context->sys_status = open_output();
if (xfer_context->sys_status == 0)
{
if (xfer_context->xfer_type & TT_ATTRIBUTE_MASK)
{
xfer_context->xfer_state = X_DEL_A_ANS_SEND;
att_buffer[0] = '\0';
}
else
xfer_context->xfer_state = X_DEL_ANS_SEND;
}
else
{
xfer_ready_error_packet(xfer_context,ANS_SEND,
X_FILESYS_ERROR,NULL,xfer_context->sys_status);
goto send_answer_send;
}
init_comp_state:
c_state.comp_state = 
(xfer_context->compression_type == COMP_NONE ? CS_NONE : CS_STABLE);
InitDecompress();
send_answer_send:
answer->packet_type = ANS_SEND;
answer->compression_type = xfer_context->compression_type;
b = (unsigned char *) xfer_context->read_buffer->unix_usr_data;
put_byte(&b, answer->packet_type);
put_byte(&b, answer->start_code);
put_byte(&b, answer->compression_type);
put_byte(&b, answer->string_length);
put_byte(&b, strlen(file_specification));
if (answer->string_length)
{
put_long(&b, answer->host_error);
put_nbyte(&b, answer->error_string, answer->string_length-4);
}
put_nbyte(&b, file_specification, strlen(file_specification));
xfer_context->read_buffer->unix_data_len =
b - xfer_context->read_buffer->unix_usr_data;
xfer_context->read_length =
xfer_context->read_buffer->unix_data_len + UX_REC_OVHD;
xfer_context->read_ready = TRUE;
return(xfer_success);
}
void xfer_ready_error_packet(xfer_context, packet, error_value, error_str, 
status_value)
struct xfer_context_block *xfer_context;
unsigned char packet;
WORD error_value;
char *error_str;
int status_value;
{
struct error_packet *error;
struct answer_send_packet *ans_start;
unsigned char *b;
WORD error_length;
char error_string[MAX_ERROR_STRING_LENGTH+1];
if (error_str == NULL)
error_length = get_msg_text(status_value, error_string);
else
{
strcpy(error_string, error_str);
error_length = strlen(error_str);
}
error_length += 4; 
if (packet == ERR_MSG)
{
error = &ep;
error->packet_type = ERR_MSG;
error->reflection_error_code = error_value;
error->string_length = error_length;
error->host_error = status_value;
strcpy(error->error_string, error_string);
b = (unsigned char *) xfer_context->read_buffer->unix_usr_data;
put_byte(&b, error->packet_type);
put_byte(&b, error->reflection_error_code);
put_word(&b, error->string_length);
put_long(&b, error->host_error);
put_nbyte(&b, error->error_string, error->string_length-4);
xfer_context->read_buffer->unix_data_len =
b - xfer_context->read_buffer->unix_usr_data;
}
else
{
ans_start = &asp;
ans_start->packet_type = ANS_SEND;
ans_start->start_code = error_value;
ans_start->string_length = error_length;
ans_start->host_error = status_value;
strcpy(ans_start->error_string, error_string);
b = (unsigned char *) xfer_context->read_buffer->unix_usr_data;
put_byte(&b, ans_start->packet_type);
put_byte(&b, ans_start->start_code);
put_byte(&b, ans_start->compression_type);
put_word(&b, ans_start->string_length);
put_long(&b, ans_start->host_error);
put_nbyte(&b, ans_start->error_string, ans_start->string_length-4);
xfer_context->read_buffer->unix_data_len =
b - xfer_context->read_buffer->unix_usr_data;
}
xfer_context->read_length =
xfer_context->read_buffer->unix_data_len + UX_REC_OVHD;
xfer_context->xfer_state = X_EXIT;
xfer_context->read_ready = TRUE;
}
enum xfer_return_type xfer_sfile (xfer_context)
struct xfer_context_block *xfer_context;
{
char *selection_ptr; 
struct get_file_packet *packet;
struct send_file_packet *send;
unsigned char *b;
packet = &gfp;
b = (unsigned char *) xfer_context->write_buffer->unix_usr_data;
packet->packet_type = get_byte(&b);
packet->transfer_type = get_word(&b);
packet->compression_type = get_byte(&b);
packet->file_sp_length = get_word(&b);
packet->selection_length = get_word(&b);
get_nbyte(&b, packet->file_spec, 
packet->file_sp_length+packet->selection_length);
if (xfer_context->xfer_state != X_INACTIVE)
return(xfer_improper_state);
xfer_context->compression_type = packet->compression_type;
xfer_context->xfer_type = packet->transfer_type;
c_state.ascii_transfer =(xfer_context->xfer_type & TT_ASCII_MASK);
read_rms_data = rd_data_routine
[xfer_context->compression_type == COMP_HUFFMAN ? 1 : 0]
[c_state.ascii_transfer];
if (xfer_context->xfer_type & TT_RESTORE_MASK)
{
send = &sfp;
send->packet_type = SEND_FILE;
send->transfer_type = xfer_context->xfer_type;
send->ascii_flags = 0;
send->compression_type = xfer_context->compression_type;
send->disposition_flags = 0;
send->file_sp_length = 0;
b = (unsigned char *) xfer_context->read_buffer->unix_usr_data;
put_byte(&b, send->packet_type);
put_word(&b, send->transfer_type);
put_byte(&b, send->ascii_flags);
put_byte(&b, send->compression_type);
put_byte(&b, send->disposition_flags);
put_nbyte(&b, &send->creation_date, DATE_TIME_SIZE);
put_nbyte(&b, &send->revision_date, DATE_TIME_SIZE);
put_long(&b, send->file_size);
put_word(&b, send->file_sp_length);
put_nbyte(&b, send->file_spec, send->file_sp_length);
xfer_context->xfer_state = X_SEND_DELV;
xfer_context->read_buffer->unix_data_len =
b - xfer_context->read_buffer->unix_usr_data;
xfer_context->read_length =
xfer_context->read_buffer->unix_data_len + UX_REC_OVHD;
xfer_context->read_ready = TRUE;
return(xfer_success);
}
(void)memcpy(init_file_spec,packet->file_spec,packet->file_sp_length);
init_file_spec[packet->file_sp_length] = '\0';
selection_ptr = packet->file_spec + packet->file_sp_length;
selection_ptr[packet->selection_length] = (char)NULL;
if (packet->selection_length)
{
is_selection = TRUE;
if (parse_selection(xfer_context,selection_ptr) == FAIL)
return(xfer_rms_error);
}
if (OpenDir(init_file_spec, NULL) == FAIL)
{
xfer_ready_error_packet(xfer_context,ERR_MSG,
X_FILESYS_ERROR,NULL,errno);
return(xfer_rms_error);
}
first_file = TRUE;
return (check_cont(xfer_context) );
}
enum xfer_return_type xfer_start (xfer_context)
struct xfer_context_block *xfer_context;
{
struct answer_send_packet *packet;
unsigned char *b;
packet = &asp;
b = (unsigned char *) xfer_context->write_buffer->unix_usr_data;
packet->packet_type = get_byte(&b);
packet->start_code = get_byte(&b);
packet->compression_type = get_byte(&b);
if (xfer_context->xfer_state != X_SEND_DELV)
return(xfer_improper_state);
switch (packet->start_code)
{
case X_PPL_OK:
#ifndef NO_BACKUP
if (xfer_context->xfer_type & TT_RESTORE_MASK)
{
enum xfer_return_type st;
if ((st = xfer_restore_start(xfer_context)) == xfer_failure)
xfer_ready_error_packet(xfer_context,ERR_MSG,
X_FILESYS_ERROR, rst_invalid_message,0);
return(st);
}
#endif
if (xfer_context->xfer_type & (TT_ATTRIBUTE_MASK|TT_IMAGE_MASK))
xfer_context->xfer_state = X_SEND_ATT;
else
xfer_context->xfer_state = X_SEND;
xfer_context->compression_type = packet->compression_type;
return ( xfer_send(xfer_context) );
case X_ERR:
return(xfer_done(xfer_context));
case X_NOUPDATE:
default:
xfer_context->xfer_state = X_PENDING;
return(check_cont(xfer_context));
}
}
enum xfer_return_type xfer_done (xfer_context)
struct xfer_context_block *xfer_context;
{ 
xfer_context->xfer_state = X_INACTIVE;
return(xfer_success);
}
enum xfer_return_type xfer_abort (xfer_context)
struct xfer_context_block *xfer_context;
{
if (xfer_fd != -1)
{
close(xfer_fd);
xfer_fd = -1;
}
if (rms_buffer)
{
free(rms_buffer);
rms_buffer = NULL;
}
xfer_context->xfer_state = X_INACTIVE;
return(xfer_success);
}
enum xfer_return_type xfer_send (xfer_context)
struct xfer_context_block *xfer_context;
{
struct data_packet *data_pkt;
unsigned char *b;
unsigned char *dbuff; 
int length;
enum xfer_return_type result;
int rms_bytes;
data_pkt = &dp;
dbuff = data_pkt->data;
if ( (xfer_context->xfer_state & (X_SEND | X_SEND_ATT | X_RST)) == 0)
return(xfer_improper_state);
result = (*read_rms_data)(dbuff,&length,xfer_context,&rms_bytes);
if ( (result == xfer_success) || (result == xfer_eof) )
{
if (length != 0)
{ 
data_pkt->packet_type = DATA_MSG; 
data_pkt->count = rms_bytes;
b = (unsigned char *) xfer_context->read_buffer->unix_usr_data;
put_byte(&b, data_pkt->packet_type);
put_word(&b, data_pkt->count);
put_nbyte(&b, data_pkt->data, length);
xfer_context->read_buffer->unix_data_len =
b - xfer_context->read_buffer->unix_usr_data;
xfer_context->read_length =
xfer_context->read_buffer->unix_data_len + UX_REC_OVHD;
xfer_context->read_ready = TRUE;
if (result == xfer_eof)
{
if (xfer_context->xfer_state == X_RST)
xfer_context->xfer_state = X_EOF_RST;
else
xfer_context->xfer_state = X_EOF;
}
return(xfer_success);
}
else if (result == xfer_eof)
{
return(send_eof(xfer_context));
} 
}
else
{
if (xfer_context->sys_status == NO_RESTORE)
xfer_ready_error_packet(xfer_context,ERR_MSG,X_FILESYS_ERROR,
no_rst_message,0);
else
xfer_ready_error_packet(xfer_context,ERR_MSG,X_FILESYS_ERROR,
NULL,xfer_context->sys_status);
return(xfer_rms_error);
}
}
enum xfer_return_type xfer_ratt (xfer_context)
struct xfer_context_block *xfer_context;
{
int count = 0; 
struct data_packet *data_pkt;
unsigned char *b, *start_buffer;
unsigned char *input_buffer, *max_buffer; 
unsigned char c; 
int numbytes;
if (msg_cont)
{
input_buffer = 
(unsigned char *)xfer_context->write_buffer->unix_usr_data;
numbytes = xfer_context->write_buffer->unix_data_len;
} 
else 
{
data_pkt = &dp;
b = (unsigned char *) xfer_context->write_buffer->unix_usr_data;
data_pkt->packet_type = get_byte(&b);
data_pkt->count = get_word(&b);
numbytes = xfer_context->write_buffer->unix_data_len -
(b - xfer_context->write_buffer->unix_usr_data);
get_nbyte(&b, data_pkt->data, numbytes);
input_buffer = data_pkt->data;
}
start_buffer = input_buffer;
max_buffer = input_buffer + numbytes;
count = strlen(att_buffer);
while ( input_buffer < max_buffer )
{
if ((*decompress)(&input_buffer,&c_state,&c))
{
att_buffer[count++] = (char)c;
if (count == MAX_ATTRIBUTE_SIZE || c == END_OF_RECORD)
goto end_of_attributes;
}
} 
return xfer_success;
end_of_attributes:
att_buffer[--count] = '\0'; 
c_state.comp_state = 
(xfer_context->compression_type == COMP_NONE ? CS_NONE : CS_STABLE);
if (parse_attributes(xfer_context,att_buffer) == FAIL)
return xfer_rms_error;
xfer_context->sys_status = 0;
xfer_context->xfer_state = X_RECV;
if (input_buffer < max_buffer &&
(*write_rms_data)(xfer_context,input_buffer-start_buffer) !=
xfer_success)
{
xfer_ready_error_packet(xfer_context,ERR_MSG,X_FILESYS_ERROR,
NULL,xfer_context->sys_status);
return(xfer_rms_error);
}
return xfer_success;
}
enum xfer_return_type xfer_recv (xfer_context)
struct xfer_context_block *xfer_context;
{
if ((*write_rms_data)(xfer_context,0) == xfer_success)
{
return(xfer_success);
}
else
{
xfer_ready_error_packet(xfer_context,ERR_MSG,X_FILESYS_ERROR,
NULL,xfer_context->sys_status);
return(xfer_rms_error);
}
}
enum xfer_return_type send_eof (xfer_context)
struct xfer_context_block *xfer_context;
{
struct eof_packet *eof_ptr = 
(struct eof_packet *) xfer_context->read_buffer->unix_usr_data;
eof_ptr->packet_type = EOF_MSG;
xfer_context->read_buffer->unix_data_len = EOF_PACKET_SIZE;
xfer_context->read_length =
xfer_context->read_buffer->unix_data_len + UX_REC_OVHD;
if (xfer_context->xfer_type & TT_RESTORE_MASK)
xfer_context->xfer_state = X_EOT_RST;
else if (xfer_context->xfer_state == X_DIR_EOF)
xfer_context->xfer_state = X_DIR_CONTINUE;
else
xfer_context->xfer_state = X_PENDING;
xfer_context->read_ready = TRUE;
if (rms_buffer)
{
free(rms_buffer);
rms_buffer = NULL;
}
return(xfer_success);
}
enum xfer_return_type send_eot (xfer_context)
struct xfer_context_block *xfer_context;
{
struct eot_packet *eot_ptr = 
(struct eot_packet *) xfer_context->read_buffer->unix_usr_data;
eot_ptr->packet_type = EOT_MSG;
xfer_context->read_buffer->unix_data_len = EOT_PACKET_SIZE;
xfer_context->read_length =
xfer_context->read_buffer->unix_data_len + UX_REC_OVHD;
xfer_context->xfer_state = X_INACTIVE;
xfer_context->read_ready = TRUE;
return(xfer_success);
}
enum xfer_return_type xfer_sclose (xfer_context)
struct xfer_context_block *xfer_context;
{
int sys_status = 0;
struct cont_msg_packet *continue_pkt = 
(struct cont_msg_packet *) xfer_context->read_buffer->unix_usr_data;
if (xfer_context->xfer_state == X_RECV_A)
{
xfer_ready_error_packet(xfer_context,ERR_MSG,X_FILESYS_ERROR,
badattr_message,0);
if (rms_buffer)
{
free(rms_buffer);
rms_buffer = NULL;
}
close(xfer_fd);
xfer_fd = -1;
return xfer_rms_error;
}
if (xfer_context->xfer_state == X_EXIT)
{
if (rms_buffer)
{
free(rms_buffer);
rms_buffer = NULL;
}
close(xfer_fd);
xfer_fd = -1;
return xfer_rms_error;
}
xfer_context->xfer_state = X_EXIT;
xfer_context->read_ready = TRUE;
if (xfer_context->compression_type == COMP_HUFFMAN)
{
msg_cont = 1;
xfer_context->write_buffer->unix_usr_data[0] = 0xff;
xfer_context->write_buffer->unix_usr_data[1] = 0xff;
xfer_context->write_buffer->unix_data_len = 2;
(*write_rms_data)(xfer_context,0);
}
if (c_state.buffer_count != 0)
{
if (ppl_write(xfer_fd,rms_buffer,c_state.buffer_count) !=
c_state.buffer_count)
sys_status = errno;
}
if (rms_buffer)
{
free(rms_buffer);
rms_buffer = NULL;
}
close(xfer_fd);
xfer_fd = -1;
if (creation_date.day != 0)
{
struct utimbuf 
{
time_t actime;
time_t modtime;
} times;
times.actime = GetUnixDate(&creation_date);
times.modtime = GetUnixDate(&revision_date);
if (utime(file_specification, &times) == -1)
{
sys_status = errno;
}
}
if (sys_status == 0) 
{
continue_pkt->packet_type = CONT_MSG;
xfer_context->read_buffer->unix_data_len = CONT_MSG_PACKET_SIZE;
xfer_context->read_length =
xfer_context->read_buffer->unix_data_len + UX_REC_OVHD;
return(xfer_success);
}
else
{
xfer_ready_error_packet(xfer_context,ERR_MSG,
X_FILESYS_ERROR,NULL,sys_status);
return(xfer_rms_error);
}
}
enum xfer_return_type check_cont (xfer_context)
struct xfer_context_block *xfer_context;
{
int status;
if ((xfer_context->xfer_state & (X_PENDING | X_INACTIVE)) )
{
if (xfer_fd != -1)
{
close(xfer_fd);
xfer_fd = -1;
}
if ((status = open_next_file()) == 0)
{
initiate_send(xfer_context);
c_state.restore_in_progress = FALSE;
c_state.comp_state = 
(xfer_context->compression_type == COMP_NONE ? CS_NONE : CS_START);
InitCompression();
return(xfer_success);
}
else 
{
if (is_selection == TRUE)
FreeOptions();
if (status == ENOENT)
return(send_eot(xfer_context));
else 
{
xfer_context->sys_status = status;
if (status == -1)
xfer_ready_error_packet(xfer_context,ERR_MSG,ENOENT,
nofile_message,0);
else
xfer_ready_error_packet(xfer_context,ERR_MSG,
X_FILESYS_ERROR,NULL,status);
return(xfer_rms_error);
}
}
}
else
return(xfer_improper_state);
}
enum xfer_return_type check_err (xfer_context)
struct xfer_context_block *xfer_context;
{
if (xfer_context->xfer_state == X_PENDING)
return(send_eot(xfer_context));
return(xfer_success);
}
open_next_file ()
{
int status = 0;
if ((status = search_for_file()) == 0)
{
if ((xfer_fd = open(current_file,O_RDONLY)) < 0)
{
return errno;
}
if (fstat(xfer_fd, &statbuf) == -1)
{
close(xfer_fd);
xfer_fd = -1;
return errno;
}
rec_size = DEFAULT_RMS_RECORD_SIZE;
if ((rms_buffer = (BYTE *)malloc(DEFAULT_RMS_RECORD_SIZE)) == NULL)
{
close(xfer_fd);
xfer_fd = -1;
return errno;
}
c_state.buffer_ptr = rms_buffer;
end_rms_buffer = rms_buffer;
c_state.buffer_count = -1; 
file_size = statbuf.st_size;
GetPplDate(&creation_date, statbuf.st_mtime);
revision_date = creation_date;
}
return(status);
}
search_for_file ()
{
char *name, *fname;
extern int dirsort;
char myname[MAX_FILENAME+1], *mn;
while ((name = NextDir(FALSE, NULL)) != (char *) NULL)
{
fname = FullName(name);
for (mn=myname; *fname != NULL; fname++)
{
*mn++ = (*fname == '\\' ? *++fname : *fname);
if (*fname == NULL)
break;
}
*mn = NULL;
if (is_selection == FALSE || dirsort == YES)
{
strcpy(current_file, myname);
first_file = FALSE;
return 0;
}
if (CheckOptions(myname) == SUCCESS)
{
strcpy(current_file, myname);
first_file = FALSE;
return 0;
}
}
CloseDir();
return (first_file == TRUE ? -1 : ENOENT);
}
void initiate_send (xfer_context)
struct xfer_context_block *xfer_context;
{
struct send_file_packet *send;
unsigned char *b;
char dir[MAX_FILENAME+1], fn[MAX_FILENAME+1];
xfer_context->xfer_state = X_SEND_DELV;
send = &sfp;
send->packet_type = SEND_FILE;
send->transfer_type = xfer_context->xfer_type;
send->compression_type = xfer_context->compression_type;
send->ascii_flags = 0;
send->disposition_flags = 0;
send->file_size = file_size;
parsepath(current_file, dir, fn);
send->file_sp_length = strlen(fn);
memcpy(send->file_spec, fn, send->file_sp_length);
send->creation_date = creation_date;
send->revision_date = revision_date;
if ( xfer_context->xfer_type & (TT_ATTRIBUTE_MASK | TT_IMAGE_MASK) )
{
if (xfer_context->xfer_type & TT_ONLY_MASK)
send->file_size = 0;
send->file_size += fill_attribute_buffer(xfer_context);
}
b = (unsigned char *) xfer_context->read_buffer->unix_usr_data;
put_byte(&b, send->packet_type);
put_word(&b, send->transfer_type);
put_byte(&b, send->ascii_flags);
put_byte(&b, send->compression_type);
put_byte(&b, send->disposition_flags);
put_nbyte(&b, &send->creation_date, DATE_TIME_SIZE);
put_nbyte(&b, &send->revision_date, DATE_TIME_SIZE);
put_long(&b, send->file_size);
put_word(&b, send->file_sp_length);
put_nbyte(&b, send->file_spec, send->file_sp_length);
xfer_context->read_buffer->unix_data_len = 
b - xfer_context->read_buffer->unix_usr_data;
xfer_context->read_length =
xfer_context->read_buffer->unix_data_len + UX_REC_OVHD;
xfer_context->read_ready = TRUE;
}
#include <grp.h>
#include <pwd.h>
int return_owner_attributes(att)
char *att;
{
struct passwd *pwd;
if ((pwd = (struct passwd *)getpwuid(statbuf.st_uid)) == 
(struct passwd *)NULL)
sprintf(att+strlen(att), "-o %d ", statbuf.st_uid);
else
sprintf(att+strlen(att), "-o %s ", pwd->pw_name);
return(0);
}
int return_group_attributes(att)
char *att;
{
struct group *grp;
if ((grp = (struct group *)getgrgid(statbuf.st_gid)) == 
(struct group *)NULL)
sprintf(att+strlen(att), "-g %d ", statbuf.st_gid);
else
sprintf(att+strlen(att), "-g %s ", grp->gr_name);
return 0;
}
int return_protection_attributes(att)
char *att;
{ 
sprintf(att+strlen(att),"-m %o ", statbuf.st_mode);
return(0);
}
int fill_attribute_buffer (xfer_context)
struct xfer_context_block *xfer_context;
{
int temp, i;
for (i=0; i<RETURNED_ATTRIBUTES; i++)
temp = (*returned_attribute_routine[i])(xfer_context->attr_buffer);
temp = strlen(xfer_context->attr_buffer);
temp--;
if (xfer_context->xfer_type & TT_ASCII_MASK)
xfer_context->attr_buffer[temp++] = '\n';
else
xfer_context->attr_buffer[temp++] = 255;
xfer_context->attr_buffer[temp] = '\0';
xfer_context->attr_pointer = xfer_context->attr_buffer;
return(temp);
}
open_output ()
{
extern int open_mode;
rms_bsize = DEFAULT_RMS_RECORD_SIZE;
if ((rms_buffer = (BYTE *)malloc(rms_bsize)) == NULL)
return errno;
c_state.buffer_ptr = rms_buffer;
c_state.buffer_count = 0;
if ((xfer_fd = 
open(file_specification,O_WRONLY+O_CREAT+O_EXCL, open_mode)) < 0)
return errno;
if (fstat(xfer_fd, &statbuf) == -1)
{
close(xfer_fd);
xfer_fd = -1;
return errno;
}
return(0);
}
enum xfer_return_type open_existing_file(xfer_context)
struct xfer_context_block *xfer_context;
{
int mode = O_WRONLY;
if (xfer_context->disposition & DF_OVERWRITE_MASK)
mode |= O_TRUNC;
if (xfer_context->disposition & DF_APPEND_MASK)
mode |= O_APPEND;
if ((xfer_fd = open(file_specification,mode)) < 0)
return(errno == ENOENT ? xfer_nofile : 
filesys_error(xfer_context,errno));
if (fstat(xfer_fd, &statbuf) == -1)
{
close(xfer_fd);
xfer_fd = -1;
return(errno == ENOENT ? xfer_nofile : 
filesys_error(xfer_context,errno));
}
rms_bsize = DEFAULT_RMS_RECORD_SIZE;
if ((rms_buffer = (BYTE *)malloc(rms_bsize)) == (BYTE *) NULL)
return (filesys_error(xfer_context, errno));
xfer_context->xfer_state = X_DEL_ANS_SEND;
c_state.buffer_ptr = rms_buffer;
c_state.buffer_count = 0;
return (xfer_success);
}
enum xfer_return_type filesys_error(xfer_context, status)
struct xfer_context_block *xfer_context;
int status;
{
struct answer_send_packet *answer;
unsigned char *b;
answer = &asp;
answer->start_code = X_FILESYS_ERROR;
answer->string_length = get_msg_text(status, answer->error_string)+4;
answer->host_error = status;
b = (unsigned char *) xfer_context->read_buffer->unix_usr_data;
put_byte(&b, answer->packet_type);
put_byte(&b, answer->start_code);
put_byte(&b, answer->compression_type);
put_word(&b, answer->string_length);
put_long(&b, answer->host_error);
put_nbyte(&b, answer->error_string, answer->string_length-4);
xfer_context->read_buffer->unix_data_len =
b - xfer_context->read_buffer->unix_usr_data;
xfer_context->read_length =
xfer_context->read_buffer->unix_data_len + UX_REC_OVHD;
return(xfer_rms_error);
}
fill_rms_buffer (state, xfer_context, count)
struct cstate *state;
struct xfer_context_block *xfer_context;
int *count;
{
int status;
#ifndef NO_BACKUP
if (state->restore_in_progress)
{
status = fill_restore_buffer(state,rms_buffer);
*count += state->buffer_count;
return(status);
}
#endif
if (xfer_context->xfer_state == X_SEND_ATT)
{
if (strlen(xfer_context->attr_pointer)==0)
{
if (xfer_context->xfer_type & TT_ONLY_MASK)
return(EOF);
xfer_context->xfer_state = X_SEND;
}
else
{
state->buffer_count =
min(rec_size,strlen(xfer_context->attr_pointer));
memcpy(rms_buffer,xfer_context->attr_pointer,
state->buffer_count);
xfer_context->attr_pointer += state->buffer_count;
*count += state->buffer_count;
state->buffer_ptr = rms_buffer;
return(0);
}
}
if ((state->buffer_count = 
ppl_read(xfer_fd, rms_buffer, DEFAULT_RMS_RECORD_SIZE)) < 0)
return errno;
else if (state->buffer_count == 0)
return EOF;
*count += state->buffer_count;
state->buffer_ptr = rms_buffer;
return(0);
}
enum xfer_return_type rd_ascii_data(rec_ptr,length,xfer_context,byte_count)
unsigned char *rec_ptr;
int *length;
struct xfer_context_block *xfer_context;
int *byte_count;
#define BUFFER_EMPTY c_state.buffer_ptr >= end_rms_buffer
{
unsigned char old, new; 
int status;
BOOL escaped;
*length = 0;
*byte_count = 0;
old = c_state.old;
new = c_state.new;
c_state.eof_pending = FALSE;
while(TRUE)
{
switch (c_state.comp_state)
{
case CS_NONE:
case CS_START:
if (BUFFER_EMPTY)
{
if ((status = fill_rms_buffer(&c_state,
xfer_context,byte_count)) == EOF)
return(xfer_eof);
else if (status != 0)
{
xfer_context->sys_status = status;
return(xfer_rms_error);
}
end_rms_buffer = 
rms_buffer+c_state.buffer_count;
}
old = *(c_state.buffer_ptr++);
if (old & 0x80)
{
new = old & 0x7f;
old = SPACE_COMPRESS_ESCAPE;
c_state.comp_state = CS_ASCII_8;
break;
}
c_state.comp_state = CS_STABLE;
break;
case CS_STABLE:
if (c_state.eof_pending)
return(xfer_eof);
if (BUFFER_EMPTY)
{
status = fill_rms_buffer(&c_state,
xfer_context,byte_count);
end_rms_buffer = 
rms_buffer+c_state.buffer_count;
if (status == EOF)
{
if (old == '\n' && new != SPACE_COMPRESS_ESCAPE)
old = END_OF_RECORD;
*rec_ptr++ = old;
(*length)++;
return(xfer_eof);
}
else if (status != 0)
{
xfer_context->sys_status = status;
return(xfer_rms_error);
}
}
escaped = (new == SPACE_COMPRESS_ESCAPE ? YES : NO);
new = *(c_state.buffer_ptr++);
if ( (new == old) && (new == ASCII_SPACE) )
{
c_state.comp_state = CS_DUPLICATE;
c_state.count = 1;
break;
}
if (old & 0x80)
{
new = old & 0x7f;
old = SPACE_COMPRESS_ESCAPE;
c_state.comp_state = CS_ASCII_8;
c_state.buffer_ptr--;
break;
}
if (old == '\n' && escaped == NO)
old = END_OF_RECORD;
*rec_ptr++ = old;
(*length)++;
swap(old,new);
break;
case CS_ASCII_8:
*rec_ptr++ = old;
(*length)++;
swap(old,new);
c_state.comp_state = CS_STABLE;
break;
case CS_ESCAPE:
*rec_ptr++ = c_state.count | 0x80;
c_state.comp_state = CS_STABLE;
(*length)++;
break;
case CS_DUPLICATE:
if (BUFFER_EMPTY)
{
status = fill_rms_buffer(&c_state,
xfer_context,byte_count);
end_rms_buffer = 
rms_buffer+c_state.buffer_count;
if (status == EOF)
{
new = !old;
c_state.eof_pending = TRUE;
goto cs_dup_label;
}
else if (status != 0)
{
xfer_context->sys_status = status;
return(xfer_rms_error);
}
}
new = *(c_state.buffer_ptr++);
cs_dup_label:
c_state.count++;
if (old != new)
{
swap(old,new);
c_state.comp_state = CS_ESCAPE;
break;
}
else
if (c_state.count == 125)
c_state.comp_state = CS_ESCAPE;
break;
case CS_WRTDUP:
while (--c_state.count > 0)
{
*rec_ptr++ = new;
(*length)++;
if (*length >= MAX_DATA_LENGTH)
break;
}
if (c_state.count == 0)
c_state.comp_state = CS_STABLE;
break;
case CS_COUNT:
*rec_ptr++ = (unsigned char)c_state.count + 32;
(*length)++;
c_state.comp_state = CS_WRTREP;
break;
case CS_WRTREP:
c_state.comp_state = CS_STABLE;
*rec_ptr++ = c_state.repeat;
(*length)++;
break;
} 
if (*length >= MAX_DATA_LENGTH)
{
c_state.old = old;
c_state.new = new;
return(xfer_success);
}
} 
}
enum xfer_return_type rd_binary_data(rec_ptr,length,xfer_context,byte_count)
unsigned char *rec_ptr;
int *length;
struct xfer_context_block *xfer_context;
int *byte_count;
#define BUFFER_EMPTY c_state.buffer_ptr >= end_rms_buffer
{
unsigned char old, new; 
int status; 
*length = 0;
*byte_count = 0;
old = c_state.old;
new = c_state.new;
c_state.eof_pending = FALSE;
while(TRUE)
{
switch (c_state.comp_state)
{
case CS_START:
if (BUFFER_EMPTY)
{
status = fill_rms_buffer(&c_state,
xfer_context,byte_count);
end_rms_buffer = 
rms_buffer+c_state.buffer_count;
if (status == EOF)
return(xfer_eof);
else if (status != 0)
{
xfer_context->sys_status = status;
return(xfer_rms_error);
}
}
old = *(c_state.buffer_ptr++);
c_state.comp_state = CS_STABLE;
break;
case CS_STABLE:
if (c_state.eof_pending)
return(xfer_eof);
if (BUFFER_EMPTY)
{
status = fill_rms_buffer(&c_state,
xfer_context,byte_count);
end_rms_buffer = 
rms_buffer+c_state.buffer_count;
if (status == EOF)
{
*rec_ptr++ = old;
(*length)++;
return(xfer_eof);
}
else if (status != 0)
{
xfer_context->sys_status = status;
return(xfer_rms_error);
}
}
new = *(c_state.buffer_ptr++);
if (new == old)
{
c_state.comp_state = CS_DUPLICATE;
c_state.count = 1;
break;
}
if ( old == COMPRESS )
{
c_state.count = 1;
c_state.repeat = old;
c_state.comp_state = CS_COUNT;
}
*rec_ptr++ = old;
(*length)++;
swap(old,new);
break;
case CS_ESCAPE:
cs_escape_label: 
c_state.repeat = new;
new = COMPRESS;
c_state.comp_state = CS_COUNT;
*rec_ptr++ = new;
(*length)++;
break;
case CS_DUPLICATE:
while (TRUE)
{
if (BUFFER_EMPTY)
{
status = fill_rms_buffer(&c_state,
xfer_context,byte_count);
end_rms_buffer = 
rms_buffer+c_state.buffer_count;
if (status == EOF)
{
new = !old;
c_state.eof_pending = TRUE;
goto cs_dup_label;
}
else if (status != 0)
{
xfer_context->sys_status = status;
return(xfer_rms_error);
}
}
new = *(c_state.buffer_ptr++);
cs_dup_label:
c_state.count++;
if (old != new)
{
swap(old,new);
if ( (c_state.count >= MIN_DUPS) ||
(new == COMPRESS) )
{
c_state.comp_state = CS_ESCAPE;
goto cs_escape_label;
}
else
{
c_state.count++;
c_state.comp_state = CS_WRTDUP;
goto cs_writedup_label;
}
}
else
if (c_state.count == 256)
{
c_state.comp_state = CS_ESCAPE;
goto cs_escape_label;
}
}
case CS_WRTDUP:
cs_writedup_label:
while (--c_state.count > 0)
{
*rec_ptr++ = new;
(*length)++;
if (*length >= MAX_DATA_LENGTH)
break;
}
if (c_state.count == 0)
c_state.comp_state = CS_STABLE;
break;
case CS_COUNT:
*rec_ptr++ = (unsigned char)c_state.count + 32;
(*length)++;
c_state.comp_state = CS_WRTREP;
break;
case CS_WRTREP:
c_state.comp_state = CS_STABLE;
*rec_ptr++ = c_state.repeat;
(*length)++;
break;
case CS_NONE:
if (BUFFER_EMPTY)
{
status = fill_rms_buffer(&c_state,
xfer_context,byte_count);
end_rms_buffer = 
rms_buffer+c_state.buffer_count;
if (status == EOF)
return(xfer_eof);
else if (status != 0)
{
xfer_context->sys_status = status;
return(xfer_rms_error);
}
}
*rec_ptr++ = *(c_state.buffer_ptr++);
(*length)++;
break;
} 
if (*length >= MAX_DATA_LENGTH)
{
c_state.old = old;
c_state.new = new;
return(xfer_success);
}
} 
}
enum xfer_return_type wr_binary_data (xfer_context, offset)
struct xfer_context_block *xfer_context;
int offset;
{
struct data_packet *data_pkt;
unsigned char *b;
unsigned char *input_buffer; 
unsigned char *max_buffer; 
unsigned char *output_buffer = c_state.buffer_ptr;
int byte_count; 
unsigned char c; 
if (msg_cont)
{
input_buffer = 
(unsigned char *)xfer_context->write_buffer->unix_usr_data;
byte_count = xfer_context->write_buffer->unix_data_len;
} 
else 
{
data_pkt = &dp;
b = (unsigned char *) xfer_context->write_buffer->unix_usr_data;
data_pkt->packet_type = get_byte(&b);
data_pkt->count = get_word(&b);
byte_count = xfer_context->write_buffer->unix_data_len -
(b - xfer_context->write_buffer->unix_usr_data);
get_nbyte(&b, data_pkt->data, byte_count);
input_buffer = data_pkt->data;
}
max_buffer = input_buffer + byte_count;
input_buffer += offset;
while ( input_buffer < max_buffer )
{
switch(c_state.comp_state)
{
case CS_NONE:
c = *input_buffer;
input_buffer++;
break;
case CS_STABLE:
c = *input_buffer;
input_buffer++;
if (c == COMPRESS)
{
c_state.comp_state = CS_COUNT;
goto next_loop;
}
break;
case CS_COUNT:
c_state.bcount = *input_buffer - 32;
input_buffer++;
c_state.comp_state = CS_WRTDUP;
goto next_loop;
case CS_WRTDUP:
c = *input_buffer;
writedup_again:
if (--c_state.bcount == 0)
{
input_buffer++;
c_state.comp_state = CS_STABLE;
}
break;
} 
*output_buffer = c;
c_state.buffer_count++;
if (c_state.buffer_count == rms_bsize)
{
if (ppl_write(xfer_fd, rms_buffer,c_state.buffer_count) !=
c_state.buffer_count)
{
xfer_context->sys_status = errno;
return(xfer_rms_error);
}
output_buffer = rms_buffer;
c_state.buffer_count = 0;
}
else
output_buffer++;
if (c_state.comp_state == CS_WRTDUP) 
goto writedup_again;
next_loop:
;
} 
c_state.buffer_ptr = output_buffer;
return(xfer_success);
}
enum xfer_return_type wr_ascii_data (xfer_context, offset)
struct xfer_context_block *xfer_context;
int offset;
{
unsigned char *b;
unsigned char *input_buffer; 
unsigned char *max_buffer; 
unsigned char *output_buffer = c_state.buffer_ptr;
int byte_count; 
unsigned char c; 
BOOL ff_is_eor;
if (msg_cont)
{
input_buffer = 
(unsigned char *)xfer_context->write_buffer->unix_usr_data;
byte_count = xfer_context->write_buffer->unix_data_len;
} 
else
{
b = (unsigned char *) xfer_context->write_buffer->unix_usr_data;
dp.packet_type = get_byte(&b);
dp.count = get_word(&b);
byte_count = xfer_context->write_buffer->unix_data_len -
(b - xfer_context->write_buffer->unix_usr_data);
get_nbyte(&b, dp.data, byte_count);
input_buffer = dp.data;
}
max_buffer = input_buffer + byte_count;
input_buffer += offset;
while ( input_buffer < max_buffer )
{
ff_is_eor = TRUE;
switch(c_state.comp_state)
{
case CS_NONE:
case CS_STABLE:
c = *input_buffer;
if (c & 0x80)
{
if (c == SPACE_COMPRESS_ESCAPE)
{
c_state.comp_state = CS_ASCII_8;
input_buffer++;
goto loop_again;
}
else if (c != END_OF_RECORD)
{
c_state.count = c & 0x7f;
c_state.comp_state = CS_CHAR;
c = ASCII_SPACE;
goto cs_char_state;
}
}
input_buffer++;
break;
case CS_ASCII_8:
c = *input_buffer + 0x80;
input_buffer++;
c_state.comp_state = CS_STABLE;
ff_is_eor = FALSE;
break;
case CS_CHAR:
c = ASCII_SPACE;
cs_char_state:
if ( --c_state.count == 0)
{
input_buffer++;
c_state.comp_state = CS_STABLE;
}
break;
} 
*output_buffer = c;
c_state.buffer_count++;
if (*output_buffer == END_OF_RECORD && ff_is_eor == TRUE)
*output_buffer = 10; 
if (c_state.buffer_count == rms_bsize)
{
if (ppl_write(xfer_fd, rms_buffer, c_state.buffer_count)!=
c_state.buffer_count)
{
xfer_context->sys_status = errno;
return(xfer_rms_error);
}
output_buffer = rms_buffer;
c_state.buffer_count = 0;
}
else
output_buffer++;
if (c_state.comp_state == CS_CHAR) 
goto cs_char_state;
loop_again:
;
} 
c_state.buffer_ptr = output_buffer;
return(xfer_success);
}
enum xfer_return_type wr_h_binary_data (xfer_context, offset)
struct xfer_context_block *xfer_context;
int offset;
{
struct data_packet *data_pkt;
unsigned char *b;
unsigned char *input_buffer; 
unsigned char *max_buffer; 
unsigned char *output_buffer = c_state.buffer_ptr;
int byte_count; 
int c; 
if (msg_cont)
{
input_buffer = (unsigned char *)xfer_context->write_buffer->unix_usr_data;
byte_count = xfer_context->write_buffer->unix_data_len;
} 
else 
{
data_pkt = &dp;
b = (unsigned char *) xfer_context->write_buffer->unix_usr_data;
data_pkt->packet_type = get_byte(&b);
data_pkt->count = get_word(&b);
byte_count = xfer_context->write_buffer->unix_data_len -
(b - xfer_context->write_buffer->unix_usr_data);
get_nbyte(&b, data_pkt->data, byte_count);
input_buffer = data_pkt->data;
}
max_buffer = input_buffer + byte_count;
input_buffer += offset;
while ( input_buffer < max_buffer )
{
int token, i, j;
unsigned char new_count;
unsigned short temp;
if (compress.state == COUNT_STATE)
{
c = compress.save_char;
if (!--compress.count)
compress.state = INIT_STATE;
goto write_it;
}
getbyte:
if (!compress.bitsleft)
{
compress.bitsleft = BITSPERBYTE;
compress.byte = (compress.byte & 0xff00) | (*input_buffer & 0x00ff);
input_buffer++;
}
if (compress.state == INIT_STATE)
{
compress.numbits = 3;
compress.byte &= 0x00ff;
compress.state = LEN_STATE;
}
again:
if (!compress.bitsleft)
{
if (input_buffer < max_buffer)
goto getbyte;
else
break;
}
if (compress.bitsleft < compress.numbits)
{
compress.byte <<= compress.bitsleft;
compress.numbits -= compress.bitsleft;
compress.bitsleft = 0;
}
else
{
compress.byte <<= compress.numbits;
compress.bitsleft -= compress.numbits;
compress.numbits = 0;
}
if (compress.numbits)
{
if (input_buffer < max_buffer)
goto getbyte;
else
break;
}
switch(compress.state)
{
case TOKEN_STATE:
token = MSB(compress.byte);
if (compress.len == 7 && token == 0x7f)
{
compress.state = CHECK_END_STATE;
compress.numbits = 1;
compress.byte &= 0x00ff;
goto again;
}
break;
case LEN_STATE:
compress.state = TOKEN_STATE;
compress.numbits = (!(compress.len = MSB(compress.byte))
? 1 : compress.len);
compress.byte &= 0x00ff;
goto again;
case CHECK_END_STATE:
if (compress.byte & 0x100)
goto end;
token = 0x7f;
compress.len = 7;
break;
}
i = (token+token_base[compress.len]) & 0xff;
compress.state = INIT_STATE;
#ifdef NEWCODE
token_indexes[TOKEN_COUNT(i)]++;
#endif
token_cnt_ptrs[i]++;
if (!i)
{
if (TOKEN_COUNT(0) == 0xff)
halve_counts();
c = TOKEN_PTR(0);
}
else if (TOKEN_COUNT(i) <= TOKEN_COUNT(i-1))
{
c = TOKEN_PTR(i);
}
else
{
new_count = TOKEN_COUNT(i);
c = TOKEN_PTR(i);
#ifdef NEWCODE
j = token_indexes[new_count-1] - 1;
#else
for (j=i-1; j>0 && new_count > TOKEN_COUNT(j-1); j--)
;
#endif
temp = token_cnt_ptrs[j];
token_cnt_ptrs[j] = token_cnt_ptrs[i];
token_cnt_ptrs[i] = temp;
if (new_count == 0xff)
halve_counts();
}
if (compress.rle_state != RLE_THREE_STATE)
{
urle_byte(c);
goto write_it;
}
urle_byte(c);
if (c)
{
compress.state = COUNT_STATE;
compress.count = c;
}
continue;
write_it:
*output_buffer = c;
c_state.buffer_count++;
if (c_state.buffer_count == rms_bsize)
{
if (ppl_write(xfer_fd, rms_buffer,c_state.buffer_count) !=
c_state.buffer_count)
{
xfer_context->sys_status = errno;
return(xfer_rms_error);
}
output_buffer = rms_buffer;
c_state.buffer_count = 0;
}
else
output_buffer++;
} 
end:
c_state.buffer_ptr = output_buffer;
return(xfer_success);
}
enum xfer_return_type wr_h_ascii_data (xfer_context, offset)
struct xfer_context_block *xfer_context;
int offset;
{
struct data_packet *data_pkt;
unsigned char *b;
unsigned char *input_buffer; 
unsigned char *max_buffer; 
unsigned char *output_buffer = c_state.buffer_ptr;
int byte_count; 
int c; 
BOOL ff_is_eor;
if (msg_cont)
{
input_buffer = (unsigned char *)xfer_context->write_buffer->unix_usr_data;
byte_count = xfer_context->write_buffer->unix_data_len;
} 
else
{
data_pkt = &dp;
b = (unsigned char *) xfer_context->write_buffer->unix_usr_data;
data_pkt->packet_type = get_byte(&b);
data_pkt->count = get_word(&b);
byte_count = xfer_context->write_buffer->unix_data_len -
(b - xfer_context->write_buffer->unix_usr_data);
get_nbyte(&b, data_pkt->data, byte_count);
input_buffer = data_pkt->data;
}
max_buffer = input_buffer + byte_count;
input_buffer += offset;
while ( input_buffer < max_buffer )
{
int token, i, j;
unsigned char new_count;
unsigned short temp;
if (compress.state >= COUNT_STATE)
{
if (compress.state == COUNT_STATE)
{
c = compress.save_char;
if (!--compress.count)
compress.state = INIT_STATE;
compress.new_state = compress.state;
if ((c=unspace_byte(c, &ff_is_eor))>= 0)
goto write_it;
continue;
}
else if (compress.state == SPACE_STATE)
{
if (!--compress.space)
{
compress.state = compress.new_state;
compress.new_state = INIT_STATE;
}
c = ASCII_SPACE;
goto write_it;
}
}
getbyte: 
if (!compress.bitsleft)
{
compress.bitsleft = BITSPERBYTE;
compress.byte = (compress.byte & 0xff00) | (*input_buffer & 0x00ff);
input_buffer++;
}
if (compress.state == INIT_STATE)
{
compress.numbits = 3;
compress.byte &= 0x00ff;
compress.state = LEN_STATE;
}
again:
if (!compress.bitsleft)
{
if (input_buffer < max_buffer)
goto getbyte;
else
break;
}
if (compress.bitsleft < compress.numbits)
{
compress.byte <<= compress.bitsleft;
compress.numbits -= compress.bitsleft;
compress.bitsleft = 0;
}
else
{
compress.byte <<= compress.numbits;
compress.bitsleft -= compress.numbits;
compress.numbits = 0;
}
if (compress.numbits)
{
if (input_buffer < max_buffer)
goto getbyte;
else
break;
}
switch(compress.state)
{
case TOKEN_STATE:
token = MSB(compress.byte);
if (compress.len == 7 && token == 0x7f)
{
compress.state = CHECK_END_STATE;
compress.numbits = 1;
compress.byte &= 0x00ff;
goto again;
}
break;
case LEN_STATE:
compress.state = TOKEN_STATE;
compress.numbits = (!(compress.len = MSB(compress.byte))
? 1 : compress.len);
compress.byte &= 0x00ff;
goto again;
case CHECK_END_STATE:
if (compress.byte & 0x100)
goto end;
token = 0x7f;
compress.len = 7;
break;
}
i = (token+token_base[compress.len]) & 0xff;
compress.state = INIT_STATE;
#ifdef NEWCODE
token_indexes[TOKEN_COUNT(i)]++;
#endif
token_cnt_ptrs[i]++;
if (!i)
{
if (TOKEN_COUNT(0) == 0xff)
halve_counts();
c = TOKEN_PTR(0);
}
else if (TOKEN_COUNT(i) <= TOKEN_COUNT(i-1))
{
c = TOKEN_PTR(i);
}
else
{
new_count = TOKEN_COUNT(i);
c = TOKEN_PTR(i);
#ifdef NEWCODE
j = token_indexes[new_count-1] - 1;
#else
for (j=i-1; j>0 && new_count > TOKEN_COUNT(j-1); j--)
;
#endif
temp = token_cnt_ptrs[j];
token_cnt_ptrs[j] = token_cnt_ptrs[i];
token_cnt_ptrs[i] = temp;
if (new_count == 0xff)
halve_counts();
}
if (compress.rle_state != RLE_THREE_STATE)
{
urle_byte(c);
if ((c = unspace_byte(c, &ff_is_eor)) >= 0)
goto write_it;
continue;
}
urle_byte(c);
if (c)
{
compress.state = COUNT_STATE;
compress.count = c;
}
continue;
write_it:
*output_buffer = c;
c_state.buffer_count++;
if (*output_buffer == END_OF_RECORD && ff_is_eor)
*output_buffer = 10; 
if (c_state.buffer_count == rms_bsize)
{
if (ppl_write(xfer_fd, rms_buffer, c_state.buffer_count)!= 
c_state.buffer_count)
{
xfer_context->sys_status = errno;
return(xfer_rms_error);
}
output_buffer = rms_buffer;
c_state.buffer_count = 0;
}
else
output_buffer++;
} 
end:
c_state.buffer_ptr = output_buffer;
return(xfer_success);
}
BOOL decomp_ascii (buffer, state, c)
unsigned char **buffer;
struct cstate *state;
unsigned char *c;
{
switch(state->comp_state)
{
case CS_NONE:
case CS_STABLE:
*c = **buffer;
if (*c == END_OF_RECORD)
;
else if (*c == SPACE_COMPRESS_ESCAPE)
{
state->comp_state = CS_ASCII_8;
(*buffer)++;
return (FALSE);
}
else if (*c & 0x80)
{
state->count = *c & 0x7f;
state->comp_state = CS_CHAR;
return (FALSE);
}
(*buffer)++;
return(TRUE);
case CS_ASCII_8:
*c = (**buffer) + 0x80;
(*buffer)++;
state->comp_state = CS_STABLE;
return(TRUE);
case CS_COUNT:
state->comp_state = CS_CHAR;
state->count = **buffer - 32; 
case CS_CHAR:
*c = ASCII_SPACE;
if ( --state->count == 0)
{
(*buffer)++;
state->comp_state = CS_STABLE;
}
return(TRUE);
} 
return FALSE;
}
BOOL decomp_binary (buffer, state, c)
unsigned char **buffer;
struct cstate *state;
unsigned char *c;
{
switch(state->comp_state)
{
case CS_NONE:
*c = **buffer;
(*buffer)++;
return(TRUE);
case CS_STABLE:
*c = **buffer;
{
if (**buffer != COMPRESS)
{
(*buffer)++;
return(TRUE);
}
else
{
(*buffer)++;
state->comp_state = CS_COUNT;
return(FALSE);
}
}
case CS_COUNT:
state->comp_state = CS_CHAR;
state->bcount = **buffer - 32; 
(*buffer)++;
return(FALSE);
case CS_CHAR:
state->comp_state = CS_WRTDUP;
case CS_WRTDUP:
*c = **buffer;
if (--state->bcount == 0)
{
(*buffer)++;
state->comp_state = CS_STABLE;
}
return(TRUE);
}
return FALSE;
}
int get_msg_text (msg_id, msg_buf)
int msg_id;
char *msg_buf;
{
extern char *sys_errlist[];
extern int sys_nerr, errno;
if (msg_id < sys_nerr)
strcpy(msg_buf, sys_errlist[msg_id]);
else
sprintf(msg_buf, "Error %d", msg_id);
return (strlen(msg_buf));
}
parse_attributes (xfer_context, attributes)
struct xfer_context_block *xfer_context;
char *attributes;
{
if (SetAttrs(file_specification, attributes) == FAIL)
{
xfer_ready_error_packet(xfer_context,ERR_MSG,X_FILESYS_ERROR,
badattr_message,0);
return FAIL;
}
return SUCCESS;
}
parse_selection (xfer_context, selection)
struct xfer_context_block *xfer_context;
char *selection;
{
if (SetOptions(selection) == FAIL)
{
xfer_ready_error_packet(xfer_context,ERR_MSG,X_FILESYS_ERROR,
badselection_message,0);
return (FAIL);
}
return (SUCCESS);
}
BOOL host_file_newer (rev_date, new_file)
struct date_time *rev_date;
BOOL *new_file;
{
if (stat(file_specification, &statbuf) == -1)
{
*new_file = TRUE;
return(FALSE);
}
*new_file = FALSE;
return (GetUnixDate(rev_date) <= statbuf.st_mtime ? TRUE : FALSE);
}
lowcase(s)
char *s;
{
char *p;
for (p = s; *p; p++)
if (isupper(*p))
*p = tolower(*p);
}
#ifndef NO_BACKUP
enum xfer_return_type xfer_restore_start (xfer_context)
struct xfer_context_block *xfer_context;
{
unsigned char s_len, x_len;
file_open(SPECIAL_RST_FILE);
temp_fd = u_fd;
if (file_read(&s_len,1) != 1)
return(xfer_failure);
s_len -= 32;
x_len = file_read(rst_file_name,s_len);
if (x_len != s_len)
return(xfer_failure);
rst_file_name[x_len] = (char)NULL;
if (file_read(&s_len,1) != 1)
return(xfer_failure);
s_len -= 32;
if (file_read(rst_path,s_len) != s_len)
return(xfer_failure);
rst_path[s_len] = (char)NULL;
if (file_read(&s_len,1) != 1)
return(xfer_failure);
subs_ok = (s_len == 'S' ? TRUE : FALSE);
if (!Binit(rst_file_name,NO,0,0))
return(xfer_failure);
rms_buffer = (unsigned char *)malloc(RST_BUFFER_SIZE);
c_state.buffer_ptr = rms_buffer;
c_state.buffer_count = -1;
c_state.comp_state = 
(xfer_context->compression_type == COMP_NONE ? CS_NONE : CS_START);
InitCompression();
c_state.ascii_transfer = FALSE;
c_state.restore_in_progress = TRUE;
xfer_context->xfer_state = X_RST;
rst_state = RST_F_FILE;
read_rms_data = rd_data_routine
[xfer_context->compression_type == COMP_HUFFMAN ? 1 : 0]
[FALSE];
return(xfer_send(xfer_context));
}
enum xfer_return_type xfer_bkup_restore_close (xfer_context)
struct xfer_context_block *xfer_context;
{
struct cont_msg_packet *continue_pkt = 
(struct cont_msg_packet *) xfer_context->read_buffer->unix_usr_data;
BYTE *error_msg;
int result;
if (xfer_context->xfer_state == X_BKUP)
{
if (xfer_context->compression_type == COMP_HUFFMAN)
{
unsigned char hbuf[2];
hbuf[0] = 0xff;
hbuf[1] = 0xff;
xfer_backup (hbuf, hbuf+2);
}
result = Bterm();
error_msg = bkup_fail_message;
}
else
{
if (xfer_context->compression_type == COMP_HUFFMAN)
{
xfer_context->write_buffer->unix_usr_data[0] = 0xff;
xfer_context->write_buffer->unix_usr_data[1] = 0xff;
xfer_context->write_buffer->unix_data_len = 2;
xfer_rrestore (xfer_context, 1);
}
error_msg = rst_close_message;
file_close();
result = 0;
}
xfer_context->xfer_state = X_EXIT;
xfer_context->read_ready = TRUE;
if (result == -1)
{
xfer_ready_error_packet(xfer_context,ERR_MSG,X_FILESYS_ERROR,
error_msg,0L);
return(xfer_rms_error);
}
else
{
continue_pkt->packet_type = CONT_MSG;
xfer_context->read_buffer->unix_data_len = CONT_MSG_PACKET_SIZE;
xfer_context->read_length =
xfer_context->read_buffer->unix_data_len + UX_REC_OVHD;
return(xfer_success);
}
}
fill_restore_buffer (state, buffer)
struct cstate *state;
unsigned char *buffer;
{
int count = 0;
char *strchr();
while (count < RST_BUFFER_SIZE)
{
switch (rst_state)
{
case RST_F_FILE:
rst_more = Bopenf(rst_path,subs_ok);
if (!rst_more)
{
state->buffer_count = count;
state->buffer_ptr = rms_buffer;
return(NO_RESTORE);
}
rst_dir_size = fill_directory_restore();
rst_state = RST_FDIR;
rst_count = 0;
break;
case RST_FDIR:
buffer[count++] = rst_dir[rst_count++];
if (rst_count == rst_dir_size)
{
if (dir.fsize == 0)
rst_state = RST_NEXT_FILE;
else
rst_state = RST_FDATA;
rst_count = 0;
}
break;
case RST_FDATA:
buffer[count++] = Bread();
if (++rst_count == dir.fsize)
{
rst_count = 0;
rst_state = RST_NEXT_FILE;
}
break;
case RST_NEXT_FILE:
if (strchr(rst_path, '*') == NULL &&
strchr(rst_path, '?') == NULL)
goto end_backup;
rst_more = Bopenn();
if (!rst_more)
{
u_fd = temp_fd;
if (next_restore_path(rst_path))
{
u_fd = rest_fd;
rst_state = RST_F_FILE;
}
else
{
end_backup:
(void)Bterm();
file_close();
file_delete(SPECIAL_RST_FILE);
u_fd = rest_fd;
state->buffer_count = count;
state->buffer_ptr = rms_buffer;
rst_state = RST_EOF;
return(0);
}
}
else
{
rst_state = RST_FDIR;
rst_dir_size = fill_directory_restore();
rst_count = 0;
}
break;
case RST_EOF:
state->buffer_count = count;
state->buffer_ptr = rms_buffer;
return(EOF);
}
}
state->buffer_count = count;
state->buffer_ptr = rms_buffer;
return(0);
}
int fill_directory_restore (
)
{
int pos;
strcpy(rst_dir,dir.fname);
pos = strlen(dir.fname) + 1;
rst_dir[pos++] = (dir.fsize & 0xff000000) >> 24;
rst_dir[pos++] = (dir.fsize & 0x00ff0000) >> 16;
rst_dir[pos++] = (dir.fsize & 0x0000ff00) >> 8;
rst_dir[pos++] = (dir.fsize & 0x000000ff);
rst_dir[pos++] = (dir.ddate & 0xff00) >> 8;
rst_dir[pos++] = (dir.ddate & 0xff);
rst_dir[pos++] = (dir.dtime & 0xff00) >> 8;
rst_dir[pos++] = (dir.dtime & 0xff);
rst_dir[pos++] = dir.dattr;
return(pos);
}
BOOL next_restore_path (path)
char *path;
{
unsigned char s_len;
file_read(&s_len,1);
if ( file_read(&s_len,1) == 1)
{
if (file_read(path,s_len-32) == s_len-32)
{
path[s_len-32] = (char)NULL;
return(TRUE);
}
}
return(FALSE);
}
enum xfer_return_type xfer_rbackup (xfer_context)
struct xfer_context_block *xfer_context;
{
struct data_packet *packet;
unsigned char *b;
int byte_count, offset;
unsigned char *packet_ptr, *packet_max;
if (msg_cont)
{
packet_ptr = (unsigned char *)xfer_context->write_buffer->unix_usr_data;
byte_count = xfer_context->write_buffer->unix_data_len;
} 
else 
{
packet = &dp;
b = (unsigned char *) xfer_context->write_buffer->unix_usr_data;
packet->packet_type = get_byte(&b);
packet->count = get_word(&b);
byte_count = xfer_context->write_buffer->unix_data_len - 
(b - xfer_context->write_buffer->unix_usr_data);
get_nbyte(&b, packet->data, byte_count);
packet_ptr = packet->data;
}
packet_max = packet_ptr + byte_count;
if (xfer_context->xfer_state == X_BKUP_START)
{
if (init_backup(xfer_context,&offset) != xfer_success)
{
xfer_ready_error_packet(xfer_context,ERR_MSG,X_FILESYS_ERROR,
bkup_invalid_message,0);
return (xfer_failure);
}
xfer_context->xfer_state = X_BKUP;
packet_ptr += offset;
}
return(xfer_backup(packet_ptr,packet_max));
}
enum xfer_return_type init_backup (xfer_context, bytes_read)
struct xfer_context_block *xfer_context;
int *bytes_read;
{
#define GETDC while (!(*decompress)(&packet_ptr,&c_state,&c))
struct data_packet *packet;
unsigned char *b;
unsigned char *packet_ptr;
int numbytes;
unsigned char c;
char *x;
packet = &dp;
b = (unsigned char *) xfer_context->write_buffer->unix_usr_data;
packet->packet_type = get_byte(&b);
packet->count = get_word(&b);
numbytes = xfer_context->write_buffer->unix_data_len - 
(b - xfer_context->write_buffer->unix_usr_data);
get_nbyte(&b, packet->data, numbytes);
packet_ptr = packet->data;
x = file_specification;
do
{
GETDC;
*x++ = c;
}
while (c!='\0');
GETDC; bkup_new_date = c;
GETDC; bkup_new_date = bkup_new_date*256 + c;
GETDC; bkup_new_time = c;
GETDC; bkup_new_time = bkup_new_time*256 + c;
*bytes_read = packet_ptr - packet->data;
if (Binit (
file_specification, 
YES, 
DEF_BURECSZ, 
DEF_BUHASH) == NO) 
return xfer_failure;
c_state.comp_state = 
(xfer_context->compression_type == COMP_NONE ? CS_NONE : CS_STABLE);
c_state.ascii_transfer = FALSE;
bkup_f_offset = 0;
bkup_state = BKUP_FNAME;
return xfer_success;
}
void init_restore (xfer_context)
struct xfer_context_block *xfer_context;
{
file_create(SPECIAL_RST_FILE);
rst_state = RST_BACKUP_FILE;
xfer_context->xfer_state = X_RST_START;
}
enum xfer_return_type xfer_rrestore (xfer_context, flush)
struct xfer_context_block *xfer_context;
int flush;
{
struct data_packet *packet;
unsigned char *b;
unsigned char *dbuff;
unsigned char *dbuff_max;
unsigned char s_len;
unsigned char c;
int numbytes;
if (flush)
{
dbuff = (unsigned char *)xfer_context->write_buffer->unix_usr_data;
dbuff_max = dbuff+xfer_context->write_buffer->unix_data_len;
}
else
{
packet = &dp;
b = (unsigned char *) xfer_context->write_buffer->unix_usr_data;
packet->packet_type = get_byte(&b);
packet->count = get_word(&b);
numbytes = xfer_context->write_buffer->unix_data_len - 
(b - xfer_context->write_buffer->unix_usr_data);
get_nbyte(&b, packet->data, numbytes);
dbuff = packet->data;
dbuff_max = dbuff + packet->count;
}
while (dbuff < dbuff_max)
{
if((*decompress)(&dbuff,&c_state,&c))
{
switch (rst_state)
{
case RST_BACKUP_FILE:
file_specification[bkup_f_offset++] = c;
if (c == '\0')
{
rst_state = RST_F_PATHNAME;
s_len = strlen(file_specification) + 32;
file_write(&s_len,1);
file_write(file_specification,s_len-32);
bkup_f_offset = 0;
}
break;
case RST_F_PATHNAME:
case RST_PATHNAME:
rst_path[bkup_f_offset++] = c;
if (c == '\0')
{
s_len = strlen(rst_path);
if (s_len == 0)
continue;
s_len += 32;
file_write(&s_len,1);
file_write(rst_path,s_len-32);
bkup_f_offset = 0;
if (rst_state == RST_F_PATHNAME)
rst_state = RST_SUBDIR;
}
break;
case RST_SUBDIR:
subdir_flag[bkup_f_offset++] = c;
if (bkup_f_offset == 2)
{
if (subdir_flag[0] == 'S')
file_write("S\n",2);
else
file_write("N\n",2);
rst_state = RST_PATHNAME;
bkup_f_offset = 0;
}
break;
}
}
}
return xfer_success;
}
enum xfer_return_type xfer_backup (dbuff, dbuff_max)
unsigned char *dbuff;
unsigned char *dbuff_max;
{
unsigned char c;
while (dbuff < dbuff_max)
{
if((*decompress)(&dbuff,&c_state,&c))
{
switch (bkup_state)
{
case BKUP_FNAME:
bkup_filespec[bkup_f_offset++] = c;
if (c == '\0' )
{
bkup_state = BKUP_FSIZE;
bkup_byte_count = 4; 
bkup_f_size = 0;
}
break;
case BKUP_FSIZE:
bkup_f_size = bkup_f_size * 256 + c;
if (--bkup_byte_count == 0)
{
bkup_state = BKUP_DATE;
bkup_byte_count = 4;
bkup_dt_time = 0L;
}
break;
case BKUP_DATE:
bkup_dt_time = bkup_dt_time * 256 + c;
if (--bkup_byte_count == 0)
{
bkup_state = BKUP_FATTR;
bkup_date = bkup_dt_time / 0x10000;
bkup_time = bkup_dt_time % 0x10000;
}
break;
case BKUP_FATTR:
bkup_f_attr = c;
bkup_byte_count = bkup_f_size;
bkup_state = BKUP_FDATA;
Bcreate();
if (bkup_byte_count == 0)
{
Binstall (
bkup_new_date, bkup_new_time,
bkup_filespec, bkup_f_size,
bkup_date,
bkup_time,
bkup_f_attr );
bkup_state = BKUP_FNAME;
bkup_f_offset = 0;
}
break;
case BKUP_FDATA:
Bwrite(c);
if (--bkup_byte_count == 0)
{
Binstall (
bkup_new_date, bkup_new_time,
bkup_filespec, bkup_f_size,
bkup_date,
bkup_time,
bkup_f_attr );
bkup_state = BKUP_FNAME;
bkup_f_offset = 0;
}
break;
} 
} 
} 
return(xfer_success);
}

BOOL Binit(fname, create_it, rec_size, ibuckets)
char *fname;
BOOL create_it;
int rec_size, ibuckets;
{
int i;
long get_file_size();
if (strlen(fname) == 0)
strcpy(fname, "BACKUP");
if (get_file_size(fname) < BU_HDRSZ)
{
if (!create_it)
return(NO);
else
{
if (ibuckets == 0)
ibuckets = BU_DEFBUCK;
if (ibuckets > BU_MAXBUCK)
ibuckets = BU_MAXBUCK;
if (rec_size > BU_MAXRSZ)
rec_size = BU_MAXRSZ;
if (rec_size < BU_HDRSZ)
rec_size = BU_HDRSZ;
if (rec_size < BU_DIRSZ)
rec_size = BU_DIRSZ;
RF_create(fname, rec_size);
hdr.version[0] = '1';
hdr.version[1] = '.';
hdr.version[2] = '0';
hdr.version[3] = '0';
hdr.recsize = rec_size;
hdr.buckets = ibuckets;
hdr.hblocking = hdr.recsize >> 2; 
hdr.hrec_count = hdr.buckets / hdr.hblocking;
if (hdr.buckets % hdr.hblocking) 
++hdr.hrec_count;
hdr.free_first = 0L;
hdr.free_last = 0L;
hdr.file_last = hdr.hrec_count;
hdr.bu_date = 0; 
hdr.bu_time = 0;
checkpoint(CKPT_INITIATE); 
crit_initiate();
return(YES);
}
}
file_open(fname);
(void)file_read(bu_rec, BU_HDRSZ); 
hdr_read();
if (file_close() == -1)
{
pshutdown(ferrno, ferrtx);
}
RF_open(fname, hdr.recsize);
if (hdr.c_status != CKPT_INITIATE)
for (i = 1; i <= hdr.hrec_count; ++i)
if (hash_read((LONG) i) == NO)
return NO;
if (hdr.c_status != CKPT_OKAY)
{
info_restore();
switch (hdr.c_status)
{
case CKPT_INITIATE:
crit_initiate();
break;
case CKPT_DELETE:
crit_delete();
break;
case CKPT_INSTALL:
crit_install();
break;
default:
pshutdown(-99,"Invalid ckeckpoint status");
}
}
return(YES);
}
void crit_initiate()
{
int i;
for (i = 0; i < hdr.buckets; ++i)
htab[i] = 0;
for (i = 1; i <= hdr.hrec_count; ++i)
hash_write((LONG) i);
checkpoint(CKPT_OKAY);
}
int Bterm()
{
hdr_write();
return(RF_close());
}
void Bcreate()
{
nfirst = 0L;
file_lrec = hdr.file_last; 
bu_link = hdr.free_first; 
bplink(0L); 
}
void Bdelete(pathname)
BYTE *pathname;
{
if (!Blookup(pathname))
return;
checkpoint(CKPT_DELETE); 
crit_delete(); 
}
void crit_delete()
{
Add_to_free(dir.dfirst, dir.dlast);
Set_prior(dir.syn_next);
Add_to_free(current, current);
checkpoint(CKPT_OKAY); 
}
void Binstall(new_date, new_time, pathname, size, date, time, attr)
WORD new_date, new_time;
BYTE *pathname;
LONG size;
WORD date, time;
BYTE attr;
{
BYTE *p, *q;
int i;
LONG first_drec = 0L, last_drec = 0L;
if (size > 0)
{
last_drec = bu_link; 
data_write(YES); 
if (hdr.free_first > 0L)
first_drec = hdr.free_first;
else
first_drec = hdr.file_last + 1;
if (nfirst > 0L)
last_drec = file_lrec;
}
hdr.free_first = bu_link; 
dupname = Blookup(pathname);
odfirst = dir.dfirst; 
odlast = dir.dlast;
dir.dfirst = first_drec;
dir.dlast = last_drec;
dir.fdate = new_date;
dir.ftime = new_time;
dir.fsize = size;
dir.dtime = time;
dir.ddate = date;
dir.dattr = attr;
p = dir.fname;
q = pathname;
for (i = 0; i < BU_FNSZ && *q; ++i)
*p++ = *q++;
for (; i < BU_FNSZ; ++i)
*p++ = (char)NULL;
hdr.bu_date = new_date;
hdr.bu_time = new_time;
hdr.file_last = file_lrec; 
if (!dupname)
{
if (hdr.free_first == 0L)
newdir = ++hdr.file_last;
else
{
newdir = hdr.free_first;
RF_read(bu_rec, hdr.free_first);
hdr.free_first = bglink();
}
}
checkpoint(CKPT_INSTALL);
crit_install(); 
}
void crit_install()
{
if ( (nfirst == 0L) &&
(dir.fsize > 0L) &&
(hdr.free_last != dir.dlast) ) 
{
RF_read(bu_rec, dir.dlast); 
bplink(0L); 
RF_write(bu_rec, dir.dlast); 
}
if ( (nfirst > 0L) && (hdr.free_last > 0L) )
{
RF_read(bu_rec, hdr.free_last);
bplink(nfirst); 
RF_write(bu_rec, hdr.free_last);
}
if (hdr.free_first == 0L)
hdr.free_last = 0L;
if (dupname) 
Add_to_free(odfirst, odlast);
else
{
Set_prior(newdir);
dir.syn_next = current;
current = newdir;
}
dir_write(current);
checkpoint(CKPT_OKAY);
}
BOOL Bopenf(path, subdirs_ok)
char *path;
BOOL subdirs_ok;
{
if (Bcompile(path, subdirs_ok)) 
{
if (!Bposition((WORD) 0, YES)) 
return(NO);
while (!Bmatch(dir.fname))
{
if (!Badvance(YES)) 
return(NO);
}
return(YES);
}
else
return(Blookup(path));
}
BOOL Bopenn()
{
while (Badvance(YES))
{
if (Bmatch(dir.fname))
return(YES);
}
return(NO);
}
BYTE Bread()
{
return(bgchar());
}
void Bwrite (c)
BYTE c;
{
bpchar(c);
}
BOOL Badvance(keep_going)
BOOL keep_going;
{
prior = current;
current = dir.syn_next;
if (current > 0L)
{
dir_read(current);
return(YES);
}
if (!keep_going)
return(NO);
return(Bposition((WORD) bucket+1, YES));
}
WORD Bhash(name)
char *name;
{
WORD hash_value;
hash_value = 0;
while (*name)
hash_value += *name++;
return(hash_value % hdr.buckets);
}
BOOL Blookup(name)
char *name;
{
int rval;
if (!Bposition(Bhash(name), NO))
return(NO);
while ((rval = strncmp(name, dir.fname, BU_FNSZ)) > 0)
{
if (!Badvance(NO))
return(NO);
}
return(rval == 0);
}
BOOL Bposition(hash_value, keep_going)
WORD hash_value;
BOOL keep_going;
{
prior = 0; 
current = 0;
for (bucket = hash_value; bucket < hdr.buckets; ++bucket)
{
current = htab[bucket];
if (current > 0L)
{
dir_read(current);
return(YES);
}
if (!keep_going)
return(NO);
}
return(NO);
}
void Add_to_free(first, last)
LONG first, last;
{
if (first == 0L)
return;
if ( (hdr.free_first == 0L) && (first != last) )
{
hdr.free_first = first; 
hdr.free_last = last; 
}
else
{
bplink(hdr.free_first);
RF_write(bu_rec, last);
hdr.free_first = first; 
if (hdr.free_last == 0L) 
hdr.free_last = last;
}
}
void data_write(eof_flag)
BOOL eof_flag;
{
int i;
bpfill();
if (bu_link == 0L)
{
++file_lrec; 
if (eof_flag)
bplink(0L); 
else
bplink(file_lrec + 1L); 
RF_write(bu_rec, file_lrec);
if (nfirst == 0L) 
nfirst = file_lrec;
}
else
{
RF_read(bu_rec2, bu_link);
for (i = 0; i < 4; ++i) 
bu_rec[i] = bu_rec2[i];
RF_write(bu_rec, bu_link); 
bu_link = bglink();
}
bplink(0L); 
}
void Set_prior(link_value)
LONG link_value;
{
if (prior == 0L) 
{
htab[bucket] = link_value;
hash_write( (LONG) ((bucket / hdr.hblocking) + 1));
}
else
{
RF_read(bu_rec, prior);
bplink(link_value);
RF_write(bu_rec, prior);
}
}
static void add_chr(c)
BYTE c;
{
if (autoix >= autotab + AUTOSIZE)
pshutdown(-35, "Internal error.");
*autoix++ = c;
}
BOOL Bcompile(pname, subs_ok)
BYTE *pname;
BOOL subs_ok;
{
BYTE *p, *q;
int i;
BOOL wild = NO;
BYTE buf[WRQPATHSIZE+2];
if ((i = strlen(pname)) > WRQPATHSIZE || i < 1)
pshutdown(-46, "Internal error.");
if (subs_ok)
{
for (p = q = pname; *p; ++p)
if (*p == SD_CHAR)
q = p + 1;
for (p = buf; pname < q;)
*p++ = *pname++;
*p++ = SUBDIR;
while (*p++ = *pname++)
;
pname = buf;
}
for (autoix = autotab; *pname; ++pname)
switch (*pname)
{
case '*':
for (i = 0; i < 8; ++i)
add_chr(FANY);
while (*pname != '.' && *pname != SD_CHAR && *pname)
++pname;
--pname;
wild = YES;
break;
case '?':
add_chr(FANY);
wild = YES;
break;
case SUBDIR:
add_chr(FSUBDIR);
wild = YES;
break;
case '.':
add_chr(FDOT);
break;
default:
add_chr(FCHAR);
add_chr(*pname);
}
if (wild)
{
add_chr(FCHAR);
add_chr((char)NULL);
add_chr(FSUCCEED);
return(YES);
}
else
{
autoix = autotab;
add_chr(FFAIL);
return(NO);
}
}
BOOL Bmatch(s)
BYTE *s;
{
BYTE *p, *q;
static int fcount = 0;
extern void send_rr();
if (fcount++ > 20)
{
send_rr();
fcount = 0;
}
for (p = autotab; ;)
switch (*p++)
{
case FCHAR:
if (*p++ != *s++)
return(NO);
break;
case FDOT:
if (*s == '.')
++s;
else if (*s)
return(NO);
break;
case FSUBDIR:
for (q = s; *q; ++q)
if (*q == SD_CHAR)
s = q + 1;
break;
case FANY:
if (*s == SD_CHAR)
return(NO);
if (*s && *s != '.')
++s;
break;
case FSUCCEED:
return(YES);
default: 
return(NO);
}
}
BYTE bgchar()
{
if ((bu_ptr - bu_rec) >= hdr.recsize)
{
RF_read(bu_rec, bu_link);
bu_link = bglink();
}
return(*bu_ptr++);
}
void bgstr(s, c)
BYTE *s;
int c;
{
while (c--)
*s++ = bgchar();
}
WORD bgword()
{
BYTE c;
c = bgchar();
return( (c<<8) + (bgchar() & 0xff));
}
LONG bglong()
{
WORD w;
w = bgword();
return( (((LONG) w) << 16) + (bgword() & 0xffff));
}
LONG bglink()
{
bu_ptr = bu_rec;
return(bglong());
}
void bpchar(c)
BYTE c;
{
if ((bu_ptr - bu_rec) >= hdr.recsize)
data_write(NO);
*bu_ptr++ = c;
}
void bpstr(s, c)
BYTE *s;
int c;
{
while (c--)
bpchar(*s++);
}
void bpword(w)
WORD w;
{
bpchar( (BYTE) (w>>8));
bpchar( (BYTE) w);
}
void bplong(l)
LONG l;
{
bpword( (WORD) (l>>16));
bpword( (WORD) l);
}
void bplink(l)
LONG l;
{
bu_ptr = bu_rec;
bplong(l);
}
void bpfill()
{
while ((bu_ptr - bu_rec) < hdr.recsize)
bpchar((char)NULL);
}
void hdr_read()
{
bu_ptr = bu_rec;
hdr.recsize = BU_HDRSZ; 
bgstr(hdr.version, BU_VERSZ);
hdr.recsize = bgword();
hdr.buckets = bgword();
hdr.hrec_count = bgchar();
hdr.hblocking = bgword();
hdr.free_first = bglong();
hdr.free_last = bglong();
hdr.file_last = bglong();
hdr.bu_date = bgword();
hdr.bu_time = bgword();
hdr.c_status = bgchar();
hdr.c_dupname = bgchar();
hdr.c_prior = bglong();
hdr.c_current = bglong();
hdr.c_bucket = bglong();
hdr.c_nfirst = bglong();
hdr.c_newdir = bglong();
hdr.c_odfirst = bglong();
hdr.c_odlast = bglong();
hdr.c_dir.syn_next = bglong();
hdr.c_dir.dfirst = bglong();
hdr.c_dir.dlast = bglong();
hdr.c_dir.fdate = bgword();
hdr.c_dir.ftime = bgword();
hdr.c_dir.fsize = bglong();
hdr.c_dir.ddate = bgword();
hdr.c_dir.dtime = bgword();
hdr.c_dir.dattr = bgchar();
bgstr(hdr.c_dir.fname, BU_FNSZ);
}
void hdr_write()
{
bu_ptr = bu_rec;
bpstr(hdr.version, BU_VERSZ);
bpword(hdr.recsize);
bpword(hdr.buckets);
bpchar(hdr.hrec_count);
bpword(hdr.hblocking);
bplong(hdr.free_first);
bplong(hdr.free_last);
bplong(hdr.file_last);
bpword(hdr.bu_date);
bpword(hdr.bu_time);
bpchar(hdr.c_status);
bpchar(hdr.c_dupname);
bplong(hdr.c_prior);
bplong(hdr.c_current);
bplong(hdr.c_bucket);
bplong(hdr.c_nfirst);
bplong(hdr.c_newdir);
bplong(hdr.c_odfirst);
bplong(hdr.c_odlast);
bplong(hdr.c_dir.syn_next);
bplong(hdr.c_dir.dfirst);
bplong(hdr.c_dir.dlast);
bpword(hdr.c_dir.fdate);
bpword(hdr.c_dir.ftime);
bplong(hdr.c_dir.fsize);
bpword(hdr.c_dir.ddate);
bpword(hdr.c_dir.dtime);
bpchar(hdr.c_dir.dattr);
bpstr(hdr.c_dir.fname, BU_FNSZ);
bpfill(); 
RF_write(bu_rec, 0L);
}
void checkpoint(st)
BYTE st;
{
BYTE *p, *q;
int i;
hdr.c_status = st;
hdr.c_dupname = dupname;
hdr.c_prior = prior;
hdr.c_current = current;
hdr.c_bucket = bucket;
hdr.c_nfirst = nfirst;
hdr.c_newdir = newdir;
hdr.c_odfirst = odfirst;
hdr.c_odlast = odlast;
hdr.c_dir.syn_next = dir.syn_next;
hdr.c_dir.dfirst = dir.dfirst;
hdr.c_dir.dlast = dir.dlast;
hdr.c_dir.fdate = dir.fdate;
hdr.c_dir.ftime = dir.ftime;
hdr.c_dir.fsize = dir.fsize;
hdr.c_dir.ddate = dir.ddate;
hdr.c_dir.dtime = dir.dtime;
hdr.c_dir.dattr = dir.dattr;
p = hdr.c_dir.fname;
q = dir.fname;
for (i = 0; i < BU_FNSZ; ++i)
*p++ = *q++;
hdr_write();
}
void info_restore()
{
BYTE *p, *q;
int i;
dupname = hdr.c_dupname;
prior = hdr.c_prior;
current = hdr.c_current;
bucket = hdr.c_bucket;
nfirst = hdr.c_nfirst;
newdir = hdr.c_newdir;
odfirst = hdr.c_odfirst;
odlast = hdr.c_odlast;
dir.syn_next = hdr.c_dir.syn_next;
dir.dfirst = hdr.c_dir.dfirst;
dir.dlast = hdr.c_dir.dlast;
dir.fdate = hdr.c_dir.fdate;
dir.ftime = hdr.c_dir.ftime;
dir.fsize = hdr.c_dir.fsize;
dir.ddate = hdr.c_dir.ddate;
dir.dtime = hdr.c_dir.dtime;
dir.dattr = hdr.c_dir.dattr;
p = dir.fname;
q = hdr.c_dir.fname;
for (i = 0; i < BU_FNSZ; ++i)
*p++ = *q++;
}
BOOL hash_read(r)
LONG r; 
{
int offset, i;
if (RF_read(bu_rec, r) == -1)
return NO;
offset = (r-1) * hdr.hblocking;
bu_ptr = bu_rec;
for (i = 0; i < hdr.hblocking; ++i)
if (offset < hdr.buckets)
htab[offset++] = bglong();
return YES;
}
void hash_write(r)
LONG r;
{
int offset, i;
offset = (r-1) * hdr.hblocking;
bu_ptr = bu_rec;
for (i = 0; i < hdr.hblocking; ++i)
if (offset < hdr.buckets)
bplong(htab[offset++]);
bpfill();
RF_write(bu_rec, r);
}
void dir_read(r)
LONG r;
{
RF_read(bu_rec, r);
dir.syn_next = bglink();
dir.dfirst = bglong();
dir.dlast = bglong();
dir.fdate = bgword();
dir.ftime = bgword();
dir.fsize = bglong();
dir.ddate = bgword();
dir.dtime = bgword();
dir.dattr = bgchar();
bgstr(dir.fname, BU_FNSZ);
bu_ptr = bu_rec + hdr.recsize + 1; 
bu_link = dir.dfirst; 
}
void dir_write(r)
LONG r;
{
bplink(dir.syn_next);
bplong(dir.dfirst);
bplong(dir.dlast);
bpword(dir.fdate);
bpword(dir.ftime);
bplong(dir.fsize);
bpword(dir.ddate);
bpword(dir.dtime);
bpchar(dir.dattr);
bpstr(dir.fname, BU_FNSZ);
bpfill();
RF_write(bu_rec, r);
}
void pshutdown (ferrno, ferrtxt)
int ferrno;
char *ferrtxt;
{
}
long get_file_size(fn)
char *fn;
{
struct stat statbuf;
return (stat(fn, &statbuf) == -1 ? -1L : statbuf.st_size);
}

int file_open(fn)
char *fn; 
{
u_eof = NO;
u_fd = fl_open(fn, 0); 
return (u_fd == -1 ? -1 : 0);
}
int file_create(fn)
char *fn;
{
u_fd = fl_create(fn);
return (u_fd == -1 ? -1 : 0);
}
int file_read (buf, blen)
char *buf; 
int blen; 
{
int i;
if (u_eof)
return(0);
if ((i = fl_read(u_fd, buf, blen)) != blen)
u_eof = YES;
return(i);
}
int file_write(buf, blen)
char *buf;
int blen;
{
return (fl_write(u_fd, buf, blen));
}
int file_close()
{
return(fl_close(u_fd));
}
int file_delete(nm)
char *nm;
{
if (delete(nm))
{
pshutdown(errno, "error on file delete.");
return -1;
}
return 0;
}
int RF_create(nm, rsize)
char *nm;
int rsize;
{
if (fl_close(fl_create(nm)) == -1)
{
pshutdown(ferrno, "close after RF_create failed.");
return -1;
}
return (RF_open(nm, rsize));
}
int RF_open (nm, rsize)
char *nm;
int rsize;
{
RF_rsize = rsize;
if (!(RF_ptr = fopen(nm,"r+")))
{
pshutdown(-1,"open failed; file not found or inaccessible.");
return -1;
}
if (fseek(RF_ptr,0,2)==EOF)
{
pshutdown(-1,"fseek failed.");
return -1;
}
RF_eof = ftell(RF_ptr)/RF_rsize;
bkup_closed = NO;
return 0;
}
int RF_read(buf, rnum)
char *buf;
LONG rnum;
{
if (RF_position(rnum) == -1)
return -1;
if (!ppl_fread(buf, RF_rsize, 1, RF_ptr))
{
pshutdown(-1,"read failed.");
return -1;
}
return 0;
}
int RF_write(buf, rnum)
char *buf;
LONG rnum;
{
if (RF_position(rnum) == -1)
return -1;
if (!ppl_fwrite(buf, RF_rsize, 1, RF_ptr))
{
pshutdown(-1,"write failed.");
return -1;
}
if (rnum == RF_eof)
RF_eof += 1;
return 0;
}
int RF_close()
{
int st;
bkup_closed = YES;
if ((st = fclose(RF_ptr))==EOF)
pshutdown(-1,"close failed.");
return st;
}
int RF_position(rnum)
LONG rnum; 
{
if (rnum > RF_eof || fseek(RF_ptr, rnum*RF_rsize,0)==EOF)
{
pshutdown(-1,"fseek failed.");
return -1;
}
return 0;
}
static int fl_open(fn, open_flag)
char *fn;
int open_flag;
{
int r_value;
if ((r_value = open(fn, open_flag)) == -1)
{
ferrno = errno;
ferrtx = "open failed; file not found or inaccessible.";
pshutdown(ferrno, ferrtx);
}
return(r_value);
}
static int fl_create(fn)
char *fn;
{
int r_value;
if ((r_value = creat(fn, 0644)) == -1)
{
ferrno = errno;
ferrtx = "open failed; file not creatable.";
#ifdef ENOTDIR
if (errno == ENOTDIR)
ferrtx = "a component of the path prefix is not a directory.";
#endif
#ifdef ENOENT
if (errno == ENOENT)
ferrtx = "a component of the path prefix does not exist.";
#endif
#ifdef EACCES
if (errno == EACCES)
ferrtx = "search/write permission denied for the specified file.";
#endif
#ifdef EISDIR
if (errno == EISDIR)
ferrtx = "specified file is a directory.";
#endif
#ifdef EROFS
if (errno == EROFS)
ferrtx = "file would reside on a read-only file system.";
#endif
pshutdown(ferrno, ferrtx);
}
return(r_value);
}
static int fl_close(fd)
int fd;
{
if (close(fd) == -1)
{
ferrno = errno;
ferrtx = "close failed.";
#ifdef EBADF
if (errno == EBADF)
ferrtx = "close: bad file handle.";
#endif
return(-1);
}
else
return(0);
}
static int fl_read(fd, buf, blen)
int fd;
char *buf; 
int blen; 
{
int i, progress;
progress = 0;
for (i = 1; (i >= 1) && blen; buf += i, blen -= i, progress += i)
i = ppl_read(fd, buf, blen);
if (i == -1)
{
pshutdown(errno, "read failed.");
return -1;
}
return(progress);
}
static int fl_write(fd, buf, blen)
int fd;
char *buf;
int blen;
{
int i;
if ((i = ppl_write(fd, buf, blen)) == -1)
{
ferrno = errno;
ferrtx = "write failed.";
if (file_switch == 'F')
ferrtx = "rec length not a factor of file size";
pshutdown(ferrno, ferrtx);
return -1;
}
if (i != blen)
{
pshutdown(EINVAL, "write: out of room.");
return -1;
}
return blen;
}
delete(name)
char *name;
{
return (unlink(name));
}
#endif
