summaryrefslogtreecommitdiff
path: root/v4.0/src/CMD/BACKUP/BACKUP.C
diff options
context:
space:
mode:
Diffstat (limited to 'v4.0/src/CMD/BACKUP/BACKUP.C')
-rw-r--r--v4.0/src/CMD/BACKUP/BACKUP.C4385
1 files changed, 4385 insertions, 0 deletions
diff --git a/v4.0/src/CMD/BACKUP/BACKUP.C b/v4.0/src/CMD/BACKUP/BACKUP.C
new file mode 100644
index 0000000..2f2805a
--- /dev/null
+++ b/v4.0/src/CMD/BACKUP/BACKUP.C
@@ -0,0 +1,4385 @@
1/* 0 */
2
3/************************************************************
4/*
5/* UTILITY NAME: BACKUP.COM
6/*
7/* SOURCE FILE NAME: BACKUP.C
8/*
9/* DESCRIPTIVE NAME:
10/* DOS Backup Utility Program
11/*
12/* STATUS: BACKUP utility, DOS Version 4.00
13/* Written using the C programming language.
14/*
15/*
16/* COMPILER/LINKER INVOCATION:
17/*
18/* cc /AS /Os /Zep /W3 /DLINT_ARGS /UDEBUG backup.c;
19/* link backup,,,mapper+comsubs
20/*
21/* Note: You MUST(!) use the PACKED option (/Zp) to make sure data structures
22/* are not aligned !!!
23/*
24/* FUNCTION:
25/* BACKUP will back up files from one disk(ette) to another. Accepts
26/* global characters, other parameters are defined to allow a more
27/* restrictive BACKUP procedure. Compacts data into one large file and
28/* a control file containing directory information. Allows FORMATTING
29/* target diskette, intelligent error recovery, and proper handling of
30/* file sharing and sharing errors. Optionally creates a log file for
31/* tracking purposes. Sets errorlevels on termination to indicate
32/* result.
33/*
34/* RESTRICTIONS:
35/* The BACKUP Utility program will be version checked to run ONLY on
36/* DOS version 4.00. BACKUP performs a file by file backup using the
37/* DOS file system, ie. it is not an image type backup.
38/*
39/*
40/* SYNTAX:
41/*
42/* BACKUP [d:][path] filename [.ext]] d: [/S] [/F[:size]]
43/* [/L[:fn]] [/M] [/A] [T:hh:mm:ss] [/D:mm-dd-yy]
44/*
45/* [/F[:size]] undocumented
46/*
47/* SOURCE HISTORY:
48/*
49/* New for DOS 3.3 and OS/2
50/*
51/* Modification History:
52/*
53/* ;AN000; Code added in DOS 4.0
54/* 6-05-87 RW
55/* ;AN000;1 No BACKUP of SYSTEM files
56/* ;AN000;2 Support for APPEND /X deactivation
57/* ;AN000;3 Support for Extended Attributes
58/* ;AN000;4 Support for PARSE service routines
59/* ;AN000;5 Support for code page file tags
60/* ;AN000;6 Support for MESSAGE retriever
61/* ;AN000;7 Allow logfile to go on BACKUP target drive
62/* ;AN000;8 Eliminate double prompting on single diskette drive systems
63/* ;AN000;9 Put error message in logfile on share error
64/* ;AN000;10 Make diskette formatting the default (DCR 177)
65/* ;AN000;d178 DCR 178 Find FORMAT.COM before beginning
66/* ;AN001; DCR 434 - Allow /F:size to specify format size
67/* ;AN002; Don't use "C" routines to find PATH in environment
68/* ;AN003; Make BACKUP handle UNC format returned from XLAT
69/* ;AN004; Add CR, LF to end of command line (p3646)
70/* ;AN005; Make sure no bogus BACKUP and CONTROL files are left in case of error exit
71/* ;AN006; Make sure we don't try to BACKUP logfile
72/* ;AN007; Make sure ABORT responses to critical errors are aborted
73/* ;AN008; Make PARSE errors messages display the offending parameter
74/* ;AN009; Fix parser
75/* ;AN010; Don't find FORMAT.COM on target drive
76/* ;AN011; Make BACKUP handle disk full properly on fixed disk
77/*****************************************************************
78
79 /* "C" supplied include files */
80#include <process.h>
81#include <malloc.h>
82#include <direct.h> /*;AN000;*/
83#include <string.h>
84#include <dos.h>
85#include <stdlib.h> /*;AN000;d178*/
86
87#include <doscalls.h> /* OS/2 Include file */
88
89#include "backup.h" /* BACKUP structures, defines, ...*/
90#include "backpars.h" /* DEFINEs and STRUCTs for the DOS Parse service routines */
91
92#include <version.h> /* symbol defns to determine degree of compatibility */
93
94 /**********************************/
95 /* DATA STRUCTURES */
96 /**********************************/
97 WORD rc; /* Return code from DOS calls */
98
99 unsigned selector; /* Kinda like a segment address */
100
101 struct node *curr_node; /* Pointer to "node" structure for the */
102 /* directory currently being processed */
103
104 struct node *last_child; /* Pointer to "node" structure for the */
105 /* last directory discovered in the */
106 /* directory currently being processed */
107
108 struct subst_list sublist; /*;AN000;6 Message substitution list */
109
110 struct p_parms parms; /*;AN000;4 Parser data structure */
111 struct p_parmsx parmsx; /*;AN000;4 Parser data structure */
112 struct p_pos_blk pos1; /*;AN000;4 Parser data structure */
113 struct p_pos_blk pos2; /*;AN000;4 Parser data structure */
114 struct p_sw_blk sw1; /*;AN000;4 Parser data structure */
115 struct p_sw_blk sw2; /*;AN000;4 Parser data structure */
116 struct p_sw_blk sw3; /*;AN000;4 Parser data structure */
117 struct p_sw_blk sw4; /*;AN000;4 Parser data structure */
118 struct p_sw_blk sw5; /*;AN001;DCR 434 Parser data structure */
119
120 struct p_result_blk pos_buff; /*;AN000;4 Parsr data structure */
121 struct switchbuff sw_buff; /*;AN000;4 Parsr data structure */
122 struct timebuff time_buff; /*;AN000;4 Parsr data structure */
123 struct datebuff date_buff; /*;AN000;4 Parsr data structure */
124 struct val_list_struct value_list; /*;AN001;DCR 434*/
125 struct val_table_struct value_table; /*;AN001;DCR 434*/
126 char curr_parm[128]; /*;AN009; Current parameter being parsed*/
127
128 DWORD noval = 0; /*;AN000;4 Value list for PARSR */
129
130 struct FileFindBuf dta; /* Return area for Find First/Next*/
131 struct FileFindBuf *dta_addr; /* Pointer to above */
132 union REGS inregs, outregs; /*;AN000;2 Register set */
133
134 /**********************************/
135 /* DATA AREAS */
136 /**********************************/
137 WORD dirhandle; /* Dirhandle field, for Find First, Find Next */
138 BYTE dirhandles_open = FALSE; /* Flag indicating at least 1 open dirhandle */
139
140 WORD def_drive; /* Storage for default drive (1=A,2=B,...) */
141 BYTE src_drive_letter; /* ASCII drive letter, source drive */
142 BYTE tgt_drive_letter; /* ASCII drive letter, target drive */
143 BYTE src_def_dir[PATHLEN+20]; /* default dir on source, drive letter omitted */
144
145 BYTE src_drive_path_fn[PATHLEN+20]; /* D:\path\fn - The fully qualified spec to be backed up*/
146 BYTE src_drive_path[PATHLEN+20]; /* D:\path - Fully qualified drive and path to be backed up */
147 BYTE src_fn[PATHLEN]; /* fn - File spec to be backed up. Set to *.* if no filespec entered. */
148 BYTE ext[3]; /* Filename extension */
149
150 WORD files_backed_up = 0; /* Counter for number files backed up on current target */
151 BYTE diskettes_complete = 0; /* Number of diskettes already filled and complete */
152 DWORD curr_db_begin_offset; /* Offset within the control file of the current Directory Block */
153 DWORD curr_fh_begin_offset; /* Offset within the control file of the current File Header */
154 WORD handle_source = 0xffff; /* Handle for source file */
155 WORD handle_target = 0xffff; /* Handle for target file */
156 WORD handle_control = 0xffff; /* Handle for control file */
157 WORD handle_logfile = 0xffff; /* Handle for log file */
158 DWORD part_size; /* Number of bytes from a file on the disk (for files that span) */
159 DWORD cumul_part_size; /* Number of bytes from all disks for a particular file */
160
161 BYTE logfile_path[PATHLEN+20]; /* D:\path\filename - drive,path, and name */
162 BYTE format_path[PATHLEN+20]; /*;AN000;d178 Full path to FORMAT.COM */
163 BYTE format_size[128]; /*;AN001;DCR 434 If user enters "/F:size" this will be "size" */
164
165 /**********************************/
166 /* PROGRAM CONTROL FLAGS */
167 /**********************************/
168 BYTE do_subdirs = FALSE; /* User parameters, /S */
169 BYTE do_add = FALSE; /* User parameters, /A */
170 BYTE do_modified = FALSE; /* User parameters, /M */
171 BYTE do_format_parms = FALSE; /* User parameters, /F ;AN000;d177 */
172 BYTE do_logfile = FALSE; /* User parameters, /L */
173 BYTE do_time = FALSE; /* User parameters, /T */
174 BYTE do_date = FALSE; /* User parameters, /D */
175
176 BYTE buffers_allocated = FALSE; /* Indicates if file buffers were allocated */
177 BYTE curr_dir_set = FALSE; /* Indicates if the current directory on source was changed */
178 BYTE def_drive_set = FALSE; /* Indicates if the default drive was changed */
179
180 BYTE control_opened = FALSE; /* Indicates if file opened or not */
181 BYTE logfile_opened = FALSE; /*;AN000;7 Indicates if logfile file is opened */
182 BYTE source_opened = FALSE; /* Indicates if file opened or not */
183 BYTE target_opened = FALSE; /* Indicates if file opened or not */
184
185 BYTE doing_first_target = TRUE; /* Indicates that first target is being processed */
186 BYTE got_first_target = FALSE; /* Indicates that first target is being processed */
187
188 BYTE source_removable; /* Indicates if the source drive is removable */
189 BYTE target_removable; /* Indicates if the target drive is removable */
190
191 BYTE file_spans_target; /* Indicates that first target is being processed */
192 BYTE disk_full = FALSE; /* Flag indicating the disk is full */
193 BYTE logfile_on_target = FALSE; /*;AN000;7 Flag telling if user wants logfile on target drive */
194 BYTE got_path_validity = FALSE; /*;AN000;4 Flag indicating we have not verified input path*/
195 BYTE checking_target = FALSE; /*;AN007; Indicates if we are checking target diskette to determine if it is formatted */
196
197 BYTE new_directory = TRUE; /* Indicates that file to be backed up is in a different directory */
198 BYTE found_a_file = FALSE; /* Indicates if a file was found to be backed up */
199 BYTE back_it_up = FALSE; /* Indicates if a file was found and conforms to specified parameters */ char author[45]=" Program Author: W. Russell Whitehead ";
200 /**********************************/
201 /* EXTENDED ATTRIBUTES */
202 /**********************************/
203/*EAEA BYTE ext_attrib_flg = FALSE; /*;AN000;3 Indicates there are extended attributes*/
204/*EAEA WORD ext_attrib_len; /*;AN000;3 Length of extended attributes*/
205/*EAEA BYTE ext_attrib_buff[EXTATTBUFLEN]; /*;AN000;3 Buffer for extended attributes*/
206 BYTE ext_attrib_buff[3]; /*;AN000;3 Buffer for extended attributes*/
207 struct parm_list ea_parmlist; /*;AN000;3 Parameter list for extended open*/
208
209 /**********************************/
210 /* APPEND STUFF */
211 /**********************************/
212 BYTE append_indicator = 0xff; /*;AN000;2 Indicates if support for APPEND /X is active */
213 WORD original_append_func; /*;AN000;2 APPEND functions on program entry, restored on program exit */
214
215 /**********************************/
216 /* OTHER STUFF */
217 /**********************************/
218 BYTE span_seq_num; /* Counter indicating which part of a spanning file is on current target */
219
220 WORD data_file_alloc_size = 0xffff; /* Number of paragraphs to initially try to allocate for data file */
221
222 DWORD data_file_tot_len = 0; /* Storage area for data file current length */
223 DWORD ctl_file_tot_len = 0; /* Storage area for control file current length on the disk */
224
225 WORD ctry_date_fmt;
226 BYTE ctry_time_fmt;
227 WORD ctry_date_sep;
228 WORD ctry_time_sep;
229
230 WORD user_specified_time = 0; /* Time user entered in response to /T parameter */
231 WORD user_specified_date = 0; /* Date user entered in response to /T parameter */
232
233 BYTE return_code = RETCODE_NO_ERROR; /* Save area for DOS ErrorLevel */
234
235/** ***********************************************/
236/*
237/* SUBROUTINE NAME: main
238/*
239/* FUNCTION:
240/*
241/* Backs up files from source to target drive
242/*
243/***************************************************/
244main(argc,argv)
245int argc;
246char *argv[];
247{
248 init(); /*;AN000;6 Mundane initializization of data structures, */
249 /* check DOS version,preload messages */
250 def_drive = get_current_drive(); /* Save default drive number*/
251 check_drive_validity(argc,argv); /* Check for validity of input drive(s) */
252 get_drive_types(); /* Find out if source and target are removable */
253 get_country_info(); /* Get country dependent information */
254 parser(argc,argv); /*;AN000;4 Parse input line, init switches and flags*/
255 check_path_validity(argv); /*;AN000;4 Verify that the source filespec is valid */
256 if (target_removable) /*;AN000;d178 If target drive is diskette */
257 find_format(); /*;AN000;d178 Find FORMAT.COM and build path to it*/
258 save_current_dirs(); /* Save default directories on def drive, source and target */
259 alloc_buffer(); /* Allocate IO buffer */
260 check_appendX(); /*;AN000;2 Check APPEND /X status, turn off if active */
261 set_vectors(); /* Set vectors for Int 23h and 24h */
262 do_backup(); /* Do the BACKUP */
263
264 return(0);
265} /* end main */
266
267/** ***********************************************/
268/*
269/* SUBROUTINE NAME: init
270/*
271/* FUNCTION:
272/* Preload messages
273/* Check DOS version
274/* Mundane initializization of data structures
275/*
276/**************************************************/
277void init() /*;AN000;6*/
278{ /*;AN000;6*/
279
280 /**********************************/
281 /** PRELOAD MESSAGES **/
282 /**********************************/
283 sysloadmsg(&inregs,&outregs); /*;AN000;6 Preload messages, check DOS version */
284
285 if (outregs.x.cflag & CARRY) /*;AN000;6 If there was an error */
286 { /*;AN000;6*/
287 sysdispmsg(&outregs,&outregs); /*;AN000;6 Display the error message (Use OUTREGS as input*/
288 return_code = RETCODE_ERROR; /*;AN000;6 Set the return code */
289 terminate(); /*;AN000;6 and terminate */
290 } /*;AN000;6*/
291
292 /**********************************/
293 /** SETUP MESSAGE SUBST LIST **/
294 /**********************************/
295 sublist.sl_size1= SUBLIST_SIZE; /*;AN000;6 Initialize subst list for message retriever*/
296 sublist.sl_size2= SUBLIST_SIZE; /*;AN000;6*/
297 sublist.one = 1; /*;AN000;6*/
298 sublist.two = 2; /*;AN000;6*/
299 sublist.zero1 = 0; /*;AN000;6*/
300 sublist.zero2 = 0; /*;AN000;6*/
301
302 ext_attrib_buff[0] = 0; /*;AN000;3*/
303 ext_attrib_buff[1] = 0; /*;AN000;3*/
304
305 date_buff.month = 0; /*;AN000;3*/
306 date_buff.day = 0; /*;AN000;3*/
307 date_buff.year = 0; /*;AN000;3*/
308
309 time_buff.hours = 0; /*;AN000;3*/
310 time_buff.minutes = 0; /*;AN000;3*/
311 time_buff.seconds = 0; /*;AN000;3*/
312 time_buff.hundreds= 0; /*;AN000;3*/
313
314 dta_addr = (struct FileFindBuf *)&dta; /* Get address of FindFile buffer */
315
316 return; /*;AN000;6*/
317} /*;AN000;6*/
318
319
320/** ***********************************************/
321/*
322/* SUBROUTINE NAME: parser
323/*
324/* FUNCTION:
325/*
326/* Parse the command line
327/*
328/**************************************************/
329void parser(argc,argv) /*;AN000;4*/
330int argc; /*;AN000;4*/
331char *argv[]; /*;AN000;4*/
332{ /*;AN000;4*/
333 char cmd_line[128]; /*;AN000;4*/
334 char not_finished = TRUE; /*;AN000;4*/
335 int x; /*;AN000;4*/
336
337 parse_init(); /* Initialize parser data structures*//*;AN000;4*/
338
339 /* Copy command line parameters to local area */
340 cmd_line[0] = NUL; /*;AN000;4*/
341 for (x=1; x<=argc; x++) /*;AN000;4*/
342 { /*;AN000;4*/
343 strcat(cmd_line,argv[x]); /*;AN000;4*/
344 if (x != argc) strcat(cmd_line," "); /*;AN000;4*/
345 } /*;AN000;4*/
346
347 strcat(cmd_line,"\r"); /*;AN004;*/
348
349 inregs.x.si = (WORD)&cmd_line[0]; /*DS:SI points to cmd line*//*;AN000;4*/
350
351
352
353 while (not_finished) /*;AN000;4 For all strings in command line */
354 { /*;AN000;4*/
355 inregs.x.dx = 0; /*;AN000;4 RESERVED */
356 inregs.x.di = (WORD)&parms; /*ES:DI*/ /*;AN000;4 address of parm list */
357
358 parse(&inregs,&outregs); /*;AN000;4 Call DOS SYSPARSE service routines*/
359
360 x=0; /* Save the parsed parameter */ /*;AN009;*/
361 for (inregs.x.si; inregs.x.si<outregs.x.si; inregs.x.si++) /*;AN009;*/
362 { /*;AN009;*/
363 curr_parm[x] = *(char *)inregs.x.si; /*;AN009;*/
364 x++; /*;AN009;*/
365 } /*;AN009;*/
366
367 curr_parm[x] = NUL; /*;AN009;*/
368
369 inregs = outregs; /*;AN000;4 Reset registers*/
370
371 if (outregs.x.ax!=(WORD)NOERROR) /*;AN000;4*/
372 { /*;AN000;4*/
373 if (outregs.x.ax!=(WORD)EOL) /*;AN000;4*/
374 parse_error(outregs.x.ax,outregs.x.dx); /*;AN000;4*//*;AN008;*/
375 not_finished = FALSE; /*;AN000;4*/
376 } /*;AN000;4*/
377
378 if (not_finished) /*;AN000;4 If there was not an error*/
379 { /*;AN000;4*/
380 if (outregs.x.dx == (WORD)&sw_buff) /*;AN000;4*/
381 process_switch(); /*;AN000;4 Its a switch*//*;AN008;*/
382
383 if (outregs.x.dx == (WORD)&time_buff) /*;AN000;4*/
384 { /*;AN000;4 Its a TIME parameter*/
385 if (do_time) /*;AN000;4*/
386 parse_error(outregs.x.ax,outregs.x.dx); /*;AN000;4*//*;AN008;*/
387
388 check_time(time_buff.hours,time_buff.minutes,time_buff.seconds,time_buff.hundreds);/*;AN000;4*/
389 time_buff.seconds = time_buff.seconds / 2; /*;AN000;4 See "NOTE FROM PARSER SUBROUTINE" in backup.h */
390 user_specified_time = (time_buff.hours*0x800) + (time_buff.minutes*32) + time_buff.seconds;/*;AN000;4 TIME bit format hhhhhmmmmmmxxxxx */
391 } /*;AN000;4*/
392
393 if (outregs.x.dx == (WORD)&date_buff) /*;AN000;4*/
394 { /*;AN000;4*/
395 if (do_date) /*;AN000;4*/
396 parse_error(outregs.x.ax,outregs.x.dx); /*;AN000;4*//*;AN008;*/
397
398 check_date(date_buff.year,date_buff.month,date_buff.day);/*;AN000;4*/
399 user_specified_date = ((date_buff.year-1980)*512) + (date_buff.month*32) + (date_buff.day); /*;AN000;4 DATE bit format yyyyyyymmmmddddd */
400 } /*;AN000;4*/
401
402 } /* end not_finished */ /*;AN000;4*/
403
404 } /* end WHILE */ /*;AN000;4*/
405
406 if (strlen(argv[1]) >= 5) /*;AN000;p2592*/
407 check_for_device_names(argv); /*;AN000;p2592*/
408
409 return; /*;AN000;4 Return to caller*/
410} /* end parser */ /*;AN000;4*/
411/** ***********************************************/
412/*
413/* SUBROUTINE NAME: parse_error
414/*
415/* FUNCTION:
416/*
417/* There was a parse error. Display appropriate
418/* error message and terminate.
419/*
420/**************************************************/
421void parse_error(ax,dx) /*;AN000;4*/
422WORD ax; /*;AN000;4*/
423WORD dx; /*;AN000;4*/
424{ /*;AN000;4*/
425 sublist.value1 = &curr_parm[0]; /*;AN008;*/
426 sublist.flags1 = LEFT_ALIGN + CHAR_FIELD_ASCIIZ; /*;AN008;*/
427 sublist.pad_char1 = ' '; /*;AN008;*/
428 sublist.one = 0; /*;AN008;*/
429 sublist.max_width1 = (BYTE)strlen(curr_parm); /*;AN008;*/
430 sublist.min_width1 = sublist.max_width1; /*;AN008;*/
431
432 if (dx == (WORD)&time_buff) /*;AN000;4*/
433 display_it(INV_TIME,STDERR,1,NOWAIT,(BYTE)UTIL_MSG); /*;AN000;4*/
434 else /*;AN000;4*/
435 if (dx == (WORD)&date_buff) /*;AN000;4*/
436 display_it(INV_DATE,STDERR,1,NOWAIT,(BYTE)UTIL_MSG); /*;AN000;4*/
437 else /*;AN000;4*/
438 display_it (ax,STDERR,1,NOWAIT,(BYTE)PARSEERROR); /*;AN000;6*/
439
440 return_code = RETCODE_ERROR; /*;AN000;4*/
441 clean_up_and_exit(); /*;AN000;4*/
442
443 return; /*;AN000;4*/
444} /* end parse_error */ /*;AN000;4*/
445
446/** ***********************************************/
447/*
448/* SUBROUTINE NAME: check_date
449/*
450/* FUNCTION:
451/*
452/* A date parameter was entered. Validate it
453/*
454/**************************************************/
455void check_date(year,month,day) /*;AN000;4*/
456WORD year; /*;AN000;4*/
457BYTE month; /*;AN000;4*/
458BYTE day; /*;AN000;4*/
459{ /*;AN000;4*/
460 if (year > 2099 || year < 1980) /*;AC000;4*/
461 error_exit(INV_DATE); /*;AC000;4*/
462
463 if (month > 12 || month < 1) /*;AC000;4*/
464 error_exit(INV_DATE); /*;AC000;4*/
465
466 if (day > 31 || day < 1) /*;AC000;4*/
467 error_exit(INV_DATE); /*;AC000;4*/
468
469 /* Verify day not greater then 30 if Apr,Jun,Sep,Nov */
470 if ((day>30) && (month==4 || month==6 || month==9 || month==11))/*;AC000;4*/
471 error_exit(INV_DATE); /*;AC000;4*/
472
473 if (month == 2) /* Deal with February */ /*;AC000;4*/
474 { /*;AC000;4*/
475 if (day > 29) /* if Feb 30 or above */ /*;AC000;4*/
476 error_exit(INV_DATE); /* then Bad Date */ /*;AC000;4*/
477
478 if ((year % 4) != 0) /* If not a leap year */ /*;AC000;4*/
479 if (day > 28) /* if Feb 29 or above */ /*;AC000;4*/
480 error_exit(INV_DATE); /* then Bad Date */ /*;AC000;4*/
481 } /*;AC000;4*/
482
483 do_date = TRUE; /*;AN000;4*/
484
485 return; /*;AN000;4*/
486} /* end check_date */ /*;AN000;4*/
487
488/** ***********************************************/
489/*
490/* SUBROUTINE NAME: check_time
491/*
492/* FUNCTION:
493/*
494/* A time parameter was entered. Validate it
495/*
496/**************************************************/
497void check_time(hours,minutes,seconds,hundreds) /*;AN000;4*/
498BYTE hours; /*;AN000;4*/
499BYTE minutes; /*;AN000;4*/
500BYTE seconds; /*;AN000;4*/
501BYTE hundreds; /*;AN000;4*/
502{ /*;AN000;4*/
503 if (hours > 23 || hours < 0) /*;AC000;4*/
504 error_exit(INV_TIME); /*;AC000;4*/
505
506 if (minutes >= 60 || minutes < 0) /*;AC000;4*/
507 error_exit(INV_TIME); /*;AC000;4*/
508
509 if (seconds >= 60 || seconds < 0) /*;AC000;4*/
510 error_exit(INV_TIME); /*;AC000;4*/
511
512 if (hundreds > 99 || hundreds < 0) /*;AC000;4*/
513 error_exit(INV_TIME); /*;AC000;4*/
514
515 do_time = TRUE; /*;AN000;4*/
516
517 return; /*;AN000;4*/
518} /* end check_time */ /*;AN000;4*/
519
520/** ***********************************************/
521/*
522/* SUBROUTINE NAME: parse_init
523/*
524/* FUNCTION:
525/*
526/* Initialize the parser data structures
527/*
528/**************************************************/
529void parse_init() /*;AN000;4*/
530{ /* Initialize PARMS data structure */ /*;AN000;4*/
531 parms.parmsx_ptr = (WORD)&parmsx; /*;AN000;4*/
532 parms.p_num_extra = 1; /*;AN000;4*/
533 parms.p_len_extra_delim = 1; /*;AN000;4*/
534 parms.p_extra_delim[0] = ';'; /*;AN000;4*/
535 parms.p_extra_delim[1] = NUL; /*;AN000;4 */
536
537 /* Initialize PARMSX data structure */
538 parmsx.p_minpos= 2; /*;AN000;4*/
539 parmsx.p_maxpos= 2; /*;AN000;4*/
540 parmsx.pos1_ptr= (WORD)&pos1; /*;AN000;4*/
541 parmsx.pos2_ptr= (WORD)&pos2; /*;AN000;4*/
542 parmsx.num_sw = 5; /*;AN000;4*/
543 parmsx.sw1_ptr = (WORD)&sw1; /*;AN000;4*/
544 parmsx.sw2_ptr = (WORD)&sw2; /*;AN000;4*/
545 parmsx.sw3_ptr = (WORD)&sw3; /*;AN000;4*/
546 parmsx.sw4_ptr = (WORD)&sw4; /*;AN000;4*/
547 parmsx.sw5_ptr = (WORD)&sw5; /*;AN001;DCR 434*/
548 parmsx.num_keywords = 0; /*;AN000;4*/
549
550 /* Initialize POS1 data structure */
551 pos1.match_flag = FILESPEC; /*;AN000;4*/
552 pos1.function_flag = 0; /*;AN000;4*/
553 pos1.result_buf = (WORD)&pos_buff; /*;AN000;4*/
554 pos1.value_list = (WORD)&noval; /*;AN000;4*/
555 pos1.nid = 0; /*;AN000;4*/
556
557 /* Initialize POS2 data structure */
558 pos2.match_flag = DRIVELETTER; /*;AN000;4*/
559 pos2.function_flag = 0; /*;AN000;4*/
560 pos2.result_buf = (WORD)&pos_buff; /*;AN000;4*/
561 pos2.value_list = (WORD)&noval; /*;AN000;4*/
562 pos2.nid = 0; /*;AN000;4*/
563
564 /* Initialize SW1 data structure */
565 sw1.p_match_flag = 0; /*;AN000;4*/
566 sw1.p_function_flag = 0; /*;AN000;4*/
567 sw1.p_result_buf = (WORD)&sw_buff; /*;AN000;4*/
568 sw1.p_value_list = (WORD)&noval; /*;AN000;4*/
569 sw1.p_nid = 4; /*;AN000;4*/
570 strcpy(sw1.switch1,"/S"); /*;AN000;4*/
571 strcpy(sw1.switch2,"/M"); /*;AN000;4*/
572 strcpy(sw1.switch3,"/A"); /*;AN000;4*/
573
574 /* Initialize SW2 data structure */
575 sw2.p_match_flag = DATESTRING; /*;AN000;4*/
576 sw2.p_function_flag = 0; /*;AN000;4*/
577 sw2.p_result_buf = (WORD)&date_buff; /*;AN000;4*/
578 sw2.p_value_list = (WORD)&noval; /*;AN000;4*/
579 sw2.p_nid = 1; /*;AN000;4*/
580 strcpy(sw2.switch1,"/D"); /*;AN000;4*/
581
582 /* Initialize SW3 data structure */
583 sw3.p_match_flag = TIMESTRING; /*;AN000;4*/
584 sw3.p_function_flag = 0; /*;AN000;4*/
585 sw3.p_result_buf = (WORD)&time_buff; /*;AN000;4*/
586 sw3.p_value_list = (WORD)&noval; /*;AN000;4*/
587 sw3.p_nid = 1; /*;AN000;4*/
588 strcpy(sw3.switch1,"/T"); /*;AN000;4*/
589
590 /* Initialize SW4 data structure */
591 sw4.p_match_flag = SSTRING + OPTIONAL; /*;AN000;4*/
592 sw4.p_function_flag = CAP_FILETABLE; /*;AN000;4*/
593 sw4.p_result_buf = (WORD)&sw_buff; /*;AN000;4*/
594 sw4.p_value_list = (WORD)&noval; /*;AN000;4*/
595 sw4.p_nid = 1; /*;AN000;4*/
596 strcpy(sw4.switch1,"/L"); /*;AN000;4*/
597
598 /* Initialize SW5 data structure */
599 sw5.p_match_flag = SSTRING + OPTIONAL; /*;AN001;DCR 434*/
600 sw5.p_function_flag = CAP_CHARTABLE; /*;AN001;DCR 434*/
601 sw5.p_result_buf = (WORD)&sw_buff; /*;AN001;DCR 434*/
602 sw5.p_value_list = (WORD)&value_list; /*;AN001;DCR 434*/
603 sw5.p_nid = 1; /*;AN001;DCR 434*/
604 strcpy(sw5.switch1,"/F"); /*;AN001;DCR 434*/
605
606 /* Initialize value list data structure */
607 value_list.nval = 3; /*;AN001;DCR 434*/
608 value_list.num_ranges = 0; /*;AN001;DCR 434*/
609 value_list.num_choices = 0; /*;AN001;DCR 434*/
610 value_list.num_strings = 27; /*;AN001;DCR 434*/
611 value_list.val01 = (WORD)&value_table.val01[0]; /*;AN001;DCR 434*/
612 value_list.val02 = (WORD)&value_table.val02[0]; /*;AN001;DCR 434*/
613 value_list.val03 = (WORD)&value_table.val03[0]; /*;AN001;DCR 434*/
614 value_list.val04 = (WORD)&value_table.val04[0]; /*;AN001;DCR 434*/
615 value_list.val05 = (WORD)&value_table.val05[0]; /*;AN001;DCR 434*/
616 value_list.val06 = (WORD)&value_table.val06[0]; /*;AN001;DCR 434*/
617 value_list.val07 = (WORD)&value_table.val07[0]; /*;AN001;DCR 434*/
618 value_list.val08 = (WORD)&value_table.val08[0]; /*;AN001;DCR 434*/
619 value_list.val09 = (WORD)&value_table.val09[0]; /*;AN001;DCR 434*/
620 value_list.val10 = (WORD)&value_table.val10[0]; /*;AN001;DCR 434*/
621 value_list.val11 = (WORD)&value_table.val11[0]; /*;AN001;DCR 434*/
622 value_list.val12 = (WORD)&value_table.val12[0]; /*;AN001;DCR 434*/
623 value_list.val13 = (WORD)&value_table.val13[0]; /*;AN001;DCR 434*/
624 value_list.val14 = (WORD)&value_table.val14[0]; /*;AN001;DCR 434*/
625 value_list.val15 = (WORD)&value_table.val15[0]; /*;AN001;DCR 434*/
626 value_list.val16 = (WORD)&value_table.val16[0]; /*;AN001;DCR 434*/
627 value_list.val17 = (WORD)&value_table.val17[0]; /*;AN001;DCR 434*/
628 value_list.val18 = (WORD)&value_table.val18[0]; /*;AN001;DCR 434*/
629 value_list.val19 = (WORD)&value_table.val19[0]; /*;AN001;DCR 434*/
630 value_list.val20 = (WORD)&value_table.val20[0]; /*;AN001;DCR 434*/
631 value_list.val21 = (WORD)&value_table.val21[0]; /*;AN001;DCR 434*/
632 value_list.val22 = (WORD)&value_table.val22[0]; /*;AN001;DCR 434*/
633 value_list.val23 = (WORD)&value_table.val23[0]; /*;AN001;DCR 434*/
634 value_list.val24 = (WORD)&value_table.val24[0]; /*;AN001;DCR 434*/
635 value_list.val25 = (WORD)&value_table.val25[0]; /*;AN001;DCR 434*/
636 value_list.val26 = (WORD)&value_table.val26[0]; /*;AN001;DCR 434*/
637 value_list.val27 = (WORD)&value_table.val27[0]; /*;AN001;DCR 434*/
638
639 /* Initialize FORMAT value table */
640 strcpy(value_table.val01,"160"); /*;AN001;DCR 434*/
641 strcpy(value_table.val02,"160K"); /*;AN001;DCR 434*/
642 strcpy(value_table.val03,"160KB"); /*;AN001;DCR 434*/
643 strcpy(value_table.val04,"180"); /*;AN001;DCR 434*/
644 strcpy(value_table.val05,"180K"); /*;AN001;DCR 434*/
645 strcpy(value_table.val06,"180KB"); /*;AN001;DCR 434*/
646 strcpy(value_table.val07,"320"); /*;AN001;DCR 434*/
647 strcpy(value_table.val08,"320K"); /*;AN001;DCR 434*/
648 strcpy(value_table.val09,"320KB"); /*;AN001;DCR 434*/
649 strcpy(value_table.val10,"360"); /*;AN001;DCR 434*/
650 strcpy(value_table.val11,"360K"); /*;AN001;DCR 434*/
651 strcpy(value_table.val12,"360KB"); /*;AN001;DCR 434*/
652 strcpy(value_table.val13,"720"); /*;AN001;DCR 434*/
653 strcpy(value_table.val14,"720K"); /*;AN001;DCR 434*/
654 strcpy(value_table.val15,"720KB"); /*;AN001;DCR 434*/
655 strcpy(value_table.val16,"1200"); /*;AN001;DCR 434*/
656 strcpy(value_table.val17,"1200K"); /*;AN001;DCR 434*/
657 strcpy(value_table.val18,"1200KB"); /*;AN001;DCR 434*/
658 strcpy(value_table.val19,"1.2"); /*;AN001;DCR 434*/
659 strcpy(value_table.val20,"1.2M"); /*;AN001;DCR 434*/
660 strcpy(value_table.val21,"1.2MB"); /*;AN001;DCR 434*/
661 strcpy(value_table.val22,"1440"); /*;AN001;DCR 434*/
662 strcpy(value_table.val23,"1440K"); /*;AN001;DCR 434*/
663 strcpy(value_table.val24,"1440KB"); /*;AN001;DCR 434*/
664 strcpy(value_table.val25,"1.44"); /*;AN001;DCR 434*/
665 strcpy(value_table.val26,"1.44M"); /*;AN001;DCR 434*/
666 strcpy(value_table.val27,"1.44MB"); /*;AN001;DCR 434*/
667
668 return; /*;AN000;4*/
669} /*;AN000;4*/
670/** ***********************************************/
671/*
672/* SUBROUTINE NAME: find_format
673/*
674/* FUNCTION:
675/*
676/* Search for the FORMAT utility. If found, then
677/* build a full path to it from the root. If not
678/* found, tell the user and terminate.
679/*
680/***************************************************/
681void find_format() /*;AN000;d178*/
682{ /*;AN000;d178*/
683 BYTE found_it= FALSE; /*;AN000;d178*/
684 BYTE no_more = FALSE; /*;AN000;d178*/
685 int findex,pindex; /*;AN002;*/
686 BYTE done = FALSE; /*;AN002;*/
687 char path[130]; /*;AN002;*/
688
689 /*******************************/
690 /* First try current directory */
691 format_path[0] = '.'; /*;AN000;d178*/
692 format_path[1] = NUL; /*;AN000;d178*/
693
694 /* Build full path */
695 xlat(format_path,format_path); /*;AN000;d178*/
696
697 /* If at root, remove trailing backslash */
698 if (strlen(format_path)==3 && format_path[1]==':') /*;AN000;p1900*/
699 format_path[2] = NUL; /*;AN000;p1900*/
700
701 strcat(format_path,"\\FORMAT.COM"); /*;AN000;d178*/
702
703 /* Now look for it */
704 if (format_path[0] == tgt_drive_letter) /*;AN010;*/
705 if (target_removable) /*;AN010;*/
706 format_path[0] = NUL; /*;AN010;*/
707
708 if (exist(format_path)) /*;AN000;d178*/
709 found_it = TRUE; /*;AN000;d178*/
710 else /*;AN000;d178*/
711 {
712 get_path(path); /*;AN002;*/
713
714 if (strlen(path)==0 || path[0]==NUL) /*;AN002;*/
715 error_exit(CANT_FIND_FORMAT); /*;AN002;*/
716 }
717
718 pindex = 0;
719 while (!found_it && path[pindex] != NUL)
720 {
721 for (findex=0; path[pindex]!=NUL && path[pindex]!=';'; pindex++) /*;AN002;*/
722 { /*;AN002;*/
723 format_path[findex] = path[pindex]; /*;AN002;*/
724 findex++; /*;AN002;*/
725 } /*;AN002;*/
726
727 if (path[pindex]==';')
728 pindex++;
729
730 format_path[findex] = NUL; /*;AN002;*/
731
732 xlat(format_path,format_path); /*;AN002;*/
733
734 if (strlen(format_path)==3 && format_path[1]==':') /*;AN000;p1900*/
735 format_path[2] = NUL; /*;AN000;p1900*/
736
737 strcat(format_path,"\\FORMAT.COM"); /*;AN000;d178*/
738
739 if (format_path[0] == tgt_drive_letter) /*;AN010;*/
740 if (target_removable) /*;AN010;*/
741 format_path[0] = NUL; /*;AN010;*/
742
743 if (exist(format_path)) /*;AN000;d178*/
744 found_it = TRUE; /*;AN000;d178*/
745 } /*;AN000;d178*/
746
747 if (!found_it) /*;AN000;d178*/
748 error_exit(CANT_FIND_FORMAT); /*;AN000;d178*/
749
750 return; /*;AN000;d178*/
751} /*;AN000;d178*/
752/** ***********************************************/
753/*
754/* SUBROUTINE NAME: get_path
755/*
756/* FUNCTION:
757/* Finds the environment pointer in the PSP, and
758/* searches the envirnment for a PATH statement.
759/* If found, copies it to the buffer address passed in.
760/*
761/***************************************************/
762void get_path(p) /*;AN002;*/
763char *p; /*;AN002;*/
764{ /*;AN002;*/
765 char far * env_ptr; /*;AN002;*/
766 WORD env_seg; /*;AN002;*/
767 BYTE got_path = FALSE; /*;AN002;*/
768 BYTE done = FALSE; /*;AN002;*/
769 union REGS xregs; /*;AN002;*/
770 char path[130]; /*;AN002;*/
771
772 /* First find PSP */
773 xregs.x.ax = 0x6200; /* Get PSP Address */ /*;AN002;*/
774 intdos(&xregs,&xregs); /* Returned in BX */ /*;AN002;*/
775
776 /* Build pointer to env ptr from PSP+2c */
777 env_ptr = far_ptr(xregs.x.bx,0x2c); /*;AN002;*/
778 env_seg = *(WORD far *)env_ptr; /*;AN002;*/
779 env_ptr = far_ptr(env_seg,0); /*;AN002;*/
780 *p = NUL; /*;AN002;*/
781
782 /* Search for PATH in the environment */
783 while (!done) /*;AN002;*/
784 { /*;AN002;*/
785 if /*;AN002;*/
786 (*env_ptr == 'P' && /*;AN002;*/
787 *(env_ptr+1) == 'A' && /*;AN002;*/
788 *(env_ptr+2) == 'T' && /*;AN002;*/
789 *(env_ptr+3) == 'H' && /*;AN002;*/
790 *(env_ptr+4) == '=' /*;AN002;*/
791 ) /*;AN002;*/
792 { /*;AN002;*/
793 done = TRUE; /*;AN002;*/
794 got_path = TRUE; /*;AN002;*/
795 } /*;AN002;*/
796 else /*;AN002;*/
797 if (*env_ptr == NUL && *(env_ptr+1) == NUL) /*;AN002;*/
798 done = TRUE; /*;AN002;*/
799
800 if (!done) /*;AN002;*/
801 env_ptr++; /*;AN002;*/
802 } /*;AN002;*/
803
804 /* Copy path to desired buffer */
805 if (got_path) /*;AN002;*/
806 { /*;AN002;*/
807 env_ptr += 5; /* Skip over "PATH=" */ /*;AN002;*/
808 for (; *env_ptr!=NUL; env_ptr++) /*;AN002;*/
809 { /*;AN002;*/
810 *p = *env_ptr; /*;AN002;*/
811 p++; /*;AN002;*/
812 } /*;AN002;*/
813
814 *p = NUL; /*;AN002;*/
815 } /*;AN002;*/
816
817 return; /*;AN002;*/
818} /*;AN002;*/
819
820/** ***********************************************/
821/*
822/* SUBROUTINE NAME: xlat
823/*
824/* FUNCTION:
825/*
826/* Performs name translate function. Calls DOS function
827/* call 60h to build full path from root using the "src"
828/* passed in, places resultant path at "tgt".
829/*
830/***************************************************/
831void xlat(tgt,src) /*;AN000;*/
832char * tgt; /*;AN000;*/
833char * src; /*;AN000;*/
834{ /*;AN000;*/
835 union REGS xregs;
836
837 xregs.x.ax = 0x6000; /* Name Xlat*/ /*;AN000;*/
838 xregs.x.bx = 0; /* Drive*/ /*;AN000;*/
839 xregs.x.si = (WORD)src; /* Source*/ /*;AN000;*/
840 xregs.x.di = (WORD)tgt; /* Target*/ /*;AN000;*/
841 intdos(&xregs,&xregs); /* Blammo!*/ /*;AN000;*/
842
843 return; /*;AN000;*/
844} /*;AN000;*/
845/** ***********************************************/
846/*
847/* SUBROUTINE NAME: check_drive_validity
848/*
849/* FUNCTION:
850/*
851/* Verify that at least the target drive letter is
852/* is entered. Verify that they are valid drives.
853/*
854/***************************************************/
855void check_drive_validity(argc,argv)
856int argc;
857char *argv[];
858{
859 char *t;
860 int i;
861 BYTE specified_drive;
862
863 if (argc < 2)
864 error_exit(NO_SOURCE);
865
866 /*********************/
867 /* Verify the source */
868 /*********************/
869 *argv[1] = (BYTE)com_toupper(*argv[1]);
870
871
872 t = argv[1];
873 t++;
874 if (*t == ':') /* Check specified source drive */ /*;AC000;p2671*/
875 { /*;AN000;p2671*/
876 if (*argv[1] < 'A') /*;AN000;p2671*/
877 error_exit(INV_DRIVE); /*;AN000;p2671*/
878 if (*argv[1] > 'Z') /*;AN000;p2671*/
879 error_exit(INV_DRIVE); /*;AN000;p2671*/
880 src_drive_letter = *argv[1]; /*;AN000;p2671*/
881 } /* Use default drive for source */ /*;AN000;p2671*/
882 else /*;AN000;p2671*/
883 src_drive_letter = (BYTE)def_drive + 'A' - 1; /*;AN000;p2671*/
884
885 /*********************/
886 /* Verify the target */
887 /*********************/
888 if (argc < 3 )
889 error_exit(NO_TARGET);
890
891 *argv[2] = (BYTE)com_toupper(*argv[2]);
892
893 if (*argv[2] < 'A')
894 error_exit(INV_DRIVE);
895 if (*argv[2] > 'Z')
896 error_exit(INV_DRIVE);
897
898 /* Verify drive letter followed by ":" */
899 t = argv[2];
900 t++;
901 if (*t != ':')
902 error_exit(NO_TARGET);
903
904 /* Make sure drive letters are different */
905 if (src_drive_letter == *argv[2]) /*;AN000;p2671*/
906 error_exit(SRC_AND_TGT_SAME);
907
908 /* Is source a valid drive? */
909 specified_drive = src_drive_letter - 'A' + 1;
910 set_default_drive(specified_drive);
911 if (get_current_drive() != specified_drive)
912 error_exit(INV_DRIVE);
913
914 /* Is target a valid drive? */
915 specified_drive = *argv[2] - 'A' + 1;
916 set_default_drive(specified_drive);
917 if (get_current_drive() != specified_drive)
918 error_exit(INV_DRIVE);
919
920 set_default_drive(def_drive); /* Reset default drive to original one */
921 def_drive_set = FALSE;
922
923 tgt_drive_letter = *argv[2];
924
925 return;
926} /* end check_drive_validity */
927
928/** ***********************************************/
929/*
930/* SUBROUTINE NAME: check_for_device_names
931/*
932/* FUNCTION:
933/*
934/* Make sure user not trying to restore a reserved device name
935/*
936/**************************************************/
937#define INVPARM 10 /*;AN000;4*/
938void check_for_device_names(argv) /*;AN000;p2592*/
939char *argv[]; /*;AN000;p2592*/
940{ /*;AN000;p2592*/
941 union REGS qregs; /*;AN000;p2592*/
942 char target[128]; /*;AN000;p2592*/
943 char *t; /*;AN000;p2592*/
944
945#define CAPITALIZE_STRING 0x6521 /*;AN000;p2592*/
946
947 qregs.x.ax = CAPITALIZE_STRING; /*;AN000;p2592*/
948 qregs.x.dx = (WORD)argv[1]; /*;AN000;p2592*/
949 strcpy(target,argv[1]); /*;AN000;p2592*/
950 qregs.x.cx = strlen(target); /*;AN000;p2592*/
951 intdos(&qregs,&qregs); /*;AN000;p2592*/
952 strcpy(target,argv[1]); /*;AN000;p2592*/
953
954 for (t=&target[0]; *t!=NUL; t++)
955 if /*;AN000;p2592*/
956 ( strcmp(t,"LPT1")==0 || /*;AN000;p2592*/
957 strcmp(t,"LPT2")==0 || /*;AN000;p2592*/
958 strcmp(t,"PRN")==0 || /*;AN000;p2592*/
959 strcmp(t,"CON")==0 || /*;AN000;p2592*/
960 strcmp(t,"NUL")==0 || /*;AN000;p2592*/
961 strcmp(t,"AUX")==0 || /*;AN000;p2592*/
962 strcmp(t,"LPT1:")==0 || /*;AN000;p2592*/
963 strcmp(t,"LPT2:")==0 || /*;AN000;p2592*/
964 strcmp(t,"PRN:")==0 || /*;AN000;p2592*/
965 strcmp(t,"CON:")==0 || /*;AN000;p2592*/
966 strcmp(t,"NUL:")==0 || /*;AN000;p2592*/
967 strcmp(t,"AUX:")==0 /*;AN000;p2592*/
968 ) /*;AN000;p2592*/
969 { /*;AN000;p2592*/
970 sublist.value1 = (char far *)t; /*;AN000;p2592*/
971 sublist.flags1 = LEFT_ALIGN + CHAR_FIELD_ASCIIZ; /*;AN000;p2592*/
972 sublist.one = 0; /*;AN000;p2592*/
973 sublist.max_width1 = (BYTE)strlen(t); /*;AN000;p2592*/
974 sublist.min_width1 = sublist.max_width1; /*;AN000;p2592*/
975
976 display_it (INVPARM,STDERR,1,NOWAIT,(BYTE)PARSEERROR); /*;AN000;p2592*/
977 return_code = RETCODE_ERROR; /*;AN000;4*/
978 clean_up_and_exit(); /*;AN000;4*/
979 } /*;AN000;p2592*/
980
981
982 return; /*;AN000;p2592*/
983} /*;AN000;p2592*/
984
985
986/** ***********************************************/
987/*
988/* SUBROUTINE NAME: check_path_validity
989/*
990/* FUNCTION:
991/*
992/* Verify that the path entered by the user exists.
993/* Build a full path from the root, place it in
994/* src_drive_path. Extract filespec and place it
995/* in user_filespec.
996/*
997/***************************************************/
998void check_path_validity(argv)
999char *argv[];
1000{
1001 WORD dhandle;
1002 char temppath[PATHLEN+20];
1003 char temppath2[PATHLEN+20];
1004 char globals = FALSE;
1005 int x; /*;AN000;p2943*/
1006 char *foo,*foo2; /*;AN003;*/
1007 union REGS qregs; /*;AC000;8*/
1008
1009 strcpy(src_drive_path_fn,argv[1]); /* Copy argv[1] to string area */
1010
1011 for (x=0; x<strlen(src_drive_path_fn); x++) /*;AN000;p2943*/
1012 if (src_drive_path_fn[x] == BACKSLASH) /*;AN000;p2943*/
1013 if (src_drive_path_fn[x+1] == BACKSLASH) /*;AN000;p2943*/
1014 error_exit(INV_PATH); /*;AN000;p2943*/
1015
1016 if (strlen(src_drive_path_fn) == 2) /* If only a drive letter entered, make it d:*.* */
1017 if (src_drive_path_fn[1] == ':') /*;AN000;p2671*/
1018 strcat(src_drive_path_fn,"*.*");
1019
1020 if (src_drive_path_fn[strlen(src_drive_path_fn)-1] == BACKSLASH)/*;AN000;p2671*/
1021 strcat(src_drive_path_fn,"*.*"); /*;AN000;p2671*/
1022
1023 xlat(src_drive_path_fn,src_drive_path_fn); /*;AN000;p2671*/
1024
1025 /* Handle UNC format ( \\srv\name\path\path\file ) (Remote drive) */
1026 if (src_drive_path_fn[0] == BACKSLASH) /*;AN003;*/
1027 if (src_drive_path_fn[1] == BACKSLASH) /*;AN003;*/
1028 { /*;AN003;*/
1029 foo = strchr(src_drive_path_fn+3,BACKSLASH); /*;AN003;*/
1030 if (foo == NUL) /*;AN003;*/
1031 error_exit(INV_PATH); /*;AN003;*/
1032
1033 foo2 = foo + 1; /*;AN003;*/
1034 foo = strchr(foo2,BACKSLASH); /*;AN003;*/
1035 if (foo == NUL) /*;AN003;*/
1036 error_exit(INV_PATH); /*;AN003;*/
1037
1038 sprintf(src_drive_path_fn,"%c:%s",src_drive_letter,foo); /*;AN003;*/
1039 } /*;AN003;*/
1040
1041 /* See if there are global characters specified */
1042 if (com_strchr(src_drive_path_fn,'?') != NUL)
1043 globals = TRUE;
1044 else
1045 if (com_strchr(src_drive_path_fn,'*') != NUL)
1046 globals = TRUE;
1047
1048
1049 if (src_drive_path_fn[3] == BACKSLASH) /* Don't let user entered d:\\ */
1050 if (src_drive_path_fn[2] == BACKSLASH)
1051 error_exit(INV_PATH);
1052
1053 if (source_removable) /* If backing up from a diskette */
1054 {
1055 display_msg(INSERTSOURCE); /* Ask user for diskette and wait for input*/
1056 /*wait_for_keystroke(); /* Let user "Strike any key when ready" */
1057 }
1058
1059
1060 /* If single drive system, eliminates double prompting */
1061 /* for user to "Insert diskette for drive %1" */
1062 qregs.x.ax = SETLOGICALDRIVE; /*;AN000;8*/
1063 qregs.h.bl = src_drive_letter - 'A' + 1; /*;AN000;8*/
1064 intdos(&qregs,&qregs); /*;AN000;8*/
1065
1066 find_first /* Check for Invalid Path */
1067 ( /* Also figure out if it is file or directory */
1068 &src_drive_path_fn[0],
1069 &dhandle,
1070 dta_addr,
1071 (SUBDIR + SYSTEM + HIDDEN)
1072 );
1073
1074 if (rc != NOERROR) /* If there was an error */
1075 if (rc == 3) /* If it was Path Not Found */
1076 error_exit(INV_PATH); /* Terminate */
1077
1078 if (rc == NOERROR)
1079 findclose(dhandle);
1080
1081 if ((dta.attributes & SUBDIR) == SUBDIR) /* If they entered a subdirectory name, */
1082 if (dta.file_name[0] != '.') /* add to the end of it "\*.*" */
1083 if (!globals) /* But only if there are no global chars */
1084 strcat(src_drive_path_fn,"\\*.*");
1085
1086
1087 /************************/
1088 /* Build src_drive_FN **/
1089 strcpy(src_drive_path,src_drive_path_fn);
1090
1091 /* Remove last BACKSLASH to get the pathname */
1092 foo = com_strrchr(src_drive_path,BACKSLASH);
1093
1094 if (foo != NUL)
1095 if ((foo - src_drive_path) > 2)
1096 *foo = NUL;
1097 else
1098 { /* foo must = 2 */
1099 foo++;
1100 *foo = NUL;
1101 }
1102
1103 /************************/
1104 /* Build src_fn **/
1105 foo = com_strrchr(src_drive_path_fn,BACKSLASH); /*;AN000;p2341*/
1106
1107 if (foo == NUL) /*;AN000;p2341*/
1108 foo = &src_drive_path_fn[2]; /*;AN000;p2341*/
1109 else /*;AN000;p2341*/
1110 foo++; /* Skip over last non-DBCS char */ /*;AN000;p2341*/
1111
1112 strcpy(src_fn,foo); /*;AN003;*/
1113
1114 got_path_validity = TRUE; /*;AN000;4*/
1115
1116 return;
1117} /* end check_path_validity */
1118
1119/** ***********************************************/
1120/*
1121/* SUBROUTINE NAME: alloc_buffers
1122/*
1123/* FUNCTION:
1124/* Attempt to allocate a (64k-1) buffer. If
1125/* fails, decrement buff size by 512 and keep
1126/* trying. If can't get at least a 2k buffer,
1127/* give up.
1128/*
1129/***************************************************/
1130void alloc_buffer()
1131{
1132 alloc_seg();
1133
1134 while ((rc != NOERROR) && (data_file_alloc_size > 2048))
1135 {
1136 data_file_alloc_size = data_file_alloc_size - 512;
1137 alloc_seg();
1138 }
1139
1140 if (rc == NOERROR && data_file_alloc_size > 2048)
1141 buffers_allocated = TRUE;
1142 else
1143 error_exit(INSUFF_MEMORY);
1144
1145 return;
1146}
1147
1148/** ***********************************************/
1149/*
1150/* SUBROUTINE NAME: process_switch
1151/*
1152/* FUNCTION:
1153/*
1154/* Identify the parameter and set program control
1155/* flags as appropriate.
1156/*
1157/***************************************************/
1158void process_switch() /*;AN000;4*/
1159{ /*;AN000;4*/
1160 char far * y; /*;AN000;4*/
1161 int i = 0; /*;AN000;4*/
1162 char temp_str[PATHLEN+20]; /*;AN000;7*/
1163
1164 if (sw_buff.sw_synonym_ptr == (WORD)&sw1.switch1[0]) /* /S */ /*;AN000;4 /S */
1165 { /*;AN000;4*/
1166 do_subdirs=TRUE; /*;AN000;4*/
1167 } /*;AN000;4*/
1168
1169 if (sw_buff.sw_synonym_ptr == (WORD)&sw5.switch1[0]) /* /F */ /*;AN001;DCR 434 /F */
1170 { /*;AN001;DCR 434*/
1171 if (!target_removable) /*;AN001;DCR 434*/
1172 error_exit(CANT_FORMAT_HARDFILE); /*;AN001;DCR 434*/
1173
1174 do_format_parms=TRUE; /*;AN001;DCR 434*/
1175 format_size[0] = ' '; /* Can't do STRCPY during PARSE */ /*;AN001;DCR 434*/
1176 format_size[1] = '/'; /*;AN001;DCR 434*/
1177 format_size[2] = 'F'; /*;AN001;DCR 434*/
1178 format_size[3] = ':'; /*;AN001;DCR 434*/
1179 format_size[4] = NUL; /*;AN001;DCR 434*/
1180
1181 i = 4; /* Copy size */ /*;AN001;DCR 434*/
1182 for (y=(char *)sw_buff.sw_string_ptr; *y!=NUL; y++) /*;AN001;DCR 434*/
1183 { /*;AN001;DCR 434*/
1184 format_size[i] = (BYTE)*y; /*;AN001;DCR 434*/
1185 i++; /*;AN001;DCR 434*/
1186 } /*;AN001;DCR 434*/
1187
1188 /* Handle case where user only enters /F */
1189 if (
1190 format_size[4] == NUL || /*;AN001;DCR 434*/
1191 format_size[4] < '0' || /*;AN001;DCR 434*/
1192 format_size[4] > '9' /*;AN001;DCR 434*/
1193 ) /*;AN001;DCR 434*/
1194 format_size[0] = NUL; /*;AN001;DCR 434*/
1195
1196 } /*;AN001;DCR 434*/
1197
1198 if (sw_buff.sw_synonym_ptr == (WORD)&sw1.switch2[0]) /* /M */ /*;AN000;4 /M */
1199 { /*;AN000;4*/
1200 do_modified=TRUE; /*;AN000;4*/
1201 } /*;AN000;4*/
1202
1203 if (sw_buff.sw_synonym_ptr == (WORD)&sw1.switch3[0]) /* /A */ /*;AN000;4 /A */
1204 { /*;AN000;4*/
1205 do_add=TRUE; /*;AN000;4*/
1206 } /*;AN000;4*/
1207
1208 if (sw_buff.sw_synonym_ptr == (WORD)&sw4.switch1[0]) /* /L */ /*;AN000;4 /L */
1209 { /*;AN000;4*/
1210 do_logfile = TRUE; /*;AN000;4*/
1211 i = 0; /* Copy filespec */ /*;AN000;4*/
1212 for (y=(char far *)sw_buff.sw_string_ptr; *y!=NUL; y++) /*;AN000;4*/
1213 { /*;AN000;4*/
1214 temp_str[i] = (BYTE)*y; /*;AN000;4*/
1215 i++; /*;AN000;4*/
1216 } /*;AN000;4*/
1217
1218 temp_str[i] = NUL; /*;AN000;4*/
1219
1220 if (strlen(temp_str) == 0) /* Use default logfile? */ /*;AN000;7 Is default logfile?*/
1221 sprintf(temp_str,"%c:\\BACKUP.LOG",src_drive_letter); /*;AN000;7*/
1222
1223 xlat(logfile_path,temp_str); /*;AN000;7*/
1224
1225 if ((BYTE)logfile_path[0] == tgt_drive_letter) /*;AN000;7*/
1226 logfile_on_target = TRUE; /*;AN000;7*/
1227 } /*;AN000;4*/
1228
1229 return; /*;AN000;4*/
1230} /* end process_switch */ /*;AN000;4*/
1231
1232
1233/** ***********************************************/
1234/*
1235/* SUBROUTINE NAME: save_current_dirs
1236/*
1237/* FUNCTION:
1238/*
1239/* Save the current directory on default drive.
1240/* Later when we terminate we must restore it.
1241/*
1242/***************************************************/
1243void save_current_dirs()
1244{
1245
1246 src_def_dir[0] = BACKSLASH;
1247 get_current_dir(src_drive_letter -'A'+1,&src_def_dir[1]);
1248
1249 return;
1250} /* end save_current_dirs */
1251/** ***********************************************/
1252/*
1253/* SUBROUTINE NAME: open_logfile
1254/*
1255/* FUNCTION:
1256/* User specified the /L parameter for a BACKUP
1257/* log file. First try to open it. If it doesn't
1258/* exist then create it.
1259/*
1260/***************************************************/
1261void open_logfile()
1262{
1263 int x; /*;AN000;7*/
1264
1265 handle_logfile = /*;AN000;5*/
1266 extended_open /*;AN000;5*/
1267 (OPEN_IT, /* Flag;AN000;5*/
1268 0, /* attr;AN000;5*/
1269 (char far *)logfile_path, /* path;AN000;5*/
1270 (WORD)(DENYWRITE+WRITEACCESS) /* mode;AN000;5*/
1271 ); /*;AN000;5*/
1272
1273 if (rc == NOERROR)
1274 lseek(handle_logfile,EOFILE,(DWORD)0);
1275 else /* If you didn't, create the file */
1276 handle_logfile = /*;AN000;5*/
1277 extended_open /*;AN000;5*/
1278 ( CREATE_IT, /*;AN000;5*/
1279 (WORD)ARCHIVE, /*;AN000;5*/
1280 (char far *)logfile_path, /*;AN000;5*/
1281 (WORD)(WRITEACCESS) /*;AN000;5*/
1282 ); /*;AN000;5*/
1283
1284 if (rc != NOERROR) /* Terminate if can't open logfile */
1285 error_exit(CANT_OPEN_LOGFILE);
1286
1287 display_msg(LOGGING); /* Tell user where we are logging */
1288
1289 datetime(); /* Put date and time of BACKUP in logfile */
1290
1291 logfile_opened = TRUE; /*;AN000;7 The logfile is open */
1292
1293 return;
1294} /* end open_logfile */
1295
1296/** ***********************************************/
1297/*
1298/* SUBROUTINE NAME: set_vectors
1299/*
1300/* FUNCTION:
1301/* Hook control break and critical vector to
1302/* allow BACKUP to gracefully terminate.
1303/*
1304/***************************************************/
1305void set_vectors()
1306{
1307
1308 setsignal(ACTIONHOOK,CTRLC); /* Handle CTRL_C */
1309 setsignal(ACTIONHOOK,CTRLBREAK); /* Handle CTRL_BREAK */
1310 set_int24_vector(); /*;AN000; Set Critical error vector (int 24h) */
1311
1312 return;
1313} /* end set_vectors */
1314
1315/** ***********************************************/
1316/*
1317/* SUBROUTINE NAME: check_appendX
1318/*
1319/* FUNCTION:
1320/* Check APPEND /X status. If it is not active,
1321/* do nothing. If it is active, then turn it off
1322/* and set flag indicating that we must reset it later.
1323/*
1324/***************************************************/
1325void check_appendX() /*;AN000;2*/
1326{ /*;AN000;2*/
1327 union REGS gregs; /*;AN000;2 Register set */
1328
1329 gregs.x.ax = INSTALL_CHECK; /*;AN000;2 Get installed state*/
1330 int86(0x2f,&gregs,&gregs); /*;AN000;2*/
1331
1332 /*****************************************************/
1333 /* 1) See if append is active
1334 /* 2) If so, figure out if DOS or PCNET version
1335 /*****************************************************/
1336 if (gregs.h.al == 0) /*;AN000;2 Zero if not installed*/
1337 append_indicator = NOT_INSTALLED; /*;AN000;2 */
1338 else /*;AN000;2 See which APPEND it is*/
1339 { /*;AN000;2*/
1340 gregs.x.ax = GET_APPEND_VER; /*;AN000;2*/
1341 int86(0x2f,&gregs,&gregs); /*;AN000;2*/
1342
1343 if (gregs.h.al == (BYTE)-1) /*;AN000;2 -1 if DOS version*/
1344 append_indicator = DOS_APPEND; /*;AN000;2*/
1345 else /*;AN000;2*/
1346 append_indicator = NET_APPEND; /*;AN000;2*/
1347 } /*;AN000;2*/
1348
1349 /*****************************************************/
1350 /* If it is the DOS append
1351 /* 1) Get the current append functions (returned in BX)
1352 /* 2) Reset append with /X support off
1353 /*****************************************************/
1354 if (append_indicator == DOS_APPEND) /*;AN000;2*/
1355 { /*;AN000;2*/
1356 gregs.x.ax = GET_STATE; /*;AN000;2 Get active APPEND functions*/
1357 int86(0x2f,&gregs,&gregs); /*;AN000;2*/
1358 original_append_func = gregs.x.bx; /*;AN000;2*/
1359
1360 gregs.x.ax = SET_STATE; /*;AN000;2*/
1361 gregs.x.bx = gregs.x.bx & (!APPEND_X_BIT); /*;AN000;2*/
1362 int86(0x2f,&gregs,&gregs); /*;AN000;2*/
1363
1364 } /*;AN000;2*/
1365
1366 return; /*;AN000;2*/
1367} /*;AN000;2*/
1368
1369/** ***********************************************/
1370/*
1371/* SUBROUTINE NAME: get_drive_types
1372/*
1373/* FUNCTION:
1374/* For the source and target drives, figure out
1375/* if they are removable or not.
1376/*
1377/***************************************************/
1378void get_drive_types() /* Check if the source and target drive are removable*/
1379{
1380#define REMOVABLE 0
1381
1382 WORD drivehandle;
1383 char drive_spec[3];
1384
1385 /* Check Source drive */
1386 drive_spec[0] = src_drive_letter;
1387 drive_spec[1] = ':';
1388 drive_spec[2] = NUL;
1389
1390 /* Device open, source drive */
1391 drivehandle = handle_open(drive_spec,OPENDASD+DENYNONE) ;
1392
1393 /* Now see if it is removable */
1394 if (ioctl(drivehandle) == REMOVABLE)
1395 source_removable = TRUE;
1396 else
1397 source_removable = FALSE;
1398
1399 close_file(drivehandle);
1400
1401 /* Check Target drive */
1402 drive_spec[0] = tgt_drive_letter;
1403 drive_spec[1] = ':';
1404 drive_spec[2] = NUL;
1405
1406 drivehandle = handle_open(drive_spec,OPENDASD+DENYNONE) ;
1407
1408 if (ioctl(drivehandle) == REMOVABLE)
1409 target_removable = TRUE;
1410 else
1411 target_removable = FALSE;
1412
1413 close_file(drivehandle);
1414
1415 return;
1416} /* end get_drive_types */
1417
1418/** ***********************************************/
1419/*
1420/* SUBROUTINE NAME: do_backup
1421/*
1422/* FUNCTION:
1423/*
1424/* BACKUP all files that should be backed up
1425/*
1426/***************************************************/
1427void do_backup()
1428{
1429 set_default_dir(); /* Set default dir to one where source files are */
1430
1431 find_first_file(); /* Find first file to be backed up */
1432 if (back_it_up) /* If you found one.... */
1433 { /* then */
1434 get_first_target(); /* get the first diskette (or last if /A specified!) */
1435 do /* Repeat this */
1436 {
1437 open_source_file(); /* Open the file we found */
1438 if (source_opened) /* If succeessful open of source */
1439 do_copy(); /* Copy it to the target drive. Handle files that span diskettes. */
1440 find_next_file(); /* Search for another file */
1441 }
1442 while (back_it_up); /* While there are file to back up */
1443 display_msg(CRLF);
1444 }
1445 else /* otherwise */
1446 {
1447 display_msg(NONEFNDMSG);
1448 return_code = RETCODE_NO_FILES;/* there were no files to be backed up */
1449 }
1450
1451 clean_up_and_exit();
1452
1453 return;
1454} /* end do_backup */
1455/** ***********************************************/
1456/*
1457/* SUBROUTINE NAME: find_first_file
1458/*
1459/* FUNCTION:
1460/*
1461/* Find the first file conforming to user entered spec.
1462/* If necessary, look on other directory levels also.
1463/*
1464/***************************************************/
1465void find_first_file()
1466{
1467 char loop_done = FALSE;
1468
1469 back_it_up = FALSE; /* Havn't found a file yet ! */
1470 find_the_first(); /* Sets the "found_a_file" flag */
1471
1472 if (found_a_file) /* If you find a file, do this stuff */
1473 do
1474 {
1475 if (found_a_file) /* If you got one, then */
1476 see_if_it_should_be_backed_up(); /* Check it against user entered parameters */
1477
1478 if (!back_it_up) /* If it shouldn't be processed... */
1479 find_the_next(); /* then find another (sets the "found_a_file" flag) */
1480 else
1481 loop_done = TRUE; /* Otherwise your done here */
1482
1483 if (!found_a_file) /* Don't remove this ! */
1484 loop_done = TRUE; /* This has gotta stay ! */
1485 }
1486 while (!loop_done);
1487
1488 return;
1489} /* end find_first_file */
1490
1491/** *********************************************/
1492/*
1493/* SUBROUTINE NAME: find_next_file
1494/*
1495/* FUNCTION:
1496/*
1497/* Find the next file conforming to user entered spec
1498/*
1499/************************************************/
1500void find_next_file()
1501{
1502 char loop_done = FALSE;
1503
1504 back_it_up = FALSE;
1505
1506 do
1507 {
1508 find_the_next();
1509 if (found_a_file)
1510 {
1511 see_if_it_should_be_backed_up();
1512 if (back_it_up)
1513 loop_done = TRUE;
1514 }
1515 else
1516 loop_done = TRUE;
1517 }
1518 while (!loop_done);
1519
1520 return;
1521} /* end find_next_file */
1522
1523/** *********************************************/
1524/*
1525/* SUBROUTINE NAME: find_the_first
1526/*
1527/* FUNCTION:
1528/*
1529/* Find the first file conforming to user entered spec.
1530/* Searches in current directory, if one not found then
1531/* goes to the next level and repeats.
1532/*
1533/************************************************/
1534void find_the_first()
1535{
1536 char loop_done = FALSE;
1537 char file_spec[PATHLEN];
1538
1539 found_a_file = FALSE;
1540 sprintf(file_spec,"%c:%s",src_drive_letter,src_fn);
1541
1542 do
1543 {
1544 find_first /* Find file conforming to user-entered file spec */
1545 (
1546 &file_spec[0],
1547 &dirhandle,
1548 dta_addr,
1549 (SYSTEM + HIDDEN)
1550 );
1551
1552 if (rc == NOERROR)
1553 { /* If no error */
1554 found_a_file = TRUE; /* then we found a file */
1555 loop_done = TRUE; /* and we are done here */
1556 }
1557 else /* If there was an error */
1558 if (do_subdirs) /* and if user said /S */
1559 {
1560 change_levels(); /* Change DIR (Sets NewDirectory if level changed) */
1561 if (!new_directory) /* If there ain't none */
1562 loop_done = TRUE; /* then were done */
1563 }
1564 else
1565 loop_done = TRUE;
1566 }
1567 while (!loop_done);
1568
1569 return;
1570} /* end find_the_first */
1571/** ***********************************************/
1572/*
1573/* SUBROUTINE NAME: find_the_next
1574/*
1575/* FUNCTION:
1576/*
1577/* Find the next file conforming to user entered spec
1578/*
1579/***************************************************/
1580void find_the_next()
1581{
1582 char loop_done = FALSE;
1583
1584 found_a_file = FALSE;
1585
1586 find_next(dirhandle,dta_addr);
1587
1588 if (rc == NOERROR)
1589 {
1590 found_a_file = TRUE;
1591 loop_done = TRUE;
1592 }
1593 else
1594 do
1595 {
1596 if (do_subdirs)
1597 {
1598 change_levels(); /* Change DIR to next dir level */
1599 if (!new_directory) /* If we were successful */
1600 loop_done = TRUE; /* Then indicate that fact */
1601 else /* otherwise */
1602 {
1603 find_the_first(); /* Look for first file at this level */
1604 loop_done = TRUE;
1605 }
1606 }
1607 else
1608 loop_done = TRUE;
1609 }
1610 while (!loop_done);
1611
1612 return;
1613} /* end find_the_next */
1614
1615/** ***********************************************/
1616/*
1617/* SUBROUTINE NAME: change_levels
1618/*
1619/* FUNCTION:
1620/* Change directory to next one in the linked list
1621/* of directories to be processed.
1622/*
1623/***************************************************/
1624void change_levels()
1625{
1626 new_directory = FALSE;
1627 remove_node();
1628 return;
1629} /* end change_levels */
1630
1631/** ***********************************************/
1632/*
1633/* SUBROUTINE NAME: alloc_node
1634/*
1635/* FUNCTION:
1636/* Allocates a node for the linked list of subdirectories
1637/* to be processed.
1638/*
1639/***************************************************/
1640struct node * alloc_node(path_len)
1641unsigned int path_len;
1642{
1643 struct node *pointer;
1644 unsigned int malloc_size;
1645
1646 malloc_size = (unsigned int) (sizeof(struct node far *) + path_len + 2);
1647#if defined(DEBUG)
1648 printf("\nMALLOCING NODE, SIZE=%04Xh...",malloc_size);
1649#endif
1650
1651 pointer = (struct node *)malloc(malloc_size);
1652
1653#if defined(DEBUG)
1654 if (pointer != NUL)
1655 printf("SUCCESSFUL, PTR=%u",(unsigned)pointer);
1656 else
1657 printf("ERROR, PTR=%u",(unsigned)pointer);
1658#endif
1659
1660 if (pointer == NUL)
1661 error_exit(INSUFF_MEMORY);
1662 else
1663 return(pointer);
1664
1665} /* end alloc_node */
1666
1667
1668/** ***********************************************/
1669/*
1670/* SUBROUTINE NAME: alloc_first_node
1671/*
1672/* FUNCTION:
1673/*
1674/* Allocate the first node in the linked list.
1675/*
1676/***************************************************/
1677void alloc_first_node()
1678{
1679#if defined(DEBUG)
1680printf("\nINSERTING FIRST NODE=%s",src_drive_path);
1681#endif
1682
1683 curr_node = alloc_node(strlen(src_drive_path+1));
1684 last_child = curr_node;
1685 strcpy(curr_node->path,src_drive_path);
1686 curr_node->np = NUL;
1687
1688 return;
1689} /* end alloc_first_node */
1690
1691
1692/** ***********************************************/
1693/*
1694/* SUBROUTINE NAME: insert_node
1695/*
1696/* FUNCTION:
1697/*
1698/* Insert next node in the linked list of subdirectories
1699/* to be processed.
1700/*
1701/***************************************************/
1702void insert_node(path_addr)
1703char *path_addr;
1704{
1705 struct node *temp; /* temporary pointer to a node */
1706 struct node *newnode; /* same thing */
1707
1708#if defined(DEBUG)
1709printf("\nINSERTING NODE=%s",*path_addr);
1710#endif
1711 temp = last_child->np;
1712 newnode = alloc_node(strlen(path_addr));
1713 last_child->np = newnode;
1714 newnode->np = temp;
1715 strcpy(newnode->path,path_addr);
1716 last_child = newnode;
1717
1718 return;
1719} /* end insert_node */
1720
1721/** ***********************************************/
1722/*
1723/* SUBROUTINE NAME: remove_node
1724/*
1725/* FUNCTION:
1726/* CHDIR to the next level to be processed.
1727/* Release the node for that directory
1728/*
1729/***************************************************/
1730void remove_node()
1731{
1732 struct node *temp;
1733
1734 temp = curr_node;
1735 last_child = curr_node->np;
1736 if (curr_node->np != NUL)
1737 {
1738 rc = chdir(last_child->path);
1739 if (rc == NOERROR)
1740 {
1741 new_directory = TRUE;
1742 strcpy(src_drive_path,last_child->path);
1743
1744#if defined(DEBUG)
1745 printf("\nFREE NODE %u",(unsigned)curr_node);
1746#endif
1747 free((char *)curr_node);
1748 curr_node = last_child;
1749
1750 if (do_subdirs) /* Place all subdirs in linked list */
1751 find_all_subdirs();
1752 }
1753 }
1754 return;
1755} /* end remove_node */
1756
1757/** ***********************************************/
1758/*
1759/* SUBROUTINE NAME: find_all_subdirs
1760/*
1761/* FUNCTION:
1762/* User entered "/S" parameter. Search for all
1763/* subdirectory entries at this level. Place
1764/* them all in the linked list of directories to
1765/* be processed.
1766/***************************************************/
1767void find_all_subdirs()
1768{
1769 WORD dhandle;
1770 char global[6];
1771 char full_path[PATHLEN+20];
1772 struct FileFindBuf tempdta;
1773
1774 sprintf(global,"%c:*.*",src_drive_letter);
1775
1776 find_first /* Find all subdirectory entries in current directory. */
1777 (
1778 &global[0],
1779 &dhandle,
1780 &tempdta,
1781 (SUBDIR + SYSTEM + HIDDEN)
1782 );
1783
1784 while (rc == NOERROR)
1785 {
1786 if ((tempdta.attributes & SUBDIR) == SUBDIR) /* If its a subdirectory */
1787 if (tempdta.file_name[0] != '.') /* But not "." or ".." */
1788 {
1789 if (src_drive_path[strlen(src_drive_path)-1] != BACKSLASH)
1790 sprintf(full_path,"%s\\%s",src_drive_path,tempdta.file_name);
1791 else
1792 sprintf(full_path,"%s%s", src_drive_path,tempdta.file_name);
1793
1794 insert_node((char *)full_path); /* Save it in the linked list */
1795 }
1796
1797 find_next(dhandle,&tempdta);
1798 }
1799
1800 return;
1801}
1802
1803/** ***********************************************/
1804/*
1805/* SUBROUTINE NAME: get_first_target
1806/*
1807/* FUNCTION:
1808/* We are ready for the target disk. If it is a
1809/* diskette, ask user to put one in. Remember
1810/* to correctly handle /A if user wants it.
1811/*
1812/***************************************************/
1813void get_first_target()
1814{
1815 if (target_removable)
1816 get_diskette();
1817 else
1818 get_hardfile();
1819
1820 if (do_logfile)
1821 open_logfile(); /*;AN000;7 Open or create logfile*/
1822
1823 if (!do_add)
1824 put_disk_header();
1825
1826 return;
1827} /* end get_first_target */
1828
1829/** ***********************************************/
1830/*
1831/* SUBROUTINE NAME: get_next_target
1832/*
1833/* FUNCTION:
1834/* We are ready for the next target diskette.
1835/* Ask user to insert it. Format if required.
1836/* Create files, reset variables.
1837/*
1838/***************************************************/
1839void get_next_target()
1840{
1841
1842 doing_first_target = FALSE;
1843 files_backed_up = 0;
1844 display_msg(CRLF);
1845
1846 get_diskette(); /* Get it */
1847
1848 disk_full = FALSE;
1849
1850 if (do_logfile)
1851 {
1852 if (logfile_on_target) /*;AN000;7 and if logfile on the target drive*/
1853 open_logfile(); /*;AN000;7 Open or create it*/
1854 }
1855
1856 if (file_spans_target)
1857 show_path(); /* Display to stdout and logfile the full path from root */
1858
1859 put_disk_header();
1860 put_new_fh();
1861
1862 return;
1863} /* end get_next_target */
1864
1865/** ***********************************************/
1866/*
1867/* SUBROUTINE NAME: see_if_it_should_be_backed_up
1868/*
1869/* FUNCTION:
1870/* We found a file, its directory information is
1871/* at the DTA structure. Don't backup a subdirectory
1872/* or volume label. If /M specified, only backup files
1873/* with archive bit set. Don't BACKUP 0 length files.
1874/* If /D: and/or /T: specified, only backup appropriate files.
1875/*
1876/***************************************************/
1877void see_if_it_should_be_backed_up()
1878{
1879 BYTE temp[PATHLEN+20]; /*;AN006;*/
1880
1881 back_it_up = TRUE;
1882
1883 if ((dta.attributes & SUBDIR) == SUBDIR) /* Is it a directory name ? */
1884 back_it_up = FALSE; /* Indicate that we don't want to back it up */
1885
1886 if ((dta.attributes & VOLLABEL) == VOLLABEL) /* Is it a volumelabel ? */
1887 back_it_up = FALSE; /* Indicate that we don't want to back it up */
1888
1889 if (do_modified) /* Check ARCHIVE bit */
1890 if ((dta.attributes & ARCHIVE) != ARCHIVE)
1891 back_it_up = FALSE;
1892
1893 if (do_time) /* Check TIME parameter */
1894 {
1895 if (do_date)
1896 { /* If user entered a date, only files modified */
1897 if (dta.write_date == user_specified_date) /* after specified time AND ON THE DATE ENTERED */
1898 if (dta.write_time < user_specified_time) /* will be processed. Files dated after that will */
1899 back_it_up = FALSE; /* ignore time parm */
1900 }
1901 else /* If user entered time with NO DATE PARM, then */
1902 if (dta.write_time < user_specified_time) /* files modifed on or after specified time will be */
1903 back_it_up = FALSE; /* processed, regardless of date */
1904 }
1905
1906 if (do_date) /* Check DATE parameter */
1907 {
1908 if (dta.write_date < user_specified_date)
1909 back_it_up = FALSE;
1910 }
1911
1912#define SAME 0
1913
1914 if (strcmp(src_drive_path+2,"\\") == SAME) /*;AN000;1 If we are processing the root directory */
1915 if /*;AN000;1 and if we are looking at any of these files */
1916 (strcmp(dta.file_name,"IBMBIO.COM") == SAME || /*;AN000;1*/
1917 strcmp(dta.file_name,"IBMDOS.COM") == SAME || /*;AN000;1*/
1918#if ! IBMCOPYRIGHT
1919 strcmp(dta.file_name,"IO.SYS") == SAME || /*;AN000;1*/
1920 strcmp(dta.file_name,"MSDOS.SYS") == SAME || /*;AN000;1*/
1921#endif
1922 strcmp(dta.file_name,"COMMAND.COM") == SAME || /*;AN000;1*/
1923 strcmp(dta.file_name,"CMD.EXE") == SAME /*;AN000;1*/
1924 ) /*;AN000;1*/
1925 back_it_up = FALSE; /*;AN000;1 then do not back them up! */
1926
1927
1928
1929 if (do_logfile) /*;AN006;*/
1930 { /*;AN006;*/
1931 strcpy(temp,src_drive_path); /*;AN006;*/
1932
1933 if (strlen(temp) == 3) /*;AN006;*/
1934 temp[2] = NUL; /*;AN006;*/
1935
1936 sprintf(temp,"%s\\%s",temp,dta.file_name); /*;AN006;*/
1937
1938 if (strcmp(logfile_path,temp) == SAME)/*;AN006;*/
1939 back_it_up = FALSE; /*;AN006;*/
1940 } /*;AN006;*/
1941
1942 return;
1943} /* end see_if_it_should_be_backed_up */
1944
1945/** ***********************************************/
1946/*
1947/* SUBROUTINE NAME: get_diskette
1948/*
1949/* FUNCTION:
1950/* Get the diskette from user. If unformatted
1951/* and user entered /F, then try to FORMAT it.
1952/* Create target files on root of diskette.
1953/**************************************************/
1954void get_diskette()
1955{
1956 union REGS qregs; /*;AN000;8*/
1957
1958 if (!do_add)
1959 {
1960 display_msg(INSERTTARGET);
1961 display_msg(ERASEMSG);
1962 }
1963 else
1964 if (doing_first_target)
1965 display_msg(LASTDISKMSG);
1966 else
1967 {
1968 display_msg(INSERTTARGET);
1969 display_msg(ERASEMSG);
1970 }
1971
1972 got_first_target = TRUE; /*;AN000;*/
1973
1974 /*wait_for_keystroke(); /* Let user "Strike any key when ready" */
1975
1976 /* If single drive system, eliminates double prompting */
1977 /* for user to "Insert diskette for drive %1" */
1978 qregs.x.ax = SETLOGICALDRIVE; /*;AN000;8*/
1979 qregs.h.bl = tgt_drive_letter - 'A' + 1; /*;AN000;8*/
1980 intdos(&qregs,&qregs); /*;AN000;8*/
1981
1982 if (target_removable) /*;AN000;d177*/
1983 format_target();
1984
1985 if (do_add) /* If we are adding files */
1986 if (doing_first_target) /* and if its the first target */
1987 check_last_target(); /* verify that its a valid one */
1988
1989 display_msg(BUDISKMSG);
1990 display_msg(SEQUENCEMSG);
1991 delete_files(ROOTDIR); /* Delete all files in the root dir of target drive */
1992
1993 create_target(); /* Create target files */
1994
1995 return;
1996} /* end get_diskette */
1997
1998/** ***********************************************/
1999/*
2000/* SUBROUTINE NAME: get_hardfile
2001/*
2002/* FUNCTION:
2003/* Target is a hardfile. FORMATTING hardfile is
2004/* not allowed by BACKUP. Create target files
2005/* in BACKUP directory of disk.
2006/***************************************************/
2007void get_hardfile()
2008{
2009 char dirname[15];
2010
2011 sprintf(dirname,"%c:\\BACKUP\\*.*",tgt_drive_letter);
2012 if (exist(&dirname[0]))
2013 {
2014 if (!do_add)
2015 {
2016 display_msg(FERASEMSG);
2017 /*wait_for_keystroke(); /* Let user "Strike any key when ready" */
2018 }
2019 delete_files(BACKUPDIR); /* Delete \BACKUP\*.* of target drive if not do_add */
2020 }
2021 else
2022 {
2023 sprintf(dirname,"%c:\\BACKUP",tgt_drive_letter);
2024 mkdir(dirname);
2025 }
2026
2027 display_msg(BUDISKMSG);
2028 create_target();
2029
2030 return;
2031} /* end get_hardfile */
2032
2033
2034/** ***********************************************/
2035/*
2036/* SUBROUTINE NAME: check_last_target
2037/*
2038/* FUNCTION:
2039/* User entered /A parameter. Make sure that
2040/* we are not adding to a BACKUP diskette created
2041/* with the disgusting old BACKUP format.
2042/* Make sure there is a BACKUP.xxx and CONTROL.xxx
2043/* file out there. Make sure it was the last target
2044/* and get the sequence number.
2045/***************************************************/
2046void check_last_target()
2047{
2048 WORD dhandle;
2049 WORD bytes_read;
2050 BYTE flag;
2051 char path[25];
2052 char current_file[25];
2053
2054 struct FileFindBuf tempdta;
2055
2056 if (target_removable) /* Make sure there is no old BACKUP on here */
2057 sprintf(path,"%c:\\BACKUPID.@@@",tgt_drive_letter);
2058 else
2059 sprintf(path,"%c:\\BACKUP\\BACKUPID.@@@",tgt_drive_letter);
2060
2061 if (exist(path))
2062 error_exit(INVTARGET);
2063
2064 if (target_removable) /* Build path to control file */
2065 sprintf(path,"%c:\\CONTROL.*",tgt_drive_letter);
2066 else
2067 sprintf(path,"%c:\\BACKUP\CONTROL.*",tgt_drive_letter);
2068
2069 find_first /* Find the control file */
2070 (
2071 &path[0],
2072 &dhandle,
2073 &tempdta,
2074 (SYSTEM + HIDDEN)
2075 );
2076
2077 if (rc != NOERROR) /* If you got one, then close dirhandle */
2078 error_exit(NOTLASTMSG);
2079
2080 findclose(dhandle);
2081
2082
2083 /* Add drive letter to control file name */
2084 sprintf(path,"%c:%s",tgt_drive_letter,tempdta.file_name);
2085
2086 handle_control = /* Open the control file;AN000;5*/
2087 extended_open /*;AN000;5*/
2088 (OPEN_IT, /*;AN000;5*/
2089 0, /*;AN000;5*/
2090 (char far *)path, /*;AN000;5*/
2091 (WORD)(DENYWRITE+READACCESS) /*;AN000;5*/
2092 ); /*;AN000;5*/
2093
2094 if (rc != NOERROR) /* If can't open it, strange error */
2095 error_exit(NOTLASTMSG);
2096
2097 /* Get diskette sequence number */
2098 lseek(handle_control,BOFILE,(DWORD)9);
2099 bytes_read = handle_read(handle_control,1,(char far *)&diskettes_complete);
2100 diskettes_complete--; /* This diskette is not longer "complete" */
2101
2102 /* Seek to DH_LastDisk and read that byte */
2103 lseek(handle_control,BOFILE,(DWORD)138); /* Check DH_LastDisk flag in control file */
2104 bytes_read = handle_read(handle_control,1,(char far *)&flag);
2105
2106 if (flag != LAST_TARGET) /* If wasn't last target, terminate */
2107 error_exit(NOTLASTMSG);
2108
2109 close_file(handle_control); /* Close the control file */
2110 control_opened = FALSE; /*;AN005; And say it isn't open */
2111
2112 return;
2113} /* end check_last_target */
2114/** ***********************************************/
2115/*
2116/* SUBROUTINE NAME: format_target
2117/*
2118/* FUNCTION:
2119/* See if the target is formatted. If not, try
2120/* to format it.
2121/*
2122/***************************************************/
2123void format_target()
2124{
2125#define HOOK 0
2126#define UNHOOK 1
2127
2128 WORD bfree;
2129 char format_parms[35]; /*;AC000;8*/
2130 WORD temp_rc; /*;AN000;p2631 Return code from DOS calls */
2131
2132 if (do_add)
2133 if (doing_first_target)
2134 return;
2135
2136 /**********************************/
2137 /* See if diskette is unformatted */
2138 /**********************************/
2139 do_dos_error(HOOK); /* Replace hard error handler */
2140 rc = NOERROR; /* Reset return code */
2141 checking_target = TRUE; /*;AN007;*/
2142 bfree = (WORD)disk_free_space();/* If this generates hard error, then format target */
2143 checking_target = FALSE; /*;AN007;*/
2144
2145 temp_rc = rc; /*;AN000;p2631*/
2146 do_dos_error(UNHOOK); /*;AN000;p2631 Unhook hard error handler */
2147 rc = temp_rc; /*;AN000;p2631*/
2148
2149 if (rc != NOERROR) /* If there was a hard error... */
2150 { /* Then FORMAT the target */
2151 display_msg(CRLF);
2152
2153 sprintf(format_parms,"%c:",tgt_drive_letter);
2154
2155 if (do_format_parms) /*;AN001;DCR 434*/
2156 if (format_size[0] != NUL) /*;AN001;DCR 434*/
2157 strcat(format_parms,format_size); /*;AN001;DCR 434*/
2158
2159 strcat(format_parms," /BACKUP /V:BACKUP"); /*;AN000;8*/
2160
2161 if (spawnlp(P_WAIT,format_path,"FORMAT",format_parms,NUL) == NOERROR) /*;AC000;d178*/
2162 {
2163 display_msg(CRLF); /* Skip a line */
2164 }
2165 else
2166 {
2167 display_msg(ERR_EXEC_FORMAT); /* Display "Error executing FORMAT" */
2168 display_msg(INSERTTARGET); /* And give another chance */
2169 display_msg(ERASEMSG);
2170 /*wait_for_keystroke(); */
2171 }
2172
2173 }
2174
2175 return;
2176} /* end format_target */
2177
2178/** ***********************************************/
2179/*
2180/* SUBROUTINE NAME: set_default_dir
2181/*
2182/* FUNCTION:
2183/*
2184/*
2185/*
2186/***************************************************/
2187void set_default_dir()
2188{
2189 if (com_strchr(src_drive_path,BACKSLASH) != NUL) /* if there IS a backslash... */
2190 if (strlen(src_drive_path) >= 3) /* if length is greater than 3... */
2191 {
2192 rc = chdir(src_drive_path); /* then change dir to there. */
2193 if (rc == NOERROR)
2194 {
2195 src_drive_path[2] = BACKSLASH;
2196 get_current_dir(src_drive_letter-'A'+1,&src_drive_path[3]);
2197 }
2198 else
2199 error_exit(INV_PATH);
2200 }
2201
2202 curr_dir_set = TRUE;
2203
2204 if (do_subdirs) /* If we are processing subdirectories too, */
2205 {
2206 alloc_first_node(); /* then put current level in linked list */
2207 find_all_subdirs(); /* And get all directory entries in that level */
2208 }
2209
2210 return;
2211} /* end set_default_dir */
2212
2213/** ***********************************************/
2214/*
2215/* SUBROUTINE NAME: label_target_drive
2216/*
2217/* FUNCTION:
2218/* Create volume label BACKUP.xxx on target
2219/* diskette drive.
2220/*
2221/***************************************************/
2222void label_target_drive() /* Create Volume label BACKUP.XXX on target */
2223{
2224
2225 char fsbuf[20];
2226 WORD handle;
2227
2228 build_ext(diskettes_complete + 1);
2229
2230 sprintf(fsbuf,"%c:BACKUP.%s",tgt_drive_letter,ext);
2231
2232 replace_volume_label(&fsbuf[0]);
2233
2234 return;
2235} /* end label_target_drive */
2236
2237/** ***********************************************/
2238/*
2239/* SUBROUTINE NAME: build_ext
2240/*
2241/* FUNCTION:
2242/*
2243/*
2244/*
2245/***************************************************/
2246void build_ext(num)
2247int num;
2248{
2249 if (num < 10)
2250 sprintf(ext,"00%u",num);
2251 else
2252 if (num < 100)
2253 sprintf(ext,"0%u",num);
2254 else
2255 sprintf(ext,"%u",num);
2256
2257 return;
2258} /* end build_ext */
2259
2260/** ***********************************************/
2261/*
2262/* SUBROUTINE NAME: create_target
2263/*
2264/* FUNCTION:
2265/*
2266/*
2267/*
2268/***************************************************/
2269void create_target()
2270{
2271 char path[25];
2272
2273 if (do_add)
2274 if (doing_first_target)
2275 {
2276 open_target();
2277 return;
2278 }
2279
2280 build_ext(diskettes_complete + 1);
2281
2282 if (target_removable)
2283 sprintf(path,"%c:\\BACKUP.%s",tgt_drive_letter,ext);
2284 else
2285 sprintf(path,"%c:\\BACKUP\\BACKUP.%s",tgt_drive_letter,ext);
2286
2287 handle_target = /*;AN000;5*/
2288 extended_open /*;AN000;5*/
2289 ( /*;AN000;5*/
2290 CREATE_IT, /*;AN000;5*/
2291 (WORD)ARCHIVE, /*;AN000;5*/
2292 (char far *)path, /*;AN000;5*/
2293 (WORD)(READWRITE) /*;AN000;5*/
2294 ); /*;AN000;5*/
2295
2296 if (rc == NOERROR)
2297 target_opened = TRUE;
2298 else
2299 error_exit(INVTARGET);
2300
2301 if (target_removable)
2302 sprintf(path,"%c:\\CONTROL.%s",tgt_drive_letter,ext);
2303 else
2304 sprintf(path,"%c:\\BACKUP\\CONTROL.%s",tgt_drive_letter,ext);
2305
2306 handle_control = /*;AN000;5*/
2307 extended_open /*;AN000;5*/
2308 ( /*;AN000;5*/
2309 CREATE_IT, /*;AN000;5*/
2310 (WORD)ARCHIVE, /*;AN000;5*/
2311 (char far *)path, /*;AN000;5*/
2312 (WORD)(READWRITE) /*;AN000;5*/
2313 ); /*;AN000;5*/
2314
2315 if (rc == NOERROR)
2316 control_opened = TRUE;
2317 else
2318 error_exit(INVTARGET);
2319
2320 data_file_tot_len = (DWORD)0;
2321 ctl_file_tot_len = (DWORD)0;
2322
2323 return;
2324} /* end create_target */
2325
2326/** ***********************************************/
2327/*
2328/* SUBROUTINE NAME: open_target
2329/*
2330/* FUNCTION:
2331/*
2332/*
2333/*
2334/***************************************************/
2335void open_target() /* Done only if /A and it is the first target */
2336{
2337
2338 char path[PATHLEN+20];
2339
2340 /* Open BACKUP.xxx File */
2341 build_ext(diskettes_complete+1);
2342
2343 if (target_removable)
2344 sprintf(path,"%c:\\BACKUP.%s",tgt_drive_letter,ext);
2345 else
2346 sprintf(path,"%c:\\BACKUP\\BACKUP.%s",tgt_drive_letter,ext);
2347
2348 /* Turn off readonly bit on BACKUP.xxx */
2349 set_attribute(path,(WORD)(get_attribute(path) & (WORD)READONLYOFF));
2350 /* Open it */
2351 handle_target = /*;AN000;5*/
2352 extended_open /*;AN000;5*/
2353 ( OPEN_IT, /*;AN000;5*/
2354 0, /*;AN000;5*/
2355 (char far *)path, /*;AN000;5*/
2356 (WORD)(DENYALL+READWRITE) /*;AN000;5*/
2357 ); /*;AN000;5*/
2358
2359 if (rc == NOERROR)
2360 target_opened = TRUE;
2361 else
2362 error_exit(INVTARGET);
2363 /* Open CONTROL.xxx File */
2364 if (target_removable)
2365 sprintf(path,"%c:\\CONTROL.%s",tgt_drive_letter,ext);
2366 else
2367 sprintf(path,"%c:\\BACKUP\\CONTROL.%s",tgt_drive_letter,ext);
2368
2369 set_attribute(path,(WORD)(get_attribute(path) & (WORD)READONLYOFF));
2370
2371 handle_control = /*;AN000;5*/
2372 extended_open /*;AN000;5*/
2373 ( OPEN_IT, /*;AN000;5*/
2374 0, /*;AN000;5*/
2375 (char far *)path, /*;AN000;5*/
2376 (WORD)(DENYALL+READWRITE) /*;AN000;5*/
2377 ); /*;AN000;5*/
2378
2379 if (rc == NOERROR)
2380 control_opened = TRUE;
2381 else
2382 error_exit(INVTARGET);
2383
2384 data_file_tot_len = (DWORD)lseek(handle_target ,EOFILE,(DWORD)0);
2385 ctl_file_tot_len = (DWORD)lseek(handle_control,EOFILE,(DWORD)0);
2386
2387 return;
2388} /* end open_target */
2389
2390/** ***********************************************/
2391/*
2392/* SUBROUTINE NAME: delete_files
2393/*
2394/* FUNCTION:
2395/* Delete all files in the root directory of target
2396/* diskette, or in the BACKUP directory of the target
2397/* hardfile. If error occurs deleting file, try to
2398/* reset the attribute to 0 and try it again.
2399/*
2400/*
2401/***************************************************/
2402void delete_files(dirlevel)
2403char dirlevel;
2404{
2405 BYTE delete_path[25];
2406 struct FileFindBuf tempdta;
2407 struct FileFindBuf *tempdta_addr;
2408 WORD dhandle;
2409 BYTE delete_it; /*;AN000;7*/
2410
2411 if (do_add) /* Don't delete files if we */
2412 if (doing_first_target) /* are adding files to an existing */
2413 return; /* BACKUP and this is the first target */
2414
2415 tempdta_addr = (struct FileFindBuf *)&tempdta;
2416
2417 if (dirlevel == ROOTDIR)
2418 sprintf(delete_path,"%c:\\*.*",tgt_drive_letter);
2419 else
2420 sprintf(delete_path,"%c:\\BACKUP\\*.*",tgt_drive_letter);
2421
2422 find_first /* Find a file to delete */
2423 (
2424 (char *)&delete_path[0],
2425 &dhandle,
2426 tempdta_addr,
2427 (SYSTEM + HIDDEN)
2428 );
2429
2430 while (rc == NOERROR)
2431 {
2432 delete_it = TRUE; /*;AN000;7*/
2433
2434 if (dirlevel == ROOTDIR)
2435 sprintf(delete_path,"%c:\\%s",tgt_drive_letter,tempdta.file_name);
2436 else
2437 sprintf(delete_path,"%c:\\BACKUP\\%s",tgt_drive_letter,tempdta.file_name);
2438
2439 if (logfile_on_target) /*;AN000;7*/
2440 if (strcmp(delete_path,logfile_path) == SAME) /*;AN000;7*/
2441 delete_it = FALSE; /*;AN000;7*/
2442
2443 if (delete_it == TRUE) /*;AN000;7*/
2444 { /*;AN000;7*/
2445 delete(delete_path);
2446
2447 if (rc != NOERROR)
2448 {
2449 set_attribute(delete_path,(WORD)0);
2450 delete(delete_path);
2451 }
2452 } /*;AN000;7*/
2453
2454 find_next(dhandle,tempdta_addr);
2455 }
2456
2457 return;
2458} /* end delete_files */
2459
2460/** ***********************************************/
2461/*
2462/* SUBROUTINE NAME: exist
2463/*
2464/* FUNCTION:
2465/* Does a FIND FIRST of the filespec passed at PATH_ADDR.
2466/* If so, returns TRUE, otherwise returns FALSE.
2467/*
2468/***************************************************/
2469WORD exist(path_addr) /* Return TRUE if specified epath exists, FALSE other */
2470char *path_addr;
2471{
2472 WORD dhandle;
2473 WORD temprc;
2474 struct FileFindBuf tempdta;
2475
2476 find_first /* DOS Find First */
2477 (
2478 path_addr,
2479 &dhandle,
2480 &tempdta,
2481 (SUBDIR + SYSTEM + HIDDEN)
2482 );
2483
2484 temprc = rc;
2485 if (rc == NOERROR) findclose(dhandle);
2486
2487 if (temprc != NOERROR)
2488 return(FALSE);
2489 else
2490 return(TRUE);
2491
2492} /* end exist */
2493
2494/** ***********************************************/
2495/*
2496/* SUBROUTINE NAME: open_source_file
2497/*
2498/* FUNCTION:
2499/* Try to open the source file at the DTA structure.
2500/* If after MAX_RETRY_OPEN_COUNT attempts you cannot
2501/* open it, then display an appropriate message and
2502/* continue. If it was opened, then get the files
2503/* extended attributes.
2504/*
2505/***************************************************/
2506void open_source_file()
2507{
2508 int num_attempts = 0;
2509 char done = FALSE;
2510 char file_to_be_backup[20];
2511
2512 source_opened = FALSE; /* Source is not opened yet */
2513 file_spans_target = FALSE; /* File does not spans diskettes */
2514 span_seq_num = 1; /* Indicate that this is the first diskette containing part of this file*/
2515 show_path(); /* Display to stdout/logfile the full path from root */
2516 sprintf(file_to_be_backup,"%c:%s",src_drive_letter,dta.file_name);
2517
2518 do
2519 { /*;AN000;5*/ /* Attempt open */
2520 handle_source = /*;AN000;5*/
2521 extended_open /*;AN000;5*/
2522 ( /*;AN000;5*/
2523 OPEN_IT, /*;AN000;5*/
2524 0, /*;AN000;5*/
2525 (char far *)file_to_be_backup, /*;AN000;5*/
2526 (WORD)(DENYWRITE+READACCESS) /*;AN000;5*/
2527 ); /*;AN000;5*/
2528
2529 if (rc != NOERROR) /* Check for error */
2530 { /* Handle Share Errors */
2531 num_attempts++; /* Increment number of attempts */
2532 if (num_attempts == MAX_RETRY_OPEN_COUNT)/* Compare with max number of retries to perform */
2533 {
2534 file_sharing_error(); /*;AN000;9 There was a share error opening the file*/
2535 done = TRUE;
2536 }
2537 }
2538 else
2539 {
2540 source_opened = TRUE; /* Set flag indicating file is opened */
2541 done = TRUE; /* We are done in this loop */
2542
2543/*EAEAEAEAEA get_extended_attributes(handle_source); /*;AN000;3 Get extended attributes for this file */
2544
2545 put_new_fh(); /* Write the file header to the control file */
2546
2547/*EAEAEAEAE if (ext_attrib_flg) /*;AN000;3 If the file has extended attributes */
2548/*EAEAEAEAE write_extended_attributes(); /*;AN000;3then write them to BACKUP file */
2549 }
2550 }
2551 while (!done);
2552
2553 return;
2554} /* end open_source_file */
2555
2556/** ***********************************************/
2557/*
2558/* SUBROUTINE NAME: file_sharing_error
2559/*
2560/* FUNCTION:
2561/*
2562/* Handle the file sharing error that just occurred
2563/*
2564/***************************************************/
2565void file_sharing_error() /*;AN000;9*/
2566{ /*;AN000;9*/
2567 union REGS reg; /*;AN000;9*/
2568
2569 display_msg(CRLF);
2570 display_msg(CONFLICTMSG); /* Say "Last file not backed */
2571 return_code = RETCODE_SHARE_ERROR; /* Set errorlevel */
2572
2573 if (do_logfile) /*;AN000;9*/
2574 { /*;AN000;9*/
2575 reg.x.ax = LASTNOTBACKUP; /*;AN000;9*/
2576 reg.x.bx = handle_logfile; /*;AN000;9*/
2577#define MSG_LEN 33 /*;AN000;9*/
2578 reg.x.cx = (WORD)MSG_LEN; /*;AN000;9*/
2579 update_logfile(&reg,&reg); /* In source file _msgret.sal /*;AN000;9*/
2580 } /*;AN000;9*/
2581
2582 return; /*;AN000;9*/
2583} /*;AN000;9*/
2584
2585/** ***********************************************/
2586/*
2587/* SUBROUTINE NAME: far_ptr
2588/*
2589/* FUNCTION:
2590/*
2591/*
2592/*
2593/***************************************************/
2594char far *far_ptr(seg,off)
2595WORD seg;
2596WORD off;
2597{
2598 char far *p;
2599
2600 PUT_SEG(p,seg);
2601 PUT_OFF(p,off);
2602
2603 return(p);
2604}
2605
2606/** ***********************************************/
2607/*
2608/* SUBROUTINE NAME: do_copy
2609/*
2610/* FUNCTION:
2611/* Copy the source file to the BACKUP.xxx file
2612/* If there are extended attributes, write them
2613/* to the BACKUP.xxx file.
2614/***************************************************/
2615void do_copy()
2616{
2617 WORD bytes_read;
2618 WORD bytes_to_read = data_file_alloc_size; /* Read size = buffer size */
2619 char done = FALSE;
2620 char file_to_be_backup[20];
2621
2622 part_size = (DWORD)0;
2623 cumul_part_size = (DWORD)0;
2624
2625 if (source_opened)
2626 {
2627 do
2628 {
2629 bytes_read =
2630 handle_read
2631 (
2632 handle_source,
2633 bytes_to_read,
2634 far_ptr(selector,0)
2635 );
2636
2637 if (bytes_read == 0)
2638 done = TRUE;
2639 else
2640 write_to_target(bytes_read);
2641
2642 if (bytes_read < bytes_to_read)
2643 done = TRUE;
2644 }
2645 while (!done);
2646
2647 close_file(handle_source); /* Close the source file handle */
2648 source_opened = FALSE; /* Indicate that the source is not opened */
2649 sprintf(file_to_be_backup,"%c:%s",src_drive_letter,dta.file_name);
2650 reset_archive_bit(file_to_be_backup);/* Reset the archive bit on the source file */
2651 files_backed_up++; /* Increment number of files backed up */
2652 }
2653
2654 return;
2655} /* end do_copy */
2656
2657/** ***********************************************/
2658/*
2659/* SUBROUTINE NAME: write_extended_attributes
2660/*
2661/* FUNCTION:
2662/* There are extended attributes for the file
2663/* just backed up. Write the length of the
2664/* extended attributes to the BACKUP.xxx file,
2665/* then write the extended attributes the that file.
2666/*
2667/**************************************************/
2668/*#define WRITE_LENGTH 2
2669/*
2670/*void write_extended_attributes() /*;AN000;3*/
2671/*{ /*;AN000;3*/
2672/* WORD written; /*;AN000;3*/
2673/* /*******************************************/
2674/* /* Write the length of extended attributes */
2675/* /*******************************************/
2676/* written =
2677/* handle_write
2678/* (
2679/* handle_target,
2680/* WRITE_LENGTH,
2681/* (char far *)&ext_attrib_len
2682/* ); /*;AN000;3*/
2683/*
2684/* if (written == WRITE_LENGTH ) /*;AN000;3*/
2685/* data_file_tot_len += WRITE_LENGTH; /*;AN000;3*/
2686/*
2687/* /*********************************/
2688/* /* Write the extended attributes */
2689/* /*********************************/
2690/* written = handle_write(handle_target,ext_attrib_len,(char far *)ext_attrib_buff); /*;AN000;3*/
2691/* if (written == ext_attrib_len) /*;AN000;3*/
2692/* data_file_tot_len += (DWORD)written; /*;AN000;3*/
2693/*
2694/* ext_attrib_buff[0] = 0; /*;AN000;3*/
2695/* ext_attrib_buff[1] = 0; /*;AN000;3*/
2696/* return; /*;AN000;3*/
2697/*} /*;AN000;3*/
2698
2699/** ***********************************************/
2700/*
2701/* SUBROUTINE NAME: show_path
2702/*
2703/* FUNCTION:
2704/* Display to stdout the full path from root.
2705/* If we are logging, put full path there too.
2706/*
2707/***************************************************/
2708void show_path()
2709{
2710 char done_path[PATHLEN+20];
2711 char logfile_entry[PATHLEN+22];
2712 WORD written = 0;
2713
2714 if (src_drive_path[strlen(src_drive_path) - 1] != BACKSLASH)
2715 sprintf(done_path,"%s\\%s",src_drive_path,dta.file_name);
2716 else
2717 sprintf(done_path,"%s%s",src_drive_path,dta.file_name);
2718
2719 done_path[0] = 0xd;
2720 done_path[1] = 0xa;
2721 /* Display logfile path on screen */
2722 handle_write(STDOUT,strlen(done_path),(char far *)&done_path[0]);
2723
2724 if (do_logfile)
2725 {
2726 build_ext(diskettes_complete+1);
2727 sprintf(logfile_entry,"\15\12%s %s",ext,&done_path[2]);
2728 written = handle_write(handle_logfile,strlen(logfile_entry),(char far *)&logfile_entry[0]);
2729 if (written != strlen(logfile_entry) || (rc != NOERROR) )
2730 {
2731 display_msg(LOGFILE_TARGET_FULL);
2732 /*wait_for_keystroke();*/
2733 do_logfile = FALSE;
2734 }
2735 }
2736
2737 return;
2738} /* end show_path */
2739
2740/** ***********************************************/
2741/*
2742/* SUBROUTINE NAME: reset_archive_bit
2743/*
2744/* FUNCTION:
2745/* Sets the attribute of the source file to what
2746/* it was before, except the archive bit is reset.
2747/*
2748/***************************************************/
2749void reset_archive_bit(path_addr)
2750char *path_addr;
2751#define ARCHIVE_MASK 223
2752{
2753 WORD attrib;
2754
2755 attrib = get_attribute(path_addr);
2756 attrib = attrib & (WORD)ARCHIVE_MASK;
2757 set_attribute(path_addr,attrib);
2758
2759 return;
2760} /* end reset_archive_bit */
2761
2762/** ***********************************************/
2763/*
2764/* SUBROUTINE NAME: write_to_target
2765/*
2766/* FUNCTION:
2767/* Write a specified # of bytes to
2768/* target. Handle disk full conditions
2769/* and everything else.
2770/***************************************************/
2771void write_to_target(bytes_to_write)
2772WORD bytes_to_write;
2773{
2774 WORD bytes_written;
2775 WORD written;
2776
2777 bytes_written = handle_write(handle_target,bytes_to_write,far_ptr(selector,0));
2778 written = bytes_written;
2779
2780 if (bytes_written == bytes_to_write) /* If we wrote it all... */
2781 {
2782 part_size += (DWORD)written; /* Update size of this part. */
2783 cumul_part_size += (DWORD)written; /* Update size of this part. */
2784 data_file_tot_len += (DWORD)written; /* Update length of BACKUP.xxx file */
2785 }
2786 else
2787 {
2788 written = write_till_target_full(bytes_to_write,0); /* Fill up current target */
2789 bytes_written += written; /* Update # bytes written */
2790 part_size += (DWORD)written; /* Update size of this part. */
2791 cumul_part_size += (DWORD)written; /* Update size of this part. */
2792 data_file_tot_len += (DWORD)written; /* Update length of BACKUP.xxx file */
2793 close_out_current_target(); /* Update CONTROL.xxx file, close files */
2794 get_next_target(); /* Get next diskette from user *
2795 /* Write rest of buffer */
2796 written = handle_write(handle_target,bytes_to_write-bytes_written,far_ptr(selector,bytes_written));
2797 bytes_written += written; /* Update # bytes written */
2798 part_size = (DWORD)written; /* Update size of this part. */
2799 cumul_part_size += (DWORD)written; /* Update size of this part. */
2800 data_file_tot_len += (DWORD)written; /* Update length of BACKUP.xxx file */
2801 }
2802
2803 return;
2804} /* end write_to_target */
2805
2806/** ***********************************************/
2807/*
2808/* SUBROUTINE NAME: write_till_target_full
2809/*
2810/* FUNCTION:
2811/* Find out how much space is left on the disk,
2812/* and use it all up.
2813/*
2814/***************************************************/
2815WORD write_till_target_full(bytes_to_write,begin_offset)
2816WORD bytes_to_write;
2817WORD begin_offset;
2818{
2819 WORD written;
2820 WORD bfree;
2821
2822 bfree = (unsigned) disk_free_space();
2823 written = handle_write(handle_target,bfree,far_ptr(selector,begin_offset));
2824
2825 return(written);
2826} /* end write_till_target_full */
2827
2828/** ***********************************************/
2829/*
2830/* SUBROUTINE NAME: close_out_current_target
2831/*
2832/* FUNCTION:
2833/* Update CONTROL.xxx file, close it, close BACKUP.xxx,
2834/* make files READONLY, die if backing up to hardfile.
2835/*
2836/***************************************************/
2837void close_out_current_target()
2838{
2839 BYTE last = LAST_TARGET; /*;AN011;*/
2840
2841 disk_full = TRUE; /* Yes, the disk is full */
2842
2843 if (part_size != 0) /* If we wrote something...*/
2844 {
2845 file_spans_target = TRUE; /* Say "Hey, this file spans diskettes !" */
2846 files_backed_up++; /* Increment number files backed up on this target */
2847 }
2848
2849 if (files_backed_up > 0) /* If we backed up something */
2850 update_db_entries(files_backed_up); /* Increment Num_Entries field in directory block and NextDB field */
2851
2852 update_fh_entries(); /* Update the fields in file header */
2853
2854 if (!target_removable) /*;AN011;*/
2855 { /*;AN011;*/
2856 /* Update DH_LastDisk == LAST_DISK */
2857 lseek(handle_control,BOFILE,(DWORD)(DHLENGTH - 1)); /*;AN011;*/
2858 handle_write(handle_control,1,(char far *)&last); /*;AN011;*/
2859 } /*;AN011;*/
2860
2861 if (control_opened) /* If the control file is open */
2862 {
2863 close_file(handle_control); /* Close it */
2864 control_opened = FALSE; /* And say it isn't open */
2865 }
2866
2867 if (target_opened)
2868 close_file(handle_target); /* Close files */
2869
2870 target_opened = FALSE; /* Indicate that target is not opened */
2871
2872 if (file_spans_target) /* If file spans to another diskette */
2873 span_seq_num++; /* then increment the sequence number */
2874
2875 mark_files_read_only(); /* Set ReadOnly Attribute of BACKUP/CONTROL files */
2876
2877 if (logfile_on_target) /*;AN000;7 If logfile resides on target drive */
2878 { /*;AN000;7 */
2879 close_file(handle_logfile); /*;AN000;7 Then close it */
2880 logfile_opened = FALSE; /*;AN000;7 and set flag indicating that */
2881 } /*;AN000;7 */
2882
2883 if (!target_removable) /* If target is a hardfile */
2884 {
2885 display_msg(LASTNOTBACKUP); /* Say "Last file not backed up */
2886 error_exit(FDISKFULLMSG); /* then give error message and quit */
2887 }
2888
2889 diskettes_complete++; /* Increment number of diskettes complete */
2890 return;
2891} /* end close_out_current_target */
2892
2893/** ***********************************************/
2894/*
2895/* SUBROUTINE NAME: mark_as_not_last_target
2896/*
2897/* FUNCTION:
2898/* Sets the field in the disk header indicating
2899/* this is not the last target
2900/*
2901/***************************************************/
2902void mark_as_not_last_target()
2903{
2904 BYTE last = NOT_LAST_TARGET;
2905 DWORD db_offset;
2906 DWORD pointer;
2907
2908 /* Update DH_LastDisk = NOT_LAST_TARGET */
2909 lseek(handle_control,BOFILE,(DWORD)(DHLENGTH - 1));
2910 handle_write(handle_control,1,(char far *)&last);
2911
2912 /* Get first DB_NextDB */
2913 pointer = lseek(handle_control,BOFILE,(DWORD)(DHLENGTH+66));
2914 handle_read(handle_control,4,(char far *)&db_offset);
2915
2916 /* Get offset of last Dir Block */
2917 while (db_offset != (DWORD)LAST_DB)
2918 {
2919 pointer = lseek(handle_control,BOFILE,(DWORD)db_offset+66);
2920 handle_read(handle_control,4,(char far *)&db_offset);
2921 }
2922
2923 /* Change DB_NextDB field to point to EOF */
2924 lseek(handle_control,BOFILE,(DWORD)pointer);
2925 handle_write(handle_control,4,(char far *)&ctl_file_tot_len);
2926
2927 lseek(handle_control,EOFILE,(DWORD)0);
2928 return;
2929} /* end mark_as_not_last_target */
2930
2931/** ***********************************************/
2932/*
2933/* SUBROUTINE NAME: mark_as_last_target
2934/*
2935/* FUNCTION:
2936/* Sets the field in the disk header indicating
2937/* this is the last target. Also updates the
2938/* directory block to indicate the number of
2939/* files that are backed up.
2940/*
2941/***************************************************/
2942void mark_as_last_target()
2943{
2944 BYTE last = LAST_TARGET;
2945
2946 /* Update DH_LastDisk == LAST_DISK */
2947 lseek(handle_control,BOFILE,(DWORD)(DHLENGTH - 1));
2948 handle_write(handle_control,1,(char far *)&last);
2949
2950 /* Update DB_NumEntries == FILES_BACKED_UP */
2951 lseek(handle_control,BOFILE,(DWORD)(curr_db_begin_offset + 64));
2952 handle_write(handle_control,2,(char far *)&files_backed_up);
2953
2954 /* Update FH Entries */
2955 update_fh_entries();
2956
2957 return;
2958} /* end mark_as_last_target */
2959
2960/** ***********************************************/
2961/*
2962/* SUBROUTINE NAME: update_db_entries
2963/*
2964/* FUNCTION:
2965/*
2966/*
2967/*
2968/***************************************************/
2969void update_db_entries(entries)
2970WORD entries;
2971{
2972 lseek(handle_control,BOFILE,(DWORD)(curr_db_begin_offset+64));
2973
2974 /* Update DB_num_entries */
2975 handle_write(handle_control,2,(char far *)&entries);
2976
2977 if (!disk_full) /* Update DB_NextDB only if we are not at the end of a disk */
2978 handle_write(handle_control,4,(char far *)&ctl_file_tot_len);
2979
2980 lseek(handle_control,EOFILE,(DWORD)0);
2981
2982 return;
2983} /* end update_db_entries */
2984
2985/** ***********************************************/
2986/*
2987/* SUBROUTINE NAME: update_fh_entries
2988/*
2989/* FUNCTION:
2990/* Update following fields in Current File Header:
2991/*
2992/* FH_Flags: Indicate file successfully processed.
2993/* Indicate if this is last part or not.
2994/*
2995/* FH_PartSize: Indicate number of bytes written
2996/*
2997/***************************************************/
2998void update_fh_entries()
2999{
3000 BYTE flag;
3001
3002 if (!file_spans_target)
3003 flag = (BYTE)(LASTPART + SUCCESSFUL);
3004 else
3005 flag = (BYTE)(NOTLASTPART + SUCCESSFUL);
3006
3007/*EAEA if (ext_attrib_flg) /*;AN000;3 If there are extended attributes */
3008/*EAEA if (span_seq_num == 1) /*;AN000;3 If its the first part of file */
3009/*EAEA flag += EXT_ATTR; /*;AN000;3 set flag indicating extended attributes exist */
3010
3011 if (!target_removable) /*;AN011;*/
3012 if (disk_full) /*;AN011;*/
3013 { /*;AN011;*/
3014 flag = (BYTE)(LASTPART + NOTSUCCESSFUL); /*;AN011;*/
3015 } /*;AN011;*/
3016
3017 /* Go to FLAG field */
3018 lseek(handle_control,BOFILE,(DWORD)(curr_fh_begin_offset+13));
3019 /* Write the FLAG field to control file */
3020 handle_write(handle_control,1,(BYTE far *)&flag);
3021
3022 /* Go to PARTSIZE field */
3023 lseek(handle_control,CURRPOS,(DWORD)10);
3024 /* Write the PARTSIZE field to control file */
3025 handle_write(handle_control,4,(char far *)&part_size);
3026
3027 lseek(handle_control,EOFILE,(DWORD)0); /* Go back to end-of-file */
3028
3029 return;
3030} /* end update_fh_entries */
3031
3032/** ***********************************************/
3033/*
3034/* SUBROUTINE NAME: mark_files_read_only
3035/*
3036/* FUNCTION:
3037/* Set the READ-ONLY attribute on BACKUP.xxx and CONTROL.xx
3038/*
3039/*
3040/***************************************************/
3041void mark_files_read_only()
3042{
3043 char path[25];
3044
3045 build_ext(diskettes_complete + 1);
3046
3047 if (target_removable)
3048 {
3049 sprintf(path,"%c:\\CONTROL.%s",tgt_drive_letter,ext);
3050 set_attribute(path,(WORD)(ARCHIVE + READONLY));
3051 sprintf(path,"%c:\\BACKUP.%s",tgt_drive_letter,ext);
3052 set_attribute(path,(WORD)(ARCHIVE + READONLY));
3053 }
3054 else
3055 {
3056 sprintf(path,"%c:\\BACKUP\\CONTROL.%s",tgt_drive_letter,ext);
3057 set_attribute(path,(WORD)(ARCHIVE + READONLY));
3058 sprintf(path,"%c:\\BACKUP\\BACKUP.%s",tgt_drive_letter,ext);
3059 set_attribute(path,(WORD)(ARCHIVE + READONLY));
3060 }
3061
3062 if (target_removable)
3063 label_target_drive();
3064
3065 return;
3066}
3067
3068/** ***********************************************/
3069/*
3070/* SUBROUTINE NAME: put_disk_header
3071/*
3072/* FUNCTION:
3073/*
3074/*
3075/*
3076/***************************************************/
3077void put_disk_header()
3078{
3079 struct Disk_Header dh;
3080 int i;
3081
3082 dh.DH_Length = DHLENGTH; /* DH_Length */
3083
3084 strcpy(dh.DH_Identifier,"BACKUP "); /* DH_Identifier */
3085 dh.DH_Sequence = diskettes_complete + 1; /* DH_Sequence */
3086 for (i=0; i<=128; i++) dh.DH_reserved[i] = NUL; /* DH_Reserved */
3087 dh.DH_LastDisk = NOT_LAST_TARGET; /* DH_LastDisk - Assume NOT THE LAST TARGET */
3088
3089 write_to_control_file((char far *)&dh,DHLENGTH);
3090 put_new_db();
3091
3092 return;
3093} /* end put_disk_header */
3094
3095/** ***********************************************/
3096/*
3097/* SUBROUTINE NAME: put_new_db
3098/*
3099/* FUNCTION:
3100/*
3101/*
3102/*
3103/***************************************************/
3104void put_new_db()
3105{
3106 struct Dir_Block db;
3107 int i;
3108
3109 if (files_backed_up > 0)
3110 update_db_entries(files_backed_up); /* Update entries in previous db */
3111
3112 curr_db_begin_offset = ctl_file_tot_len; /* Save this for updating when done with current dir */
3113
3114 db.DB_Length = DBLENGTH; /* LENGTH, IN BYTES, OF DIR BLOCK */
3115 for (i=0; i<=63; i++)
3116 db.DB_Path[i]=NUL; /* ASCII PATH OF THIS DIRECTORY, DRIVE OMITTED*/
3117
3118 strcpy(db.DB_Path,&src_drive_path[3]);
3119 db.DB_NumEntries = 0; /* NUM OF FILENAMES CURRENTLY IN LIST */
3120 db.DB_NextDB = (DWORD)LAST_DB; /* OFFSET OF NEXT DIRECTORY BLOCK */
3121
3122 write_to_control_file((char far *)&db,DBLENGTH);
3123 new_directory = FALSE;
3124 files_backed_up = 0;
3125
3126 return;
3127} /* end put_new_db */
3128
3129/** ***********************************************/
3130/*
3131/* SUBROUTINE NAME: put_new_fh
3132/*
3133/* FUNCTION:
3134/* We are about to backup a file. Write the
3135/* file header to the control file.
3136/*
3137/***************************************************/
3138void put_new_fh()
3139{
3140 struct File_Header fh;
3141 int i; /*;AN000;3*/
3142
3143 if (do_add) /* If we are adding files */
3144 if (doing_first_target) /* and it is the last diskette from previous backup */
3145 if (files_backed_up == 0) /* and we have not backed up ANY yet */
3146 mark_as_not_last_target(); /* then mark this diskette as NOT the last */
3147
3148 if (new_directory) /* If this file resides in a different directory */
3149 put_new_db(); /* then create new directory block. */
3150
3151 curr_fh_begin_offset = ctl_file_tot_len;
3152
3153 fh.FH_Length = FHLENGTH; /* LENGTH, IN BYTES, OF FILE HEADER */
3154 for (i=0; i<=11; i++) fh.FH_FName[i]=NUL; /*;AN000;3*/
3155 strcpy(fh.FH_FName,dta.file_name); /* ASCII FILE NAME */
3156
3157 fh.FH_FLength = (DWORD)dta.file_size; /* Length of file */
3158 fh.FH_FSequence = span_seq_num; /* Sequence #, for files that span */
3159 fh.FH_BeginOffset=data_file_tot_len; /* OFFSET WHERE THIS SEGMENT BEGINS */
3160 fh.FH_Attribute = dta.attributes; /* FILE ATTRIBUTE FROM DIRECTORY */
3161 fh.FH_FTime = dta.write_time; /* TIME WHEN FILE WAS LAST MODIFIED */
3162 fh.FH_FDate = dta.write_date; /* DATE WHEN FILE WAS LAST MODIFIED */
3163/*EAEA fh.FH_EA_offset = 0; /*;AN000;3 Otherwise set to zero */
3164 fh.FH_Flags = LASTPART + SUCCESSFUL;
3165
3166/*EAEA if (ext_attrib_flg) /*;AN000;3 If there are extended attributes */
3167/*EAEA if (!file_spans_target) /*;AN000;3*/
3168/*EAEA if (span_seq_num == 1) /*;AN000;3 If its the first part of file */
3169/*EAEA { /*;AN000;3*/
3170/*EAEA fh.FH_Flags += EXT_ATTR; /*;AN000;3 set flag indicating extended attributes exist */
3171/*EAEA fh.FH_EA_offset = data_file_tot_len; /*;AN000;3 OFFSET WHERE EXTENDED ATTRIBUTES BEGIN */
3172/*EAEA fh.FH_BeginOffset += ext_attrib_len+2; /*;AN000;3*/
3173/*EAEA } /*;AN000;3*/
3174
3175 if (file_spans_target)
3176 {
3177 fh.FH_PartSize = (DWORD)(dta.file_size - cumul_part_size); /*LENGTH OF THIS PART OF FILE */
3178 file_spans_target = FALSE;
3179 }
3180 else
3181 fh.FH_PartSize = (DWORD)dta.file_size;/* LENGTH OF THIS PART OF FILE */
3182
3183 write_to_control_file((char far *)&fh,FHLENGTH);
3184
3185 return;
3186} /* end put_new_fh */
3187
3188/** ***********************************************/
3189/*
3190/* SUBROUTINE NAME: write_to_control_file
3191/*
3192/* FUNCTION:
3193/* Write to the control file and update
3194/* counters
3195/*
3196/***************************************************/
3197void write_to_control_file(address,len)
3198char far * address;
3199unsigned short len;
3200{
3201 WORD written;
3202
3203 written = handle_write(handle_control,len,address);
3204 ctl_file_tot_len = ctl_file_tot_len + (DWORD)written;
3205
3206 return;
3207} /* end write_to_control_file */
3208
3209/** ***********************************************/
3210/*
3211/* SUBROUTINE NAME: control_break_handler
3212/*
3213/* FUNCTION:
3214/* Set errorlevel and call routines to
3215/* close files and terminate.
3216/*
3217/***************************************************/
3218void control_break_handler()
3219{
3220 return_code = RETCODE_CTL_BREAK;
3221 clean_up_and_exit();
3222 return;
3223}
3224
3225
3226/************************************************************/
3227/*
3228/* SUBROUTINE NAME: display_it
3229/*
3230/* SUBROUTINE FUNCTION:
3231/* Display the requested message to the standard output device.
3232/*
3233/* INPUT:
3234/* 1) (WORD) Number of the message to be displayed.
3235/* 2) (WORD) Handle to be written to.
3236/* 3) (WORD) Substitution Count
3237/* 4) (WORD) Flag indicating user should "Strike any key..."
3238/* 5) (WORD) Num indicating message class
3239/*
3240/* OUTPUT:
3241/* The message corresponding to the requested msg number will
3242/* be written to the requested handle. If requested, substitution
3243/* text will be inserted as required. The Substitution List
3244/* is global and, if used, will be initialized by DISPLAY_MSG
3245/* before calling this routine.
3246/*
3247/* NORMAL EXIT:
3248/* Message will be successfully written to requested handle.
3249/*
3250/* ERROR EXIT:
3251/* None. Note that theoretically an error can be returned from
3252/* SYSDISPMSG, but there is nothing that the application can do.
3253/*
3254/* INTERNAL REFERENCES:
3255/* System Display Message service routine SYSDISPMSG
3256/*
3257/* EXTERNAL REFERENCES:
3258/* None
3259/*
3260/************************************************************/
3261void display_it(msg_number,handle,subst_count,waitflag,class)/*;AN000;6*/
3262
3263int msg_number; /*;AN000;6*/
3264WORD handle; /*;AN000;6*/
3265int subst_count; /*;AN000;6*/
3266BYTE waitflag; /*;AN000;6*/
3267BYTE class; /*;AN000;6 1=DOSerror, 2=PARSE,-1=Utility msg*/
3268{ /*;AN000;6*/
3269 inregs.x.ax = msg_number; /*;AN000;6*/
3270 inregs.x.bx = handle; /*;AN000;6*/
3271 inregs.x.cx = subst_count; /*;AN000;6*/
3272 inregs.h.dh = class; /*;AN000;6*/
3273 inregs.h.dl = (BYTE)waitflag; /*;AN000;6*/
3274 inregs.x.si = (WORD)(char far *)&sublist; /*;AN000;6*/
3275
3276 sysdispmsg(&inregs,&outregs); /*;AN000;6*/
3277
3278 return; /*;AN000;6*/
3279} /*;AN000;6*/
3280/** ***********************************************/
3281/*
3282/* SUBROUTINE NAME: display_msg
3283/*
3284/* FUNCTION:
3285/* Display the messages referenced by
3286/* variable MSG_NUM to either STDOUT or
3287/* STDERR. In some cases insert text into
3288/* the body of the message.
3289/*
3290/***************************************************/
3291
3292void display_msg(msg_num)
3293int msg_num;
3294{
3295
3296 switch (msg_num)
3297 {
3298 case NONEFNDMSG : { display_it (msg_num,STDOUT,0,NOWAIT,(BYTE)UTIL_MSG); break; } /*;AN000;6*/
3299
3300 case INSUFF_MEMORY : /*;AN000;6*/
3301 case ERR_EXEC_FORMAT : /*;AN000;d178*/
3302 case INV_PATH : /*;AN000;6*/
3303 case INV_DATE : /*;AN000;6*/
3304 case INV_TIME : /*;AN000;6*/
3305 case NO_SOURCE : /*;AN000;6*/
3306 case NO_TARGET : /*;AN000;6*/
3307 case SRC_AND_TGT_SAME : /*;AN000;6*/
3308 case BAD_DOS_VER : /*;AN000;6*/
3309 case INV_DRIVE : /*;AN000;6*/
3310 case CANT_OPEN_LOGFILE: /*;AN000;6*/
3311 case INVTARGET : /*;AN000;6*/
3312 case NOTLASTMSG : /*;AN000;6*/
3313 case CONFLICTMSG : /*;AN000;6*/
3314 case CRLF :
3315 case CANT_FIND_FORMAT :
3316 case LASTNOTBACKUP :{ /*;AN000;6*/
3317 display_it (msg_num,STDERR,0,NOWAIT,(BYTE)UTIL_MSG); /*;AN000;6*/
3318 break; /*;AN000;6*/
3319 } /*;AN000;6*/
3320
3321 case LOGFILE_TARGET_FULL:{
3322 display_it (msg_num,STDERR,0,NOWAIT,(BYTE)UTIL_MSG);/*;AN000;6*/
3323 display_it (PRESS_ANY_KEY,STDERR,0,WAIT,(BYTE)UTIL_MSG); /*;AN000;6*/
3324 break;
3325 }
3326
3327 case LOGGING : {
3328 sublist.value1 = (char far *)&logfile_path[0]; /*;AN000;6*/
3329 sublist.flags1 = LEFT_ALIGN + CHAR_FIELD_ASCIIZ; /*;AN000;6*/
3330 sublist.pad_char1 = ' '; /*;AN000;6*/
3331 sublist.max_width1 = (BYTE)strlen(logfile_path); /*;AN000;6*/
3332 sublist.min_width1 = sublist.max_width1; /*;AN000;6*/
3333 display_it (msg_num,STDOUT,1,NOWAIT,(BYTE)UTIL_MSG); /*;AN000;6*/
3334 break;
3335 }
3336
3337 case CANT_FORMAT_HARDFILE :
3338 { sublist.value1 = (char far *)&tgt_drive_letter; /*;AN000;6*/
3339 sublist.flags1 = LEFT_ALIGN + CHAR_FIELD_ASCIIZ; /*;AN000;6*/
3340 sublist.pad_char1 = ' '; /*;AN000;6*/
3341 sublist.max_width1 = 1; /*;AN000;6*/
3342 sublist.min_width1 = 1; /*;AN000;6*/
3343 display_it (msg_num,STDERR,1,NOWAIT,(BYTE)UTIL_MSG); /*;AN000;6*/
3344 break;
3345 }
3346
3347 case BUDISKMSG : /*;AN000;6*/
3348 case FDISKFULLMSG : /*;AN000;6*/
3349 { sublist.value1 = (char far *)&tgt_drive_letter; /*;AN000;6*/
3350 sublist.flags1 = LEFT_ALIGN + CHAR_FIELD_ASCIIZ; /*;AN000;6*/
3351 sublist.pad_char1 = ' '; /*;AN000;6*/
3352 sublist.max_width1 = 1; /*;AN000;6*/
3353 sublist.min_width1 = 1; /*;AN000;6*/
3354 display_it (msg_num,STDERR,1,NOWAIT,(BYTE)UTIL_MSG); /*;AN000;6*/
3355 break;
3356 }
3357
3358
3359 case ERASEMSG : /*;AN000;6*/
3360 case FERASEMSG : /*;AN000;6*/
3361 case LASTDISKMSG : /*;AN000;6*/
3362 { sublist.value1 = (char far *)&tgt_drive_letter; /*;AN000;6*/
3363 sublist.flags1 = LEFT_ALIGN + CHAR_FIELD_ASCIIZ; /*;AN000;6*/
3364 sublist.pad_char1 = ' '; /*;AN000;6*/
3365 sublist.max_width1 = 1; /*;AN000;6*/
3366 sublist.min_width1 = 1; /*;AN000;6*/
3367 display_it (msg_num,STDERR,1,NOWAIT,(BYTE)UTIL_MSG); /*;AN000;6*/
3368 display_it (PRESS_ANY_KEY,STDERR,0,WAIT,(BYTE)UTIL_MSG); /*;AN000;6*/
3369 break;
3370 }
3371
3372
3373 case INSERTSOURCE : {
3374 sublist.value1 = (char far *)&src_drive_letter; /*;AN000;6*/
3375 sublist.flags1 = LEFT_ALIGN + CHAR_FIELD_ASCIIZ; /*;AN000;6*/
3376 sublist.pad_char1 = ' '; /*;AN000;6*/
3377 sublist.max_width1 = 1; /*;AN000;6*/
3378 sublist.min_width1 = 1; /*;AN000;6*/
3379 display_it (msg_num,STDERR,1,NOWAIT,(BYTE)UTIL_MSG); /*;AN000;6*/
3380 display_it (PRESS_ANY_KEY,STDERR,0,WAIT,(BYTE)UTIL_MSG); /*;AN000;6*/
3381 break;
3382 }
3383
3384
3385 case SEQUENCEMSG : {
3386 build_ext(diskettes_complete+1);
3387 if (diskettes_complete+1 < 100)
3388 {
3389 sublist.value1 = (char far *)&ext[1]; /*;AN000;6*/
3390 sublist.max_width1 = 2; /*;AN000;6*/
3391 }
3392 else
3393 {
3394 sublist.value1 = (char far *)&ext[0]; /*;AN000;6*/
3395 sublist.max_width1 = 3; /*;AN000;6*/
3396 }
3397 sublist.flags1 = LEFT_ALIGN + CHAR_FIELD_ASCIIZ; /*;AN000;6*/
3398 sublist.pad_char1 = ' '; /*;AN000;6*/
3399 sublist.min_width1 = sublist.max_width1; /*;AN000;6*/
3400 display_it (msg_num,STDOUT,1,NOWAIT,(BYTE)UTIL_MSG); /*;AN000;6*/
3401 break;
3402 }
3403
3404
3405 case INSERTTARGET : {
3406 build_ext(diskettes_complete+1);
3407 if (diskettes_complete+1 < 100)
3408 {
3409 sublist.value1 = (char far *)&ext[1]; /*;AN000;6*/
3410 sublist.max_width1 = 2; /*;AN000;6*/
3411 }
3412 else
3413 {
3414 sublist.value1 = (char far *)&ext[0]; /*;AN000;6*/
3415 sublist.max_width1 = 3; /*;AN000;6*/
3416 }
3417
3418 sublist.flags1 = LEFT_ALIGN + CHAR_FIELD_ASCIIZ; /*;AN000;6*/
3419 sublist.pad_char1 = ' '; /*;AN000;6*/
3420 sublist.min_width1 = sublist.max_width1; /*;AN000;6*/
3421
3422 sublist.value2 = (char far *)&tgt_drive_letter; /*;AN000;6*/
3423 sublist.flags2 = LEFT_ALIGN + CHAR_FIELD_ASCIIZ; /*;AN000;6*/
3424 sublist.pad_char2 = ' '; /*;AN000;6*/
3425 sublist.max_width2 = 1; /*;AN000;6*/
3426 sublist.min_width2 = 1; /*;AN000;6*/
3427
3428 display_it (msg_num,STDERR,2,NOWAIT,(BYTE)UTIL_MSG); /*;AN000;6*/
3429 break;
3430 }
3431
3432 }
3433
3434 return;
3435} /* end display_msg */
3436
3437/** ***********************************************/
3438/*
3439/* SUBROUTINE NAME: error_exit
3440/*
3441/* FUNCTION:
3442/* Display appropriate error message, set
3443/* the return code, and call clean_up_and_exit.
3444/*
3445/***************************************************/
3446void error_exit(error_type)
3447int error_type;
3448{
3449 display_msg(error_type);
3450 return_code = RETCODE_ERROR;
3451 clean_up_and_exit();
3452
3453 return;
3454} /* end error_exit */
3455
3456/** ***********************************************/
3457/*
3458/* SUBROUTINE NAME: restore_default_directories
3459/*
3460/* FUNCTION:
3461/* Restore the original current directory on
3462/* the source drive.
3463/*
3464/***************************************************/
3465void restore_default_directories()
3466{
3467 char path[PATHLEN+20];
3468
3469 sprintf(path,"%c:%s",src_drive_letter,src_def_dir);
3470 chdir(path);
3471
3472 return;
3473} /* end restore_default_directories */
3474
3475/**************************************************/
3476/*
3477/* SUBROUTINE NAME: clean_up_and_exit
3478/*
3479/* FUNCTION:
3480/* Update BACKUP and CONTROL files.
3481/* Close open files.
3482/* Mark BACKUP, CONTROL file read only
3483/* Restore default drive and directories
3484/* Deallocate buffers
3485/***************************************************/
3486void clean_up_and_exit()
3487{
3488 char name[15]; /*;AN000;p2652*/
3489
3490 if (source_opened)
3491 {
3492 close_file(handle_source);
3493 source_opened = FALSE; /* Indicate that source is not opened */
3494 }
3495
3496 if (target_opened)
3497 {
3498 close_file(handle_target);
3499 target_opened = FALSE; /* Indicate that target is not opened */
3500 }
3501
3502 if (control_opened)
3503 {
3504 mark_as_last_target();
3505 close_file(handle_control);
3506 control_opened = FALSE; /*;AN005;*/
3507 mark_files_read_only();
3508 }
3509
3510 if (logfile_opened)
3511 {
3512 close_file(handle_logfile);
3513 logfile_opened = FALSE;
3514 }
3515
3516 if (files_backed_up == 0 && !checking_target) /*;AN000;p2652*//*;AN007;*/
3517 { /*;AN005;*/
3518 if (!do_add) /*;AN000;p2652*/
3519 { /*;AN000;p2652*/
3520 if (target_removable && got_first_target) /*;AN000;p2652*/
3521 { /*;AN005;*/
3522 build_ext(diskettes_complete + 1); /*;AN005;*/
3523 sprintf(name,"%c:\\BACKUP.%s",tgt_drive_letter,ext); /*;AN005;*/
3524 set_attribute(name,(WORD)0); /*;AN005;*/
3525 delete(name); /*;AN005;*/
3526 /*;AN005;*/
3527 sprintf(name,"%c:\\CONTROL.%s",tgt_drive_letter,ext); /*;AN005;*/
3528 set_attribute(name,(WORD)0); /*;AN005;*/
3529 delete(name); /*;AN005;*/
3530 } /*;AN005;*/
3531
3532 if (!target_removable)
3533 delete_files(BACKUPDIR); /*;AN000;p2652*/
3534
3535 } /*;AN000;p2652*/
3536
3537 if (!target_removable) /*;AN005;*/
3538 { /*;AN005;*/
3539 sprintf(name,"%c:\\BACKUP",tgt_drive_letter); /*;AN000;p2652*/
3540 rmdir(name); /*;AN000;p2652*/
3541 } /*;AN005;*/
3542 } /*;AN005;*/
3543
3544 if (def_drive_set)
3545 {
3546 set_default_drive(def_drive);
3547 }
3548
3549 if (curr_dir_set)
3550 {
3551 restore_default_directories();
3552 }
3553
3554 if (buffers_allocated)
3555 free_seg(selector);
3556
3557 terminate();
3558
3559 return;
3560} /* end clean_up_and_exit */
3561
3562
3563
3564/** ***********************************************/
3565/* DOS FAMILY API CALLS */
3566/**************************************************/
3567
3568WORD handle_open(path_addr,mode)
3569char *path_addr;
3570WORD mode;
3571{
3572 WORD handle;
3573 WORD action;
3574
3575#if defined(DEBUG)
3576 printf("\nDOSOPEN FILE=%s, MODE=%04Xh...",path_addr,mode);
3577#endif
3578
3579 rc =
3580 DOSOPEN
3581 (
3582 (char far *)path_addr, /* Path address */
3583 (unsigned far *)&handle, /* Return area for handle */
3584 (unsigned far *)&action, /* Return area for action performed */
3585 (DWORD)0, /* File Size */
3586 (WORD)0, /* File attribute */
3587 (WORD)1, /* Flag: Only open file if it exists */
3588 (WORD)mode, /* Mode */
3589 (DWORD)0 /* Reserved */
3590 );
3591
3592#if defined(DEBUG)
3593 if (rc == NOERROR)
3594 printf("SUCCESSFUL, HANDLE=%04Xh",handle);
3595 else
3596 printf("ERROR, RC=%04Xh",rc);
3597#endif
3598
3599 return(handle);
3600} /* end handle_open */
3601
3602
3603/** ***********************************************/
3604DWORD lseek(handle,method,distance)
3605WORD handle;
3606BYTE method; /* 0=BOF+Offset, 1=CurrPos+Offset, 2=EOF+Offset */
3607DWORD distance;
3608{
3609 DWORD pointer;
3610
3611#if defined(DEBUG)
3612 printf("\nDOSCHGFILEPTR HANDLE=%04Xh, METHOD=%02Xh, DIST=%08lXh...",handle,method,distance);
3613#endif
3614
3615 rc =
3616 DOSCHGFILEPTR
3617 (
3618 handle,
3619 distance,
3620 method,
3621 (DWORD far *)&pointer
3622 );
3623
3624#if defined(DEBUG)
3625 if (rc == NOERROR)
3626 printf("SUCCESSFUL, POINTER=%08lXh",pointer);
3627 else
3628 printf("ERROR, RC=%04Xh",rc);
3629#endif
3630
3631 return((DWORD)pointer);
3632} /* end lseek */
3633
3634/** ***********************************************/
3635WORD handle_read(handle,length,address)
3636WORD handle;
3637WORD length;
3638char far *address;
3639{
3640 WORD num_read;
3641
3642#if defined(DEBUG)
3643 printf("\nDOSREAD HANDLE=%04Xh, BYTES=%04Xh, ADDR(off:seg)=%04X:%04X...",handle,length,address);
3644#endif
3645
3646 rc =
3647 DOSREAD
3648 (
3649 handle,
3650 address,
3651 length,
3652 (unsigned far *)&num_read
3653 );
3654
3655#if defined(DEBUG)
3656 if (rc == NOERROR)
3657 printf("READ %04Xh",num_read);
3658 else
3659 printf("ERROR, RC=%04Xh",rc);
3660#endif
3661
3662 return(num_read);
3663} /* end handle_read */
3664/** ***********************************************/
3665WORD handle_write(handle,length,address)
3666WORD handle;
3667WORD length;
3668char far *address;
3669{
3670 WORD written;
3671
3672#if defined(DEBUG)
3673 printf("\nDOSWRITE HANDLE=%04Xh, BYTES=%04Xh, ADDR(off:seg)=%04X:%04X...",handle,length,address);
3674#endif
3675
3676 if (length != 0)
3677 rc =
3678 DOSWRITE
3679 (
3680 handle,
3681 address,
3682 length,
3683 (unsigned far *)&written
3684 );
3685 else
3686 {
3687 written = 0;
3688 rc = NOERROR;
3689 }
3690
3691#if defined(DEBUG)
3692 if (rc == NOERROR)
3693 printf("WROTE %04Xh",written);
3694 else
3695 printf("ERROR, RC=%04Xh",rc);
3696#endif
3697
3698 return(written);
3699} /* end handle_write */
3700
3701/** ***********************************************/
3702void close_file(handle) /* Close the file handle specified. */
3703WORD handle;
3704{
3705#if defined(DEBUG)
3706 printf("\nDOSCLOSE HANDLE=%04Xh...",handle);
3707#endif
3708
3709 rc = DOSCLOSE(handle);
3710
3711#if defined(DEBUG)
3712 if (rc == NOERROR)
3713 printf("SUCCESSFUL");
3714 else
3715 printf("ERROR, RC=%04Xh",rc);
3716#endif
3717
3718 return;
3719} /* end close_file */
3720
3721/** ***********************************************/
3722WORD get_attribute(path_addr)
3723char *path_addr;
3724{
3725 WORD attribute;
3726
3727#if defined(DEBUG)
3728 printf("\nDOSQFILEMODE %s...",path_addr);
3729#endif
3730
3731 rc = DOSQFILEMODE((char far *)path_addr,(unsigned far *)&attribute,(DWORD)0);
3732
3733#if defined(DEBUG)
3734 if (rc == NOERROR)
3735 printf("SUCCESSFUL, ATTRIB=%04Xh",attribute);
3736 else
3737 printf("ERROR, RC=%04Xh",rc);
3738#endif
3739
3740 return(attribute);
3741}
3742
3743/** ***********************************************/
3744void set_attribute(path_addr,attribute)
3745char *path_addr;
3746WORD attribute;
3747{
3748#if defined(DEBUG)
3749 printf("\nDOSSETFILEMODE FILE=%s, ATTRIB=%04Xh...",path_addr,attribute);
3750#endif
3751
3752 rc = DOSSETFILEMODE((char far *)path_addr,attribute,(DWORD)0);
3753
3754#if defined(DEBUG)
3755 if (rc == NOERROR)
3756 printf("SUCCESSFUL");
3757 else
3758 printf("ERROR, RC=%04Xh",rc);
3759#endif
3760
3761 return;
3762}
3763/** ***********************************************/
3764WORD get_current_drive()
3765{
3766 WORD drive; /* 1=a */
3767 DWORD drivemap;
3768
3769#if defined(DEBUG)
3770 printf("\nDOSQCURDISK DRIVE (1=A)...");
3771#endif
3772
3773 rc = DOSQCURDISK
3774 (
3775 (unsigned far *)&drive,
3776 (DWORD far *)&drivemap
3777 );
3778
3779#if defined(DEBUG)
3780 if (rc == NOERROR)
3781 printf("SUCCESSFUL, DRIVE=%04Xh",drive);
3782 else
3783 printf("ERROR, RC=%04Xh",rc);
3784#endif
3785
3786 return(drive);
3787}
3788
3789/** ***********************************************/
3790void set_default_drive(drive) /* Change the current drive (1=A,2=B) */
3791WORD drive;
3792{
3793#if defined(DEBUG)
3794 printf("\nDOSSELECTDISK (1=A) TO %04Xh...",drive);
3795#endif
3796
3797 rc = DOSSELECTDISK(drive);
3798
3799 if (rc == NOERROR)
3800 def_drive_set = TRUE;
3801
3802#if defined(DEBUG)
3803 if (rc == NOERROR)
3804 printf("SUCCESSFUL");
3805 else
3806 printf("ERROR, RC=%04Xh",rc);
3807#endif
3808
3809 return;
3810} /* end set_default_drive */
3811
3812/** ***********************************************/
3813void get_current_dir(drive,path_addr)
3814WORD drive; /* 0=default, 1=a, . . . */
3815char *path_addr; /* Pointer to path buffer */
3816{
3817 WORD path_buff_len = PATHLEN+20;
3818
3819#if defined(DEBUG)
3820 printf("\nDOSQCURDIR DRIVE (0=def) %04Xh...",drive);
3821#endif
3822
3823 rc =
3824 DOSQCURDIR
3825 (
3826 drive,
3827 (char far *)path_addr,
3828 (unsigned far *)&path_buff_len
3829 );
3830
3831#if defined(DEBUG)
3832 if (rc == NOERROR)
3833 printf("SUCCESSFUL, CURRENT DIR IS = \\%s",path_addr);
3834 else
3835 printf("ERROR, RC=%04Xh",rc);
3836#endif
3837
3838 return;
3839} /* end get_current_dir */
3840
3841/** ***********************************************/
3842void find_first(path_addr,dirhandle_addr,dta_address,attrib)
3843char *path_addr;
3844WORD *dirhandle_addr;
3845struct FileFindBuf *dta_address;
3846WORD attrib;
3847{
3848 WORD numentries = 1;
3849 WORD temprc;
3850
3851 *dirhandle_addr = 0xffff;
3852
3853
3854#if defined(DEBUG)
3855 printf("\nDOSFINDFIRST DIRH=%04Xh, FILE=%s...",*dirhandle_addr,path_addr);
3856#endif
3857
3858 rc =
3859 DOSFINDFIRST
3860 (
3861 (char far *)path_addr,
3862 (unsigned far *)dirhandle_addr,
3863 attrib,
3864 (struct FileFindBuf far *)dta_address,
3865 (WORD)(sizeof(struct FileFindBuf)),
3866 (unsigned far *)&numentries,
3867 (DWORD)0
3868 );
3869
3870#if defined(DEBUG)
3871 if (rc == NOERROR)
3872 printf("SUCCESSFUL, NAME=%s, ATTR=%04Xh, SIZE=%08lXh, DIRH=%04Xh",(*dta_address).file_name,(*dta_address).attributes,(*dta_address).file_size,*dirhandle_addr);
3873 else
3874 printf("ERROR, DIRH=%04Xh, RC=%04Xh",*dirhandle_addr,rc);
3875#endif
3876
3877 if (rc != NOERROR)
3878 {
3879 temprc=rc;
3880 findclose(*dirhandle_addr);
3881 rc = temprc;
3882 }
3883
3884 return;
3885} /* end find_first */
3886
3887/** ***********************************************/
3888void find_next(dirhandle,dta_address)
3889WORD dirhandle;
3890struct FileFindBuf *dta_address;
3891{
3892 WORD temprc;
3893 WORD numentries = 1;
3894
3895#if defined(DEBUG)
3896 printf("\nDOSFINDNEXT, DIRH=%04Xh...",dirhandle);
3897#endif
3898
3899 rc =
3900 DOSFINDNEXT
3901 (
3902 dirhandle,
3903 (struct FileFindBuf far *)dta_address,
3904 (WORD)(sizeof(struct FileFindBuf)+12),
3905 (unsigned far *)&numentries
3906 );
3907
3908#if defined(DEBUG)
3909 if (rc == NOERROR)
3910 printf("SUCCESSFUL, NAME=%s, DIRH=%04Xh",(*dta_address).file_name,dirhandle);
3911 else
3912 printf("ERROR, RC=%04Xh",rc);
3913#endif
3914
3915 if (rc != NOERROR)
3916 {
3917 temprc=rc;
3918 findclose(dirhandle);
3919 rc = temprc;
3920 }
3921
3922 return;
3923} /* end find_next */
3924/** ***********************************************/
3925void findclose(dirhandle)
3926WORD dirhandle;
3927{
3928
3929#if defined(DEBUG)
3930 printf("\nDOSFINDCLOSE DIRH=%04Xh...",dirhandle);
3931#endif
3932
3933 rc = DOSFINDCLOSE(dirhandle);
3934
3935 dirhandles_open = FALSE;
3936
3937#if defined(DEBUG)
3938 if (rc == NOERROR)
3939 printf("SUCCESSFUL");
3940 else
3941 printf("ERROR, RC=%04Xh",rc);
3942#endif
3943
3944 return;
3945} /* end findclose */
3946/** ***********************************************/
3947void delete(path_addr)
3948char *path_addr;
3949{
3950#if defined(DEBUG)
3951 printf("\nDOSDELETE FILE %s...",path_addr);
3952#endif
3953
3954 rc = DOSDELETE((char far *)path_addr,(DWORD)0);
3955
3956#if defined(DEBUG)
3957 if (rc == NOERROR)
3958 printf("SUCCESSFUL");
3959 else
3960 printf("ERROR, RC=%04Xh",rc);
3961#endif
3962
3963 return;
3964} /* end delete */
3965/** ***********************************************/
3966long disk_free_space()
3967{
3968 struct FSAllocate fsa;
3969
3970#if defined(DEBUG)
3971 printf("\nDOSQFSINFO (0=def) DRIVE=%04Xh...",tgt_drive_letter-'A'+1);
3972#endif
3973
3974 rc =
3975 DOSQFSINFO
3976 (
3977 (WORD)tgt_drive_letter - 'A' + 1, /* Drive 0=def, 1=a... */
3978 (WORD)1, /* Level */
3979 (char far *)&fsa, /* Return info */
3980 (WORD)(sizeof(struct FSAllocate)) /* Size of return info buffer */
3981 );
3982
3983#if defined(DEBUG)
3984 if (rc == NOERROR)
3985 printf("SUCCESSFUL, FREESPACE=%08lXh",fsa.sec_per_unit * fsa.avail_units * fsa.bytes_sec);
3986 else
3987 printf("ERROR, RC=%04Xh",rc);
3988#endif
3989
3990 return((DWORD)(fsa.sec_per_unit * fsa.avail_units * fsa.bytes_sec));
3991}
3992/** ***********************************************/
3993void replace_volume_label(label_addr)
3994char *label_addr;
3995{
3996#if defined(DEBUG)
3997 printf("\nDOSSETFSINFO (0=def) DRIVE=%04Xh, LEN=%04Xh...",tgt_drive_letter-'A'+1,label_addr[0]);
3998#endif
3999
4000 rc = DOSSETFSINFO
4001 (
4002 (WORD)tgt_drive_letter-'A'+1, /* Drive 0=def, 1=a... */
4003 (WORD)2, /* Level */
4004 (char far *)label_addr, /* Buffer */
4005 (WORD)LABELLEN+1 /* Buffer size */
4006 );
4007
4008#if defined(DEBUG)
4009 if (rc == NOERROR)
4010 printf("SUCCESSFUL");
4011 else
4012 printf("ERROR, RC=%04Xh",rc);
4013#endif
4014
4015 return;
4016} /* end replace_volume_label */
4017
4018/** ***********************************************/
4019#define TERMINATE 0x4C00
4020void terminate() /* Terminate process, return errorlevel to DOS */
4021{
4022
4023 if (append_indicator == DOS_APPEND) /*;AN000;2 If append /x was reset*/
4024 { /*;AN000;2*/
4025#if defined(DEBUG)
4026printf("\nINT2Fh,(SET APPEND) AX=%04Xh TO %04Xh...",SET_STATE,original_append_func);
4027#endif
4028 inregs.x.ax = SET_STATE; /*;AN000;2*/
4029 inregs.x.bx = original_append_func; /*;AN000;2*/
4030 int86(0x2f,&inregs,&outregs); /*;AN000;2*/
4031 } /*;AN000;2*/
4032
4033 exit(return_code); /*;AN000;p972*/
4034
4035 return;
4036} /* end terminate */
4037/** ***********************************************/
4038WORD ioctl(devhandle)
4039WORD devhandle;
4040{
4041#define ISDEVREMOVABL 0x20
4042#define CATEGORY 8 /*1=serial,3=display,5=printer,8=disk*/
4043
4044 BYTE data_area;
4045
4046#if defined(DEBUG)
4047 printf("\nDOSDEVIOCTL HANDLE=%04Xh...",devhandle);
4048#endif
4049
4050 rc =
4051 DOSDEVIOCTL
4052 (
4053 (char far *)&data_area, /* Data Area */
4054 (char far *)&data_area, /* Parameter list */
4055 (WORD)ISDEVREMOVABL, /* Device Function = 20 hex */
4056 (WORD)CATEGORY, /* Device Category = 8 hex */
4057 (WORD)devhandle /* Device Handle */
4058 );
4059
4060#if defined(DEBUG)
4061 if (rc == NOERROR)
4062 printf("SUCCESSFUL, DATA_AREA(0=REMOVABLE) SET TO %02Xh",data_area);
4063 else
4064 printf("ERROR, RC=%04Xh",rc);
4065#endif
4066
4067 return(data_area);
4068} /* end IOCTL */
4069
4070/** ***********************************************/
4071void alloc_seg()
4072{
4073#if defined(DEBUG)
4074 printf("\nDOSALLOCSEG SIZE=%04Xh...",data_file_alloc_size);
4075#endif
4076
4077 rc =
4078 DOSALLOCSEG
4079 (
4080 (WORD)data_file_alloc_size, /* Bytes to allocate */
4081 (unsigned far *)&selector, /* Address of selector */
4082 (WORD)0 /* Share indicator, sez DON'T SHARE */
4083 );
4084
4085#if defined(DEBUG)
4086 if (rc == NOERROR)
4087 printf("SUCCESSFUL, SELECTOR=%04Xh, SIZE=%04Xh",selector,data_file_alloc_size);
4088 else
4089 printf("ERROR, RC=%04Xh",rc);
4090#endif
4091
4092 return;
4093}
4094
4095/** ***********************************************/
4096void free_seg(selector)
4097unsigned selector;
4098{
4099#if defined(DEBUG)
4100 printf("\nDOSFREESEG (%04Xh)...",selector);
4101#endif
4102
4103 rc = DOSFREESEG(selector); /* Address of selector */
4104
4105#if defined(DEBUG)
4106 if (rc == NOERROR)
4107 printf("SUCCESSFUL");
4108 else
4109 printf("ERROR, RC=%04Xh",rc);
4110#endif
4111
4112 return;
4113}
4114
4115/** ***********************************************/
4116void setsignal(action,signum)
4117WORD action;
4118WORD signum;
4119{
4120 DWORD old_sig_handler;
4121 WORD old_sig_action;
4122
4123#if defined(DEBUG)
4124 printf("\nDOSSETSIGHANDLER ACTION=%04Xh,SIGNUM=%04Xh...",action,signum);
4125#endif
4126
4127 rc =
4128 DOSSETSIGHANDLER
4129 (
4130 (void far *)control_break_handler, /* Signal handler address */
4131 (DWORD far *)&old_sig_handler, /* Address of previous handler */
4132 (unsigned far *)&old_sig_action, /* Address of previous action */
4133 action, /* Indicate request type (2=hook) */
4134 signum /* Signal number */
4135 );
4136
4137#if defined(DEBUG)
4138 if (rc == NOERROR)
4139 printf("SUCCESSFUL");
4140 else
4141 printf("ERROR, RC=%04Xh",rc);
4142#endif
4143
4144 return;
4145} /* end setsignal */
4146
4147/** ***********************************************/
4148void do_dos_error(flag)
4149WORD flag;
4150{
4151#if defined(DEBUG)
4152 printf("\nDOSERROR, FLAG=%04Xh...",flag);
4153#endif
4154
4155 rc = DOSERROR(flag);
4156
4157#if defined(DEBUG)
4158 if (rc == NOERROR)
4159 printf("SUCCESSFUL");
4160 else
4161 printf("ERROR, RC=%04Xh",rc);
4162#endif
4163
4164 return;
4165}
4166/** ***********************************************/
4167void get_country_info()
4168{
4169#define USACOUNTRY 1
4170#define DEFAULT_COUNTRY 0
4171#define DEFAULT_CODEPAGE 0
4172
4173 struct ctry_info_blk buff;
4174 struct countrycode ctrystuff; /* Added for CPDOS 1.1 */
4175 WORD data_len;
4176
4177 ctrystuff.country = (WORD)DEFAULT_COUNTRY;
4178 ctrystuff.codepage= (WORD)DEFAULT_CODEPAGE;
4179
4180#if defined(DEBUG)
4181 printf("\nDOSGETCTRYINFO COUNTRY=%04Xh...",ctrystuff.country);
4182#endif
4183
4184 rc =
4185 DOSGETCTRYINFO
4186 (
4187 (unsigned)sizeof(struct ctry_info_blk), /* Length of return area */
4188 (struct countrycode far *)&ctrystuff, /* Country Code */
4189 (char far *)&buff, /* Return area */
4190 (unsigned far *)&data_len /* Len of returned area */
4191 );
4192
4193#if defined(DEBUG)
4194 if (rc == NOERROR)
4195 printf("SUCCESSFUL");
4196 else
4197 printf("ERROR, RC=%04Xh",rc);
4198#endif
4199
4200 if (rc == NOERROR)
4201 {
4202 ctry_date_fmt = buff.date_format;
4203 ctry_time_fmt = buff.time_format;
4204 ctry_date_sep = buff.date_separator;
4205 ctry_time_sep = buff.time_separator;
4206#if defined(DEBUG)
4207 printf("\nDATE SEPERATOR=%c",ctry_date_sep);
4208 printf("\nTIME SEPERATOR=%c",ctry_time_sep);
4209 printf("\nDATE FORMAT=%u",ctry_date_fmt);
4210 printf("\nTIME FORMAT=%u",ctry_time_fmt);
4211#endif
4212 }
4213
4214
4215 return;
4216} /* end get_country_info */
4217
4218/** ***********************************************/
4219void datetime() /* Put date and time in logfile */
4220{
4221 struct DateTime buff;
4222 char date[12];
4223 char time[12];
4224 char datetimestring[25];
4225 WORD written = 0;
4226
4227#if defined(DEBUG)
4228 printf("\nDOSGETDATETIME...");
4229#endif
4230
4231 rc = DOSGETDATETIME((struct DateTime far *)&buff);
4232
4233#if defined(DEBUG)
4234 if (rc == NOERROR)
4235 printf("SUCCESSFUL");
4236 else
4237 printf("ERROR, RC=%04Xh",rc);
4238#endif
4239
4240 /* Build time string */
4241 sprintf(time,"%u%c%02u%c%02u",buff.hour,ctry_time_sep,buff.minutes,ctry_time_sep,buff.seconds);
4242
4243 /* Build date string */
4244 switch (ctry_date_fmt)
4245 {
4246 case USA:
4247 sprintf(date,"%u%c%02u%c%04u",buff.month,ctry_date_sep,buff.day,ctry_date_sep,buff.year);
4248 break;
4249
4250 case EUR:
4251 sprintf(date,"%u%c%02u%c%04u",buff.day,ctry_date_sep,buff.month,ctry_date_sep,buff.year);
4252 break;
4253
4254 case JAP:
4255 sprintf(date,"%04u%c%02u%c%02u",buff.year,ctry_date_sep,buff.month,ctry_date_sep,buff.day);
4256 break;
4257
4258 default:
4259 break;
4260 }
4261
4262 datetimestring[0] = 0x0d;
4263 datetimestring[1] = 0x0a;
4264 sprintf(datetimestring+2,"%s %s",date,time);
4265
4266 written = handle_write(handle_logfile,strlen(datetimestring),(char far *)&datetimestring[0]);
4267 if (written != strlen(datetimestring) || (rc != NOERROR) )
4268 {
4269 display_msg(LOGFILE_TARGET_FULL);
4270 /* wait_for_keystroke(); */
4271 do_logfile = FALSE;
4272 }
4273
4274 return;
4275} /* end datetime */
4276
4277
4278
4279
4280
4281
4282
4283
4284
4285
4286
4287
4288/** ***********************************************/
4289/*void get_extended_attributes(handle) /*;AN000;3*/
4290/*WORD handle; /*;AN000;3*/
4291/*{ /*;AN000;3*/
4292/*#if defined(DEBUG)
4293/* printf("\nGET EXTENDED ATTRIBUTE LENGTH...");
4294/*#endif
4295/* ext_attrib_flg = TRUE; /*Assume ext attrib exist*/ /*;AN000;3*/
4296/*
4297/* /* GET EXTENDED ATTRIBUTE LENGTH */
4298/* inregs.x.ax = 0x5702; /*;AN000;3*/
4299/* inregs.x.bx = handle; /*;AN000;3*/
4300/* inregs.x.cx = 0; /*;AN000;3*/
4301/* inregs.x.si = 0xffff; /*;AN000;3*/
4302/* intdos(&inregs,&outregs); /*;AN000;3*/
4303/*
4304/*#if defined(DEBUG)
4305/* if (outregs.x.cflag & CARRY)
4306/* printf("ERROR, RC=%04Xh",outregs.x.ax);
4307/* else
4308/* printf("SUCCESSFUL, LEN=%04Xh",outregs.x.cx);
4309/*#endif
4310/*
4311/* if (!(outregs.x.cflag & CARRY)) /*;AN000;3*/
4312/* ext_attrib_len = outregs.x.cx; /*;AN000;3*/
4313/* else /*;AN000;3*/
4314/* ext_attrib_flg = FALSE; /*;AN000;3 Set flag indicating no extended attributes*/
4315/*
4316/*
4317/*#if defined(DEBUG)
4318/* printf("\nGET EXTENDED ATTRIBUTES...");
4319/*#endif
4320/*
4321/* /* GET EXTENDED ATTRIBUTES */
4322/* if (ext_attrib_flg)
4323/* { /*;AN000;3*/
4324/* inregs.x.ax = 0x5702; /*;AN000;3*/
4325/* inregs.x.bx = handle; /*;AN000;3*/
4326/* inregs.x.cx = outregs.x.cx; /*;AN000;3*/
4327/* inregs.x.di = (unsigned)&ext_attrib_buff[0]; /*;AN000;3*/
4328/* inregs.x.si = 0xffff; /*;AN000;3*/
4329/* intdos(&inregs,&outregs); /*;AN000;3*/
4330/*
4331/* if (outregs.x.cflag & CARRY) /*;AN000;3*/
4332/* ext_attrib_flg = FALSE; /*;AN000;3*/
4333/*
4334/*#if defined(DEBUG)
4335/* if (outregs.x.cflag & CARRY)
4336/* printf("ERROR, RC=%04Xh",outregs.x.ax);
4337/* else
4338/* printf("SUCCESSFUL");
4339/*#endif
4340/* }
4341/*
4342/* return; /*;AN000;3*/
4343/*} /* end get_extended_attributes */ /*;AN000;3*/
4344/** ************************************************/
4345#define EXTENDEDOPEN 0x6c00 /*;AN000;3*/
4346
4347WORD extended_open(flag,attr,path_addr,mode) /*;AN000;3*/
4348WORD flag; /*;AN000;3*/
4349WORD attr; /*;AN000;3*/
4350char far *path_addr; /*;AN000;3*/
4351WORD mode; /*;AN000;3*/
4352{ /*;AN000;3*/
4353 union REGS inreg,outreg; /*;AN000;3*/
4354
4355 ea_parmlist.ext_attr_addr = (DWORD)(char far *)&ext_attrib_buff[0];/*;AN000;3*/
4356 ea_parmlist.num_additional = 0; /*;AN000;3*/
4357
4358#if defined(DEBUG)
4359 if (flag == CREATE_IT) printf("\nEXTENDED OPEN - CREATE, FILE %s...",path_addr);
4360 else printf("\nEXTENDED OPEN - OPEN, FILE %s...",path_addr);
4361#endif
4362
4363 rc = NOERROR; /*;AN000;3*/
4364 inreg.x.ax = EXTENDEDOPEN; /*;AN000;3*/
4365 inreg.x.bx = mode + NO_INHERIT; /*;AN000;3*/
4366 inreg.x.cx = attr; /*;AN000;3*/
4367 inreg.x.dx = flag + NO_CP_CHECK; /*;AN000;3*/
4368 inreg.x.si = (WORD)path_addr; /*;AN000;3*/
4369
4370 inreg.x.di = (WORD)&ea_parmlist; /*;AN000;3*/
4371
4372 intdos(&inreg,&outreg); /*;AN000;3*/
4373 if (outreg.x.cflag & CARRY) /* If there was an error /*;AN000;3*/
4374 rc = outreg.x.ax; /* then set return code /*;AN000;3*/
4375
4376#if defined(DEBUG)
4377 if (outreg.x.cflag & CARRY)
4378 printf("ERROR, RC=%04Xh",outreg.x.ax);
4379 else
4380 printf("SUCCESSFUL, HANDLE=%04Xh",outreg.x.ax);
4381#endif
4382
4383 return(outreg.x.ax); /*;AN000;3*/
4384} /* end extended_open */ /*;AN000;3*/
4385 \ No newline at end of file