In OS/2 WARP 4 you may get the error SYS1186 while trying to copy files
with odd characters in their names (e.g. "²1■%E■.AX■") using XCOPY.
To resolve this problem, you must change the codepage to 437. To do this
either issue the command CHCP 437 for a temporary change, or change
the codepage line in the file CONFIG.SYS  to CODEPAGE=437,850 and
reboot the system to make the change permanent.
Please note that I cannot reproduce this error on my system with WARP 4 and Fixpack #1.
---------- * ----------
According to the OS/2 online help, XCOPY should return a return code of 2 if it cannot access one or more source or target files. In reality (OS/2 WARP 3 with Fixpack #17) XCOPY returns 0 in this case.
(Note: I've tried this again with WARP 4 Fixpack #5 - and at least in this environment XCOPY does return a return code of 2 in case of an error.)
To get around this bug, you can use a REXX program (see below) to call XCOPY, redirect its output to the REXX queue and check the contents of the REXX queue afterwards to get the results of the XCOPY command (see also The COPY command).
Warning: XCOPY is a version dependent program! Always use the XCOPY.EXE from the current active OS/2 version!!!
 
/* sample REXX cmd to get around some of the bugs of XCOPY            */
                    /* init global variables                          */
  sourceFiles = "*.*"
  targetFiles = "test1\*.*"
                    /* flush the current REXX queue                   */
  do i = 1 to queued(); parse pull; end;
  say "Now calling xcopy to copy " || ,
       sourceFiles || " to " || targetFiles || " ..."
                    /* execute XCOPY and redirect STDOUT and STDERR   */
                    /* into the REXX queue (because the filenames go  */
                    /* to STDOUT but the error messages go to STDERR) */
  "@xcopy" sourceFiles TargetFiles "2>>&1" "| rxqueue"
  say " ... done. The RC of XCOPY is " || rc || "."
  say
  say "Now checking the result ... "
  say
                    /* get no. of lines in the REXX queue             */
  qCount = queued()
                    /* number of files copied                         */
  filesCopied = 0
                    /* no. of files not copied due to source file     */
                    /* access errors                                  */
  sourceFileErrors = 0
                    /* no. of files not copied due to target file     */
                    /* access errors                                  */
  targetFileErrors = 0
                    /* no. of files not copied due to unknown errors  */
  unknownErrors = 0
                    /* error marker for the loop                      */
  errorFound = 0
  do i = 1 to qCount
    parse upper pull curLine
    curLine = strip( curLine )
    if curLine = "" then
      iterate
    select
      when errorFound = "SourceError" then
      do
        sourceFileErrors = sourceFileErrors + 1
        say " Error: XCOPY could not access the source file "
        say "        " || curLine
        errorFound = ""
      end /* when */
      when errorFound = "TargetError" then
      do
        targetFileErrors = targetFileErrors + 1
        say " Error: XCOPY could not access the target file "
        say "        " || curLine
        errorFound = ""
      end /* when */
      when word( errorFound,1 ) = "UnknownError" then
      do
        unknownErrors = unknownErrors + 1
                    /* check if the next line is the name of a file   */
        if stream( curLine, "c", "QUERY EXISTS" ) <> "" then
        do
          say " Error: XCOPY retrieved the error " || ,
              word( errorFound,2 ) || " accessing the file "
          say "        " || curLine
        end /* if stream( ... */
        else
          say " Error: XCOPY retrieved the error " || ,
              word( errorFound,2 )
        errorFound = ""
      end /* when */
                    /* SYS1186 - source file access error            */
      when left( curLine,7 ) = "SYS1186" then
        errorFound = "SourceError"
                    /* SYS1187 - target file access error            */
      when left( curLine,7 ) = "SYS1187" then
        errorFound = "TargetError"
      when left( curLine,3 ) = "SYS" & substr( curLine,8,1 ) = ":" then
        errorFound = "UnknownError" substr( curLine,1,7 )
      otherwise
                    /* ignore status output of XCOPY                  */
        if stream( curLine, 'c', 'QUERY EXISTS' ) <> '' then
          filesCopied = filesCopied + 1
    end /* select */
  end /* do i = 1 to qCount */
  say
  say "XCOPY copied " || filesCopied || " file(s)."
  filesNotCopied = sourceFileErrors + targetFileErrors + unknownErrors
  if filesNotCopied <> 0 then
  do
    if filesNotCopied <> 1 then
      say filesNotCopied || " file(s) were not copied due to access errors."
    else
      say filesNotCopied || " file was not copied due to access errors."
    say " " || sourceFileErrors  || ,
        " file(s) because of source file access errors, "
    say " " || targetFileErrors  || ,
        " file(s) because of target file access errors "
    say " and " || unknownErrors || " file(s) because of unknown errors."
  end /* if filesNotCopied <> 0 then */
  else
  do
    say " No errors found."
  end /* else */
exit 0