		/*********************************
		 *                               *
		 *   Visual Shell v1.17  10/92   *
		 *                               *
		 *     by Torsten Jürgeleit      *
		 *                               *
		 *           dos part 1          *
		 *                               *
		 *********************************/

	/* Includes */

#include "includes.h"
#include "imports.h"
#include "protos.h"

	/* Copy selected entries */

   VOID
action_copy(VOID)
{
   struct FileRequest  *freq1 = &file_req[active_freq],
		       *freq2 = &file_req[(active_freq ? 0 : 1)];
   struct FileNode     *fnode;
   BYTE  *ptr, old_name[MAX_FILE_NAME_LEN + 1], dest[MAX_PATH_NAME_LEN + 1];
   ULONG old_pos;
   BPTR  lock, cd_lock;
   SHORT old_cursor_line = freq1->fr_CursorLine, error = VSH_STATUS_NORMAL;

   if ((freq1->fr_Mode == FREQ_MODE_NORMAL || freq1->fr_Mode ==
				 FREQ_MODE_FIND) && old_cursor_line != -1) {
      hcomp_freq_cursor(freq1);
      print_fkey_text(FKEY_MODE_NONE);

      /* Save name and pos of old cursor line node */
      fnode = get_file_node_under_cursor(freq1);
      strncpy(&old_name[0], &fnode->fn_Text[0], (size_t)fnode->fn_NameLen);
      old_name[fnode->fn_NameLen] = '\0';
      old_pos                     = fnode->fn_Pos;
      if (ptr = get_input(INPUT_MODE_COPY, &freq2->fr_DirName[0])) {
	 strcpy(&dest[0], ptr);
	 last1_answer = ANSWER_TYPE_YES;   /* Read protection */
	 last2_answer = ANSWER_TYPE_YES;   /* Overwrite */
	 cd_lock      = (BPTR)CurrentDir(freq1->fr_DirLock);
	 enable_abort = 1;
	 if (!freq1->fr_MarkedEntries) {

	    /* Copy entry under cursor only */
	    error = copy_single(freq1, fnode, &dest[0]);
	 } else {

	    /* Strip '/' from end of destination */
	    if ((ptr = &dest[0] + strlen(&dest[0]) - 1) > dest &&
					 *ptr == '/' && *(ptr - 1) != '/') {
	       *ptr = '\0';
	    }

	    /* If destination directory not exists then create it */
	    if (!(lock = quiet_lock(&dest[0], (LONG)SHARED_LOCK))) {
	       error = make_dir(&dest[0]);
	    } else {

	       /* Check if Destination is a directory */
	       if (Examine(lock, fib) == DOSFALSE) {
		  error = VSH_ERROR_EXAMINE_FAILED;
	       } else {
		  if (fib->fib_EntryType < 0) {
		     error = VSH_ERROR_MULTI_COPY_NO_DIR;
		  }
	       }
	       UnLock(lock);
	    }

	    /* Copy marked entries only */
	    if (error == VSH_STATUS_NORMAL) {
	       fnode = (struct FileNode *)freq1->fr_Display.d_List->mlh_Head;
	       do {
		  if (fnode->fn_Marked) {
		     move_freq_cursor(freq1, fnode, MOVE_MODE_NO_CURSOR);
		     if ((error = copy_multi(freq1, fnode, &dest[0])) ==
							VSH_STATUS_NORMAL) {
			/* Unmark copied entry and refresh info line */
			freq1->fr_MarkedSize -= fnode->fn_Size;
			freq1->fr_MarkedEntries--;
			fnode->fn_Marked = 0;
			print_freq_lines(freq1, (struct MinNode *)fnode,
				   (USHORT)freq1->fr_CursorLine, (USHORT)1);
			print_info_line(INFO_LINE_MODE_MARKED);
		     }
		  }
		  fnode = (struct FileNode *)fnode->fn_Node.mln_Succ;
	       } while (error == VSH_STATUS_NORMAL && freq1->fr_MarkedEntries);
	    }
	 }

	 /* After disabling ESC clear any pending break signal */
	 enable_abort = 0;
	 SetSignal(0L, (LONG)SIGBREAKF_CTRL_C);

	 /* Restore current directory and check date stamps of both directories */
	 CurrentDir(cd_lock);
	 check_date_stamp(freq1, READ_SAME_DIR_MODE_NO_CURSOR);
	 check_date_stamp(freq2, READ_SAME_DIR_MODE_NO_OUTPUT);
	 change_fkey_text();
      }
      restore_old_cursor_line(freq1, &old_name[0], old_pos, old_cursor_line);
   }
   print_status(error);
}
	/* Copy single entry to selected destination (dir or file) */

   SHORT
copy_single(struct FileRequest *freq, struct FileNode *fnode, BYTE *dest_ptr)
{
   BYTE  c, *ptr, *source = &path1_buffer[0], *dest = &path2_buffer[0],
	 *base_name = &file1_buffer[0];
   BPTR  source_lock, dest_lock;
   SHORT error = VSH_STATUS_NORMAL;

   /* Build full path name for source */
   build_path_name_from_file_node(source, freq, fnode);
   if (!(source_lock = quiet_lock(source, (LONG)SHARED_LOCK))) {
      error = VSH_ERROR_NO_SOURCE;
   } else {

      /* Build full path name for destination */
      strcpy(dest, dest_ptr);

      /* Check if copy goes to current dir */
      if ((ptr = BaseName(dest)) > dest) {

	 /* Strip '/' in front of base name of destination */
	 if (*ptr == '\0' && (ptr - 1) > dest && *(ptr - 1) == '/' &&
							*(ptr - 2) != '/') {
	    *--ptr = '\0';
	 }

	 /* Build directory name */
	 c    = *ptr;
	 *ptr = '\0';

	 /* If directory not exists then create it */
	 if (!(dest_lock = quiet_lock(dest, (LONG)SHARED_LOCK))) {
	    error = make_dir(dest);
	 } else {
	    UnLock(dest_lock);
	 }
	 *ptr = c;
      }
      if (error == VSH_STATUS_NORMAL) {
	 if (dest_lock = quiet_lock(dest, (LONG)SHARED_LOCK)) {

	    /* Source and destination are equal ? */
	    if (CompareLock(source_lock, dest_lock) ==  LCK_EQUAL) {
	       error = VSH_ERROR_COPY_ONTO_ITSELF;
	    } else {
	       if (Examine(dest_lock, fib) == DOSFALSE) {
		  error = VSH_ERROR_EXAMINE_FAILED;
	       } else {

		  /* Destination is a directory ? */
		  if (fib->fib_EntryType > 0) {
		     append_base_name(dest, fnode);
		  }
	       }
	    }
	    UnLock(dest_lock);
	 }
      }
      if (error == VSH_STATUS_NORMAL) {

	 /* Build full path name for destination */
	 if (*(ptr = BaseName(dest)) == '/') {
	    *base_name = '\0';
	 } else {
	    strcpy(base_name, ptr);

	    /* Strip '/' in front of base name of destination */
	    if ((ptr - 1) > dest && *(ptr - 1) == '/' && *(ptr - 2) != '/') {
	       ptr--;
	    }
	    *ptr = '\0';
	 }
	 if ((error = build_path_name_from_relative_path(dest,
					  dest)) == VSH_STATUS_NORMAL) {
	    TackOn(dest, base_name);

	    /* Do copy */
	    error = copy_file(source_lock, source, dest);
	 }
      }
      UnLock(source_lock);
   }
   return(error);
}
	/* Copy multiple entries to selected destination (dir only) */

   SHORT
copy_multi(struct FileRequest *freq, struct FileNode *fnode, BYTE *dest_ptr)
{
   BYTE  *source = &path1_buffer[0], *dest = &path2_buffer[0];
   BPTR  source_lock, dest_lock;
   SHORT error = VSH_STATUS_NORMAL;

   /* Build full path name for source */
   build_path_name_from_file_node(source, freq, fnode);
   if (!(source_lock = quiet_lock(source, (LONG)SHARED_LOCK))) {
      error = VSH_ERROR_NO_SOURCE;
   } else {

      /* Build full path name for destination */
      strcpy(dest, dest_ptr);
      if (!(dest_lock = quiet_lock(dest, (LONG)SHARED_LOCK))) {
	 error = VSH_ERROR_NO_DESTINATION;
      } else {

	 /* Source and destination equal ? */
	 if (CompareLock(source_lock, dest_lock) == LCK_EQUAL) {
	    error = VSH_ERROR_COPY_ONTO_ITSELF;
	 } else {

	    /* Build full path name for destination */
	    if ((error = build_path_name_from_relative_path(dest, dest)) ==
							VSH_STATUS_NORMAL) {
	       append_base_name(dest, fnode);

	       /* Do copy */
	       error = copy_file(source_lock, source, dest);
	    }
	 }
	 UnLock(dest_lock);
      }
      UnLock(source_lock);
   }
   return(error);
}
	/* Copy given entry */

   SHORT
copy_file(BPTR source_lock, BYTE *source, BYTE *dest)
{
   struct AnchorPath     *ap;
   struct FileInfoBlock  *fib1, *fib2;
   BPTR  dest_lock, cd_lock;
   BYTE  *source_ptr, *dest_ptr, *path, *base_name;
   LONG  rc;
   SHORT base_len, error = VSH_STATUS_NORMAL;

   /* Copy directory with contents */
   if (!(fib1 = AllocMem((LONG)sizeof(struct FileInfoBlock) +
			  sizeof(struct AnchorPath) + MAX_PATH_NAME_LEN + 1,
						      (LONG)MEMF_PUBLIC))) {
      error = VSH_ERROR_NO_COPY_BUFFER;
   } else {
      if (Examine(source_lock, fib1) == DOSFALSE) {
	 error = VSH_ERROR_EXAMINE_FAILED;
      } else {

	 /* Check type of entry */
	 if (fib1->fib_DirEntryType < 0) {

	    /* Copy file */
	    error = do_copy_file(source, dest, fib1);
	 } else {

	    /* Copy directory - create it if not already exists */
	    if (dest_lock = quiet_lock(dest, (LONG)SHARED_LOCK)) {
	       UnLock(dest_lock);
	    } else {
	       if ((error = make_dir(dest)) ==
					  VSH_ERROR_OBJECT_ALREADY_EXISTS) {
		  error = VSH_STATUS_NORMAL;
	       }
	       if (error == VSH_STATUS_NORMAL) {
		  error = clone_file_info_block(dest, fib1);
	       }
	    }
	    if (error == VSH_STATUS_NORMAL) {

	       /* Initialize ARP anchor path */
	       ap               = (struct AnchorPath *)((BYTE *)fib1 +
					      sizeof(struct FileInfoBlock));
	       ap->ap_BreakBits = SIGBREAKF_CTRL_C;
	       ap->ap_StrLen    = MAX_PATH_NAME_LEN;
	       ap->ap_Flags     = APF_DoWild;
	       fib2             = &ap->ap_Info;
	       path             = &ap->ap_Buf[0];

	       /* Append '/' to end of source and destination */
	       source_ptr = source + strlen(source);
	       if (*(source_ptr - 1) != ':') {
		  *source_ptr++ = '/';
	       }
	       dest_ptr = dest + strlen(dest);
	       if (*(dest_ptr - 1) != ':') {
		  *dest_ptr++ = '/';
	       }

	       /* Find first entry in selected directory */
	       cd_lock = CurrentDir(source_lock);
	       if (!(rc = FindFirst(star, ap))) {

		  /* Traverse through ALL directories in current directory */
		  do {

		     /* Get current base name */
		     base_name = BaseName(path);
		     base_len  = strlen(base_name);

		     /* Check type of current entry */
		     if (fib2->fib_DirEntryType < 0) {

			/* Copy file */
			strcpy(source_ptr, base_name);
			strcpy(dest_ptr, base_name);
			error = do_copy_file(source, dest, fib2);
		     } else {

			/* Copy directory */
			if (ap->ap_Flags & APF_DidDir) {
			   ap->ap_Flags &= ~APF_DidDir;   /* don't enter dir again */

			   /* Remove last directory name from source and destination */
			   source_ptr -= base_len + 1;
			   dest_ptr   -= base_len + 1;
			} else {
			   ap->ap_Flags |= APF_DoDir;   /* enter next dir */

			   /* Append next directory name to source and destination */
			   strcpy(source_ptr, base_name);
			   strcpy(dest_ptr, base_name);

			   /* Create next directory if not already exists */
			   if ((error = make_dir(dest)) ==
					  VSH_ERROR_OBJECT_ALREADY_EXISTS) {
			      error = VSH_STATUS_NORMAL;
			   }
			   if (error == VSH_STATUS_NORMAL) {
			      error = clone_file_info_block(dest, fib2);
			   }

			   /* Prepare end of source and destination */
			   source_ptr   += base_len;
			   *source_ptr++ = '/';
			   dest_ptr     += base_len;
			   *dest_ptr++   = '/';
			}
		     }
		  } while (error == VSH_STATUS_NORMAL &&
						      !(rc = FindNext(ap)));
	       }

	       /* Free AnchorChain and check error */
	       FreeAnchorChain(ap);
	       CurrentDir(cd_lock);
	       if (error == VSH_STATUS_NORMAL) {
		  switch (rc) {
		     case ERROR_NO_MORE_ENTRIES :
			break;
		     case ERROR_BREAK :
			error = VSH_ERROR_ABORTED;
			break;
		     default :
			error = VSH_ERROR_FINDFIRST_OR_FINDNEXT_FAILED;
			break;
		  }
	       }
	    }
	 }
      }
      FreeMem(fib1, (LONG)sizeof(struct FileInfoBlock) +
			 sizeof(struct AnchorPath) + MAX_PATH_NAME_LEN + 1);
   }
   return(error);
}
	/* Copy given file */

   SHORT
do_copy_file(BYTE *source, BYTE *dest, struct FileInfoBlock  *source_fib)
{
   BPTR  lock, source_fh, dest_fh;
   BYTE  *buffer;
   ULONG largest_chip, largest_fast, buffer_size, buffer_mode, block_size,
	 protection = source_fib->fib_Protection, size = source_fib->fib_Size;
   BOOL  read_protection = FALSE;
   SHORT error = VSH_STATUS_NORMAL;

   /* Check read protection of source */
   if (last1_answer != ANSWER_TYPE_ALL && protection & FIBF_READ) {
      switch (get_answer(ANSWER_MODE_COPY_NO_READ, source, last1_answer)) {
	 case ANSWER_TYPE_YES :
	    last1_answer = ANSWER_TYPE_YES;
	    break;
	 case ANSWER_TYPE_ALL :
	    last1_answer = ANSWER_TYPE_ALL;
	    break;
	 case ANSWER_TYPE_NO :
	    last1_answer = ANSWER_TYPE_NO;
	    error        = VSH_ERROR_SKIPPED;
	    break;
	 case ANSWER_TYPE_ESC :
	    last1_answer = ANSWER_TYPE_ESC;
	    error        = VSH_ERROR_ABORTED;
	    break;
      }
      if (error == VSH_STATUS_NORMAL) {

	 /* Clear read protection flag */
	 if (SetProtection(source, protection & ~FIBF_READ) == DOSFALSE) {
	    error = VSH_ERROR_SETPROTECTION_FAILED;
	 } else {
	    read_protection = TRUE;
	 }
      }
   }
   if (error == VSH_STATUS_NORMAL) {

      /* Check overwrite of destination */
      if (last2_answer != ANSWER_TYPE_ALL) {
	 if (lock = quiet_lock(dest, (LONG)SHARED_LOCK)) {
	    if (Examine(lock, fib) == DOSFALSE) {
	       error = VSH_ERROR_EXAMINE_FAILED;
	    } else {
	       if (fib->fib_EntryType != source_fib->fib_EntryType) {
		  error = VSH_ERROR_OBJECT_ALREADY_EXISTS;
	       } else {
		  switch (get_answer(ANSWER_MODE_COPY_OVERWRITE, dest,
							    last2_answer)) {
		     case ANSWER_TYPE_YES :
			last2_answer = ANSWER_TYPE_YES;
			break;
		     case ANSWER_TYPE_ALL :
			last2_answer = ANSWER_TYPE_ALL;
			break;
		     case ANSWER_TYPE_NO :
			last2_answer = ANSWER_TYPE_NO;
			error        = VSH_ERROR_SKIPPED;
			break;
		     case ANSWER_TYPE_ESC :
			last2_answer = ANSWER_TYPE_ESC;
			error        = VSH_ERROR_ABORTED;
			break;
		  }
	       }
	    }
	    UnLock(lock);
	 }
      }
   }
   if (error == VSH_STATUS_NORMAL) {

      /* Copy file */
      if (!(source_fh = Open(source, (LONG)MODE_OLDFILE))) {
	 error = VSH_ERROR_OPEN_FAILED;
      } else {
	 if (!(dest_fh = Open(dest, (LONG)MODE_NEWFILE))) {
	    error = VSH_ERROR_OPEN_FAILED;
	 } else {
	    if (size) {

	       /* Calc size of copy buffer and allocate it */
	       largest_chip = AvailMem((LONG)MEMF_LARGEST | MEMF_PUBLIC |
								 MEMF_CHIP);
	       largest_fast = AvailMem((LONG)MEMF_LARGEST | MEMF_PUBLIC |
								 MEMF_FAST);
	       if (largest_fast >= size) {
		  buffer_size = size;
		  buffer_mode = MEMF_PUBLIC | MEMF_FAST;
	       } else {
		  if (largest_chip >= size) {
		     buffer_size = size;
		     buffer_mode = MEMF_PUBLIC | MEMF_CHIP;
		  } else {
		     if (largest_fast >= largest_chip) {
			buffer_size = largest_fast;
			buffer_mode = MEMF_PUBLIC | MEMF_FAST;
		     } else {
			buffer_size = largest_chip;
			buffer_mode = MEMF_PUBLIC | MEMF_CHIP;
		     }
		  }
	       }
	       if (!(buffer = AllocMem(buffer_size, buffer_mode))) {
		  error = VSH_ERROR_NO_COPY_BUFFER;
	       } else {

		  /* Copy loop */
		  print_dos_status(DOS_MODE_COPY, source, dest);
		  while (size && error == VSH_STATUS_NORMAL) {
		     if (CheckAbort(NULL)) {
			error = VSH_ERROR_ABORTED;
		     } else {

			/* Read and write block of file */
			block_size = (size > buffer_size ? buffer_size :
								      size);
			if (Read(source_fh, buffer, block_size) !=
							       block_size) {
			   error = get_dos_error(VSH_ERROR_READ_FAILED);
			} else {
			   if (Write(dest_fh, buffer, block_size) !=
							       block_size) {
			      error = get_dos_error(VSH_ERROR_WRITE_FAILED);
			   } else {
			      size -= block_size;
			   }
			}
		     }
		  }
		  FreeMem(buffer, buffer_size);
	       }
	    }
	    Close(dest_fh);

	    /* If error then delete destination else clone it */
	    if (error != VSH_STATUS_NORMAL) {
	       do_delete_file(dest, 0L);
	    } else {
	       error = clone_file_info_block(dest, source_fib);
	    }
	 }
	 Close(source_fh);
      }
   }

   /* Restore protection flags */
   if (read_protection == TRUE) {
      if (SetProtection(source, protection) == DOSFALSE) {
	 error = get_dos_error(VSH_ERROR_SETPROTECTION_FAILED);
      }
   }

   /* If entry skipped then set normal status */
   if (error == VSH_ERROR_SKIPPED) {
      error = VSH_STATUS_NORMAL;
   }
   return(error);
}
	/* Clone file info block of source to destination */

   SHORT
clone_file_info_block(BYTE *path, struct FileInfoBlock  *fib)
{
   BPTR  lock;
   BSTR  base_name = CTOB(&line2_buffer[0]);
   BYTE  c, *ptr;
   SHORT error = VSH_STATUS_NORMAL;

   /* Clone protection bits, but clear ARCHIVE bit on destination */
   if (SetProtection(path, fib->fib_Protection & ~FIBF_ARCHIVE) == DOSFALSE) {
      error = VSH_ERROR_SETPROTECTION_FAILED;
   } else {

      /* Clone comment string */
      if (SetComment(path, &fib->fib_Comment[0]) == DOSFALSE) {

	 /* Don't complain if MS-DOOF */
	 if (IoErr() != ERROR_ACTION_NOT_KNOWN) {
	    error = VSH_ERROR_SETCOMMENT_FAILED;
	 }
      } else {

	 /* Save base name and get lock to parent directory */
	 CtoBStr(ptr = BaseName(path), base_name, (LONG)MAX_LINE_LEN);
	 if (*(ptr - 1) == '/') {
	    ptr--;
	 }
	 c    = *ptr;
	 *ptr = '\0';
	 if (!(lock = quiet_lock(path, (LONG)SHARED_LOCK))) {
	    error = VSH_ERROR_LOCK_FAILED;
	 } else {

	    /* Clone file date */
	    if (dos_packet(((struct FileLock *)BTOC(lock))->fl_Task, (LONG)
			       ACTION_SET_DATE, (LONG)NULL, lock, base_name,
					      &fib->fib_Date) == DOSFALSE) {
	       error = VSH_ERROR_SETDATE_FAILED;
	    }
	    UnLock(lock);
	 }
	 *ptr = c;
      }
   }
   return(error);
}
	/* Rename or move selected entries */

   VOID
action_rename_move(VOID)
{
   struct FileRequest  *freq1 = &file_req[active_freq],
		       *freq2 = &file_req[(active_freq ? 0 : 1)];
   struct FileNode     *fnode, *fvnode = (struct FileNode *)
				       freq1->fr_Display.d_FirstVisibleNode;
   BYTE  *ptr, old_name[MAX_FILE_NAME_LEN + 1], dest[MAX_PATH_NAME_LEN + 1];
   ULONG old_pos;
   BPTR  cd_lock, dest_lock;
   BOOL  read_dir = FALSE;
   SHORT old_cursor_line = freq1->fr_CursorLine, error = VSH_STATUS_NORMAL;

   if ((freq1->fr_Mode == FREQ_MODE_NORMAL || freq1->fr_Mode ==
				 FREQ_MODE_FIND) && old_cursor_line != -1) {
      hcomp_freq_cursor(freq1);
      print_fkey_text(FKEY_MODE_NONE);

      /* Save name and pos of old cursor line node */
      fnode = get_file_node_under_cursor(freq1);
      strncpy(&old_name[0], &fnode->fn_Text[0], (size_t)fnode->fn_NameLen);
      old_name[fnode->fn_NameLen] = '\0';
      old_pos                     = fnode->fn_Pos;

      /* Build destination name */
      if (!freq1->fr_MarkedEntries) {
	 ptr = &old_name[0];
      } else {
	 ptr = &freq2->fr_DirName[0];
      }
      if (ptr = get_input(INPUT_MODE_RENAME_MOVE, ptr)) {
	 strcpy(&dest[0], ptr);
	 last1_answer = ANSWER_TYPE_YES;   /* Read protection */
	 last2_answer = ANSWER_TYPE_YES;   /* Overwrite */
	 cd_lock      = (BPTR)CurrentDir(freq1->fr_DirLock);
	 enable_abort = 1;
	 if (!freq1->fr_MarkedEntries) {

	    /* Rename or move entry under cursor only */
	    print_info_line(INFO_LINE_MODE_EMPTY);
	    error = rename_move_single(freq1, fnode, &dest[0]);
	 } else {

	    /* Strip '/' from end of destination */
	    if ((ptr = &dest[strlen(&dest[0]) - 1]) > dest && *ptr == '/' &&
							*(ptr - 1) != '/') {
	       *ptr = '\0';
	    }

	    /* If destination directory not exists then create it */
	    if (dest_lock = quiet_lock(&dest[0], (LONG)SHARED_LOCK)) {
	       UnLock(dest_lock);
	    } else {
	       if ((error = make_dir(&dest[0])) == VSH_STATUS_NORMAL) {
		  if (check_date_stamp(freq1, READ_SAME_DIR_MODE_NO_READ) ==
						      VSH_STATUS_READ_DIR) {
		     read_dir = TRUE;
		  }
	       }
	    }

	    /* Rename or move marked entries only */
	    if (error == VSH_STATUS_NORMAL) {
	       fnode = (struct FileNode *)freq1->fr_Display.d_List->mlh_Head;
	       do {
		  if (fnode->fn_Marked) {
		     move_freq_cursor(freq1, fnode, MOVE_MODE_NO_CURSOR);
		     if ((error = rename_move_multi(freq1, fnode, &dest[0]))
						     == VSH_STATUS_NORMAL) {

			/* Unmark entry and refresh info line */
			freq1->fr_MarkedSize -= fnode->fn_Size;
			freq1->fr_MarkedEntries--;
			print_info_line(INFO_LINE_MODE_MARKED);
			fnode = remove_file_node(freq1, fnode);
		     }
		  } else {
		     fnode = (struct FileNode *)fnode->fn_Node.mln_Succ;
		  }
	       } while (freq1->fr_MarkedEntries && error ==
							 VSH_STATUS_NORMAL);
	       if (read_dir == TRUE) {
		  read_same_dir(freq1, READ_SAME_DIR_MODE_NO_CURSOR);
	       } else {
		  refresh_dir_info(freq1);
		  set_date_stamp(freq1);
	       }
	    }
	 }

	 /* After disabling ESC clear any pending break signal */
	 enable_abort = 0;
	 SetSignal(0L, (LONG)SIGBREAKF_CTRL_C);

	 /* Restore current directory and check date stamps of dest directory */
	 CurrentDir(cd_lock);
	 check_date_stamp(freq2, READ_SAME_DIR_MODE_NO_OUTPUT);
	 change_fkey_text();
      }
      restore_old_cursor_line(freq1, &old_name[0], old_pos, old_cursor_line);
   }
   print_status(error);
}
	/* Rename or move single entry to selected destination (dir or file) */

   SHORT
rename_move_single(struct FileRequest *freq, struct FileNode *fnode,
							     BYTE *dest_ptr)
{
   BYTE  c, *ptr, *source = &path1_buffer[0], *dest = &path2_buffer[0],
	 *base_name = &line1_buffer[0];
   BPTR  source_lock, dest_lock;
   LONG  cmp;
   BOOL  read_dir = FALSE, move_flag = FALSE;
   SHORT error = VSH_STATUS_NORMAL;

   /* Build full path name for source */
   build_path_name_from_file_node(source, freq, fnode);
   if (!(source_lock = quiet_lock(source, (LONG)SHARED_LOCK))) {
      error = VSH_ERROR_NO_SOURCE;
   } else {

      /* Build full path name for destination */
      strcpy(dest, dest_ptr);
      if (dest_lock = quiet_lock(dest, (LONG)SHARED_LOCK)) {
	 if (Examine(dest_lock, fib) == DOSFALSE) {
	    error = VSH_ERROR_EXAMINE_FAILED;
	 } else {

	    /* Check if same name was selected for destination -> only case change */
	    if ((cmp = CompareLock(source_lock, dest_lock)) != LCK_EQUAL) {

	       /* If destination is a directory then rename/move source to this one */
	       if (fib->fib_EntryType > 0) {
		  append_base_name(dest, fnode);
		  move_flag = TRUE;
	       }
	    }
	 }
      } else {

	 /* Check if rename goes to current dir */
	 if ((ptr = BaseName(dest)) == dest) {
	    cmp = LCK_VOLUME;
	 } else {

	    /* Strip '/' from end of destination */
	    if (*ptr == '\0' && (ptr - 1) > dest && *(ptr - 1) == '/' &&
							*(ptr - 2) != '/') {
	       *--ptr = '\0';
	    }

	    /* Build directory name */
	    c    = *ptr;
	    *ptr = '\0';

	    /* If destination directory not exists then create it */
	    if (!(dest_lock = quiet_lock(dest, (LONG)SHARED_LOCK))) {
	       if ((error = make_dir(dest)) == VSH_STATUS_NORMAL) {
		  if (check_date_stamp(freq, READ_SAME_DIR_MODE_NO_READ) ==
						      VSH_STATUS_READ_DIR) {
		     read_dir = TRUE;
		  }
		  if (!(dest_lock = quiet_lock(dest, (LONG)SHARED_LOCK))) {
		     error = VSH_ERROR_LOCK_FAILED;
		  } else {
		     cmp       = CompareLock(source_lock, dest_lock);
		     move_flag = TRUE;
		  }
	       }
	    } else {

	       /* Destination and current directory are the same ? */
	       if ((cmp = CompareLock(dest_lock, freq->fr_DirLock)) !=
								LCK_EQUAL) {
		  move_flag = TRUE;
	       }
	    }

	    /* If no base name then append it */
	    if ((*ptr = c) == '\0') {
	       append_base_name(dest, fnode);
	    }
	 }
      }

      /* Free source and destination lock before rename/move */
      UnLock(source_lock);
      if (dest_lock) {
	 UnLock(dest_lock);
      }
      if (error == VSH_STATUS_NORMAL) {

	 /* Build full path name for destination */
	 if (*(ptr = BaseName(dest)) == '/') {
	    *base_name = '\0';
	 } else {
	    strcpy(base_name, ptr);

	    /* Strip '/' in front of base name of destination */
	    if ((ptr - 1) > dest && *(ptr - 1) == '/' && *(ptr - 2) != '/') {
	       ptr--;
	    }
	    *ptr = '\0';
	 }
	 if ((error = build_path_name_from_relative_path(dest, dest)) ==
							VSH_STATUS_NORMAL) {
	    TackOn(dest, base_name);

	    /* Do rename or move */
	    if (cmp == LCK_EQUAL || cmp == LCK_VOLUME) {
	       error = rename_file(source, dest);
	    } else {
	       if ((error = copy_single(freq, fnode, dest)) ==
							VSH_STATUS_NORMAL) {
		  error = delete_file(freq, fnode);
	       }
	    }
	    if (error == VSH_STATUS_NORMAL) {
	       if (move_flag == FALSE) {
		  rename_file_node(freq, fnode, BaseName(dest));
	       } else {
		  remove_file_node(freq, fnode);
	       }
	    }
	 }

	 /* Read current directory again or only refresh display */
	 if (read_dir == TRUE) {
	    read_same_dir(freq, READ_SAME_DIR_MODE_NO_CURSOR);
	 } else {
	    refresh_dir_info(freq);
	    set_date_stamp(freq);
	 }
      }
   }
   return(error);
}
	/* Rename or move multiple entries to selected destination (dir only) */

   SHORT
rename_move_multi(struct FileRequest *freq, struct FileNode *fnode,
							     BYTE *dest_ptr)
{
   BYTE  *source = &path1_buffer[0], *dest = &path2_buffer[0];
   BPTR  source_lock, dest_lock;
   LONG  cmp;
   SHORT error = VSH_STATUS_NORMAL;

   /* Build full path name for source */
   build_path_name_from_file_node(source, freq, fnode);
   if (!(source_lock = quiet_lock(source, (LONG)SHARED_LOCK))) {
      error = VSH_ERROR_NO_SOURCE;
   } else {

      /* Build full path name for destination */
      strcpy(dest, dest_ptr);
      if (!(dest_lock = quiet_lock(dest, (LONG)SHARED_LOCK))) {
	 error = VSH_ERROR_NO_DESTINATION;
      } else {
	 if (Examine(dest_lock, fib) == DOSFALSE) {
	    error = VSH_ERROR_EXAMINE_FAILED;
	 } else {

	    /* Destination is a directory ? */
	    if (fib->fib_EntryType < 0) {
	       error = VSH_ERROR_MULTI_RENMOVE_NO_DIR;
	    } else {

	       /* Source and destination equal ? */
	       if ((cmp = CompareLock(source_lock, dest_lock)) == LCK_EQUAL) {
		  error = VSH_ERROR_RENMOVE_ONTO_ITSELF;
	       } else {

		  /* Free source and destination lock before rename/move */
		  UnLock(source_lock);
		  source_lock = NULL;
		  UnLock(dest_lock);
		  dest_lock = NULL;

		  /* Build full path name for destination */
		  if ((error = build_path_name_from_relative_path(dest,
					      dest)) == VSH_STATUS_NORMAL) {
		     /* Do rename or move */
		     if (cmp == LCK_VOLUME) {
			append_base_name(dest, fnode);
			error = rename_file(source, dest);
		     } else {
			if ((error = copy_multi(freq, fnode, dest)) ==
							VSH_STATUS_NORMAL) {
			   error = delete_file(freq, fnode);
			}
		     }
		  }
	       }
	    }
	 }
	 if (dest_lock) {
	    UnLock(dest_lock);
	 }
      }
      if (source_lock) {
	 UnLock(source_lock);
      }
   }
   return(error);
}
	/* Rename entry */

   SHORT
rename_file(BYTE *source, BYTE *dest)
{
   SHORT error = VSH_STATUS_NORMAL;

   if (CheckAbort(NULL)) {
      error = VSH_ERROR_ABORTED;
   } else {

      /* Do rename */
      print_dos_status(DOS_MODE_RENAME, source, dest);
      if (Rename(source, dest) == DOSFALSE) {
	 error = get_dos_error(VSH_ERROR_RENAME_FAILED);
      }
   }
   return(error);
}
