]> wirehaze git hosting - MS-DOS.git/blob - v4.0/src/CMD/BACKUP/BACKUP.C

wirehaze git hosting

MZ is back!
[MS-DOS.git] / v4.0 / src / CMD / BACKUP / BACKUP.C
1 /* \ f\e0 */
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 /**\f***********************************************/
236 /*
237 /* SUBROUTINE NAME: main
238 /*
239 /* FUNCTION:
240 /*
241 /* Backs up files from source to target drive
242 /*
243 /***************************************************/
244 main(argc,argv)
245 int argc;
246 char *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 /**\f***********************************************/
268 /*
269 /* SUBROUTINE NAME: init
270 /*
271 /* FUNCTION:
272 /* Preload messages
273 /* Check DOS version
274 /* Mundane initializization of data structures
275 /*
276 /**************************************************/
277 void 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 /**\f***********************************************/
321 /*
322 /* SUBROUTINE NAME: parser
323 /*
324 /* FUNCTION:
325 /*
326 /* Parse the command line
327 /*
328 /**************************************************/
329 void parser(argc,argv) /*;AN000;4*/
330 int argc; /*;AN000;4*/
331 char *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 /**\f***********************************************/
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 /**************************************************/
421 void parse_error(ax,dx) /*;AN000;4*/
422 WORD ax; /*;AN000;4*/
423 WORD 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 /**\f***********************************************/
447 /*
448 /* SUBROUTINE NAME: check_date
449 /*
450 /* FUNCTION:
451 /*
452 /* A date parameter was entered. Validate it
453 /*
454 /**************************************************/
455 void check_date(year,month,day) /*;AN000;4*/
456 WORD year; /*;AN000;4*/
457 BYTE month; /*;AN000;4*/
458 BYTE 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 /**\f***********************************************/
489 /*
490 /* SUBROUTINE NAME: check_time
491 /*
492 /* FUNCTION:
493 /*
494 /* A time parameter was entered. Validate it
495 /*
496 /**************************************************/
497 void check_time(hours,minutes,seconds,hundreds) /*;AN000;4*/
498 BYTE hours; /*;AN000;4*/
499 BYTE minutes; /*;AN000;4*/
500 BYTE seconds; /*;AN000;4*/
501 BYTE 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 /**\f***********************************************/
521 /*
522 /* SUBROUTINE NAME: parse_init
523 /*
524 /* FUNCTION:
525 /*
526 /* Initialize the parser data structures
527 /*
528 /**************************************************/
529 void 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 /**\f***********************************************/
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 /***************************************************/
681 void 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 /**\f***********************************************/
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 /***************************************************/
762 void get_path(p) /*;AN002;*/
763 char *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 /**\f***********************************************/
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 /***************************************************/
831 void xlat(tgt,src) /*;AN000;*/
832 char * tgt; /*;AN000;*/
833 char * 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 /**\f***********************************************/
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 /***************************************************/
855 void check_drive_validity(argc,argv)
856 int argc;
857 char *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 /**\f***********************************************/
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*/
938 void check_for_device_names(argv) /*;AN000;p2592*/
939 char *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 /**\f***********************************************/
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 /***************************************************/
998 void check_path_validity(argv)
999 char *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 /**\f***********************************************/
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 /***************************************************/
1130 void 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 /**\f***********************************************/
1149 /*
1150 /* SUBROUTINE NAME: process_switch
1151 /*
1152 /* FUNCTION:
1153 /*
1154 /* Identify the parameter and set program control
1155 /* flags as appropriate.
1156 /*
1157 /***************************************************/
1158 void 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 /**\f***********************************************/
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 /***************************************************/
1243 void 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 /**\f***********************************************/
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 /***************************************************/
1261 void 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 /**\f***********************************************/
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 /***************************************************/
1305 void 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 /**\f***********************************************/
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 /***************************************************/
1325 void 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 /**\f***********************************************/
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 /***************************************************/
1378 void 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 /**\f***********************************************/
1419 /*
1420 /* SUBROUTINE NAME: do_backup
1421 /*
1422 /* FUNCTION:
1423 /*
1424 /* BACKUP all files that should be backed up
1425 /*
1426 /***************************************************/
1427 void 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 /**\f***********************************************/
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 /***************************************************/
1465 void 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 /**\f*********************************************/
1492 /*
1493 /* SUBROUTINE NAME: find_next_file
1494 /*
1495 /* FUNCTION:
1496 /*
1497 /* Find the next file conforming to user entered spec
1498 /*
1499 /************************************************/
1500 void 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 /**\f*********************************************/
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 /************************************************/
1534 void 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 /**\f***********************************************/
1572 /*
1573 /* SUBROUTINE NAME: find_the_next
1574 /*
1575 /* FUNCTION:
1576 /*
1577 /* Find the next file conforming to user entered spec
1578 /*
1579 /***************************************************/
1580 void 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 /**\f***********************************************/
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 /***************************************************/
1624 void change_levels()
1625 {
1626 new_directory = FALSE;
1627 remove_node();
1628 return;
1629 } /* end change_levels */
1630
1631 /**\f***********************************************/
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 /***************************************************/
1640 struct node * alloc_node(path_len)
1641 unsigned 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 /**\f***********************************************/
1669 /*
1670 /* SUBROUTINE NAME: alloc_first_node
1671 /*
1672 /* FUNCTION:
1673 /*
1674 /* Allocate the first node in the linked list.
1675 /*
1676 /***************************************************/
1677 void alloc_first_node()
1678 {
1679 #if defined(DEBUG)
1680 printf("\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 /**\f***********************************************/
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 /***************************************************/
1702 void insert_node(path_addr)
1703 char *path_addr;
1704 {
1705 struct node *temp; /* temporary pointer to a node */
1706 struct node *newnode; /* same thing */
1707
1708 #if defined(DEBUG)
1709 printf("\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 /**\f***********************************************/
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 /***************************************************/
1730 void 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 /**\f***********************************************/
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 /***************************************************/
1767 void 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 /**\f***********************************************/
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 /***************************************************/
1813 void 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 /**\f***********************************************/
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 /***************************************************/
1839 void 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 /**\f***********************************************/
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 /***************************************************/
1877 void 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 /**\f***********************************************/
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 /**************************************************/
1954 void 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 /**\f***********************************************/
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 /***************************************************/
2007 void 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 /**\f***********************************************/
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 /***************************************************/
2046 void 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 /**\f***********************************************/
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 /***************************************************/
2123 void 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 /**\f***********************************************/
2179 /*
2180 /* SUBROUTINE NAME: set_default_dir
2181 /*
2182 /* FUNCTION:
2183 /*
2184 /*
2185 /*
2186 /***************************************************/
2187 void 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 /**\f***********************************************/
2214 /*
2215 /* SUBROUTINE NAME: label_target_drive
2216 /*
2217 /* FUNCTION:
2218 /* Create volume label BACKUP.xxx on target
2219 /* diskette drive.
2220 /*
2221 /***************************************************/
2222 void 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 /**\f***********************************************/
2238 /*
2239 /* SUBROUTINE NAME: build_ext
2240 /*
2241 /* FUNCTION:
2242 /*
2243 /*
2244 /*
2245 /***************************************************/
2246 void build_ext(num)
2247 int 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 /**\f***********************************************/
2261 /*
2262 /* SUBROUTINE NAME: create_target
2263 /*
2264 /* FUNCTION:
2265 /*
2266 /*
2267 /*
2268 /***************************************************/
2269 void 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 /**\f***********************************************/
2327 /*
2328 /* SUBROUTINE NAME: open_target
2329 /*
2330 /* FUNCTION:
2331 /*
2332 /*
2333 /*
2334 /***************************************************/
2335 void 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 /**\f***********************************************/
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 /***************************************************/
2402 void delete_files(dirlevel)
2403 char 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 /**\f***********************************************/
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 /***************************************************/
2469 WORD exist(path_addr) /* Return TRUE if specified epath exists, FALSE other */
2470 char *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 /**\f***********************************************/
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 /***************************************************/
2506 void 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 /**\f***********************************************/
2557 /*
2558 /* SUBROUTINE NAME: file_sharing_error
2559 /*
2560 /* FUNCTION:
2561 /*
2562 /* Handle the file sharing error that just occurred
2563 /*
2564 /***************************************************/
2565 void 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 /**\f***********************************************/
2586 /*
2587 /* SUBROUTINE NAME: far_ptr
2588 /*
2589 /* FUNCTION:
2590 /*
2591 /*
2592 /*
2593 /***************************************************/
2594 char far *far_ptr(seg,off)
2595 WORD seg;
2596 WORD off;
2597 {
2598 char far *p;
2599
2600 PUT_SEG(p,seg);
2601 PUT_OFF(p,off);
2602
2603 return(p);
2604 }
2605
2606 /**\f***********************************************/
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 /***************************************************/
2615 void 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 /**\f***********************************************/
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 /**\f***********************************************/
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 /***************************************************/
2708 void 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 /**\f***********************************************/
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 /***************************************************/
2749 void reset_archive_bit(path_addr)
2750 char *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 /**\f***********************************************/
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 /***************************************************/
2771 void write_to_target(bytes_to_write)
2772 WORD 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 /**\f***********************************************/
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 /***************************************************/
2815 WORD write_till_target_full(bytes_to_write,begin_offset)
2816 WORD bytes_to_write;
2817 WORD 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 /**\f***********************************************/
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 /***************************************************/
2837 void 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 /**\f***********************************************/
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 /***************************************************/
2902 void 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 /**\f***********************************************/
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 /***************************************************/
2942 void 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 /**\f***********************************************/
2961 /*
2962 /* SUBROUTINE NAME: update_db_entries
2963 /*
2964 /* FUNCTION:
2965 /*
2966 /*
2967 /*
2968 /***************************************************/
2969 void update_db_entries(entries)
2970 WORD 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 /**\f***********************************************/
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 /***************************************************/
2998 void 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 /**\f***********************************************/
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 /***************************************************/
3041 void 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 /**\f***********************************************/
3069 /*
3070 /* SUBROUTINE NAME: put_disk_header
3071 /*
3072 /* FUNCTION:
3073 /*
3074 /*
3075 /*
3076 /***************************************************/
3077 void 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 /**\f***********************************************/
3096 /*
3097 /* SUBROUTINE NAME: put_new_db
3098 /*
3099 /* FUNCTION:
3100 /*
3101 /*
3102 /*
3103 /***************************************************/
3104 void 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 /**\f***********************************************/
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 /***************************************************/
3138 void 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 /**\f***********************************************/
3189 /*
3190 /* SUBROUTINE NAME: write_to_control_file
3191 /*
3192 /* FUNCTION:
3193 /* Write to the control file and update
3194 /* counters
3195 /*
3196 /***************************************************/
3197 void write_to_control_file(address,len)
3198 char far * address;
3199 unsigned 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 /**\f***********************************************/
3210 /*
3211 /* SUBROUTINE NAME: control_break_handler
3212 /*
3213 /* FUNCTION:
3214 /* Set errorlevel and call routines to
3215 /* close files and terminate.
3216 /*
3217 /***************************************************/
3218 void 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 /************************************************************/
3261 void display_it(msg_number,handle,subst_count,waitflag,class)/*;AN000;6*/
3262
3263 int msg_number; /*;AN000;6*/
3264 WORD handle; /*;AN000;6*/
3265 int subst_count; /*;AN000;6*/
3266 BYTE waitflag; /*;AN000;6*/
3267 BYTE 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 /**\f***********************************************/
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
3292 void display_msg(msg_num)
3293 int 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 /**\f***********************************************/
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 /***************************************************/
3446 void error_exit(error_type)
3447 int 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 /**\f***********************************************/
3457 /*
3458 /* SUBROUTINE NAME: restore_default_directories
3459 /*
3460 /* FUNCTION:
3461 /* Restore the original current directory on
3462 /* the source drive.
3463 /*
3464 /***************************************************/
3465 void 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 /***************************************************/
3486 void 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 /**\f***********************************************/
3565 /* DOS FAMILY API CALLS */
3566 /**************************************************/
3567
3568 WORD handle_open(path_addr,mode)
3569 char *path_addr;
3570 WORD 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 /**\f***********************************************/
3604 DWORD lseek(handle,method,distance)
3605 WORD handle;
3606 BYTE method; /* 0=BOF+Offset, 1=CurrPos+Offset, 2=EOF+Offset */
3607 DWORD 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 /**\f***********************************************/
3635 WORD handle_read(handle,length,address)
3636 WORD handle;
3637 WORD length;
3638 char 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 /**\f***********************************************/
3665 WORD handle_write(handle,length,address)
3666 WORD handle;
3667 WORD length;
3668 char 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 /**\f***********************************************/
3702 void close_file(handle) /* Close the file handle specified. */
3703 WORD 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 /**\f***********************************************/
3722 WORD get_attribute(path_addr)
3723 char *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 /**\f***********************************************/
3744 void set_attribute(path_addr,attribute)
3745 char *path_addr;
3746 WORD 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 /**\f***********************************************/
3764 WORD 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 /**\f***********************************************/
3790 void set_default_drive(drive) /* Change the current drive (1=A,2=B) */
3791 WORD 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 /**\f***********************************************/
3813 void get_current_dir(drive,path_addr)
3814 WORD drive; /* 0=default, 1=a, . . . */
3815 char *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 /**\f***********************************************/
3842 void find_first(path_addr,dirhandle_addr,dta_address,attrib)
3843 char *path_addr;
3844 WORD *dirhandle_addr;
3845 struct FileFindBuf *dta_address;
3846 WORD 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 /**\f***********************************************/
3888 void find_next(dirhandle,dta_address)
3889 WORD dirhandle;
3890 struct 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 /**\f***********************************************/
3925 void findclose(dirhandle)
3926 WORD 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 /**\f***********************************************/
3947 void delete(path_addr)
3948 char *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 /**\f***********************************************/
3966 long 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 /**\f***********************************************/
3993 void replace_volume_label(label_addr)
3994 char *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 /**\f***********************************************/
4019 #define TERMINATE 0x4C00
4020 void 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)
4026 printf("\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 /**\f***********************************************/
4038 WORD ioctl(devhandle)
4039 WORD 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 /**\f***********************************************/
4071 void 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 /**\f***********************************************/
4096 void free_seg(selector)
4097 unsigned 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 /**\f***********************************************/
4116 void setsignal(action,signum)
4117 WORD action;
4118 WORD 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 /**\f***********************************************/
4148 void do_dos_error(flag)
4149 WORD 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 /**\f***********************************************/
4167 void 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 /**\f***********************************************/
4219 void 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 /**\f***********************************************/
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 /**\f************************************************/
4345 #define EXTENDEDOPEN 0x6c00 /*;AN000;3*/
4346
4347 WORD extended_open(flag,attr,path_addr,mode) /*;AN000;3*/
4348 WORD flag; /*;AN000;3*/
4349 WORD attr; /*;AN000;3*/
4350 char far *path_addr; /*;AN000;3*/
4351 WORD 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 \1a