home *** CD-ROM | disk | FTP | other *** search
- /*
- docp.c - Directory-Oriented CoPy
-
- Fancy file copy program for MS-DOS
-
- Copyright (c) 1992, Roy Bixler
- Originally by: David Oertel
- Atari ST port, overall cheez-whiz: Roy Bixler
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 1, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
- */
-
- #include <stdio.h>
- #include <conio.h>
- #include <io.h>
- #include <alloc.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sys\stat.h>
- #include <dir.h>
- #include <dos.h>
- #include <fcntl.h>
- #include <ctype.h>
-
- #define DOT_NOTATION(dir) !strcmp(dir, "\.")
-
- #include "docp.h"
- #include "doc.h"
- #include "elib.h"
- #include "protypes.h"
-
- #define OPT_LIST "abcdfghijlmnorstvwz?"
- #define GET_OPT_LIST "AaBbCcD:d:F:f:GgHhIiJjLlMmNnOoRrSsTtVvW:w:Zz?"
- #define DOT_NOTATION(dir) !strcmp(dir, "\.")
- #define MAX_BUF 0xfffeU
-
- extern int Optind;
- extern char *optarg;
- long Options = 0L;
- char Cur_source_dir[FILENAME_MAX], Org_dest_dir[FILENAME_MAX];
- ENTRY *Ptr;
- void *Buf_ptr;
- void *File_buf;
- int Reading_flag; /* set if 'reading:' has been printed last
- * reset if 'writing:' has been printed last */
-
- /* modes of date compare via 'd' option */
- #define D_BEFORE 1
- #define D_ON 2
- #define D_AFTER 4
-
- DATE_NODE *Fdate; /* used to store date entered via 'd' option */
- TIME_NODE *Ftime; /* used to store time entered via 'w' option */
-
- FILE *From_file_ptr; /* file containing file list ('-f' option) */
- int Retry = 0; /* set if target disk is full and user chooses to
- * continue */
- int Copied_a_file = 0; /* set if at least one file was copied */
-
- ENTRY *Src_tab[HASH_TAB_SIZE]; /* contains source-file names */
- ENTRY *Dst_tab[HASH_TAB_SIZE]; /* contains destination-file names */
-
-
- typedef struct file_list {
- char *string;
- struct file_list *next;
- } STDIN_TOKEN;
-
- /* linked list globals containing file list from stdin */
- STDIN_TOKEN *Stdin_list_head = NULL;
- STDIN_TOKEN *Stdin_list_tail = NULL;
- STDIN_TOKEN *Stdin_list_current = NULL;
-
- void main(int argc, char *argv[])
-
- {
- char src_dir[MAXDIR];
- char dst_dir[MAXDIR];
- unsigned long buf_size;
- int num_args;
- char **argv_ptr;
- char *all[2] = {"*.*", NULL};
-
- get_flags(argv, argc);
- check_flags();
- check_and_format_dirs(argc, argv, src_dir, dst_dir);
- #ifdef LATER
- check_target_removeable(dst_dir);
- #else
- Options |= O_TARGET_REMOVEABLE; /* assume any disk is removeable */
- #endif
- File_buf = get_file_buf(&buf_size);
- Buf_ptr = File_buf;
- argv += Optind + 2;
- num_args = argc - Optind - 2;
- argv_ptr = argv;
- if (Options & O_FROM_STDIN)
- build_stdin_file_list(&num_args);
- else if (Options & O_FROM_FILE) {
- char buf[80];
-
- num_args = 0;
- while (fgets(buf, 79, From_file_ptr) != NULL)
- num_args++;
- rewind(From_file_ptr);
- } else if (num_args == 0) {
- num_args = 1;
- argv_ptr = all;
- }
- strcpy(Org_dest_dir, dst_dir);
- if (Options & O_CHECK)
- fprintf(stdout, "The following files would be copied or moved:\n");
- else if (Options & O_ZAPTARGET)
- zap_target(dst_dir, 1);
- copy_files(src_dir, dst_dir, argv_ptr,
- num_args, File_buf, buf_size);
- write_buffer(File_buf);
- clear_archive_bits(src_dir);
-
- if (!Copied_a_file)
- fprintf(stdout, "no files copied\n");
-
- farfree(File_buf);
-
- }
-
- /*
- * check_and_format_dirs()
- *
- * Input:
- * argc - command line argument count
- * argv - command line arguments
- * Optind - argument index from getopt()
- * Output:
- * src_dir - source directory name
- * dst_dir - destination directory name
- * Comments:
- * The source and destination directories are formatted
- * The source directory is checked for existence
- * The destination directory is created if it doesn't exist
- * The two directories are checked to insure that they are
- * different
- * The destination is checked to insure that it is not a
- * subdirectory of the source
- */
-
- void check_and_format_dirs(int argc, char *argv[],
- char *src_dir, char *dst_dir)
-
- {
- if ((argc-Optind) < 2)
- usage();
-
- strcpy(src_dir, argv[Optind]);
- check_if_dir_exists(src_dir, 0);
- strcpy(dst_dir, argv[Optind + 1]);
- check_if_dir_exists(dst_dir, 1);
-
- format_dir(argv[Optind], '\1', src_dir);
- format_dir(argv[Optind + 1], '\1', dst_dir);
-
- check_if_dirs_compatible(src_dir, dst_dir);
- }
-
- #ifdef LATER
- /*
- * check_target_removeable()
- *
- * Input:
- * dst_dir - destination directory name
- * Output:
- * Options - will be modified if target directory is removeable
- * (i.e. a floppy disk)
- */
-
- void check_target_removeable(char *dst_dir)
-
- {
- char dst_drive;
-
- if (islower(dst_drive = dst_dir[0]))
- dst_drive = toupper(dst_drive);
- if ((dst_drive == 'A') || (dst_drive == 'B'))
- Options |= O_TARGET_REMOVEABLE;
- }
- #endif
-
- /*
- * check_if_dirs_compatible()
- *
- * Input:
- * src_dir - The formatted source directory name
- * dst_dir - The formatted destination directory name
- * Comments:
- * terminates if:
- * 1 - The two directories are the same
- * 2 - The destination is a subdirectory of
- * the source
- */
-
- void check_if_dirs_compatible(char *src_dir, char *dst_dir)
-
- {
- if (Options & O_CHECK)
- return;
- if (!strcmp(src_dir, dst_dir)) {
- fprintf(stderr,
- "source and destination directories are the same\n");
- exit(-1);
- }
- if ((Options & O_RECURSIVE) &&
- !strncmp(src_dir, dst_dir, strlen(src_dir))) {
- fprintf(stderr,
- "destination directory is a subdirectory of the source directory \nwhile in recursive mode\n");
- exit(-1);
- }
- }
-
- /*
- * check_if_dir_exists()
- *
- * Input:
- * dir - the directory name
- * is_dest - flag set if directory is a destination directory
- * Comments:
- * creates destination directory if it doesn't exist
- * terminates if the source directory doesn't exist
- */
-
- void check_if_dir_exists(char *dir, int is_dest)
-
- {
- int retval;
- char *ext_path = append_dir_to_path(dir, "*.*");
- struct ffblk tmp;
-
- if ((!just_disk(dir)) && (findfirst(ext_path, &tmp, FA_DIREC)))
- if ((is_dest) && ((Options & O_BATCH) ||
- (printf("directory %s does not exist - ", dir),
- ask_user("create it (Y/N/Q) ? "))))
- create_dir(dir);
- else {
- printf("docp: directory '%s' does not exist\n", dir);
- exit(-1);
- }
- free(ext_path);
- }
-
-
- /*
- * create_dir()
- *
- * Input:
- * dir - the directory to be created
- * options - command line options
- * Comments:
- * creates destination directory
- */
-
- void create_dir(char *dir)
-
- {
- char next_dir[MAXDIR], *p;
-
- strcpy(next_dir, dir);
- for (p=next_dir; *p; p++)
- if (*p == '/')
- *p = '\\';
-
- p = next_dir;
- while ((p = strchr(p, '\\')) != NULL) {
- *p = '\0';
- mkdir(next_dir);
- *p++ = '\\';
- }
- if (mkdir(dir) == -1) {
- fprintf(stderr, "cannot create directory '%s'\n", dir);
- exit(-1);
- }
- else if (Options & O_VERBOSE)
- printf("created directory '%s'\n", dir);
- }
-
-
- /*
- * just_disk()
- *
- * Input:
- * dir - the directory to be checked
- * Output:
- * returns :
- * 1 - if 'dir' is a "just" a directory specification of the
- * form 'X:', 'X:\' or 'X:/'
- * 0 - otherwise
- */
-
- int just_disk(char *dir)
-
- {
- if (dir == NULL)
- return 0;
- switch (strlen(dir)) {
- case 1:
- return ((dir[0] == '/') || (dir[0] == '\\'));
- case 2:
- return ((isalpha(dir[0])) && (dir[1] == ':'));
- case 3:
- return ((isalpha(dir[0])) && (dir[1] == ':') &&
- ((dir[2] == '/') || (dir[2] == '\\')));
- default:
- return 0;
- }
- }
-
- /*
- * change_disk()
- *
- * Input:
- * dir - the destination directory
- * curdir - the current working directory
- * Comments:
- * changes to the disk specified by dir
- */
-
- void change_disk(char *dir, char *cur_dir)
-
- {
- int maxdrives;
-
- if ((strlen(dir) > 1) && (*(dir + 1) == ':')) {
- if (isupper(*dir))
- tolower(*dir);
- maxdrives = setdisk(*dir - 'a');
- if (maxdrives < (*dir - 'a') + 1) {
- setdisk(*cur_dir - 'A');
- fprintf(stderr, "drive '%c' is not accessable\n", *dir);
- exit(-1);
- }
- }
- }
-
- /*
- * copy_files()
- *
- * Input:
- * src_dir - the source directory
- * dst_dir - the destination directory
- * file_spec - the command-line file list
- * num_args - the number of arguments in the file list
- * file_buf - the buffer for reading and writing files
- * buf_size - the size of 'file_buf'
- * Comments:
- * copy or move the files from the source directory to the
- * destination directory
- */
-
- void copy_files(char *src_dir, char *dst_dir, char *file_spec[], int num_args,
- void *file_buf, unsigned long buf_size)
-
- {
- struct ffblk fblk;
- char ref_list[MAXPATH];
- char src_file[MAXPATH], dst_file[MAXPATH];
- int done, index;
- long file_size;
- char *file;
-
- strcpy(Cur_source_dir, src_dir);
- build_hash_tab(src_dir, Src_tab, num_args, file_spec);
- build_hash_tab(dst_dir, Dst_tab, num_args, file_spec);
-
- if ((Options & O_ZAPTARGET) && (!(Options & (O_CHECK|O_GATHER))))
- zap_target(dst_dir, 1);
- file = get_first(&index);
- while (file != NULL) {
- strcpy(src_file, src_dir);
- strcat(src_file, file);
-
- strcpy(dst_file, dst_dir);
- strcat(dst_file, file);
- if (should_file_copy(file, src_file)) {
- if (Options & O_CHECK)
- fprintf(stdout, "\t%s -> %s\n",
- src_file, dst_file);
- else
- copy_file(Ptr, dst_file, src_file,
- buf_size);
- } else
- report_not_copied(src_file);
-
- file = get_next(&index);
- }
-
- clear_archive_bits(src_dir);
- copy_sub_dirs(src_dir, dst_dir, file_spec, num_args,
- file_buf, buf_size);
- if (Options & O_MOVE) {
- int len = strlen(src_dir);
- char put_back;
-
- if ((len > 0) && (src_dir[--len] == '\\')) { /* if src_dir has */
- src_dir[len] = '\0'; /* trailing \, */
- put_back = 1; /* zap it */
- }
- else
- put_back = 0;
- rmdir(src_dir); /* don't try too hard, but do it if we can */
- if (put_back) /* put back */
- src_dir[len] = '\\'; /* trailing \ */
- }
- if (Options & O_ZAPTARGET) {
- int len = strlen(dst_dir);
- char put_back;
-
- if ((len > 0) && (dst_dir[--len] == '\\')) { /* if dst_dir has */
- dst_dir[len] = '\0'; /* trailing \, */
- put_back = 1; /* zap it */
- }
- else
- put_back = 0;
- rmdir(dst_dir);
- if (put_back) /* put back */
- dst_dir[len] = '\\'; /* trailing \ */
- }
- }
-
- /*
- * report_not_copied()
- *
- * Input:
- * src_dir - source directory
- * Comments:
- * reports that a file was not copied
- */
-
- void report_not_copied(char *src_file)
-
- {
- if ((Options & O_X_VERBOSE) && !(Options & O_CHECK)) {
- if (!Reading_flag) {
- fprintf(stdout, "reading:\n");
- Reading_flag = 1;
- }
- printf("\t%s ** NOT COPIED **\n", src_file);
- }
- }
-
- /*
- * zap_target()
- *
- * Input:
- * dst_dir - the destination directory
- * print_heading - true on entry, false for recursive calls
- * Comments:
- * zaps the files in the target directory
- */
-
- void zap_target(char *dst_dir, int print_banner)
-
- {
- int done, attrib = 0, i;
- struct ffblk fblk;
- char dst_file[FILENAME_MAX], buf[MAXPATH+20];
-
- if (Options & O_COPY_HIDDEN)
- attrib |= (FA_HIDDEN|FA_SYSTEM);
- if ((Options & O_RECURSIVE) && (!(Options & O_GATHER)))
- attrib |= FA_DIREC;
- strcpy(dst_file, dst_dir);
- if (dst_file[(i = strlen(dst_file))-1] != '\\') {
- strcat(dst_file, "\\");
- i++;
- }
- strcat(dst_file, "*.*");
- done = findfirst(dst_file, &fblk, attrib);
- if ((!done) && (Options & O_VERBOSE) && (print_banner))
- printf("deleting:\n");
- while (!done) {
- strcpy(dst_file+i, fblk.ff_name);
- if (fblk.ff_attrib & FA_DIREC) {
- if (!is_special(fblk.ff_name)) {
- zap_target(dst_file, 0);
- rmdir(dst_file);
- }
- }
- else if ((!(Options & O_INTERACTIVE)) ||
- (sprintf(buf, "Delete file %s (Y/N/Q) ?", dst_file),
- ask_user(buf))) {
- if (Options & O_VERBOSE)
- printf("\t%s\n", dst_file);
- delete_file(dst_file, '\1');
- }
-
- done = findnext(&fblk);
- }
- }
-
- /*
- * build_hash_tab()
- *
- * Input:
- * dir - the directory for which to table will be built
- * num_args - the number of arguments in the file list
- * file_spec - the command-line file list
- * Output:
- * hash_tab - the hash table containing all the file names
- * of the directory 'dir'
- * Comments:
- * builds a hash table containing all the file names of a
- * directory specified by the command-line file list.
- * First it adds all the names specified by the file
- * list, then it subtracts those specified
- * by the '-' notation in the file list.
- */
-
- void build_hash_tab(char *dir, ENTRY * hash_tab[],
- int num_args, char *file_spec[])
-
- {
- add_to_hash_tab(dir, hash_tab, 1, num_args, file_spec);
- take_from_hash_tab(dir, hash_tab, num_args, file_spec);
- }
-
- /*
- * add_to_hash_tab()
- *
- * Input:
- * dir - the directory for which to table will be built
- * from_file_poss - is it possible to get file list from a file?
- * num_args - the number of arguments in the file list
- * file_spec - the command-line file list
- * Output:
- * hash_tab - the hash table containing all the file names
- * of the directory 'dir'
- * Comments:
- * adds all the files specified by the file list and within
- * the directory 'dir' to the hash table.
- */
-
- void add_to_hash_tab(char *dir, ENTRY *hash_tab[],
- int from_file_poss, int num_args, char *file_spec[])
-
- {
- int done;
- struct ffblk fblk;
- char ref_list[MAXPATH];
- int i;
- char buf[80];
- int files_added = 0;
-
- if ((from_file_poss) && (Options & O_FROM_STDIN))
- Stdin_list_current = Stdin_list_head;
-
- if ((from_file_poss) && (Options & O_FROM_FILE))
- rewind(From_file_ptr);
-
- for (i = 0; i < num_args; i++) {
- strcpy(ref_list, dir);
- get_file_spec(buf, file_spec, i);
- if (*buf != '-') {
- int attrib = 0;
-
- files_added = 1;
- strcat(ref_list, buf);
- if (Options & O_COPY_HIDDEN)
- attrib |= (FA_HIDDEN | FA_SYSTEM);
- done = findfirst(ref_list, &fblk, attrib);
- while (!done) {
- if (find_entry(fblk.ff_name, hash_tab) == NULL)
- add_entry(&fblk, hash_tab);
- done = findnext(&fblk);
- }
- }
- }
- if (!files_added) {
- char *all[2] = {"*.*", NULL};
-
- add_to_hash_tab(dir, hash_tab, 0, 1, all);
- }
- }
-
- /*
- * take_from_hash_tab()
- *
- * Input:
- * dir - the directory for which to table will be built
- * num_args - the number of arguments in the file list
- * file_spec - the command-line file list
- * Output:
- * hash_tab - the hash table containing all the file names
- * of the directory 'dir' and specified by the file
- * list, 'file_spec'.
- * Comments:
- * takes all the files specified by using the '-' notation
- * and within the directory 'dir' from the hash table.
- */
-
- void take_from_hash_tab(char *dir, ENTRY * hash_tab[],
- int num_args, char *file_spec[])
-
- {
- int done;
- struct ffblk fblk;
- char ref_list[MAXPATH];
- int i;
- char buf[80];
-
- if (Options & O_FROM_STDIN)
- Stdin_list_current = Stdin_list_head;
-
- if (Options & O_FROM_FILE)
- rewind(From_file_ptr);
-
- for (i = 0; i < num_args; i++) {
- strcpy(ref_list, dir);
-
- get_file_spec(buf, file_spec, i);
-
- if (*buf == '-') {
- int attrib = 0;
-
- strcat(ref_list, buf + 1);
- if (Options & O_COPY_HIDDEN)
- attrib |= (FA_HIDDEN | FA_SYSTEM);
- done = findfirst(ref_list, &fblk, attrib);
- while (!done) {
- remove_entry(fblk.ff_name, hash_tab);
- done = findnext(&fblk);
- }
- }
- }
- }
-
-
- /*
- * get_file_spec()
- *
- * Input:
- * file_spec - the command-line file list
- * i - index into the command-line file list
- * Output:
- * buf - the next token from the command line file list
- * Comments:
- * gets the next token from the command-line file list
- */
-
- void get_file_spec(char *buf, char *file_spec[], int i)
-
- {
- if (Options & O_FROM_STDIN) {
- strcpy(buf, Stdin_list_current->string);
- Stdin_list_current = Stdin_list_current->next;
- } else if (Options & O_FROM_FILE) {
- fgets(buf, 79, From_file_ptr);
- zap_trailing_nl(buf, 79, From_file_ptr); /* clobber newline */
- } else
- strcpy(buf, file_spec[i]);
- }
-
-
- #ifdef DEBUG
- /*
- * print_fdate
- *
- * given a dta structure, print out the date in it
- */
-
- void print_fdate(unsigned fdate)
-
- {
- printf("%02u/%02u/%02u",
- (fdate >> 9) + 80,
- (fdate >> 5) & 0xf,
- (fdate) & 0x1f);
- }
-
-
-
- /*
- * print_ftime
- *
- * given a dta structure, print out the time in it
- */
-
- void print_ftime(unsigned ftime)
-
- {
- printf("%02u:%02u:%02u",
- (ftime >> 11),
- (ftime >> 5) & 0x3f,
- (ftime & 0x1f));
- }
-
- #endif /* DEBUG */
-
-
-
- /*
- * add_entry()
- *
- * Input:
- * fblk - structure containing the file name, date, and time
- * Output:
- * hash_tab - add entry to this array of pointers
- * Comments:
- * ands a file name along with its date and time to a hash table
- */
-
- void add_entry(struct ffblk * fblk, ENTRY * hash_tab[])
-
- {
- int bucket;
- ENTRY *ptr;
-
- bucket = hashpjw(fblk->ff_name);
- if (hash_tab[bucket] == NULL) {
- if ((hash_tab[bucket] = (ENTRY *) malloc(sizeof(ENTRY))) ==
- NULL) {
- fprintf(stderr, "out of memory");
- exit(-1);
- }
- hash_tab[bucket]->next = NULL;
- } else {
- if ((ptr = (ENTRY *) malloc(sizeof(ENTRY))) == NULL) {
- fprintf(stderr, "out of memory");
- exit(-1);
- }
- ptr->next = hash_tab[bucket];
- hash_tab[bucket] = ptr;
- }
- strcpy(hash_tab[bucket]->name, fblk->ff_name);
- hash_tab[bucket]->attr = fblk->ff_attrib;
- hash_tab[bucket]->ftime = fblk->ff_ftime;
- hash_tab[bucket]->fdate = fblk->ff_fdate;
- hash_tab[bucket]->copied = 0;
- }
-
- /*
- * get_first()
- *
- * Input:
- * none
- * Output:
- * index - index to first hash table bucket. Each bucket is a
- * linked-list of structures, one for each file.
- * Ptr - pointer to first hash table file entry
- * returns - the name of the first file in the hash table
- * Comments:
- * selects the proper hash table and finds its first entry
- */
-
- char *get_first(int *index)
-
- {
- *index = 0;
-
- Ptr = (Options & O_TARGET_DIR) ? Dst_tab[0] : Src_tab[0];
- move_Ptr(index);
-
- return (Ptr == NULL) ? NULL : Ptr->name;
- }
-
- /*
- * get_next()
- *
- * Input:
- * index - index to current hash-table bucket. Each bucket is a
- * linked-list of structures, one for each file.
- * Ptr - pointer to current hash-table file entry
- * Output:
- * index - index to next hash table bucket (may not be different
- * from current bucket).
- * Ptr - pointer to next hash table file entry
- * returns - the name of the next file in the hash table
- *
- * Comments:
- * finds the next entry in the currently selected hash table
- * of file names
- */
-
- char *get_next(int *index)
-
- {
- if (Ptr != NULL)
- Ptr = Ptr->next;
- move_Ptr(index);
- return (Ptr == NULL) ? NULL : Ptr->name;
- }
-
- /*
- * move_Ptr()
- *
- * Input:
- * index - index to current hash-table bucket. Each bucket is a
- * linked-list of structures, one for each file.
- * Ptr - pointer to hash table file entry
- * Output:
- * index - index to hash-table bucket.
- * Ptr - pointer to hash table file entry
- * Comments:
- * finds the next non-NULL entry, only if the hash-table
- * pointer is NULL
- */
-
- void move_Ptr(int *index)
-
- {
- if (Ptr == NULL)
- for ((*index)++; (*index < HASH_TAB_SIZE); (*index)++)
- if ((Ptr = ((Options & O_TARGET_DIR) ? Dst_tab[*index]
- : Src_tab[*index])) != NULL)
- break;
- }
-
- /*
- * get_fmode
- *
- * given a file name, return its mode (i.e. attributes or permissions)
- */
-
- short get_fmode(char *src_file)
-
- {
- struct stat statbuf;
-
- return (stat(src_file, &statbuf))
- ? '\0'
- : statbuf.st_mode & (S_IREAD|S_IWRITE|S_IEXEC);
- }
-
- /*
- * clear_archive_bits
- *
- * given a source directory, go through the hash table (up to the value
- * of Ptr on entry to this function) and clear the archive bits of all
- * file entries. This has the desired effect of clearing archive bits
- * of all source files which have been copied.
- */
-
- void clear_archive_bits(char *src_dir)
-
- {
- ENTRY *Org_Ptr = Ptr;
- char source_file[FILENAME_MAX], *cur_name;
- int index, n;
-
- if ((Options & O_ARCHIVE) && (!(Options & O_CHECK))) {
- n = strlen(src_dir);
- strcpy(source_file, src_dir);
- cur_name = get_first(&index);
- while (Ptr != NULL) {
- if (Ptr->copied) {
- strcat(source_file, cur_name);
- _chmod(source_file, 1, ((Ptr->copied) & (~FA_ARCH)));
- source_file[n] = '\0';
- }
- if (Org_Ptr == Ptr)
- break;
- else
- cur_name = get_next(&index);
- }
- }
- }
-
- /*
- * clear_hash_tab()
- *
- * Input:
- * hash_tab - the hash table to be cleared
- * Output:
- * hash_tab - with all its entries cleared and all its
- * buckets set to NULL
- * Comments:
- * removes all entries from a hash table
- */
-
- void clear_hash_tab(ENTRY * hash_tab[])
-
- {
- int i;
- ENTRY *ptr, *temp;
-
- for (i = 0; i < HASH_TAB_SIZE; i++) {
- ptr = hash_tab[i];
- while (ptr != NULL) {
- temp = ptr;
- ptr = ptr->next;
- free(temp);
- }
- hash_tab[i] = NULL;
- }
- }
-
- /*
- * remove_entry()
- *
- * Input:
- * file - the name of the file to be removed
- * hash_tab - the hash table from which the file is to be
- * removed
- * Output:
- * hash_tab - the hash table with the file removed
- * Comments:
- * removes one entry from a hash table
- */
-
- void remove_entry(char *file, ENTRY * hash_tab[])
-
- {
- int bucket;
- ENTRY *ptr, *temp;
- ENTRY **lastptr;
-
- bucket = hashpjw(file);
- if (hash_tab[bucket] != NULL) {
- ptr = hash_tab[bucket];
- lastptr = &(hash_tab[bucket]);
- while (ptr != NULL) {
- if (!strcmp(file, ptr->name)) {
- *lastptr = ptr->next;
- free(ptr);
- break;
- }
- lastptr = &(ptr->next);
- ptr = ptr->next;
- }
- }
- }
-
- /*
- * find_entry()
- *
- * Input:
- * file - the name of the file to be found
- * hash_tab - the hash table which is to be searched
- * Output:
- * returns - a pointer to the entry in the hash table,
- * or NULL if not found
- * Comments:
- * finds an entry in the hash table
- */
-
- ENTRY *find_entry(char *file, ENTRY * hash_tab[])
-
- {
- int bucket;
- ENTRY *ptr, *temp;
-
- bucket = hashpjw(file);
- if (hash_tab[bucket] == NULL)
- ptr = NULL;
- else {
- ptr = hash_tab[bucket];
- while (ptr != NULL) {
- if (!strcmp(file, ptr->name)) {
- break;
- }
- ptr = ptr->next;
- }
- }
-
- return (ptr);
- }
-
- /*
- * copy_sub_dirs()
- *
- * Input:
- * src_dir - the source directory
- * dst_dir - the destination directory
- * file_spec - the command-line file list
- * num_args - the number of arguments in the file list
- * file_buf - the buffer for reading and writing files
- * buf_size - the size of 'file_buf'
- * Comments:
- * copies the files in the sub-directories if the recursive
- * mode is specified
- */
-
- void copy_sub_dirs(char *src_dir, char *dst_dir, char *file_spec[],
- int num_args, void *file_buf, unsigned long buf_size)
-
- {
- int done;
- char ref_list[MAXDIR];
- struct ffblk fblk;
-
- if (Options & O_RECURSIVE) {
- strcpy(ref_list, src_dir);
- strcat(ref_list, "*.*");
-
- done = findfirst(ref_list, &fblk, FA_DIREC);
- while (!done) {
- if ((fblk.ff_attrib & FA_DIREC) && (!is_special(fblk.ff_name))) {
- char new_src_dir[MAXDIR], new_dst_dir[MAXDIR];
-
- if (should_dir_copy(src_dir, dst_dir,
- fblk.ff_name, new_src_dir, new_dst_dir)) {
- clear_hash_tab(Src_tab);
- clear_hash_tab(Dst_tab);
- copy_files(new_src_dir, new_dst_dir,
- file_spec, num_args,
- file_buf, buf_size);
- }
- }
- done = findnext(&fblk);
- }
- }
- }
-
-
- /*
- * should_dir_copy()
- *
- * Input:
- * src_dir - the full path of the current source directory
- * dst_dir - the full path of the current destination directory
- * name - the name of the sub-directory
- * Output:
- * new_src_dir - the full path of the source sub-directory
- * new_dst_dir - the full path of the destination sub-directory
- * returns - 1 if sub-directory should be copied
- * 0 if sub-directory should NOT be copied
- * Comments:
- * determines whether a sub-directory should be copied
- */
-
- int should_dir_copy(char *src_dir, char *dst_dir, char *name,
- char *new_src_dir, char *new_dst_dir)
-
- {
- struct stat src_buf, dst_buf;
- int ret_src, ret_dst;
- int status;
- int ret_val;
-
- strcpy(new_src_dir, src_dir);
- strcat(new_src_dir, name);
-
- strcpy(new_dst_dir, dst_dir);
- if (Options & O_GATHER)
- new_dst_dir[strlen(new_dst_dir) - 1] = '\0'; /* chop slash */
- else
- strcat(new_dst_dir, name);
-
- ret_src = stat(new_src_dir, &src_buf);
- ret_dst = stat(new_dst_dir, &dst_buf);
-
- if (ret_src == -1) /* sub dir does not exist in source dir */
- ret_val = 0;
- else if (!(src_buf.st_mode & S_IFDIR)) /* src dir is a file */
- ret_val = 0;
- else if (Options & (O_GATHER|O_CHECK))
- ret_val = 1;
- else if (ret_dst == -1) { /* destination dir does not exist */
- status = mkdir(new_dst_dir);
- if (status) {
- fprintf(stderr, "unable to create directory\n");
- exit(-1);
- }
- ret_val = 1;
- } else
- ret_val = 1;
-
- strcat(new_src_dir, "\\");
- strcat(new_dst_dir, "\\");
-
- return (ret_val);
- }
-
- /*
- * should_file_copy()
- *
- * Input:
- * file - name of file to be copied
- * src_file - full path of file to be copied
- * Output:
- * returns: 1 if file should be copied/moved
- * 0 if file should NOT be copied/moved
- * Comments:
- * looks up the file name in the source and destination
- * hash tables and determines whether a file should be
- * copied/moved
- */
-
- int should_file_copy(char *file, char *src_file)
-
- {
- ENTRY *src, *dst;
-
- /* source does not exit */
- if ((src = find_entry(file, Src_tab)) != NULL) {
- if (Options & O_DATE_CHECK)
- if (!(within_date_range(src)))
- return 0;
-
- if (Options & O_ARCHIVE)
- if (!(src->attr & FA_ARCH))
- return 0;
-
- if ((dst = find_entry(file, Dst_tab)) != NULL) {
-
- if ((Options & (O_CP_IF_SRC_NEWER|O_COPY_IF_SRC_OLDER)) ==
- (O_CP_IF_SRC_NEWER|O_COPY_IF_SRC_OLDER))
- return 0;
-
- if (Options & O_CP_IF_SRC_NEWER)
- if (cmptime_entry(src, dst) <= 0L)
- return 0;
-
- if (Options & O_COPY_IF_SRC_OLDER)
- if (cmptime_entry(src, dst) >= 0L)
- return 0;
-
- }
- }
- else /* source file missing? of course don't copy (something's fishy!) */
- return 0;
-
- if (Options & O_INTERACTIVE) {
- char buf[MAXPATH + 20];
-
- sprintf(buf, "copy %s (Y/N/Q) ? ", src_file);
- return ask_user(buf); /* user has the final say-so */
- }
-
- return 1;
- }
-
-
-
- /*
- * cmptime_entry
- *
- * given two files, return positive if the first has a more recent modification
- * date/time, zero if the files have the same modification date/time or
- * negative if the second is more recent.
- */
-
- long cmptime_entry(ENTRY *a, ENTRY *b)
-
- {
- return (((unsigned long) a->fdate) << 16 | (unsigned long) a->ftime) -
- (((unsigned long) b->fdate) << 16 | (unsigned long) b->ftime);
- }
-
- int within_date_range(ENTRY *src)
-
- {
- int retval = 1;
- DATE_NODE *d = Fdate;
- TIME_NODE *t = Ftime;
- int saw_after_or_before = 0;
-
- /* AND the 'before' and 'after' modes */
- while (d != NULL) {
- if ((d->mode & D_BEFORE) || (d->mode & D_AFTER))
- saw_after_or_before = 1;
- if (((d->mode & D_BEFORE) && (src->fdate >= d->fdate)) ||
- ((d->mode & D_AFTER) && (src->fdate <= d->fdate))) {
- retval = 0;
- }
- d = d->next;
- }
-
- if (!saw_after_or_before)
- retval = 0;
- /* OR the 'on' modes */
- d = Fdate;
- while (d != NULL) {
- if ((d->mode & D_ON) && (src->fdate == d->fdate))
- retval = 1;
- d = d->next;
- }
-
-
- /* AND the 'before' and 'after' modes */
- if (retval)
- while (t != NULL) {
- if (((t->mode & D_BEFORE) &&
- (src->ftime >= t->ftime)) ||
- ((t->mode & D_AFTER) &&
- (src->ftime <= t->ftime)))
- retval = 0;
- t = t->next;
- }
-
- return retval;
- }
-
- /*
- * file_exists()
- *
- * Input:
- * name - full path of file
- * Output:
- * returns: 1 if file exists
- * 0 if file does NOT exist
- */
-
- int file_exists(char *name)
-
- {
- return (access(name, 0) == 0);
- }
-
- /*
- * get_file_buf()
- *
- * Input:
- * Output:
- * buf_size - size of buffer
- * returns - pointer to buffer
- */
-
- void *get_file_buf(unsigned long *buf_size)
-
- {
- void *buf_mem;
-
- *buf_size = (coreleft() < MAX_BUF) ? coreleft() : MAX_BUF;
-
- buf_mem = malloc(*buf_size);
-
- if (buf_mem == NULL) {
- fprintf(stderr, "could not allocate file buffer\n");
- exit(-1);
- }
-
- return (buf_mem);
- }
-
-
- /*
- * copy_file()
- *
- * Input:
- * dst_file - full path of destination file
- * src_file - full path of source file
- * buf_size - size of buffer for file i/o
- * File_buf - buffer for file i/o
- * Buf_ptr - pointer to next available memory in i/o buffer
- * Reading_flag - indicates whether 'reading:' has been printed
- * Comments:
- * copies source file to destination file
- */
-
- void copy_file(ENTRY *ptr, char *dst_file, char *src_file,
- unsigned long buf_size)
-
- {
- int src_handle, dst_handle;
- long bytes;
- int retval;
- long bytes_needed, bytes_left;
- struct ftime ftime_buf;
- long fsize;
- short fattr;
-
- if ((Options & O_MOVE) && (*src_file == *dst_file)) {
- if (!Reading_flag && (Options & O_VERBOSE)) {
- fprintf(stdout, "renaming file:\n");
- fprintf(stdout, "\t%s -> %s\n", src_file, dst_file);
- Reading_flag = 0;
- }
- if (rename_file(ptr, src_file, dst_file))
- clean_up_and_exit();
- } else {
- if ((src_handle = open(src_file, O_RDONLY | O_BINARY)) == -1) {
- fprintf(stderr, "unable to open file '%s' \n", src_file);
- clean_up_and_exit();
- }
- getftime(src_handle, &ftime_buf);
- fsize = filelength(src_handle);
- fattr = (Options & O_ARCHIVE) ? _chmod(src_file, 0, 0)
- : get_fmode(src_file);
- bytes_needed = sizeof(ENTRY *) + (strlen(src_file) + 1) +
- (strlen(dst_file) + 1) + sizeof(fsize) + fsize +
- sizeof(struct ftime) + sizeof(fattr);
- bytes_left = (char *) File_buf - (char *) Buf_ptr + buf_size;
-
- if ((bytes_needed > MAX_BUF) || (Options & O_INTERACTIVE)) {
- if (Buf_ptr != File_buf)
- write_buffer(File_buf);
- copy_file_unbuffered(src_handle, ptr, src_file, dst_file,
- fsize, &ftime_buf, fattr,
- buf_size);
- } else {
- if (bytes_left < bytes_needed)
- write_buffer(File_buf);
- if (!Reading_flag && (Options & O_VERBOSE)) {
- fprintf(stdout, "reading:\n");
- Reading_flag = 1;
- }
- if (Options & O_VERBOSE)
- fprintf(stdout, "\t%s\n", src_file);
- copy_file_to_buffer(src_handle, ptr, src_file, dst_file,
- &ftime_buf, fsize, fattr);
- }
- close(src_handle);
- }
- }
-
- /*
- * rename_file()
- *
- * Input:
- * ptr - pointer to hash table entry (so we can mark this as 'copied')
- * src_file - source file name (full path)
- * dst_file - destination file name (full path)
- * Comments:
- * renames a file. if the destination file already exits,
- * then it is deleted.
- */
-
- int rename_file(ENTRY *ptr, char *src_file, char *dst_file)
-
- {
- int old_attrib;
-
- if ((old_attrib = _chmod(src_file, 0, 0)) < 0) {
- fprintf(stderr, "cannot move file %s\n", src_file);
- return -1;
- }
- if (rename(src_file, dst_file) == -1) {
-
- if (file_exists(dst_file))
- if (delete_file(dst_file, '\0')) {
- if ((!(Options & O_BATCH)) &&
- (printf("Target %s protected - ", dst_file),
- !(ask_user("force move onto it (Y/N/Q)? ")))) {
- fprintf(stderr, "%s NOT moved to %s\n", src_file,
- dst_file);
- return -1;
- }
- if (delete_file(dst_file, '\1')) {
- fprintf(stderr, "could not remove %s\n", dst_file);
- return -1;
- }
- }
- if (old_attrib & FA_RDONLY)
- _chmod(src_file, 1, old_attrib & (~FA_RDONLY));
- if (rename(src_file, dst_file) == -1) {
- if (old_attrib & FA_RDONLY)
- _chmod(src_file, 1, old_attrib);
- fprintf(stderr, "cannot move file %s\n", src_file);
- return -1;
- } else if (old_attrib & FA_RDONLY)
- _chmod(dst_file, 1, old_attrib);
- }
- Copied_a_file = 1;
- ptr->copied = (old_attrib) ? old_attrib : FA_ARCH;
-
- return 0;
- }
-
- /*
- * copy_file_to_buffer()
- *
- * Input:
- * src_handle - source file handle
- * src_file - source file name (full path)
- * dst_file - destination file name (full path)
- * st_buf - stat buffer of source file
- * attrib - file access mode (contains hidden)
- * Output:
- * Buf_ptr - pointer to unused position in buffer
- * Comments:
- * copies the source file along with a header to memory.
- * the header contains source-file name, dest-file name,
- * source-file date, source-file size, and the source-file
- * modes.
- */
-
- void copy_file_to_buffer(int src_handle, ENTRY *ptr, char *src_file,
- char *dst_file, struct ftime *ftime_buf,
- long fsize, short fattr)
-
- {
- memcpy((char *) Buf_ptr, &ptr, sizeof(ENTRY *));
- Buf_ptr = (char *) Buf_ptr + sizeof(ENTRY *);
- strcpy((char *) Buf_ptr, src_file);
- Buf_ptr = (char *) Buf_ptr + strlen(src_file) + 1;
- strcpy((char *) Buf_ptr, dst_file);
- Buf_ptr = (char *) Buf_ptr + strlen(dst_file) + 1;
- memcpy(Buf_ptr, &fsize, sizeof(fsize));
- Buf_ptr = (char *) Buf_ptr + sizeof(long);
- memcpy(Buf_ptr, ftime_buf, sizeof(struct ftime));
- Buf_ptr = (char *) Buf_ptr + sizeof(struct ftime);
- memcpy(Buf_ptr, &fattr, sizeof(char));
- Buf_ptr = (char *) Buf_ptr + sizeof(char);
- read(src_handle, Buf_ptr, fsize);
- Buf_ptr = (char *) Buf_ptr + fsize;
- }
-
- /*
- * copy_file_unbuffered()
- *
- * Input:
- * src_handle - handle of source file
- * src_file - name of source file (full path name)
- * dst_file - name of destination file (full path name)
- * buf_size - size of file buffer
- * Reading_flag - indicates whether 'reading:' has been printed
- * File_buf - buffer for file i/o
- * Output:
- * Reading_flag - reset to indicate that the message
- * 'reading and writing file:' has been printed.
- * Comments:
- * copies the source file to the destination file without
- * buffering (as is done with smaller files). the file modes
- * and file date are also copied.
- */
-
- void copy_file_unbuffered(int src_handle, ENTRY *ptr,
- char *src_file, char *dst_file,
- long fsize, struct ftime *ftime_buf, short fattr,
- unsigned long buf_size)
-
- {
- int dst_handle;
- int retval;
- struct stat st_buf;
-
- fstat(src_handle, &st_buf);
- if (!access(src_file, 2)) /* weird problem with TURBO */
- st_buf.st_mode |= S_IWRITE;
-
- _fmode = O_BINARY;
- do {
- Retry = 0;
- if (open_dest_file(&dst_handle, dst_file,
- (fattr & FA_RDONLY) ? S_IREAD : S_IREAD | S_IWRITE))
- return;
- if (!Reading_flag && (Options & O_VERBOSE)) {
- fprintf(stdout, "reading and writing file:\n");
- fprintf(stdout, "\t%s -> %s\n", src_file, dst_file);
- Reading_flag = 0;
- }
-
- if (!(Options & O_LARGEFILES))
- lseek(src_handle, 0L, SEEK_SET);
- copy_file_contents(src_handle, dst_handle, src_file, dst_file,
- buf_size);
- } while (Retry);
-
- copy_file_dates(src_handle, dst_handle);
- if (Options & O_MOVE)
- delete_file(src_file, '\0');
- close(dst_handle);
- Copied_a_file = 1;
- if (Options & O_ARCHIVE)
- _chmod(dst_file, 1, fattr);
- else
- chmod(dst_file, fattr);
- ptr->copied = (fattr) ? fattr : FA_ARCH;
- }
-
- /*
- * ensure_dest_dir_exist
- *
- * given a destination file name, first ensure the existence of the directory
- * which will contain it. This function exists to make a target-disk swap work
- * together with the recursive option. Return non-zero on success, zero on
- * failure.
- */
-
- int ensure_dest_dir_exist(char *dst_file)
-
- {
- int stat_err, ret_val = 1;
- struct stat statbuf;
- char *p;
-
- if ((p = strrchr(dst_file, '\\')) == NULL)
- return 0;
- *p = '\0';
- if ((!(stat_err = stat(dst_file, &statbuf))) &&
- (!(statbuf.st_mode & S_IFDIR)))
- ret_val = 0;
- else if (stat_err)
- create_dir(dst_file);
- *p = '\\';
-
- return ret_val; /* if 'create_dir()' returns, it was
- * successful */
- }
-
- /*
- * write_to_fit_disk
- *
- * a previously attempted write wrote 0 bytes to the disk because it
- * detected that the disk could not accept the number of bytes given in
- * the 'write' call. This is an oddity of Borland C.
- *
- * find out how many bytes are free on the target drive and pass that number
- * to the 'write' command.
- */
-
- int write_to_fit_disk(int dst_handle, char *dst_file, void *file_buf,
- unsigned max_bytes_write)
-
- {
- struct dfree drv_free;
- long drive_remaining; /* # of bytes left on drive */
-
- getdfree(dst_file[0]-'A'+1, &drv_free);
- if ((drive_remaining = drv_free.df_avail * drv_free.df_bsec *
- drv_free.df_sclus) > MAX_BUF)
- return 0;
- return write(dst_handle, file_buf,
- (unsigned) ((drive_remaining < max_bytes_write)
- ? drive_remaining
- : max_bytes_write));
- }
-
- /*
- * target_disk_full
- *
- * called when the target disk is full. Depending on the options, it may
- * be possible to change target disks and go on.
- */
-
- void target_disk_full(char *dst_file, int dst_handle)
-
- {
- close(dst_handle);
- if (!(Options & O_LARGEFILES))
- delete_file(dst_file, '\1');
- if (ok_to_retry())
- if (ask_user("out of disk space, continue (Y/N/Q) ? ")) {
- if (Options & O_ZAPTARGET)
- zap_target(Org_dest_dir, 1);
- Retry = 1;
- }
- else
- clean_up_and_exit();
- else {
- fprintf(stderr, "out of disk space\n");
- clean_up_and_exit();
- }
- }
-
-
- /*
- * clean_up_and_exit
- *
- * error occurred (like write error/target full). Clean up (clear archive
- * bits of source files already copied) and exit.
- */
-
- void clean_up_and_exit()
-
- {
- clear_archive_bits(Cur_source_dir);
- exit(-1);
- }
-
- /*
- * copy_file_contents()
- *
- * Input:
- * src_handle - handle of source file
- * src_handle - handle of destination file
- * src_file - name of source file (full path name)
- * dst_file - name of destination file (full path name)
- * buf_size - size of file buffer
- * File_buf - buffer for file i/o
- * Comments:
- * copies the contents of the source file to the destination
- * file.
- */
-
- void copy_file_contents(int src_handle, int dst_handle, char *src_file,
- char *dst_file, unsigned long buf_size)
-
- {
- unsigned bytes_read, bytes_written;
- long last_read_pos;
-
- while (1) {
- last_read_pos = tell(src_handle);
- bytes_read = read(src_handle, File_buf, (unsigned) buf_size);
- if (((int) bytes_read) == -1) {
- fprintf(stderr, "Can't read file '%s'\n", src_file);
- exit(-1);
- }
- if (bytes_read) {
- bytes_written = write(dst_handle, File_buf, bytes_read);
- if (((int) bytes_written) == -1) {
- fprintf(stderr, "Can't write to file '%s'\n",
- dst_file);
- exit(-1);
- }
- } else
- break;
- if (bytes_read != bytes_written) {
- if (Options & O_LARGEFILES) {
- if (bytes_written == 0)
- bytes_written = write_to_fit_disk(dst_handle, dst_file,
- File_buf, bytes_read);
- lseek(src_handle, last_read_pos+bytes_written, SEEK_SET);
- }
- target_disk_full(dst_file, dst_handle);
- break;
- }
- }
- }
-
- /*
- * ok_to_retry()
- *
- * Input:
- * none
- * Comments:
- * checks if the target directory was used to determine the file
- * list. If it was, then the copy is aborted when disk is full
- */
-
- int ok_to_retry()
-
- {
- return ((!(Options & O_BATCH)) && (Options & O_TARGET_REMOVEABLE) &&
- (!(Options &
- (O_TARGET_DIR | O_COPY_IF_SRC_OLDER | O_CP_IF_SRC_NEWER))));
- }
-
- /*
- * write_buffer()
- *
- * Input:
- * file_buf - memory buffer containing file contents along
- * with their headers
- * File_buf - starting location of memory buffer
- * Output:
- * Reading_flag - reset to indicate recent output of message,
- * 'writing:'
- * Buf_ptr - location of available memory in memory buffer
- * Comments:
- * copies all the files contained in the memory buffer to their
- * destination files
- */
-
- void write_buffer(void *file_buf)
-
- {
- ENTRY *ptr;
- int dst_handle;
- char src_file[MAXDIR];
- char dst_file[MAXDIR];
- struct ftime ftime_buf;
- long fsize;
- short fattr;
-
- _fmode = O_BINARY;
- if ((Options & O_VERBOSE) && (file_buf < Buf_ptr))
- printf("writing:\n");
- Reading_flag = 0;
- while (file_buf < Buf_ptr) {
- file_buf = get_header_info(file_buf, &ptr, src_file, dst_file,
- &ftime_buf, &fsize, &fattr);
- if (!(Options & O_CHECK))
- if (!write_dest_file(&dst_handle, dst_file, file_buf, fsize,
- fattr)) {
- if (Options & O_MOVE)
- delete_file(src_file, '\1');
- Copied_a_file = 1;
- setftime(dst_handle, &ftime_buf);
- close(dst_handle);
- if (Options & O_ARCHIVE)
- _chmod(dst_file, 1, fattr);
- else
- chmod(dst_file, fattr);
- ptr->copied = (fattr) ? fattr : FA_ARCH;
- }
- file_buf = (char *) file_buf + fsize;
- }
- Buf_ptr = File_buf;
- }
-
- /*
- * get_header_info()
- *
- * Input:
- * file_buf - pointer to memory buffer containing file
- * contents and header
- * Output:
- * src_file - source file name (full path)
- * dst_file - destination file name (full path)
- * stat_buf - file status buffer
- * mode - mode settings of source file
- * returns - location of next file in memory buffer
- * Comments:
- * gets a file's header information from the memory buffer
- */
-
- void *get_header_info(void *file_buf, ENTRY ** ptr,
- char *src_file, char *dst_file, struct ftime * ftimebuf,
- long *fsize, short *fattr)
-
- {
- memcpy(ptr, (char *) file_buf, sizeof(ENTRY *));
- file_buf = (char *) file_buf + sizeof(ENTRY *);
- strcpy(src_file, (char *) file_buf);
- file_buf = (char *) file_buf + strlen((char *) file_buf) + 1;
- strcpy(dst_file, (char *) file_buf);
- file_buf = (char *) file_buf + strlen((char *) file_buf) + 1;
- memcpy(fsize, file_buf, sizeof(long));
- file_buf = (char *) file_buf + sizeof(long);
- memcpy(ftimebuf, file_buf, sizeof(struct ftime));
- file_buf = (char *) file_buf + sizeof(struct ftime);
- memcpy(fattr, file_buf, sizeof(char));
- file_buf = (char *) file_buf + sizeof(char);
- return (file_buf);
- }
-
- /*
- * write_dest_file()
- *
- * Input:
- * dst_handle - handle of file to be written
- * dst_file - full-path name of file to be written
- * file_buf - memory buffer containing file contents
- * file_size - size of file to be written
- * fattr - file attributes
- * Comments:
- * copies a file's contents from a memory buffer to a disk file.
- * Returns 0 normally, 1 if the destination couldn't be opened for write.
- */
-
- int write_dest_file(int *dst_handle, char *dst_file, void *file_buf,
- long file_size, int fattr)
-
- {
- unsigned bytes_written;
- long written_so_far = 0L;
-
- do {
- Retry = 0;
- if (Options & O_VERBOSE)
- printf("\t%s\n", dst_file);
- if (open_dest_file(dst_handle, dst_file, ((fattr & FA_RDONLY)
- ? S_IREAD
- : S_IREAD | S_IWRITE)))
- break;
- bytes_written = write(*dst_handle, ((char *) file_buf)+written_so_far,
- (unsigned) (file_size-written_so_far));
- if (((int) bytes_written) == -1){
- fprintf(stderr, "Can't write to file '%s'\n", dst_file);
- exit(-1);
- }
- if (bytes_written != (int) (file_size-written_so_far)) {
- if (Options & O_LARGEFILES) {
- if (bytes_written == 0)
- bytes_written =
- write_to_fit_disk(*dst_handle, dst_file,
- ((char *) file_buf)+written_so_far,
- (unsigned) (file_size-written_so_far));
- written_so_far += bytes_written;
- }
- target_disk_full(dst_file, *dst_handle);
- }
- else
- return 0;
- } while (Retry);
-
- return 1;
- }
-
- /*
- * open_dest_file()
- *
- * Input:
- * dst_handle - handle of file to be opened
- * dst_file - full-path name of file to be opened
- * mode - mode settings of file to be opened
- * Comments:
- * opens a file for write. If not successful because file is read-only,
- * tries to recover.
- */
-
- int open_dest_file(int *handle, char *name, unsigned modes)
-
- {
- if ((*handle = open((char *)name,
- (Options & O_JOIN)
- ? O_WRONLY | O_APPEND | O_CREAT | O_BINARY
- : O_WRONLY | O_TRUNC | O_CREAT | O_BINARY,
- modes)) == -1) {
- struct stat statbuf;
-
- if (stat(name, &statbuf)) {
- ensure_dest_dir_exist(name);
- if ((*handle = open((char *)name,
- (Options & O_JOIN)
- ? O_WRONLY | O_APPEND | O_CREAT | O_BINARY
- : O_WRONLY | O_TRUNC | O_CREAT | O_BINARY,
- modes)) < 0) {
- fprintf(stderr, "unable to open file '%s' for write\n", name);
- return -1;
- }
- } else if ((Options & O_BATCH) ||
- (printf("file '%s' is not writeable.\n", name),
- ask_user("Attempt to delete and overwrite it (Y/N/Q) ? "))) {
- delete_file(name, '\1');
- if ((*handle = open((char *)name,
- (Options & O_JOIN)
- ? O_WRONLY | O_APPEND | O_CREAT | O_BINARY
- : O_WRONLY | O_TRUNC | O_CREAT | O_BINARY,
- modes)) < 0) {
- fprintf(stderr, "unable to open file '%s' for write\n",
- name);
- return -1;
- }
- } else {
- printf("Skipped copy to '%s' (open for write failed).\n",
- name);
- return -1;
- }
- }
- return 0;
- }
-
- /*
- * usage()
- *
- * Comments:
- * outputs brief instructions on the proper use of docp
- */
-
- void usage()
-
- {
- fprintf(stdout, USAGE_MESS);
- exit(-1);
- }
-
- /*
- * get_flags()
- *
- * Input:
- * argv - command line arguments
- * argc - count of the command line arguments
- * Output:
- * From_file_ptr - pointer to file containing file list
- * Comments:
- * parses the flags specified on the command line, and sets
- * the appropriate bit fields in a variable called 'options'
- */
-
- void get_flags(char *argv[], int argc)
-
- {
- char c;
- char from_file[MAXDIR];
-
- while ((c = getopt(argc, argv, "abcd:f:ghijlmnorstvw:z?")) != EOF)
- switch (c) {
- case 'a': /* copy using archive bit */
- Options |= O_ARCHIVE;
- break;
- case 'b': /* batch mode - don't ask questions */
- Options |= O_BATCH;
- break;
- case 'c': /* check mode, don't copy files */
- Options |= O_VERBOSE | O_X_VERBOSE | O_CHECK;
- break;
- case 'd': /* date check */
- Options |= O_DATE_CHECK;
- set_Fdate(optarg);
- break;
- case 'f': /* file list from file */
- Options |= O_FROM_FILE;
- strcpy(from_file, optarg);
- if (!strcmp(from_file, "-"))
- Options |= O_FROM_STDIN;
- else {
- Options |= O_FROM_FILE;
- if ((From_file_ptr = fopen(from_file, "r"))
- == NULL) {
- fprintf(stderr, "unable to open '-f' file '%s'\n",
- from_file);
- exit(-1);
- }
- }
- break;
- case 'g': /* gather files into one directory */
- Options |= O_GATHER | O_RECURSIVE;
- break;
- case 'h': /* copy hidden files as well */
- Options |= O_COPY_HIDDEN;
- break;
- case 'i': /* interactive confirm */
- Options |= O_INTERACTIVE;
- break;
- case 'j': /* join files */
- Options |= O_JOIN;
- break;
- case 'l': /* large files (split) */
- Options |= O_LARGEFILES;
- break;
- case 'm': /* move mode */
- Options |= O_MOVE;
- break;
- case 'n': /* no action */
- Options |= O_CP_IF_SRC_NEWER;
- break;
- case 'o': /* copy if source is older */
- Options |= O_COPY_IF_SRC_OLDER;
- break;
- case 'r': /* update subdirectories */
- Options |= O_RECURSIVE;
- break;
- case 's': /* reference list from source */
- Options |= O_SOURCE_DIR;
- break;
- case 't': /* get file list from target */
- Options |= O_TARGET_DIR;
- break;
- case 'v': /* verbose */
- if (Options & O_VERBOSE)
- Options |= O_X_VERBOSE;
- else
- Options |= O_VERBOSE;
-
- break;
- case 'w': /* time check */
- Options |= O_TIME_CHECK;
- set_Ftime(optarg);
- break;
- case 'z': /* zap the target before copying */
- Options |= O_ZAPTARGET;
- break;
- case '?': /* documentation */
- show_doc();
- break;
- case '\0':
- usage();
- break;
- default:
- break;
- }
- set_defaults();
- }
-
- /*
- * set_defaults()
- *
- * Input:
- * none
- * Output:
- * none
- * Comments:
- * sets the default command-line flags
- */
-
- void set_defaults()
-
- {
- if (!(Options &
- (O_ARCHIVE | O_COPY_IF_SRC_OLDER | O_CP_IF_SRC_NEWER |
- O_DATE_CHECK | O_TIME_CHECK)))
- Options |= O_COPY_ALL;
-
- if (!(Options & (O_SOURCE_DIR | O_TARGET_DIR)))
- Options |= O_SOURCE_DIR;
-
- if ((Options & O_TIME_CHECK) && !(Options & O_DATE_CHECK)) {
- Options |= O_DATE_CHECK;
- set_todays_date();
- }
- }
-
- /*
- * check_flags()
- *
- * Input:
- * none
- * Comments:
- * terminates if the command-line flags are inconsistent
- */
-
- void check_flags()
-
- {
- if ((Options & O_SOURCE_DIR) && (Options & O_TARGET_DIR)) {
- fprintf(stderr, "specify only one of '-s' and '-t' options\n");
- exit(-1);
- }
-
- if ((Options & O_BATCH) && (Options & O_INTERACTIVE)) {
- fprintf(stderr, "specify only one of '-b' and '-i' options\n");
- exit(-1);
- }
- }
-
-
- /*
- * show_doc()
- *
- * Comments:
- * outputs expanded description of docp
- */
-
- void show_doc()
-
- {
- fprintf(stdout, FULL_DOC1);
- fprintf(stdout, FULL_DOC2);
- fprintf(stdout, FULL_DOC3);
- fprintf(stdout, FULL_DOC4);
- exit(0);
- }
-
- /*
- * set_Ftime()
- *
- * Input:
- * time_str - time string following '-w' option. includes relation
- * followed by time (e.g. "a3:15pm")
- * Output:
- * Ftime - global with reference time
- * Time_check_mode - global with relationship to reference time
- * Comments:
- * takes time string specified in '-w' option and stores the
- * time in Ftime and the relationship in Time_check_mode.
- */
-
- void set_Ftime(char *time_str)
-
- {
- TIME time;
- int i;
- char *time_arg = time_str;
-
- time.mode = 0;
- while ((*time_str == 'o') || (*time_str == 'b') || (*time_str == 'a'))
- switch (*time_str) {
- case 'o':
- time_str++;
- time.mode |= D_ON;
- break;
- case 'b':
- time_str++;
- time.mode |= D_BEFORE;
- break;
- case 'a':
- time_str++;
- time.mode |= D_AFTER;
- break;
- default:
- break;
- }
- time.hour = atoi(time_str);
- if ((time_str = get_field(time_str, (int *) &(time.min))) == NULL)
- bad_time(time_arg);
- while (*time_str != '\0')
- if (((*time_str == 'p') || (*time_str == 'P')) &&
- (time.hour < 13)) {
- time.hour += 12;
- break;
- } else
- time_str++;
-
- check_time(&time, time_arg);
- store_time(&time);
- }
-
- /*
- * store_time()
- *
- * Input:
- * time - structure containing time
- * Output:
- * Ftime - time in form returned by findnext()
- * Comments:
- * converts time to form returned by findnext()
- */
-
- void store_time(TIME *time)
-
- {
- TIME_NODE *d;
-
- if ((d = (TIME_NODE *) malloc(sizeof(TIME_NODE))) == NULL) {
- fprintf(stderr, "out of memory");
- exit(-1);
- }
- d->ftime = (time->min << 5) | (time->hour << 11);
- d->mode = time->mode;
- d->next = Ftime;
- Ftime = d;
- }
-
- /*
- * check_time()
- *
- * Input:
- * time - structure containing time
- * Comments:
- * does a crude check on the time entered
- */
-
- void check_time(TIME *time, char *time_arg)
-
- {
- if ((time->hour < 1) || (time->hour > 24) ||
- (time->min < 0) || (time->min > 60))
- bad_time(time_arg);
- }
-
- /*
- * bad_time()
- *
- * Comments:
- * termination routine called when a bad time is found
- */
-
- void bad_time(char *time_arg)
-
- {
- fprintf(stderr, "bad time specified, '%s'\n", time_arg);
- exit(-1);
- }
-
- /*
- * set_Fdate()
- *
- * Input:
- * date_str - date string following '-d' option. includes relation
- * followed by date (e.g. ">=3/23/91")
- * Output:
- * Fdate - global with reference date
- * Date_check_mode - global with relationship to reference date
- * Comments:
- * takes date string specified in '-d' option and stores the
- * date in Fdate and the relationship in Date_check_mode.
- */
-
- void set_Fdate(char *date_str)
-
- {
- DATE date;
- int *p;
- int i;
-
- date.mode = 0;
- while ((*date_str == 'o') || (*date_str == 'b') || (*date_str == 'a'))
- switch (*date_str) {
- case 'o':
- date_str++;
- date.mode |= D_ON;
- break;
- case 'b':
- date_str++;
- date.mode |= D_BEFORE;
- break;
- case 'a':
- date_str++;
- date.mode |= D_AFTER;
- break;
- default:
- break;
- }
-
- convert_date_str(&date, date_str);
- check_date(&date, date_str);
- store_date(&date);
- }
-
- /*
- * convert_date_str()
- *
- * Input:
- * date_str - date string from command line
- * Output:
- * date - numeric date structure
- * Comments:
- * converts command-line date string into numeric structure
- */
-
- void convert_date_str(DATE *date, char *date_str)
-
- {
- char *new_date_str;
-
- date->mo = atoi(date_str);
- if ((date_str = get_field(date_str, (int *) &(date->day))) == NULL)
- return;
- if ((date_str = get_field(date_str, (int *) &(date->year))) == NULL)
- return;
- }
-
-
- /*
- * get_field()
- *
- * Input:
- * date_str - current position in date string from command line
- * Output:
- * date_str - new position in date string from command line
- * date_field - numeric value of date field (day or year)
- * Comments:
- * gets numeric date from field of command-line date string
- */
-
- char *get_field(char *string, int *field)
-
- {
- char *new_string;
-
- new_string = strchr(string, '/');
- if (new_string == NULL)
- new_string = strchr(string, '-');
- if (new_string == NULL)
- new_string = strchr(string, ':');
- if (new_string == NULL)
- *field = 0;
- else {
- new_string++;
- *field = atoi(new_string);
- }
-
- return (new_string);
- }
-
- /*
- * set_todays_date()
- *
- * Output:
- * Fdate - adds today's date in date table with ON option set.
- * Comments:
- * stores today's date in date table. Done when user only
- * specifies time option without date option.
- */
-
- void set_todays_date()
-
- {
- DATE date;
- struct date from_os_date;
-
- get_todays_date(&date);
- date.mode = D_ON;
- store_date(&date);
- }
-
- /*
- * get_todays_date()
- *
- * Output:
- * date - today's date from the operating system
- * Comments:
- * gets the current date from the operating system
- */
-
- void get_todays_date(DATE *date)
-
- {
- struct date from_os_date;
-
- getdate(&from_os_date);
- date->year = from_os_date.da_year - 1900;
- date->mo = from_os_date.da_mon;
- date->day = from_os_date.da_day;
- }
-
- /*
- * store_date()
- *
- * Input:
- * date - structure containing date
- * Output:
- * Fdate - date in form returned by findnext()
- * Comments:
- * converts date to form returned by findnext()
- */
-
- void store_date(DATE *date)
-
- {
- DATE_NODE *d;
-
- if ((d = (DATE_NODE *) malloc(sizeof(DATE_NODE))) == NULL) {
- fprintf(stderr, "out of memory");
- exit(-1);
- }
- d->fdate = date->day | (date->mo << 5) | ((date->year - 80) << 9);
- d->mode = date->mode;
- d->next = Fdate;
- Fdate = d;
- }
-
- /*
- * check_date()
- *
- * Input:
- * date - structure containing date
- * date_str - date string from command line
- * Comments:
- * does a crude check on the date entered
- */
-
- void check_date(DATE *date, char *date_str)
-
- {
- if ((date->mo < 1) || (date->mo > 12) ||
- (date->day < 1) || (date->day > 31))
- bad_date(date_str);
- }
-
- /*
- * bad_date()
- *
- * Input:
- * date_str - date string from command line
- * Comments:
- * termination routine called when a bad date is found
- */
-
- void bad_date(char *date_str)
-
- {
- fprintf(stderr, "bad date specified '%s'\n", date_str);
- exit(-1);
- }
-
- /*
- * build_stdin_file_list()
- *
- * Output:
- * num_args - the number of args in the stdin file list
- * Comments:
- * builds linked list containing file list tokens from stdin.
- */
-
- void build_stdin_file_list(int *num_args)
-
- {
- char s[80];
-
- while (fgets(s, 79, stdin) != NULL) {
- zap_trailing_nl(s, 79, stdin); /* clobber newline */
- add_to_stdin_list(s);
- (*num_args)++;
- }
- if (*num_args == 0) {
- add_to_stdin_list("*.*");
- *num_args = 1;
- }
- }
-
-
- /*
- * add_to_stdin_list()
- *
- * input:
- * s - the file list token
- * Output:
- * Stdin_list_head - first element of file list
- * Stdin_list_tail - last element of file list
- * Comments:
- * adds a file list token to a linked list
- */
-
- void add_to_stdin_list(char *s)
-
- {
- STDIN_TOKEN *new_token;
-
- if ((new_token = (STDIN_TOKEN *) malloc(sizeof(STDIN_TOKEN))) == NULL) {
- fprintf(stderr, "out of memory");
- exit(-1);
- }
- if ((new_token->string = (char *) malloc(strlen(s) + 1)) == NULL) {
- fprintf(stderr, "out of memory");
- exit(-1);
- }
- strcpy(new_token->string, s);
- new_token->next = NULL;
- if (Stdin_list_head == NULL)
- Stdin_list_head = Stdin_list_tail = new_token;
- else {
- Stdin_list_tail->next = new_token;
- Stdin_list_tail = new_token;
- }
- }
-