Win NFS by FUSE

一个C++实现的FUSE网络文件系统,客户端linux 服务端 Windows

服务端

#include "FuseServer.h"
#include <iostream>
#include <string>
#include <cstdlib>
#include <cstring>

#ifdef _WIN32
#include <WinSock2.h>
#include <Windows.h>
#include <io.h>

#else//!_WIN32
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>
#endif // _WIN32

#include <filesystem>
#include <fstream>
#include <sstream>
#include <vector>
#include <map>
#include <mutex>
#include <thread>
#include <chrono>
#include <new>
#include "FS_Util.h"
#include "HandleMgr.h"

using namespace std;
#include "SocketApi.h"
#include "FuseCommon.h"
#include "SockMgr.h"
#include "win_lowio.h"
#include "Utils.h"

#ifdef _WIN32
namespace fs = std::experimental::filesystem::v1;
#else//!_WIN32
namespace fs = std::filesystem;
#endif // _WIN32

// 处理认证请求
bool handle_authenticate(HSOCKET client_socket, const CommunicationPacket &request)
{
	ResponsePkt response;
	response.init(request);

	// 检查密码是否正确
	if (std::string(request.auth.password) == string(AUTH_PASSWORD))
	{
		response.response.status = ResponseStatus::FU_SUCCESS;
		print_with_time_and_thread(LOG_WARN, "Authentication successful\n");
	}
	else
	{
		response.response.status = ResponseStatus::FU_AUTH_FAILED;
		print_with_time_and_thread(LOG_ERROR, "Authentication failed\n");
	}

	skapi_send(client_socket, (char*)&response, sizeof(response));
	return response.response.status == ResponseStatus::FU_SUCCESS;
}

string make_this_file_path(const CommunicationPacket &request)
{
	string x = SHARE_DIR + "/" + request.path;
	Utils::_FormatWindowsPathA(x);
	return x;
}

// 处理GET_ATTR请求
void handle_get_attr(HSOCKET client_socket, const CommunicationPacket &request)
{
	ResponsePkt response;
	response.init(request);

	std::string full_path = make_this_file_path(request);

	FsAttr attr;
	int et = 0, er = 0;
	if (FsUtil_GetAttr(full_path.c_str(), attr, et, er))
	{
		memset(&response.response.mustat, 0, sizeof(response.response.mustat));
		fill_fa(response.response.mustat, attr);

		response.response.status = ResponseStatus::FU_SUCCESS;
		print_with_time_and_thread(LOG_DEBUG, "GET_ATTR successful for path: %s\n", full_path.c_str());
	}
	else
	{
		response.response.status = ResponseStatus::FU_NOT_FOUND;
		print_with_time_and_thread(LOG_ERROR, "GET_ATTR failed for path: %s, et: %d, er: %d\n", full_path.c_str(), et, er);
	}
	skapi_send(client_socket, (char*)&response, sizeof(response));
}

// 处理READ_DIR请求
void handle_read_dir(HSOCKET client_socket, const CommunicationPacket &request)
{
	std::string full_path = make_this_file_path(request);
	std::stringstream ss;

	try
	{
		// 读取目录内容
		ss << "0|." << std::endl;
		ss << "0|.." << std::endl;
		for (const auto &entry : fs::directory_iterator(full_path))
		{
			//文件属性
			std::string file_path = entry.path().u8string();
			FsAttr fa = {};
			int et = 0, er = 0;
			if (!FsUtil_GetAttr(file_path.c_str(), fa, et, er))
			{
				print_with_time_and_thread(LOG_ERROR, "READ_DIR failed getattr path: %s %d-%d\n", full_path.c_str(), et, er);
			}
			ss << FA2str(fa) << "|";
			ss << entry.path().filename().u8string() << std::endl;
		}

		std::string dir_content = ss.str();
		size_t al = sizeof(ResponsePkt) + dir_content.length() + 1;
		ResponsePkt *rList = (ResponsePkt*)malloc(al);
		if (rList)
		{
			rList->init(request);
			rList->set_variable_data(dir_content.c_str(), (uint32_t)(dir_content.length() + 1), (uint32_t)(al + 1));
			rList->response.status = ResponseStatus::FU_SUCCESS;
			skapi_send(client_socket, (char*)rList, (int)(rList->get_total_need()));
			print_with_time_and_thread(LOG_DEBUG, "READ_DIR successful for path: %s\n", full_path.c_str());
			free(rList);
		}
		else
		{
			ResponsePkt rErr;
			rErr.init(request);
			rErr.response.status = ResponseStatus::FU_ERROR;
			print_with_time_and_thread(LOG_ERROR, "READ_DIR failed for path: %s \n", full_path.c_str());
			skapi_send(client_socket, (char*)&rErr, sizeof(rErr));
		}
	}
	catch (...)
	{
		ResponsePkt rErr;
		rErr.init(request);
		rErr.response.status = ResponseStatus::FU_NOT_FOUND;
		print_with_time_and_thread(LOG_ERROR, "READ_DIR failed for path: %s, error: %d\n", full_path.c_str(), errno);
		skapi_send(client_socket, (char*)&rErr, sizeof(rErr));
	}
}


// 处理CREATE请求
void handle_create(HSOCKET client_socket, const CommunicationPacket &request)
{
	ResponsePkt response;
	response.init(request);

	std::string full_path = make_this_file_path(request);

#ifdef _WIN32
	unsigned int mode = linux_open_mode_to_win(request.create.create_mode);
#else//!_WIN32
	unsigned int mode = request.create.create_mode;
#endif//_WIN32

	try
	{
		// 创建文件
		wlo_handle fd = wlo_create(full_path.c_str(), (mode));
		if (fd < 0)
		{
			response.response.status = ResponseStatus::FU_ERROR;
			print_with_time_and_thread(LOG_ERROR, "CREATE failed for path: %s, error: %d\n", full_path.c_str(), errno);
		}
		else
		{
			long long handle_id = FileHandleManager::getInstance().addFileHandle(fd);
			response.response.status = ResponseStatus::FU_SUCCESS;
			response.response.fd_id_out = handle_id;
			print_with_time_and_thread(LOG_DEBUG, "CREATE successful for path: %s\n", full_path.c_str());
		}
	}
	catch (...)
	{
		response.response.status = ResponseStatus::FU_ERROR;
		print_with_time_and_thread(LOG_ERROR, "CREATE failed for path: %s, error: %d\n", full_path.c_str(), errno);
	}
	skapi_send(client_socket, (char*)&response, sizeof(response));
}

// 处理MKDIR请求
void handle_mkdir(HSOCKET client_socket, const CommunicationPacket &request)
{
	ResponsePkt response;
	response.init(request);

	std::string full_path = make_this_file_path(request);

	try
	{
		// 创建目录
		fs::path fpat = full_path;
		fs::create_directory(fpat);
		response.response.status = ResponseStatus::FU_SUCCESS;
		print_with_time_and_thread(LOG_DEBUG, "MKDIR successful for path: %s\n", full_path.c_str());
	}
	catch (const fs::filesystem_error &e)
	{
		response.response.status = ResponseStatus::FU_ERROR;
		print_with_time_and_thread(LOG_ERROR, "MKDIR failed for path: %s, error: %s\n", full_path.c_str(), e.what());
	}

	skapi_send(client_socket, (char*)&response, sizeof(response));
}

// 处理RMDIR请求
void handle_rmdir(HSOCKET client_socket, const CommunicationPacket &request)
{
	ResponsePkt response;
	response.init(request);

	std::string full_path = make_this_file_path(request);

	try
	{
		// 删除目录
		fs::remove(full_path);
		response.response.status = ResponseStatus::FU_SUCCESS;
		print_with_time_and_thread(LOG_DEBUG, "RMDIR successful for path: %s\n", full_path.c_str());
	}
	catch (const fs::filesystem_error &e)
	{
		response.response.status = ResponseStatus::FU_ERROR;
		print_with_time_and_thread(LOG_ERROR, "RMDIR failed for path: %s, error: %s\n", full_path.c_str(), e.what());
	}

	skapi_send(client_socket, (char*)&response, sizeof(response));
}

// 处理UNLINK请求
void handle_unlink(HSOCKET client_socket, const CommunicationPacket &request)
{
	ResponsePkt response;
	response.init(request);

	std::string full_path = make_this_file_path(request);

	try
	{
		// 删除文件
		int err = my_unlink(full_path.c_str());
		if (err == 0)
		{
			response.response.status = ResponseStatus::FU_SUCCESS;
			print_with_time_and_thread(LOG_DEBUG, "UNLINK successful for path: %s\n", full_path.c_str());
		}
		else
		{
			response.response.status = ResponseStatus::FU_ERROR;
			print_with_time_and_thread(LOG_ERROR, "UNLINK err for path: %s, err=%d\n", full_path.c_str(), err);
		}
	}
	catch (const fs::filesystem_error &e)
	{
		response.response.status = ResponseStatus::FU_ERROR;
		print_with_time_and_thread(LOG_ERROR, "UNLINK failed for path: %s, error: %s\n", full_path.c_str(), e.what());
	}

	skapi_send(client_socket, (char*)&response, sizeof(response));
}

// 处理RENAME请求
void handle_rename(HSOCKET client_socket, const CommunicationPacket &request)
{
	ResponsePkt response;
	response.init(request);

	std::string old_full_path = make_this_file_path(request);
	std::string new_full_path = SHARE_DIR + "/" + request.rename.newpath;
	unsigned int flags = request.rename.Flag_Rename;
	/** Rename a file
	 *
	 * *flags* may be `RENAME_EXCHANGE` or `RENAME_NOREPLACE`. If
	 * RENAME_NOREPLACE is specified, the filesystem must not
	 * overwrite *newname* if it exists and return an error
	 * instead. If `RENAME_EXCHANGE` is specified, the filesystem
	 * must atomically exchange the two files, i.e. both must
	 * exist and neither may be deleted.
	 */

	try
	{
		int rerrr;
		if (0 != (rerrr = my_renameat2(old_full_path.c_str(), new_full_path.c_str(), flags)))
		{
			response.response.status = ResponseStatus::FU_ERROR;
			print_with_time_and_thread(LOG_ERROR, "RENAME failed from %s to %s, error: %d\n", old_full_path.c_str(), new_full_path.c_str(), rerrr);
			skapi_send(client_socket, (char*)&response, sizeof(response));
			return;
		}
		response.response.status = ResponseStatus::FU_SUCCESS;
		print_with_time_and_thread(LOG_DEBUG, "RENAME successful from %s to %s\n", old_full_path.c_str(), new_full_path.c_str());
	}
	catch (const fs::filesystem_error &e)
	{
		response.response.status = ResponseStatus::FU_ERROR;
		print_with_time_and_thread(LOG_ERROR, "RENAME failed from %s to %s, error: %s\n", old_full_path.c_str(), new_full_path.c_str(), e.what());
	}

	skapi_send(client_socket, (char*)&response, sizeof(response));
}

// 处理LINK请求
void handle_link(HSOCKET client_socket, const CommunicationPacket &request)
{
	ResponsePkt response;
	response.init(request);

	std::string old_full_path = make_this_file_path(request);
	std::string new_full_path = SHARE_DIR + "/" + request.link.newpath;

	try
	{
		// 创建硬链接
		fs::create_hard_link(old_full_path, new_full_path);
		response.response.status = ResponseStatus::FU_SUCCESS;
		print_with_time_and_thread(LOG_DEBUG, "LINK successful from %s to %s\n", old_full_path.c_str(), new_full_path.c_str());
	}
	catch (const fs::filesystem_error &e)
	{
		response.response.status = ResponseStatus::FU_ERROR;
		print_with_time_and_thread(LOG_ERROR, "LINK failed from %s to %s, error: %s\n", old_full_path.c_str(), new_full_path.c_str(), e.what());
	}

	skapi_send(client_socket, (char*)&response, sizeof(response));
}

// 处理SYMLINK请求
void handle_symlink(HSOCKET client_socket, const CommunicationPacket &request)
{
	ResponsePkt response;
	response.init(request);

	std::string target_path = request.symlink.target;
	std::string link_full_path = make_this_file_path(request);

	try
	{
		// 创建符号链接
		fs::create_symlink(target_path, link_full_path);
		response.response.status = ResponseStatus::FU_SUCCESS;
		print_with_time_and_thread(LOG_DEBUG, "SYMLINK successful from %s to %s\n", target_path.c_str(), link_full_path.c_str());
	}
	catch (const fs::filesystem_error &e)
	{
		response.response.status = ResponseStatus::FU_ERROR;
		print_with_time_and_thread(LOG_ERROR, "SYMLINK failed from %s to %s, error: %s\n", target_path.c_str(), link_full_path.c_str(), e.what());
	}

	skapi_send(client_socket, (char*)&response, sizeof(response));
}

// 处理READLINK请求
void handle_readlink(HSOCKET client_socket, const CommunicationPacket &request)
{
	std::string full_path = make_this_file_path(request);

	try
	{
		// 读取符号链接
#ifdef _WIN32
		std::string target0 = GetSymbollnkTarget(full_path);
#else//!_WIN32
		fs::path ftar = fs::read_symlink(full_path);
		std::string target0 = ftar.string();
#endif // _WIN32

		//全路径转为相对路径
		std::string target = get_realitive_path(SHARE_DIR, target0);

		size_t aln = sizeof(ResponsePkt) + target.length() + 1;
		ResponsePkt *pTr = (ResponsePkt*)malloc(aln);
		if (pTr)
		{
			pTr->init(request);
			pTr->set_variable_data(target.c_str(), (uint32_t)(target.size() + 1), (uint32_t)(aln));
			pTr->response.status = ResponseStatus::FU_SUCCESS;
			print_with_time_and_thread(LOG_DEBUG, "READLINK successful for path: %s, target: %s\n", full_path.c_str(), target.c_str());
			skapi_send(client_socket, (char*)pTr, (int)(pTr->get_total_need()));
			free(pTr);
		}
		else
		{
			ResponsePkt rErr;
			rErr.init(request);
			rErr.response.status = ResponseStatus::FU_ERROR;
			print_with_time_and_thread(LOG_ERROR, "READLINK failed for path: %s, error: %d\n", full_path.c_str(), errno);
			skapi_send(client_socket, (char*)&rErr, sizeof(rErr));
		}
	}
	catch (const fs::filesystem_error &e)
	{
		ResponsePkt rErr;
		rErr.init(request);
		rErr.response.status = ResponseStatus::FU_ERROR;
		print_with_time_and_thread(LOG_ERROR, "READLINK failed for path: %s, error: %s\n", full_path.c_str(), e.what());
		skapi_send(client_socket, (char*)&rErr, sizeof(rErr));
	}

}

// 处理SYNC请求
void handle_sync(HSOCKET client_socket, const CommunicationPacket &request)
{
	ResponsePkt response;
	response.init(request);

	FileHandleManager::FileHandleInfo *info = FileHandleManager::getInstance().getFileHandle(request.fd_id_in);
	if (!info)
	{
		response.response.status = ResponseStatus::FU_ERROR;
		print_with_time_and_thread(LOG_ERROR, "SYNC failed: invalid file handle\n");
		skapi_send(client_socket, (char*)&response, sizeof(response));
		return;
	}

	try
	{
		// 同步文件到磁盘
		wlo_sync(info->fd);
		response.response.status = ResponseStatus::FU_SUCCESS;
		print_with_time_and_thread(LOG_DEBUG, "SYNC successful for file handle: %lld\n", (long long)request.fd_id_in);
	}
	catch (const std::exception &e)
	{
		response.response.status = ResponseStatus::FU_ERROR;
		print_with_time_and_thread(LOG_ERROR, "SYNC failed: %s\n", e.what());
	}

	skapi_send(client_socket, (char*)&response, sizeof(response));
}

// 处理OPEN请求
void handle_open(HSOCKET client_socket, const CommunicationPacket &request)
{
	ResponsePkt response;
	response.init(request);

	std::string full_path = make_this_file_path(request);

#ifdef _WIN32
	unsigned int flags = linux_open_flag_to_win(request.open.open_flags);
	unsigned int mode = linux_open_mode_to_win(request.open.open_mode);
#else//!_WIN32
	unsigned int flags = (request.open.open_flags);
	unsigned int mode = (request.open.open_mode);
#endif//_WIN32

	try
	{
		// 打开文件
		wlo_handle fd = wlo_open(full_path.c_str(), flags, mode);
		if (fd < 0)
		{
			response.response.status = ResponseStatus::FU_ERROR;
			print_with_time_and_thread(LOG_ERROR, "OPEN failed for path: %s, error: %d\n", full_path.c_str(), errno);
		}
		else
		{
			// 添加到文件句柄管理器
			long long handle_id = FileHandleManager::getInstance().addFileHandle(fd);

			response.response.status = ResponseStatus::FU_SUCCESS;
			response.response.fd_id_out = handle_id;

			print_with_time_and_thread(LOG_DEBUG, "OPEN successful for path: %s, handle: %lld\n", full_path.c_str(), handle_id);
		}
	}
	catch (...)
	{
		response.response.status = ResponseStatus::FU_ERROR;
		print_with_time_and_thread(LOG_ERROR, "OPEN failed for path: %s, error: %d\n", full_path.c_str(), errno);
	}
	skapi_send(client_socket, (char*)&response, sizeof(response));
}

// 处理CLOSE请求
void handle_close(HSOCKET client_socket, const CommunicationPacket &request)
{
	ResponsePkt response;
	response.init(request);

	uint64_t handle_id = request.fd_id_in;

	try
	{
		// 从文件句柄管理器中移除
		FileHandleManager::getInstance().removeFileHandle(handle_id);

		response.response.status = ResponseStatus::FU_SUCCESS;

		print_with_time_and_thread(LOG_DEBUG, "CLOSE successful for handle: %lld\n", handle_id);
	}
	catch (const std::exception &e)
	{
		response.response.status = ResponseStatus::FU_ERROR;
		print_with_time_and_thread(LOG_ERROR, "CLOSE failed for handle: %lld, error: %s\n", handle_id, e.what());
	}

	skapi_send(client_socket, (char*)&response, sizeof(response));
}

void handle_utimens(HSOCKET client_socket, const CommunicationPacket &request)
{
	ResponsePkt response;
	response.init(request);
	//utimensat
	try
	{
		std::string full_path = make_this_file_path(request);
		FileHandleManager::FileHandleInfo *info = FileHandleManager::getInstance().getFileHandle(request.fd_id_in);
		int ret = -1;
		if (info)
		{
			// 如果文件已打开,使用futimens通过文件描述符修改时间
			ret = wlo_futimens(info->fd, request.utimens.times);
		}
		else
		{
			// 文件未打开,使用utimensat通过文件路径修改时间
			// AT_FDCWD表示相对于当前工作目录,AT_SYMLINK_NOFOLLOW表示不跟随符号链接
			ret = utimensat(/*AT_FDCWD*/0, full_path.c_str(), request.utimens.times, /*AT_SYMLINK_NOFOLLOW*/ 0);
		}

		if (ret == 0)
		{
			response.response.status = ResponseStatus::FU_SUCCESS;
			print_with_time_and_thread(LOG_DEBUG, "UTIME successful for handle: %lld\n", request.fd_id_in);
		}
		else
		{
			response.response.status = ResponseStatus::FU_ERROR;
			print_with_time_and_thread(LOG_ERROR, "UTIME failed for handle: %lld, error: %d\n", request.fd_id_in, errno);

		}
	}
	catch (const std::exception &e)
	{
		response.response.status = ResponseStatus::FU_ERROR;
		print_with_time_and_thread(LOG_ERROR, "CLOSE failed for handle: %lld, error: %s\n", request.fd_id_in, e.what());
	}

	skapi_send(client_socket, (char*)&response, sizeof(response));
}

// 处理READ请求(优化大文件读取)
void handle_read(HSOCKET client_socket, const CommunicationPacket &request)
{
	ResponsePkt errorResponse;
	errorResponse.init(request);

	FileHandleManager::FileHandleInfo *info = FileHandleManager::getInstance().getFileHandle(request.fd_id_in);
	if (!info)
	{
		errorResponse.response.status = ResponseStatus::FU_ERROR;
		print_with_time_and_thread(LOG_ERROR, "READ failed: invalid file handle\n");
		skapi_send(client_socket, (char*)&errorResponse, sizeof(errorResponse));
		return;
	}

	// 使用64位偏移量处理大文件
	long long offset = request.read.offset;
	size_t read_size = request.read.size;

	// 读取文件数据
	size_t aln = sizeof(ResponsePkt) + read_size;
	ResponsePkt *pTT = (ResponsePkt*)malloc(aln);
	if (pTT)
	{
		pTT->init(request);

		long long oldpos = wlo_seek64(info->fd, 0, SEEK_CUR);
		wlo_seek64(info->fd, offset, SEEK_SET);
		ssize_t bytes_read = (ssize_t)wlo_read(info->fd, pTT->variable_data, (unsigned int)read_size);
		wlo_seek64(info->fd, oldpos, SEEK_SET);

		if (bytes_read < 0)
		{
			free(pTT);
			pTT = 0;
			errorResponse.response.status = ResponseStatus::FU_ERROR;
			print_with_time_and_thread(LOG_ERROR, "READ failed: failed to read file\n");
			skapi_send(client_socket, (char*)&errorResponse, sizeof(errorResponse));
			return;
		}

		pTT->response.status = ResponseStatus::FU_SUCCESS;
		pTT->response.bytes_transferred = bytes_read;
		pTT->variable_data_size = (uint32_t)bytes_read;

		unsigned long long hs = HashData(pTT->variable_data, bytes_read);
		print_with_time_and_thread(LOG_DEBUG, "READ successful: read %zd bytes at offset %lld, hash=0x%016llX\n", bytes_read, (long long)offset, hs);
		skapi_send_multi(client_socket, (char*)pTT, (int)(pTT->get_total_need()));
		free(pTT);
		pTT = 0;
	}
	else
	{
		errorResponse.response.status = ResponseStatus::FU_ERROR;
		print_with_time_and_thread(LOG_ERROR, "READ failed: failed to read file\n");
		skapi_send(client_socket, (char*)&errorResponse, sizeof(errorResponse));
	}
}

// 处理WRITE请求(优化大文件写入)
void handle_write(HSOCKET client_socket, const CommunicationPacket &request, ssize_t bytes_read)
{
	ResponsePkt response;
	response.init(request);

	//需要读取完整了
	const CommunicationPacket* pTotalReq = &request;
	bool bNeedFree = false;
	if (request.get_total_need() > (size_t)bytes_read)
	{
		pTotalReq = (CommunicationPacket*)malloc(request.get_total_need());
		if (!pTotalReq)
		{
			response.response.status = ResponseStatus::FU_ERROR;
			print_with_time_and_thread(LOG_ERROR, "WRITE failed: alloc\n");
			skapi_send(client_socket, (char*)&response, sizeof(response));
			return;
		}
		bNeedFree = true;
		memcpy((void*)pTotalReq, &request, bytes_read);
		size_t remain = request.get_total_need() - bytes_read;
		int readrm = skapi_recv_multi_bytes_known(client_socket, ((char*)pTotalReq) + bytes_read, (int)remain);
		if (readrm != (int)remain)
		{
			response.response.status = ResponseStatus::FU_ERROR;
			print_with_time_and_thread(LOG_ERROR, "WRITE failed: read remain\n");
			skapi_send(client_socket, (char*)&response, sizeof(response));
			if (bNeedFree && pTotalReq)
				free((void*)pTotalReq);
			return;
		}
	}

	FileHandleManager::FileHandleInfo *info = FileHandleManager::getInstance().getFileHandle(request.fd_id_in);
	if (!info)
	{
		response.response.status = ResponseStatus::FU_ERROR;
		print_with_time_and_thread(LOG_ERROR, "WRITE failed: invalid file handle\n");
		skapi_send(client_socket, (char*)&response, sizeof(response));
		if (bNeedFree && pTotalReq)
			free((void*)pTotalReq);
		return;
	}

	// 使用64位偏移量处理大文件
	long long offset = request.write.offset;
	size_t write_size = request.write.size;

	// 写入文件数据
	long long oldpos = wlo_seek64(info->fd, 0, SEEK_CUR);
	wlo_seek64(info->fd, offset, SEEK_SET);
	ssize_t bytes_written = wlo_write(info->fd, pTotalReq->variable_data, (unsigned int)write_size);
	unsigned long long hs = HashData(pTotalReq->variable_data, write_size);
	wlo_seek64(info->fd, oldpos, SEEK_SET);//一般采用pwrite 不影响位置

	if (bNeedFree && pTotalReq) {
		free((void*)pTotalReq);
		pTotalReq = 0;
	}

	if (bytes_written < 0)
	{
		response.response.status = ResponseStatus::FU_ERROR;
		print_with_time_and_thread(LOG_ERROR, "WRITE failed: failed to write file\n");
		skapi_send(client_socket, (char*)&response, sizeof(response));
		return;
	}

	response.response.status = ResponseStatus::FU_SUCCESS;
	response.response.bytes_transferred = bytes_written;
	print_with_time_and_thread(LOG_DEBUG, "WRITE successful: wrote %zd bytes at offset %lld, hash=0x%016llX\n",
		bytes_written, (long long)offset, hs);
	skapi_send(client_socket, (char*)&response, sizeof(response));
}


struct ClientCtx
{
	HSOCKET sk = BAD_SOCKET;
};

// 处理客户端请求
void* handle_client(void *arg)
{
	ClientCtx *pCTX = (ClientCtx*)arg; // 使用C风格指针强制转换
	ClientCtx CTX = *pCTX;
	delete pCTX; // 使用C风格指针强制转换
	pCTX = 0;
	arg = 0;

	try
	{
		// 首先进行认证
		CommunicationPacket auth_request;
		ssize_t bytes_read = skapi_recv(CTX.sk, (char*)&auth_request, sizeof(auth_request));
		if (bytes_read <= 0)
		{
			print_with_time_and_thread(LOG_ERROR, "Failed to receive authentication request\n");
			skapi_closesocket(CTX.sk);
			return nullptr;
		}

		if (auth_request.command != CommandType::AUTHENTICATE)
		{
			print_with_time_and_thread(LOG_ERROR, "First command must be authentication\n");
			skapi_closesocket(CTX.sk);
			return nullptr;
		}

		if (!handle_authenticate(CTX.sk, auth_request))
		{
			print_with_time_and_thread(LOG_ERROR, "Authentication failed\n");
			skapi_closesocket(CTX.sk);
			return nullptr;
		}

		print_with_time_and_thread(LOG_DEBUG, "Client authenticated successfully\n");

		// 认证成功后处理其他请求
		while (true)
		{
			CommunicationPacket request;
			bytes_read = skapi_recv(CTX.sk, (char*)&request, sizeof(request));
			if (bytes_read <= 0)
			{
				break;
			}

			switch (request.command)
			{
			case CommandType::GET_ATTR:
				handle_get_attr(CTX.sk, request);
				break;
			case CommandType::READ_DIR:
				handle_read_dir(CTX.sk, request);
				break;
			case CommandType::CREATE:
				handle_create(CTX.sk, request);
				break;
			case CommandType::MKDIR:
				handle_mkdir(CTX.sk, request);
				break;
			case CommandType::RMDIR:
				handle_rmdir(CTX.sk, request);
				break;
			case CommandType::UNLINK:
				handle_unlink(CTX.sk, request);
				break;
			case CommandType::RENAME:
				handle_rename(CTX.sk, request);
				break;
			case CommandType::LINK:
				handle_link(CTX.sk, request);
				break;
			case CommandType::SYMLINK:
				handle_symlink(CTX.sk, request);
				break;
			case CommandType::READLINK:
				handle_readlink(CTX.sk, request);
				break;
			case CommandType::SYNC:
				handle_sync(CTX.sk, request);
				break;
			case CommandType::READ:
				handle_read(CTX.sk, request);
				break;
			case CommandType::WRITE:
				handle_write(CTX.sk, request, bytes_read);
				break;
			case CommandType::OPEN:
				handle_open(CTX.sk, request);
				break;
			case CommandType::CLOSE:
				handle_close(CTX.sk, request);
				break;
			case CommandType::UTIMENS:
				handle_utimens(CTX.sk, request);
				break;
				// 其他命令的处理保持不变...
			default:
				ResponsePkt response;
				response.init(request);
				response.response.status = ResponseStatus::FU_NOT_IMPLEMENTED;
				print_with_time_and_thread(LOG_ERROR, "Command not implemented: %d\n", (int)request.command); // 使用C风格指针强制转换
				skapi_send(CTX.sk, (char*)&response, sizeof(response));
				break;
			}
		}
	}
	catch (const std::exception &e)
	{
		print_with_time_and_thread(LOG_ERROR, "Client error: %s\n", e.what());
	}

	skapi_closesocket(CTX.sk);
	print_with_time_and_thread(LOG_ERROR, "Client connection closed\n");
	return nullptr;
}

HSOCKET g_server_socket = BAD_SOCKET;

int server_main()
{
	skapi_global_init();

	// 创建共享目录(如果不存在)
	fs::create_directories(SHARE_DIR);

	HSOCKET client_socket;
	struct sockaddr_in server_addr, client_addr;
	int client_len = sizeof(client_addr);

	// 创建套接字
	if ((g_server_socket = skapi_socket()) == BAD_SOCKET)
	{
		print_with_time_and_thread(LOG_ERROR, "Failed to create socket\n");
		return 1;
	}

	// 配置服务器地址
	memset(&server_addr, 0, sizeof(server_addr));
	server_addr.sin_family = AF_INET;
	server_addr.sin_addr.s_addr = inet_addr(SERVER_IP.c_str()); // inet_addr("127.0.0.1");
	server_addr.sin_port = htons((unsigned short)SERVER_PORT);

#ifndef _WIN32
	// 设置SO_REUSEADDR选项 允许端口快速重用
	int opt = 1;
	setsockopt((int)(long long)g_server_socket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
#endif // !_WIN32

	// 绑定套接字
	if (skapi_bind(g_server_socket, (struct sockaddr*) &server_addr, sizeof(server_addr)) != 0)
	{
		print_with_time_and_thread(LOG_ERROR, "Failed to bind socket\n");
		return 1;
	}

	// 监听连接
	if (skapi_listen(g_server_socket, SOMAXCONN) != 0)
	{
		print_with_time_and_thread(LOG_ERROR, "Failed to listen on socket\n");
		return 1;
	}

	printf("listen ok %s:%d\n", SERVER_IP.c_str(), SERVER_PORT);

#ifdef _WIN32
	string sCmd = ::GetCommandLineA();
	if (strstr(sCmd.c_str(), "--silient"))
	{
		HWND hConsole = ::GetConsoleWindow();
		if (hConsole)
		{
			ShowWindow(hConsole, SW_HIDE);
		}
	}
#endif // _WIN32

	while (1)
	{
		if (BAD_SOCKET == (client_socket = skapi_accept(g_server_socket, (struct sockaddr*) &client_addr, &client_len)))
		{
			continue;
		}

		print_with_time_and_thread(LOG_WARN, "New connection from %s\n", inet_ntoa(client_addr.sin_addr));

		// 创建新线程处理客户端请求
		ClientCtx *client_socket_ptr = new (nothrow) ClientCtx;
		if (client_socket_ptr)
		{
			client_socket_ptr->sk = client_socket;
			pthread_t thread_id;
			if (create_thread(&thread_id, handle_client, (void*)client_socket_ptr) != 0)
			{ // 使用C风格指针强制转换
				print_with_time_and_thread(LOG_ERROR, "Failed to create thread\n");
				delete client_socket_ptr;
				skapi_closesocket(client_socket);
				continue;
			}
			// 分离线程,避免内存泄漏
			pthread_detach(thread_id);
		}
		else
		{
			skapi_closesocket(client_socket);
			continue;
		}
	}

	skapi_closesocket(g_server_socket);

	return 0;
}

客户端

#include "FuseClient.h"
#define FUSE_USE_VERSION 30
#include <fuse3/fuse.h>

#include <iostream>
#include <string>
#include <cstdlib>
#include <cstring>

#ifdef _WIN32
#include <WinSock2.h>
#include <Windows.h>
#include <io.h>
#else//!_WIN32
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#endif // _WIN32

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <vector>
#include <map>
#include <mutex>
#include <sstream>

#include "FuseCommon.h"
#include "SocketApi.h"
#include "SockMgr.h"
#include "FS_Util.h"
#include "AutoLock.h"

ACDCriticalSection g_lockSerial;
uint64_t g_lstReqSerial = 1;
uint64_t get_new_req_serial()
{
	CAutoLock lock(&g_lockSerial);
	g_lstReqSerial++;
	return g_lstReqSerial;
}

// 发送请求并接收响应
int send_request(CommunicationPacket &request, CmdResponse &response)
{
	request.serial = get_new_req_serial();
	HSOCKET sock = SocketManager::getInstance().getSocket();
	if (sock == BAD_SOCKET)
	{
		return -ENOENT;
	}

	try
	{
		if (response.prepare())
		{
			// 发送请求
			int nSend = skapi_send_multi(sock, (char*)&request, (int)request.get_total_need());
			if (nSend != (int)request.get_total_need())
			{
				SocketManager::getInstance().resetSocket();
				print_with_time_and_thread(LOG_ERROR, "Failed to send req\n");
				return -ENOENT;
			}

			// 接收响应
			ssize_t bytes_read = skapi_recv(sock, (char*)response.pPkt, sizeof(ResponsePkt));
			if (bytes_read <= 0)
			{
				SocketManager::getInstance().resetSocket();
				print_with_time_and_thread(LOG_ERROR, "Failed to receive response1\n");
				return -ENOENT;
			}

			//要处理剩余数据
			if (response.pPkt->variable_data_size > 0)
			{
				size_t total_need = response.pPkt->get_total_need();
				if (total_need > (size_t)bytes_read)
				{
					if (response.extend_to(total_need))
					{
						size_t remain = total_need - bytes_read;
						ssize_t bytes_read2 = skapi_recv_multi_bytes_known(sock, ((char*)(response.pPkt)) + bytes_read, (int)remain);
						if (bytes_read2 <= 0)
						{
							SocketManager::getInstance().resetSocket();
							print_with_time_and_thread(LOG_ERROR, "Failed to receive response3\n");
							return -ENOENT;
						}
					}
					else
					{
						SocketManager::getInstance().resetSocket();
						print_with_time_and_thread(LOG_ERROR, "Failed to receive response2\n");
						return -ENOENT;
					}
				}
			}

			if (response.pPkt->commandSrc != request.command || response.pPkt->serialSrc != request.serial)
			{
				SocketManager::getInstance().resetSocket();
				print_with_time_and_thread(LOG_ERROR, "Request mismatch cmd=%d\n", request.command);
				return -ENOENT; // 返回文件不存在错误
			}

			if (response.pPkt->response.status != ResponseStatus::FU_SUCCESS)
			{
				print_with_time_and_thread(LOG_ERROR, "Request failed status=%d, cmd=%d\n", response.pPkt->response.status, request.command);
				return -ENOENT; // 返回文件不存在错误
			}

			return 0;
		}
		else
		{
			SocketManager::getInstance().resetSocket();
			print_with_time_and_thread(LOG_ERROR, "Failed to receive response4\n");
			return -ENOENT;
		}
	}
	catch (...)
	{
		SocketManager::getInstance().resetSocket();
		print_with_time_and_thread(LOG_ERROR, "Request failed with exception\n");
		return -ENOENT;
	}
}

// GET_ATTR操作
static int nfs_getattr(const char *path, struct stat *stbuf, struct fuse_file_info *fi)
{
	CommunicationPacket request;
	request.init(CommandType::GET_ATTR);
	strncpy(request.path, path, sizeof(request.path) - 1);

	CmdResponse response;
	int res = send_request(request, response);
	if (res == 0)
	{
		memset(stbuf, 0, sizeof(struct stat));
		equal_stat((*stbuf), response.pPkt->response.mustat);
		print_with_time_and_thread(LOG_DEBUG, "GET_ATTR successful for path: %s, dir=%d, reg=%d, lnk=%d\n", path, S_ISDIR(stbuf->st_mode), S_ISREG(stbuf->st_mode), S_ISLNK(stbuf->st_mode));
	}
	else
	{
		print_with_time_and_thread(LOG_ERROR, "GET_ATTR failed for path: %s\n", path);
	}

	return res;
}

int nfs_utimens(const char *path, const struct timespec tv[2], struct fuse_file_info *fi)
{
	CommunicationPacket request;
	request.init(CommandType::UTIMENS);
	strncpy(request.path, path, sizeof(request.path) - 1);
	memcpy(request.utimens.times, tv, sizeof(request.utimens.times));
	request.fd_id_in = fi->fh;

	CmdResponse response;
	int res = send_request(request, response);
	if (res == 0)
	{
		print_with_time_and_thread(LOG_DEBUG, "UTIMENS successful for path: %s\n", path);
	}
	else
	{
		print_with_time_and_thread(LOG_ERROR, "UTIMENS failed for path: %s\n", path);
	}

	return res;
}

// READ_DIR操作
struct DIRFA
{
	FsAttr fa;
	string path;
};
static int nfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler, _Xoff_t offset, struct fuse_file_info *fi, enum fuse_readdir_flags flags)
{
	CommunicationPacket request;
	request.init(CommandType::READ_DIR);
	strncpy(request.path, path, sizeof(request.path) - 1);

	CmdResponse response;
	int res = send_request(request, response);
	if (res == 0)
	{
		// 解析目录内容
		std::string dir_content(response.pPkt->variable_data, response.pPkt->variable_data_size);
		std::stringstream ss(dir_content);
		std::string entry;

		vector<DIRFA> vetAll;

		while (std::getline(ss, entry))
		{
			if (entry.length() == 0)
				break;
			DIRFA dd;
			size_t fShu = entry.find('|');
			if (fShu != string::npos)
			{
				string fastr = entry.substr(0, fShu);
				dd.path = entry.substr(fShu + 1);
				FAfromStr(dd.fa, fastr.c_str());
				if (dd.path.length())
				{
					vetAll.push_back(dd);
				}
			}
		}

		int itemCnt = (int)vetAll.size();
		int readPos = 0;
		int next_index = 0;

		if (offset > 0)
		{
			//跳过offset个
			for (int i = 0; i < (int)offset; i++)
			{
				readPos++;
				if (readPos >= itemCnt)
				{
					return 0;
				}
			}
			next_index = (int)offset;
		}

		// 根据flags处理目录项
		bool readdir_plus = (flags & FUSE_READDIR_PLUS) != 0;

		DIRFA *de = 0;
		while (readPos < itemCnt && 0 != (de = &vetAll[readPos]))   // 此处可能进入getattr 需要返回的 可能需要把符号链接加上
		{
			next_index++;
			readPos++;

			if (strcmp(de->path.c_str(), ".") == 0 || strcmp(de->path.c_str(), "..") == 0)
			{
				if (filler(buf, de->path.c_str(), 0, next_index, (fuse_fill_dir_flags)0) != 0)
				{
					break;
				}
				else
				{
					printf("dir[%d]: %s\n", next_index, de->path.c_str());
				}

				continue;
			}

			if (readdir_plus)
			{
				struct stat st;
				memset(&st, 0, sizeof(st));
				fill_fa(st, de->fa);

				if (filler(buf, de->path.c_str(), &st, next_index, FUSE_FILL_DIR_PLUS) != 0)
				{
					break;
				}
				else
				{
					print_with_time_and_thread(LOG_DEBUG, "dir[%d]: %s, dir=%d, reg=%d, lnk=%d\n", next_index, de->path.c_str(), S_ISDIR(st.st_mode), S_ISREG(st.st_mode), S_ISLNK(st.st_mode));
				}
			}
			else
			{
				if (filler(buf, de->path.c_str(), 0, next_index, (fuse_fill_dir_flags)0) != 0)
				{
					break;
				}
				else
				{
					print_with_time_and_thread(LOG_DEBUG, "dir[%d]: %s\n", next_index, de->path.c_str());
				}
			}
		}

		print_with_time_and_thread(LOG_DEBUG, "READ_DIR successful for path: %s\n", path);
	}
	else
	{
		print_with_time_and_thread(LOG_ERROR, "READ_DIR failed for path: %s\n", path);
	}

	return res;
}

// CREATE操作
static int nfs_create(const char *path, mode_t mode, struct fuse_file_info *fi)
{
	CommunicationPacket request;
	request.init(CommandType::CREATE);
	strncpy(request.path, path, sizeof(request.path) - 1);
	request.create.create_mode = mode;

	CmdResponse response;
	int res = send_request(request, response);
	if (res == 0)
	{
		fi->fh = response.pPkt->response.fd_id_out; // 使用C风格指针强制转换
		print_with_time_and_thread(LOG_DEBUG, "CREATE successful for path: %s\n", path);
	}
	else
	{
		print_with_time_and_thread(LOG_ERROR, "CREATE failed for path: %s\n", path);
	}

	return res;
}

// MKDIR操作
static int nfs_mkdir(const char *path, mode_t mode)
{
	CommunicationPacket request;
	request.init(CommandType::MKDIR);
	strncpy(request.path, path, sizeof(request.path) - 1);
	request.mkdir.mkdir_mode = mode;

	CmdResponse response;
	int res = send_request(request, response);
	if (res == 0)
	{
		print_with_time_and_thread(LOG_DEBUG, "MKDIR successful for path: %s\n", path);
	}
	else
	{
		print_with_time_and_thread(LOG_ERROR, "MKDIR failed for path: %s\n", path);
	}

	return res;
}

// RMDIR操作
static int nfs_rmdir(const char *path)
{
	CommunicationPacket request;
	request.init(CommandType::RMDIR);
	strncpy(request.path, path, sizeof(request.path) - 1);

	CmdResponse response;
	int res = send_request(request, response);
	if (res == 0)
	{
		print_with_time_and_thread(LOG_DEBUG, "RMDIR successful for path: %s\n", path);
	}
	else
	{
		print_with_time_and_thread(LOG_ERROR, "RMDIR failed for path: %s\n", path);
	}

	return res;
}

// UNLINK操作
static int nfs_unlink(const char *path)
{
	CommunicationPacket request;
	request.init(CommandType::UNLINK);
	strncpy(request.path, path, sizeof(request.path) - 1);

	CmdResponse response;
	int res = send_request(request, response);
	if (res == 0)
	{
		print_with_time_and_thread(LOG_DEBUG, "UNLINK successful for path: %s\n", path);
	}
	else
	{
		print_with_time_and_thread(LOG_ERROR, "UNLINK failed for path: %s\n", path);
	}

	return res;
}

// RENAME操作
static int nfs_rename(const char *oldpath, const char *newpath, unsigned int flags)
{
	CommunicationPacket request;
	request.init(CommandType::RENAME);
	strncpy(request.path, oldpath, sizeof(request.path) - 1);
	strncpy(request.rename.newpath, newpath, sizeof(request.rename.newpath) - 1);
	request.rename.Flag_Rename = flags;

	CmdResponse response;
	int res = send_request(request, response);
	if (res == 0)
	{
		print_with_time_and_thread(LOG_DEBUG, "RENAME successful from %s to %s\n", oldpath, newpath);
	}
	else
	{
		print_with_time_and_thread(LOG_ERROR, "RENAME failed from %s to %s\n", oldpath, newpath);
	}

	return res;
}

// LINK操作
static int nfs_link(const char *oldpath, const char *newpath)
{
	CommunicationPacket request;
	request.init(CommandType::LINK);
	strncpy(request.path, oldpath, sizeof(request.path) - 1);
	strncpy(request.link.newpath, newpath, sizeof(request.link.newpath) - 1);

	CmdResponse response;
	int res = send_request(request, response);
	if (res == 0)
	{
		print_with_time_and_thread(LOG_DEBUG, "LINK successful from %s to %s\n", oldpath, newpath);
	}
	else
	{
		print_with_time_and_thread(LOG_ERROR, "LINK failed from %s to %s\n", oldpath, newpath);
	}

	return res;
}

// SYMLINK操作
static int nfs_symlink(const char *target, const char *linkpath)
{
	CommunicationPacket request;
	request.init(CommandType::SYMLINK);
	strncpy(request.symlink.target, target, sizeof(request.symlink.target) - 1);
	strncpy(request.path, linkpath, sizeof(request.path) - 1);

	CmdResponse response;
	int res = send_request(request, response);
	if (res == 0)
	{
		print_with_time_and_thread(LOG_DEBUG, "SYMLINK successful from %s to %s\n", target, linkpath);
	}
	else
	{
		print_with_time_and_thread(LOG_ERROR, "SYMLINK failed from %s to %s\n", target, linkpath);
	}

	return res;
}

// READLINK操作
static int nfs_readlink(const char *path, char *buf, size_t bufsize)
{
	CommunicationPacket request;
	request.init(CommandType::READLINK);
	strncpy(request.path, path, sizeof(request.path) - 1);

	CmdResponse response;
	int res = send_request(request, response);
	if (res == 0)
	{
		size_t copy_size = min(bufsize - 1, (size_t)response.pPkt->variable_data_size);
		memcpy(buf, response.pPkt->variable_data, copy_size);
		buf[copy_size] = '\0';
		print_with_time_and_thread(LOG_DEBUG, "READLINK successful for path: %s, target: %s\n", path, buf);
		return 0;
	}
	else
	{
		print_with_time_and_thread(LOG_ERROR, "READLINK failed for path: %s\n", path);
	}

	return res;
}

// SYNC操作
static int nfs_fsync(const char *path, int datasync, struct fuse_file_info *fi)
{
	CommunicationPacket request;
	request.init(CommandType::SYNC);
	request.fd_id_in = fi->fh; // 使用C风格指针强制转换

	CmdResponse response;
	int res = send_request(request, response);
	if (res == 0)
	{
		print_with_time_and_thread(LOG_DEBUG, "SYNC successful for file handle: %lld\n", (long long)fi->fh);
	}
	else
	{
		print_with_time_and_thread(LOG_ERROR, "SYNC failed for file handle: %lld\n", (long long)fi->fh);
	}

	return res;
}

// READ操作(优化大文件读取)
static int nfs_read(const char *path, char *buf, size_t size, _Xoff_t offset, struct fuse_file_info *fi)
{
	CommunicationPacket request;
	request.init(CommandType::READ);
	request.fd_id_in = fi->fh; // 使用C风格指针强制转换
	request.read.size = (uint32_t)size;
	request.read.offset = offset; // 使用64位偏移量,支持大文件

	CmdResponse response;
	int res = send_request(request, response);
	if (res == 0)
	{
		memcpy(buf, response.pPkt->variable_data, response.pPkt->response.bytes_transferred);
		unsigned long long hs = HashData(response.pPkt->variable_data, response.pPkt->response.bytes_transferred);
		print_with_time_and_thread(LOG_DEBUG, "READ successful: read %zd bytes from path: %s at offset %lld, hash=0x%016llX\n",
			response.pPkt->response.bytes_transferred, path, (long long)offset, hs); // 使用C风格指针强制转换
		return (int)response.pPkt->response.bytes_transferred;
	}

	print_with_time_and_thread(LOG_ERROR, "READ failed for path: %s\n", path);
	return res;
}

// WRITE操作(优化大文件写入)
static int nfs_write(const char *path, const char *buf, size_t size, _Xoff_t offset, struct fuse_file_info *fi)
{
	size_t aln = sizeof(CommunicationPacket) + size;
	CommunicationPacket *request = (CommunicationPacket*)malloc(aln);
	if (request)
	{
		request->init(CommandType::WRITE);
		request->fd_id_in = fi->fh; // 使用C风格指针强制转换
		request->write.size = (uint32_t)size;
		request->write.offset = offset; // 使用64位偏移量,支持大文件
		request->set_variable_data(buf, (uint32_t)size, (uint32_t)aln);

		CmdResponse response;
		int res = send_request(*request, response);
		free(request);
		request = 0;
		if (res == 0)
		{
			unsigned long long hash_data = HashData(buf, size);
			print_with_time_and_thread(LOG_DEBUG, "WRITE successful: wrote %zd bytes to path: %s at offset %lld, hash=0x%016llX\n",
				response.pPkt->response.bytes_transferred, path, (long long)offset, hash_data); // 使用C风格指针强制转换
			return (int)response.pPkt->response.bytes_transferred;
		}
		print_with_time_and_thread(LOG_ERROR, "WRITE failed for path: %s\n", path);
		return res;
	}

	return -ENOENT;
}

// OPEN操作
static int nfs_open(const char *path, struct fuse_file_info *fi)
{
	CommunicationPacket request;
	request.init(CommandType::OPEN);
	strncpy(request.path, path, sizeof(request.path) - 1);
	request.open.open_flags = fi->flags;
	request.open.open_mode = 0644;

	CmdResponse response;
	int res = send_request(request, response);
	if (res == 0)
	{
		fi->fh = response.pPkt->response.fd_id_out; // 使用C风格指针强制转换
	}

	return res;
}

// CLOSE操作
static int nfs_release(const char *path, struct fuse_file_info *fi)
{
	CommunicationPacket request;
	request.init(CommandType::CLOSE);
	request.fd_id_in = fi->fh; // 使用C风格指针强制转换

	CmdResponse response;
	return send_request(request, response);
}

// FUSE操作结构体
static struct fuse_operations nfs_oper =
{ 0 };

void Init_Nfs_Opper(struct fuse_operations &oper)
{
	//oper.init = nfs_init;
	//oper.destroy = nfs_destroy;
	oper.getattr = nfs_getattr;
	oper.utimens = nfs_utimens;
	oper.readdir = nfs_readdir;
	oper.create = nfs_create;
	oper.mkdir = nfs_mkdir;
	oper.rmdir = nfs_rmdir;
	oper.unlink = nfs_unlink;
	oper.rename = nfs_rename;
	oper.link = nfs_link;
	oper.symlink = nfs_symlink;
	oper.readlink = nfs_readlink;
	oper.fsync = nfs_fsync;
	oper.open = nfs_open;
	oper.read = nfs_read;      // 优化大文件读取
	oper.write = nfs_write;     // 优化大文件写入
	oper.release = nfs_release;
}

int client_main(int argc, char *argv[])
{
	skapi_global_init();
	Init_Nfs_Opper(nfs_oper);

	print_with_time_and_thread(LOG_WARN, "Network file system client starting...\n");
	print_with_time_and_thread(LOG_WARN, "Connecting to server: %s:%d\n", SERVER_IP.c_str(), SERVER_PORT);
	print_with_time_and_thread(LOG_ERROR, "Authentication password: %s\n", AUTH_PASSWORD.c_str());

	return fuse_main(argc, argv, &nfs_oper, NULL);
}

main

#include <stdio.h>
#include <string.h>

#ifdef _WIN32
#include <WinSock2.h>
#include <Windows.h>
#include <Shlwapi.h>
#include "AWConv.h"
#else//!win
#include <sys/mount.h>
#endif//_WIN32

#include <string>

#define FUSE_USE_VERSION 30
#include <fuse3/fuse.h>

using namespace std;

#include "FuseClient.h"
#include "FuseServer.h"
#include "SockMgr.h"
#include "Utils.h"
#include "Config.h"


void LoadCfg()
{
	ConfigMap cfmp = ConfigParser::load(Utils::GetPathUnderFolderOfCurrentModule("myfuse.conf"));
	if (cfmp["SERVER_IP"].length())
		SERVER_IP = cfmp["SERVER_IP"];
	if (cfmp["AUTH_PASSWORD"].length())
		AUTH_PASSWORD = cfmp["AUTH_PASSWORD"];
	if (cfmp["SHARE_DIR"].length())
		SHARE_DIR = cfmp["SHARE_DIR"];
	if (cfmp["SERVER_PORT"].length())
		SERVER_PORT = atoi(cfmp["SERVER_PORT"].c_str());
	if (SHARE_DIR.compare(".") == 0)
	{
		wchar_t szExe[MAX_PATH] = {};
		::GetModuleFileNameW(0, szExe, MAX_PATH);
		PathAppendW(szExe, L"..");
		SHARE_DIR = (LPCSTR)MyCW2A(szExe, CP_UTF8);
	}
}


//#define TEST_SERV

#ifndef _WIN32
/**
 * @brief 卸载FUSE文件系统
 * @param mountpoint 挂载点路径
 * @param lazy 是否延迟卸载(对应 -z 选项)
 * @return 0成功,-1失败
 *
 * 等价于: fusermount3 -z -u <mountpoint>
 */
int fuse_unmount(const char* mountpoint, int lazy) {
	if (mountpoint == NULL) {
		errno = EINVAL;
		return -1;
	}

	int flags = 0;

	// -z 选项:延迟卸载(lazy unmount)
	if (lazy) {
		flags |= MNT_DETACH;
	}

	// -u 选项:卸载操作
	// umount2() 是 Linux 特有的系统调用
	if (umount2(mountpoint, flags) != 0) {
		return -1;
	}

	return 0;
}
#endif // !_WIN32

int main(int argc, char *argv[])
{
#ifdef _WIN32
	SetConsoleOutputCP(CP_UTF8);
	SetConsoleCP(CP_UTF8);
#endif//_WIN32

	LoadCfg();

	//<app> --server 
	if (argc >= 2 && argv[1] && strcmp(argv[1], "--server") == 0)
		return server_main();

	//test create server
#ifdef TEST_SERV
	char exe[MAX_PATH] = {}; GetModuleFileNameA(0, exe, MAX_PATH);
	ShellExecuteA(0, "open", (exe), " --server", 0, SW_SHOW);
#endif//!TEST_SERV

#ifndef _WIN32
	string mount_point = argv[1];
	int ur = fuse_unmount(mount_point.c_str(), 1);
	printf("ur=%d,%d\n", ur, errno);

	// 设置FUSE选项
	const char *newargvs[10] =
		{ argv[0], argv[1], "-f", "-s", "-oallow_other" };
	struct fuse_args args = FUSE_ARGS_INIT(5, (char**) newargvs);

	// 挂载FUSE文件系统
	return client_main(args.argc, args.argv);

#else//_WIN32
	return client_main(argc, argv);
#endif // _WIN32
}

Utils

#include "FS_Util.h"
#include "AWConv.h"
#include <string.h>
#include <vector>
#include <filesystem>
#include "CStringUtil.h"

#ifdef _WIN32
#include <Windows.h>
#include <strsafe.h>
#include <Shlwapi.h>
#include <io.h>
#else//_WIN32
#include <unistd.h>
#endif//_WIN32

#include "md5.h"

//必须使用fuse3 接口   .
#define FUSE_USE_VERSION 30
#include <fuse3/fuse.h>

#include "Utils.h"

#define PATH_MAX 4096

#ifdef _WIN32
namespace fs = std::experimental::filesystem::v1;
#else//!_WIN32
namespace fs = std::filesystem;
#endif // _WIN32

using namespace std;

#ifdef _WIN32
uint64_t get_file_index(const wchar_t* path)
{
	HANDLE hFile = INVALID_HANDLE_VALUE;
	if (PathIsDirectory(path))
	{
		// 先尝试直接打开文件或目录
		hFile = CreateFileW(
			path,
			GENERIC_READ,
			FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
			NULL,
			OPEN_EXISTING,
			FILE_FLAG_BACKUP_SEMANTICS | FILE_ATTRIBUTE_NORMAL,  // 关键:FILE_FLAG_BACKUP_SEMANTICS
			NULL
		);
	}
	else
	{
		hFile = CreateFileW(
			path,
			GENERIC_READ,
			FILE_SHARE_READ,
			NULL,
			OPEN_EXISTING,
			FILE_ATTRIBUTE_NORMAL,
			NULL
		);
	}

	if (hFile == INVALID_HANDLE_VALUE) {
		return 0;
	}

	BY_HANDLE_FILE_INFORMATION fileInfo;
	if (!GetFileInformationByHandle(hFile, &fileInfo)) {
		CloseHandle(hFile);
		return 0;
	}

	CloseHandle(hFile);

	// 拼接64位File Index
	return ((uint64_t)fileInfo.nFileIndexHigh << 32) | fileInfo.nFileIndexLow;
}

static uint64_t get_inode_from_file_index(const wchar_t* path) {

	// 获取File Index
	uint64_t file_index = get_file_index(path);

	// 组合设备号和File Index
	return ((uint64_t)3 << 40) | (file_index & 0xFFFFFFFFFFULL);
}
#endif//_WIN32

bool FsUtil_GetAttr(const char *fn, FsAttr &atr, int& et, int& er)
{
	try
	{
		memset(&atr, 0, sizeof(FsAttr));

#ifdef _WIN32
		std::wstring wsPath = MyCA2W(fn, CP_UTF8);
		//Utils::_FormatWindowsPathW(wsPath);

		WIN32_FILE_ATTRIBUTE_DATA fileData = { 0 };
		if (!GetFileAttributesExW(wsPath.c_str(), GetFileExInfoStandard, &fileData)) {
			// 处理错误:文件不存在、权限不足等
			er = GetLastError();
			et = FSUTIL_GATTR_gaex;
			//if (er == ERROR_FILE_NOT_FOUND)
			//{
			//	wstring t = wsPath;
			//	Utils::_FormatWindowsPathW(t);
			//	if (PathFileExistsW(t.c_str()))
			//	{
			//		printf("!!! File Exist %s\n", fn);
			//	}
			//}
			return false;
		}

		// 转换文件时间(Windows FILETIME转time_t)
		FILETIME ft = {};
		LARGE_INTEGER li = {};

		// 最后访问时间
		ft = fileData.ftLastAccessTime;
		li.LowPart = ft.dwLowDateTime;
		li.HighPart = ft.dwHighDateTime;
		atr.mst_atime = (li.QuadPart - 116444736000000000LL) / 10000000LL;

		// 最后修改时间
		ft = fileData.ftLastWriteTime;
		li.LowPart = ft.dwLowDateTime;
		li.HighPart = ft.dwHighDateTime;
		atr.mst_mtime = (li.QuadPart - 116444736000000000LL) / 10000000LL;

		// 最后状态改变时间(创建时间)
		ft = fileData.ftCreationTime;
		li.LowPart = ft.dwLowDateTime;
		li.HighPart = ft.dwHighDateTime;
		atr.mst_ctime = (li.QuadPart - 116444736000000000LL) / 10000000LL;

		// 文件大小
		atr.mst_size = (static_cast<uint64_t>(fileData.nFileSizeHigh) << 32) | fileData.nFileSizeLow;

		// 文件类型和权限
		if (fileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
			atr.mst_isdir = true;
		}
		else {
			atr.mst_isdir = false;
		}

		//link
		if (fileData.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
		{
			atr.mst_islink = true;
		}
		atr.mst_ino = get_inode_from_file_index(wsPath.c_str());

#else //! _WIN32
		struct stat statbuf;
		if (stat(fn, &statbuf) != 0)
		{
			// 处理错误:文件不存在、权限不足等
			return false;
		}

		// 直接复制stat结构体中的字段
		//atr.mst_mode = static_cast<unsigned short>(statbuf.st_mode);
		atr.mst_isdir = S_ISDIR(statbuf.st_mode);
		atr.mst_islink = S_ISLNK(statbuf.st_mode);
		atr.mst_size = static_cast<uint64_t>(statbuf.st_size);
		atr.mst_atime = statbuf.st_atime;
		atr.mst_mtime = statbuf.st_mtime;
		atr.mst_ctime = statbuf.st_ctime;
		atr.mst_ino = statbuf.st_ino;

#endif//_WIN32

		return true; // 获取属性成功
	}
	catch (...)
	{
#ifdef _WIN32
		er = GetLastError();
#endif//_WIN32
		et = FSUTIL_GATTR_except;
		return false;
	}
	return false;
}

int my_unlink(const char * fn)
{
#ifdef _WIN32
	std::wstring wsPath = MyCA2W(fn, CP_UTF8);
	BOOL bRet = ::DeleteFileW(wsPath.c_str());
	if (!bRet)
	{
		DWORD err = GetLastError();
		if (err == ERROR_ACCESS_DENIED)
			return EACCES;
		return EIO;
	}
	return 0;

#else//!_WIN32
	return unlink(fn);
#endif // _WIN32
}

string FA2str(FsAttr & fa)
{
	string sr;
	CStrUtilA::Format(sr, "%llu,%llu,%llu,%llu,%llu,%d,%d",
		(unsigned long long)fa.mst_ino,
		(unsigned long long)fa.mst_size,
		(unsigned long long)fa.mst_atime,
		(unsigned long long)fa.mst_mtime,
		(unsigned long long)fa.mst_ctime,
		(int)fa.mst_isdir,
		(int)fa.mst_islink
	);
	return sr;
}

void FAfromStr(FsAttr & fa, const char * fas)
{
	unsigned long long fa_mst_ino = 0;
	unsigned long long fa_mst_size = 0;
	unsigned long long fa_mst_atim = 0;
	unsigned long long fa_mst_mtim = 0;
	unsigned long long fa_mst_ctim = 0;
	int mst_isdir = 0;
	int mst_islink = 0;

	sscanf(fas, "%llu,%llu,%llu,%llu,%llu,%d,%d",
		&fa_mst_ino,
		&fa_mst_size,
		&fa_mst_atim,
		&fa_mst_mtim,
		&fa_mst_ctim,
		&mst_isdir,
		&mst_islink
	);
	fa.mst_ino = fa_mst_ino;
	fa.mst_size = fa_mst_size;
	fa.mst_atime = fa_mst_atim;
	fa.mst_mtime = fa_mst_mtim;
	fa.mst_ctime = fa_mst_ctim;
	fa.mst_isdir = mst_isdir;
	fa.mst_islink = mst_islink;
}

#ifdef _WIN32
extern int futimens_winfh(HANDLE hFile, const struct timespec times[2]);

/**
 * Windows下实现与Linux utimensat相同功能的函数
 * @param dirfd: 目录文件描述符(Windows下忽略)
 * @param pathname: 文件路径
 * @param times: 时间数组,times[0]为访问时间,times[1]为修改时间
 * @param flags: 标志位(Windows下仅支持AT_SYMLINK_NOFOLLOW)
 * @return: 0表示成功,负数表示错误码
 */
int utimensat(int dirfd, const char* pathname, const struct timespec times[2], int flags)
{
	// Windows下忽略dirfd,直接使用绝对路径或相对路径
	std::wstring wpath = MyCA2W(pathname, CP_UTF8);

	// 确定打开方式
	DWORD desired_access = FILE_WRITE_ATTRIBUTES;
	DWORD share_mode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
	DWORD creation_disposition = OPEN_EXISTING;
	DWORD flags_and_attributes = FILE_FLAG_BACKUP_SEMANTICS;

	//// 如果需要修改符号链接本身的时间
	//if (flags & AT_SYMLINK_NOFOLLOW) {
	//	flags_and_attributes |= FILE_FLAG_OPEN_REPARSE_POINT;
	//}

	HANDLE hFile = CreateFileW(wpath.c_str(), desired_access, share_mode, NULL, creation_disposition, flags_and_attributes, NULL);
	if (hFile == INVALID_HANDLE_VALUE) {
		DWORD win_err = GetLastError();
		// 转换Windows错误码到errno
		switch (win_err) {
		case ERROR_ACCESS_DENIED:
			errno = EACCES;
			break;
		case ERROR_FILE_NOT_FOUND:
			errno = ENOENT;
			break;
		case ERROR_PATH_NOT_FOUND:
			errno = ENOENT;
			break;
		case ERROR_SHARING_VIOLATION:
			errno = EBUSY;
			break;
		default:
			errno = EINVAL;
			break;
		}
		return -1;
	}

	// 使用futimens实现相同逻辑
	int result = futimens_winfh(hFile, times);
	CloseHandle(hFile);
	return result;
}

//// 定义renameat2的标志常量(与Linux对齐)
//enum {
//	RENAME_NOREPLACE = 1 << 0,  // 禁止覆盖已存在的目标文件
//	RENAME_EXCHANGE = 1 << 1   // 交换源和目标文件(仅当两者都存在时)
//};

/**
 * @brief 模拟Linux renameat2函数的行为(忽略fd参数,使用路径)
 * @param oldpath 源文件路径
 * @param newpath 目标文件路径
 * @param flags 控制标志(RENAME_NOREPLACE/RENAME_EXCHANGE)
 * @return 0成功,-1失败并设置errno
 */
int my_renameat2(const char* oldpath, const char* newpath, unsigned int flags) {
	if (oldpath == nullptr || newpath == nullptr) {
		errno = EINVAL;
		return -1;
	}

	// 转换为宽字符路径(Windows API要求)
	std::wstring w_oldpath = MyCA2W(oldpath, CP_UTF8);
	std::wstring w_newpath = MyCA2W(newpath, CP_UTF8);

	// 处理RENAME_EXCHANGE标志(交换两个文件)
	if (flags & RENAME_EXCHANGE) {
		// 检查两个文件是否都存在
		if (GetFileAttributesW(w_oldpath.c_str()) == INVALID_FILE_ATTRIBUTES ||
			GetFileAttributesW(w_newpath.c_str()) == INVALID_FILE_ATTRIBUTES) {
			errno = ENOENT;
			return -1;
		}

		// 创建临时文件名
		wchar_t temp_path[MAX_PATH] = {};
		wchar_t tmpDir[MAX_PATH] = {};
		StringCchCopyW(tmpDir, MAX_PATH, w_oldpath.c_str());
		PathAppendW(tmpDir, L"..");
		if (!GetTempFileNameW(tmpDir, L"rnxtmp", 0, temp_path)) {
			errno = EIO;
			return -1;
		}

		// 交换逻辑:old -> temp -> new -> old
		if (!MoveFileExW(w_oldpath.c_str(), temp_path, MOVEFILE_REPLACE_EXISTING)) {
			DeleteFileW(temp_path);
			errno = EIO;
			return -1;
		}
		if (!MoveFileExW(w_newpath.c_str(), w_oldpath.c_str(), MOVEFILE_REPLACE_EXISTING)) {
			MoveFileExW(temp_path, w_oldpath.c_str(), MOVEFILE_REPLACE_EXISTING);
			DeleteFileW(temp_path);
			errno = EIO;
			return -1;
		}
		if (!MoveFileExW(temp_path, w_newpath.c_str(), MOVEFILE_REPLACE_EXISTING)) {
			MoveFileExW(w_oldpath.c_str(), w_newpath.c_str(), MOVEFILE_REPLACE_EXISTING);
			MoveFileExW(temp_path, w_oldpath.c_str(), MOVEFILE_REPLACE_EXISTING);
			DeleteFileW(temp_path);
			errno = EIO;
			return -1;
		}

		DeleteFileW(temp_path);
		return 0;
	}

	// 处理RENAME_NOREPLACE标志(禁止覆盖)
	if (flags & RENAME_NOREPLACE) {
		// 检查目标文件是否存在
		DWORD attr = GetFileAttributesW(w_newpath.c_str());
		if (attr != INVALID_FILE_ATTRIBUTES) {
			errno = EEXIST;  // 目标已存在
			return -1;
		}
	}

	// 执行重命名/移动操作
	DWORD move_flags = MOVEFILE_REPLACE_EXISTING;  // 默认允许覆盖
	if (!MoveFileExW(w_oldpath.c_str(), w_newpath.c_str(), move_flags)) {
		switch (GetLastError()) {
		case ERROR_FILE_NOT_FOUND:
			errno = ENOENT;
			break;
		case ERROR_ACCESS_DENIED:
			errno = EACCES;
			break;
		case ERROR_ALREADY_EXISTS:
			errno = EEXIST;
			break;
		case ERROR_NOT_SAME_DEVICE:
			errno = EXDEV;  // 跨设备移动
			break;
		default:
			errno = EIO;
			break;
		}
		return -1;
	}

	return 0;
}

#else//_WIN32

int my_renameat2(const char *oldpath, const char *newpath, unsigned int flags)
{
	if (oldpath == nullptr || newpath == nullptr)
	{
		errno = EINVAL;
		return -1;
	}

	// 处理RENAME_EXCHANGE标志(交换两个文件)
	if (flags & RENAME_EXCHANGE)
	{
		// 检查两个文件是否都存在
		struct stat st_old, st_new;
		if (stat(oldpath, &st_old) != 0 || stat(newpath, &st_new) != 0)
		{
			errno = ENOENT;
			return -1;
		}

		// 生成临时文件名(在newpath同目录下)
		char temp_path[PATH_MAX];
		char dir_path[PATH_MAX - 16];

		// 提取目录路径
		const char *last_slash = strrchr(newpath, '/');
		if (last_slash != nullptr)
		{
			size_t dir_len = last_slash - newpath;
			if (dir_len >= PATH_MAX)
			{
				errno = ENAMETOOLONG;
				return -1;
			}
			strncpy(dir_path, newpath, dir_len);
			dir_path[dir_len] = '\0';
		}
		else
		{
			strcpy(dir_path, ".");
		}

		// 创建临时文件名
		snprintf(temp_path, PATH_MAX, "%s/.rnxtmp", dir_path);
		int temp_fd = mkstemp(temp_path);
		if (temp_fd == -1)
		{
			return -1;
		}
		close(temp_fd);

		// 交换逻辑:old -> temp, new -> old, temp -> new
		if (rename(oldpath, temp_path) != 0)
		{
			int saved_errno = errno;
			unlink(temp_path);
			errno = saved_errno;
			return -1;
		}

		if (rename(newpath, oldpath) != 0)
		{
			int saved_errno = errno;
			rename(temp_path, oldpath); // 回滚
			unlink(temp_path);
			errno = saved_errno;
			return -1;
		}

		if (rename(temp_path, newpath) != 0)
		{
			int saved_errno = errno;
			rename(oldpath, newpath); // 回滚第二步
			rename(temp_path, oldpath); // 回滚第一步
			unlink(temp_path);
			errno = saved_errno;
			return -1;
		}

		unlink(temp_path); // 清理临时文件(如果还存在)
		return 0;
	}

	// 处理RENAME_NOREPLACE标志(禁止覆盖)
	if (flags & RENAME_NOREPLACE)
	{
		// 检查目标文件是否存在
		struct stat st;
		if (stat(newpath, &st) == 0)
		{
			errno = EEXIST; // 目标已存在
			return -1;
		}
		// 如果stat失败但不是因为文件不存在,需要处理
		if (errno != ENOENT)
		{
			return -1;
		}
	}

	// 执行标准重命名操作
	return rename(oldpath, newpath);
}
#endif//_WIN32

std::string get_realitive_path(const std::string baseP, const std::string fullP)
{
	string strRoot = baseP;
	Utils::_FormatWindowsPathA(strRoot);
	string strFull = fullP;
	Utils::_FormatWindowsPathA(strFull);
	if (strFull.length() > strRoot.length())
	{
		size_t rightLen = strFull.length() - strRoot.length();
		string strLeft = strFull.substr(0, strRoot.length());
		string strRight = strFull.substr(strFull.length() - rightLen);
		if (Utils::MyStricmp(strLeft.c_str(), strRoot.c_str()) == 0 && strRight[0] == '\\')
		{
			return strRight.substr(1);
		}
	}
	throw std::runtime_error("cant open link");
}

#ifdef _WIN32

unsigned int linux_open_flag_to_win(unsigned int lflg)
{
	unsigned int ret = 0;
	unsigned int acc = lflg & LNX_O_ACCMODE;

	unsigned int accR = 0;
	if (acc == LNX_O_RDONLY)
		accR = O_RDONLY;
	else if (acc == LNX_O_WRONLY)
		accR = O_WRONLY;
	else if (acc == LNX_O_RDWR)
		accR = O_RDWR;

	if (lflg & LNX_O_CREAT)
	{
		ret |= _O_CREAT;
		if (lflg & LNX_O_EXCL)
		{
			// Windows不支持原子性的O_EXCL,需在调用后额外检查
			ret |= _O_EXCL;
		}
	}
	if (lflg & LNX_O_TRUNC)
		ret |= O_TRUNC;
	if (lflg & LNX_O_APPEND)
		ret |= O_APPEND;

	return ret | accR;
}

unsigned int linux_open_mode_to_win(unsigned int lmod)
{
	unsigned int ret = 0;

	if (lmod & (LNX_S_IRUSR | LNX_S_IRGRP | LNX_S_IROTH))
		ret |= _S_IREAD;

	if (lmod & (LNX_S_IWUSR | LNX_S_IWGRP | LNX_S_IWOTH))
		ret |= _S_IWRITE;

	//if (lmod & (LNX_S_IXUSR | LNX_S_IXGRP | LNX_S_IXOTH))
	//	ret |= _S_IEXEC;

	return ret;
}

#endif//_WIN32

unsigned long long HashData(const char * buf, size_t size)
{
#ifdef CHECK_RW
	unsigned long long byMd5[2] = { 0 };
	MD5_CTX ctx;
	QHMD5Init(&ctx);
	QHMD5Update(&ctx, (unsigned char*)buf, (unsigned int)size);
	QHMD5Final((unsigned char*)byMd5, &ctx);
	return byMd5[0];
#else//CHECK_RW
	return 0;
#endif // CHECK_RW
}

low-io

#ifdef _WIN32

#include <Windows.h>
#include "win_lowio.h"
#include <string>
#include "AWConv.h"
#include <new>
#include <filesystem>
#include "FS_Util.h"

#ifdef _WIN32
namespace fs = std::experimental::filesystem::v1;
#else//!_WIN32
namespace fs = std::filesystem;
#endif // _WIN32

struct WLO_HANDLEST
{
	HANDLE hFile = INVALID_HANDLE_VALUE;
};

#define WLOHANDLEST(fh) (*((WLO_HANDLEST*)(fh)))

wlo_handle _alloc_osfhnd()
{
	WLO_HANDLEST* p = new(std::nothrow) WLO_HANDLEST;
	if (!p)
		return -1;
	return (wlo_handle)p;
}

void _free_osfhnd(wlo_handle h)
{
	if (h && h != -1)
	{
		delete (WLO_HANDLEST*)(h);
	}
}

DWORD const GENERIC_READ_WRITE = (GENERIC_READ | GENERIC_WRITE);

#define _VALIDATE_RETURN_ERRCODE(expr, err) \
    do { \
        if (!(expr)) { \
            return err; \
        } \
    } while (0)

#define _VALIDATE_RETURN(expr, err, ret) \
    do { \
        if (!(expr)) { \
            _set_errno(err); \
            return ret; \
        } \
    } while (0)

struct file_options
{
	// These are the flags that are used for the osflag of the CRT file
	// object that is created.
	char  crt_flags;

	// These are the flags that are eventually passed to CreateFile to tell
	// the Operating System how to create the file:
	DWORD access;
	DWORD create;
	DWORD share;
	DWORD attributes;
	DWORD flags;
};


#define _O_RDONLY      0x0000  // open for reading only
#define _O_WRONLY      0x0001  // open for writing only
#define _O_RDWR        0x0002  // open for reading and writing
#define _O_APPEND      0x0008  // writes done at eof

#define _O_CREAT       0x0100  // create and open file
#define _O_TRUNC       0x0200  // open and truncate
#define _O_EXCL        0x0400  // open only if file doesn't already exist

#define _O_TEXT        0x4000  // file mode is text (translated)
#define _O_BINARY      0x8000  // file mode is binary (untranslated)
#define _O_WTEXT       0x10000 // file mode is UTF16 (translated)
#define _O_U16TEXT     0x20000 // file mode is UTF16 no BOM (translated)
#define _O_U8TEXT      0x40000 // file mode is UTF8  no BOM (translated)

#define _O_NOINHERIT   0x0080  // child process doesn't inherit file
#define _O_TEMPORARY   0x0040  // temporary file bit (file is deleted when last handle is closed)
#define _O_SHORT_LIVED 0x1000  // temporary storage file, try not to flush
#define _O_OBTAIN_DIR  0x2000  // get information about a directory
#define _O_SEQUENTIAL  0x0020  // file access is primarily sequential
#define _O_RANDOM      0x0010  // file access is primarily random


#define _SH_DENYRW      0x10    // deny read/write mode
#define _SH_DENYWR      0x20    // deny write mode
#define _SH_DENYRD      0x30    // deny read mode
#define _SH_DENYNO      0x40    // deny none mode
#define _SH_SECURE      0x80    // secure mode

#define _S_IFMT   0xF000 // File type mask
#define _S_IFDIR  0x4000 // Directory
#define _S_IFCHR  0x2000 // Character special
#define _S_IFIFO  0x1000 // Pipe
#define _S_IFREG  0x8000 // Regular
#define _S_IREAD  0x0100 // Read permission, owner
#define _S_IWRITE 0x0080 // Write permission, owner
#define _S_IEXEC  0x0040 // Execute/search permission, owner

static DWORD decode_open_create_flags(int const oflag) throw()
{
	switch (oflag & (_O_CREAT | _O_EXCL | _O_TRUNC))
	{
	case 0:
	case _O_EXCL: // ignore EXCL w/o CREAT
		return OPEN_EXISTING;

	case _O_CREAT:
		return OPEN_ALWAYS;

	case _O_CREAT | _O_EXCL:
	case _O_CREAT | _O_TRUNC | _O_EXCL:
		return CREATE_NEW;

	case _O_TRUNC:
	case _O_TRUNC | _O_EXCL: // ignore EXCL w/o CREAT
		return TRUNCATE_EXISTING;

	case _O_CREAT | _O_TRUNC:
		return CREATE_ALWAYS;
	}

	// This is unreachable, but the compiler can't tell.
	_VALIDATE_RETURN(("Invalid open flag", 0), EINVAL, static_cast<DWORD>(-1));
	return 0;
}

static DWORD decode_access_flags(int const oflag) throw()
{
	switch (oflag & (_O_RDONLY | _O_WRONLY | _O_RDWR))
	{
	case _O_RDONLY:
		return GENERIC_READ;

	case _O_WRONLY:
		// If the file is being opened in append mode, we give read access as
		// well because in append (a, not a+) mode, we need to read the BOM to
		// determine the encoding (ANSI, UTF-8, or UTF-16).
		if ((oflag & _O_APPEND) && (oflag & (_O_WTEXT | _O_U16TEXT | _O_U8TEXT)) != 0)
			return GENERIC_READ | GENERIC_WRITE;

		return GENERIC_WRITE;

	case _O_RDWR:
		return GENERIC_READ | GENERIC_WRITE;
	}

	// This is unreachable, but the compiler can't tell.
	_VALIDATE_RETURN(("Invalid open flag", 0), EINVAL, static_cast<DWORD>(-1));
	return 0;
}

static DWORD decode_sharing_flags(int const shflag, int const access) throw()
{
	switch (shflag)
	{
	case _SH_DENYRW:
		return 0;

	case _SH_DENYWR:
		return FILE_SHARE_READ;

	case _SH_DENYRD:
		return FILE_SHARE_WRITE;

	case _SH_DENYNO:
		return FILE_SHARE_READ | FILE_SHARE_WRITE;

	case _SH_SECURE:
		if (access == GENERIC_READ)
			return FILE_SHARE_READ;
		else
			return 0;
	}

	_VALIDATE_RETURN(("Invalid sharing flag", 0), EINVAL, static_cast<DWORD>(-1));
	return 0;
}

static file_options decode_options(int const oflag, int const shflag, int const pmode) throw()
{
	file_options result;
	result.crt_flags = 0;
	result.access = decode_access_flags(oflag);
	result.create = decode_open_create_flags(oflag);
	result.share = decode_sharing_flags(shflag, result.access);
	result.attributes = FILE_ATTRIBUTE_NORMAL;
	result.flags = 0;

	if (oflag & _O_TEMPORARY)
	{
		result.flags |= FILE_FLAG_DELETE_ON_CLOSE;
		result.access |= DELETE;
		result.share |= FILE_SHARE_DELETE;
	}

	if (oflag & _O_SHORT_LIVED)
	{
		result.attributes |= FILE_ATTRIBUTE_TEMPORARY;
	}

	if (oflag & _O_OBTAIN_DIR)
	{
		result.flags |= FILE_FLAG_BACKUP_SEMANTICS;
	}

	if (oflag & _O_SEQUENTIAL)
	{
		result.flags |= FILE_FLAG_SEQUENTIAL_SCAN;
	}
	else if (oflag & _O_RANDOM)
	{
		result.flags |= FILE_FLAG_RANDOM_ACCESS;
	}

	return result;
}

static HANDLE __cdecl create_file(
	PCWSTR               const path,
	SECURITY_ATTRIBUTES* const security_attributes,
	file_options         const options
) throw()
{
	return CreateFileW(
		path,
		options.access,
		options.share,
		security_attributes,
		options.create,
		options.flags | options.attributes,
		nullptr);
}

static errno_t __cdecl _wsopen_nolock(
	int*           const punlock_flag,
	wlo_handle*    const pfh,
	wchar_t const* const path,
	int            const oflag,
	int            const shflag,
	int            const pmode,
	int            const secure
)
{
	UNREFERENCED_PARAMETER(secure);

	// First, do the initial parse of the options.  The only thing that can fail
	// here is the parsing of the share options, in which case -1 is returned
	// and errno is set.
	file_options options = decode_options(oflag, shflag, pmode);
	if (options.share == static_cast<DWORD>(-1))
	{
		_doserrno = 0;
		*pfh = -1;
		return errno;
	}

	// Allocate the CRT file handle.  Note that if a handle is allocated, it is
	// locked when it is returned by the allocation function.  It is our caller's
	// responsibility to unlock the file handle (we do not unlock it before
	// returning).
	*pfh = _alloc_osfhnd();
	if (*pfh == -1)
	{
		_doserrno = 0;
		*pfh = -1;
		errno = EMFILE;
		return errno;
	}

	// Beyond this point, do not change *pfh, even if an error occurs.  Our
	// caller requires the handle in order to release its lock.
	*punlock_flag = 1;

	SECURITY_ATTRIBUTES security_attributes;
	security_attributes.nLength = sizeof(security_attributes);
	security_attributes.lpSecurityDescriptor = nullptr;
	security_attributes.bInheritHandle = (oflag & _O_NOINHERIT) == 0;


	// Try to open or create the file:
	HANDLE os_handle = create_file(path, &security_attributes, options);
	if (os_handle == INVALID_HANDLE_VALUE)
	{
		if ((options.access & GENERIC_READ_WRITE) == GENERIC_READ_WRITE && (oflag & _O_WRONLY))
		{
			// The call may have failed because we may be trying to open
			// something for reading that does not allow reading (e.g. a pipe or
			// a device).  So, we try again with just GENERIC_WRITE.  If this
			// succeeds, we will have to assume the default encoding because we
			// will have no way to read the BOM.
			options.access &= ~GENERIC_READ;

			os_handle = create_file(path, &security_attributes, options);
		}
	}

	if (os_handle == INVALID_HANDLE_VALUE)
	{
		_free_osfhnd(*pfh);
		*pfh = -1;
		return EACCES;
	}
	WLOHANDLEST(*pfh).hFile = os_handle;

	return 0; // Success!
}


static errno_t __cdecl _sopen_nolock(
	int*        const punlock_flag,
	wlo_handle* const pfh,
	char const* const path,
	int         const oflag,
	int         const shflag,
	int         const pmode,
	int         const secure
)
{
	std::wstring wide_path;
	try
	{
		wide_path = MyCA2W(path, CP_UTF8);
	}
	catch (...)
	{
		return -1;
	}

	return _wsopen_nolock(punlock_flag, pfh, wide_path.c_str(), oflag, shflag, pmode, secure);
}

static int __cdecl common_sopen_dispatch(
	char const* const path,
	int              const oflag,
	int              const shflag,
	int              const pmode,
	wlo_handle*      const pfh,
	int              const secure
) throw()
{
	_VALIDATE_RETURN_ERRCODE(pfh != nullptr, EINVAL);
	*pfh = -1;

	_VALIDATE_RETURN_ERRCODE(path != nullptr, EINVAL);

	if (secure)
	{
		_VALIDATE_RETURN_ERRCODE((pmode & (~(_S_IREAD | _S_IWRITE))) == 0, EINVAL);
	}

	int unlock_flag = 0;
	errno_t error_code = 0;
	error_code = _sopen_nolock(&unlock_flag, pfh, path, oflag, shflag, pmode, secure);

	if (error_code != 0)
	{
		*pfh = -1;
	}

	return error_code;
}

static int __cdecl _sopen_dispatch(
	char const* const path,
	int         const oflag,
	int         const shflag,
	int         const pmode,
	wlo_handle* const pfh,
	int         const secure
)
{
	return common_sopen_dispatch(path, oflag, shflag, pmode, pfh, secure);
}

static int __cdecl _sopen_s(
	wlo_handle*        const pfh,
	char const* const path,
	int         const oflag,
	int         const shflag,
	int         const pmode
)
{
	// The last argument is 1 so that pmode is validated in open_s:
	return _sopen_dispatch(path, oflag, shflag, pmode, pfh, 1/*TRUE*/);
}


// Creates a new file.
//
// If the file does not exist, this function creates a new file with the given
// permission setting and opens it for writing.  If the file already exists and
// its permission allows writing, this function truncates it to zero length and
// opens it for writing.
//
// The only XENIX mode bit supported is user write (S_IWRITE).
//
// On success, the handle for the newly created file is returned.  On failure,
// -1 is returned and errno is set.
static wlo_handle common_creat(char const* const path, int const pmode) throw()
{
	wlo_handle fh = -1;
	errno_t e = _sopen_s(&fh, path, _O_CREAT + _O_TRUNC + _O_RDWR, _SH_DENYNO, pmode);
	return e == 0 ? fh : -1;
}

wlo_handle wlo_create(char const* const path, int const pmode)
{
	return common_creat(path, pmode);
}

void wlo_close(wlo_handle fh)
{
	if (fh != -1 && fh)
	{
		if (WLOHANDLEST(fh).hFile != INVALID_HANDLE_VALUE)
		{
			CloseHandle(WLOHANDLEST(fh).hFile);
			WLOHANDLEST(fh).hFile = INVALID_HANDLE_VALUE;
		}
		_free_osfhnd(fh);
	}
}

static wlo_handle __cdecl common_open(
	char const* const  path,
	int              const  oflag,
	int              const  pmode
) throw()
{
	_VALIDATE_RETURN(path != nullptr, EINVAL, -1);

	wlo_handle fh = -1;
	int unlock_flag = 0;
	errno_t error_code = 0;
	error_code = _sopen_nolock(&unlock_flag, &fh, path, oflag, _SH_DENYNO, pmode, 0);


	if (error_code != 0)
	{
		errno = error_code;
		return -1;
	}

	return fh;
}

wlo_handle wlo_open(char const* const path, int const oflag, ...)
{
	va_list arglist;
	va_start(arglist, oflag);
	int const pmode = va_arg(arglist, int);
	va_end(arglist);

	return common_open(path, oflag, pmode);
}

// 将文件指针设置到指定位置,返回新的偏移量
long long wlo_seek64(wlo_handle fh, long long offset, int _Origin)
{
	// 验证句柄有效性
	_VALIDATE_RETURN(fh != -1 && fh != 0, EBADF, static_cast<long long>(-1));

	// 验证文件句柄有效性
	if (WLOHANDLEST(fh).hFile == INVALID_HANDLE_VALUE)
	{
		errno = EBADF;
		return static_cast<long long>(-1);
	}

	// 转换CRT的origin为Windows的DWORD类型
	DWORD moveMethod;
	switch (_Origin)
	{
	case SEEK_SET:
		moveMethod = FILE_BEGIN;
		break;
	case SEEK_CUR:
		moveMethod = FILE_CURRENT;
		break;
	case SEEK_END:
		moveMethod = FILE_END;
		break;
	default:
		_VALIDATE_RETURN(("Invalid seek origin", 0), EINVAL, static_cast<long long>(-1));
		return static_cast<long long>(-1); // 编译器需要的返回值
	}

	// 使用SetFilePointerEx进行64位文件定位
	LARGE_INTEGER liDistanceToMove;
	LARGE_INTEGER liNewFilePointer;

	liDistanceToMove.QuadPart = offset;

	if (!SetFilePointerEx(WLOHANDLEST(fh).hFile, liDistanceToMove, &liNewFilePointer, moveMethod))
	{
		// 获取Windows错误码并转换为errno
		DWORD win_err = GetLastError();
		switch (win_err)
		{
		case ERROR_ACCESS_DENIED:
			errno = EACCES;
			break;
		case ERROR_INVALID_PARAMETER:
			errno = EINVAL;
			break;
		default:
			errno = EIO;
			break;
		}
		return static_cast<long long>(-1);
	}

	// 返回新的文件偏移量
	return liNewFilePointer.QuadPart;
}

// 从文件中读取数据,返回实际读取的字节数
int wlo_read(wlo_handle fh, void* _DstBuf, unsigned int _MaxCharCount)
{
	// 验证句柄有效性
	_VALIDATE_RETURN(fh != -1 && fh != 0, EBADF, -1);

	// 验证输出缓冲区指针
	_VALIDATE_RETURN(_DstBuf != nullptr, EINVAL, -1);

	// 验证文件句柄有效性
	if (WLOHANDLEST(fh).hFile == INVALID_HANDLE_VALUE)
	{
		errno = EBADF;
		return -1;
	}

	// 读取文件内容
	DWORD bytesRead;
	if (!ReadFile(WLOHANDLEST(fh).hFile, _DstBuf, static_cast<DWORD>(_MaxCharCount), &bytesRead, nullptr))
	{
		// 获取Windows错误码并转换为errno
		DWORD win_err = GetLastError();
		switch (win_err)
		{
		case ERROR_ACCESS_DENIED:
			errno = EACCES;
			break;
		case ERROR_HANDLE_EOF:
			return 0; // 文件已结束
		default:
			errno = EIO;
			break;
		}
		return -1;
	}

	// 返回实际读取的字节数
	return static_cast<int>(bytesRead);
}

// 向文件中写入数据,返回实际写入的字节数
int wlo_write(wlo_handle fh, void const* _Buf, unsigned int _MaxCharCount)
{
	// 验证句柄有效性
	_VALIDATE_RETURN(fh != -1 && fh != 0, EBADF, -1);

	// 验证输入缓冲区指针
	_VALIDATE_RETURN(_Buf != nullptr, EINVAL, -1);

	// 验证文件句柄有效性
	if (WLOHANDLEST(fh).hFile == INVALID_HANDLE_VALUE)
	{
		errno = EBADF;
		return -1;
	}

	// 写入文件内容
	DWORD bytesWritten;
	if (!WriteFile(WLOHANDLEST(fh).hFile, _Buf, static_cast<DWORD>(_MaxCharCount), &bytesWritten, nullptr))
	{
		// 获取Windows错误码并转换为errno
		DWORD win_err = GetLastError();
		switch (win_err)
		{
		case ERROR_ACCESS_DENIED:
			errno = EACCES;
			break;

		case ERROR_DISK_FULL:
			errno = ENOSPC;
			break;
		default:
			errno = EIO;
			break;
		}
		return -1;
	}

	// 返回实际写入的字节数
	return static_cast<int>(bytesWritten);
}

int wlo_sync(wlo_handle fh)
{
	// 验证句柄有效性
	_VALIDATE_RETURN(fh != -1 && fh != 0, EBADF, -1);
	// 验证文件句柄有效性
	if (WLOHANDLEST(fh).hFile == INVALID_HANDLE_VALUE)
	{
		errno = EBADF;
		return -1;
	}
	if (FlushFileBuffers(WLOHANDLEST(fh).hFile))
	{
		return 0;
	}

	// 获取Windows错误码并转换为errno
	DWORD win_err = GetLastError();
	switch (win_err)
	{
	case ERROR_ACCESS_DENIED:
		errno = EACCES;
		break;

	case ERROR_WRITE_PROTECT:
		errno = EROFS;
		break;
	case ERROR_DISK_FULL:
		errno = ENOSPC;
		break;
	case ERROR_INVALID_HANDLE:
		errno = EBADF;
		break;
	default:
		errno = EIO;
		break;
	}
	return -1;
}

#ifdef _WIN32

// 定义与Linux兼容的常量
#define UTIME_NOW 1000000001
#define UTIME_OMIT 1000000002

int futimens_winfh(HANDLE hFile, const struct timespec times[2])
{
	if (hFile == INVALID_HANDLE_VALUE) {
		errno = EBADF;
		return -1;
	}

	FILETIME ft_access, ft_modify;
	SYSTEMTIME st;

	// 获取当前时间(如果需要)
	GetSystemTime(&st);
	SystemTimeToFileTime(&st, &ft_access);
	ft_modify = ft_access;

	// 处理访问时间
	if (times != NULL) {
		if (times[0].tv_nsec == UTIME_NOW) {
			// 设置为当前时间(已经获取)
		}
		else if (times[0].tv_nsec != UTIME_OMIT) {
			// 转换timespec到FILETIME
			ULARGE_INTEGER ul;
			ul.QuadPart = (unsigned long long)times[0].tv_sec * 10000000ULL + 116444736000000000ULL;
			ul.QuadPart += times[0].tv_nsec / 100; // 纳秒转换为100纳秒单位
			ft_access.dwLowDateTime = ul.LowPart;
			ft_access.dwHighDateTime = ul.HighPart;
		}
	}

	// 处理修改时间
	if (times != NULL) {
		if (times[1].tv_nsec == UTIME_NOW) {
			// 设置为当前时间(已经获取)
		}
		else if (times[1].tv_nsec != UTIME_OMIT) {
			// 转换timespec到FILETIME
			ULARGE_INTEGER ul;
			ul.QuadPart = (unsigned long long)times[1].tv_sec * 10000000ULL + 116444736000000000ULL;
			ul.QuadPart += times[1].tv_nsec / 100; // 纳秒转换为100纳秒单位
			ft_modify.dwLowDateTime = ul.LowPart;
			ft_modify.dwHighDateTime = ul.HighPart;
		}
	}

	// 设置文件时间
	BOOL result = SetFileTime(hFile, NULL, &ft_access, &ft_modify);
	if (!result) {
		DWORD win_err = GetLastError();
		// 转换Windows错误码到errno
		switch (win_err) {
		case ERROR_ACCESS_DENIED:
			errno = EACCES;
			break;
		case ERROR_FILE_NOT_FOUND:
			errno = ENOENT;
			break;
		case ERROR_PATH_NOT_FOUND:
			errno = ENOENT;
			break;
		case ERROR_INVALID_HANDLE:
			errno = EBADF;
			break;
		default:
			errno = EINVAL;
			break;
		}
		return -1;
	}

	return 0;
}

// 定义符号链接重解析数据的相关常量
#define SYMBOLIC_LINK_REPARSE_TAG IO_REPARSE_TAG_SYMLINK
typedef struct _REPARSE_DATA_BUFFER {
	DWORD  ReparseTag;
	WORD   ReparseDataLength;
	WORD   Reserved;
	union {
		struct {
			WORD SubstituteNameOffset;
			WORD SubstituteNameLength;
			WORD PrintNameOffset;
			WORD PrintNameLength;
			DWORD Flags;
			WCHAR PathBuffer[1];
		} SymbolicLinkReparseBuffer;
		// 其他类型的重解析数据结构(此处省略)
	} u;
} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;

// 符号链接标志定义
#define SYMLINK_FLAG_RELATIVE 0x00000001

/**
 * @brief 获取Windows符号链接的目标路径
 * @param full_path 符号链接的完整路径(UTF-8编码)
 * @return 目标路径(UTF-8编码),如果是相对路径会转换为绝对路径
 * @throws std::runtime_error 当无法获取目标路径时抛出异常,包含错误信息
 */
std::string GetSymbollnkTarget(const std::string& full_path)
{
	// 将UTF-8路径转换为宽字符
	std::wstring wpath = MyCA2W(full_path.c_str(), CP_UTF8);

	// 打开符号链接文件,需要特定标志
	HANDLE hFile = CreateFileW(
		wpath.c_str(),
		GENERIC_READ,
		FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
		nullptr,
		OPEN_EXISTING,
		FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS,
		nullptr
	);

	if (hFile == INVALID_HANDLE_VALUE) {
		throw std::runtime_error("cant open link");
	}

	// 准备接收重解析数据的缓冲区
	std::vector<char> buffer(MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
	DWORD bytes_returned = 0;

	// 发送IO控制码获取重解析数据
	BOOL success = DeviceIoControl(
		hFile,
		FSCTL_GET_REPARSE_POINT,
		nullptr,
		0,
		buffer.data(),
		(DWORD)buffer.size(),
		&bytes_returned,
		nullptr
	);

	CloseHandle(hFile);

	if (!success) {
		DWORD error = GetLastError();
		std::string error_msg = "DeviceIoControl failed: " + std::to_string(error);
		if (error == ERROR_NOT_A_REPARSE_POINT) {
			error_msg += " (Not a symbolic link)";
		}
		throw std::runtime_error(error_msg);
	}

	// 解析重解析数据
	PREPARSE_DATA_BUFFER reparse_data = reinterpret_cast<PREPARSE_DATA_BUFFER>(buffer.data());
	if (reparse_data->ReparseTag != SYMBOLIC_LINK_REPARSE_TAG) {
		throw std::runtime_error("Not a symbolic link reparse point");
	}

	// 提取目标路径
	const WCHAR* path_buffer = reparse_data->u.SymbolicLinkReparseBuffer.PathBuffer;
	WORD substitute_name_offset = reparse_data->u.SymbolicLinkReparseBuffer.SubstituteNameOffset;
	WORD substitute_name_length = reparse_data->u.SymbolicLinkReparseBuffer.SubstituteNameLength;
	std::wstring target_path(
		path_buffer + substitute_name_offset / sizeof(WCHAR),
		substitute_name_length / sizeof(WCHAR)
	);

	// 处理相对路径
	if (reparse_data->u.SymbolicLinkReparseBuffer.Flags & SYMLINK_FLAG_RELATIVE) {
		// 获取符号链接所在的目录
		fs::path link_path(full_path);
		fs::path link_dir = link_path.parent_path();
		// 组合成绝对路径
		fs::path absolute_target = link_dir / target_path;
		target_path = absolute_target.wstring();
	}

	return std::string(MyCW2A(target_path.c_str(), CP_UTF8));
}
#endif // _WIN32


int wlo_futimens(wlo_handle fh, const timespec times[2])
{
	// 验证句柄有效性
	_VALIDATE_RETURN(fh != -1 && fh != 0, EBADF, -1);
	// 验证文件句柄有效性
	if (WLOHANDLEST(fh).hFile == INVALID_HANDLE_VALUE)
	{
		errno = EBADF;
		return -1;
	}
	HANDLE hFile = WLOHANDLEST(fh).hFile;
	return futimens_winfh(hFile, times);
}

#endif//_WIN32


通讯协议

#pragma once

#include <cstdint>
#include <cstring>
#include <sys/stat.h>

#ifdef _WIN32
#include <fuse3/fuse.h>

#else//!_WIN32
#include <sys/time.h>
#endif // _WIN32

#include <pthread.h>

#define PATH_LEN 176


#ifndef _WIN32
#define  _Xoff_t off_t
#endif//_WIN32

#define my_min(a,b) ( (a)<(b) ? (a):(b) )
#define my_offsetof(st,mb) ((unsigned int)(uint64_t) &(((st*)0)->mb) )

#ifdef _WIN32
#define lseek64 _lseeki64
#endif // _WIN32

extern int g_logLevel;
// 打印当前时间和线程ID
#define LOG_DEBUG 0
#define LOG_WARN  1
#define LOG_ERROR 2
void print_with_time_and_thread(int level, const char *format, ...);

// 创建线程
int create_thread(pthread_t *thread, void* (*start_routine)(void*), void *arg);

// 等待线程结束
int join_thread(pthread_t thread);

// 获取当前时间字符串
const char* get_current_time_str();


#pragma pack(push,1)


// 命令类型
enum class CommandType : uint32_t
{
	unk,
	AUTHENTICATE,
	GET_ATTR,
	SET_ATTR,
	READ_DIR,
	OPEN,
	READ,
	WRITE,
	CREATE,
	MKDIR,
	RMDIR,
	UNLINK,
	RENAME,
	CLOSE,
	LSEEK,
	TRUNCATE,
	CHMOD,
	CHOWN,
	UTIMENS,
	LINK,
	SYMLINK,
	READLINK,
	SYNC,
	RESPONSE
};

// 响应状态
enum class ResponseStatus : uint32_t
{
	FU_SUCCESS,
	FU_ERROR,
	FU_NOT_FOUND,
	FU_PERMISSION_DENIED,
	FU_NOT_IMPLEMENTED,
	FU_AUTH_FAILED
};

// 不同命令的参数结构体
struct AuthParams
{
	char password[64];
};

struct GetAttrParams
{
	uint32_t Flag_GetAttr;
};

struct my_time
{
	uint64_t tv_sec;
};

struct myfuse_stat
{
	uint64_t     st_ino;
	uint32_t     st_mode;
	uint16_t     st_nlink;
	uint64_t     st_size;

	union
	{
		my_time  st_atim;
#ifdef _WIN32
		uint64_t st_atime;
#endif//_WIN32
	};
	union
	{
		my_time  st_mtim;
#ifdef _WIN32
		uint64_t st_mtime;
#endif//_WIN32
	};
	union
	{
		my_time  st_ctim;
#ifdef _WIN32
		uint64_t st_ctime;
#endif//_WIN32
	};
};

struct SetAttrParams
{
	myfuse_stat fustbuf;
	uint32_t valid; // 哪些属性是有效的,使用FUSE_SETATTR_*标志
};

struct OpenParams
{
	uint32_t open_flags;
	uint32_t open_mode;
};

struct ReadParams
{
	uint32_t size;
	int64_t offset; // 使用64位偏移量,支持大文件
};

struct WriteParams
{
	uint32_t size;
	int64_t offset; // 使用64位偏移量,支持大文件
};

struct TruncateParams
{
	int64_t length; // 使用64位长度,支持大文件
};

struct UtimensParams
{
	struct timespec times[2];
};

struct LinkParams
{
	char newpath[PATH_LEN];
};

struct SymlinkParams
{
	char target[PATH_LEN];
};

struct CreateParams
{
	uint32_t create_mode;
};

struct MkdirParams
{
	uint32_t mkdir_mode;
};

struct RmdirParams
{
	uint32_t Flag_Rmdir;
};

struct UnlinkParams
{
	uint32_t Flag_Ulink;
};

struct RenameParams
{
	char newpath[PATH_LEN];
	unsigned Flag_Rename;
};

struct ResponseParams
{
	ResponseStatus status;
	union
	{
		struct myfuse_stat mustat;
		size_t entry_count;
		uint64_t fd_id_out;
		size_t bytes_transferred;
		int64_t new_offset; // 使用64位偏移量,支持大文件
	};
};

///////////////////////////////////////////////////////////////////////
// 统一通讯结构体
///////////////////////////////////////////////////////////////////////
struct CommunicationPacket
{
	CommandType command = (CommandType)0;
	uint32_t variable_data_size = 0; // 可变长数据的大小,0表示没有可变长数据
	char path[PATH_LEN];
	uint64_t fd_id_in = 0;
	uint64_t serial = 0;

	// 使用union存储不同命令的参数
	union
	{
		AuthParams auth;
		GetAttrParams getattr;
		CreateParams create;
		MkdirParams mkdir;
		RmdirParams rmdir;
		UnlinkParams unlink;
		RenameParams rename;
		LinkParams link;
		SymlinkParams symlink;
		ReadParams read;
		WriteParams write;
		OpenParams open;
		UtimensParams utimens;
		SetAttrParams setattr;
		TruncateParams truncate;
	};

	// 可变长尾部数据,实际大小由variable_data_size指定
	char variable_data[1];

	////////////////////////STRUCT END//////
	void init(CommandType cmd); // 初始化函数
	bool set_variable_data(const char *data, uint32_t size, uint32_t allocSize); // 设置可变长数据 allocSize:结构分配长度
	size_t get_total_need() const;//根据可变长度的大小确定总共需要多少数据
};

///////////////////////////////////////////////////////////////////////
// ResponsePkt
///////////////////////////////////////////////////////////////////////
struct ResponsePkt
{
	CommandType commandSrc = (CommandType)0;
	uint64_t serialSrc = 0;
	uint32_t variable_data_size = 0; // 可变长数据的大小,0表示没有可变长数据
	ResponseParams response;
	// 可变长尾部数据,实际大小由variable_data_size指定
	char variable_data[1];

	////////////////////////STRUCT END//////
	void init(const CommunicationPacket& src); // 初始化函数
	bool set_variable_data(const char *data, uint32_t size, uint32_t allocSize); // 设置可变长数据 allocSize:结构分配长度
	size_t get_total_need();
};

///////////////////////////////////////////////////////////////////////
// CmdResponse
///////////////////////////////////////////////////////////////////////
struct CmdResponse
{
	CmdResponse();
	~CmdResponse();
	ResponsePkt *pPkt = 0;
	bool prepare();//准备一个ResponsePkt大小的空间
	bool extend_to(size_t newLen);//长度增长到 newLen
};

#pragma pack(pop)//1
#include "FuseCommon.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <pthread.h>
#include <stdarg.h>
#include <new>

using namespace std;

#ifdef _WIN32
#include <Windows.h>
#endif // _WIN32

int g_logLevel = LOG_WARN;
// 打印当前时间和线程ID
void print_with_time_and_thread(int level, const char* format, ...)
{
	if (level < g_logLevel)
		return;

	// 获取当前时间
	time_t now;
	time(&now);
	struct tm* local_time = localtime(&now);

	// 获取当前线程ID
	pthread_t thread_id = pthread_self();

	// 打印时间和线程ID
#ifdef _WIN32
	printf("[%04d-%02d-%02d %02d:%02d:%02d] [Thread: %lu] ",
		local_time->tm_year + 1900,
		local_time->tm_mon + 1,
		local_time->tm_mday,
		local_time->tm_hour,
		local_time->tm_min,
		local_time->tm_sec,
		(unsigned long)GetCurrentThreadId());
#else//!_WIN32
	printf("[%04d-%02d-%02d %02d:%02d:%02d] [Thread: %lu] ",
		local_time->tm_year + 1900,
		local_time->tm_mon + 1,
		local_time->tm_mday,
		local_time->tm_hour,
		local_time->tm_min,
		local_time->tm_sec,
		(unsigned long)thread_id);
#endif // _WIN32

	// 打印格式化消息
	va_list args;
	va_start(args, format);
	vprintf(format, args);
	va_end(args);
}

// 创建线程
int create_thread(pthread_t* thread, void* (*start_routine)(void*), void* arg) {
	print_with_time_and_thread(LOG_WARN, "Creating new thread\n");
	return pthread_create(thread, NULL, start_routine, arg);
}

// 等待线程结束
int join_thread(pthread_t thread) {
	print_with_time_and_thread(LOG_WARN, "Waiting for thread to finish\n");
	return pthread_join(thread, NULL);
}

// 获取当前时间字符串
const char* get_current_time_str()
{
	static char time_str[64] = {};
	time_t now;
	time(&now);
	struct tm *local_time = localtime(&now);

	snprintf(time_str, sizeof(time_str), "%04d-%02d-%02d %02d:%02d:%02d",
		local_time->tm_year + 1900,
		local_time->tm_mon + 1,
		local_time->tm_mday,
		local_time->tm_hour,
		local_time->tm_min,
		local_time->tm_sec
	);

	return time_str;
}

///////////////////////////////////////////////////////////////////////
// 统一通讯结构体
///////////////////////////////////////////////////////////////////////
void CommunicationPacket::init(CommandType cmd)
{
	memset((char*)this, 0, sizeof(CommunicationPacket));
	command = cmd;
	variable_data_size = 0;
}

// 设置可变长数据

bool CommunicationPacket::set_variable_data(const char * data, uint32_t size, uint32_t allocSize)
{
	//allocSize:结构分配长度
	if (allocSize < sizeof(CommunicationPacket))
		return false;

	size_t remain = allocSize - my_offsetof(CommunicationPacket, variable_data);

	if (size > remain) {
		return false;
	}
	memcpy(variable_data, data, size);
	variable_data_size = size;
	return true;
}

size_t CommunicationPacket::get_total_need() const
{
	//可变长度加上可变区域前的长度
	return variable_data_size + my_offsetof(CommunicationPacket, variable_data);
}

///////////////////////////////////////////////////////////////////////
// ResponsePkt
///////////////////////////////////////////////////////////////////////
void ResponsePkt::init(const CommunicationPacket& src) // 初始化函数
{
	memset((char*)this, 0, sizeof(ResponsePkt));
	commandSrc = src.command;
	serialSrc = src.serial;
}

bool ResponsePkt::set_variable_data(const char * data, uint32_t size, uint32_t allocSize)
{
	//allocSize:结构分配长度
	if (allocSize < sizeof(ResponsePkt))
		return false;

	size_t remain = allocSize - my_offsetof(ResponsePkt, variable_data);

	if (size > remain) {
		return false;
	}
	memcpy(variable_data, data, size);
	variable_data_size = size;
	return true;
}

size_t ResponsePkt::get_total_need()
{
	return variable_data_size + my_offsetof(ResponsePkt, variable_data);
}

///////////////////////////////////////////////////////////////////////
// CmdResponse
///////////////////////////////////////////////////////////////////////
CmdResponse::CmdResponse() {}
CmdResponse::~CmdResponse() { if (pPkt)free(pPkt); }

bool CmdResponse::prepare()
{
	pPkt = (ResponsePkt*)malloc(sizeof(ResponsePkt));
	if (pPkt)
		return true;
	return false;
}

bool CmdResponse::extend_to(size_t newLen)
{
	if (!pPkt)
		return false;
	if (newLen < sizeof(ResponsePkt))
		return false;
	ResponsePkt* pPkt2 = (ResponsePkt*)malloc(newLen);
	if (!pPkt2)
		return false;
	memcpy(pPkt2, pPkt, sizeof(ResponsePkt));
	free(pPkt);
	pPkt = pPkt2;
	return true;
}

连接管理

#include "SockMgr.h"


#ifdef _WIN32
#include <Windows.h>
#include <WinSock.h>
#include <io.h>
#else//!_WIN32
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#endif // _WIN32

#include "FuseCommon.h"

string  SERVER_IP = "127.0.0.1"; // Windows服务器IP
int     SERVER_PORT = 30876;
string  AUTH_PASSWORD = "123456"; // 设置认证密码
string  SHARE_DIR = "C:/share";


SocketManager & SocketManager::getInstance() {
	static SocketManager instance;
	return instance;
}

HSOCKET SocketManager::getSocket() {
	std::lock_guard<std::mutex> lock(mutex_);
	if (sock_ == BAD_SOCKET) {
		sock_ = connect_to_server();
		if (sock_ != BAD_SOCKET) {
			// 连接成功后进行认证
			if (!authenticate(sock_)) {
				skapi_closesocket(sock_);
				sock_ = BAD_SOCKET;
			}
		}
	}
	return sock_;
}

void SocketManager::resetSocket()
{
	std::lock_guard<std::mutex> lock(mutex_);
	if (sock_ != BAD_SOCKET)
	{
		skapi_closesocket(sock_);
		sock_ = BAD_SOCKET;
	}
}

SocketManager::SocketManager() : sock_(BAD_SOCKET) {}

HSOCKET SocketManager::connect_to_server() {
	HSOCKET sock = skapi_socket();
	if (sock == BAD_SOCKET) {
		print_with_time_and_thread(LOG_ERROR, "Failed to create socket\n");
		return BAD_SOCKET;
	}

	if (skapi_connect(sock, SERVER_IP.c_str(), (unsigned short)SERVER_PORT) < 0) {
		print_with_time_and_thread(LOG_ERROR, "Failed to connect to server\n");
		skapi_closesocket(sock);
		return BAD_SOCKET;
	}

	print_with_time_and_thread(LOG_WARN, "Connected to server %s:%d\n", SERVER_IP.c_str(), SERVER_PORT);
	return sock;
}

bool SocketManager::authenticate(HSOCKET sock) {
	CommunicationPacket request;
	request.init(CommandType::AUTHENTICATE);
	strncpy(request.auth.password, AUTH_PASSWORD.c_str(), sizeof(request.auth.password) - 1);

	skapi_send(sock, (char*)&request, sizeof(request));

	ResponsePkt response;
	ssize_t bytes_read = skapi_recv(sock, (char*)&response, sizeof(response));
	if (bytes_read <= 0 || response.response.status != ResponseStatus::FU_SUCCESS) {
		print_with_time_and_thread(LOG_ERROR, "Authentication failed\n");
		skapi_closesocket(sock);
		sock_ = BAD_SOCKET;
		return false;
	}

	print_with_time_and_thread(LOG_WARN, "Authenticated successfully\n");
	return true;
}

句柄管理

#include "HandleMgr.h"

#ifdef _WIN32
#include <WinSock2.h>
#include <Windows.h>
#include <io.h>

#else//!_WIN32
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#endif // _WIN32

#include "SnowflakeId.h"

FileHandleManager & FileHandleManager::getInstance() {
	static FileHandleManager instance;
	return instance;
}

long long FileHandleManager::addFileHandle(wlo_handle fd) {
	std::lock_guard<std::mutex> lock(mutex_);
	long long id = SnowflakeIdGenerator::getInstance().nextId();

	FileHandleInfo info;
	info.fd = fd;

	fileHandles_[id] = info;
	return id;
}

void FileHandleManager::removeFileHandle(long long id) {
	std::lock_guard<std::mutex> lock(mutex_);
	auto it = fileHandles_.find(id);
	if (it != fileHandles_.end()) {
		wlo_close(it->second.fd);
		fileHandles_.erase(it);
	}
}

FileHandleManager::FileHandleInfo * FileHandleManager::getFileHandle(long long id) {
	std::lock_guard<std::mutex> lock(mutex_);
	auto it = fileHandles_.find(id);
	return it != fileHandles_.end() ? &it->second : nullptr;
}







#include "SnowflakeId.h"

SnowflakeIdGenerator & SnowflakeIdGenerator::getInstance() {
	static SnowflakeIdGenerator instance;
	return instance;
}

long long SnowflakeIdGenerator::nextId() {
	std::lock_guard<std::mutex> lock(mutex_);

	auto now = std::chrono::system_clock::now();
	auto duration = now.time_since_epoch();
	long long currentTime = std::chrono::duration_cast<std::chrono::milliseconds>(duration).count();

	if (currentTime < lastTime) {
		throw std::runtime_error("Clock moved backwards");
	}

	if (currentTime == lastTime) {
		sequence = (sequence + 1) & SEQUENCE_MASK;
		if (sequence == 0) {
			// 等待下一毫秒
			while (currentTime == lastTime) {
				now = std::chrono::system_clock::now();
				duration = now.time_since_epoch();
				currentTime = std::chrono::duration_cast<std::chrono::milliseconds>(duration).count();
			}
		}
	}
	else {
		sequence = 0;
	}

	lastTime = currentTime;

	return ((currentTime - EPOCH) << TIMESTAMP_SHIFT) |
		(WORKER_ID << WORKER_ID_SHIFT) |
		(DATA_CENTER_ID << DATA_CENTER_ID_SHIFT) |
		sequence;
}

SnowflakeIdGenerator::SnowflakeIdGenerator() : lastTime(0), sequence(0), WORKER_ID(1), DATA_CENTER_ID(1) {}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值