/** Forces any buffered output bytes to be written. */
  void flush() // @B2A - code relocated from IFSFileOutputStreamImplRemote,etc.
      throws IOException, AS400SecurityException {
    // Request that changes be committed to disk.
    IFSCommitReq req = new IFSCommitReq(fileHandle_);
    ClientAccessDataStream ds = null;
    try {
      ds = (ClientAccessDataStream) server_.sendAndReceive(req);
    } catch (ConnectionDroppedException e) {
      Trace.log(Trace.ERROR, "Byte stream server connection lost");
      connectionDropped(e);
    } catch (InterruptedException e) {
      Trace.log(Trace.ERROR, "Interrupted", e);
      throw new InterruptedIOException(e.getMessage());
    }

    // Verify that the request was successful.
    if (ds instanceof IFSReturnCodeRep) {
      int rc = ((IFSReturnCodeRep) ds).getReturnCode();
      if (rc != IFSReturnCodeRep.SUCCESS) {
        throwSecurityExceptionIfAccessDenied(path_, rc); // check for "access denied"
        Trace.log(Trace.ERROR, "IFSReturnCodeRep return code", descriptionForReturnCode(rc));
        throw new ExtendedIOException(path_, rc);
      }
    } else {
      // Unknown data stream.
      Trace.log(Trace.ERROR, "Unknown reply data stream", ds.data_);
      throw new InternalErrorException(
          Integer.toHexString(ds.getReqRepID()), InternalErrorException.DATA_STREAM_UNKNOWN);
    }
  }
 /** Copies a file or directory to another file or directory. */
 boolean copyTo(String destinationPath, boolean replace)
     throws AS400SecurityException, IOException {
   ClientAccessDataStream ds = null;
   IFSCopyReq req = new IFSCopyReq(path_, destinationPath, replace);
   try {
     ds = (ClientAccessDataStream) server_.sendAndReceive(req);
   } catch (ConnectionDroppedException e) {
     Trace.log(Trace.ERROR, "Byte stream connection lost during copy", e);
     connectionDropped(e);
   } catch (InterruptedException e) {
     Trace.log(Trace.ERROR, "Interrupted", e);
     throw new InterruptedIOException(e.getMessage());
   }
   if (ds instanceof IFSReturnCodeRep) {
     int rc = ((IFSReturnCodeRep) ds).getReturnCode();
     if (rc != IFSReturnCodeRep.SUCCESS) {
       String path = (rc == IFSReturnCodeRep.DUPLICATE_DIR_ENTRY_NAME ? destinationPath : path_);
       throwSecurityExceptionIfAccessDenied(path, rc); // check for "access denied"
       Trace.log(Trace.ERROR, "IFSReturnCodeRep return code", descriptionForReturnCode(rc));
       throw new ExtendedIOException(path, rc);
     }
     return true;
   } else {
     Trace.log(Trace.ERROR, "Unknown reply data stream", ds.data_);
     throw new InternalErrorException(
         Integer.toHexString(ds.getReqRepID()), InternalErrorException.DATA_STREAM_UNKNOWN);
   }
 }
  void close(int fileHandle) throws IOException {
    if (fileHandle == UNINITIALIZED) return; // @B8c

    // Close the file.  Send a close request to the server.
    ClientAccessDataStream ds = null;
    IFSCloseReq req = new IFSCloseReq(fileHandle);
    try {
      ds = (ClientAccessDataStream) server_.sendAndReceive(req);
    } catch (ConnectionDroppedException e) {
      Trace.log(Trace.ERROR, "Byte stream connection lost during close", e);
      connectionDropped(e);
    } catch (InterruptedException e) {
      Trace.log(Trace.ERROR, "Interrupted", e);
      throw new InterruptedIOException(e.getMessage());
    }

    // Validate the reply.
    if (ds instanceof IFSCloseRep) {
      int rc = ((IFSCloseRep) ds).getReturnCode();
      if (rc != 0) {
        Trace.log(Trace.ERROR, "IFSCloseRep return code", rc);
        throw new ExtendedIOException(path_, rc);
      }
    } else if (ds instanceof IFSReturnCodeRep) {
      int rc = ((IFSReturnCodeRep) ds).getReturnCode();
      if (rc != IFSReturnCodeRep.SUCCESS) {
        Trace.log(Trace.ERROR, "IFSReturnCodeRep return code", descriptionForReturnCode(rc));
        throw new ExtendedIOException(path_, rc);
      }
    } else {
      Trace.log(Trace.ERROR, "Unknown reply data stream", ds.data_);
      throw new InternalErrorException(
          Integer.toHexString(ds.getReqRepID()), InternalErrorException.DATA_STREAM_UNKNOWN);
    }
  }
  // @B8a
  boolean setLength(long length) throws IOException, AS400SecurityException {
    // Assume that we are connected to the server.

    // Prepare to issue a 'change attributes' request.
    ClientAccessDataStream ds = null;

    int fileHandle = UNINITIALIZED;

    try {
      // Open the file for read/write, get a file handle, and call 'change attributes'.
      fileHandle = createFileHandle(IFSOpenReq.WRITE_ACCESS, IFSOpenReq.OPEN_OPTION_FAIL_OPEN);
      if (fileHandle == UNINITIALIZED) {
        if (Trace.traceOn_)
          Trace.log(
              Trace.ERROR,
              "Unable to create handle to file " + path_ + ". IFSReturnCodeRep return code",
              errorRC_);
        return false;
      }
      IFSChangeAttrsReq req = new IFSChangeAttrsReq(fileHandle, length, serverDatastreamLevel_);
      ds = (ClientAccessDataStream) server_.sendAndReceive(req);
    } catch (ConnectionDroppedException e) {
      Trace.log(Trace.ERROR, "Byte stream server connection lost.");
      connectionDropped(e);
    } catch (InterruptedException e) {
      Trace.log(Trace.ERROR, "Interrupted");
      throw new InterruptedIOException(e.getMessage());
    } finally {
      close(fileHandle); // we don't need this handle anymore
    }

    // Verify the reply.
    boolean success = false;
    if (ds instanceof IFSReturnCodeRep) {
      int rc = ((IFSReturnCodeRep) ds).getReturnCode();
      if (rc == IFSReturnCodeRep.SUCCESS) success = true;
      else {
        throwSecurityExceptionIfAccessDenied(path_, rc); // check for "access denied"
        Trace.log(
            Trace.ERROR, path_ + ": IFSReturnCodeRep return code", descriptionForReturnCode(rc));
      }
    } else {
      // Unknown data stream.
      Trace.log(Trace.ERROR, "Unknown reply data stream", ds.data_);
      throw new InternalErrorException(
          Integer.toHexString(ds.getReqRepID()), InternalErrorException.DATA_STREAM_UNKNOWN);
    }

    // Back off the file pointer if needed.
    if (fileOffset_ > length) {
      fileOffset_ = length;
    }

    return success;
  }
  // Opens the file with specified access and option, and returns a file handle.
  // If failure, sets errorRC_ and returns UNINITIALIZED.
  int createFileHandle(int access, int openOption) // @D1C @B8c
      throws IOException, AS400SecurityException {
    int returnCode = IFSReturnCodeRep.FILE_NOT_FOUND;
    int fileHandle = UNINITIALIZED;
    errorRC_ = 0;

    // Try to open the file for the specified type of access.
    try {
      // Process an open file request.
      // For 3rd parm (file data CCSID), specify 0 since we don't care about CCSID.
      IFSOpenReq req =
          new IFSOpenReq(
              getPathnameAsBytes(),
              preferredServerCCSID_,
              0,
              access,
              IFSOpenReq.DENY_NONE,
              IFSOpenReq.NO_CONVERSION,
              openOption,
              serverDatastreamLevel_); // @D1C
      ClientAccessDataStream ds = (ClientAccessDataStream) server_.sendAndReceive(req);
      if (ds instanceof IFSOpenRep) {
        // The open was successful.  Close the file if appropriate.
        returnCode = IFSReturnCodeRep.SUCCESS;
        fileHandle = ((IFSOpenRep) ds).getFileHandle(); // @B8a
      } else if (ds instanceof IFSReturnCodeRep) {
        returnCode = ((IFSReturnCodeRep) ds).getReturnCode();
        throwSecurityExceptionIfAccessDenied(path_, returnCode); // check for "access denied"
      } else {
        // Unknown data stream.
        Trace.log(Trace.ERROR, "Unknown reply data stream", ds.data_);
        throw new InternalErrorException(
            Integer.toHexString(ds.getReqRepID()), InternalErrorException.DATA_STREAM_UNKNOWN);
      }
    } catch (ConnectionDroppedException e) {
      Trace.log(Trace.ERROR, "Byte stream server connection lost", e);
      connectionDropped(e);
    } catch (InterruptedException e) {
      Trace.log(Trace.ERROR, "Interrupted", e);
      throw new InterruptedIOException(e.getMessage());
    }

    if (returnCode != IFSReturnCodeRep.SUCCESS) {
      if (Trace.isTraceOn() && Trace.isTraceDiagnosticOn()) {
        Trace.log(
            Trace.DIAGNOSTIC,
            "Unable to open file " + path_ + ": " + "IFSReturnCodeRep return code",
            descriptionForReturnCode(returnCode));
      }
      errorRC_ = returnCode;
      return UNINITIALIZED;
    }

    return fileHandle;
  }
  IFSKey lock(
      long offset, // @B2A - code relocated from IFSFileOutputStreamImplRemote,etc.
      long length)
      throws IOException, AS400SecurityException {
    // Assume the arguments have been validated by the caller.

    // Attempt to lock the file.
    ClientAccessDataStream ds = null;
    try {
      // Issue a mandatory, exclusive lock bytes request.  Mandatory
      // means that the file system enforces the lock by causing any
      // operation which conflicts with the lock to fail.  Exclusive
      // means that only the owner of the lock can read or write the
      // locked area.
      IFSLockBytesReq req =
          new IFSLockBytesReq(fileHandle_, true, false, offset, length, serverDatastreamLevel_);
      ds = (ClientAccessDataStream) server_.sendAndReceive(req);
    } catch (ConnectionDroppedException e) {
      Trace.log(Trace.ERROR, "Byte stream server connection lost");
      connectionDropped(e);
    } catch (InterruptedException e) {
      Trace.log(Trace.ERROR, "Interrupted", e);
      throw new InterruptedIOException(e.getMessage());
    }

    // Verify the reply.
    if (ds instanceof IFSLockBytesRep) {
      int rc = ((IFSLockBytesRep) ds).getReturnCode();
      if (rc != 0) {
        Trace.log(Trace.ERROR, "IFSLockBytesRep return code", rc);
        throw new ExtendedIOException(path_, rc);
      }
    } else if (ds instanceof IFSReturnCodeRep) {
      int rc = ((IFSReturnCodeRep) ds).getReturnCode();
      if (rc != IFSReturnCodeRep.SUCCESS) {
        throwSecurityExceptionIfAccessDenied(path_, rc); // check for "access denied"
        Trace.log(Trace.ERROR, "IFSReturnCodeRep return code", descriptionForReturnCode(rc));
        throw new ExtendedIOException(path_, rc);
      }
    } else {
      // Unknown data stream.
      Trace.log(Trace.ERROR, "Unknown reply data stream", ds.data_);
      throw new InternalErrorException(
          Integer.toHexString(ds.getReqRepID()), InternalErrorException.DATA_STREAM_UNKNOWN);
    }

    // Generate the key for this lock.
    IFSKey key = new IFSKey(fileHandle_, offset, length, true);

    return key;
  }
  /**
   * Undoes a lock on this file.
   *
   * @param key The key for the lock.
   * @exception IOException If an error occurs while communicating with the server.
   * @see IFSKey
   * @see #lock
   */
  void unlock(IFSKey key) // @B2A - code relocated from IFSFileOutputStreamImplRemote,etc.
      throws IOException, AS400SecurityException {
    // Assume the argument has been validated by the caller.

    // Verify that this key is compatible with this file.
    if (key.fileHandle_ != fileHandle_) {
      Trace.log(Trace.ERROR, "Attempt to use IFSKey on different file stream.");
      throw new ExtendedIllegalArgumentException(
          "key", ExtendedIllegalArgumentException.PARAMETER_VALUE_NOT_VALID);
    }

    // Attempt to unlock the file.
    ClientAccessDataStream ds = null;
    // Issue an unlock bytes request.
    IFSUnlockBytesReq req =
        new IFSUnlockBytesReq(
            key.fileHandle_, key.offset_, key.length_, key.isMandatory_, serverDatastreamLevel_);
    try {
      ds = (ClientAccessDataStream) server_.sendAndReceive(req);
    } catch (ConnectionDroppedException e) {
      Trace.log(Trace.ERROR, "Byte stream server connection lost");
      connectionDropped(e);
    } catch (InterruptedException e) {
      Trace.log(Trace.ERROR, "Interrupted", e);
      throw new InterruptedIOException(e.getMessage());
    }

    // Verify the reply.
    if (ds instanceof IFSReturnCodeRep) {
      int rc = ((IFSReturnCodeRep) ds).getReturnCode();
      if (rc != IFSReturnCodeRep.SUCCESS) {
        throwSecurityExceptionIfAccessDenied(path_, rc); // check for "access denied"
        Trace.log(Trace.ERROR, "IFSReturnCodeRep return code", descriptionForReturnCode(rc));
        throw new ExtendedIOException(path_, rc);
      }
    } else {
      // Unknown data stream.
      Trace.log(Trace.ERROR, "Unknown reply data stream", ds.data_);
      throw new InternalErrorException(
          Integer.toHexString(ds.getReqRepID()), InternalErrorException.DATA_STREAM_UNKNOWN);
    }
  }
  /**
   * Reads up to <i>length</i> bytes of data from this input stream into <i>data</i>, starting at
   * the array offset <i>dataOffset</i>.
   *
   * @param data The buffer into which the data is read.
   * @param offset The start offset of the data in the buffer.
   * @param length The maximum number of bytes to read
   * @return The total number of bytes read into the buffer, or -1 if there is no more data because
   *     the end of file has been reached.
   * @exception ConnectionDroppedException If the connection is dropped unexpectedly.
   * @exception ExtendedIOException If an error occurs while communicating with the server.
   * @exception InterruptedIOException If this thread is interrupted.
   * @exception ServerStartupException If the server cannot be started.
   * @exception UnknownHostException If the system cannot be located.
   */
  int read(
      byte[] data, // @B2A - code relocated from IFSFileInputStreamImplRemote,etc.
      int dataOffset,
      int length)
      throws IOException, AS400SecurityException {
    // Assume the arguments have been validated by the public class.

    // If length is zero then return zero.
    if (length == 0) {
      return 0;
    }

    int totalBytesRead = 0;
    int bytesRemainingToRead = length;
    boolean endOfFile = false;
    while (totalBytesRead < length && !endOfFile) {
      // If the number of bytes being requested is greater than 16 million, then submit multiple
      // requests for smaller chunks.  The File Server has a limit that is somewhat below 16
      // megabytes (allowing for headers, etc), so 16 _million_ bytes is a safe limit.

      // Issue the read data request.
      int bytesToReadThisTime = Math.min(bytesRemainingToRead, MAX_BYTES_PER_READ);
      IFSReadReq req =
          new IFSReadReq(
              fileHandle_, fileOffset_,
              bytesToReadThisTime, serverDatastreamLevel_);
      ClientAccessDataStream ds = null;
      try {
        ds = (ClientAccessDataStream) server_.sendAndReceive(req);
      } catch (ConnectionDroppedException e) {
        Trace.log(Trace.ERROR, "Byte stream server connection lost");
        connectionDropped(e);
      } catch (InterruptedException e) {
        Trace.log(Trace.ERROR, "Interrupted", e);
        throw new InterruptedIOException(e.getMessage());
      }

      // Receive replies until the end of chain.
      boolean endOfChain = false;
      int bytesReadByThisRequest = 0;
      do {
        if (ds instanceof IFSReadRep) {
          // Copy the data from the reply to the data parameter.
          byte[] buffer = ((IFSReadRep) ds).getData();
          if (buffer.length > 0) {
            System.arraycopy(buffer, 0, data, dataOffset, buffer.length);
            bytesReadByThisRequest += buffer.length;
            dataOffset += buffer.length;
          } else // no data returned. This implies end-of-file (e.g. if file is empty).
          {
            bytesReadByThisRequest = -1;
            endOfFile = true;
          }
        } else if (ds instanceof IFSReturnCodeRep) {
          // Check for failure.
          int rc = ((IFSReturnCodeRep) ds).getReturnCode();

          if (rc == IFSReturnCodeRep.SUCCESS) { // It worked, so nothing special to do here.
          } else if (rc == IFSReturnCodeRep.NO_MORE_DATA) {
            // End of file.
            bytesReadByThisRequest = -1;
            endOfFile = true;
          } else // none of the above
          {
            throwSecurityExceptionIfAccessDenied(path_, rc); // check for "access denied"
            Trace.log(Trace.ERROR, "IFSReturnCodeRep return code", descriptionForReturnCode(rc));
            throw new ExtendedIOException(path_, rc);
          }
        } else // neither IFSReadRep nor IFSReturnCodeRep
        {
          // Unknown data stream.
          Trace.log(Trace.ERROR, "Unknown reply data stream", ds.data_);
          throw new InternalErrorException(
              Integer.toHexString(ds.getReqRepID()), InternalErrorException.DATA_STREAM_UNKNOWN);
        }

        // Get the next reply if not end of chain.
        endOfChain = ((IFSDataStream) ds).isEndOfChain();
        if (!endOfChain) {
          try {
            ds = (ClientAccessDataStream) server_.receive(req.getCorrelation());
          } catch (ConnectionDroppedException e) {
            Trace.log(Trace.ERROR, "Byte stream server connection lost");
            connectionDropped(e);
          } catch (InterruptedException e) {
            Trace.log(Trace.ERROR, "Interrupted", e);
            throw new InterruptedIOException(e.getMessage());
          }
        }
      } while (!endOfChain);

      // Advance the file pointer.
      if (bytesReadByThisRequest > 0) {
        incrementFileOffset(bytesReadByThisRequest);
        totalBytesRead += bytesReadByThisRequest;
        bytesRemainingToRead -= bytesReadByThisRequest;
      }
    }

    // If we have read zero bytes and hit end-of-file, indicate that by returning -1.
    // Otherwise return total number of bytes read.
    return (endOfFile && totalBytesRead == 0 ? -1 : totalBytesRead);
  }
  // Submit the specified request, and fetch list attributes reply(s).
  // The returned Vector contains IFSListAttrsRep objects.
  Vector listAttributes(IFSListAttrsReq req) throws IOException, AS400SecurityException {
    // Assume connect() has already been done.

    errorRC_ = 0;
    Vector replys = new Vector(256);
    ClientAccessDataStream ds = null;
    try {
      ds = (ClientAccessDataStream) server_.sendAndReceive(req);
    } catch (ConnectionDroppedException e) {
      Trace.log(Trace.ERROR, "Byte stream server connection lost.");
      connectionDropped(e);
    } catch (InterruptedException e) {
      Trace.log(Trace.ERROR, "Interrupted");
      throw new InterruptedIOException(e.getMessage());
    }

    // @A1A
    int rc = -1; // @A1A

    boolean done = false;
    do {
      if (ds instanceof IFSListAttrsRep) {
        replys.addElement(ds);
      } else if (ds instanceof IFSReturnCodeRep) {
        // If the return code is NO_MORE_FILES then all files
        // that match the specification have been returned.
        rc = ((IFSReturnCodeRep) ds).getReturnCode();

        if (rc != IFSReturnCodeRep.SUCCESS
            && // @D4A
            rc != IFSReturnCodeRep.NO_MORE_FILES
            && rc != IFSReturnCodeRep.FILE_NOT_FOUND
            && rc != IFSReturnCodeRep.PATH_NOT_FOUND) {
          throwSecurityExceptionIfAccessDenied(path_, rc); // check for "access denied"
          Trace.log(
              Trace.ERROR,
              "Error getting file attributes for file "
                  + path_
                  + ": "
                  + "IFSReturnCodeRep return code",
              descriptionForReturnCode(rc));
          throw new ExtendedIOException(path_, rc);
        }

      } else {
        // Unknown data stream.
        Trace.log(Trace.ERROR, "Unknown reply data stream", ds.data_); // @A9C
        throw new InternalErrorException(
            Integer.toHexString(ds.getReqRepID()), InternalErrorException.DATA_STREAM_UNKNOWN);
      }

      // Fetch the next reply if not already done.
      done = ((IFSDataStream) ds).isEndOfChain();
      if (!done) {
        try {
          ds = (ClientAccessDataStream) server_.receive(req.getCorrelation());
        } catch (ConnectionDroppedException e) {
          Trace.log(Trace.ERROR, "Byte stream server connection lost.");
          connectionDropped(e);
        } catch (InterruptedException e) {
          Trace.log(Trace.ERROR, "Interrupted");
          throw new InterruptedIOException(e.getMessage());
        }
      }
    } while (!done);

    // @A1A
    if (rc == IFSReturnCodeRep.PATH_NOT_FOUND) { // @A1A
      // If the directory or file does not exist, then return NULL.
      errorRC_ = rc;
      replys = null; // @A1A
    } // @A1A
    else { // @A1A
      // Set the vector capacity to the current size.
      replys.trimToSize();
    } // @A1A

    return replys;
  }
  void writeBytes(
      byte[] data, // @B2A - code relocated from IFSFileOutputStreamImplRemote,etc.
      int dataOffset,
      int length,
      boolean forceToStorage)
      throws IOException, AS400SecurityException {
    // Assume the arguments have been validated by the caller.

    // Send write requests until all data has been written.
    while (length > 0) {
      // Determine how much data can be written on this request.
      int writeLength = (length > maxDataBlockSize_ ? maxDataBlockSize_ : length);

      // Build the write request.  Set the chain bit if there is
      // more data to write.
      IFSWriteReq req =
          new IFSWriteReq(
              fileHandle_,
              fileOffset_,
              data,
              dataOffset,
              writeLength,
              0xffff,
              forceToStorage,
              serverDatastreamLevel_);
      if (length - writeLength > 0) {
        // Indicate that there is more to write.
        req.setChainIndicator(1);
      }

      // Send the request.
      ClientAccessDataStream ds = null;
      try {
        // Send the request and receive the response.
        ds = (ClientAccessDataStream) server_.sendAndReceive(req);
      } catch (ConnectionDroppedException e) {
        Trace.log(Trace.ERROR, "Byte stream server connection lost");
        connectionDropped(e);
      } catch (InterruptedException e) {
        Trace.log(Trace.ERROR, "Interrupted", e);
        throw new InterruptedIOException(e.getMessage());
      }

      // Check the reply.
      if (ds instanceof IFSWriteRep) {
        IFSWriteRep rep = (IFSWriteRep) ds;
        int rc = rep.getReturnCode();
        if (rc != 0) {
          Trace.log(Trace.ERROR, "IFSWriteRep return code", rc);
          throw new ExtendedIOException(path_, rc);
        }

        // Advance the file pointer the length of the data
        // written.
        int lengthWritten = writeLength - rep.getLengthNotWritten();
        incrementFileOffset(lengthWritten);
        dataOffset += lengthWritten;
        length -= lengthWritten;

        // Ensure that all data requested was written.
        if (lengthWritten != writeLength) {
          Trace.log(
              Trace.ERROR,
              "Incomplete write.  Only "
                  + Integer.toString(lengthWritten)
                  + " bytes of a requested "
                  + Integer.toString(writeLength)
                  + " were written.");
          throw new ExtendedIOException(path_, ExtendedIOException.UNKNOWN_ERROR);
        }
      } else if (ds instanceof IFSReturnCodeRep) {
        int rc = ((IFSReturnCodeRep) ds).getReturnCode();
        if (rc != IFSReturnCodeRep.SUCCESS) {
          throwSecurityExceptionIfAccessDenied(path_, rc); // check for "access denied"
          Trace.log(Trace.ERROR, "IFSReturnCodeRep return code", descriptionForReturnCode(rc));
          throw new ExtendedIOException(path_, rc);
        }
      } else {
        // Unknown data stream.
        Trace.log(Trace.ERROR, "Unknown reply data stream", ds.data_);
        throw new InternalErrorException(
            Integer.toHexString(ds.getReqRepID()), InternalErrorException.DATA_STREAM_UNKNOWN);
      }
    }
  }