コード例 #1
0
  /**
   * Opens file based on parameters and options, returning a FileDescriptor encapsulating the handle
   * to the open file.
   */
  private static FileDescriptor open(
      String pathForWindows, String pathToCheck, Flags flags, long pSecurityDescriptor)
      throws WindowsException {
    // set to true if file must be truncated after open
    boolean truncateAfterOpen = false;

    // map options
    int dwDesiredAccess = 0;
    if (flags.read) dwDesiredAccess |= GENERIC_READ;
    if (flags.write) dwDesiredAccess |= GENERIC_WRITE;

    int dwShareMode = 0;
    if (flags.shareRead) dwShareMode |= FILE_SHARE_READ;
    if (flags.shareWrite) dwShareMode |= FILE_SHARE_WRITE;
    if (flags.shareDelete) dwShareMode |= FILE_SHARE_DELETE;

    int dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL;
    int dwCreationDisposition = OPEN_EXISTING;
    if (flags.write) {
      if (flags.createNew) {
        dwCreationDisposition = CREATE_NEW;
        // force create to fail if file is orphaned reparse point
        dwFlagsAndAttributes |= FILE_FLAG_OPEN_REPARSE_POINT;
      } else {
        if (flags.create) dwCreationDisposition = OPEN_ALWAYS;
        if (flags.truncateExisting) {
          // Windows doesn't have a creation disposition that exactly
          // corresponds to CREATE + TRUNCATE_EXISTING so we use
          // the OPEN_ALWAYS mode and then truncate the file.
          if (dwCreationDisposition == OPEN_ALWAYS) {
            truncateAfterOpen = true;
          } else {
            dwCreationDisposition = TRUNCATE_EXISTING;
          }
        }
      }
    }

    if (flags.dsync || flags.sync) dwFlagsAndAttributes |= FILE_FLAG_WRITE_THROUGH;
    if (flags.overlapped) dwFlagsAndAttributes |= FILE_FLAG_OVERLAPPED;
    if (flags.deleteOnClose) dwFlagsAndAttributes |= FILE_FLAG_DELETE_ON_CLOSE;

    // NOFOLLOW_LINKS and NOFOLLOW_REPARSEPOINT mean open reparse point
    boolean okayToFollowLinks = true;
    if (dwCreationDisposition != CREATE_NEW
        && (flags.noFollowLinks || flags.openReparsePoint || flags.deleteOnClose)) {
      if (flags.noFollowLinks || flags.deleteOnClose) okayToFollowLinks = false;
      dwFlagsAndAttributes |= FILE_FLAG_OPEN_REPARSE_POINT;
    }

    // permission check
    if (pathToCheck != null) {
      SecurityManager sm = System.getSecurityManager();
      if (sm != null) {
        if (flags.read) sm.checkRead(pathToCheck);
        if (flags.write) sm.checkWrite(pathToCheck);
        if (flags.deleteOnClose) sm.checkDelete(pathToCheck);
      }
    }

    // open file
    long handle =
        CreateFile(
            pathForWindows,
            dwDesiredAccess,
            dwShareMode,
            pSecurityDescriptor,
            dwCreationDisposition,
            dwFlagsAndAttributes);

    // make sure this isn't a symbolic link.
    if (!okayToFollowLinks) {
      try {
        if (WindowsFileAttributes.readAttributes(handle).isSymbolicLink())
          throw new WindowsException("File is symbolic link");
      } catch (WindowsException x) {
        CloseHandle(handle);
        throw x;
      }
    }

    // truncate file (for CREATE + TRUNCATE_EXISTING case)
    if (truncateAfterOpen) {
      try {
        SetEndOfFile(handle);
      } catch (WindowsException x) {
        CloseHandle(handle);
        throw x;
      }
    }

    // make the file sparse if needed
    if (dwCreationDisposition == CREATE_NEW && flags.sparse) {
      try {
        DeviceIoControlSetSparse(handle);
      } catch (WindowsException x) {
        // ignore as sparse option is hint
      }
    }

    // create FileDescriptor and return
    FileDescriptor fdObj = new FileDescriptor();
    fdAccess.setHandle(fdObj, handle);
    return fdObj;
  }
    /**
     * Register a directory for changes as follows:
     *
     * <p>1. Open directory 2. Read its attributes (and check it really is a directory) 3. Assign
     * completion key and associated handle with completion port 4. Call ReadDirectoryChangesW to
     * start (async) read of changes 5. Create or return existing key representing registration
     */
    @Override
    Object implRegister(
        Path obj, Set<? extends WatchEvent.Kind<?>> events, WatchEvent.Modifier... modifiers) {
      WindowsPath dir = (WindowsPath) obj;
      boolean watchSubtree = false;

      // FILE_TREE modifier allowed
      for (WatchEvent.Modifier modifier : modifiers) {
        if (modifier == ExtendedWatchEventModifier.FILE_TREE) {
          watchSubtree = true;
        } else {
          if (modifier == null) return new NullPointerException();
          if (modifier instanceof com.sun.nio.file.SensitivityWatchEventModifier)
            continue; // ignore
          return new UnsupportedOperationException("Modifier not supported");
        }
      }

      // open directory
      long handle;
      try {
        handle =
            CreateFile(
                dir.getPathForWin32Calls(),
                FILE_LIST_DIRECTORY,
                (FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE),
                OPEN_EXISTING,
                FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED);
      } catch (WindowsException x) {
        return x.asIOException(dir);
      }

      boolean registered = false;
      try {
        // read attributes and check file is a directory
        WindowsFileAttributes attrs;
        try {
          attrs = WindowsFileAttributes.readAttributes(handle);
        } catch (WindowsException x) {
          return x.asIOException(dir);
        }
        if (!attrs.isDirectory()) {
          return new NotDirectoryException(dir.getPathForExceptionMessage());
        }

        // check if this directory is already registered
        FileKey fk =
            new FileKey(attrs.volSerialNumber(), attrs.fileIndexHigh(), attrs.fileIndexLow());
        WindowsWatchKey existing = fk2key.get(fk);

        // if already registered and we're not changing the subtree
        // modifier then simply update the event and return the key.
        if (existing != null && watchSubtree == existing.watchSubtree()) {
          existing.setEvents(events);
          return existing;
        }

        // Can overflow the int type capacity.
        // Skip WAKEUP_COMPLETION_KEY value.
        int completionKey = ++lastCompletionKey;
        if (completionKey == WAKEUP_COMPLETION_KEY) completionKey = ++lastCompletionKey;

        // associate handle with completion port
        try {
          CreateIoCompletionPort(handle, port, completionKey);
        } catch (WindowsException x) {
          return new IOException(x.getMessage());
        }

        // allocate memory for events, including space for other structures
        // needed to do overlapped I/O
        int size = CHANGES_BUFFER_SIZE + SIZEOF_DWORD + SIZEOF_OVERLAPPED;
        NativeBuffer buffer = NativeBuffers.getNativeBuffer(size);

        long bufferAddress = buffer.address();
        long overlappedAddress = bufferAddress + size - SIZEOF_OVERLAPPED;
        long countAddress = overlappedAddress - SIZEOF_DWORD;

        // zero the overlapped structure
        UNSAFE.setMemory(overlappedAddress, SIZEOF_OVERLAPPED, (byte) 0);

        // start async read of changes to directory
        try {
          createAndAttachEvent(overlappedAddress);

          ReadDirectoryChangesW(
              handle,
              bufferAddress,
              CHANGES_BUFFER_SIZE,
              watchSubtree,
              ALL_FILE_NOTIFY_EVENTS,
              countAddress,
              overlappedAddress);
        } catch (WindowsException x) {
          closeAttachedEvent(overlappedAddress);
          buffer.release();
          return new IOException(x.getMessage());
        }

        WindowsWatchKey watchKey;
        if (existing == null) {
          // not registered so create new watch key
          watchKey =
              new WindowsWatchKey(dir, watcher, fk)
                  .init(
                      handle,
                      events,
                      watchSubtree,
                      buffer,
                      countAddress,
                      overlappedAddress,
                      completionKey);
          // map file key to watch key
          fk2key.put(fk, watchKey);
        } else {
          // directory already registered so need to:
          // 1. remove mapping from old completion key to existing watch key
          // 2. release existing key's resources (handle/buffer)
          // 3. re-initialize key with new handle/buffer
          ck2key.remove(existing.completionKey());
          releaseResources(existing);
          watchKey =
              existing.init(
                  handle,
                  events,
                  watchSubtree,
                  buffer,
                  countAddress,
                  overlappedAddress,
                  completionKey);
        }
        // map completion map to watch key
        ck2key.put(completionKey, watchKey);

        registered = true;
        return watchKey;

      } finally {
        if (!registered) CloseHandle(handle);
      }
    }