Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

344 lines
12 KiB

#include "cmd.h"
/* useful macro */
#define Wild(spec) ((spec)->flags & (CI_NAMEWILD))
/* Globals from cpwork.c */
extern int copy_mode;
extern unsigned DosErr ;
/* Globals from command */
extern TCHAR SwitChar, CASwitch, CBSwitch, CFSwitch, CVSwitch, CNSwitch, CZSwitch;
extern BOOLEAN VerifyCurrent; // cpwork.c
/* parse_args
*
* This is the key function which decides how copy will react to any
* given invocation. It parses the arguments, fills the source and
* destination structures, and sets the copy_mode.
*
* ENTRY
*
* args - raw argument line entered by the user
*
* source - pointer to an initialized cpyinfo struct. This one isn't
* used; it's just a header to a linked list containing the
* actual source structures.
*
* dest - like source, but there will be at most one filled-in dest struct.
*
* EXIT
*
* source - the caller's source pointer has not, of course, been changed. It
* still points to the empty header (which might not be completely
* empty - see handle_switch for details). It is the head of a
* linked list of structures, terminated by one with a NULL in its
* next field. Each structure corresponds to a source spec.
*
* dest - if a destination was specified, the caller's dest pointer points
* to an empty header which points to the actual destination struct.
* If the destination is implicit, the fspec and next fields of the
* struct are still NULL, but the flag field has been filled in with
* the copy mode. If the user specified a copy mode (ascii or
* binary) one or more times, the last switch applies to the
* destination. If not, CI_NOTSET is used.
*
* copy_mode - set to type of copy being done - COPY, COMBINE, CONCAT, or
* TOUCH.
*
*/
void parse_args(args, source, dest)
TCHAR *args;
struct cpyinfo *source, *dest;
{
TCHAR *tas; /* tokenized argument string */
TCHAR copydelims[4]; /* copy token delimters */
int parse_state = SEEN_NO_FILES; /* state of the parser */
int all_sources_wildcards = TRUE, /* flag to help decide copy mode */
number_of_sources = 0, /* number of specs seen so far */
current_copy_mode = CI_NOTSET, /* ascii, binary, or not set */
tlen; /* offset to next token */
BOOL ShortNameSwitch=FALSE;
BOOL RestartableSwitch=FALSE;
copydelims[0] = PLUS; /* delimiters for token parser */
copydelims[1] = COMMA;
copydelims[2] = SwitChar;
copydelims[3] = NULLC;
if (!*(tas = TokStr(args, copydelims, TS_SDTOKENS))) /* tokenize args */
copy_error(MSG_BAD_SYNTAX,CE_NOPCOUNT); /* M003 */
for ( ; *tas ; tas += tlen+1 ) /* cycle through tokens in args */
{
tlen = mystrlen(tas);
switch(*tas) {
case PLUS:
if (parse_state != JUST_SEEN_SOURCE_FILE)
/* M003 */ copy_error(MSG_BAD_SYNTAX,CE_NOPCOUNT);
parse_state = SEEN_PLUS_EXPECTING_SOURCE_FILE;
break;
case COMMA:
if (parse_state == SEEN_COMMA_EXPECTING_SECOND)
parse_state = SEEN_TWO_COMMAS;
else if ((parse_state == SEEN_PLUS_EXPECTING_SOURCE_FILE) &&
(number_of_sources == 1))
parse_state = SEEN_COMMA_EXPECTING_SECOND;
else if (parse_state != JUST_SEEN_SOURCE_FILE)
/* M003 */ copy_error(MSG_BAD_SYNTAX,CE_NOPCOUNT);
break;
default: /* file or switch */
if (*tas == SwitChar) {
handle_switch(tas,source,dest,parse_state,
&current_copy_mode, &ShortNameSwitch, &RestartableSwitch);
tlen = *(tas + 3) ? 2 : 3; /* offset past switch */
}
else
/*509*/ { /* must be device or file */
/*509*/ mystrcpy(tas,stripit(tas));
parse_state = found_file(tas,parse_state,&source,&dest,
&number_of_sources,&all_sources_wildcards,current_copy_mode);
/*509*/ }
break;
}
}
/* set copy mode appropriately */
set_mode(number_of_sources,parse_state,all_sources_wildcards,dest);
if (ShortNameSwitch)
source->flags |= CI_SHORTNAME;
if (RestartableSwitch)
//
// If running on a platform that does not support CopyFileEx
// display an error message if they try to use /Z option
//
if (lpCopyFileExW == NULL)
copy_error(MSG_NO_COPYFILEEX,CE_NOPCOUNT);
else
source->flags |= CI_RESTARTABLE;
/* if no dest specified, put current copy mode in header */
if (number_of_sources != 0) /*M005 if sources specd */
{ /*M005 then */
if (parse_state != SEEN_DEST) /*M005 if seen a destspec*/
{ /*M005 then */
dest->flags = current_copy_mode; /*M005 save cur mode */
} /*M005 endif */
} /*M005 */
else /*M005 */
{ /*M005 else */
copy_error(MSG_BAD_SYNTAX,CE_NOPCOUNT); /*M005 disp inv#parms */
} /*M005 endif */
}
/* handle_switch
*
* There are four switches to handle: CASwitch, CBSwitch, CFSwitch and
* CVSwitch.
*
* CBSwitch and CASwitch set the copy mode to binary and ascii respectively.
* This change applies to the previous filespec and all succeeding ones.
* Figure out which was the last filespec read and set its flags; then set
* the current copy mode.
*
* Note: If there was no previous filespec, the source pointer is pointing
* at an unitialized header. In this case, we set the flags in this
* struct to the current copy mode. This doesn't accomplish
* anything, but the code is simpler if it doesn't bother to check.
*
* CFSwitch indicates that the copy should fail if we can't copy the EAs.
*
* CVSwitch enables the much slower verified copy mode. This is very
* easy to handle; call a magic internal DOS routine. All writes are then
* verified automagically without our interference.
*
*/
void handle_switch(tas, source, dest, parse_state, current_copy_mode, ShortNameSwitch,RestartableSwitch)
TCHAR *tas;
struct cpyinfo *source;
struct cpyinfo *dest;
int parse_state;
int *current_copy_mode;
BOOL *ShortNameSwitch;
BOOL *RestartableSwitch;
{
TCHAR ch = _totupper(tas[2]);
if ((ch == CASwitch) || (ch == CBSwitch)) {
*current_copy_mode = (ch == CASwitch ? CI_ASCII : CI_BINARY);
if (parse_state == SEEN_DEST) { /* then prev spec was dest */
dest->flags &= (~CI_ASCII) & (~CI_BINARY) & (~CI_NOTSET);
dest->flags |= *current_copy_mode;
}
else { /* set last source spec */
source->flags &= (~CI_ASCII) & (~CI_BINARY) & (~CI_NOTSET);
source->flags |= *current_copy_mode;
}
}
else if (ch == CVSwitch)
VerifyCurrent = 1;
else if (ch == CNSwitch)
*ShortNameSwitch = TRUE;
else if (ch == CZSwitch)
*RestartableSwitch = TRUE;
else
copy_error(MSG_BAD_SYNTAX,CE_NOPCOUNT); /* M003 */
}
/* found_file
*
* Token was a file or device. Put it in the appropriate structure and
* run ScanFSpec on it. Figure out what the new parser state should be
* and return it. Note: This function has one inelegant side-effect; if
* it sees a destination file after a double-comma ("copy foo+,, bar"), it
* sets the copy_mode to TOUCH. Otherwise the copier wouldn't remember to
* use the current date and time with the copied file. Set_mode notices that
* the mode is TOUCH and doesn't change it. This works because the copy modes
* CONCAT, COMBINE, COPY, and TOUCH are mutually exclusive in all but this one
* case where we both copy and touch at once.
*
*/
found_file(token,parse_state,source,dest,num_sources,all_sources_wild,mode)
TCHAR *token;
int parse_state;
struct cpyinfo **source, **dest;
int *num_sources, *all_sources_wild,mode;
{
struct cpyinfo *add_filespec_to_struct();
/* if it's a source, add to the list of source structures */
if ((parse_state == SEEN_NO_FILES) ||
(parse_state == SEEN_PLUS_EXPECTING_SOURCE_FILE)) {
*source = add_filespec_to_struct(*source,token,mode);
ScanFSpec(*source);
//
// Could have an abort from access to floppy etc. so get out
// of copy. If it is just an invalid name then proceed since
// it is a wild card. If is actually invalid we will catch
// this later.
if ((DosErr) && (DosErr != ERROR_INVALID_NAME)) {
copy_error(DosErr, CE_NOPCOUNT);
}
parse_state = JUST_SEEN_SOURCE_FILE;
(*num_sources)++;
if (!Wild(*source))
*all_sources_wild = FALSE;
}
/* if it's a dest, make it the dest structure */
else if ((parse_state == SEEN_TWO_COMMAS) ||
(parse_state == JUST_SEEN_SOURCE_FILE)) {
if (parse_state == SEEN_TWO_COMMAS)
copy_mode = TOUCH;
*dest = add_filespec_to_struct(*dest,token,mode);
ScanFSpec(*dest);
//
// Could have an abort from access to floppy etc. so get out
// of copy
//
if ((DosErr) && (DosErr != ERROR_INVALID_NAME)) {
copy_error(DosErr, CE_NOPCOUNT);
}
parse_state = SEEN_DEST;
}
/* if we have a dest or the syntax is messed up, complain */
else
copy_error(MSG_BAD_SYNTAX,CE_NOPCOUNT); /* M003 */
return(parse_state);
}
/* set_mode
*
* Given all the current state information, determine which kind of copy
* is being done and set the copy_mode. As explained in found_file, if
* the mode has been set to TOUCH, set_mode doesn't do anything.
*/
void set_mode(number_sources,parse_state,all_sources_wildcards,dest)
int number_sources,
parse_state,
all_sources_wildcards;
struct cpyinfo *dest;
{
if (copy_mode == TOUCH) /* tacky special case */
return;
/* If there was one source, we are doing a touch, a concatenate,
* or a copy. It's a touch if there was one file and we saw a "+" or a
* "+,,". If the source was a wildcard and the destination is a file,
* it's a concatenate. Otherwise it's a copy.
*/
if (number_sources == 1) {
if ((parse_state == SEEN_TWO_COMMAS) ||
(parse_state == SEEN_PLUS_EXPECTING_SOURCE_FILE))
copy_mode = TOUCH;
else if (all_sources_wildcards && dest->fspec && !Wild(dest) &&
!(*lastc(dest->fspec) == COLON))
copy_mode = CONCAT;
}
/* For more than one source, we are combining or concatenating. It's
* a combine if all sources were wildcards and the destination is either
* a wildcard, a directory, or implicit. Otherwise it's a concatenation.
*/
else {
if ((all_sources_wildcards) &&
((!dest->fspec) || Wild(dest) ||
(*lastc(dest->fspec) == COLON)))
copy_mode = COMBINE;
else
copy_mode = CONCAT;
}
DEBUG((FCGRP,COLVL,"Set flags: copy_mode = %d",copy_mode));
}
/* add_filespec_to_struct
*
* ENTRY
*
* spec - points to a filled structure with a NULL in its next field.
*
* file_spec - filename to put in new structure
*
* mode - copy mode
*
* EXIT
*
* Return a pointer to a new cpyinfo struct with its fields filled in
* appropriately. The old spec struct's next field points to this new
* structure.
*
*/
struct cpyinfo *
add_filespec_to_struct(spec,file_spec,mode)
struct cpyinfo *spec;
TCHAR *file_spec;
int mode;
{
struct cpyinfo *initialize_struct();
spec->next = initialize_struct();
spec = spec->next;
spec->fspec = file_spec;
spec->flags |= mode;
return(spec);
}