confuse 0.1.0

A fuser-compatible filesystem API facade using Dokan on Windows and fuser elsewhere.
Documentation
macro_rules! handler_metadata {
    () => {
        fn set_end_of_file(
            &'h self, file_name: &widestring::U16CStr, offset: i64,
            _info: &dokan::OperationInfo<'c, 'h, Self>, context: &'c Self::Context,
        ) -> dokan::OperationResult<()> {
            let fs = self.fs.lock().map_err(|_| STATUS_NOT_IMPLEMENTED)?;
            let reply = ReplyAttr::capture();
            let req = request_from_ids(context.request_ids);
            let resolved = self
                .resolve_context_or_path(&*fs, &req, file_name, context)
                .map_err(errno_to_ntstatus)?;
            fs.setattr(
                &req,
                resolved.ino,
                None,
                None,
                None,
                Some(nonnegative_i64_to_u64(offset)?),
                None,
                None,
                None,
                None,
                None,
                None,
                None,
                None,
                reply.duplicate(),
            );
            let status = *reply.status.lock().map_err(|_| STATUS_NOT_IMPLEMENTED)?;
            self.drain_resolver_forgets(&*fs, &req);
            match status {
                Some(Ok(_)) => {
                    self.finish_metadata_mutation(&*fs, &req, file_name, resolved.ino);
                    Ok(())
                }
                Some(Err(err)) => Err(errno_to_ntstatus(err)),
                None => Err(missing_reply_status()),
            }
        }

        fn set_allocation_size(
            &'h self, file_name: &widestring::U16CStr, alloc_size: i64,
            _info: &dokan::OperationInfo<'c, 'h, Self>, context: &'c Self::Context,
        ) -> dokan::OperationResult<()> {
            let fs = self.fs.lock().map_err(|_| STATUS_NOT_IMPLEMENTED)?;
            let reply = ReplyEmpty::capture();
            let req = request_from_ids(context.request_ids);
            let resolved = self
                .resolve_context_or_path(&*fs, &req, file_name, context)
                .map_err(errno_to_ntstatus)?;
            allocation_size_with_context(&*fs, &req, resolved, alloc_size, reply.duplicate())?;
            let status = *reply.status.lock().map_err(|_| STATUS_NOT_IMPLEMENTED)?;
            self.drain_resolver_forgets(&*fs, &req);
            match status {
                Some(Ok(())) => {
                    self.finish_metadata_mutation(&*fs, &req, file_name, resolved.ino);
                    Ok(())
                }
                Some(Err(err)) => Err(classify_optional_probe_error(err).ntstatus()),
                None => Err(missing_reply_status()),
            }
        }

        fn set_file_attributes(
            &'h self, file_name: &widestring::U16CStr, file_attributes: u32,
            _info: &dokan::OperationInfo<'c, 'h, Self>, context: &'c Self::Context,
        ) -> dokan::OperationResult<()> {
            let fs = self.fs.lock().map_err(|_| STATUS_NOT_IMPLEMENTED)?;
            let reply = ReplyAttr::capture();
            let mode = if (file_attributes & FILE_ATTRIBUTE_READONLY) != 0 {
                Some(0o444_u32)
            } else {
                Some(0o644_u32)
            };
            let req = request_from_ids(context.request_ids);
            let resolved = self
                .resolve_context_or_path(&*fs, &req, file_name, context)
                .map_err(errno_to_ntstatus)?;
            fs.setattr(
                &req,
                resolved.ino,
                mode,
                None,
                None,
                None,
                None,
                None,
                None,
                None,
                None,
                None,
                None,
                None,
                reply.duplicate(),
            );
            let status = *reply.status.lock().map_err(|_| STATUS_NOT_IMPLEMENTED)?;
            self.drain_resolver_forgets(&*fs, &req);
            match status {
                Some(Ok(_)) => {
                    self.finish_metadata_mutation(&*fs, &req, file_name, resolved.ino);
                    Ok(())
                }
                Some(Err(err)) => Err(errno_to_ntstatus(err)),
                None => Err(missing_reply_status()),
            }
        }

        fn set_file_time(
            &'h self, file_name: &widestring::U16CStr, creation_time: dokan::FileTimeOperation,
            last_access_time: dokan::FileTimeOperation, last_write_time: dokan::FileTimeOperation,
            _info: &dokan::OperationInfo<'c, 'h, Self>, context: &'c Self::Context,
        ) -> dokan::OperationResult<()> {
            let fs = self.fs.lock().map_err(|_| STATUS_NOT_IMPLEMENTED)?;
            let reply = ReplyAttr::capture();
            let req = request_from_ids(context.request_ids);
            let resolved = self
                .resolve_context_or_path(&*fs, &req, file_name, context)
                .map_err(errno_to_ntstatus)?;
            fs.setattr(
                &req,
                resolved.ino,
                None,
                None,
                None,
                None,
                filetime_op_to_option(last_access_time).map(TimeOrNow::SpecificTime),
                filetime_op_to_option(last_write_time).map(TimeOrNow::SpecificTime),
                filetime_op_to_option(creation_time),
                None,
                filetime_op_to_option(creation_time),
                None,
                None,
                None,
                reply.duplicate(),
            );
            let status = *reply.status.lock().map_err(|_| STATUS_NOT_IMPLEMENTED)?;
            self.drain_resolver_forgets(&*fs, &req);
            match status {
                Some(Ok(_)) => {
                    self.finish_metadata_mutation(&*fs, &req, file_name, resolved.ino);
                    Ok(())
                }
                Some(Err(err)) => Err(errno_to_ntstatus(err)),
                None => Err(missing_reply_status()),
            }
        }

        fn get_disk_free_space(
            &'h self, _info: &dokan::OperationInfo<'c, 'h, Self>,
        ) -> dokan::OperationResult<dokan::DiskSpaceInfo> {
            let fs = self.fs.lock().map_err(|_| STATUS_NOT_IMPLEMENTED)?;
            let reply = ReplyStatfs::capture();
            let req = request_from_info(_info);
            fs.statfs(&req, INodeNo::ROOT, reply.duplicate());
            match *reply.status.lock().map_err(|_| STATUS_NOT_IMPLEMENTED)? {
                Some(Ok((blocks, bfree, bavail, _files, _ffree, bsize, _namelen, _frsize))) => {
                    Ok(dokan::DiskSpaceInfo {
                        byte_count: blocks.saturating_mul(bsize as u64),
                        free_byte_count: bfree.saturating_mul(bsize as u64),
                        available_byte_count: bavail.saturating_mul(bsize as u64),
                    })
                }
                Some(Err(err)) => Err(errno_to_ntstatus(err)),
                None => Err(missing_reply_status()),
            }
        }

        fn get_volume_information(
            &'h self, _info: &dokan::OperationInfo<'c, 'h, Self>,
        ) -> dokan::OperationResult<dokan::VolumeInfo> {
            let name = U16CString::from_str(self.volume_name.as_str())
                .map_err(|_| STATUS_NOT_IMPLEMENTED)?;
            let fs_name =
                U16CString::from_str(self.fs_name.as_str()).map_err(|_| STATUS_NOT_IMPLEMENTED)?;
            Ok(dokan::VolumeInfo {
                name,
                serial_number: 0xC0FFEE,
                max_component_length: 255,
                fs_flags: self.volume_flags,
                fs_name,
            })
        }
    };
}

macro_rules! handler_io_info {
    () => {
        fn read_file(
            &'h self, _file_name: &widestring::U16CStr, offset: i64, buffer: &mut [u8],
            _info: &dokan::OperationInfo<'c, 'h, Self>, context: &'c Self::Context,
        ) -> dokan::OperationResult<u32> {
            let fs = self.fs.lock().map_err(|_| STATUS_NOT_IMPLEMENTED)?;
            let reply = ReplyData::capture();
            let req = request_from_ids(context.request_ids);
            let resolved = self
                .resolve_context_or_path(&*fs, &req, _file_name, context)
                .map_err(errno_to_ntstatus)?;
            fs.read(
                &req,
                resolved.ino,
                resolved.fh,
                nonnegative_i64_to_u64(offset)?,
                checked_dokan_len(buffer.len())?,
                open_flags_from_fopen_flags(resolved.flags),
                lock_owner_from_context(resolved),
                reply.duplicate(),
            );
            let data_result = reply
                .data
                .lock()
                .map_err(|_| STATUS_NOT_IMPLEMENTED)?
                .clone();
            self.drain_resolver_forgets(&*fs, &req);
            match data_result {
                Some(Ok(data)) => {
                    let n = data.len().min(buffer.len());
                    buffer[..n].copy_from_slice(&data[..n]);
                    Ok(checked_dokan_len(n)?)
                }
                Some(Err(err)) => Err(errno_to_ntstatus(err)),
                None => Err(missing_reply_status()),
            }
        }

        fn write_file(
            &'h self, _file_name: &widestring::U16CStr, offset: i64, buffer: &[u8],
            info: &dokan::OperationInfo<'c, 'h, Self>, context: &'c Self::Context,
        ) -> dokan::OperationResult<u32> {
            let fs = self.fs.lock().map_err(|_| STATUS_NOT_IMPLEMENTED)?;
            let reply = ReplyWrite::capture();
            let req = request_from_ids(context.request_ids);
            let resolved = self
                .resolve_context_or_path(&*fs, &req, _file_name, context)
                .map_err(errno_to_ntstatus)?;
            let (offset, len) = dokan_write_plan(
                &*fs,
                &req,
                resolved,
                offset,
                buffer.len(),
                info.write_to_eof(),
                info.paging_io(),
            )?;
            let data = &buffer[..len];
            fs.write(
                &req,
                resolved.ino,
                resolved.fh,
                offset,
                data,
                write_flags(0),
                open_flags_from_fopen_flags(resolved.flags),
                lock_owner_from_context(resolved),
                reply.duplicate(),
            );
            let written = *reply.written.lock().map_err(|_| STATUS_NOT_IMPLEMENTED)?;
            self.drain_resolver_forgets(&*fs, &req);
            match written {
                Some(Ok(n)) => {
                    self.finish_metadata_mutation(&*fs, &req, _file_name, resolved.ino);
                    Ok(n)
                }
                Some(Err(err)) => Err(errno_to_ntstatus(err)),
                None => Err(missing_reply_status()),
            }
        }

        fn get_file_information(
            &'h self, file_name: &widestring::U16CStr, _info: &dokan::OperationInfo<'c, 'h, Self>,
            _context: &'c Self::Context,
        ) -> dokan::OperationResult<dokan::FileInfo> {
            let fs = self.fs.lock().map_err(|_| STATUS_NOT_IMPLEMENTED)?;
            let reply = ReplyAttr::capture();
            let req = request_from_ids(_context.request_ids);
            let resolved = self
                .resolve_context_or_path(&*fs, &req, file_name, _context)
                .map_err(errno_to_ntstatus)?;
            let cached_attr = {
                self.resolver
                    .lock()
                    .map_err(|_| STATUS_NOT_IMPLEMENTED)?
                    .cached_attr(resolved.ino)
            };
            if let Some(attr) = cached_attr {
                self.drain_resolver_forgets(&*fs, &req);
                return Ok(dokan::FileInfo {
                    attributes: filetype_to_windows_attr(attr.kind, attr.perm),
                    creation_time: attr.ctime,
                    last_access_time: attr.atime,
                    last_write_time: attr.mtime,
                    file_size: attr.size,
                    number_of_links: attr.nlink,
                    file_index: attr.ino.0,
                });
            }
            fs.getattr(&req, resolved.ino, Some(resolved.fh), reply.duplicate());
            let payload = *reply.payload.lock().map_err(|_| STATUS_NOT_IMPLEMENTED)?;
            self.drain_resolver_forgets(&*fs, &req);
            match payload {
                Some(Ok(payload)) => {
                    self.resolver
                        .lock()
                        .map_err(|_| STATUS_NOT_IMPLEMENTED)?
                        .remember_attr(payload.attr.ino, payload.attr, payload.ttl);
                    Ok(dokan::FileInfo {
                        attributes: filetype_to_windows_attr(payload.attr.kind, payload.attr.perm),
                        creation_time: payload.attr.ctime,
                        last_access_time: payload.attr.atime,
                        last_write_time: payload.attr.mtime,
                        file_size: payload.attr.size,
                        number_of_links: payload.attr.nlink,
                        file_index: payload.attr.ino.0,
                    })
                }
                Some(Err(err)) => Err(errno_to_ntstatus(err)),
                None => Err(missing_reply_status()),
            }
        }
    };
}