static UserPrincipal fromSid(long sidAddress) throws IOException { String sidString; try { sidString = ConvertSidToStringSid(sidAddress); if (sidString == null) { // pre-Windows XP system? throw new AssertionError(); } } catch (WindowsException x) { throw new IOException("Unable to convert SID to String: " + x.errorString()); } // lookup account; if not available then use the SID as the name Account account = null; String name; try { account = LookupAccountSid(sidAddress); name = account.domain() + "\\" + account.name(); } catch (WindowsException x) { name = sidString; } int sidType = (account == null) ? SidTypeUnknown : account.use(); if ((sidType == SidTypeGroup) || (sidType == SidTypeWellKnownGroup) || (sidType == SidTypeAlias)) // alias for local group { return new Group(sidString, sidType, name); } else { return new User(sidString, sidType, name); } }
static UserPrincipal lookup(String name) throws IOException { SecurityManager sm = System.getSecurityManager(); if (sm != null) { sm.checkPermission(new RuntimePermission("lookupUserInformation")); } // invoke LookupAccountName to get buffer size needed for SID int size = 0; try { size = LookupAccountName(name, 0L, 0); } catch (WindowsException x) { if (x.lastError() == ERROR_NONE_MAPPED) throw new UserPrincipalNotFoundException(name); throw new IOException(name + ": " + x.errorString()); } assert size > 0; // allocate buffer and re-invoke LookupAccountName get SID NativeBuffer sidBuffer = NativeBuffers.getNativeBuffer(size); try { int newSize = LookupAccountName(name, sidBuffer.address(), size); if (newSize != size) { // can this happen? throw new AssertionError("SID change during lookup"); } // return user principal return fromSid(sidBuffer.address()); } catch (WindowsException x) { throw new IOException(name + ": " + x.errorString()); } finally { sidBuffer.release(); } }
@Override void wakeup() throws IOException { try { PostQueuedCompletionStatus(port, WAKEUP_COMPLETION_KEY); } catch (WindowsException x) { throw new IOException(x.getMessage()); } }
/** Creates an I/O completion port and a daemon thread to service it */ WindowsWatchService(WindowsFileSystem fs) throws IOException { // create I/O completion port long port = 0L; try { port = CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0); } catch (WindowsException x) { throw new IOException(x.getMessage()); } this.poller = new Poller(fs, this, port); this.poller.start(); }
/** * Open/creates file, returning AsynchronousFileChannel to access the file * * @param pathForWindows The path of the file to open/create * @param pathToCheck The path used for permission checks (if security manager) * @param pool The thread pool that the channel is associated with */ static AsynchronousFileChannel newAsynchronousFileChannel( String pathForWindows, String pathToCheck, Set<? extends OpenOption> options, long pSecurityDescriptor, ThreadPool pool) throws IOException { Flags flags = Flags.toFlags(options); // Overlapped I/O required flags.overlapped = true; // default is reading if (!flags.read && !flags.write) { flags.read = true; } // validation if (flags.append) throw new UnsupportedOperationException("APPEND not allowed"); // open file for overlapped I/O FileDescriptor fdObj; try { fdObj = open(pathForWindows, pathToCheck, flags, pSecurityDescriptor); } catch (WindowsException x) { x.rethrowAsIOException(pathForWindows); return null; } // create the AsynchronousFileChannel try { return WindowsAsynchronousFileChannelImpl.open(fdObj, flags.read, flags.write, pool); } catch (IOException x) { // IOException is thrown if the file handle cannot be associated // with the completion port. All we can do is close the file. long handle = fdAccess.getHandle(fdObj); CloseHandle(handle); throw x; } }
/** Poller main loop */ @Override public void run() { for (; ; ) { CompletionStatus info; try { info = GetQueuedCompletionStatus(port); } catch (WindowsException x) { // this should not happen x.printStackTrace(); return; } // wakeup if (info.completionKey() == WAKEUP_COMPLETION_KEY) { boolean shutdown = processRequests(); if (shutdown) { return; } continue; } // map completionKey to get WatchKey WindowsWatchKey key = ck2key.get((int) info.completionKey()); if (key == null) { // We get here when a registration is changed. In that case // the directory is closed which causes an event with the // old completion key. continue; } boolean criticalError = false; int errorCode = info.error(); int messageSize = info.bytesTransferred(); if (errorCode == ERROR_NOTIFY_ENUM_DIR) { // buffer overflow key.signalEvent(StandardWatchEventKinds.OVERFLOW, null); } else if (errorCode != 0 && errorCode != ERROR_MORE_DATA) { // ReadDirectoryChangesW failed criticalError = true; } else { // ERROR_MORE_DATA is a warning about incomplete // data transfer over TCP/UDP stack. For the case // [messageSize] is zero in the most of cases. if (messageSize > 0) { // process non-empty events. processEvents(key, messageSize); } else if (errorCode == 0) { // insufficient buffer size // not described, but can happen. key.signalEvent(StandardWatchEventKinds.OVERFLOW, null); } // start read for next batch of changes try { ReadDirectoryChangesW( key.handle(), key.buffer().address(), CHANGES_BUFFER_SIZE, key.watchSubtree(), ALL_FILE_NOTIFY_EVENTS, key.countAddress(), key.overlappedAddress()); } catch (WindowsException x) { // no choice but to cancel key criticalError = true; } } if (criticalError) { implCancelKey(key); key.signal(); } } }
/** * 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); } }