OutputStream (@NotNull VirtualFile file, Object requestor, long modStamp, long timeStamp) { return new ByteArrayOutputStream() { private boolean closed; // protection against user calling .close() twice @Override public void close() throws IOException { if (closed) return; super.close(); app.assertWriteAccessAllowed(); long oldLength = getLastRecordedLength(file); VFileContentChangeEvent event = new VFileContentChangeEvent( requestor, file, file.getModificationStamp(), modStamp, file.getTimeStamp(), -1, oldLength, count); List<VFileEvent> events = List.of(event); fireBeforeEvents(getPublisher(), events); final VFileEventTracker eventTracker; if (getVfsLogEx() == null) { eventTracker = null; } else { eventTracker = getVfsLogEx().getApplicationVFileEventsTracker().trackEvent(event); } NewVirtualFileSystem fs = getFileSystem(file); // `FSRecords.ContentOutputStream` already buffered, no need to wrap in `BufferedStream` try (OutputStream persistenceStream = writeContent(file, /*contentOfFixedSize: */ fs.isReadOnly())) { persistenceStream.write(buf, 0, count); } finally { try (OutputStream ioFileStream = fs.getOutputStream(file, requestor, modStamp, timeStamp)) { ioFileStream.write(buf, 0, count); } finally { closed = true; try { FileAttributes attributes = fs.getAttributes(file); // due to FS rounding, the timestamp of the file can significantly differ from the current time long newTimestamp = attributes != null ? attributes.lastModified : DEFAULT_TIMESTAMP; long newLength = attributes != null ? attributes.length : DEFAULT_LENGTH; executeTouch(file, false, event.getModificationStamp(), newLength, newTimestamp); } finally { if (eventTracker != null) eventTracker.completeEventTracking(); } fireAfterEvents(getPublisher(), events); } } } }; }