/**
* Copyright (C) 2008 Happy Fish / YuQing
*
* FastDFS may be copied only under the terms of the GNU General
* Public License V3, which may be found in the FastDFS source kit.
* Please visit the FastDFS Home Page http://www.fastken.com/ for more detail.
**/

//storage_service.c

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#include <sys/time.h>
#include <unistd.h>
#include "fdfs_define.h"
#include "fastcommon/logger.h"
#include "fdfs_global.h"
#include "fastcommon/sockopt.h"
#include "fastcommon/shared_func.h"
#include "fastcommon/pthread_func.h"
#include "fastcommon/sched_thread.h"
#include "fastcommon/fast_mblock.h"
#include "fastcommon/fc_atomic.h"
#include "sf/sf_service.h"
#include "sf/sf_nio.h"
#include "tracker_types.h"
#include "tracker_proto.h"
#include "storage_service.h"
#include "storage_func.h"
#include "storage_sync.h"
#include "storage_global.h"
#include "fastcommon/base64.h"
#include "fastcommon/hash.h"
#include "fdht_client.h"
#include "fdfs_global.h"
#include "tracker_client.h"
#include "storage_client.h"
#include "storage_dio.h"
#include "storage_sync.h"
#include "trunk_mem.h"
#include "trunk_sync.h"
#include "trunk_client.h"
#include "fastcommon/ioevent_loop.h"

//storage access log actions
#define ACCESS_LOG_ACTION_UPLOAD_FILE    "upload"
#define ACCESS_LOG_ACTION_DOWNLOAD_FILE  "download"
#define ACCESS_LOG_ACTION_DELETE_FILE    "delete"
#define ACCESS_LOG_ACTION_GET_METADATA   "get_metadata"
#define ACCESS_LOG_ACTION_SET_METADATA   "set_metadata"
#define ACCESS_LOG_ACTION_MODIFY_FILE    "modify"
#define ACCESS_LOG_ACTION_APPEND_FILE    "append"
#define ACCESS_LOG_ACTION_TRUNCATE_FILE  "truncate"
#define ACCESS_LOG_ACTION_QUERY_FILE     "status"
#define ACCESS_LOG_ACTION_RENAME_FILE    "rename"

typedef struct
{
    int storage_id;
    time_t mtime;
    int64_t fsize;
} StorageFileInfoForCRC32;

static int last_stat_change_count = 1;  //for sync to stat file
static volatile int64_t temp_file_sequence = 0;

static struct fast_mblock_man finfo_for_crc32_allocator;

extern int storage_client_create_link(ConnectionInfo *pTrackerServer, \
		ConnectionInfo *pStorageServer, const char *master_filename,\
		const char *src_filename, const int src_filename_len, \
		const char *src_file_sig, const int src_file_sig_len, \
		const char *group_name, const char *prefix_name, \
		const char *file_ext_name, \
		char *remote_filename, int *filename_len);

static int storage_deal_task(struct fast_task_info *pTask, const int stage);

static int storage_do_delete_file(struct fast_task_info *pTask, \
		DeleteFileLogCallback log_callback, \
		FileDealDoneCallback done_callback, \
		const int store_path_index);

static int storage_write_to_file(struct fast_task_info *pTask, \
		const int64_t file_offset, const int64_t upload_bytes, \
		const int buff_offset, TaskDealFunc deal_func, \
		FileDealDoneCallback done_callback, \
		DisconnectCleanFunc clean_func, const int store_path_index);

static int storage_read_from_file(struct fast_task_info *pTask, \
		const int64_t file_offset, const int64_t download_bytes, \
		FileDealDoneCallback done_callback, \
		const int store_path_index);

static int storage_service_upload_file_done(struct fast_task_info *pTask);

#define TASK_STATUS_CONTINUE          12345

#define FDHT_KEY_NAME_FILE_ID	"fid"
#define FDHT_KEY_NAME_REF_COUNT	"ref"
#define FDHT_KEY_NAME_FILE_SIG	"sig"

#define FILE_SIGNATURE_SIZE	24

#define STORAGE_GEN_FILE_SIGNATURE(file_size, hash_codes, sig_buff) \
	long2buff(file_size, sig_buff); \
	if (g_file_signature_method == STORAGE_FILE_SIGNATURE_METHOD_HASH) \
	{ \
		int2buff(hash_codes[0], sig_buff + 8);  \
		int2buff(hash_codes[1], sig_buff + 12); \
		int2buff(hash_codes[2], sig_buff + 16); \
		int2buff(hash_codes[3], sig_buff + 20); \
	} \
	else \
	{ \
		memcpy(sig_buff + 8, hash_codes, 16);  \
	}

#define STORAGE_STAT_FILE_FAIL_LOG(result, client_ip, type_caption, filename) \
	if (result == ENOENT) \
	{ \
		logWarning("file: "__FILE__", line: %d, " \
			"client ip: %s, %s file: %s not exist", \
			__LINE__, client_ip, type_caption, filename); \
	} \
	else \
	{ \
		logError("file: "__FILE__", line: %d, " \
			"call stat fail, client ip: %s, %s file: %s, "\
			"error no: %d, error info: %s", __LINE__, client_ip, \
			type_caption, filename, result, STRERROR(result)); \
	}


typedef struct
{
	char src_true_filename[128];
	char src_file_sig[64];
	int src_file_sig_len;
} SourceFileInfo;

typedef struct
{
	SourceFileInfo src_file_info;
	bool need_response;
} TrunkCreateLinkArg;

static int storage_create_link_core(struct fast_task_info *pTask, \
		SourceFileInfo *pSourceFileInfo, \
		const char *src_filename, const char *master_filename, \
		const int master_filename_len, \
		const char *prefix_name, const char *file_ext_name, \
		char *filename, int *filename_len, const bool bNeedReponse);

static int storage_set_link_file_meta(struct fast_task_info *pTask, \
		const SourceFileInfo *pSrcFileInfo, const char *link_filename);

static FDFSStorageServer *get_storage_server(const char *storage_server_id)
{
	FDFSStorageServer targetServer;
	FDFSStorageServer *pTargetServer;
	FDFSStorageServer **ppFound;

	memset(&targetServer, 0, sizeof(targetServer));
	strcpy(targetServer.server.id, storage_server_id);

	pTargetServer = &targetServer;
	ppFound = (FDFSStorageServer **)bsearch(&pTargetServer, \
		g_sorted_storages, g_storage_count, \
		sizeof(FDFSStorageServer *), storage_cmp_by_server_id);
	if (ppFound == NULL)
	{
		return NULL;
	}
	else
	{
		return *ppFound;
	}
}

#define CHECK_AND_WRITE_TO_STAT_FILE1  \
\
		if (pClientInfo->pSrcStorage == NULL) \
		{ \
			pClientInfo->pSrcStorage = get_storage_server( \
					pClientInfo->storage_server_id); \
		} \
		if (pClientInfo->pSrcStorage != NULL) \
		{ \
			pClientInfo->pSrcStorage->last_sync_src_timestamp = \
					pFileContext->timestamp2log; \
			g_sync_change_count++; \
		} \
\
		g_storage_stat.last_sync_update = g_current_time; \
		++g_stat_change_count; \

#define CHECK_AND_WRITE_TO_STAT_FILE1_WITH_BYTES( \
		total_bytes, success_bytes, bytes)  \
\
		if (pClientInfo->pSrcStorage == NULL) \
		{ \
			pClientInfo->pSrcStorage = get_storage_server( \
					pClientInfo->storage_server_id); \
		} \
		if (pClientInfo->pSrcStorage != NULL) \
		{ \
			pClientInfo->pSrcStorage->last_sync_src_timestamp = \
					pFileContext->timestamp2log; \
			g_sync_change_count++; \
		} \
\
		g_storage_stat.last_sync_update = g_current_time; \
        __sync_add_and_fetch(&total_bytes, bytes);   \
		__sync_add_and_fetch(&success_bytes, bytes); \
		++g_stat_change_count; \

#define CHECK_AND_WRITE_TO_STAT_FILE2(total_count, success_count)  \
		__sync_add_and_fetch(&total_count, 1);   \
		__sync_add_and_fetch(&success_count, 1); \
		++g_stat_change_count; \

#define CHECK_AND_WRITE_TO_STAT_FILE2_WITH_BYTES(total_count, success_count, \
		total_bytes, success_bytes, bytes)  \
		__sync_add_and_fetch(&total_count, 1);      \
		__sync_add_and_fetch(&success_count, 1);    \
		__sync_add_and_fetch(&total_bytes, bytes);  \
		__sync_add_and_fetch(&success_bytes, bytes);\
		++g_stat_change_count; \

#define CHECK_AND_WRITE_TO_STAT_FILE3(total_count, success_count, timestamp)  \
		__sync_add_and_fetch(&total_count, 1); \
		__sync_add_and_fetch(&success_count, 1); \
		timestamp = g_current_time; \
		++g_stat_change_count;  \

#define CHECK_AND_WRITE_TO_STAT_FILE3_WITH_BYTES(total_count, success_count, \
		timestamp, total_bytes, success_bytes, bytes)  \
		__sync_add_and_fetch(&total_count, 1);   \
		__sync_add_and_fetch(&success_count, 1); \
		__sync_add_and_fetch(&total_bytes, bytes);   \
		__sync_add_and_fetch(&success_bytes, bytes); \
		timestamp = g_current_time; \
		++g_stat_change_count;      \

static void storage_log_access_log(struct fast_task_info *pTask, \
		const char *action, const int status)
{
	StorageClientInfo *pClientInfo;
	struct timeval tv_end;
	int time_used;

	pClientInfo = (StorageClientInfo *)pTask->arg;
	gettimeofday(&tv_end, NULL);
	time_used = (tv_end.tv_sec - pClientInfo->file_context. \
			tv_deal_start.tv_sec) * 1000
		  + (tv_end.tv_usec - pClientInfo->file_context. \
			tv_deal_start.tv_usec) / 1000;
	logAccess(&g_access_log_context, &(pClientInfo->file_context. \
		tv_deal_start), "%s %s %s %d %d %"PRId64" " \
		"%"PRId64, pTask->client_ip, action, \
		pClientInfo->file_context.fname2log, status, time_used, \
		pClientInfo->request_length, pClientInfo->total_length);
}

#define STORAGE_ACCESS_STRCPY_FNAME2LOG(filename, filename_len, pClientInfo) \
	do \
	{ \
		if (g_use_access_log) \
		{ \
			if (filename_len < sizeof(pClientInfo-> \
				file_context.fname2log)) \
			{ \
				memcpy(pClientInfo->file_context.fname2log, \
					filename, filename_len + 1); \
			} \
			else \
			{ \
				memcpy(pClientInfo->file_context.fname2log, \
					filename, sizeof(pClientInfo-> \
					file_context.fname2log)); \
				*(pClientInfo->file_context.fname2log + \
					sizeof(pClientInfo->file_context. \
					fname2log) - 1) = '\0'; \
			} \
		} \
	} while (0)
	

#define STORAGE_ACCESS_LOG(pTask, action, status) \
	do \
	{ \
		if (g_use_access_log && (status != TASK_STATUS_CONTINUE)) \
		{ \
			storage_log_access_log(pTask, action, status); \
		} \
	} while (0)


static int storage_delete_file_auto(StorageFileContext *pFileContext)
{
	if (pFileContext->extra_info.upload.file_type & _FILE_TYPE_TRUNK)
	{
		return trunk_file_delete(pFileContext->filename,
                        &(pFileContext->extra_info.upload.trunk_info));
	}
	else
	{
		if (unlink(pFileContext->filename) == 0)
		{
			return 0;
		}
		else
		{
			return errno != 0 ? errno : ENOENT;
		}
	}
}

static bool storage_is_slave_file(const char *remote_filename, \
		const int filename_len)
{
	int buff_len;
	char buff[64];
	int64_t file_size;

	if (filename_len < FDFS_NORMAL_LOGIC_FILENAME_LENGTH)
	{
		logError("file: "__FILE__", line: %d, " \
			"filename is too short, length: %d < %d", \
			__LINE__, filename_len, FDFS_LOGIC_FILE_PATH_LEN \
			+ FDFS_FILENAME_BASE64_LENGTH \
			+ FDFS_FILE_EXT_NAME_MAX_LEN + 1);
		return false;
	}

	memset(buff, 0, sizeof(buff));
	base64_decode_auto(&g_fdfs_base64_context, (char *)remote_filename + \
		FDFS_LOGIC_FILE_PATH_LEN, FDFS_FILENAME_BASE64_LENGTH, \
		buff, &buff_len);

	file_size = buff2long(buff + sizeof(int) * 2);
	if (IS_TRUNK_FILE(file_size))
	{
		return filename_len > FDFS_TRUNK_LOGIC_FILENAME_LENGTH;
	}

	return filename_len > FDFS_NORMAL_LOGIC_FILENAME_LENGTH;
}

static void storage_delete_file_log_error(struct fast_task_info *pTask, \
			const int err_no)
{
	StorageFileContext *pFileContext;

	pFileContext =  &(((StorageClientInfo *)pTask->arg)->file_context);
	logError("file: "__FILE__", line: %d, " \
		"client ip: %s, delete file %s fail," \
		"errno: %d, error info: %s", __LINE__, \
		pTask->client_ip, pFileContext->filename, \
		err_no, STRERROR(err_no));
}

static void storage_sync_delete_file_log_error(struct fast_task_info *pTask, \
			const int err_no)
{
	StorageFileContext *pFileContext;

	pFileContext =  &(((StorageClientInfo *)pTask->arg)->file_context);
	if (err_no == ENOENT)
	{
		logWarning("file: "__FILE__", line: %d, " \
			"cmd=%d, client ip: %s, " \
			"file %s not exist, " \
			"maybe delete later?", __LINE__, \
			STORAGE_PROTO_CMD_SYNC_DELETE_FILE, \
			pTask->client_ip, pFileContext->filename);
	}
	else
	{
		logError("file: "__FILE__", line: %d, " \
			"client ip: %s, delete file %s fail," \
			"errno: %d, error info: %s", \
			__LINE__, pTask->client_ip, \
			pFileContext->filename, err_no, STRERROR(err_no));
	}
}

static void storage_sync_delete_file_done_callback( \
		struct fast_task_info *pTask, const int err_no)
{
	StorageClientInfo *pClientInfo;
	StorageFileContext *pFileContext;
	TrackerHeader *pHeader;
	int result;

	pClientInfo = (StorageClientInfo *)pTask->arg;
	pFileContext =  &(pClientInfo->file_context);

	if (err_no == 0 && pFileContext->sync_flag != '\0')
	{
		result = storage_binlog_write(pFileContext->timestamp2log, \
			pFileContext->sync_flag, pFileContext->fname2log);
	}
	else
	{
		result = err_no;
	}

	if (result == 0)
	{
		CHECK_AND_WRITE_TO_STAT_FILE1
	}

	pClientInfo->total_length = sizeof(TrackerHeader);
	pClientInfo->total_offset = 0;
	pTask->length = pClientInfo->total_length;
	pHeader = (TrackerHeader *)pTask->data;
	pHeader->status = result;
	pHeader->cmd = STORAGE_PROTO_CMD_RESP;
	long2buff(pClientInfo->total_length - sizeof(TrackerHeader), \
			pHeader->pkg_len);

	sf_nio_notify(pTask, SF_NIO_STAGE_SEND);
}

static void storage_sync_truncate_file_done_callback( \
		struct fast_task_info *pTask, const int err_no)
{
	StorageClientInfo *pClientInfo;
	StorageFileContext *pFileContext;
	TrackerHeader *pHeader;
	int result;

	pClientInfo = (StorageClientInfo *)pTask->arg;
	pFileContext =  &(pClientInfo->file_context);

	if (err_no == 0 && pFileContext->sync_flag != '\0')
	{
		set_file_utimes(pFileContext->filename, \
			pFileContext->timestamp2log);
		result = storage_binlog_write(pFileContext->timestamp2log, \
			pFileContext->sync_flag, pFileContext->fname2log);
	}
	else
	{
		result = err_no;
	}

	if (result == 0)
	{
		CHECK_AND_WRITE_TO_STAT_FILE1
	}

	pClientInfo->total_length = sizeof(TrackerHeader);
	pClientInfo->total_offset = 0;
	pTask->length = pClientInfo->total_length;
	pHeader = (TrackerHeader *)pTask->data;
	pHeader->status = result;
	pHeader->cmd = STORAGE_PROTO_CMD_RESP;
	long2buff(pClientInfo->total_length - sizeof(TrackerHeader), \
			pHeader->pkg_len);

	sf_nio_notify(pTask, SF_NIO_STAGE_SEND);
}

static int storage_sync_copy_file_rename_filename(
		StorageFileContext *pFileContext)
{
	char full_filename[MAX_PATH_SIZE + 256];
	int filename_len;
	int result;
	int store_path_index;

	filename_len = strlen(pFileContext->fname2log);
    if ((result=storage_logic_to_local_full_filename(
                    pFileContext->fname2log, filename_len,
                    &store_path_index, full_filename,
                    sizeof(full_filename))) != 0)
	{
		return result;
	}

	if (rename(pFileContext->filename, full_filename) != 0)
	{
		result = errno != 0 ? errno : EPERM;
		logWarning("file: "__FILE__", line: %d, "
			"rename %s to %s fail, "
			"errno: %d, error info: %s", __LINE__,
			pFileContext->filename, full_filename,
			result, STRERROR(result));
		return result;
	}

	return 0;
}

static void storage_sync_copy_file_done_callback(struct fast_task_info *pTask, \
			const int err_no)
{
	StorageClientInfo *pClientInfo;
	StorageFileContext *pFileContext;
	TrackerHeader *pHeader;
	int result;

	pClientInfo = (StorageClientInfo *)pTask->arg;
	pFileContext =  &(pClientInfo->file_context);
	result = err_no;
	if (result == 0)
	{
		if (pFileContext->op == FDFS_STORAGE_FILE_OP_WRITE) 
		{
			if (!(pFileContext->extra_info.upload.file_type & \
					_FILE_TYPE_TRUNK))
			{
			set_file_utimes(pFileContext->filename, \
				pFileContext->timestamp2log);

			result = storage_sync_copy_file_rename_filename( \
					pFileContext);
			}

			if (result == 0)
			{
			storage_binlog_write(pFileContext->timestamp2log, \
			pFileContext->sync_flag, pFileContext->fname2log);
			}
		}
		else  //FDFS_STORAGE_FILE_OP_DISCARD
		{
			storage_binlog_write(pFileContext->timestamp2log, \
			pFileContext->sync_flag, pFileContext->fname2log);
		}
	}

	if (pFileContext->op == FDFS_STORAGE_FILE_OP_WRITE)
	{
		if (result == 0)
		{
			CHECK_AND_WRITE_TO_STAT_FILE1_WITH_BYTES( \
				g_storage_stat.total_sync_in_bytes, \
				g_storage_stat.success_sync_in_bytes, \
				pFileContext->end - pFileContext->start)
		}
	}
	else  //FDFS_STORAGE_FILE_OP_DISCARD
	{
		if (result == 0)
		{
			CHECK_AND_WRITE_TO_STAT_FILE1
		}

		result = EEXIST;
	}
	if (result != 0)
    {
        __sync_add_and_fetch(&g_storage_stat.total_sync_in_bytes,
                pClientInfo->total_offset);
    }

	pClientInfo->total_length = sizeof(TrackerHeader);
	pClientInfo->total_offset = 0;
	pTask->length = pClientInfo->total_length;
	pHeader = (TrackerHeader *)pTask->data;
	pHeader->status = result;
	pHeader->cmd = STORAGE_PROTO_CMD_RESP;
	long2buff(pClientInfo->total_length - sizeof(TrackerHeader), \
			pHeader->pkg_len);

	sf_nio_notify(pTask, SF_NIO_STAGE_SEND);
}

static void storage_sync_modify_file_done_callback( \
		struct fast_task_info *pTask, const int err_no)
{
	StorageClientInfo *pClientInfo;
	StorageFileContext *pFileContext;
	TrackerHeader *pHeader;
	int result;

	pClientInfo = (StorageClientInfo *)pTask->arg;
	pFileContext =  &(pClientInfo->file_context);
	result = err_no;

	if (pFileContext->op != FDFS_STORAGE_FILE_OP_DISCARD)
	{
		if (result == 0)
		{
			set_file_utimes(pFileContext->filename, \
				pFileContext->timestamp2log);

			storage_binlog_write(pFileContext->timestamp2log, \
			    pFileContext->sync_flag, pFileContext->fname2log);

			CHECK_AND_WRITE_TO_STAT_FILE1_WITH_BYTES( \
				g_storage_stat.total_sync_in_bytes, \
				g_storage_stat.success_sync_in_bytes, \
				pFileContext->end - pFileContext->start)
		}
	}
	else  //FDFS_STORAGE_FILE_OP_DISCARD
	{
		if (result == 0)
		{
			struct stat file_stat;

			if (lstat(pFileContext->filename, &file_stat) != 0)
			{
				result = errno != 0 ? errno : ENOENT;
				STORAGE_STAT_FILE_FAIL_LOG(result,
					pTask->client_ip, "regular",
					pFileContext->filename)
			}
			else if (!S_ISREG(file_stat.st_mode))
			{
				result = EEXIST;
			}
			else if (file_stat.st_size < pFileContext->end)
			{
				result = ENOENT;  //need to resync
			}
			else
			{
				result = EEXIST;
			}

			CHECK_AND_WRITE_TO_STAT_FILE1
		}
	}

	if (result != 0)
    {
        __sync_add_and_fetch(&g_storage_stat.total_sync_in_bytes,
                pClientInfo->total_offset);
    }

	pClientInfo->total_length = sizeof(TrackerHeader);
	pClientInfo->total_offset = 0;
	pTask->length = pClientInfo->total_length;
	pHeader = (TrackerHeader *)pTask->data;
	pHeader->status = result;
	pHeader->cmd = STORAGE_PROTO_CMD_RESP;
	long2buff(pClientInfo->total_length - sizeof(TrackerHeader), \
			pHeader->pkg_len);

	sf_nio_notify(pTask, SF_NIO_STAGE_SEND);
}

static void storage_get_metadata_done_callback(struct fast_task_info *pTask,
			const int err_no)
{
	TrackerHeader *pHeader;

	STORAGE_ACCESS_LOG(pTask, ACCESS_LOG_ACTION_GET_METADATA, \
		err_no);

	if (err_no != 0)
	{
        __sync_add_and_fetch(&g_storage_stat.total_get_meta_count, 1);
		if (pTask->length == sizeof(TrackerHeader)) //never response
		{
			pHeader = (TrackerHeader *)pTask->data;
			pHeader->status = err_no;
			sf_nio_notify(pTask, SF_NIO_STAGE_SEND);
		}
		else
		{
			sf_nio_notify(pTask, SF_NIO_STAGE_CLOSE);
		}
	}
	else
	{
		CHECK_AND_WRITE_TO_STAT_FILE2( \
			g_storage_stat.total_get_meta_count, \
			g_storage_stat.success_get_meta_count)

		sf_nio_notify(pTask, SF_NIO_STAGE_SEND);
	}
}

static void storage_download_file_done_callback( \
		struct fast_task_info *pTask, const int err_no)
{
	StorageFileContext *pFileContext;
	TrackerHeader *pHeader;

	STORAGE_ACCESS_LOG(pTask, ACCESS_LOG_ACTION_DOWNLOAD_FILE, \
		err_no);

	pFileContext = &(((StorageClientInfo *)pTask->arg)->file_context);
	if (err_no != 0)
	{
        __sync_add_and_fetch(&g_storage_stat.total_download_count, 1);
        __sync_add_and_fetch(&g_storage_stat.total_download_bytes,
                pFileContext->offset - pFileContext->start);

		if (pTask->length == sizeof(TrackerHeader)) //never response
		{
			pHeader = (TrackerHeader *)pTask->data;
			pHeader->status = err_no;
			sf_nio_notify(pTask, SF_NIO_STAGE_SEND);
		}
		else
		{
			sf_nio_notify(pTask, SF_NIO_STAGE_CLOSE);
		}
	}
	else
	{
		CHECK_AND_WRITE_TO_STAT_FILE2_WITH_BYTES( \
			g_storage_stat.total_download_count, \
			g_storage_stat.success_download_count, \
			g_storage_stat.total_download_bytes, \
			g_storage_stat.success_download_bytes, \
			pFileContext->end - pFileContext->start)
       sf_nio_notify(pTask, SF_NIO_STAGE_SEND);
	}
}

static int storage_do_delete_meta_file(struct fast_task_info *pTask)
{
	StorageClientInfo *pClientInfo;
	StorageFileContext *pFileContext;
	GroupArray *pGroupArray;
	char meta_filename[MAX_PATH_SIZE + 256];
	char true_filename[128];
	char value[128];
	FDHTKeyInfo key_info_fid;
	FDHTKeyInfo key_info_ref;
	FDHTKeyInfo key_info_sig;
	char *pValue;
	int value_len;
	int src_file_nlink;
	int result;
	int store_path_index;

	pClientInfo = (StorageClientInfo *)pTask->arg;
	pFileContext =  &(pClientInfo->file_context);

	if (pFileContext->extra_info.upload.file_type & \
				_FILE_TYPE_TRUNK)
	{
		int filename_len = strlen(pFileContext->fname2log);
		if ((result=storage_split_filename_ex(pFileContext->fname2log, \
			&filename_len, true_filename, &store_path_index)) != 0)
		{
			return result;
		}

		sprintf(meta_filename, "%s/data/%s"FDFS_STORAGE_META_FILE_EXT, \
			g_fdfs_store_paths.paths[store_path_index].path, true_filename);
	}
	else
	{
		sprintf(meta_filename, "%s"FDFS_STORAGE_META_FILE_EXT, \
				pFileContext->filename);
	}
	if (fileExists(meta_filename))
	{
		if (unlink(meta_filename) != 0)
		{
			if (errno != ENOENT)
			{
				result = errno != 0 ? errno : EACCES;
				logError("file: "__FILE__", line: %d, " \
					"client ip: %s, delete file %s fail," \
					"errno: %d, error info: %s", __LINE__,\
					pTask->client_ip, meta_filename, \
					result, STRERROR(result));
				return result;
			}
		}
		else
		{
			sprintf(meta_filename, "%s"FDFS_STORAGE_META_FILE_EXT, \
					pFileContext->fname2log);
			result = storage_binlog_write(g_current_time, \
				STORAGE_OP_TYPE_SOURCE_DELETE_FILE, meta_filename);
			if (result != 0)
			{
				return result;
			}
		}
	}

	src_file_nlink = -1;
	if (g_check_file_duplicate)
	{
		pGroupArray = pTask->thread_data->arg;
		memset(&key_info_sig, 0, sizeof(key_info_sig));
		key_info_sig.namespace_len = g_namespace_len;
		memcpy(key_info_sig.szNameSpace, g_key_namespace, \
				g_namespace_len);
		key_info_sig.obj_id_len = snprintf(\
				key_info_sig.szObjectId, \
				sizeof(key_info_sig.szObjectId), "%s/%s", \
				g_group_name, pFileContext->fname2log);

		key_info_sig.key_len = sizeof(FDHT_KEY_NAME_FILE_SIG)-1;
		memcpy(key_info_sig.szKey, FDHT_KEY_NAME_FILE_SIG, \
				key_info_sig.key_len);
		pValue = value;
		value_len = sizeof(value) - 1;
		result = fdht_get_ex1(pGroupArray, g_keep_alive, \
				&key_info_sig, FDHT_EXPIRES_NONE, \
				&pValue, &value_len, malloc);
		if (result == 0)
		{
			memcpy(&key_info_fid, &key_info_sig, \
					sizeof(FDHTKeyInfo));
			key_info_fid.obj_id_len = value_len;
			memcpy(key_info_fid.szObjectId, pValue, \
					value_len);

			key_info_fid.key_len = sizeof(FDHT_KEY_NAME_FILE_ID) - 1;
			memcpy(key_info_fid.szKey, FDHT_KEY_NAME_FILE_ID, \
					key_info_fid.key_len);
			value_len = sizeof(value) - 1;
			result = fdht_get_ex1(pGroupArray, \
					g_keep_alive, &key_info_fid, \
					FDHT_EXPIRES_NONE, &pValue, \
					&value_len, malloc);
			if (result == 0)
			{
				memcpy(&key_info_ref, &key_info_sig, \
						sizeof(FDHTKeyInfo));
				key_info_ref.obj_id_len = value_len;
				memcpy(key_info_ref.szObjectId, pValue, 
						value_len);
				key_info_ref.key_len = \
					sizeof(FDHT_KEY_NAME_REF_COUNT)-1;
				memcpy(key_info_ref.szKey, \
					FDHT_KEY_NAME_REF_COUNT, \
					key_info_ref.key_len);
				value_len = sizeof(value) - 1;

				result = fdht_get_ex1(pGroupArray, \
						g_keep_alive, &key_info_ref, \
						FDHT_EXPIRES_NONE, &pValue, \
						&value_len, malloc);
				if (result == 0)
				{
					*(pValue + value_len) = '\0';
					src_file_nlink = atoi(pValue);
				}
				else if (result != ENOENT)
				{
					logError("file: "__FILE__", line: %d, " \
						"client ip: %s, fdht_get fail," \
						"errno: %d, error info: %s", \
						__LINE__, pTask->client_ip, \
						result, STRERROR(result));
					return result;
				}
			}
			else if (result != ENOENT)
			{
				logError("file: "__FILE__", line: %d, " \
					"client ip: %s, fdht_get fail," \
					"errno: %d, error info: %s", \
					__LINE__, pTask->client_ip, \
					result, STRERROR(result));
				return result;
			}
		}
		else if (result != ENOENT)
		{
			logError("file: "__FILE__", line: %d, " \
					"client ip: %s, fdht_get fail," \
					"errno: %d, error info: %s", \
					__LINE__, pTask->client_ip, \
					result, STRERROR(result));
			return result;
		}
	}

	if (src_file_nlink < 0)
	{
		return 0;
	}

	if (g_check_file_duplicate)
	{
		char *pSeperator;
		struct stat stat_buf;
		FDFSTrunkHeader trunkHeader;

		pGroupArray = pTask->thread_data->arg;
		if ((result=fdht_delete_ex(pGroupArray, g_keep_alive, \
						&key_info_sig)) != 0)
		{
			logWarning("file: "__FILE__", line: %d, " \
				"client ip: %s, fdht_delete fail," \
				"errno: %d, error info: %s", \
				__LINE__, pTask->client_ip, \
				result, STRERROR(result));
		}

		value_len = sizeof(value) - 1;
		result = fdht_inc_ex(pGroupArray, g_keep_alive, \
				&key_info_ref, FDHT_EXPIRES_NEVER, -1, \
				value, &value_len);
		if (result != 0)
		{
			logWarning("file: "__FILE__", line: %d, " \
				"client ip: %s, fdht_inc fail," \
				"errno: %d, error info: %s", \
				__LINE__, pTask->client_ip, \
				result, STRERROR(result));
			return result;
		}

		if (!(value_len == 1 && *value == '0')) //value == 0
		{
			return 0;
		}

		if ((result=fdht_delete_ex(pGroupArray, g_keep_alive, \
						&key_info_fid)) != 0)
		{
			logWarning("file: "__FILE__", line: %d, " \
				"client ip: %s, fdht_delete fail," \
				"errno: %d, error info: %s", \
				__LINE__, pTask->client_ip, \
				result, STRERROR(result));
		}
		if ((result=fdht_delete_ex(pGroupArray, g_keep_alive, \
						&key_info_ref)) != 0)
		{
			logWarning("file: "__FILE__", line: %d, " \
				"client ip: %s, fdht_delete fail," \
				"errno: %d, error info: %s", \
				__LINE__, pTask->client_ip, \
				result, STRERROR(result));
		}

		*(key_info_ref.szObjectId+key_info_ref.obj_id_len)='\0';
		pSeperator = strchr(key_info_ref.szObjectId, '/');
		if (pSeperator == NULL)
		{
			logWarning("file: "__FILE__", line: %d, " \
				"invalid file_id: %s", __LINE__, \
				key_info_ref.szObjectId);
			return 0;
		}

		pSeperator++;
		value_len = key_info_ref.obj_id_len - (pSeperator - \
				key_info_ref.szObjectId);
		memcpy(value, pSeperator, value_len + 1);
		if ((result=storage_split_filename_ex(value, &value_len, \
				true_filename, &store_path_index)) != 0)
		{
			return result;
		}
		if ((result=fdfs_check_data_filename(true_filename, \
					value_len)) != 0)
		{
			return result;
		}

		if ((result=trunk_file_lstat(store_path_index, true_filename, \
			value_len, &stat_buf, \
			&(pFileContext->extra_info.upload.trunk_info), \
			&trunkHeader)) != 0)
		{
			STORAGE_STAT_FILE_FAIL_LOG(result, pTask->client_ip,
				"logic", value)
			return 0;
		}

		if (IS_TRUNK_FILE_BY_ID(pFileContext->extra_info. \
					upload.trunk_info))
		{
			trunk_get_full_filename(&(pFileContext->extra_info. \
				upload.trunk_info), pFileContext->filename, \
				sizeof(pFileContext->filename));
		}
		else
		{
			sprintf(pFileContext->filename, "%s/data/%s", \
				g_fdfs_store_paths.paths[store_path_index].path, \
				true_filename);
		}

		if ((result=storage_delete_file_auto(pFileContext)) != 0)
		{
			logWarning("file: "__FILE__", line: %d, " \
				"client ip: %s, delete logic source file " \
				"%s fail, errno: %d, error info: %s", \
				__LINE__, pTask->client_ip, \
				value, errno, STRERROR(errno));
			return 0;
		}

		storage_binlog_write(g_current_time, \
				STORAGE_OP_TYPE_SOURCE_DELETE_FILE, value);
		pFileContext->delete_flag |= STORAGE_DELETE_FLAG_FILE;
	}

	return 0;
}

static void storage_delete_fdfs_file_done_callback( \
		struct fast_task_info *pTask, const int err_no)
{
	StorageClientInfo *pClientInfo;
	StorageFileContext *pFileContext;
	TrackerHeader *pHeader;
	int result;

	pClientInfo = (StorageClientInfo *)pTask->arg;
	pFileContext =  &(pClientInfo->file_context);

	if (err_no == 0)
	{
		if (pFileContext->extra_info.upload.file_type & \
				_FILE_TYPE_TRUNK)
		{
			trunk_client_trunk_free_space( \
				&(pFileContext->extra_info.upload.trunk_info));
		}

		result = storage_binlog_write(g_current_time, \
			STORAGE_OP_TYPE_SOURCE_DELETE_FILE, \
			pFileContext->fname2log);
	}
	else
	{
		result = err_no;
	}

	if (result == 0)
	{
		result = storage_do_delete_meta_file(pTask);
	}

	if (result != 0)
	{
		if (pFileContext->delete_flag == STORAGE_DELETE_FLAG_NONE ||
				(pFileContext->delete_flag & STORAGE_DELETE_FLAG_FILE))
		{
            __sync_add_and_fetch(&g_storage_stat.total_delete_count, 1);
		}
		if (pFileContext->delete_flag & STORAGE_DELETE_FLAG_LINK)
		{
            __sync_add_and_fetch(&g_storage_stat.total_delete_link_count, 1);
		}
	}
	else
	{
		if (pFileContext->delete_flag & STORAGE_DELETE_FLAG_FILE)
		{
			CHECK_AND_WRITE_TO_STAT_FILE3( \
					g_storage_stat.total_delete_count, \
					g_storage_stat.success_delete_count, \
					g_storage_stat.last_source_update)
		}

		if (pFileContext->delete_flag & STORAGE_DELETE_FLAG_LINK)
		{
			CHECK_AND_WRITE_TO_STAT_FILE3( \
					g_storage_stat.total_delete_link_count, \
					g_storage_stat.success_delete_link_count, \
					g_storage_stat.last_source_update)
		}

	}

	pClientInfo->total_length = sizeof(TrackerHeader);
	pClientInfo->total_offset = 0;
	pTask->length = pClientInfo->total_length;
	pHeader = (TrackerHeader *)pTask->data;
	pHeader->status = result;
	pHeader->cmd = STORAGE_PROTO_CMD_RESP;
	long2buff(pClientInfo->total_length - sizeof(TrackerHeader), \
			pHeader->pkg_len);

	STORAGE_ACCESS_LOG(pTask, ACCESS_LOG_ACTION_DELETE_FILE, result);

	sf_nio_notify(pTask, SF_NIO_STAGE_SEND);
}

static void storage_upload_file_done_callback(struct fast_task_info *pTask, \
			const int err_no)
{
	StorageClientInfo *pClientInfo;
	StorageFileContext *pFileContext;
	TrackerHeader *pHeader;
	int result;

	pClientInfo = (StorageClientInfo *)pTask->arg;
	pFileContext =  &(pClientInfo->file_context);

	if (pFileContext->extra_info.upload.file_type & _FILE_TYPE_TRUNK)
	{
		result = trunk_client_trunk_alloc_confirm( \
			&(pFileContext->extra_info.upload.trunk_info), err_no);
		if (err_no != 0)
		{
			result = err_no;
		}
	}
	else
	{
		result = err_no;
	}

	if (result == 0)
	{
		result = storage_service_upload_file_done(pTask);
		if (result == 0)
		{
		if (pFileContext->create_flag & STORAGE_CREATE_FLAG_FILE)
		{
			result = storage_binlog_write(\
				pFileContext->timestamp2log, \
				STORAGE_OP_TYPE_SOURCE_CREATE_FILE, \
				pFileContext->fname2log);
		}
		}
	}

	if (result == 0)
	{
		int filename_len;
		char *p;

		if (pFileContext->create_flag & STORAGE_CREATE_FLAG_FILE)
		{
			CHECK_AND_WRITE_TO_STAT_FILE3_WITH_BYTES( \
				g_storage_stat.total_upload_count, \
				g_storage_stat.success_upload_count, \
				g_storage_stat.last_source_update, \
				g_storage_stat.total_upload_bytes, \
				g_storage_stat.success_upload_bytes, \
				pFileContext->end - pFileContext->start)
		}

		filename_len = strlen(pFileContext->fname2log);
		pClientInfo->total_length = sizeof(TrackerHeader) + \
					FDFS_GROUP_NAME_MAX_LEN + filename_len;
		p = pTask->data + sizeof(TrackerHeader);
		memcpy(p, pFileContext->extra_info.upload.group_name, \
			FDFS_GROUP_NAME_MAX_LEN);
		p += FDFS_GROUP_NAME_MAX_LEN;
		memcpy(p, pFileContext->fname2log, filename_len);
	}
	else
	{
		if (pFileContext->create_flag & STORAGE_CREATE_FLAG_FILE)
        {
            __sync_add_and_fetch(&g_storage_stat.total_upload_count, 1);
            __sync_add_and_fetch(&g_storage_stat.total_upload_bytes,
                    pClientInfo->total_offset);
        }

		pClientInfo->total_length = sizeof(TrackerHeader);
	}

	STORAGE_ACCESS_LOG(pTask, ACCESS_LOG_ACTION_UPLOAD_FILE, result);

	pClientInfo->total_offset = 0;
	pTask->length = pClientInfo->total_length;

	pHeader = (TrackerHeader *)pTask->data;
	pHeader->status = result;
	pHeader->cmd = STORAGE_PROTO_CMD_RESP;
	long2buff(pClientInfo->total_length - sizeof(TrackerHeader), \
			pHeader->pkg_len);

	sf_nio_notify(pTask, SF_NIO_STAGE_SEND);
}

static void storage_trunk_create_link_file_done_callback( \
		struct fast_task_info *pTask, const int err_no)
{
	StorageClientInfo *pClientInfo;
	StorageFileContext *pFileContext;
	TrackerHeader *pHeader;
	TrunkCreateLinkArg *pCreateLinkArg;
	SourceFileInfo *pSourceFileInfo;
	int result;

	pClientInfo = (StorageClientInfo *)pTask->arg;
	pFileContext =  &(pClientInfo->file_context);
	pCreateLinkArg = (TrunkCreateLinkArg *)pClientInfo->extra_arg;
	pSourceFileInfo = &(pCreateLinkArg->src_file_info);

	result = trunk_client_trunk_alloc_confirm( \
			&(pFileContext->extra_info.upload.trunk_info), err_no);
	if (err_no != 0)
	{
		result = err_no;
	}

	if (result == 0)
	{
		result = storage_service_upload_file_done(pTask);
		if (result == 0)
		{
			char src_filename[128];
			char binlog_msg[256];

			sprintf(src_filename, \
				"%c"FDFS_STORAGE_DATA_DIR_FORMAT"/%s", \
				FDFS_STORAGE_STORE_PATH_PREFIX_CHAR, \
				pFileContext->extra_info.upload.trunk_info. \
				path.store_path_index, \
				pSourceFileInfo->src_true_filename);

			sprintf(binlog_msg, "%s %s", \
				pFileContext->fname2log, src_filename);
			result = storage_binlog_write( \
				pFileContext->timestamp2log, \
				STORAGE_OP_TYPE_SOURCE_CREATE_LINK, \
				binlog_msg);
		}
	}

	if (result == 0)
	{
		int filename_len;
		char *p;

		CHECK_AND_WRITE_TO_STAT_FILE3( \
			g_storage_stat.total_create_link_count, \
			g_storage_stat.success_create_link_count, \
			g_storage_stat.last_source_update)

		filename_len = strlen(pFileContext->fname2log);
		pClientInfo->total_length = sizeof(TrackerHeader) + \
					FDFS_GROUP_NAME_MAX_LEN + filename_len;
		p = pTask->data + sizeof(TrackerHeader);
		memcpy(p, pFileContext->extra_info.upload.group_name, \
			FDFS_GROUP_NAME_MAX_LEN);
		p += FDFS_GROUP_NAME_MAX_LEN;
		memcpy(p, pFileContext->fname2log, filename_len);
	}
	else
	{
        __sync_add_and_fetch(&g_storage_stat.total_create_link_count, 1);
		pClientInfo->total_length = sizeof(TrackerHeader);
	}

	storage_set_link_file_meta(pTask, pSourceFileInfo, \
		pFileContext->fname2log);

	if (pCreateLinkArg->need_response)
	{
		pClientInfo->total_offset = 0;
		pTask->length = pClientInfo->total_length;

		pHeader = (TrackerHeader *)pTask->data;
		pHeader->status = result;
		pHeader->cmd = STORAGE_PROTO_CMD_RESP;
		long2buff(pClientInfo->total_length - sizeof(TrackerHeader), \
				pHeader->pkg_len);

		sf_nio_notify(pTask, SF_NIO_STAGE_SEND);
	}
}

static void storage_append_file_done_callback(struct fast_task_info *pTask, \
			const int err_no)
{
	StorageClientInfo *pClientInfo;
	StorageFileContext *pFileContext;
	TrackerHeader *pHeader;
	char extra[64];
	int result;

	pClientInfo = (StorageClientInfo *)pTask->arg;
	pFileContext =  &(pClientInfo->file_context);

	if (err_no == 0)
	{
		struct stat stat_buf;
		if (stat(pFileContext->filename, &stat_buf) == 0)
		{
			pFileContext->timestamp2log = stat_buf.st_mtime;
		}
		else
		{
			result = errno != 0 ? errno : ENOENT;
			STORAGE_STAT_FILE_FAIL_LOG(result, pTask->client_ip,
				"regular", pFileContext->filename)
		}

		sprintf(extra, "%"PRId64" %"PRId64, \
				pFileContext->start, \
				pFileContext->end - pFileContext->start);
		result = storage_binlog_write_ex(pFileContext->timestamp2log, \
				pFileContext->sync_flag, \
				pFileContext->fname2log, extra);
	}
	else
	{
		result = err_no;
	}

	if (result == 0)
	{
		CHECK_AND_WRITE_TO_STAT_FILE3_WITH_BYTES( \
			g_storage_stat.total_append_count, \
			g_storage_stat.success_append_count, \
			g_storage_stat.last_source_update, \
			g_storage_stat.total_append_bytes, \
			g_storage_stat.success_append_bytes, \
			pFileContext->end - pFileContext->start)
	}
	else
    {
        __sync_add_and_fetch(&g_storage_stat.total_append_count, 1);
        __sync_add_and_fetch(&g_storage_stat.total_append_bytes,
                pClientInfo->total_offset);
    }

	pClientInfo->total_length = sizeof(TrackerHeader);
	pClientInfo->total_offset = 0;
	pTask->length = pClientInfo->total_length;

	pHeader = (TrackerHeader *)pTask->data;
	pHeader->status = result;
	pHeader->cmd = STORAGE_PROTO_CMD_RESP;
	long2buff(0, pHeader->pkg_len);

	STORAGE_ACCESS_LOG(pTask, ACCESS_LOG_ACTION_APPEND_FILE, result);

	sf_nio_notify(pTask, SF_NIO_STAGE_SEND);
}

static void storage_modify_file_done_callback(struct fast_task_info *pTask, \
			const int err_no)
{
	StorageClientInfo *pClientInfo;
	StorageFileContext *pFileContext;
	TrackerHeader *pHeader;
	char extra[64];
	int result;

	pClientInfo = (StorageClientInfo *)pTask->arg;
	pFileContext =  &(pClientInfo->file_context);

	if (err_no == 0)
	{
		struct stat stat_buf;
		if (stat(pFileContext->filename, &stat_buf) == 0)
		{
			pFileContext->timestamp2log = stat_buf.st_mtime;
		}
		else
		{
			result = errno != 0 ? errno : ENOENT;
			STORAGE_STAT_FILE_FAIL_LOG(result, pTask->client_ip,
				"regular", pFileContext->filename)
		}

		sprintf(extra, "%"PRId64" %"PRId64, \
				pFileContext->start, \
				pFileContext->end - pFileContext->start);
		result = storage_binlog_write_ex(pFileContext->timestamp2log, \
				pFileContext->sync_flag, \
				pFileContext->fname2log, extra);
	}
	else
	{
		result = err_no;
	}

	if (result == 0)
	{
		CHECK_AND_WRITE_TO_STAT_FILE3_WITH_BYTES( \
			g_storage_stat.total_modify_count, \
			g_storage_stat.success_modify_count, \
			g_storage_stat.last_source_update, \
			g_storage_stat.total_modify_bytes, \
			g_storage_stat.success_modify_bytes, \
			pFileContext->end - pFileContext->start)
	}
	else
	{
        __sync_add_and_fetch(&g_storage_stat.total_modify_count, 1);
        __sync_add_and_fetch(&g_storage_stat.total_modify_bytes,
                pClientInfo->total_offset);
	}

	pClientInfo->total_length = sizeof(TrackerHeader);
	pClientInfo->total_offset = 0;
	pTask->length = pClientInfo->total_length;

	pHeader = (TrackerHeader *)pTask->data;
	pHeader->status = result;
	pHeader->cmd = STORAGE_PROTO_CMD_RESP;
	long2buff(0, pHeader->pkg_len);

	STORAGE_ACCESS_LOG(pTask, ACCESS_LOG_ACTION_MODIFY_FILE, result);

	sf_nio_notify(pTask, SF_NIO_STAGE_SEND);
}

static void storage_do_truncate_file_done_callback(struct fast_task_info *pTask, \
			const int err_no)
{
	StorageClientInfo *pClientInfo;
	StorageFileContext *pFileContext;
	TrackerHeader *pHeader;
	char extra[64];
	int result;

	pClientInfo = (StorageClientInfo *)pTask->arg;
	pFileContext =  &(pClientInfo->file_context);

	if (err_no == 0)
	{
		struct stat stat_buf;
		if (stat(pFileContext->filename, &stat_buf) == 0)
		{
			pFileContext->timestamp2log = stat_buf.st_mtime;
		}
		else
		{
			result = errno != 0 ? errno : ENOENT;
			STORAGE_STAT_FILE_FAIL_LOG(result, pTask->client_ip,
				"regular", pFileContext->filename)
		}
		sprintf(extra, "%"PRId64" %"PRId64, \
				pFileContext->end - pFileContext->start,
				pFileContext->offset);
		result = storage_binlog_write_ex(pFileContext->timestamp2log, \
				pFileContext->sync_flag, \
				pFileContext->fname2log, extra);
	}
	else
	{
		result = err_no;
	}

	if (result == 0)
	{
		CHECK_AND_WRITE_TO_STAT_FILE3( \
			g_storage_stat.total_truncate_count, \
			g_storage_stat.success_truncate_count, \
			g_storage_stat.last_source_update)
	}
	else
	{
        __sync_add_and_fetch(&g_storage_stat.total_truncate_count, 1);
	}

	pClientInfo->total_length = sizeof(TrackerHeader);
	pClientInfo->total_offset = 0;
	pTask->length = pClientInfo->total_length;

	pHeader = (TrackerHeader *)pTask->data;
	pHeader->status = result;
	pHeader->cmd = STORAGE_PROTO_CMD_RESP;
	long2buff(0, pHeader->pkg_len);

	STORAGE_ACCESS_LOG(pTask, ACCESS_LOG_ACTION_TRUNCATE_FILE, result);

	sf_nio_notify(pTask, SF_NIO_STAGE_SEND);
}

static void storage_set_metadata_done_callback( \
		struct fast_task_info *pTask, const int err_no)
{
	StorageClientInfo *pClientInfo;
	StorageFileContext *pFileContext;
	TrackerHeader *pHeader;
	int result;

	pClientInfo = (StorageClientInfo *)pTask->arg;
	pFileContext =  &(pClientInfo->file_context);

	if (err_no == 0)
	{
		if (pFileContext->sync_flag != '\0')
		{
		result = storage_binlog_write(pFileContext->timestamp2log, \
			pFileContext->sync_flag, pFileContext->fname2log);
		}
		else
		{
			result = err_no;
		}
	}
	else
	{
		result = err_no;
	}

	if (result != 0)
	{
        __sync_add_and_fetch(&g_storage_stat.total_set_meta_count, 1);
	}
	else
	{
		CHECK_AND_WRITE_TO_STAT_FILE3( \
				g_storage_stat.total_set_meta_count, \
				g_storage_stat.success_set_meta_count, \
				g_storage_stat.last_source_update)
	}

	pClientInfo->total_length = sizeof(TrackerHeader);
	pClientInfo->total_offset = 0;
	pTask->length = pClientInfo->total_length;
	pHeader = (TrackerHeader *)pTask->data;
	pHeader->status = result;
	pHeader->cmd = STORAGE_PROTO_CMD_RESP;
	long2buff(pClientInfo->total_length - sizeof(TrackerHeader), \
			pHeader->pkg_len);

	STORAGE_ACCESS_LOG(pTask, ACCESS_LOG_ACTION_SET_METADATA, result);

	sf_nio_notify(pTask, SF_NIO_STAGE_SEND);
}

void task_finish_clean_up(struct fast_task_info *pTask)
{
    if (__sync_sub_and_fetch(&pTask->reffer_count, 0) == 1)
    {
        storage_clear_task(pTask);
    }
    ++g_stat_change_count;
    sf_task_finish_clean_up(pTask);
}

int storage_set_body_length(struct fast_task_info *pTask)
{
    StorageClientInfo *pClientInfo;
    int64_t total_length;

    pClientInfo = (StorageClientInfo *)pTask->arg;
    if (pClientInfo->total_length == 0) //header
    {
        total_length = buff2long(((TrackerHeader *)
                    pTask->data)->pkg_len);
        if (total_length < 0)
        {
            logError("file: "__FILE__", line: %d, "
                    "client ip: %s, pkg length: %"PRId64" < 0",
                    __LINE__, pTask->client_ip, total_length);
            return EINVAL;
        }

        pClientInfo->total_length = total_length + sizeof(TrackerHeader);
        if (pClientInfo->total_length > pTask->size)
        {
            pTask->length = pTask->size - sizeof(TrackerHeader);
        }
        else
        {
            pTask->length = total_length;
        }
    }

    return 0;
}

static int sock_accept_done_callback(struct fast_task_info *task,
        const in_addr_t client_addr, const bool bInnerPort)
{
    if (g_allow_ip_count >= 0)
    {
        if (bsearch(&client_addr, g_allow_ip_addrs,
                    g_allow_ip_count, sizeof(in_addr_t),
                    cmp_by_ip_addr_t) == NULL)
        {
            logError("file: "__FILE__", line: %d, "
                    "ip addr %s is not allowed to access",
                    __LINE__, task->client_ip);
            return EPERM;
        }
    }

    return 0;
}

static int sock_send_done_callback(struct fast_task_info *pTask,
        const int length)
{
    StorageClientInfo *pClientInfo;

    pClientInfo = (StorageClientInfo *)pTask->arg;
    pClientInfo->total_offset += length;
    if (pClientInfo->total_offset >= pClientInfo->total_length)
    {
        if (pClientInfo->total_length == sizeof(TrackerHeader)
                && ((TrackerHeader *)pTask->data)->status == EINVAL)
        {
            logDebug("file: "__FILE__", line: %d, "
                    "close conn: #%d, client ip: %s",
                    __LINE__, pTask->event.fd,
                    pTask->client_ip);
            return EINVAL;
        }

        /*  response done, try to recv again */
        pClientInfo->total_length = 0;
        pClientInfo->total_offset = 0;
        return 0;
    }
    else  //continue to send file content
    {
        /* continue read from file */
        return storage_dio_queue_push(pTask);
    }
}

static void *alloc_thread_extra_data_func(const int thread_index)
{
    int result;
    GroupArray *group_array;  //FastDHT group array

    if (g_check_file_duplicate)
    {
        group_array = fc_malloc(sizeof(GroupArray));
        if ((result=fdht_copy_group_array(group_array, &g_group_array)) != 0)
        {
            return NULL;
        }
        return group_array;
    }
    else
    {
        return NULL;
    }
}

int storage_service_init()
{
	int result;

	last_stat_change_count = g_stat_change_count;
    if ((result=fast_mblock_init(&finfo_for_crc32_allocator,
                    sizeof(StorageFileInfoForCRC32), 1024)) != 0)
    {
        return result;
    }

    result = sf_service_init("storage", alloc_thread_extra_data_func,
            NULL, sock_accept_done_callback, storage_set_body_length,
            sock_send_done_callback, storage_deal_task, task_finish_clean_up,
            NULL, 1000, sizeof(TrackerHeader), sizeof(StorageClientInfo));
    sf_enable_thread_notify(false);
    sf_set_remove_from_ready_list(false);

	return result;
}

void storage_service_destroy()
{
}

int storage_get_storage_path_index(int *store_path_index)
{
	int i;

	*store_path_index = g_store_path_index;
	if (g_store_path_mode == FDFS_STORE_PATH_LOAD_BALANCE)
	{
		if (*store_path_index < 0 || *store_path_index >= \
			g_fdfs_store_paths.count)
		{
			return ENOSPC;
		}
	}
	else
	{
		if (*store_path_index >= g_fdfs_store_paths.count)
		{
			*store_path_index = 0;
		}

		if (!storage_check_reserved_space_path(g_fdfs_store_paths.paths \
			[*store_path_index].total_mb, g_fdfs_store_paths.paths \
			[*store_path_index].free_mb, g_avg_storage_reserved_mb))
		{
			for (i=0; i<g_fdfs_store_paths.count; i++)
			{
				if (storage_check_reserved_space_path( \
					g_fdfs_store_paths.paths[i].total_mb, \
					g_fdfs_store_paths.paths[i].free_mb, \
			 		g_avg_storage_reserved_mb))
				{
					*store_path_index = i;
					g_store_path_index = i;
					break;
				}
			}

			if (i == g_fdfs_store_paths.count)
			{
				return ENOSPC;
			}
		}

		g_store_path_index++;
		if (g_store_path_index >= g_fdfs_store_paths.count)
		{
			g_store_path_index = 0;
		}
	}

	return 0;
}

void storage_get_store_path(const char *filename, const int filename_len, \
		int *sub_path_high, int *sub_path_low)
{
	int n;
    int write_file_count;
    int path_index_high;

	if (g_file_distribute_path_mode == FDFS_FILE_DIST_PATH_ROUND_ROBIN)
	{
		*sub_path_high = FC_ATOMIC_GET(g_dist_path_index_high);
		*sub_path_low = FC_ATOMIC_GET(g_dist_path_index_low);
        while (1) {
            write_file_count = __sync_add_and_fetch(
                    &g_dist_write_file_count, 1);
            if (write_file_count < g_file_distribute_rotate_count)
            {
                break;
            }
            if (write_file_count == g_file_distribute_rotate_count)
            {
                if (__sync_add_and_fetch(&g_dist_path_index_low, 1) >=
                        g_subdir_count_per_path)
                {  //rotate
                    path_index_high = __sync_add_and_fetch(
                            &g_dist_path_index_high, 1);
                    if (path_index_high >= g_subdir_count_per_path) //rotate
                    {
                        FC_ATOMIC_SET(g_dist_path_index_high, 0);
                    }
                    FC_ATOMIC_SET(g_dist_path_index_low, 0);
                }

                FC_ATOMIC_SET(g_dist_write_file_count, 0);
                ++g_stat_change_count;
                break;
            }
        }
	}
	else //random
	{
		n = PJWHash(filename, filename_len) % (1 << 16);
		*sub_path_high = ((n >> 8) & 0xFF) % g_subdir_count_per_path;
		*sub_path_low = (n & 0xFF) % g_subdir_count_per_path;
	}
}

#define COMBINE_RAND_FILE_SIZE(file_size, masked_file_size) \
	do \
	{ \
		int r; \
		r = (rand() & 0x007FFFFF) | 0x80000000; \
		masked_file_size = (((int64_t)r) << 32 ) | file_size; \
	} while (0)


static int storage_gen_filename(StorageClientInfo *pClientInfo,
		const int64_t file_size, const int crc32,
		const char *szFormattedExt, const int ext_name_len,
		const time_t timestamp, char *filename, int *filename_len)
{
	char buff[sizeof(int) * 5];
	char encoded[sizeof(int) * 8 + 1];
	int len;
	int64_t masked_file_size;
	FDFSTrunkFullInfo *pTrunkInfo;

	pTrunkInfo = &(pClientInfo->file_context.extra_info.upload.trunk_info);
	int2buff(htonl(g_server_id_in_filename), buff);
	int2buff(timestamp, buff+sizeof(int));
	if ((file_size >> 32) != 0)
	{
		masked_file_size = file_size;
	}
	else
	{
		COMBINE_RAND_FILE_SIZE(file_size, masked_file_size);
	}
	long2buff(masked_file_size, buff+sizeof(int)*2);
	int2buff(crc32, buff+sizeof(int)*4);

	base64_encode_ex(&g_fdfs_base64_context, buff, sizeof(int) * 5, encoded, \
			filename_len, false);

	if (!pClientInfo->file_context.extra_info.upload.if_sub_path_alloced)
	{
		int sub_path_high;
		int sub_path_low;
		storage_get_store_path(encoded, *filename_len,
			&sub_path_high, &sub_path_low);

		pTrunkInfo->path.sub_path_high = sub_path_high;
		pTrunkInfo->path.sub_path_low  = sub_path_low;

		pClientInfo->file_context.extra_info.upload.
				if_sub_path_alloced = true;
	}

	len = sprintf(filename, FDFS_STORAGE_DATA_DIR_FORMAT"/"
			FDFS_STORAGE_DATA_DIR_FORMAT"/",
			pTrunkInfo->path.sub_path_high, 
			pTrunkInfo->path.sub_path_low);
	memcpy(filename+len, encoded, *filename_len);
	memcpy(filename+len+(*filename_len), szFormattedExt, ext_name_len);
	*filename_len += len + ext_name_len;
	*(filename + (*filename_len)) = '\0';

	return 0;
}

static int storage_sort_metadata_buff(char *meta_buff, const int meta_size)
{
	FDFSMetaData *meta_list;
	int meta_count;
	int meta_bytes;
	int result;

	meta_list = fdfs_split_metadata(meta_buff, &meta_count, &result);
	if (meta_list == NULL)
	{
		return result;
	}

	qsort((void *)meta_list, meta_count, sizeof(FDFSMetaData), \
		metadata_cmp_by_name);

	fdfs_pack_metadata(meta_list, meta_count, meta_buff, &meta_bytes);
	free(meta_list);

	return 0;
}

static void storage_format_ext_name(const char *file_ext_name,
		char *szFormattedExt)
{
	int i;
	int ext_name_len;
	int pad_len;
	char *p;

	ext_name_len = strlen(file_ext_name);
	if (ext_name_len == 0)
	{
		pad_len = FDFS_FILE_EXT_NAME_MAX_LEN + 1;
	}
	else
	{
		pad_len = FDFS_FILE_EXT_NAME_MAX_LEN - ext_name_len;
	}

	p = szFormattedExt;
	for (i=0; i<pad_len; i++)
	{
		*p++ = '0' + (int)(10.0 * (double)rand() / RAND_MAX);
	}

	if (ext_name_len > 0)
	{
		*p++ = '.';
		memcpy(p, file_ext_name, ext_name_len);
		p += ext_name_len;
	}
	*p = '\0';
}
 
static int storage_get_filename(StorageClientInfo *pClientInfo,
	const int start_time, const int64_t file_size, const int crc32,
	const char *szFormattedExt, char *filename,
	int *filename_len, char *full_filename)
{
	int i;
	int result;
	int store_path_index;

	store_path_index = pClientInfo->file_context.extra_info.upload.
				trunk_info.path.store_path_index;
	for (i=0; i<10; i++)
	{
		if ((result=storage_gen_filename(pClientInfo, file_size,
			crc32, szFormattedExt, FDFS_FILE_EXT_NAME_MAX_LEN + 1,
			start_time, filename, filename_len)) != 0)
		{
			return result;
		}

		sprintf(full_filename, "%s/data/%s",
			g_fdfs_store_paths.paths[store_path_index].path, filename);
		if (!fileExists(full_filename))
		{
			break;
		}

		*full_filename = '\0';
	}

	if (*full_filename == '\0')
	{
		logError("file: "__FILE__", line: %d, "
			"Can't generate uniq filename", __LINE__);
		*filename = '\0';
		*filename_len = 0;
		return ENOENT;
	}

	return 0;
}

static int storage_client_create_link_wrapper(struct fast_task_info *pTask, \
		const char *master_filename, \
		const char *src_filename, const int src_filename_len, \
		const char *src_file_sig, const int src_file_sig_len, \
		const char *group_name, const char *prefix_name, \
		const char *file_ext_name, \
		char *remote_filename, int *filename_len)
{
	int result;
	int src_store_path_index;
	TrackerServerInfo trackerServer;
	ConnectionInfo *pTracker;
	ConnectionInfo storageServer;
	ConnectionInfo *pStorageServer;
	StorageClientInfo *pClientInfo;
	StorageFileContext *pFileContext;
	SourceFileInfo sourceFileInfo;
	bool bCreateDirectly;

	pClientInfo = (StorageClientInfo *)pTask->arg;
	pFileContext =  &(pClientInfo->file_context);

	if ((pTracker=tracker_get_connection_r(&trackerServer, &result)) == NULL)
	{
		return result;
	}

	if (strcmp(group_name, g_group_name) != 0)
	{
		pStorageServer = NULL;
		bCreateDirectly = false;
	}
	else
	{
		result = tracker_query_storage_update(pTracker, \
				&storageServer, group_name, src_filename);
		if (result != 0)
		{
			tracker_close_connection_ex(pTracker, true);
			return result;
		}

		if (is_local_host_ip(storageServer.ip_addr))
		{
			bCreateDirectly = true;
		}
		else
		{
			bCreateDirectly = false;
		}

		if (!bCreateDirectly)
		{
			if ((pStorageServer=tracker_make_connection(
				&storageServer, &result)) == NULL)
			{
				tracker_close_connection(pTracker);
				return result;
			}
		}
		else
		{
			pStorageServer = NULL;
		}
	}

	if (bCreateDirectly)
	{
		sourceFileInfo.src_file_sig_len = src_file_sig_len;
		memcpy(sourceFileInfo.src_file_sig, src_file_sig, \
			src_file_sig_len);
		*(sourceFileInfo.src_file_sig + src_file_sig_len) = '\0';

		*filename_len = src_filename_len;
		if ((result=storage_split_filename_ex(src_filename, \
			filename_len, sourceFileInfo.src_true_filename, \
			&src_store_path_index)) != 0)
		{
			tracker_close_connection(pTracker);
			return result;
		}

		pFileContext->extra_info.upload.trunk_info.path. \
			store_path_index = src_store_path_index;
		result = storage_create_link_core(pTask, \
			&sourceFileInfo, src_filename, \
			master_filename, strlen(master_filename), \
			prefix_name, file_ext_name, \
			remote_filename, filename_len, false);
		if (result == TASK_STATUS_CONTINUE)
		{
			result = 0;
		}
	}
	else
	{
		result = storage_client_create_link(pTracker, \
				pStorageServer, master_filename, \
				src_filename, src_filename_len, \
				src_file_sig, src_file_sig_len, \
				group_name, prefix_name, \
				file_ext_name, remote_filename, filename_len);
		if (pStorageServer != NULL)
		{
			tracker_close_connection_ex(pStorageServer, result != 0);
		}
	}

	tracker_close_connection(pTracker);

	return result;
}

static int storage_service_upload_file_done(struct fast_task_info *pTask)
{
	int result;
	int filename_len;
	StorageClientInfo *pClientInfo;
	StorageFileContext *pFileContext;
	int64_t file_size;
	int64_t file_size_in_name;
	time_t end_time;
	char new_fname2log[128];
	char new_full_filename[MAX_PATH_SIZE+64];
	char new_filename[128];
	int new_filename_len;

	pClientInfo = (StorageClientInfo *)pTask->arg;
	pFileContext =  &(pClientInfo->file_context);
	file_size = pFileContext->end - pFileContext->start;

	*new_full_filename = '\0';
	*new_filename = '\0';
	new_filename_len = 0;
	if (pFileContext->extra_info.upload.file_type & _FILE_TYPE_TRUNK)
	{
		end_time = pFileContext->extra_info.upload.start_time;
		COMBINE_RAND_FILE_SIZE(file_size, file_size_in_name);
		file_size_in_name |= FDFS_TRUNK_FILE_MARK_SIZE;
	}
	else
	{
		struct stat stat_buf;
		if (stat(pFileContext->filename, &stat_buf) == 0)
		{
			end_time = stat_buf.st_mtime;
		}
		else
		{
			result = errno != 0 ? errno : ENOENT;
			STORAGE_STAT_FILE_FAIL_LOG(result, pTask->client_ip,
				"regular", pFileContext->filename)
			end_time = g_current_time;
		}

		if (pFileContext->extra_info.upload.file_type & _FILE_TYPE_APPENDER)
		{
			COMBINE_RAND_FILE_SIZE(0, file_size_in_name);
			file_size_in_name |= FDFS_APPENDER_FILE_SIZE;
		}
		else
		{
			file_size_in_name = file_size;
		}
	}

	if ((result=storage_get_filename(pClientInfo, end_time, \
		file_size_in_name, pFileContext->crc32, \
		pFileContext->extra_info.upload.formatted_ext_name, \
		new_filename, &new_filename_len, new_full_filename)) != 0)
	{
		storage_delete_file_auto(pFileContext);
		return result;
	}

	memcpy(pFileContext->extra_info.upload.group_name, g_group_name, \
		FDFS_GROUP_NAME_MAX_LEN + 1);
	sprintf(new_fname2log, "%c"FDFS_STORAGE_DATA_DIR_FORMAT"/%s", \
		FDFS_STORAGE_STORE_PATH_PREFIX_CHAR, \
		pFileContext->extra_info.upload.trunk_info.path. \
		store_path_index, new_filename);

	if (pFileContext->extra_info.upload.file_type & _FILE_TYPE_TRUNK)
	{
		char trunk_buff[FDFS_TRUNK_FILE_INFO_LEN + 1];
		trunk_file_info_encode(&(pFileContext->extra_info.upload. \
					trunk_info.file), trunk_buff);

		sprintf(new_fname2log + FDFS_LOGIC_FILE_PATH_LEN \
			+ FDFS_FILENAME_BASE64_LENGTH, "%s%s", trunk_buff, \
			new_filename + FDFS_TRUE_FILE_PATH_LEN + \
			FDFS_FILENAME_BASE64_LENGTH);
	}
	else if (rename(pFileContext->filename, new_full_filename) != 0)
	{
		result = errno != 0 ? errno : EPERM;
		logError("file: "__FILE__", line: %d, " \
			"rename %s to %s fail, " \
			"errno: %d, error info: %s", __LINE__, \
			pFileContext->filename, new_full_filename, \
			result, STRERROR(result));

		unlink(pFileContext->filename);
		return result;
	}

	pFileContext->timestamp2log = end_time;
	if (pFileContext->extra_info.upload.file_type & _FILE_TYPE_APPENDER)
	{
		strcpy(pFileContext->fname2log, new_fname2log);
		pFileContext->create_flag = STORAGE_CREATE_FLAG_FILE;
		return 0;
	}

	if ((pFileContext->extra_info.upload.file_type & _FILE_TYPE_SLAVE))
	{
		char true_filename[128];
		char filename[128];
		int master_store_path_index;
		int master_filename_len = strlen(pFileContext->extra_info. \
						upload.master_filename);
		if ((result=storage_split_filename_ex(pFileContext->extra_info.\
			upload.master_filename, &master_filename_len, \
			true_filename, &master_store_path_index)) != 0)
		{
			unlink(new_full_filename);
			return result;
		}
		if ((result=fdfs_gen_slave_filename(true_filename, \
			pFileContext->extra_info.upload.prefix_name, \
			pFileContext->extra_info.upload.file_ext_name, \
			filename, &filename_len)) != 0)
		{
			unlink(new_full_filename);
			return result;
		}

		snprintf(pFileContext->filename, sizeof(pFileContext->filename), \
			"%s/data/%s", g_fdfs_store_paths.paths[master_store_path_index].path, \
			filename);
		sprintf(pFileContext->fname2log, \
			"%c"FDFS_STORAGE_DATA_DIR_FORMAT"/%s", \
			FDFS_STORAGE_STORE_PATH_PREFIX_CHAR, \
			master_store_path_index, filename);

		if (g_store_slave_file_use_link)
		{
			if (symlink(new_full_filename, pFileContext->filename) != 0)
			{
				result = errno != 0 ? errno : ENOENT;
				logError("file: "__FILE__", line: %d, " \
					"link file %s to %s fail, " \
					"errno: %d, error info: %s", \
					__LINE__, new_full_filename, \
					pFileContext->filename, \
					result, STRERROR(result));

				unlink(new_full_filename);
				return result;
			}

			result = storage_binlog_write( \
					pFileContext->timestamp2log, \
					STORAGE_OP_TYPE_SOURCE_CREATE_FILE, \
					new_fname2log);
			if (result == 0)
			{
				char binlog_buff[256];
				snprintf(binlog_buff, sizeof(binlog_buff), \
					"%s %s", pFileContext->fname2log, \
					new_fname2log);
				result = storage_binlog_write( \
					pFileContext->timestamp2log, \
					STORAGE_OP_TYPE_SOURCE_CREATE_LINK, \
					binlog_buff);
			}
			if (result != 0)
			{
				unlink(new_full_filename);
				unlink(pFileContext->filename);
				return result;
			}

			pFileContext->create_flag = STORAGE_CREATE_FLAG_LINK;
		}
		else
		{
			if (rename(new_full_filename, pFileContext->filename) != 0)
			{
				result = errno != 0 ? errno : ENOENT;
				logError("file: "__FILE__", line: %d, " \
					"rename file %s to %s fail, " \
					"errno: %d, error info: %s", \
					__LINE__, new_full_filename, \
					pFileContext->filename, \
					result, STRERROR(result));

				unlink(new_full_filename);
				return result;
			}

			pFileContext->create_flag = STORAGE_CREATE_FLAG_FILE;
		}

		return 0;
	}

	strcpy(pFileContext->fname2log, new_fname2log);
	if (!(pFileContext->extra_info.upload.file_type & _FILE_TYPE_TRUNK))
	{
		strcpy(pFileContext->filename, new_full_filename);
	}

	if (g_check_file_duplicate && !(pFileContext->extra_info.upload.file_type & \
		_FILE_TYPE_LINK))
	{
		GroupArray *pGroupArray;
		char value[128];
		FDHTKeyInfo key_info;
		char *pValue;
		int value_len;
		int nSigLen;
		char szFileSig[FILE_SIGNATURE_SIZE];
		//char buff[64];

		memset(&key_info, 0, sizeof(key_info));
		key_info.namespace_len = g_namespace_len;
		memcpy(key_info.szNameSpace, g_key_namespace, g_namespace_len);

		pGroupArray = pTask->thread_data->arg;
		STORAGE_GEN_FILE_SIGNATURE(file_size, \
				pFileContext->file_hash_codes, szFileSig)
		/*
		bin2hex(szFileSig, FILE_SIGNATURE_SIZE, buff);
		logInfo("file: "__FILE__", line: %d, " \
			"file sig: %s", __LINE__, buff);
		*/

		nSigLen = FILE_SIGNATURE_SIZE;
		key_info.obj_id_len = nSigLen;
		memcpy(key_info.szObjectId, szFileSig, nSigLen);
		key_info.key_len = sizeof(FDHT_KEY_NAME_FILE_ID) - 1;
		memcpy(key_info.szKey, FDHT_KEY_NAME_FILE_ID, \
				sizeof(FDHT_KEY_NAME_FILE_ID) - 1);

		pValue = value;
		value_len = sizeof(value) - 1;
		result = fdht_get_ex1(pGroupArray, g_keep_alive, \
				&key_info, FDHT_EXPIRES_NONE, \
				&pValue, &value_len, malloc);
		if (result == 0)
		{   //exists
			char *pGroupName;
			char *pSrcFilename;
			char *pSeperator;

			*(value + value_len) = '\0';
			pSeperator = strchr(value, '/');
			if (pSeperator == NULL)
			{
				logError("file: "__FILE__", line: %d, "\
					"value %s is invalid", \
					__LINE__, value);

				return EINVAL;
			}

			*pSeperator = '\0';
			pGroupName = value;
			pSrcFilename = pSeperator + 1;

			if ((result=storage_delete_file_auto(pFileContext)) != 0)
			{
				logError("file: "__FILE__", line: %d, "\
					"unlink %s fail, errno: %d, " \
					"error info: %s", __LINE__, \
					((pFileContext->extra_info.upload. \
					file_type & _FILE_TYPE_TRUNK) ? \
					pFileContext->fname2log \
					: pFileContext->filename), \
					result, STRERROR(result));

				return result;
			}

			memset(pFileContext->extra_info.upload.group_name, \
				0, FDFS_GROUP_NAME_MAX_LEN + 1);
			snprintf(pFileContext->extra_info.upload.group_name, \
				FDFS_GROUP_NAME_MAX_LEN + 1, "%s", pGroupName);
			result = storage_client_create_link_wrapper(pTask, \
				pFileContext->extra_info.upload.master_filename, \
				pSrcFilename, value_len-(pSrcFilename-value),\
				key_info.szObjectId, key_info.obj_id_len, \
				pGroupName, \
				pFileContext->extra_info.upload.prefix_name, \
				pFileContext->extra_info.upload.file_ext_name,\
				pFileContext->fname2log, &filename_len);

			pFileContext->create_flag = STORAGE_CREATE_FLAG_LINK;
			return result;
		}
		else if (result == ENOENT)
		{
			char src_filename[128];
			FDHTKeyInfo ref_count_key;

			filename_len = sprintf(src_filename, "%s", new_fname2log);
			value_len = sprintf(value, "%s/%s", \
					g_group_name, new_fname2log);
			if ((result=fdht_set_ex(pGroupArray, g_keep_alive, \
						&key_info, FDHT_EXPIRES_NEVER, \
						value, value_len)) != 0)
			{
				logError("file: "__FILE__", line: %d, "\
					"client ip: %s, fdht_set fail,"\
					"errno: %d, error info: %s", \
					__LINE__, pTask->client_ip, \
					result, STRERROR(result));

				storage_delete_file_auto(pFileContext);
				return result;
			}

			memcpy(&ref_count_key, &key_info, sizeof(FDHTKeyInfo));
			ref_count_key.obj_id_len = value_len;
			memcpy(ref_count_key.szObjectId, value, value_len);
			ref_count_key.key_len = sizeof(FDHT_KEY_NAME_REF_COUNT) - 1;
			memcpy(ref_count_key.szKey, FDHT_KEY_NAME_REF_COUNT, \
					ref_count_key.key_len);
			if ((result=fdht_set_ex(pGroupArray, g_keep_alive, \
				&ref_count_key, FDHT_EXPIRES_NEVER, "0", 1)) != 0)
			{
				logError("file: "__FILE__", line: %d, "\
					"client ip: %s, fdht_set fail,"\
					"errno: %d, error info: %s", \
					__LINE__, pTask->client_ip, \
					result, STRERROR(result));

				storage_delete_file_auto(pFileContext);
				return result;
			}


			result = storage_binlog_write(pFileContext->timestamp2log, \
					STORAGE_OP_TYPE_SOURCE_CREATE_FILE, \
					src_filename);
			if (result != 0)
			{
				storage_delete_file_auto(pFileContext);
				return result;
			}

			result = storage_client_create_link_wrapper(pTask, \
				pFileContext->extra_info.upload.master_filename, \
				src_filename, filename_len, szFileSig, nSigLen,\
				g_group_name, pFileContext->extra_info.upload.prefix_name, \
				pFileContext->extra_info.upload.file_ext_name, \
				pFileContext->fname2log, &filename_len);

			if (result != 0)
			{
				fdht_delete_ex(pGroupArray, g_keep_alive, &key_info);
				fdht_delete_ex(pGroupArray, g_keep_alive, &ref_count_key);

				storage_delete_file_auto(pFileContext);
			}

			pFileContext->create_flag = STORAGE_CREATE_FLAG_LINK;
			return result;
		}
		else //error
		{
			logError("file: "__FILE__", line: %d, " \
				"fdht_get fail, " \
				"errno: %d, error info: %s", \
				__LINE__, result, STRERROR(errno));

			storage_delete_file_auto(pFileContext);
			return result;
		}
	}

	if (pFileContext->extra_info.upload.file_type & _FILE_TYPE_LINK)
	{
		pFileContext->create_flag = STORAGE_CREATE_FLAG_LINK;
	}
	else
	{
		pFileContext->create_flag = STORAGE_CREATE_FLAG_FILE;
	}

	return 0;
}

static int storage_nio_notify(struct fast_task_info *pTask, const int stage)
{
    StorageClientInfo *pClientInfo;
    int64_t remain_bytes;

    pClientInfo = (StorageClientInfo *)pTask->arg;
    if (stage == SF_NIO_STAGE_RECV)
    {
        pTask->offset = 0;
        remain_bytes = pClientInfo->total_length -
            pClientInfo->total_offset;
        if (remain_bytes > pTask->size)
        {
            pTask->length = pTask->size;
        }
        else
        {
            pTask->length = remain_bytes;
        }
    }

    return sf_nio_notify(pTask, stage);
}

static int calc_crc32_continue_callback(struct fast_task_info *pTask,
        const int stage)
{
    pTask->length = 0;
    return storage_dio_queue_push(pTask);
}

static int storage_trunk_do_create_link(struct fast_task_info *pTask, \
		const int64_t file_bytes, const int buff_offset, \
		FileBeforeOpenCallback before_open_callback,
		FileDealDoneCallback done_callback)
{
	StorageClientInfo *pClientInfo;
	StorageFileContext *pFileContext;
	int64_t file_offset;

	pClientInfo = (StorageClientInfo *)pTask->arg;
	pFileContext =  &(pClientInfo->file_context);

	file_offset = TRUNK_FILE_START_OFFSET( \
			pFileContext->extra_info.upload.trunk_info);
	trunk_get_full_filename(&(pFileContext->extra_info.upload.trunk_info), 
			pFileContext->filename, sizeof(pFileContext->filename));
	pFileContext->extra_info.upload.before_open_callback = \
				before_open_callback;
	pFileContext->extra_info.upload.before_close_callback = \
				dio_write_chunk_header;
	pFileContext->open_flags = O_RDWR | g_extra_open_file_flags;
	pFileContext->op = FDFS_STORAGE_FILE_OP_WRITE;
	pFileContext->fd = -1;
	pFileContext->buff_offset = buff_offset;
	pFileContext->offset = file_offset;
	pFileContext->start = file_offset;
	pFileContext->end = file_offset + file_bytes;
	pFileContext->dio_thread_index = storage_dio_get_thread_index( \
		pTask, pFileContext->extra_info.upload.trunk_info.path. \
		store_path_index, pFileContext->op);

    pFileContext->continue_callback = storage_nio_notify;
	pFileContext->done_callback = done_callback;
	pClientInfo->clean_func = dio_trunk_write_finish_clean_up;

	return dio_write_file(pTask);
}

static int storage_trunk_create_link(struct fast_task_info *pTask, \
	const char *src_filename, const SourceFileInfo *pSourceFileInfo, \
	const bool bNeedReponse)
{
	StorageClientInfo *pClientInfo;
	StorageFileContext *pFileContext;
	FDFSTrunkFullInfo *pTrunkInfo;
	TrunkCreateLinkArg *pCreateLinkArg;
	char *p;
	int64_t file_bytes;
	int result;

	pClientInfo = (StorageClientInfo *)pTask->arg;
	pFileContext =  &(pClientInfo->file_context);
	file_bytes = strlen(src_filename);

	pFileContext->extra_info.upload.if_sub_path_alloced = true;
	pTrunkInfo = &(pFileContext->extra_info.upload.trunk_info);
	if ((result=trunk_client_trunk_alloc_space( \
			TRUNK_CALC_SIZE(file_bytes), pTrunkInfo)) != 0)
	{
		return result;
	}

	pTask->length = pTask->size;
	p = pTask->data + (pTask->length - sizeof(TrunkCreateLinkArg) \
			    - file_bytes);
	if (p < pTask->data + sizeof(TrackerHeader))
	{
		logError("file: "__FILE__", line: %d, " \
			"task buffer size: %d is too small", \
			__LINE__, pTask->size);
		return ENOSPC;
	}

	pCreateLinkArg = (TrunkCreateLinkArg *)p;
	memcpy(&(pCreateLinkArg->src_file_info), pSourceFileInfo, \
			sizeof(SourceFileInfo));
	pCreateLinkArg->need_response = bNeedReponse;
	pClientInfo->extra_arg = (void *)pCreateLinkArg;
	p += sizeof(TrunkCreateLinkArg);
	memcpy(p, src_filename, file_bytes);

	storage_trunk_do_create_link(pTask, file_bytes, p - pTask->data, \
			dio_check_trunk_file_when_upload, \
			storage_trunk_create_link_file_done_callback);
	return TASK_STATUS_CONTINUE;
}

static int storage_service_do_create_link(struct fast_task_info *pTask, \
		const SourceFileInfo *pSrcFileInfo, \
		const int64_t file_size, const char *master_filename, \
		const char *prefix_name, const char *file_ext_name,  \
		char *filename, int *filename_len)
{
	StorageClientInfo *pClientInfo;
	StorageFileContext *pFileContext;
	int result;
	int crc32;
	int store_path_index;
	char src_full_filename[MAX_PATH_SIZE+64];
	char full_filename[MAX_PATH_SIZE+64];

	pClientInfo = (StorageClientInfo *)pTask->arg;
	pFileContext =  &(pClientInfo->file_context);
	store_path_index = pFileContext->extra_info. \
				upload.trunk_info.path.store_path_index;
	if (*filename_len == 0)
	{
		char formatted_ext_name[FDFS_FILE_EXT_NAME_MAX_LEN + 2];

		storage_format_ext_name(file_ext_name, formatted_ext_name);
		crc32 = rand();
		if ((result=storage_get_filename(pClientInfo, g_current_time, \
			file_size, crc32, formatted_ext_name, filename, \
			filename_len, full_filename)) != 0)
		{
			return result;
		}
	}
	else
	{
		sprintf(full_filename, "%s/data/%s", \
			g_fdfs_store_paths.paths[store_path_index].path, \
			filename);
	}

	sprintf(src_full_filename, "%s/data/%s", \
		g_fdfs_store_paths.paths[store_path_index].path, \
		pSrcFileInfo->src_true_filename);
	if (symlink(src_full_filename, full_filename) != 0)
	{
		result = errno != 0 ? errno : ENOENT;
		logError("file: "__FILE__", line: %d, " \
			"link file %s to %s fail, " \
			"errno: %d, error info: %s", __LINE__, \
			src_full_filename, full_filename, \
			result, STRERROR(result));
		*filename = '\0';
		*filename_len = 0;
		return result;
	}

	*filename_len=sprintf(full_filename, \
			"%c"FDFS_STORAGE_DATA_DIR_FORMAT"/%s", \
			FDFS_STORAGE_STORE_PATH_PREFIX_CHAR, \
			store_path_index, filename);
	memcpy(filename, full_filename, (*filename_len) + 1);

	return storage_set_link_file_meta(pTask, pSrcFileInfo, filename);
}

static int storage_set_link_file_meta(struct fast_task_info *pTask, \
		const SourceFileInfo *pSrcFileInfo, const char *link_filename)
{
	StorageClientInfo *pClientInfo;
	StorageFileContext *pFileContext;
	GroupArray *pGroupArray;
	FDHTKeyInfo key_info;
	char value[128];
	int value_len;
	int result;

	if (!g_check_file_duplicate)
	{
		return 0;
	}

	pClientInfo = (StorageClientInfo *)pTask->arg;
	pFileContext =  &(pClientInfo->file_context);

	memset(&key_info, 0, sizeof(key_info));
	key_info.namespace_len = g_namespace_len;
	memcpy(key_info.szNameSpace, g_key_namespace, g_namespace_len);

    pGroupArray = pTask->thread_data->arg;
	key_info.obj_id_len = snprintf(key_info.szObjectId, \
		sizeof(key_info.szObjectId), \
		"%s/%c"FDFS_STORAGE_DATA_DIR_FORMAT"/%s", \
		g_group_name, FDFS_STORAGE_STORE_PATH_PREFIX_CHAR, \
		pFileContext->extra_info.upload.trunk_info.path. \
		store_path_index, pSrcFileInfo->src_true_filename);

	key_info.key_len = sizeof(FDHT_KEY_NAME_REF_COUNT) - 1;
	memcpy(key_info.szKey, FDHT_KEY_NAME_REF_COUNT, key_info.key_len);
	value_len = sizeof(value) - 1;
	if ((result=fdht_inc_ex(pGroupArray, g_keep_alive, &key_info, \
		FDHT_EXPIRES_NEVER, 1, value, &value_len)) != 0)
	{
		logWarning("file: "__FILE__", line: %d, " \
			"client ip: %s, fdht_inc fail," \
			"errno: %d, error info: %s", \
			__LINE__, pTask->client_ip, \
			result, STRERROR(result));
		return 0;
	}

	key_info.obj_id_len = snprintf(key_info.szObjectId, \
			sizeof(key_info.szObjectId), \
			"%s/%s", g_group_name, link_filename);
	key_info.key_len = sizeof(FDHT_KEY_NAME_FILE_SIG) - 1;
	memcpy(key_info.szKey, FDHT_KEY_NAME_FILE_SIG, key_info.key_len);
	if ((result=fdht_set_ex(pGroupArray, g_keep_alive, \
		&key_info, FDHT_EXPIRES_NEVER, \
		pSrcFileInfo->src_file_sig, \
		pSrcFileInfo->src_file_sig_len)) != 0)
	{
		logWarning("file: "__FILE__", line: %d, " \
			"client ip: %s, fdht_set fail," \
			"errno: %d, error info: %s", \
			__LINE__, pTask->client_ip, \
			result, STRERROR(result));
	}

	/*
	logInfo("create link, counter=%s, object_id=%s(%d), key=%s, file_sig_len=(%d)", \
		value, key_info.szObjectId, key_info.obj_id_len, \
		FDHT_KEY_NAME_FILE_SIG, \
		pSrcFileInfo->src_file_sig_len);
	*/

	return 0;
}

static int storage_do_set_metadata(struct fast_task_info *pTask)
{
	StorageClientInfo *pClientInfo;
	StorageFileContext *pFileContext;
	FDFSMetaData *old_meta_list;
	FDFSMetaData *new_meta_list;
	FDFSMetaData *all_meta_list;
	FDFSMetaData *pOldMeta;
	FDFSMetaData *pNewMeta;
	FDFSMetaData *pAllMeta;
	FDFSMetaData *pOldMetaEnd;
	FDFSMetaData *pNewMetaEnd;
	char *meta_buff;
	char *file_buff;
	char *all_meta_buff;
	int64_t file_bytes;
	int meta_bytes;
	int old_meta_count;
	int new_meta_count;
	int all_meta_bytes;
	int result;

	pClientInfo = (StorageClientInfo *)pTask->arg;
	pFileContext =  &(pClientInfo->file_context);

	pFileContext->sync_flag = '\0';
	meta_buff = pFileContext->extra_info.setmeta.meta_buff;
	meta_bytes = pFileContext->extra_info.setmeta.meta_bytes;

	do
	{
	if (pFileContext->extra_info.setmeta.op_flag == \
			STORAGE_SET_METADATA_FLAG_OVERWRITE)
	{
		if (meta_bytes == 0)
		{
			if (!fileExists(pFileContext->filename))
			{
				result = 0;
				break;
			}

			pFileContext->sync_flag = STORAGE_OP_TYPE_SOURCE_DELETE_FILE;
			if (unlink(pFileContext->filename) != 0)
			{
				logError("file: "__FILE__", line: %d, " \
					"client ip: %s, delete file %s fail," \
					"errno: %d, error info: %s", __LINE__, \
					pTask->client_ip, pFileContext->filename, \
					errno, STRERROR(errno));
				result = errno != 0 ? errno : EPERM;
			}
			else
			{
				result = 0;
			}

			break;
		}

		if ((result=storage_sort_metadata_buff(meta_buff, \
				meta_bytes)) != 0)
		{
			break;
		}

		if (fileExists(pFileContext->filename))
		{
			pFileContext->sync_flag = STORAGE_OP_TYPE_SOURCE_UPDATE_FILE;
		}
		else
		{
			pFileContext->sync_flag = STORAGE_OP_TYPE_SOURCE_CREATE_FILE;
		}

		result = writeToFile(pFileContext->filename, meta_buff, meta_bytes);
		break;
	}

	if (meta_bytes == 0)
	{
		result = 0;
		break;
	}

	result = getFileContent(pFileContext->filename, &file_buff, &file_bytes);
	if (result == ENOENT)
	{
		if (meta_bytes == 0)
		{
			result = 0;
			break;
		}

		if ((result=storage_sort_metadata_buff(meta_buff, \
				meta_bytes)) != 0)
		{
			break;
		}

		pFileContext->sync_flag = STORAGE_OP_TYPE_SOURCE_CREATE_FILE;
		result = writeToFile(pFileContext->filename, meta_buff, meta_bytes);
		break;
	}
	else if (result != 0)
	{
		break;
	}

	old_meta_list = fdfs_split_metadata(file_buff, &old_meta_count, &result);
	if (old_meta_list == NULL)
	{
		free(file_buff);
		break;
	}

	new_meta_list = fdfs_split_metadata(meta_buff, &new_meta_count, &result);
	if (new_meta_list == NULL)
	{
		free(file_buff);
		free(old_meta_list);
		break;
	}

	all_meta_list = (FDFSMetaData *)malloc(sizeof(FDFSMetaData) * \
				(old_meta_count + new_meta_count));
	if (all_meta_list == NULL)
	{
		free(file_buff);
		free(old_meta_list);
		free(new_meta_list);

		logError("file: "__FILE__", line: %d, " \
			"malloc %d bytes fail", __LINE__, \
			(int)sizeof(FDFSMetaData) \
			 * (old_meta_count + new_meta_count));
		result = errno != 0 ? errno : ENOMEM;
		break;
	}

	qsort((void *)new_meta_list, new_meta_count, sizeof(FDFSMetaData), \
		metadata_cmp_by_name);

	pOldMetaEnd = old_meta_list + old_meta_count;
	pNewMetaEnd = new_meta_list + new_meta_count;
	pOldMeta = old_meta_list;
	pNewMeta = new_meta_list;
	pAllMeta = all_meta_list;
	while (pOldMeta < pOldMetaEnd && pNewMeta < pNewMetaEnd)
	{
		result = strcmp(pOldMeta->name, pNewMeta->name);
		if (result < 0)
		{
			memcpy(pAllMeta, pOldMeta, sizeof(FDFSMetaData));
			pOldMeta++;
		}
		else if (result == 0)
		{
			memcpy(pAllMeta, pNewMeta, sizeof(FDFSMetaData));
			pOldMeta++;
			pNewMeta++;
		}
		else  //result > 0
		{
			memcpy(pAllMeta, pNewMeta, sizeof(FDFSMetaData));
			pNewMeta++;
		}

		pAllMeta++;
	}

	while (pOldMeta < pOldMetaEnd)
	{
		memcpy(pAllMeta, pOldMeta, sizeof(FDFSMetaData));
		pOldMeta++;
		pAllMeta++;
	}

	while (pNewMeta < pNewMetaEnd)
	{
		memcpy(pAllMeta, pNewMeta, sizeof(FDFSMetaData));
		pNewMeta++;
		pAllMeta++;
	}

	free(file_buff);
	free(old_meta_list);
	free(new_meta_list);

	all_meta_buff = fdfs_pack_metadata(all_meta_list, \
			pAllMeta - all_meta_list, NULL, &all_meta_bytes);
	free(all_meta_list);
	if (all_meta_buff == NULL)
	{
		result = errno != 0 ? errno : ENOMEM;
		break;
	}

	pFileContext->sync_flag = STORAGE_OP_TYPE_SOURCE_UPDATE_FILE;
	result = writeToFile(pFileContext->filename, all_meta_buff, all_meta_bytes);

	free(all_meta_buff);
	} while (0);

	storage_set_metadata_done_callback(pTask, result);
	return result;
}

/**
8 bytes: filename length
8 bytes: meta data size
1 bytes: operation flag, 
     'O' for overwrite all old metadata
     'M' for merge, insert when the meta item not exist, otherwise update it
FDFS_GROUP_NAME_MAX_LEN bytes: group_name
filename
meta data bytes: each meta data separated by \x01,
		 name and value separated by \x02
**/
static int storage_server_set_metadata(struct fast_task_info *pTask)
{
	StorageClientInfo *pClientInfo;
	StorageFileContext *pFileContext;
	int64_t nInPackLen;
	FDFSTrunkHeader trunkHeader;
	char group_name[FDFS_GROUP_NAME_MAX_LEN + 1];
	char filename[128];
	char true_filename[128];
	char *p;
	char *meta_buff;
	int meta_bytes;
	int filename_len;
	int true_filename_len;
	int result;
	int store_path_index;
	struct stat stat_buf;

	pClientInfo = (StorageClientInfo *)pTask->arg;
	pFileContext =  &(pClientInfo->file_context);

	nInPackLen = pClientInfo->total_length - sizeof(TrackerHeader);
	if (nInPackLen <= 2 * FDFS_PROTO_PKG_LEN_SIZE + 1 + \
			FDFS_GROUP_NAME_MAX_LEN)
	{
		logError("file: "__FILE__", line: %d, " \
			"cmd=%d, client ip: %s, package size " \
			"%"PRId64" is not correct, " \
			"expect length > %d", \
			__LINE__, STORAGE_PROTO_CMD_SET_METADATA, \
			pTask->client_ip,  nInPackLen, \
			2 * FDFS_PROTO_PKG_LEN_SIZE + 1 \
			+ FDFS_GROUP_NAME_MAX_LEN);

		return EINVAL;
	}

	if (nInPackLen + sizeof(TrackerHeader) >= pTask->size)
	{
		logError("file: "__FILE__", line: %d, " \
			"cmd=%d, client ip: %s, package size " \
			"%"PRId64" is not correct, " \
			"expect length < %d", \
			__LINE__, STORAGE_PROTO_CMD_SET_METADATA, \
			pTask->client_ip,  nInPackLen, \
			pTask->size - (int)sizeof(TrackerHeader));

		return EINVAL;
	}

	p = pTask->data + sizeof(TrackerHeader);
	filename_len = buff2long(p);
	p += FDFS_PROTO_PKG_LEN_SIZE;
	meta_bytes = buff2long(p);
	p += FDFS_PROTO_PKG_LEN_SIZE;
	if (filename_len <= 0 || filename_len >= sizeof(filename))
	{
		logError("file: "__FILE__", line: %d, " \
			"client ip:%s, invalid filename length: %d", \
			__LINE__, pTask->client_ip, filename_len);

		return EINVAL;
	}

	pFileContext->extra_info.setmeta.op_flag = *p++;
	if (pFileContext->extra_info.setmeta.op_flag != \
		STORAGE_SET_METADATA_FLAG_OVERWRITE && \
	    pFileContext->extra_info.setmeta.op_flag != \
		STORAGE_SET_METADATA_FLAG_MERGE)
	{
		logError("file: "__FILE__", line: %d, " \
			"client ip:%s, " \
			"invalid operation flag: 0x%02X", \
			__LINE__, pTask->client_ip, \
			pFileContext->extra_info.setmeta.op_flag);

		return EINVAL;
	}

	if (meta_bytes < 0 || meta_bytes != nInPackLen - \
		(2 * FDFS_PROTO_PKG_LEN_SIZE + 1 + \
		 FDFS_GROUP_NAME_MAX_LEN + filename_len))
	{
		logError("file: "__FILE__", line: %d, " \
			"client ip:%s, invalid meta bytes: %d", \
			__LINE__, pTask->client_ip, meta_bytes);

		return EINVAL;
	}

	memcpy(group_name, p, FDFS_GROUP_NAME_MAX_LEN);
	*(group_name + FDFS_GROUP_NAME_MAX_LEN) = '\0';
	p += FDFS_GROUP_NAME_MAX_LEN;
	if (strcmp(group_name, g_group_name) != 0)
	{
		logError("file: "__FILE__", line: %d, " \
			"client ip:%s, group_name: %s " \
			"not correct, should be: %s", \
			__LINE__, pTask->client_ip, \
			group_name, g_group_name);
		return EINVAL;
	}

	memcpy(filename, p, filename_len);
	*(filename + filename_len) = '\0';
	p += filename_len;

	STORAGE_ACCESS_STRCPY_FNAME2LOG(filename, filename_len, \
		pClientInfo);

	true_filename_len = filename_len;
	if ((result=storage_split_filename_ex(filename, \
		&true_filename_len, true_filename, &store_path_index)) != 0)
	{
		return result;
	}
	if ((result=fdfs_check_data_filename(true_filename, \
			true_filename_len)) != 0)
	{
		return result;
	}

	meta_buff = p;
	*(meta_buff + meta_bytes) = '\0';

	if ((result=trunk_file_lstat(store_path_index, true_filename, \
			true_filename_len, &stat_buf, \
			&(pFileContext->extra_info.upload.trunk_info), \
			&trunkHeader)) != 0)
	{
		STORAGE_STAT_FILE_FAIL_LOG(result, pTask->client_ip,
			"logic", filename)
		return result;
	}

	pFileContext->timestamp2log = g_current_time;
	sprintf(pFileContext->filename, "%s/data/%s%s", \
		g_fdfs_store_paths.paths[store_path_index].path, true_filename, \
		FDFS_STORAGE_META_FILE_EXT);
	sprintf(pFileContext->fname2log,"%s%s", \
		filename, FDFS_STORAGE_META_FILE_EXT);

	pClientInfo->deal_func = storage_do_set_metadata;
	pFileContext->extra_info.setmeta.meta_buff = meta_buff;
	pFileContext->extra_info.setmeta.meta_bytes = meta_bytes;

	pFileContext->dio_thread_index = storage_dio_get_thread_index( \
		pTask, store_path_index, FDFS_STORAGE_FILE_OP_WRITE);

	if ((result=storage_dio_queue_push(pTask)) != 0)
	{
		return result;
	}

	return TASK_STATUS_CONTINUE;
}

/**
IP_ADDRESS_SIZE bytes: tracker client ip address
**/
static int storage_server_report_server_id(struct fast_task_info *pTask)
{
	StorageClientInfo *pClientInfo;
	char *storage_server_id;
	int64_t nInPackLen;

	pClientInfo = (StorageClientInfo *)pTask->arg;
	nInPackLen = pClientInfo->total_length - sizeof(TrackerHeader);
	pClientInfo->total_length = sizeof(TrackerHeader);
	if (nInPackLen != FDFS_STORAGE_ID_MAX_SIZE)
	{
		logError("file: "__FILE__", line: %d, " \
			"cmd=%d, client ip: %s, package size " \
			"%"PRId64" is not correct, " \
			"expect length: %d", __LINE__, \
			STORAGE_PROTO_CMD_REPORT_SERVER_ID, \
			pTask->client_ip,  nInPackLen, \
			FDFS_STORAGE_ID_MAX_SIZE);
		return EINVAL;
	}

	storage_server_id = pTask->data + sizeof(TrackerHeader);
	*(storage_server_id + (FDFS_STORAGE_ID_MAX_SIZE - 1)) = '\0';
	if (*storage_server_id == '\0')
	{
		logError("file: "__FILE__", line: %d, " \
			"client ip: %s, storage server id is empty!", \
			__LINE__, pTask->client_ip);
		return EINVAL;
	}

	strcpy(pClientInfo->storage_server_id, storage_server_id);

	logDebug("file: "__FILE__", line: %d, " \
			"client ip: %s, storage server id: %s", \
			__LINE__, pTask->client_ip, storage_server_id);

	return 0;
}

/**
N bytes: binlog
**/
static int storage_server_trunk_sync_binlog(struct fast_task_info *pTask)
{
	StorageClientInfo *pClientInfo;
	char *binlog_buff;
	int64_t nInPackLen;

	pClientInfo = (StorageClientInfo *)pTask->arg;
	nInPackLen = pClientInfo->total_length - sizeof(TrackerHeader);
	pClientInfo->total_length = sizeof(TrackerHeader);
	if (nInPackLen == 0)
	{
		logError("file: "__FILE__", line: %d, " \
			"cmd=%d, client ip: %s, package size " \
			"%"PRId64" is not correct", __LINE__, \
			STORAGE_PROTO_CMD_TRUNK_SYNC_BINLOG, \
			pTask->client_ip,  nInPackLen);
		return EINVAL;
	}

	if (!g_if_use_trunk_file)
	{
		logError("file: "__FILE__", line: %d, " \
			"client ip: %s, invalid command: %d, " \
			"because i don't use trunk file!", \
			__LINE__, pTask->client_ip, \
			STORAGE_PROTO_CMD_TRUNK_SYNC_BINLOG);
		return EINVAL;
	}

	if (g_if_trunker_self)
	{
		logError("file: "__FILE__", line: %d, " \
			"client ip: %s, invalid command: %d, " \
			"because i am the TRUNK server!", \
			__LINE__, pTask->client_ip, \
			STORAGE_PROTO_CMD_TRUNK_SYNC_BINLOG);
		return EINVAL;
	}

	binlog_buff = pTask->data + sizeof(TrackerHeader);
	return trunk_binlog_write_buffer(binlog_buff, nInPackLen);
}

static int query_file_info_response(struct fast_task_info *pTask,
        const StorageFileInfoForCRC32 *finfo, const int crc32)
{
	char *p;

	p = pTask->data + sizeof(TrackerHeader);
	long2buff(finfo->fsize, p);
	p += FDFS_PROTO_PKG_LEN_SIZE;
	long2buff(finfo->mtime, p);
	p += FDFS_PROTO_PKG_LEN_SIZE;
	long2buff(crc32, p);
	p += FDFS_PROTO_PKG_LEN_SIZE;

	memset(p, 0, IP_ADDRESS_SIZE);
	if (fdfs_get_server_id_type(finfo->storage_id) == FDFS_ID_TYPE_SERVER_ID)
	{
		if (g_use_storage_id)
		{
			FDFSStorageIdInfo *pStorageIdInfo;
			char id[16];

			sprintf(id, "%d", finfo->storage_id);
			pStorageIdInfo = fdfs_get_storage_by_id(id);
			if (pStorageIdInfo != NULL)
			{
                strcpy(p, fdfs_get_ipaddr_by_peer_ip(
                            &pStorageIdInfo->ip_addrs,
                            pTask->client_ip));
			}
		}
	}
	else
	{
		struct in_addr ip_addr;
		memset(&ip_addr, 0, sizeof(ip_addr));
		ip_addr.s_addr = finfo->storage_id;
		inet_ntop(AF_INET, &ip_addr, p, IP_ADDRESS_SIZE);
	}
	p += IP_ADDRESS_SIZE;

	((StorageClientInfo *)pTask->arg)->total_length = p - pTask->data;
    return 0;
}

static void calc_crc32_done_callback_for_query_finfo(
        struct fast_task_info *pTask, const int err_no)
{
	StorageClientInfo *pClientInfo;
    StorageFileInfoForCRC32 *crc32_file_info;
	StorageFileContext *pFileContext;
	TrackerHeader *pHeader;
	int result;

	pClientInfo = (StorageClientInfo *)pTask->arg;
	pFileContext =  &(pClientInfo->file_context);
    crc32_file_info = (StorageFileInfoForCRC32 *)pClientInfo->extra_arg;

	if (err_no == 0)
	{
        result = query_file_info_response(pTask, crc32_file_info,
                pFileContext->crc32);
	}
	else
	{
		result = err_no;
        pClientInfo->total_length = sizeof(TrackerHeader);
	}

    fast_mblock_free_object(&finfo_for_crc32_allocator, crc32_file_info);

	pClientInfo->total_offset = 0;
	pTask->length = pClientInfo->total_length;

	pHeader = (TrackerHeader *)pTask->data;
	pHeader->status = result;
	pHeader->cmd = STORAGE_PROTO_CMD_RESP;
	long2buff(pTask->length - sizeof(TrackerHeader), pHeader->pkg_len);

    STORAGE_ACCESS_LOG(pTask, ACCESS_LOG_ACTION_QUERY_FILE, result);
	sf_nio_notify(pTask, SF_NIO_STAGE_SEND);
}

static int push_calc_crc32_to_dio_queue(struct fast_task_info *pTask,
        FileDealDoneCallback done_callback, const int store_path_index,
        const struct stat *file_stat, const int storage_id)
{
    StorageClientInfo *pClientInfo;
    StorageFileContext *pFileContext;
    StorageFileInfoForCRC32 *crc32_file_info;

    pClientInfo = (StorageClientInfo *)pTask->arg;
    pFileContext =  &(pClientInfo->file_context);

    crc32_file_info = (StorageFileInfoForCRC32 *)fast_mblock_alloc_object(
            &finfo_for_crc32_allocator);
    if (crc32_file_info == NULL)
    {
        logError("file: "__FILE__", line: %d, "
                "finfo_for_crc32_allocator %d bytes object fail",
                __LINE__, (int)sizeof(StorageFileInfoForCRC32));
        return errno != 0 ? errno : ENOMEM;
    }

    crc32_file_info->storage_id = storage_id;
    crc32_file_info->fsize = file_stat->st_size;
    crc32_file_info->mtime = file_stat->st_mtime;
    pClientInfo->extra_arg = crc32_file_info;

    pFileContext->fd = -1;
    pFileContext->calc_crc32 = true;
    pFileContext->continue_callback = calc_crc32_continue_callback;
    return storage_read_from_file(pTask, 0, file_stat->st_size,
            done_callback, store_path_index);
}

static int query_file_info_deal_response(struct fast_task_info *pTask,
        const char *filename, const char *true_filename,
        struct stat *file_stat, const int store_path_index)
{
	char decode_buff[64];
	int buff_len;
    int storage_id;
    int crc32;
    int64_t file_size;
    StorageFileInfoForCRC32 finfo;

	memset(decode_buff, 0, sizeof(decode_buff));
	base64_decode_auto(&g_fdfs_base64_context, filename +
		FDFS_LOGIC_FILE_PATH_LEN, FDFS_FILENAME_BASE64_LENGTH,
		decode_buff, &buff_len);
	storage_id = ntohl(buff2int(decode_buff));
	file_size = buff2long(decode_buff + sizeof(int) * 2);
	if (IS_APPENDER_FILE(file_size))
    {
        StorageClientInfo *pClientInfo;
        StorageFileContext *pFileContext;

        pClientInfo = (StorageClientInfo *)pTask->arg;
        pFileContext =  &(pClientInfo->file_context);

        snprintf(pFileContext->fname2log, sizeof(pFileContext->fname2log),
                "%s", filename);
        snprintf(pFileContext->filename, sizeof(pFileContext->filename),
                "%s/data/%s", g_fdfs_store_paths.paths[store_path_index].path,
                true_filename);

        return push_calc_crc32_to_dio_queue(pTask,
                calc_crc32_done_callback_for_query_finfo,
                store_path_index, file_stat, storage_id);
    }

    finfo.storage_id = storage_id;
    finfo.fsize = file_stat->st_size;
    finfo.mtime = file_stat->st_mtime;
	crc32 = buff2int(decode_buff + sizeof(int) * 4);
    return query_file_info_response(pTask, &finfo, crc32);
}

/**
FDFS_GROUP_NAME_MAX_LEN bytes: group_name
filename
**/
static int storage_server_query_file_info(struct fast_task_info *pTask)
{
	StorageClientInfo *pClientInfo;
	char *in_buff;
	char *filename;
	char group_name[FDFS_GROUP_NAME_MAX_LEN + 1];
	char true_filename[128];
	char src_filename[MAX_PATH_SIZE + 128];
	struct stat file_lstat;
	struct stat file_stat;
	FDFSTrunkFullInfo trunkInfo;
	FDFSTrunkHeader trunkHeader;
	int64_t nInPackLen;
	int store_path_index;
	int filename_len;
	int true_filename_len;
	int result;
	int len;
	bool bSilence;

	pClientInfo = (StorageClientInfo *)pTask->arg;
	nInPackLen = pClientInfo->total_length - sizeof(TrackerHeader);
	if (nInPackLen <= FDFS_GROUP_NAME_MAX_LEN)
	{
		logError("file: "__FILE__", line: %d, " \
			"cmd=%d, client ip: %s, package size " \
			"%"PRId64" is not correct, " \
			"expect length > %d", __LINE__, \
			STORAGE_PROTO_CMD_QUERY_FILE_INFO, \
			pTask->client_ip,  nInPackLen, \
			FDFS_GROUP_NAME_MAX_LEN);
		return EINVAL;
	}

	filename_len = nInPackLen - FDFS_GROUP_NAME_MAX_LEN;
	if (filename_len >= sizeof(pClientInfo->file_context.fname2log))
	{
		logError("file: "__FILE__", line: %d, " \
			"cmd=%d, client ip: %s, filename length: %d" \
			" is not correct, expect length < %d", __LINE__, \
			STORAGE_PROTO_CMD_QUERY_FILE_INFO, \
			pTask->client_ip, filename_len, \
			(int)sizeof(pClientInfo->file_context.fname2log));
		return EINVAL;
	}

	in_buff = pTask->data + sizeof(TrackerHeader);
	filename = in_buff + FDFS_GROUP_NAME_MAX_LEN;
	*(filename + filename_len) = '\0';

	STORAGE_ACCESS_STRCPY_FNAME2LOG(filename, filename_len, \
			pClientInfo);

	bSilence = ((TrackerHeader *)pTask->data)->status != 0;
	memcpy(group_name, in_buff, FDFS_GROUP_NAME_MAX_LEN);
	*(group_name + FDFS_GROUP_NAME_MAX_LEN) = '\0';
	if (strcmp(group_name, g_group_name) != 0)
	{
		logError("file: "__FILE__", line: %d, " \
			"client ip:%s, group_name: %s " \
			"not correct, should be: %s", \
			__LINE__, pTask->client_ip, \
			group_name, g_group_name);
		return EINVAL;
	}

	true_filename_len = filename_len;
	if ((result=storage_split_filename_ex(filename, &true_filename_len, \
			true_filename, &store_path_index)) != 0)
	{
		return result;
	}
	if ((result=fdfs_check_data_filename(true_filename, \
			true_filename_len)) != 0)
	{
		return result;
	}

	if ((result=trunk_file_lstat(store_path_index, true_filename, \
			true_filename_len, &file_lstat, \
			&trunkInfo, &trunkHeader)) != 0)
	{
		if (result != ENOENT)
		{
			logError("file: "__FILE__", line: %d, " \
				"client ip:%s, lstat logic file: %s fail, " \
				"errno: %d, error info: %s", \
				__LINE__, pTask->client_ip, filename, \
				result, STRERROR(result));
		}
		else if (!bSilence)
		{
			logDebug("file: "__FILE__", line: %d, " \
				"client ip:%s, logic file: %s not exist", \
				__LINE__, pTask->client_ip, filename);
		}

		return result;
	}

	if (S_ISLNK(file_lstat.st_mode))
	{
		if (IS_TRUNK_FILE_BY_ID(trunkInfo))
		{
		char src_true_filename[128];
		int src_filename_len;
		int src_store_path_index;

		result = trunk_file_get_content(&trunkInfo, file_lstat.st_size, \
				NULL, src_filename, sizeof(src_filename) - 1);
		if (result != 0)
		{
			if (!bSilence)
			{
			logError("file: "__FILE__", line: %d, " \
				"client ip:%s, call readlink file %s fail, " \
				"errno: %d, error info: %s", \
				__LINE__, pTask->client_ip, true_filename, 
				result, STRERROR(result));
			}
			return result;
		}

		src_filename_len = file_lstat.st_size;
		*(src_filename + src_filename_len) = '\0';
		if ((result=storage_split_filename_ex(src_filename, \
			&src_filename_len, src_true_filename, \
			&src_store_path_index)) != 0)
		{
			return result;
		}

		result = trunk_file_lstat(src_store_path_index, \
				src_true_filename, src_filename_len, \
				&file_stat, &trunkInfo, &trunkHeader);
		if (result != 0)
		{
			if (result != ENOENT)
			{
				logError("file: "__FILE__", line: %d, " \
				"client ip:%s, call lstat logic file: %s " \
				"fail, errno: %d, error info: %s", \
				__LINE__, pTask->client_ip, src_filename, \
				result, STRERROR(result));
			}
			else if (!bSilence)
			{
				logDebug("file: "__FILE__", line: %d, " \
				"client ip:%s, logic file: %s not exist", \
				__LINE__, pTask->client_ip, src_filename);
			}
			return result;
		}
		}
		else
		{
            char full_filename[MAX_PATH_SIZE + 128];
			sprintf(full_filename, "%s/data/%s",
				g_fdfs_store_paths.paths[store_path_index].path,
				true_filename);
			if ((len=readlink(full_filename, src_filename, \
					sizeof(src_filename))) < 0)
			{
				result = errno != 0 ? errno : EPERM;
				logError("file: "__FILE__", line: %d, " \
					"client ip:%s, call readlink file %s " \
					"fail, errno: %d, error info: %s", \
					__LINE__, pTask->client_ip, \
					true_filename, result, STRERROR(result));
				return result;
			}

			*(src_filename + len) = '\0';
			strcpy(full_filename, src_filename);
			if (stat(full_filename, &file_stat) != 0)
			{
				result = errno != 0 ? errno : ENOENT;
				STORAGE_STAT_FILE_FAIL_LOG(result,
					pTask->client_ip, "regular", full_filename)
				return result;
			}
		}

        file_stat.st_mtime = file_lstat.st_mtime;
	}
	else
	{
		memcpy(&file_stat, &file_lstat, sizeof(struct stat));
	}

	if (filename_len < FDFS_LOGIC_FILE_PATH_LEN + \
				FDFS_FILENAME_BASE64_LENGTH)
	{
		logError("file: "__FILE__", line: %d, " \
			"client ip:%s, length of filename: %s " \
			"is too small, should >= %d", \
			__LINE__, pTask->client_ip, filename, \
			FDFS_LOGIC_FILE_PATH_LEN + FDFS_FILENAME_BASE64_LENGTH);
		return EINVAL;
	}

	return query_file_info_deal_response(pTask, filename,
            true_filename, &file_stat, store_path_index);
}

#define CHECK_TRUNK_SERVER(pTask) \
	if (!g_if_trunker_self) \
	{ \
		logError("file: "__FILE__", line: %d, " \
			"client ip:%s, i am not trunk server!", \
			__LINE__, pTask->client_ip); \
		return EINVAL; \
	}

/**
request package format:
FDFS_GROUP_NAME_MAX_LEN bytes: group_name
4 bytes: file size
1 bytes: store_path_index

response package format:
1 byte: store_path_index
1 byte: sub_path_high
1 byte: sub_path_low
4 bytes: trunk file id
4 bytes: trunk offset
4 bytes: trunk size
**/
static int storage_server_trunk_alloc_space(struct fast_task_info *pTask)
{
	StorageClientInfo *pClientInfo;
	FDFSTrunkInfoBuff *pApplyBody;
	char *in_buff;
	char group_name[FDFS_GROUP_NAME_MAX_LEN + 1];
	FDFSTrunkFullInfo trunkInfo;
	int64_t nInPackLen;
	int file_size;
	int result;

	pClientInfo = (StorageClientInfo *)pTask->arg;
	nInPackLen = pClientInfo->total_length - sizeof(TrackerHeader);
	CHECK_TRUNK_SERVER(pTask)

	if (nInPackLen != FDFS_GROUP_NAME_MAX_LEN + 5)
	{
		logError("file: "__FILE__", line: %d, " \
			"cmd=%d, client ip: %s, package size " \
			"%"PRId64" is not correct, " \
			"expect length: %d", __LINE__, \
			STORAGE_PROTO_CMD_TRUNK_ALLOC_SPACE, \
			pTask->client_ip,  nInPackLen, \
			FDFS_GROUP_NAME_MAX_LEN + 5);
		return EINVAL;
	}

	in_buff = pTask->data + sizeof(TrackerHeader);
	memcpy(group_name, in_buff, FDFS_GROUP_NAME_MAX_LEN);
	*(group_name + FDFS_GROUP_NAME_MAX_LEN) = '\0';
	if (strcmp(group_name, g_group_name) != 0)
	{
		logError("file: "__FILE__", line: %d, " \
			"client ip:%s, group_name: %s " \
			"not correct, should be: %s", \
			__LINE__, pTask->client_ip, \
			group_name, g_group_name);
		return EINVAL;
	}

	file_size = buff2int(in_buff + FDFS_GROUP_NAME_MAX_LEN);
	if (file_size < 0 || !trunk_check_size(file_size))
	{
		logError("file: "__FILE__", line: %d, " \
			"client ip:%s, invalid file size: %d", \
			__LINE__, pTask->client_ip, file_size);
		return EINVAL;
	}

	trunkInfo.path.store_path_index = *(in_buff+FDFS_GROUP_NAME_MAX_LEN+4);
    if (trunkInfo.path.store_path_index < 0 ||
            trunkInfo.path.store_path_index >= g_fdfs_store_paths.count)
    {
		logError("file: "__FILE__", line: %d, " \
			"client ip: %s, store_path_index: %d " \
			"is invalid", __LINE__, \
			pTask->client_ip, trunkInfo.path.store_path_index);
		return EINVAL;
    }
	if ((result=trunk_alloc_space(file_size, &trunkInfo)) != 0)
	{
		return result;
	}

	pApplyBody = (FDFSTrunkInfoBuff *)(pTask->data+sizeof(TrackerHeader));
	pApplyBody->store_path_index = trunkInfo.path.store_path_index;
	pApplyBody->sub_path_high = trunkInfo.path.sub_path_high;
	pApplyBody->sub_path_low = trunkInfo.path.sub_path_low;
	int2buff(trunkInfo.file.id, pApplyBody->id);
	int2buff(trunkInfo.file.offset, pApplyBody->offset);
	int2buff(trunkInfo.file.size, pApplyBody->size);

	pClientInfo->total_length = sizeof(TrackerHeader) + \
				sizeof(FDFSTrunkInfoBuff);
	return 0;
}

#define storage_server_trunk_alloc_confirm(pTask) \
	storage_server_trunk_confirm_or_free(pTask)

#define storage_server_trunk_free_space(pTask) \
	storage_server_trunk_confirm_or_free(pTask)

static int storage_server_trunk_get_binlog_size(struct fast_task_info *pTask)
{
	StorageClientInfo *pClientInfo;
	TrackerHeader *pHeader;
	char *p;
	char binlog_filename[MAX_PATH_SIZE];
	struct stat file_stat;
	int64_t nInPackLen;

	pHeader = (TrackerHeader *)pTask->data;
	pClientInfo = (StorageClientInfo *)pTask->arg;
	nInPackLen = pClientInfo->total_length - sizeof(TrackerHeader);

	if (nInPackLen != 0)
	{
		logError("file: "__FILE__", line: %d, " \
			"cmd=%d, client ip: %s, package size " \
			"%"PRId64" is not correct, " \
			"expect length: 0", __LINE__, \
			pHeader->cmd, pTask->client_ip,  nInPackLen);
		return EINVAL;
	}

	if (!g_if_use_trunk_file)
	{
		logError ("file: " __FILE__ ", line: %d, "
			"client ip: %s, i don't support trunked file!", \
			__LINE__, pTask->client_ip);
		return EINVAL;
	}

	get_trunk_binlog_filename(binlog_filename);
	if (stat(binlog_filename, &file_stat) != 0)
	{
		logError("file: "__FILE__", line: %d, " \
			"cmd=%d, client ip: %s, " \
			"stat trunk binlog file: %s fail, " \
			"errno: %d, error info: %s", \
			 __LINE__, pHeader->cmd, pTask->client_ip, 
			binlog_filename, errno, STRERROR(errno));
		return errno != 0 ? errno : ENOENT;
	}

	p = pTask->data + sizeof(TrackerHeader);
	long2buff(file_stat.st_size, p);

	pClientInfo->total_length = sizeof(TrackerHeader)
				 + FDFS_PROTO_PKG_LEN_SIZE;
	return 0;
}

static int storage_server_trunk_truncate_binlog_file(struct fast_task_info *pTask)
{
	StorageClientInfo *pClientInfo;
	TrackerHeader *pHeader;
	int64_t nInPackLen;

	pHeader = (TrackerHeader *)pTask->data;
	pClientInfo = (StorageClientInfo *)pTask->arg;
	nInPackLen = pClientInfo->total_length - sizeof(TrackerHeader);
	pClientInfo->total_length = sizeof (TrackerHeader);

	if (nInPackLen != 0)
	{
		logError("file: "__FILE__", line: %d, " \
			"cmd=%d, client ip: %s, package size " \
			"%"PRId64" is not correct, " \
			"expect length: 0", __LINE__, \
			pHeader->cmd, pTask->client_ip,  nInPackLen);
		return EINVAL;
	}

	if (!g_if_use_trunk_file)
	{
		logError ("file: " __FILE__ ", line: %d, "
			"client ip: %s, i don't support trunked file!", \
			__LINE__, pTask->client_ip);
		return EINVAL;
	}

	if (g_if_trunker_self)
	{
		logError("file: "__FILE__", line: %d, " \
			"client ip: %s, invalid command: %d, " \
			"because i am the TRUNK server!", \
			__LINE__, pTask->client_ip, pHeader->cmd);
		return EINVAL;
	}

	return trunk_binlog_truncate();
}

static int storage_server_trunk_delete_binlog_marks(struct fast_task_info *pTask)
{
	StorageClientInfo *pClientInfo;
	TrackerHeader *pHeader;
	int64_t nInPackLen;
	int result;

	pHeader = (TrackerHeader *)pTask->data;
	pClientInfo = (StorageClientInfo *)pTask->arg;
	nInPackLen = pClientInfo->total_length - sizeof(TrackerHeader);
	pClientInfo->total_length = sizeof (TrackerHeader);

	if (nInPackLen != 0)
	{
		logError("file: "__FILE__", line: %d, " \
			"cmd=%d, client ip: %s, package size " \
			"%"PRId64" is not correct, " \
			"expect length: 0", __LINE__, \
			pHeader->cmd, pTask->client_ip,  nInPackLen);
		return EINVAL;
	}

	if (!g_if_use_trunk_file)
	{
		logError ("file: " __FILE__ ", line: %d, "
			"client ip: %s, i don't support trunked file!", \
			__LINE__, pTask->client_ip);
		return EINVAL;
	}

	if (g_if_trunker_self)
	{
		logError("file: "__FILE__", line: %d, " \
			"client ip: %s, invalid command: %d, " \
			"because i am the TRUNK server!", \
			__LINE__, pTask->client_ip, pHeader->cmd);
		return EINVAL;
	}

	result = storage_delete_trunk_data_file();
	if (result != 0)
	{
		return result;
	}

	return trunk_unlink_all_mark_files();
}

/**
request package format:
  FDFS_GROUP_NAME_MAX_LEN bytes: group_name
  1 byte: store_path_index
  1 byte: sub_path_high
  1 byte: sub_path_low
  4 bytes: trunk file id
  4 bytes: trunk offset
  4 bytes: trunk size
**/
static int storage_server_trunk_confirm_or_free(struct fast_task_info *pTask)
{
	StorageClientInfo *pClientInfo;
	TrackerHeader *pHeader;
	FDFSTrunkInfoBuff *pTrunkBuff;
	char *in_buff;
	char group_name[FDFS_GROUP_NAME_MAX_LEN + 1];
	FDFSTrunkFullInfo trunkInfo;
	int64_t nInPackLen;

	pHeader = (TrackerHeader *)pTask->data;
	pClientInfo = (StorageClientInfo *)pTask->arg;
	nInPackLen = pClientInfo->total_length - sizeof(TrackerHeader);
	pClientInfo->total_length = sizeof(TrackerHeader);

	CHECK_TRUNK_SERVER(pTask)

	if (nInPackLen != STORAGE_TRUNK_ALLOC_CONFIRM_REQ_BODY_LEN)
	{
		logError("file: "__FILE__", line: %d, " \
			"cmd=%d, client ip: %s, package size " \
			"%"PRId64" is not correct, " \
			"expect length: %d", __LINE__, \
			pHeader->cmd, pTask->client_ip,  nInPackLen, \
			(int)STORAGE_TRUNK_ALLOC_CONFIRM_REQ_BODY_LEN);
		return EINVAL;
	}

	in_buff = pTask->data + sizeof(TrackerHeader);
	memcpy(group_name, in_buff, FDFS_GROUP_NAME_MAX_LEN);
	*(group_name + FDFS_GROUP_NAME_MAX_LEN) = '\0';
	if (strcmp(group_name, g_group_name) != 0)
	{
		logError("file: "__FILE__", line: %d, " \
			"client ip:%s, group_name: %s " \
			"not correct, should be: %s", \
			__LINE__, pTask->client_ip, \
			group_name, g_group_name);
		return EINVAL;
	}

	pTrunkBuff = (FDFSTrunkInfoBuff *)(in_buff + FDFS_GROUP_NAME_MAX_LEN);
	trunkInfo.path.store_path_index = pTrunkBuff->store_path_index;
	trunkInfo.path.sub_path_high = pTrunkBuff->sub_path_high;
	trunkInfo.path.sub_path_low = pTrunkBuff->sub_path_low;
	trunkInfo.file.id = buff2int(pTrunkBuff->id);
	trunkInfo.file.offset = buff2int(pTrunkBuff->offset);
	trunkInfo.file.size = buff2int(pTrunkBuff->size);

    if (trunkInfo.path.store_path_index < 0 ||
            trunkInfo.path.store_path_index >= g_fdfs_store_paths.count)
    {
		logError("file: "__FILE__", line: %d, " \
			"client ip: %s, store_path_index: %d " \
			"is invalid", __LINE__, \
			pTask->client_ip, trunkInfo.path.store_path_index);
		return EINVAL;
    }

	if (pHeader->cmd == STORAGE_PROTO_CMD_TRUNK_ALLOC_CONFIRM)
	{
		return trunk_alloc_confirm(&trunkInfo, pHeader->status);
	}
	else
	{
		return trunk_free_space(&trunkInfo, true);
	}
}

static int storage_server_fetch_one_path_binlog_dealer(
		struct fast_task_info *pTask)
{
#define STORAGE_LAST_AHEAD_BYTES   (2 * FDFS_PROTO_PKG_LEN_SIZE)

	StorageClientInfo *pClientInfo;
	StorageFileContext *pFileContext;
	StorageBinLogReader *pReader;
	char *pOutBuff;
	char *pBasePath;
	int result;
	int record_len;
	int len;
	int store_path_index;
	struct stat stat_buf;
	char diskLogicPath[16];
	char full_filename[MAX_PATH_SIZE];
	char src_filename[MAX_PATH_SIZE];
	bool bLast;
	StorageBinLogRecord record;
	int64_t pkg_len;

	pClientInfo = (StorageClientInfo *)pTask->arg;
	if (pClientInfo->total_length - pClientInfo->total_offset <=
		STORAGE_LAST_AHEAD_BYTES)  //finished, close the connection
	{
		sf_nio_notify(pTask, SF_NIO_STAGE_CLOSE);
		return 0;
	}

	pFileContext =  &(pClientInfo->file_context);
	pReader = (StorageBinLogReader *)pClientInfo->extra_arg;

	store_path_index = pFileContext->extra_info.upload.trunk_info.
				path.store_path_index;
	pBasePath = g_fdfs_store_paths.paths[store_path_index].path;
	pOutBuff = pTask->data;

	bLast = false;
	sprintf(diskLogicPath, "%c"FDFS_STORAGE_DATA_DIR_FORMAT,
		FDFS_STORAGE_STORE_PATH_PREFIX_CHAR, store_path_index);

	do
	{
		result = storage_binlog_read(pReader, &record, &record_len);
		if (result == ENOENT)  //no binlog record
		{
			bLast = true;
			result = 0;
			break;
		}
		else if (result != 0)
		{
			break;
		}

		if (g_fdfs_store_paths.paths[record.store_path_index].
                path != pBasePath)
		{
			continue;
		}

		if (!(record.op_type == STORAGE_OP_TYPE_SOURCE_CREATE_FILE
		   || record.op_type == STORAGE_OP_TYPE_REPLICA_CREATE_FILE
		   || record.op_type == STORAGE_OP_TYPE_SOURCE_CREATE_LINK
		   || record.op_type == STORAGE_OP_TYPE_REPLICA_CREATE_LINK
		   || record.op_type == STORAGE_OP_TYPE_SOURCE_RENAME_FILE
		   || record.op_type == STORAGE_OP_TYPE_REPLICA_RENAME_FILE))
		{
			continue;
		}

		if (fdfs_is_trunk_file(record.filename, record.filename_len))
		{
		if (record.op_type == STORAGE_OP_TYPE_SOURCE_CREATE_LINK)
		{
			record.op_type = STORAGE_OP_TYPE_SOURCE_CREATE_FILE;
		}
		else if (record.op_type == STORAGE_OP_TYPE_REPLICA_CREATE_LINK)
		{
			record.op_type = STORAGE_OP_TYPE_REPLICA_CREATE_FILE;
		}
		}
		else
		{
		snprintf(full_filename, sizeof(full_filename), "%s/data/%s",
			g_fdfs_store_paths.paths[record.store_path_index].path,
			record.true_filename);
		if (lstat(full_filename, &stat_buf) != 0)
		{
			if (errno == ENOENT)
			{
				continue;
			}
			else
			{
				logError("file: "__FILE__", line: %d, "
					"call stat fail, file: %s, "
					"error no: %d, error info: %s",
					__LINE__, full_filename,
					errno, STRERROR(errno));
				result = errno != 0 ? errno : EPERM;
				break;
			}
		}

		if (S_ISLNK(stat_buf.st_mode))
		{
			if (record.op_type == STORAGE_OP_TYPE_SOURCE_CREATE_FILE
		 	|| record.op_type == STORAGE_OP_TYPE_REPLICA_CREATE_FILE)
			{
				logWarning("file: "__FILE__", line: %d, " \
					"regular file %s change to symbol " \
					"link file, some mistake happen?", \
					__LINE__, full_filename);
			if (record.op_type == STORAGE_OP_TYPE_SOURCE_CREATE_FILE)
			{
			record.op_type = STORAGE_OP_TYPE_SOURCE_CREATE_LINK;
			}
			else
			{
			record.op_type = STORAGE_OP_TYPE_REPLICA_CREATE_LINK;
			}
			}
		}
		else
		{
			if (record.op_type == STORAGE_OP_TYPE_SOURCE_CREATE_LINK 
		 	|| record.op_type == STORAGE_OP_TYPE_REPLICA_CREATE_LINK)
			{
				logWarning("file: "__FILE__", line: %d, " \
					"symbol link file %s change to " \
					"regular file, some mistake happen?", \
					__LINE__, full_filename);
			if (record.op_type == STORAGE_OP_TYPE_SOURCE_CREATE_LINK)
			{
			record.op_type = STORAGE_OP_TYPE_SOURCE_CREATE_FILE;
			}
			else
			{
			record.op_type = STORAGE_OP_TYPE_REPLICA_CREATE_FILE;
			}
			}
		}
		}

		if (record.op_type == STORAGE_OP_TYPE_SOURCE_RENAME_FILE)
        {
            record.op_type = STORAGE_OP_TYPE_SOURCE_CREATE_FILE;
        }
        else if (record.op_type == STORAGE_OP_TYPE_REPLICA_RENAME_FILE)
        {
            record.op_type = STORAGE_OP_TYPE_REPLICA_CREATE_FILE;
        }

		if (record.op_type == STORAGE_OP_TYPE_SOURCE_CREATE_FILE
		 || record.op_type == STORAGE_OP_TYPE_REPLICA_CREATE_FILE)
		{
			pOutBuff += sprintf(pOutBuff, "%d %c %s\n",
					(int)record.timestamp,
					record.op_type, record.filename);
		}
		else
		{
			if ((len=readlink(full_filename, src_filename, \
					sizeof(src_filename))) < 0)
			{
				result = errno != 0 ? errno : EPERM;
				logError("file: "__FILE__", line: %d, " \
					"client ip: %s, call readlink file " \
					"%s fail, errno: %d, error info: %s", \
					__LINE__, pTask->client_ip, \
					full_filename, result, STRERROR(result));

				if (result == ENOENT)
				{
					continue;
				}
				break;
			}

			if (len <= g_fdfs_store_paths.paths[store_path_index].path_len)
			{
				logWarning("file: "__FILE__", line: %d, " \
					"invalid symbol link file: %s, " \
					"maybe not create by FastDFS?", \
					__LINE__, full_filename);
				continue;
			}
			*(src_filename + len) = '\0';
			if (!fileExists(src_filename))
			{
				logWarning("file: "__FILE__", line: %d, " \
					"client ip: %s, symbol link file: %s, "\
					"it's source file: %s not exist", \
					__LINE__, pTask->client_ip, \
					full_filename, src_filename);
				continue;
			}

			//full filename format: ${base_path}/data/filename
			pOutBuff += sprintf(pOutBuff, "%d %c %s %s/%s\n",
					(int)record.timestamp,
					record.op_type, record.filename,
					diskLogicPath, src_filename + g_fdfs_store_paths.
                    paths[store_path_index].path_len + 6);
		}

		if (pTask->size - (pOutBuff - pTask->data) <
			STORAGE_BINLOG_LINE_SIZE + FDFS_PROTO_PKG_LEN_SIZE)
		{
			break;
		}
	} while (SF_G_CONTINUE_FLAG);

    if (!SF_G_CONTINUE_FLAG)
    {
        if (result == 0)
        {
            result = EINTR;
        }
    }

	if (result != 0) //error occurs
	{
		sf_nio_notify(pTask, SF_NIO_STAGE_CLOSE);
		return result;
	}

	pTask->length = pOutBuff - pTask->data;
	if (bLast)
	{
		pkg_len = pClientInfo->total_offset + pTask->length -
				sizeof(TrackerHeader);
		long2buff(pkg_len, pOutBuff);

		pTask->length += FDFS_PROTO_PKG_LEN_SIZE;
		pClientInfo->total_length = pkg_len + FDFS_PROTO_PKG_LEN_SIZE
						+ STORAGE_LAST_AHEAD_BYTES;
	}

	sf_nio_notify(pTask, SF_NIO_STAGE_SEND);
	return 0;
}

static void fetch_one_path_binlog_finish_clean_up(struct fast_task_info *pTask)
{
	StorageClientInfo *pClientInfo;
	StorageFileContext *pFileContext;
	StorageBinLogReader *pReader;

	pClientInfo = (StorageClientInfo *)pTask->arg;
	pReader = (StorageBinLogReader *)pClientInfo->extra_arg;
	if (pReader == NULL)
	{
		return;
	}

	pClientInfo->extra_arg = NULL;

    storage_reader_remove_from_list(pReader);
	get_mark_filename_by_reader(pReader);
	if (fileExists(pReader->mark_filename))
	{
		unlink(pReader->mark_filename);
	}

	pFileContext =  &(pClientInfo->file_context);
    logInfo("file: "__FILE__", line: %d, "
            "client ip: %s, fetch binlog of store path #%d done",
            __LINE__, pTask->client_ip, pFileContext->extra_info.
            upload.trunk_info.path.store_path_index);

	storage_reader_destroy(pReader);
	free(pReader);
}

static int storage_server_do_fetch_one_path_binlog(
		struct fast_task_info *pTask, const int store_path_index)
{
	StorageClientInfo *pClientInfo;
	StorageFileContext *pFileContext;
	StorageBinLogReader *pReader;
	TrackerHeader *pHeader;
	int result;

	pReader = (StorageBinLogReader *)malloc(sizeof(StorageBinLogReader));
	if (pReader == NULL)
	{
		logError("file: "__FILE__", line: %d, " \
			"malloc %d bytes fail, errno: %d, error info: %s", \
			__LINE__, (int)sizeof(StorageBinLogReader),
			errno, STRERROR(errno));
		return errno != 0 ? errno : ENOMEM;
	}

    logInfo("file: "__FILE__", line: %d, "
            "client ip: %s, fetch binlog of store path #%d ...",
            __LINE__, pTask->client_ip, store_path_index);

	pClientInfo = (StorageClientInfo *)pTask->arg;
	pFileContext =  &(pClientInfo->file_context);

	if ((result=storage_reader_init(NULL, pReader)) != 0)
	{
		storage_reader_destroy(pReader);
        free(pReader);
		return result;
	}
    storage_reader_add_to_list(pReader);

	pClientInfo->deal_func = storage_server_fetch_one_path_binlog_dealer;
	pClientInfo->clean_func = fetch_one_path_binlog_finish_clean_up;

	pFileContext->fd = -1;
	pFileContext->op = FDFS_STORAGE_FILE_OP_READ;
	pFileContext->dio_thread_index = storage_dio_get_thread_index(
		pTask, store_path_index, pFileContext->op);
	pFileContext->extra_info.upload.trunk_info.path.store_path_index = 
				store_path_index;
	pClientInfo->extra_arg = pReader;

	pClientInfo->total_length = INFINITE_FILE_SIZE +
					sizeof(TrackerHeader);
	pClientInfo->total_offset = 0;
	pTask->length = sizeof(TrackerHeader);
	pHeader = (TrackerHeader *)pTask->data;
	pHeader->status = 0;
	pHeader->cmd = STORAGE_PROTO_CMD_RESP;
	long2buff(pClientInfo->total_length - sizeof(TrackerHeader),
			pHeader->pkg_len);

	sf_nio_notify(pTask, SF_NIO_STAGE_SEND);
	return TASK_STATUS_CONTINUE;
}

/**
FDFS_GROUP_NAME_MAX_LEN bytes: group_name
1 byte: store path index
**/
static int storage_server_fetch_one_path_binlog(struct fast_task_info *pTask)
{
	StorageClientInfo *pClientInfo;
	char *in_buff;
	char group_name[FDFS_GROUP_NAME_MAX_LEN + 1];
	int store_path_index;
	int64_t nInPackLen;

	pClientInfo = (StorageClientInfo *)pTask->arg;
	nInPackLen = pClientInfo->total_length - sizeof(TrackerHeader);
	pClientInfo->total_length = sizeof(TrackerHeader);
	if (nInPackLen != FDFS_GROUP_NAME_MAX_LEN + 1)
	{
		logError("file: "__FILE__", line: %d, " \
			"cmd=%d, client ip: %s, package size " \
			"%"PRId64" is not correct, " \
			"expect length = %d", __LINE__, \
			STORAGE_PROTO_CMD_FETCH_ONE_PATH_BINLOG, \
			pTask->client_ip,  \
			nInPackLen, FDFS_GROUP_NAME_MAX_LEN + 1);
		return EINVAL;
	}

	in_buff = pTask->data + sizeof(TrackerHeader);
	memcpy(group_name, in_buff, FDFS_GROUP_NAME_MAX_LEN);
	*(group_name + FDFS_GROUP_NAME_MAX_LEN) = '\0';
	if (strcmp(group_name, g_group_name) != 0)
	{
		logError("file: "__FILE__", line: %d, " \
			"client ip:%s, group_name: %s " \
			"not correct, should be: %s", \
			__LINE__, pTask->client_ip, \
			group_name, g_group_name);
		return EINVAL;
	}

	store_path_index = *(in_buff + FDFS_GROUP_NAME_MAX_LEN);
	if (store_path_index < 0 || store_path_index >= g_fdfs_store_paths.count)
	{
		logError("file: "__FILE__", line: %d, " \
			"client ip: %s, store_path_index: %d " \
			"is invalid", __LINE__, \
			pTask->client_ip, store_path_index);
		return EINVAL;
	}

	return storage_server_do_fetch_one_path_binlog(
			pTask, store_path_index);
}

/**
1 byte: store path index
8 bytes: file size 
FDFS_FILE_EXT_NAME_MAX_LEN bytes: file ext name, do not include dot (.)
file size bytes: file content
**/
static int storage_upload_file(struct fast_task_info *pTask, bool bAppenderFile)
{
	StorageClientInfo *pClientInfo;
	StorageFileContext *pFileContext;
	DisconnectCleanFunc clean_func;
	char *p;
	char filename[128];
	char file_ext_name[FDFS_FILE_PREFIX_MAX_LEN + 1];
	int64_t nInPackLen;
	int64_t file_offset;
	int64_t file_bytes;
	int crc32;
	int store_path_index;
	int result;
	int filename_len;

	pClientInfo = (StorageClientInfo *)pTask->arg;
	pFileContext =  &(pClientInfo->file_context);
	nInPackLen = pClientInfo->total_length - sizeof(TrackerHeader);
	if (nInPackLen < 1 + FDFS_PROTO_PKG_LEN_SIZE + 
			FDFS_FILE_EXT_NAME_MAX_LEN)
	{
		logError("file: "__FILE__", line: %d, " \
			"cmd=%d, client ip: %s, package size " \
			"%"PRId64" is not correct, " \
			"expect length >= %d", __LINE__, \
			STORAGE_PROTO_CMD_UPLOAD_FILE, \
			pTask->client_ip,  nInPackLen, \
			1 + FDFS_PROTO_PKG_LEN_SIZE + \
			FDFS_FILE_EXT_NAME_MAX_LEN);
		return EINVAL;
	}

	p = pTask->data + sizeof(TrackerHeader);
	store_path_index = *p++;

	if (store_path_index == -1)
	{
		if ((result=storage_get_storage_path_index( \
			&store_path_index)) != 0)
		{
			logError("file: "__FILE__", line: %d, " \
				"get_storage_path_index fail, " \
				"errno: %d, error info: %s", __LINE__, \
				result, STRERROR(result));
			return result;
		}
	}
	else if (store_path_index < 0 || store_path_index >= \
		g_fdfs_store_paths.count)
	{
		logError("file: "__FILE__", line: %d, " \
			"client ip: %s, store_path_index: %d " \
			"is invalid", __LINE__, \
			pTask->client_ip, store_path_index);
		return EINVAL;
	}

	file_bytes = buff2long(p);
	p += FDFS_PROTO_PKG_LEN_SIZE;
	if (file_bytes < 0 || file_bytes != nInPackLen - \
			(1 + FDFS_PROTO_PKG_LEN_SIZE + \
			 FDFS_FILE_EXT_NAME_MAX_LEN))
	{
		logError("file: "__FILE__", line: %d, " \
			"client ip: %s, pkg length is not correct, " \
			"invalid file bytes: %"PRId64 \
			", total body length: %"PRId64, \
			__LINE__, pTask->client_ip, file_bytes, nInPackLen);
		return EINVAL;
	}

	memcpy(file_ext_name, p, FDFS_FILE_EXT_NAME_MAX_LEN);
	*(file_ext_name + FDFS_FILE_EXT_NAME_MAX_LEN) = '\0';
	p += FDFS_FILE_EXT_NAME_MAX_LEN;
	if ((result=fdfs_validate_filename(file_ext_name)) != 0)
	{
		logError("file: "__FILE__", line: %d, " \
			"client ip: %s, file_ext_name: %s " \
			"is invalid!", __LINE__, \
			pTask->client_ip, file_ext_name);
		return result;
	}

	pFileContext->calc_crc32 = true;
	pFileContext->calc_file_hash = g_check_file_duplicate;
	pFileContext->extra_info.upload.start_time = g_current_time;

	strcpy(pFileContext->extra_info.upload.file_ext_name, file_ext_name);
	storage_format_ext_name(file_ext_name, \
			pFileContext->extra_info.upload.formatted_ext_name);
	pFileContext->extra_info.upload.trunk_info.path. \
				store_path_index = store_path_index;
	pFileContext->extra_info.upload.file_type = _FILE_TYPE_REGULAR;
	pFileContext->sync_flag = STORAGE_OP_TYPE_SOURCE_CREATE_FILE;
	pFileContext->timestamp2log = pFileContext->extra_info.upload.start_time;
	pFileContext->op = FDFS_STORAGE_FILE_OP_WRITE;
	if (bAppenderFile)
	{
		pFileContext->extra_info.upload.file_type |= \
					_FILE_TYPE_APPENDER;
	}
	else
	{
		if (g_if_use_trunk_file && trunk_check_size( \
			TRUNK_CALC_SIZE(file_bytes)))
		{
			pFileContext->extra_info.upload.file_type |= \
						_FILE_TYPE_TRUNK;
		}
	}

	if (pFileContext->extra_info.upload.file_type & _FILE_TYPE_TRUNK)
	{
		FDFSTrunkFullInfo *pTrunkInfo;

		pFileContext->extra_info.upload.if_sub_path_alloced = true;
		pTrunkInfo = &(pFileContext->extra_info.upload.trunk_info);
		if ((result=trunk_client_trunk_alloc_space( \
			TRUNK_CALC_SIZE(file_bytes), pTrunkInfo)) != 0)
		{
			return result;
		}

		clean_func = dio_trunk_write_finish_clean_up;
		file_offset = TRUNK_FILE_START_OFFSET((*pTrunkInfo));
        pFileContext->extra_info.upload.if_gen_filename = true;
		trunk_get_full_filename(pTrunkInfo, pFileContext->filename, \
				sizeof(pFileContext->filename));
		pFileContext->extra_info.upload.before_open_callback = \
					dio_check_trunk_file_when_upload;
		pFileContext->extra_info.upload.before_close_callback = \
					dio_write_chunk_header;
		pFileContext->open_flags = O_RDWR | g_extra_open_file_flags;
	}
	else
	{
		char reserved_space_str[32];

		if (!storage_check_reserved_space_path(g_fdfs_store_paths.paths \
			[store_path_index].total_mb, g_fdfs_store_paths.paths \
			[store_path_index].free_mb - (file_bytes/FDFS_ONE_MB), \
			g_avg_storage_reserved_mb))
		{
			logError("file: "__FILE__", line: %d, " \
				"no space to upload file, "
				"free space: %"PRId64" MB is too small, file bytes: " \
				"%"PRId64", reserved space: %s", \
				__LINE__, g_fdfs_store_paths.paths[store_path_index].\
				free_mb, file_bytes, \
				fdfs_storage_reserved_space_to_string_ex( \
				  g_storage_reserved_space.flag, \
          g_avg_storage_reserved_mb, \
				  g_fdfs_store_paths.paths[store_path_index]. \
				  total_mb, g_storage_reserved_space.rs.ratio,\
				  reserved_space_str));
			return ENOSPC;
		}

		crc32 = rand();
		*filename = '\0';
		filename_len = 0;
		pFileContext->extra_info.upload.if_sub_path_alloced = false;
		if ((result=storage_get_filename(pClientInfo, \
			pFileContext->extra_info.upload.start_time, \
			file_bytes, crc32, pFileContext->extra_info.upload.\
			formatted_ext_name, filename, &filename_len, \
			pFileContext->filename)) != 0)
		{
			return result;
		}

		clean_func = dio_write_finish_clean_up;
		file_offset = 0;
        pFileContext->extra_info.upload.if_gen_filename = true;
		pFileContext->extra_info.upload.before_open_callback = NULL;
		pFileContext->extra_info.upload.before_close_callback = NULL;
		pFileContext->open_flags = O_WRONLY | O_CREAT | O_TRUNC \
						| g_extra_open_file_flags;
	}

    pFileContext->continue_callback = storage_nio_notify;
    return storage_write_to_file(pTask, file_offset, file_bytes, \
            p - pTask->data, dio_write_file, \
			storage_upload_file_done_callback, \
			clean_func, store_path_index);
}

static int storage_deal_active_test(struct fast_task_info *pTask)
{
	StorageClientInfo *pClientInfo;
	int64_t nInPackLen;

	pClientInfo = (StorageClientInfo *)pTask->arg;
	nInPackLen = pClientInfo->total_length - sizeof(TrackerHeader);
	pClientInfo->total_length = sizeof(TrackerHeader);
	if (nInPackLen != 0)
	{
		logError("file: "__FILE__", line: %d, " \
			"cmd=%d, client ip: %s, package size " \
			"%"PRId64" is not correct, " \
			"expect length 0", __LINE__, \
			FDFS_PROTO_CMD_ACTIVE_TEST, pTask->client_ip, \
			nInPackLen);
		return EINVAL;
	}

	return 0;
}

static int storage_server_check_appender_file(struct fast_task_info *pTask,
        char *appender_filename, const int appender_filename_len,
        char *true_filename, struct stat *stat_buf, int *store_path_index)
{
	StorageFileContext *pFileContext;
	char decode_buff[64];
	int result;
	int filename_len;
	int buff_len;
	int64_t appender_file_size;

	pFileContext =  &(((StorageClientInfo *)pTask->arg)->file_context);
    filename_len = appender_filename_len;
    if ((result=storage_split_filename_ex(appender_filename,
		&filename_len, true_filename, store_path_index)) != 0)
	{
		return result;
	}
	if ((result=fdfs_check_data_filename(true_filename, filename_len)) != 0)
	{
		return result;
	}

	snprintf(pFileContext->filename, sizeof(pFileContext->filename),
            "%s/data/%s", g_fdfs_store_paths.paths[*store_path_index].path,
            true_filename);
	if (lstat(pFileContext->filename, stat_buf) == 0)
	{
		if (!S_ISREG(stat_buf->st_mode))
		{
			logError("file: "__FILE__", line: %d, "
				"client ip: %s, appender file: %s "
				"is not a regular file", __LINE__,
				pTask->client_ip, pFileContext->filename);

			return EINVAL;
		}
	}
	else
	{
		result = errno != 0 ? errno : ENOENT;
		if (result == ENOENT)
		{
			logWarning("file: "__FILE__", line: %d, "
				"client ip: %s, appender file: %s "
				"not exist", __LINE__, pTask->client_ip,
                pFileContext->filename);
		}
		else
		{
			logError("file: "__FILE__", line: %d, "
				"client ip: %s, stat appednder file %s fail, "
				"errno: %d, error info: %s",
				__LINE__, pTask->client_ip,
				pFileContext->filename, result, STRERROR(result));
		}

		return result;
	}

	strcpy(pFileContext->fname2log, appender_filename);

	memset(decode_buff, 0, sizeof(decode_buff));
	base64_decode_auto(&g_fdfs_base64_context, pFileContext->fname2log +
		FDFS_LOGIC_FILE_PATH_LEN, FDFS_FILENAME_BASE64_LENGTH,
		decode_buff, &buff_len);

	appender_file_size = buff2long(decode_buff + sizeof(int) * 2);
	if (!IS_APPENDER_FILE(appender_file_size))
	{
		logError("file: "__FILE__", line: %d, "
			"client ip: %s, file: %s is not a valid "
			"appender file, file size: %"PRId64,
			__LINE__, pTask->client_ip, appender_filename,
			appender_file_size);

		return EINVAL;
	}

    return 0;
}

static void calc_crc32_done_callback_for_regenerate(
        struct fast_task_info *pTask, const int err_no)
{
	StorageClientInfo *pClientInfo;
    StorageFileInfoForCRC32 *crc32_file_info;
	StorageFileContext *pFileContext;
	TrackerHeader *pHeader;
    char full_filename[MAX_PATH_SIZE + 128];
	int result;

	pClientInfo = (StorageClientInfo *)pTask->arg;
	pFileContext =  &(pClientInfo->file_context);
    crc32_file_info = (StorageFileInfoForCRC32 *)pClientInfo->extra_arg;
	pHeader = (TrackerHeader *)pTask->data;

	if (err_no == 0)
    {
        char *formatted_ext_name;
        char return_filename[128];
        char filename[128];
        int filename_len;

        *filename = '\0';
        filename_len = 0;
        formatted_ext_name = pFileContext->filename +
            (strlen(pFileContext->filename) -
            (FDFS_FILE_EXT_NAME_MAX_LEN + 1));

        pFileContext->timestamp2log = g_current_time;
        if ((result=storage_get_filename(pClientInfo,
                        pFileContext->timestamp2log,
                        crc32_file_info->fsize, pFileContext->crc32,
                        formatted_ext_name, filename, &filename_len,
                        full_filename)) == 0)
        {
            if (*full_filename == '\0')
            {
                result = EBUSY;
                logWarning("file: "__FILE__", line: %d, "
                        "Can't generate uniq filename", __LINE__);
            }
            else
            {
                if (rename(pFileContext->filename, full_filename) != 0)
                {
                    result = errno != 0 ? errno : EPERM;
                    logWarning("file: "__FILE__", line: %d, "
                            "rename %s to %s fail, "
                            "errno: %d, error info: %s", __LINE__,
                            pFileContext->filename, full_filename,
                            result, STRERROR(result));
                }
                else
                {
                    char *p;
                    char binlog_msg[256];

                    filename_len = snprintf(return_filename,
                            sizeof(return_filename),
                            "%c"FDFS_STORAGE_DATA_DIR_FORMAT"/%s",
                            FDFS_STORAGE_STORE_PATH_PREFIX_CHAR,
                            pFileContext->extra_info.upload.trunk_info.
                            path.store_path_index, filename);

                    sprintf(binlog_msg, "%s %s",
                            return_filename, pFileContext->fname2log);
                    result = storage_binlog_write(
                            pFileContext->timestamp2log,
                            STORAGE_OP_TYPE_SOURCE_RENAME_FILE,
                            binlog_msg);

                    pClientInfo->total_length = sizeof(TrackerHeader) +
                        FDFS_GROUP_NAME_MAX_LEN + filename_len;
                    p = pTask->data + sizeof(TrackerHeader);
                    memcpy(p, g_group_name, FDFS_GROUP_NAME_MAX_LEN);
                    p += FDFS_GROUP_NAME_MAX_LEN;
                    memcpy(p, return_filename, filename_len);

                    if (g_use_access_log)
                    {
                        snprintf(pFileContext->fname2log +
                                strlen(pFileContext->fname2log),
                                sizeof(pFileContext->fname2log),
                                "=>%s", return_filename);
                    }
                }
            }
        }
    }
	else
	{
		result = err_no;
	}

    fast_mblock_free_object(&finfo_for_crc32_allocator, crc32_file_info);
    if (result != 0)
    {
        pClientInfo->total_length = sizeof(TrackerHeader);
    }

	pClientInfo->total_offset = 0;
	pTask->length = pClientInfo->total_length;

	pHeader->status = result;
	pHeader->cmd = STORAGE_PROTO_CMD_RESP;
	long2buff(pTask->length - sizeof(TrackerHeader), pHeader->pkg_len);

    STORAGE_ACCESS_LOG(pTask, ACCESS_LOG_ACTION_RENAME_FILE, result);
	sf_nio_notify(pTask, SF_NIO_STAGE_SEND);
}

/**
body length: appender filename
**/
static int storage_server_regenerate_appender_filename(struct fast_task_info *pTask)
{
	StorageClientInfo *pClientInfo;
	StorageFileContext *pFileContext;
    FDFSTrunkFullInfo *pTrunkInfo;
	char *p;
	char appender_filename[128];
	char true_filename[128];
	struct stat stat_buf;
	int appender_filename_len;
	int64_t nInPackLen;
	int result;
	int store_path_index;

	pClientInfo = (StorageClientInfo *)pTask->arg;
	pFileContext =  &(pClientInfo->file_context);

	nInPackLen = pClientInfo->total_length - sizeof(TrackerHeader);
    appender_filename_len = nInPackLen;
	if ((nInPackLen < FDFS_LOGIC_FILE_PATH_LEN + FDFS_FILENAME_BASE64_LENGTH +
            FDFS_FILE_EXT_NAME_MAX_LEN + 1)
		|| (appender_filename_len >= sizeof(appender_filename)))
	{
		logError("file: "__FILE__", line: %d, " 
			"client ip: %s, invalid package length: %"PRId64,
            __LINE__, pTask->client_ip, nInPackLen);
		return EINVAL;
	}

	p = pTask->data + sizeof(TrackerHeader);
	memcpy(appender_filename, p, appender_filename_len);
	*(appender_filename + appender_filename_len) = '\0';

	STORAGE_ACCESS_STRCPY_FNAME2LOG(appender_filename,
			appender_filename_len, pClientInfo);

    if ((result=storage_server_check_appender_file(pTask,
                    appender_filename, appender_filename_len,
                    true_filename, &stat_buf, &store_path_index)) != 0)
    {
        return result;
    }

    pTrunkInfo = &(pClientInfo->file_context.extra_info.upload.trunk_info);
    pClientInfo->file_context.extra_info.upload.if_sub_path_alloced = true;
    pFileContext->extra_info.upload.trunk_info.path.store_path_index =
        store_path_index;
    pTrunkInfo->path.sub_path_high = strtol(true_filename, NULL, 16);
    pTrunkInfo->path.sub_path_low = strtol(true_filename + 3, NULL, 16);

    return push_calc_crc32_to_dio_queue(pTask,
            calc_crc32_done_callback_for_regenerate,
            store_path_index, &stat_buf,
            g_server_id_in_filename);
}

/**
8 bytes: appender filename length
8 bytes: file size
appender filename bytes: appender filename
file size bytes: file content
**/
static int storage_append_file(struct fast_task_info *pTask)
{
	StorageClientInfo *pClientInfo;
	StorageFileContext *pFileContext;
	char *p;
	char appender_filename[128];
	char true_filename[128];
	struct stat stat_buf;
	int appender_filename_len;
	int64_t nInPackLen;
	int64_t file_bytes;
	int result;
	int store_path_index;

	pClientInfo = (StorageClientInfo *)pTask->arg;
	pFileContext =  &(pClientInfo->file_context);

	nInPackLen = pClientInfo->total_length - sizeof(TrackerHeader);
	if (nInPackLen <= 2 * FDFS_PROTO_PKG_LEN_SIZE)
	{
		logError("file: "__FILE__", line: %d, " \
			"cmd=%d, client ip: %s, package size " \
			"%"PRId64" is not correct, " \
			"expect length > %d", __LINE__, \
			STORAGE_PROTO_CMD_APPEND_FILE, \
			pTask->client_ip,  \
			nInPackLen, 2 * FDFS_PROTO_PKG_LEN_SIZE);
		return EINVAL;
	}

	p = pTask->data + sizeof(TrackerHeader);

	appender_filename_len = buff2long(p);
	p += FDFS_PROTO_PKG_LEN_SIZE;
	file_bytes = buff2long(p);
	p += FDFS_PROTO_PKG_LEN_SIZE;
	if (appender_filename_len < FDFS_LOGIC_FILE_PATH_LEN + \
		FDFS_FILENAME_BASE64_LENGTH + FDFS_FILE_EXT_NAME_MAX_LEN + 1 \
		|| appender_filename_len >= sizeof(appender_filename))
	{
		logError("file: "__FILE__", line: %d, " \
			"client ip:%s, invalid appender_filename " \
			"bytes: %d", __LINE__, \
			pTask->client_ip, appender_filename_len);
		return EINVAL;
	}

	if (file_bytes < 0 || file_bytes != nInPackLen - \
		(2 * FDFS_PROTO_PKG_LEN_SIZE + appender_filename_len))
	{
		logError("file: "__FILE__", line: %d, " \
			"client ip: %s, pkg length is not correct, " \
			"invalid file bytes: %"PRId64, \
			__LINE__, pTask->client_ip, file_bytes);
		return EINVAL;
	}

	memcpy(appender_filename, p, appender_filename_len);
	*(appender_filename + appender_filename_len) = '\0';
	p += appender_filename_len;

	STORAGE_ACCESS_STRCPY_FNAME2LOG(appender_filename,
			appender_filename_len, pClientInfo);

    if ((result=storage_server_check_appender_file(pTask,
                    appender_filename, appender_filename_len,
                    true_filename, &stat_buf, &store_path_index)) != 0)
    {
        return result;
    }

	if (file_bytes == 0)
	{
		return 0;
	}

	pFileContext->extra_info.upload.start_time = g_current_time;
	pFileContext->extra_info.upload.if_gen_filename = false;

	pFileContext->calc_crc32 = false;
	pFileContext->calc_file_hash = false;

	pFileContext->sync_flag = STORAGE_OP_TYPE_SOURCE_APPEND_FILE;
	pFileContext->timestamp2log = pFileContext->extra_info.upload.start_time;
	pFileContext->extra_info.upload.file_type = _FILE_TYPE_APPENDER;
	pFileContext->extra_info.upload.before_open_callback = NULL;
	pFileContext->extra_info.upload.before_close_callback = NULL;
	pFileContext->extra_info.upload.trunk_info.path.store_path_index =
			store_path_index;
	pFileContext->op = FDFS_STORAGE_FILE_OP_APPEND;
	pFileContext->open_flags = O_WRONLY | O_APPEND | g_extra_open_file_flags;
    pFileContext->continue_callback = storage_nio_notify;

	return storage_write_to_file(pTask, stat_buf.st_size, file_bytes,
			p - pTask->data, dio_write_file,
			storage_append_file_done_callback,
			dio_append_finish_clean_up, store_path_index);
}

/**
8 bytes: appender filename length
8 bytes: file offset
8 bytes: file size
appender filename bytes: appender filename
file size bytes: file content
**/
static int storage_modify_file(struct fast_task_info *pTask)
{
	StorageClientInfo *pClientInfo;
	StorageFileContext *pFileContext;
	char *p;
	char appender_filename[128];
	char true_filename[128];
	struct stat stat_buf;
	int appender_filename_len;
	int64_t nInPackLen;
	int64_t file_offset;
	int64_t file_bytes;
	int result;
	int store_path_index;

	pClientInfo = (StorageClientInfo *)pTask->arg;
	pFileContext =  &(pClientInfo->file_context);

	nInPackLen = pClientInfo->total_length - sizeof(TrackerHeader);
	if (nInPackLen <= 3 * FDFS_PROTO_PKG_LEN_SIZE)
	{
		logError("file: "__FILE__", line: %d, " \
			"cmd=%d, client ip: %s, package size " \
			"%"PRId64" is not correct, " \
			"expect length > %d", __LINE__, \
			STORAGE_PROTO_CMD_MODIFY_FILE, \
			pTask->client_ip,  \
			nInPackLen, 3 * FDFS_PROTO_PKG_LEN_SIZE);
		return EINVAL;
	}

	p = pTask->data + sizeof(TrackerHeader);

	appender_filename_len = buff2long(p);
	p += FDFS_PROTO_PKG_LEN_SIZE;
	file_offset = buff2long(p);
	p += FDFS_PROTO_PKG_LEN_SIZE;
	file_bytes = buff2long(p);
	p += FDFS_PROTO_PKG_LEN_SIZE;
	if (appender_filename_len < FDFS_LOGIC_FILE_PATH_LEN + \
		FDFS_FILENAME_BASE64_LENGTH + FDFS_FILE_EXT_NAME_MAX_LEN + 1 \
		|| appender_filename_len >= sizeof(appender_filename))
	{
		logError("file: "__FILE__", line: %d, " \
			"client ip:%s, invalid appender_filename " \
			"bytes: %d", __LINE__, \
			pTask->client_ip, appender_filename_len);
		return EINVAL;
	}

	if (file_offset < 0)
	{
		logError("file: "__FILE__", line: %d, " \
			"client ip: %s, in request pkg, " \
			"file offset: %"PRId64" is invalid, "\
			"which < 0", __LINE__, pTask->client_ip, file_offset);
		return EINVAL;
	}

	if (file_bytes < 0 || file_bytes != nInPackLen - \
		(3 * FDFS_PROTO_PKG_LEN_SIZE + appender_filename_len))
	{
		logError("file: "__FILE__", line: %d, " \
			"client ip: %s, pkg length is not correct, " \
			"invalid file bytes: %"PRId64, \
			__LINE__, pTask->client_ip, file_bytes);
		return EINVAL;
	}

	memcpy(appender_filename, p, appender_filename_len);
	*(appender_filename + appender_filename_len) = '\0';
	p += appender_filename_len;

	STORAGE_ACCESS_STRCPY_FNAME2LOG(appender_filename, \
		appender_filename_len, pClientInfo);

    if ((result=storage_server_check_appender_file(pTask,
                    appender_filename, appender_filename_len,
                    true_filename, &stat_buf, &store_path_index)) != 0)
    {
        return result;
    }

	if (file_offset > stat_buf.st_size)
	{
		logError("file: "__FILE__", line: %d, "
			"client ip: %s, file offset: %"PRId64
			" is invalid, which > appender file size: %"
			PRId64, __LINE__, pTask->client_ip,
			file_offset, (int64_t)stat_buf.st_size);

		return EINVAL;
	}

	if (file_bytes == 0)
	{
		return 0;
	}

	pFileContext->extra_info.upload.start_time = g_current_time;
	pFileContext->extra_info.upload.if_gen_filename = false;

	pFileContext->calc_crc32 = false;
	pFileContext->calc_file_hash = false;

	pFileContext->sync_flag = STORAGE_OP_TYPE_SOURCE_MODIFY_FILE;
	pFileContext->timestamp2log = pFileContext->extra_info.upload.start_time;
	pFileContext->extra_info.upload.file_type = _FILE_TYPE_APPENDER;
	pFileContext->extra_info.upload.before_open_callback = NULL;
	pFileContext->extra_info.upload.before_close_callback = NULL;
	pFileContext->extra_info.upload.trunk_info.path.store_path_index =
			store_path_index;
	pFileContext->op = FDFS_STORAGE_FILE_OP_WRITE;
	pFileContext->open_flags = O_WRONLY | g_extra_open_file_flags;
    pFileContext->continue_callback = storage_nio_notify;

	return storage_write_to_file(pTask, file_offset, file_bytes,
			p - pTask->data, dio_write_file,
			storage_modify_file_done_callback,
			dio_modify_finish_clean_up, store_path_index);
}

/**
8 bytes: appender filename length
8 bytes: truncated file size
appender filename bytes: appender filename
**/
static int storage_do_truncate_file(struct fast_task_info *pTask)
{
	StorageClientInfo *pClientInfo;
	StorageFileContext *pFileContext;
	char *p;
	char appender_filename[128];
	char decode_buff[64];
	struct stat stat_buf;
	int appender_filename_len;
	int64_t nInPackLen;
	int64_t remain_bytes;
	int64_t appender_file_size;
	int result;
	int store_path_index;
	int filename_len;
	int buff_len;

	pClientInfo = (StorageClientInfo *)pTask->arg;
	pFileContext =  &(pClientInfo->file_context);

	nInPackLen = pClientInfo->total_length - sizeof(TrackerHeader);
	if (nInPackLen <= 2 * FDFS_PROTO_PKG_LEN_SIZE)
	{
		logError("file: "__FILE__", line: %d, " \
			"cmd=%d, client ip: %s, package size " \
			"%"PRId64" is not correct, " \
			"expect length > %d", __LINE__, \
			STORAGE_PROTO_CMD_TRUNCATE_FILE, \
			pTask->client_ip,  \
			nInPackLen, 2 * FDFS_PROTO_PKG_LEN_SIZE);
		return EINVAL;
	}

	p = pTask->data + sizeof(TrackerHeader);

	appender_filename_len = buff2long(p);
	p += FDFS_PROTO_PKG_LEN_SIZE;
	remain_bytes = buff2long(p);
	p += FDFS_PROTO_PKG_LEN_SIZE;
	if (appender_filename_len < FDFS_LOGIC_FILE_PATH_LEN + \
		FDFS_FILENAME_BASE64_LENGTH + FDFS_FILE_EXT_NAME_MAX_LEN + 1 \
		|| appender_filename_len >= sizeof(appender_filename))
	{
		logError("file: "__FILE__", line: %d, " \
			"client ip:%s, invalid appender_filename " \
			"bytes: %d", __LINE__, \
			pTask->client_ip, appender_filename_len);
		return EINVAL;
	}

	if (remain_bytes < 0)
	{
		logError("file: "__FILE__", line: %d, " \
			"client ip: %s, pkg length is not correct, " \
			"invalid file bytes: %"PRId64, \
			__LINE__, pTask->client_ip, remain_bytes);
		return EINVAL;
	}

	memcpy(appender_filename, p, appender_filename_len);
	*(appender_filename + appender_filename_len) = '\0';
	p += appender_filename_len;
	filename_len = appender_filename_len;

	STORAGE_ACCESS_STRCPY_FNAME2LOG(appender_filename, \
		appender_filename_len, pClientInfo);

    if ((result=storage_logic_to_local_full_filename(
                    appender_filename, filename_len,
                    &store_path_index, pFileContext->filename,
                    sizeof(pFileContext->filename))) != 0)
	{
		return result;
	}

	if (lstat(pFileContext->filename, &stat_buf) == 0)
	{
		if (!S_ISREG(stat_buf.st_mode))
		{
			logError("file: "__FILE__", line: %d, " \
				"client ip: %s, appender file: %s " \
				"is not a regular file", __LINE__, \
				pTask->client_ip, pFileContext->filename);

			return EINVAL;
		}
	}
	else
	{
		result = errno != 0 ? errno : ENOENT;
		if (result == ENOENT)
		{
			logWarning("file: "__FILE__", line: %d, " \
				"client ip: %s, appender file: %s " \
				"not exist", __LINE__, \
				pTask->client_ip, pFileContext->filename);
		}
		else
		{
			logError("file: "__FILE__", line: %d, " \
				"client ip: %s, stat appednder file %s fail" \
				", errno: %d, error info: %s.", \
				__LINE__, pTask->client_ip, \
				pFileContext->filename, \
				result, STRERROR(result));
		}

		return result;
	}

	strcpy(pFileContext->fname2log, appender_filename);

	memset(decode_buff, 0, sizeof(decode_buff));
	base64_decode_auto(&g_fdfs_base64_context, pFileContext->fname2log + \
		FDFS_LOGIC_FILE_PATH_LEN, FDFS_FILENAME_BASE64_LENGTH, \
		decode_buff, &buff_len);

	appender_file_size = buff2long(decode_buff + sizeof(int) * 2);
	if (!IS_APPENDER_FILE(appender_file_size))
	{
		logError("file: "__FILE__", line: %d, " \
			"client ip: %s, file: %s is not a valid " \
			"appender file, file size: %"PRId64, \
			__LINE__, pTask->client_ip, appender_filename, \
			appender_file_size);

		return EINVAL;
	}

	if (remain_bytes == stat_buf.st_size)
	{
		logWarning("file: "__FILE__", line: %d, " \
			"client ip: %s, truncated file size: " \
			"%"PRId64" == appender file size: %" \
			PRId64", skip truncate file", \
			__LINE__, pTask->client_ip, \
			remain_bytes, (int64_t)stat_buf.st_size);
		return 0;
	}
	if (remain_bytes > stat_buf.st_size)
	{
		logWarning("file: "__FILE__", line: %d, " \
			"client ip: %s, truncated file size: " \
			"%"PRId64" > appender file size: %" \
			PRId64, __LINE__, pTask->client_ip, \
			remain_bytes, (int64_t)stat_buf.st_size);
	}

	pFileContext->extra_info.upload.start_time = g_current_time;
	pFileContext->extra_info.upload.if_gen_filename = false;

	pFileContext->calc_crc32 = false;
	pFileContext->calc_file_hash = false;

	pFileContext->sync_flag = STORAGE_OP_TYPE_SOURCE_TRUNCATE_FILE;
	pFileContext->timestamp2log = pFileContext->extra_info.upload.start_time;
	pFileContext->extra_info.upload.file_type = _FILE_TYPE_APPENDER;
	pFileContext->extra_info.upload.before_open_callback = NULL;
	pFileContext->extra_info.upload.before_close_callback = NULL;
	pFileContext->extra_info.upload.trunk_info.path.store_path_index = \
			store_path_index;
	pFileContext->op = FDFS_STORAGE_FILE_OP_WRITE;
	pFileContext->open_flags = O_WRONLY | g_extra_open_file_flags;
    pFileContext->continue_callback = storage_nio_notify;

 	return storage_write_to_file(pTask, remain_bytes, \
			stat_buf.st_size, 0, dio_truncate_file, \
			storage_do_truncate_file_done_callback, \
			dio_truncate_finish_clean_up, store_path_index);
}

/**
8 bytes: master filename length
8 bytes: file size
FDFS_FILE_PREFIX_MAX_LEN bytes  : filename prefix
FDFS_FILE_EXT_NAME_MAX_LEN bytes: file ext name, do not include dot (.)
master filename bytes: master filename
file size bytes: file content
**/
static int storage_upload_slave_file(struct fast_task_info *pTask)
{
	StorageClientInfo *pClientInfo;
	StorageFileContext *pFileContext;
	FDFSTrunkHeader trunkHeader;
	char *p;
	char filename[128];
	char master_filename[128];
	char true_filename[128];
	char prefix_name[FDFS_FILE_PREFIX_MAX_LEN + 1];
	char file_ext_name[FDFS_FILE_PREFIX_MAX_LEN + 1];
	char reserved_space_str[32];
	int master_filename_len;
	int64_t nInPackLen;
	int64_t file_bytes;
	int crc32;
	int result;
	int store_path_index;
	int filename_len;
	struct stat stat_buf;

	pClientInfo = (StorageClientInfo *)pTask->arg;
	pFileContext =  &(pClientInfo->file_context);

	nInPackLen = pClientInfo->total_length - sizeof(TrackerHeader);
	if (nInPackLen <= 2 * FDFS_PROTO_PKG_LEN_SIZE + \
			FDFS_FILE_PREFIX_MAX_LEN + FDFS_FILE_EXT_NAME_MAX_LEN)
	{
		logError("file: "__FILE__", line: %d, " \
			"cmd=%d, client ip: %s, package size " \
			"%"PRId64" is not correct, " \
			"expect length > %d", __LINE__, \
			STORAGE_PROTO_CMD_UPLOAD_SLAVE_FILE, \
			pTask->client_ip,  \
			nInPackLen, 2 * FDFS_PROTO_PKG_LEN_SIZE + \
			FDFS_FILE_PREFIX_MAX_LEN + \
			FDFS_FILE_EXT_NAME_MAX_LEN);
		return EINVAL;
	}

	p = pTask->data + sizeof(TrackerHeader);

	master_filename_len = buff2long(p);
	p += FDFS_PROTO_PKG_LEN_SIZE;
	file_bytes = buff2long(p);
	p += FDFS_PROTO_PKG_LEN_SIZE;
	if (master_filename_len <= FDFS_LOGIC_FILE_PATH_LEN || \
		master_filename_len >= sizeof(master_filename))
	{
		logError("file: "__FILE__", line: %d, " \
			"client ip:%s, invalid master_filename " \
			"bytes: %d", __LINE__, \
			pTask->client_ip, master_filename_len);
		return EINVAL;
	}

	if (file_bytes < 0 || file_bytes != nInPackLen - \
		(2 * FDFS_PROTO_PKG_LEN_SIZE + FDFS_FILE_PREFIX_MAX_LEN
		 + FDFS_FILE_EXT_NAME_MAX_LEN + master_filename_len))
	{
		logError("file: "__FILE__", line: %d, " \
			"client ip: %s, pkg length is not correct, " \
			"invalid file bytes: %"PRId64, \
			__LINE__, pTask->client_ip, file_bytes);
		return EINVAL;
	}

	memcpy(prefix_name, p, FDFS_FILE_PREFIX_MAX_LEN);
	*(prefix_name + FDFS_FILE_PREFIX_MAX_LEN) = '\0';
	p += FDFS_FILE_PREFIX_MAX_LEN;
	if (*prefix_name == '\0')
	{
		logError("file: "__FILE__", line: %d, " \
			"client ip: %s, prefix_name is empty!", \
			 __LINE__, pTask->client_ip);
		return EINVAL;
	}
	if ((result=fdfs_validate_filename(prefix_name)) != 0)
	{
		logError("file: "__FILE__", line: %d, " \
			"client ip: %s, prefix_name: %s " \
			"is invalid!", __LINE__, \
			pTask->client_ip, prefix_name);
		return result;
	}

	memcpy(file_ext_name, p, FDFS_FILE_EXT_NAME_MAX_LEN);
	*(file_ext_name + FDFS_FILE_EXT_NAME_MAX_LEN) = '\0';
	p += FDFS_FILE_EXT_NAME_MAX_LEN;
	if ((result=fdfs_validate_filename(file_ext_name)) != 0)
	{
		logError("file: "__FILE__", line: %d, " \
			"client ip: %s, file_ext_name: %s " \
			"is invalid!", __LINE__, \
			pTask->client_ip, file_ext_name);
		return result;
	}

	memcpy(master_filename, p, master_filename_len);
	*(master_filename + master_filename_len) = '\0';
	p += master_filename_len;

	filename_len = master_filename_len;
	if ((result=storage_split_filename_ex(master_filename, \
		&filename_len, true_filename, &store_path_index)) != 0)
	{
		return result;
	}
	if ((result=fdfs_check_data_filename(true_filename, filename_len)) != 0)
	{
		return result;
	}

	if (!storage_check_reserved_space_path(g_fdfs_store_paths.paths \
		[store_path_index].total_mb, g_fdfs_store_paths.paths \
		[store_path_index].free_mb - (file_bytes / FDFS_ONE_MB), \
		g_avg_storage_reserved_mb))
	{
		logError("file: "__FILE__", line: %d, " \
			"no space to upload file, "
			"free space: %"PRId64" MB is too small, file bytes: " \
			"%"PRId64", reserved space: %s", __LINE__,\
			g_fdfs_store_paths.paths[store_path_index].free_mb, \
			file_bytes, fdfs_storage_reserved_space_to_string_ex(\
				g_storage_reserved_space.flag, \
				g_avg_storage_reserved_mb, \
				g_fdfs_store_paths.paths[store_path_index].total_mb, \
				g_storage_reserved_space.rs.ratio, \
				reserved_space_str));
		return ENOSPC;
	}

	if ((result=trunk_file_lstat(store_path_index, true_filename, \
			filename_len, &stat_buf, \
			&(pFileContext->extra_info.upload.trunk_info), \
			&trunkHeader)) != 0)
	{
		logError("file: "__FILE__", line: %d, " \
			"client ip: %s, stat logic file %s fail, " \
			"errno: %d, error info: %s.", \
			__LINE__, pTask->client_ip, \
			master_filename, result, STRERROR(result));
		return result;
	}

	strcpy(pFileContext->extra_info.upload.file_ext_name, file_ext_name);
	storage_format_ext_name(file_ext_name, \
			pFileContext->extra_info.upload.formatted_ext_name);
	pFileContext->extra_info.upload.start_time = g_current_time;
	pFileContext->extra_info.upload.if_gen_filename = g_check_file_duplicate;
	pFileContext->extra_info.upload.if_sub_path_alloced = false;
	pFileContext->extra_info.upload.trunk_info.path. \
				store_path_index = store_path_index;
	if ((result=fdfs_gen_slave_filename(true_filename, \
		prefix_name, file_ext_name, filename, &filename_len)) != 0)
	{
		return result;
	}

	if (g_use_access_log)
	{
		snprintf(pFileContext->fname2log, \
			sizeof(pFileContext->fname2log), \
			"%c"FDFS_STORAGE_DATA_DIR_FORMAT"/%s", \
			FDFS_STORAGE_STORE_PATH_PREFIX_CHAR, \
			store_path_index, filename);
	}

	snprintf(pFileContext->filename, sizeof(pFileContext->filename), \
		"%s/data/%s", g_fdfs_store_paths.paths[store_path_index].path, filename);
	if (fileExists(pFileContext->filename))
	{
		logError("file: "__FILE__", line: %d, " \
			"client ip: %s, slave file: %s " \
			"already exist", __LINE__, \
			pTask->client_ip, pFileContext->filename);
		return EEXIST;
	}

	crc32 = rand();
	*filename = '\0';
	filename_len = 0;
	if ((result=storage_get_filename(pClientInfo, \
			pFileContext->extra_info.upload.start_time, \
			file_bytes, crc32, \
			pFileContext->extra_info.upload.formatted_ext_name, \
			filename, &filename_len, pFileContext->filename)) != 0)
	{
		return result;
	}
	if (*pFileContext->filename == '\0')
	{
		logWarning("file: "__FILE__", line: %d, " \
			"Can't generate uniq filename", __LINE__);
		return EBUSY;
	}

	pFileContext->calc_crc32 = g_check_file_duplicate || \
				g_store_slave_file_use_link;
	if (!pFileContext->calc_crc32)
	{
		pFileContext->crc32 = 0;
	}
	pFileContext->calc_file_hash = g_check_file_duplicate;

	strcpy(pFileContext->extra_info.upload.master_filename, master_filename);
	strcpy(pFileContext->extra_info.upload.prefix_name, prefix_name);

	pFileContext->extra_info.upload.file_type = _FILE_TYPE_SLAVE | \
						_FILE_TYPE_REGULAR;
	pFileContext->sync_flag = STORAGE_OP_TYPE_SOURCE_CREATE_FILE;
	pFileContext->timestamp2log = pFileContext->extra_info.upload.start_time;
	pFileContext->extra_info.upload.before_open_callback = NULL;
	pFileContext->extra_info.upload.before_close_callback = NULL;
	pFileContext->extra_info.upload.trunk_info.path.store_path_index = \
			store_path_index;
	pFileContext->op = FDFS_STORAGE_FILE_OP_WRITE;
	pFileContext->open_flags = O_WRONLY | O_CREAT | O_TRUNC \
				| g_extra_open_file_flags;
    pFileContext->continue_callback = storage_nio_notify;

 	return storage_write_to_file(pTask, 0, file_bytes, p - pTask->data, \
			dio_write_file, storage_upload_file_done_callback, \
			dio_write_finish_clean_up, store_path_index);
}

/**
8 bytes: filename bytes
8 bytes: file size
4 bytes: source op timestamp
FDFS_GROUP_NAME_MAX_LEN bytes: group_name
filename bytes : filename
file size bytes: file content
**/
static int storage_sync_copy_file(struct fast_task_info *pTask, \
		const char proto_cmd)
{
	StorageClientInfo *pClientInfo;
	StorageFileContext *pFileContext;
	TaskDealFunc deal_func;
	DisconnectCleanFunc clean_func;
	FDFSTrunkHeader trunkHeader;
	char *p;
	char group_name[FDFS_GROUP_NAME_MAX_LEN + 1];
	char true_filename[128];
	char filename[128];
	int filename_len;
	int64_t nInPackLen;
	int64_t file_bytes;
	int64_t file_offset;
	int result;
	int store_path_index;
	bool have_file_content;

	pClientInfo = (StorageClientInfo *)pTask->arg;
	pFileContext =  &(pClientInfo->file_context);

	nInPackLen = pClientInfo->total_length - sizeof(TrackerHeader);
	if (nInPackLen <= 2 * FDFS_PROTO_PKG_LEN_SIZE + \
		4 + FDFS_GROUP_NAME_MAX_LEN)
	{
		logError("file: "__FILE__", line: %d, " \
			"cmd=%d, client ip: %s, package size " \
			"%"PRId64"is not correct, " \
			"expect length > %d", __LINE__, \
			proto_cmd, pTask->client_ip, nInPackLen, \
			2 * FDFS_PROTO_PKG_LEN_SIZE + 4+FDFS_GROUP_NAME_MAX_LEN);
		return EINVAL;
	}

	p = pTask->data + sizeof(TrackerHeader);

	filename_len = buff2long(p);
	p += FDFS_PROTO_PKG_LEN_SIZE;
	file_bytes = buff2long(p);
	p += FDFS_PROTO_PKG_LEN_SIZE;
	if (filename_len < 0 || filename_len >= sizeof(filename))
	{
		logError("file: "__FILE__", line: %d, " \
			"client ip: %s, in request pkg, " \
			"filename length: %d is invalid, " \
			"which < 0 or >= %d", __LINE__, pTask->client_ip, \
			filename_len,  (int)sizeof(filename));
		return EINVAL;
	}

	if (file_bytes < 0)
	{
		logError("file: "__FILE__", line: %d, " \
			"client ip: %s, in request pkg, " \
			"file size: %"PRId64" is invalid, "\
			"which < 0", __LINE__, pTask->client_ip, file_bytes);
		return EINVAL;
	}

	pFileContext->timestamp2log = buff2int(p);
	p += 4;

	memcpy(group_name, p, FDFS_GROUP_NAME_MAX_LEN);
	*(group_name + FDFS_GROUP_NAME_MAX_LEN) = '\0';
	p += FDFS_GROUP_NAME_MAX_LEN;
	if (strcmp(group_name, g_group_name) != 0)
	{
		logError("file: "__FILE__", line: %d, " \
			"client ip:%s, group_name: %s " \
			"not correct, should be: %s", __LINE__, \
			pTask->client_ip, group_name, g_group_name);
		return EINVAL;
	}

	have_file_content = ((TrackerHeader *)pTask->data)->status == 0;
	if (have_file_content)
	{
	if (file_bytes != nInPackLen - (2*FDFS_PROTO_PKG_LEN_SIZE + \
			4 + FDFS_GROUP_NAME_MAX_LEN + filename_len))
	{
		logError("file: "__FILE__", line: %d, " \
			"client ip: %s, in request pkg, " \
			"file size: %"PRId64 \
			" != remain bytes: %"PRId64"", \
			__LINE__, pTask->client_ip, file_bytes, \
			nInPackLen - (2*FDFS_PROTO_PKG_LEN_SIZE + \
			FDFS_GROUP_NAME_MAX_LEN + filename_len));
		return EINVAL;
	}
	}
	else
	{
	if (0 != nInPackLen - (2*FDFS_PROTO_PKG_LEN_SIZE + \
			4 + FDFS_GROUP_NAME_MAX_LEN + filename_len))
	{
		logError("file: "__FILE__", line: %d, " \
			"client ip: %s, in request pkg, " \
			" remain bytes: %"PRId64" != 0 ", \
			__LINE__, pTask->client_ip, \
			nInPackLen - (2*FDFS_PROTO_PKG_LEN_SIZE + \
			FDFS_GROUP_NAME_MAX_LEN + filename_len));
		return EINVAL;
	}
	}

	memcpy(filename, p, filename_len);
	*(filename + filename_len) = '\0';
	p += filename_len;

	if ((result=storage_split_filename_ex(filename, \
		&filename_len, true_filename, &store_path_index)) != 0)
	{
		return result;
	}
	if ((result=fdfs_check_data_filename(true_filename, filename_len)) != 0)
	{
		return result;
	}

	if (proto_cmd == STORAGE_PROTO_CMD_SYNC_CREATE_FILE)
	{
		pFileContext->sync_flag = STORAGE_OP_TYPE_REPLICA_CREATE_FILE;
	}
	else
	{
		pFileContext->sync_flag = STORAGE_OP_TYPE_REPLICA_UPDATE_FILE;
	}

	if (have_file_content)
	{
		pFileContext->op = FDFS_STORAGE_FILE_OP_WRITE;
	}
	else
	{
		pFileContext->op = FDFS_STORAGE_FILE_OP_DISCARD;
		*(pFileContext->filename) = '\0';
	}

	pFileContext->extra_info.upload.file_type = \
				_FILE_TYPE_REGULAR;
	if (proto_cmd == STORAGE_PROTO_CMD_SYNC_CREATE_FILE && \
		have_file_content)
	{
		struct stat stat_buf;

		if ((result=trunk_file_lstat(store_path_index, \
			true_filename, filename_len, &stat_buf, \
			&(pFileContext->extra_info.upload.trunk_info), \
			&trunkHeader)) != 0)
		{
			if (result != ENOENT)  //accept no exist
			{
			logError("file: "__FILE__", line: %d, " \
				"client ip: %s, stat logic file %s fail, " \
				"errno: %d, error info: %s.", \
				__LINE__, pTask->client_ip, \
				filename, result, STRERROR(result));
			return result;
			}
		}
		else if (!S_ISREG(stat_buf.st_mode))
		{
			logWarning("file: "__FILE__", line: %d, " \
				"client ip: %s, logic file %s is not " \
				"a regular file, will be overwrited", \
				__LINE__, pTask->client_ip, filename);
		}
		else if (stat_buf.st_size != file_bytes)
		{
			logWarning("file: "__FILE__", line: %d, " \
				"client ip: %s, logic file %s, " \
				"my file size: %"PRId64\
				" != src file size: %"PRId64 \
				", will be overwrited", __LINE__, \
				pTask->client_ip, filename, \
				(int64_t)stat_buf.st_size, file_bytes);
		}
		else
		{
			logWarning("file: "__FILE__", line: %d, " \
				"cmd=%d, client ip: %s, data file: %s " \
				"already exists, ignore it", \
				__LINE__, proto_cmd, \
				pTask->client_ip, filename);

			pFileContext->op = FDFS_STORAGE_FILE_OP_DISCARD;
			*(pFileContext->filename) = '\0';
		}

		if (IS_TRUNK_FILE_BY_ID(pFileContext->extra_info. \
					upload.trunk_info))
		{
			pFileContext->extra_info.upload.file_type |= \
						_FILE_TYPE_TRUNK;
		}
	}

	if (pFileContext->op == FDFS_STORAGE_FILE_OP_WRITE)
	{
	if (pFileContext->extra_info.upload.file_type & _FILE_TYPE_TRUNK)
	{
		pFileContext->crc32 = trunkHeader.crc32;
		pFileContext->extra_info.upload.start_time = trunkHeader.mtime;
       		snprintf(pFileContext->extra_info.upload.formatted_ext_name, \
		sizeof(pFileContext->extra_info.upload.formatted_ext_name), 
			"%s", trunkHeader.formatted_ext_name);

		clean_func = dio_trunk_write_finish_clean_up;
		file_offset = TRUNK_FILE_START_OFFSET(pFileContext-> \
					extra_info.upload.trunk_info);
		trunk_get_full_filename(&pFileContext-> \
			extra_info.upload.trunk_info, pFileContext->filename, \
			sizeof(pFileContext->filename));
		pFileContext->extra_info.upload.before_open_callback = \
					dio_check_trunk_file_when_sync;
		pFileContext->extra_info.upload.before_close_callback = \
					dio_write_chunk_header;
		pFileContext->open_flags = O_RDWR | g_extra_open_file_flags;
	}
	else
	{
		#define MKTEMP_MAX_COUNT  10
		int i;
		struct stat stat_buf;

		for (i=0; i < MKTEMP_MAX_COUNT; i++)
		{
			sprintf(pFileContext->filename, "%s/data/.cp%"PRId64".tmp",
				g_fdfs_store_paths.paths[store_path_index].path,
                __sync_add_and_fetch(&temp_file_sequence, 1));
			if (stat(pFileContext->filename, &stat_buf) == 0)
			{
				if (g_current_time - stat_buf.st_mtime > 600)
				{
					if (unlink(pFileContext->filename) != 0
						&& errno != ENOENT)
					{
					logWarning("file: "__FILE__", line: %d"\
					", client ip: %s, unlink temp file %s "\
					" fail, errno: %d, error info: %s", \
					__LINE__, pTask->client_ip, \
					pFileContext->filename, \
					errno, STRERROR(errno));
					continue;
					}
				}
				else
				{
				logWarning("file: "__FILE__", line: %d, " \
					"client ip: %s, temp file %s already "\
					"exists", __LINE__, pTask->client_ip, \
					pFileContext->filename);
				continue;
				}
			}

			break;
		}

		if (i == MKTEMP_MAX_COUNT)
		{
			logError("file: "__FILE__", line: %d, " \
				"client ip: %s, make temp file fail", \
				__LINE__, pTask->client_ip);
			return EAGAIN;
		}

		clean_func = dio_write_finish_clean_up;
		file_offset = 0;
		pFileContext->extra_info.upload.before_open_callback = NULL;
		pFileContext->extra_info.upload.before_close_callback = NULL;
		pFileContext->open_flags = O_WRONLY | O_CREAT | O_TRUNC \
						| g_extra_open_file_flags;
	}

		deal_func = dio_write_file;
	}
	else
	{
		file_offset = 0;
		deal_func = dio_discard_file;
		clean_func = NULL;

		pFileContext->extra_info.upload.before_open_callback = NULL;
		pFileContext->extra_info.upload.before_close_callback = NULL;
	}
	
	pFileContext->calc_crc32 = false;
	pFileContext->calc_file_hash = false;
	strcpy(pFileContext->fname2log, filename);
    pFileContext->continue_callback = storage_nio_notify;

	if (have_file_content)
	{
		return storage_write_to_file(pTask, file_offset, file_bytes, \
			p - pTask->data, deal_func, \
			storage_sync_copy_file_done_callback, \
			clean_func, store_path_index);
	}
	else
    {
        storage_sync_copy_file_done_callback(pTask, 0);
        return TASK_STATUS_CONTINUE;
    }
}

/**
8 bytes: filename bytes
8 bytes: start offset
8 bytes: append bytes 
4 bytes: source op timestamp
FDFS_GROUP_NAME_MAX_LEN bytes: group_name
filename bytes : filename
file size bytes: file content
**/
static int storage_sync_append_file(struct fast_task_info *pTask)
{
	StorageClientInfo *pClientInfo;
	StorageFileContext *pFileContext;
	TaskDealFunc deal_func;
	char *p;
	char group_name[FDFS_GROUP_NAME_MAX_LEN + 1];
	char filename[128];
	bool need_write_file;
	int filename_len;
	int64_t nInPackLen;
	int64_t start_offset;
	int64_t append_bytes;
	struct stat stat_buf;
	int result;
	int store_path_index;

	pClientInfo = (StorageClientInfo *)pTask->arg;
	pFileContext =  &(pClientInfo->file_context);

	nInPackLen = pClientInfo->total_length - sizeof(TrackerHeader);
	if (nInPackLen <= 3 * FDFS_PROTO_PKG_LEN_SIZE + \
		4 + FDFS_GROUP_NAME_MAX_LEN)
	{
		logError("file: "__FILE__", line: %d, " \
			"cmd=%d, client ip: %s, package size " \
			"%"PRId64"is not correct, " \
			"expect length > %d", __LINE__, \
			STORAGE_PROTO_CMD_SYNC_APPEND_FILE, \
			pTask->client_ip, nInPackLen, \
			3 * FDFS_PROTO_PKG_LEN_SIZE + 4+FDFS_GROUP_NAME_MAX_LEN);
		return EINVAL;
	}

	p = pTask->data + sizeof(TrackerHeader);

	filename_len = buff2long(p);
	p += FDFS_PROTO_PKG_LEN_SIZE;
	start_offset = buff2long(p);
	p += FDFS_PROTO_PKG_LEN_SIZE;
	append_bytes = buff2long(p);
	p += FDFS_PROTO_PKG_LEN_SIZE;
	if (filename_len < 0 || filename_len >= sizeof(filename))
	{
		logError("file: "__FILE__", line: %d, " \
			"client ip: %s, in request pkg, " \
			"filename length: %d is invalid, " \
			"which < 0 or >= %d", __LINE__, pTask->client_ip, \
			filename_len,  (int)sizeof(filename));
		return EINVAL;
	}

	if (start_offset < 0)
	{
		logError("file: "__FILE__", line: %d, " \
			"client ip: %s, in request pkg, " \
			"start offset: %"PRId64" is invalid, "\
			"which < 0", __LINE__, pTask->client_ip, start_offset);
		return EINVAL;
	}

	if (append_bytes < 0)
	{
		logError("file: "__FILE__", line: %d, " \
			"client ip: %s, in request pkg, " \
			"append bytes: %"PRId64" is invalid, "\
			"which < 0", __LINE__, pTask->client_ip, append_bytes);
		return EINVAL;
	}

	pFileContext->timestamp2log = buff2int(p);
	p += 4;

	memcpy(group_name, p, FDFS_GROUP_NAME_MAX_LEN);
	*(group_name + FDFS_GROUP_NAME_MAX_LEN) = '\0';
	p += FDFS_GROUP_NAME_MAX_LEN;
	if (strcmp(group_name, g_group_name) != 0)
	{
		logError("file: "__FILE__", line: %d, " \
			"client ip:%s, group_name: %s " \
			"not correct, should be: %s", __LINE__, \
			pTask->client_ip, group_name, g_group_name);
		return EINVAL;
	}

	if (append_bytes != nInPackLen - (3 * FDFS_PROTO_PKG_LEN_SIZE + \
			4 + FDFS_GROUP_NAME_MAX_LEN + filename_len))
	{
		logError("file: "__FILE__", line: %d, " \
			"client ip: %s, in request pkg, " \
			"file size: %"PRId64 \
			" != remain bytes: %"PRId64"", \
			__LINE__, pTask->client_ip, append_bytes, \
			nInPackLen - (3 * FDFS_PROTO_PKG_LEN_SIZE + \
			FDFS_GROUP_NAME_MAX_LEN + filename_len));
		return EINVAL;
	}

	memcpy(filename, p, filename_len);
	*(filename + filename_len) = '\0';
	p += filename_len;

    if ((result=storage_logic_to_local_full_filename(
                    filename, filename_len,
                    &store_path_index, pFileContext->filename,
                    sizeof(pFileContext->filename))) != 0)
	{
		return result;
	}

	if (lstat(pFileContext->filename, &stat_buf) != 0)
	{
		result = errno != 0 ? errno : ENOENT;
		if (result != ENOENT)
		{
		logError("file: "__FILE__", line: %d, " \
			"client ip: %s, stat file %s fail, " \
			"errno: %d, error info: %s.", \
			__LINE__, pTask->client_ip, \
			pFileContext->filename, result, STRERROR(result));
		return result;
		}
		else
		{
		logWarning("file: "__FILE__", line: %d, " \
			"client ip: %s, appender file %s not exists, " \
			"will be resynced", __LINE__, pTask->client_ip, \
			pFileContext->filename);
		need_write_file = false;
		}
	}
	else if (!S_ISREG(stat_buf.st_mode))
	{
		logError("file: "__FILE__", line: %d, " \
			"client ip: %s, file %s is not a regular " \
			"file, will be ignored",  __LINE__, \
			pTask->client_ip, pFileContext->filename);
		need_write_file = false;
	}
	else if (stat_buf.st_size == start_offset)
	{
		need_write_file = true;
	}
	else if (stat_buf.st_size > start_offset)
	{
		if (stat_buf.st_size >= start_offset + append_bytes)
		{
		logDebug("file: "__FILE__", line: %d, " \
			"client ip: %s, file %s,  my file size: %" \
			PRId64" >= src file size: " \
			"%"PRId64", do not append", \
			__LINE__, pTask->client_ip, pFileContext->filename, \
			(int64_t)stat_buf.st_size,
            start_offset + append_bytes);
		}
		else
		{
		logWarning("file: "__FILE__", line: %d, " \
			"client ip: %s, file %s,  my file size: %" \
			PRId64" > %"PRId64 \
			", but < %"PRId64", need be resynced", \
			__LINE__, pTask->client_ip, pFileContext->filename, \
			(int64_t)stat_buf.st_size, start_offset, \
			start_offset + append_bytes);

		}

		need_write_file = false;
	}
	else //stat_buf.st_size < start_offset
	{
		logWarning("file: "__FILE__", line: %d, " \
			"client ip: %s, file %s,  my file size: %" \
			PRId64" < start offset " \
			"%"PRId64", need to resync this file!", \
			__LINE__, pTask->client_ip, pFileContext->filename, \
			(int64_t)stat_buf.st_size, start_offset);
		need_write_file = false;
	}

	pFileContext->sync_flag = STORAGE_OP_TYPE_REPLICA_APPEND_FILE;

	if (need_write_file)
	{
		deal_func = dio_write_file;
		pFileContext->op = FDFS_STORAGE_FILE_OP_APPEND;
		pFileContext->open_flags = O_WRONLY | O_APPEND | g_extra_open_file_flags;

		snprintf(pFileContext->fname2log, \
			sizeof(pFileContext->fname2log), \
			"%s %"PRId64" %"PRId64, \
			filename, start_offset, append_bytes);
	}
	else
	{
		deal_func = dio_discard_file;
		pFileContext->op = FDFS_STORAGE_FILE_OP_DISCARD;
		pFileContext->open_flags = 0;
	}

	pFileContext->calc_crc32 = false;
	pFileContext->calc_file_hash = false;
	pFileContext->extra_info.upload.before_open_callback = NULL;
	pFileContext->extra_info.upload.before_close_callback = NULL;
    pFileContext->continue_callback = storage_nio_notify;

	return storage_write_to_file(pTask, start_offset, append_bytes, \
		p - pTask->data, deal_func, \
		storage_sync_modify_file_done_callback, \
		dio_append_finish_clean_up, store_path_index);
}

/**
8 bytes: filename bytes
8 bytes: start offset
8 bytes: append bytes 
4 bytes: source op timestamp
FDFS_GROUP_NAME_MAX_LEN bytes: group_name
filename bytes : filename
file size bytes: file content
**/
static int storage_sync_modify_file(struct fast_task_info *pTask)
{
	StorageClientInfo *pClientInfo;
	StorageFileContext *pFileContext;
	TaskDealFunc deal_func;
	char *p;
	char group_name[FDFS_GROUP_NAME_MAX_LEN + 1];
	char filename[128];
	bool need_write_file;
	int filename_len;
	int64_t nInPackLen;
	int64_t start_offset;
	int64_t modify_bytes;
	struct stat stat_buf;
	int result;
	int store_path_index;

	pClientInfo = (StorageClientInfo *)pTask->arg;
	pFileContext =  &(pClientInfo->file_context);

	nInPackLen = pClientInfo->total_length - sizeof(TrackerHeader);
	if (nInPackLen <= 3 * FDFS_PROTO_PKG_LEN_SIZE + \
		4 + FDFS_GROUP_NAME_MAX_LEN)
	{
		logError("file: "__FILE__", line: %d, " \
			"cmd=%d, client ip: %s, package size " \
			"%"PRId64"is not correct, " \
			"expect length > %d", __LINE__, \
			STORAGE_PROTO_CMD_SYNC_MODIFY_FILE, \
			pTask->client_ip, nInPackLen, \
			3 * FDFS_PROTO_PKG_LEN_SIZE + 4 + \
			FDFS_GROUP_NAME_MAX_LEN);
		return EINVAL;
	}

	p = pTask->data + sizeof(TrackerHeader);

	filename_len = buff2long(p);
	p += FDFS_PROTO_PKG_LEN_SIZE;
	start_offset = buff2long(p);
	p += FDFS_PROTO_PKG_LEN_SIZE;
	modify_bytes = buff2long(p);
	p += FDFS_PROTO_PKG_LEN_SIZE;
	if (filename_len < 0 || filename_len >= sizeof(filename))
	{
		logError("file: "__FILE__", line: %d, " \
			"client ip: %s, in request pkg, " \
			"filename length: %d is invalid, " \
			"which < 0 or >= %d", __LINE__, pTask->client_ip, \
			filename_len,  (int)sizeof(filename));
		return EINVAL;
	}

	if (start_offset < 0)
	{
		logError("file: "__FILE__", line: %d, " \
			"client ip: %s, in request pkg, " \
			"start offset: %"PRId64" is invalid, "\
			"which < 0", __LINE__, pTask->client_ip, start_offset);
		return EINVAL;
	}

	if (modify_bytes < 0)
	{
		logError("file: "__FILE__", line: %d, " \
			"client ip: %s, in request pkg, " \
			"modify file bytes: %"PRId64" is invalid, "\
			"which < 0", __LINE__, pTask->client_ip, modify_bytes);
		return EINVAL;
	}

	pFileContext->timestamp2log = buff2int(p);
	p += 4;

	memcpy(group_name, p, FDFS_GROUP_NAME_MAX_LEN);
	*(group_name + FDFS_GROUP_NAME_MAX_LEN) = '\0';
	p += FDFS_GROUP_NAME_MAX_LEN;
	if (strcmp(group_name, g_group_name) != 0)
	{
		logError("file: "__FILE__", line: %d, " \
			"client ip:%s, group_name: %s " \
			"not correct, should be: %s", __LINE__, \
			pTask->client_ip, group_name, g_group_name);
		return EINVAL;
	}

	if (modify_bytes != nInPackLen - (3 * FDFS_PROTO_PKG_LEN_SIZE + \
			4 + FDFS_GROUP_NAME_MAX_LEN + filename_len))
	{
		logError("file: "__FILE__", line: %d, " \
			"client ip: %s, in request pkg, " \
			"file size: %"PRId64 \
			" != remain bytes: %"PRId64"", \
			__LINE__, pTask->client_ip, modify_bytes, \
			nInPackLen - (3 * FDFS_PROTO_PKG_LEN_SIZE + \
			FDFS_GROUP_NAME_MAX_LEN + filename_len));
		return EINVAL;
	}

	memcpy(filename, p, filename_len);
	*(filename + filename_len) = '\0';
	p += filename_len;

    if ((result=storage_logic_to_local_full_filename(
                    filename, filename_len,
                    &store_path_index, pFileContext->filename,
                    sizeof(pFileContext->filename))) != 0)
	{
		return result;
	}

	if (lstat(pFileContext->filename, &stat_buf) != 0)
	{
		result = errno != 0 ? errno : ENOENT;
		if (result != ENOENT)
		{
		logError("file: "__FILE__", line: %d, " \
			"client ip: %s, stat file %s fail, " \
			"errno: %d, error info: %s.", \
			__LINE__, pTask->client_ip, \
			pFileContext->filename, result, STRERROR(result));
		return result;
		}
		else
		{
		logWarning("file: "__FILE__", line: %d, " \
			"client ip: %s, appender file %s not exists, " \
			"will be resynced", __LINE__, pTask->client_ip, \
			pFileContext->filename);
		need_write_file = false;
		}
	}
	else if (!S_ISREG(stat_buf.st_mode))
	{
		logError("file: "__FILE__", line: %d, " \
			"client ip: %s, file %s is not a regular " \
			"file, will be ignored",  __LINE__, \
			pTask->client_ip, pFileContext->filename);
		need_write_file = false;
	}
	else if (stat_buf.st_size < start_offset)
	{
		logWarning("file: "__FILE__", line: %d, " \
			"client ip: %s, file %s,  my file size: %" \
			PRId64" < start offset " \
			"%"PRId64", need to resync this file!", \
			__LINE__, pTask->client_ip, pFileContext->filename, \
			(int64_t)stat_buf.st_size, start_offset);
		need_write_file = false;
	}
	else
	{
		need_write_file = true;
	}

	pFileContext->sync_flag = STORAGE_OP_TYPE_REPLICA_MODIFY_FILE;
	if (need_write_file)
	{
		deal_func = dio_write_file;
		pFileContext->op = FDFS_STORAGE_FILE_OP_WRITE;
		pFileContext->open_flags = O_WRONLY | g_extra_open_file_flags;

		snprintf(pFileContext->fname2log, \
			sizeof(pFileContext->fname2log), \
			"%s %"PRId64" %"PRId64, \
			filename, start_offset, modify_bytes);
	}
	else
	{
		deal_func = dio_discard_file;
		pFileContext->op = FDFS_STORAGE_FILE_OP_DISCARD;
		pFileContext->open_flags = 0;
	}

	pFileContext->calc_crc32 = false;
	pFileContext->calc_file_hash = false;
	pFileContext->extra_info.upload.before_open_callback = NULL;
	pFileContext->extra_info.upload.before_close_callback = NULL;
    pFileContext->continue_callback = storage_nio_notify;

	return storage_write_to_file(pTask, start_offset, modify_bytes, \
		p - pTask->data, deal_func, \
		storage_sync_modify_file_done_callback, \
		dio_modify_finish_clean_up, store_path_index);
}

/**
8 bytes: filename bytes
8 bytes: old file size
8 bytes: new file size
4 bytes: source op timestamp
FDFS_GROUP_NAME_MAX_LEN bytes: group_name
filename bytes : filename
**/
static int storage_sync_truncate_file(struct fast_task_info *pTask)
{
	StorageClientInfo *pClientInfo;
	StorageFileContext *pFileContext;
	char *p;
	char group_name[FDFS_GROUP_NAME_MAX_LEN + 1];
	char filename[128];
	int filename_len;
	int64_t nInPackLen;
	int64_t old_file_size;
	int64_t new_file_size;
	struct stat stat_buf;
	int result;
	int store_path_index;

	pClientInfo = (StorageClientInfo *)pTask->arg;
	pFileContext =  &(pClientInfo->file_context);

	nInPackLen = pClientInfo->total_length - sizeof(TrackerHeader);
	if (nInPackLen <= 3 * FDFS_PROTO_PKG_LEN_SIZE + \
		4 + FDFS_GROUP_NAME_MAX_LEN)
	{
		logError("file: "__FILE__", line: %d, " \
			"cmd=%d, client ip: %s, package size " \
			"%"PRId64"is not correct, " \
			"expect length > %d", __LINE__, \
			STORAGE_PROTO_CMD_SYNC_TRUNCATE_FILE, \
			pTask->client_ip, nInPackLen, \
			3 * FDFS_PROTO_PKG_LEN_SIZE + 4 +
			FDFS_GROUP_NAME_MAX_LEN);
		return EINVAL;
	}

	p = pTask->data + sizeof(TrackerHeader);

	filename_len = buff2long(p);
	p += FDFS_PROTO_PKG_LEN_SIZE;
	old_file_size = buff2long(p);
	p += FDFS_PROTO_PKG_LEN_SIZE;
	new_file_size = buff2long(p);
	p += FDFS_PROTO_PKG_LEN_SIZE;
	if (filename_len < 0 || filename_len >= sizeof(filename))
	{
		logError("file: "__FILE__", line: %d, " \
			"client ip: %s, in request pkg, " \
			"filename length: %d is invalid, " \
			"which < 0 or >= %d", __LINE__, \
			pTask->client_ip, filename_len, \
			(int)sizeof(filename));
		return EINVAL;
	}

	if (filename_len != nInPackLen - (3 * FDFS_PROTO_PKG_LEN_SIZE +\
		4 + FDFS_GROUP_NAME_MAX_LEN))
	{
		logError("file: "__FILE__", line: %d, " \
			"client ip: %s, in request pkg, " \
			"filename length: %d != %d", __LINE__, \
			pTask->client_ip, filename_len, \
			(int)nInPackLen - (3 * FDFS_PROTO_PKG_LEN_SIZE + \
			4 + FDFS_GROUP_NAME_MAX_LEN));
		return EINVAL;
	}

	if (old_file_size < 0)
	{
		logError("file: "__FILE__", line: %d, " \
			"client ip: %s, in request pkg, " \
			"start offset: %"PRId64 \
			"is invalid, which < 0", __LINE__, \
			pTask->client_ip, old_file_size);
		return EINVAL;
	}

	if (new_file_size < 0)
	{
		logError("file: "__FILE__", line: %d, " \
			"client ip: %s, in request pkg, " \
			"modify file bytes: %"PRId64 \
			" is invalid, which < 0", __LINE__, \
			pTask->client_ip, new_file_size);
		return EINVAL;
	}

	pFileContext->timestamp2log = buff2int(p);
	p += 4;

	memcpy(group_name, p, FDFS_GROUP_NAME_MAX_LEN);
	*(group_name + FDFS_GROUP_NAME_MAX_LEN) = '\0';
	p += FDFS_GROUP_NAME_MAX_LEN;
	if (strcmp(group_name, g_group_name) != 0)
	{
		logError("file: "__FILE__", line: %d, " \
			"client ip:%s, group_name: %s " \
			"not correct, should be: %s", __LINE__, \
			pTask->client_ip, group_name, g_group_name);
		return EINVAL;
	}

	memcpy(filename, p, filename_len);
	*(filename + filename_len) = '\0';
	p += filename_len;

    if ((result=storage_logic_to_local_full_filename(
                    filename, filename_len,
                    &store_path_index, pFileContext->filename,
                    sizeof(pFileContext->filename))) != 0)
	{
		return result;
	}

	if (lstat(pFileContext->filename, &stat_buf) != 0)
	{
		result = errno != 0 ? errno : ENOENT;
		if (result != ENOENT)
		{
		logError("file: "__FILE__", line: %d, " \
			"client ip: %s, stat file %s fail, " \
			"errno: %d, error info: %s.", \
			__LINE__, pTask->client_ip, \
			pFileContext->filename, result, STRERROR(result));
		}
		else
		{
		logWarning("file: "__FILE__", line: %d, " \
			"client ip: %s, appender file %s not exists, " \
			"will be resynced", __LINE__, pTask->client_ip, \
			pFileContext->filename);
		}
		return result;
	}
	if (!S_ISREG(stat_buf.st_mode))
	{
		logError("file: "__FILE__", line: %d, " \
			"client ip: %s, file %s is not a regular " \
			"file, will be ignored",  __LINE__, \
			pTask->client_ip, pFileContext->filename);
		return EEXIST;
	}
	if (stat_buf.st_size != old_file_size)
	{
		logWarning("file: "__FILE__", line: %d, " \
			"client ip: %s, file %s,  my file size: %" \
			PRId64" != before truncated size: " \
			"%"PRId64", skip!", __LINE__, \
			pTask->client_ip, pFileContext->filename, \
			(int64_t)stat_buf.st_size, old_file_size);
		return EEXIST;
	}

	pFileContext->sync_flag = STORAGE_OP_TYPE_REPLICA_TRUNCATE_FILE;
	pFileContext->op = FDFS_STORAGE_FILE_OP_WRITE;
	pFileContext->open_flags = O_WRONLY | g_extra_open_file_flags;

	snprintf(pFileContext->fname2log, \
		sizeof(pFileContext->fname2log), \
		"%s %"PRId64" %"PRId64, \
		filename, old_file_size, new_file_size);

	pFileContext->calc_crc32 = false;
	pFileContext->calc_file_hash = false;
	pFileContext->extra_info.upload.before_open_callback = NULL;
	pFileContext->extra_info.upload.before_close_callback = NULL;
    pFileContext->continue_callback = storage_nio_notify;

	return storage_write_to_file(pTask, new_file_size, \
		old_file_size, 0, dio_truncate_file, \
		storage_sync_truncate_file_done_callback, \
		dio_truncate_finish_clean_up, store_path_index);
}

/**
8 bytes: dest(link) filename length
8 bytes: source filename length
4 bytes: source op timestamp
FDFS_GROUP_NAME_MAX_LEN bytes: group_name
dest filename length: dest filename
source filename length: source filename
**/
static int storage_do_sync_link_file(struct fast_task_info *pTask)
{
	StorageClientInfo *pClientInfo;
	StorageFileContext *pFileContext;
	TrackerHeader *pHeader;
	char *p;
	struct stat stat_buf;
	FDFSTrunkHeader srcTrunkHeader;
	FDFSTrunkHeader destTrunkHeader;
	char group_name[FDFS_GROUP_NAME_MAX_LEN + 1];
	char dest_filename[128];
	char dest_true_filename[128];
	char src_filename[128];
	char src_true_filename[128];
	char src_full_filename[MAX_PATH_SIZE];
	char binlog_buff[256];
	bool need_create_link;
	int64_t nInPackLen;
	int dest_filename_len;
	int dest_true_filename_len;
	int src_filename_len;
	int src_true_filename_len;
	int result;
	int dest_store_path_index;
	int src_store_path_index;

	pClientInfo = (StorageClientInfo *)pTask->arg;
	pFileContext =  &(pClientInfo->file_context);

	nInPackLen = pClientInfo->total_length - sizeof(TrackerHeader);
	pClientInfo->total_length = sizeof(TrackerHeader);

	do
	{
	p = pTask->data + sizeof(TrackerHeader);

	dest_filename_len = buff2long(p);
	p += FDFS_PROTO_PKG_LEN_SIZE;

	src_filename_len = buff2long(p);
	p += FDFS_PROTO_PKG_LEN_SIZE + 4;

	if (src_filename_len < 0 || src_filename_len >= sizeof(src_filename))
	{
		logError("file: "__FILE__", line: %d, " \
			"client ip: %s, in request pkg, " \
			"filename length: %d is invalid, " \
			"which < 0 or >= %d", \
			__LINE__, pTask->client_ip, \
			src_filename_len, (int)sizeof(src_filename));
		result = EINVAL;
		break;
	}

	memcpy(group_name, p, FDFS_GROUP_NAME_MAX_LEN);
	*(group_name + FDFS_GROUP_NAME_MAX_LEN) = '\0';
	p += FDFS_GROUP_NAME_MAX_LEN;
	if (strcmp(group_name, g_group_name) != 0)
	{
		logError("file: "__FILE__", line: %d, " \
			"client ip: %s, group_name: %s " \
			"not correct, should be: %s", \
			__LINE__, pTask->client_ip, \
			group_name, g_group_name);
		result = EINVAL;
		break;
	}

	if (nInPackLen != 2 * FDFS_PROTO_PKG_LEN_SIZE + 4 + \
		FDFS_GROUP_NAME_MAX_LEN + dest_filename_len + src_filename_len)
	{
		logError("file: "__FILE__", line: %d, " \
			"client ip: %s, in request pkg, " \
			"pgk length: %"PRId64 \
			" != bytes: %d", __LINE__, pTask->client_ip, \
			nInPackLen, 2 * FDFS_PROTO_PKG_LEN_SIZE + \
			FDFS_GROUP_NAME_MAX_LEN + dest_filename_len + \
			src_filename_len);
		result = EINVAL;
		break;
	}

	memcpy(dest_filename, p, dest_filename_len);
	*(dest_filename + dest_filename_len) = '\0';
	p += dest_filename_len;

	memcpy(src_filename, p, src_filename_len);
	*(src_filename + src_filename_len) = '\0';
	p += src_filename_len;

	dest_true_filename_len = dest_filename_len;
	if ((result=storage_split_filename_ex(dest_filename, \
		&dest_true_filename_len, dest_true_filename, \
		&dest_store_path_index)) != 0)
	{
		break;
	}

	src_true_filename_len = src_filename_len;
	if ((result=storage_split_filename_ex(src_filename, \
			&src_true_filename_len, src_true_filename, \
			&src_store_path_index)) != 0)
	{
		break;
	}
	if ((result=fdfs_check_data_filename(src_true_filename, \
			src_filename_len)) != 0)
	{
		break;
	}

	memset(&destTrunkHeader, 0, sizeof(destTrunkHeader));
	if (trunk_file_lstat(dest_store_path_index, dest_true_filename, \
			dest_true_filename_len, &stat_buf, \
			&(pFileContext->extra_info.upload.trunk_info), \
			&destTrunkHeader) == 0)
	{
		need_create_link = false;
		logWarning("file: "__FILE__", line: %d, " \
			"client ip: %s, logic link file: %s " \
			"already exists, ignore it", __LINE__, \
			pTask->client_ip, dest_filename);
	}
	else
	{
		FDFSTrunkFullInfo trunkInfo;
		if (trunk_file_lstat(src_store_path_index, src_true_filename, \
			src_true_filename_len, &stat_buf, \
			&trunkInfo, &srcTrunkHeader) != 0)
		{
			need_create_link = false;
			logWarning("file: "__FILE__", line: %d, " \
				"client ip: %s, logic source file: %s " \
				"not exists, ignore it", __LINE__, \
				pTask->client_ip, src_filename);
		}
		else
		{
			need_create_link = true;
		}
	}

	if (need_create_link)
	{
		if (IS_TRUNK_FILE_BY_ID(pFileContext->extra_info.upload.trunk_info))
		{
			pFileContext->extra_info.upload.file_type = \
						_FILE_TYPE_LINK;
			pFileContext->extra_info.upload.start_time = \
						destTrunkHeader.mtime;
			pFileContext->crc32 = destTrunkHeader.crc32;
			strcpy(pFileContext->extra_info.upload. \
				formatted_ext_name, \
				destTrunkHeader.formatted_ext_name);

			pTask->length = pTask->size;
			p = pTask->data + (pTask->length - src_filename_len);
			if (p < pTask->data + sizeof(TrackerHeader))
			{
				logError("file: "__FILE__", line: %d, " \
					"task buffer size: %d is too small", \
					__LINE__, pTask->size);
				break;
			}

			memcpy(p, src_filename, src_filename_len);
			result = storage_trunk_do_create_link(pTask, \
					src_filename_len, p - pTask->data, \
					dio_check_trunk_file_when_sync, NULL);
			if (result != 0)
			{
				break;
			}
		}
		else
		{
		snprintf(pFileContext->filename, sizeof(pFileContext->filename), \
			"%s/data/%s", g_fdfs_store_paths.paths[dest_store_path_index].path, \
			dest_true_filename);

		snprintf(src_full_filename, sizeof(src_full_filename), \
			"%s/data/%s", g_fdfs_store_paths.paths[src_store_path_index].path, \
			src_true_filename);
		if (symlink(src_full_filename, pFileContext->filename) != 0)
		{
			result = errno != 0 ? errno : EPERM;
			if (result == EEXIST)
			{
			logWarning("file: "__FILE__", line: %d, " \
				"client ip: %s, data file: %s " \
				"already exists, ignore it", __LINE__, \
				pTask->client_ip, pFileContext->filename);
			result = 0;
			}
			else
			{
			logError("file: "__FILE__", line: %d, " \
				"client ip: %s, link file %s to %s fail, " \
				"errno: %d, error info: %s", \
				__LINE__, pTask->client_ip, \
				src_full_filename, pFileContext->filename, \
				result, STRERROR(result));
			break;
			}

		}
		}
	}

	snprintf(binlog_buff, sizeof(binlog_buff), "%s %s", \
		dest_filename, src_filename);
	result = storage_binlog_write(pFileContext->timestamp2log, \
			STORAGE_OP_TYPE_REPLICA_CREATE_LINK, \
			binlog_buff);
	} while (0);

	CHECK_AND_WRITE_TO_STAT_FILE1

	pClientInfo->total_offset = 0;
	pTask->length = pClientInfo->total_length;
	pHeader = (TrackerHeader *)pTask->data;
	pHeader->status = result;
	pHeader->cmd = STORAGE_PROTO_CMD_RESP;
	long2buff(pClientInfo->total_length - sizeof(TrackerHeader), \
			pHeader->pkg_len);

	sf_nio_notify(pTask, SF_NIO_STAGE_SEND);
	return result;
}

static int storage_sync_link_file(struct fast_task_info *pTask)
{
	StorageClientInfo *pClientInfo;
	StorageFileContext *pFileContext;
	char *p;
	char dest_filename[128];
	char dest_true_filename[128];
	int64_t nInPackLen;
	int dest_filename_len;
	int src_filename_len;
	int result;
	int dest_store_path_index;

	pClientInfo = (StorageClientInfo *)pTask->arg;
	pFileContext =  &(pClientInfo->file_context);

	nInPackLen = pClientInfo->total_length - sizeof(TrackerHeader);

	if (nInPackLen <= 2 * FDFS_PROTO_PKG_LEN_SIZE + \
			4 + FDFS_GROUP_NAME_MAX_LEN)
	{
		logError("file: "__FILE__", line: %d, " \
			"client ip: %s, package size " \
			"%"PRId64" is not correct, " \
			"expect length > %d", __LINE__, \
			pTask->client_ip,  nInPackLen, \
			2 * FDFS_PROTO_PKG_LEN_SIZE + \
			4 + FDFS_GROUP_NAME_MAX_LEN);
		return EINVAL;
	}

	p = pTask->data + sizeof(TrackerHeader);

	dest_filename_len = buff2long(p);
	p += FDFS_PROTO_PKG_LEN_SIZE;

	src_filename_len = buff2long(p);
	p += FDFS_PROTO_PKG_LEN_SIZE;

	if (dest_filename_len < 0 || dest_filename_len >= sizeof(dest_filename))
	{
		logError("file: "__FILE__", line: %d, " \
			"client ip: %s, in request pkg, " \
			"filename length: %d is invalid, " \
			"which < 0 or >= %d", \
			__LINE__, pTask->client_ip, \
			dest_filename_len, (int)sizeof(dest_filename));
		return EINVAL;
	}

	pFileContext->timestamp2log = buff2int(p);
	p += 4 + FDFS_GROUP_NAME_MAX_LEN;
	if (nInPackLen != 2 * FDFS_PROTO_PKG_LEN_SIZE + 4 + \
		FDFS_GROUP_NAME_MAX_LEN + dest_filename_len + src_filename_len)
	{
		logError("file: "__FILE__", line: %d, " \
			"client ip: %s, in request pkg, " \
			"pgk length: %"PRId64 \
			" != bytes: %d", __LINE__, pTask->client_ip, \
			nInPackLen, 2 * FDFS_PROTO_PKG_LEN_SIZE + \
			FDFS_GROUP_NAME_MAX_LEN + dest_filename_len + \
			src_filename_len);
		return EINVAL;
	}

	memcpy(dest_filename, p, dest_filename_len);
	*(dest_filename + dest_filename_len) = '\0';
	p += dest_filename_len;

	if ((result=storage_split_filename_ex(dest_filename, \
		&dest_filename_len, dest_true_filename, \
		&dest_store_path_index)) != 0)
	{
		return result;
	}
	if ((result=fdfs_check_data_filename(dest_true_filename, \
			dest_filename_len)) != 0)
	{
		return result;
	}
	pFileContext->extra_info.upload.trunk_info.path.store_path_index = \
				dest_store_path_index;

	pClientInfo->deal_func = storage_do_sync_link_file;

	pFileContext->fd = -1;
	pFileContext->op = FDFS_STORAGE_FILE_OP_WRITE;
	pFileContext->dio_thread_index = storage_dio_get_thread_index( \
		pTask, dest_store_path_index, pFileContext->op);

	if ((result=storage_dio_queue_push(pTask)) != 0)
	{
		return result;
	}

	return TASK_STATUS_CONTINUE;
}

static int storage_sync_rename_file(struct fast_task_info *pTask)
{
	StorageClientInfo *pClientInfo;
	StorageFileContext *pFileContext;
	char *p;
	char group_name[FDFS_GROUP_NAME_MAX_LEN + 1];
	char dest_filename[128];
	char dest_full_filename[MAX_PATH_SIZE];
	char src_full_filename[MAX_PATH_SIZE];
	char src_filename[128];
	int64_t nInPackLen;
	int dest_filename_len;
	int src_filename_len;
	int result;
	int dest_store_path_index;
    int src_store_path_index;

	pClientInfo = (StorageClientInfo *)pTask->arg;
	pFileContext =  &(pClientInfo->file_context);

	nInPackLen = pClientInfo->total_length - sizeof(TrackerHeader);
	if (nInPackLen <= 2 * FDFS_PROTO_PKG_LEN_SIZE +
			4 + FDFS_GROUP_NAME_MAX_LEN)
	{
		logError("file: "__FILE__", line: %d, "
			"client ip: %s, package size "
			"%"PRId64" is not correct, "
			"expect length > %d", __LINE__,
			pTask->client_ip,  nInPackLen,
			2 * FDFS_PROTO_PKG_LEN_SIZE +
			4 + FDFS_GROUP_NAME_MAX_LEN);
		return EINVAL;
	}

	p = pTask->data + sizeof(TrackerHeader);

	dest_filename_len = buff2long(p);
	p += FDFS_PROTO_PKG_LEN_SIZE;

	src_filename_len = buff2long(p);
	p += FDFS_PROTO_PKG_LEN_SIZE;

	if (dest_filename_len < 0 || dest_filename_len >= sizeof(dest_filename))
	{
		logError("file: "__FILE__", line: %d, "
			"client ip: %s, in request pkg, "
			"filename length: %d is invalid, "
			"which < 0 or >= %d", __LINE__, pTask->client_ip,
			dest_filename_len, (int)sizeof(dest_filename));
		return EINVAL;
	}

	pFileContext->timestamp2log = buff2int(p);
	p += 4;

	memcpy(group_name, p, FDFS_GROUP_NAME_MAX_LEN);
	*(group_name + FDFS_GROUP_NAME_MAX_LEN) = '\0';
	p += FDFS_GROUP_NAME_MAX_LEN;
	if (strcmp(group_name, g_group_name) != 0)
	{
		logError("file: "__FILE__", line: %d, "
			"client ip:%s, group_name: %s "
			"not correct, should be: %s",
			__LINE__, pTask->client_ip,
			group_name, g_group_name);
		return EINVAL;
	}

	if (nInPackLen != 2 * FDFS_PROTO_PKG_LEN_SIZE + 4 +
		FDFS_GROUP_NAME_MAX_LEN + dest_filename_len + src_filename_len)
	{
		logError("file: "__FILE__", line: %d, "
			"client ip: %s, in request pkg, "
			"pgk length: %"PRId64" != bytes: %d",
            __LINE__, pTask->client_ip,
			nInPackLen, 2 * FDFS_PROTO_PKG_LEN_SIZE +
			FDFS_GROUP_NAME_MAX_LEN + dest_filename_len +
			src_filename_len);
		return EINVAL;
	}

	memcpy(dest_filename, p, dest_filename_len);
	*(dest_filename + dest_filename_len) = '\0';
	p += dest_filename_len;

	memcpy(src_filename, p, src_filename_len);
	*(src_filename + src_filename_len) = '\0';

    if ((result=storage_logic_to_local_full_filename(
                    dest_filename, dest_filename_len,
                    &dest_store_path_index, dest_full_filename,
                    sizeof(dest_full_filename))) != 0)
	{
		return result;
	}

    if (access(dest_full_filename, F_OK) == 0)
    {
        logDebug("file: "__FILE__", line: %d, "
                "client ip: %s, dest file: %s "
                "already exist", __LINE__,
                pTask->client_ip, dest_full_filename);
        return EEXIST;
    }

    if ((result=storage_logic_to_local_full_filename(
                    src_filename, src_filename_len,
                    &src_store_path_index, src_full_filename,
                    sizeof(src_full_filename))) != 0)
	{
		return result;
	}

	if (rename(src_full_filename, dest_full_filename) != 0)
	{
		result = errno != 0 ? errno : EPERM;
		logWarning("file: "__FILE__", line: %d, "
			"client ip: %s, rename %s to %s fail, "
			"errno: %d, error info: %s", __LINE__,
			pTask->client_ip, src_full_filename,
            dest_full_filename, result, STRERROR(result));
		return result;
	}

	return storage_binlog_write_ex(pFileContext->timestamp2log,
            STORAGE_OP_TYPE_REPLICA_RENAME_FILE,
            dest_filename, src_filename);
}

/**
pkg format:
Header
FDFS_GROUP_NAME_MAX_LEN bytes: group_name
filename
**/
static int storage_server_get_metadata(struct fast_task_info *pTask)
{
	StorageClientInfo *pClientInfo;
	StorageFileContext *pFileContext;
	char *p;
	int result;
	int store_path_index;
	char group_name[FDFS_GROUP_NAME_MAX_LEN + 1];
	char true_filename[128];
	struct stat stat_buf;
	FDFSTrunkFullInfo trunkInfo;
	FDFSTrunkHeader trunkHeader;
	char *filename;
	int filename_len;
	int64_t file_bytes;
	int64_t nInPackLen;

	pClientInfo = (StorageClientInfo *)pTask->arg;
	pFileContext =  &(pClientInfo->file_context);

	nInPackLen = pClientInfo->total_length - sizeof(TrackerHeader);
	if (nInPackLen <= FDFS_GROUP_NAME_MAX_LEN)
	{
		logError("file: "__FILE__", line: %d, " \
			"cmd=%d, client ip: %s, package size " \
			"%"PRId64" is not correct, " \
			"expect length > %d", __LINE__, \
			STORAGE_PROTO_CMD_GET_METADATA, \
			pTask->client_ip, nInPackLen, FDFS_GROUP_NAME_MAX_LEN);
		return EINVAL;
	}

	if (nInPackLen >= pTask->size)
	{
		logError("file: "__FILE__", line: %d, " \
				"cmd=%d, client ip: %s, package size " \
				"%"PRId64" is too large, " \
				"expect length should < %d", __LINE__, \
				STORAGE_PROTO_CMD_GET_METADATA, \
				pTask->client_ip,  \
				nInPackLen, pTask->size);
		return EINVAL;
	}

	p = pTask->data + sizeof(TrackerHeader);

	memcpy(group_name, p, FDFS_GROUP_NAME_MAX_LEN);
	*(group_name + FDFS_GROUP_NAME_MAX_LEN) = '\0';
	p += FDFS_GROUP_NAME_MAX_LEN;
	if (strcmp(group_name, g_group_name) != 0)
	{
		logError("file: "__FILE__", line: %d, " \
			"client ip:%s, group_name: %s " \
			"not correct, should be: %s", \
			__LINE__, pTask->client_ip, \
			group_name, g_group_name);
		return EINVAL;
	}

	filename = p;
	filename_len = nInPackLen - FDFS_GROUP_NAME_MAX_LEN;
	*(filename + filename_len) = '\0';

	STORAGE_ACCESS_STRCPY_FNAME2LOG(filename, filename_len, \
			pClientInfo);

	if ((result=storage_split_filename_ex(filename, \
		&filename_len, true_filename, &store_path_index)) != 0)
	{
		return result;
	}
	if ((result=fdfs_check_data_filename(true_filename, \
			filename_len)) != 0)
	{
		return result;
	}

	if ((result=trunk_file_stat(store_path_index, \
		true_filename, filename_len, &stat_buf, \
		&trunkInfo, &trunkHeader)) != 0)
	{
		STORAGE_STAT_FILE_FAIL_LOG(result, pTask->client_ip,
			"logic", filename)
		return result;
	}

	sprintf(pFileContext->filename, "%s/data/%s%s", \
			g_fdfs_store_paths.paths[store_path_index].path, \
			true_filename, FDFS_STORAGE_META_FILE_EXT);
	if (lstat(pFileContext->filename, &stat_buf) == 0)
	{
		if (!S_ISREG(stat_buf.st_mode))
		{
			logError("file: "__FILE__", line: %d, " \
				"%s is not a regular file", \
				__LINE__, pFileContext->filename);
			return EISDIR;
		}

		file_bytes = stat_buf.st_size;
	}
	else
	{
		result = errno != 0 ? errno : ENOENT;
		STORAGE_STAT_FILE_FAIL_LOG(result, pTask->client_ip,
			"regular", pFileContext->filename)
		return result;
	}

	pFileContext->fd = -1;
	pFileContext->calc_crc32 = false;
    pFileContext->continue_callback = storage_nio_notify;
	return storage_read_from_file(pTask, 0, file_bytes, \
			storage_get_metadata_done_callback, store_path_index);
}

/**
pkg format:
Header
8 bytes: file offset
8 bytes: download file bytes
FDFS_GROUP_NAME_MAX_LEN bytes: group_name
filename
**/
static int storage_server_download_file(struct fast_task_info *pTask)
{
	StorageClientInfo *pClientInfo;
	StorageFileContext *pFileContext;
	char *p;
	int result;
	int store_path_index;
	char group_name[FDFS_GROUP_NAME_MAX_LEN + 1];
	char true_filename[128];
	char *filename;
	int filename_len;
	int64_t file_offset;
	int64_t download_bytes;
	int64_t file_bytes;
	struct stat stat_buf;
	int64_t nInPackLen;
	FDFSTrunkFullInfo trunkInfo;
	FDFSTrunkHeader trunkHeader;

	pClientInfo = (StorageClientInfo *)pTask->arg;
	pFileContext =  &(pClientInfo->file_context);

	nInPackLen = pClientInfo->total_length - sizeof(TrackerHeader);
	if (nInPackLen <= 16 + FDFS_GROUP_NAME_MAX_LEN)
	{
		logError("file: "__FILE__", line: %d, " \
			"cmd=%d, client ip: %s, package size " \
			"%"PRId64" is not correct, " \
			"expect length > %d", __LINE__, \
			STORAGE_PROTO_CMD_DOWNLOAD_FILE, \
			pTask->client_ip,  \
			nInPackLen, 16 + FDFS_GROUP_NAME_MAX_LEN);
		return EINVAL;
	}

	if (nInPackLen >= pTask->size)
	{
		logError("file: "__FILE__", line: %d, " \
			"cmd=%d, client ip: %s, package size " \
			"%"PRId64" is too large, " \
			"expect length should < %d", __LINE__, \
			STORAGE_PROTO_CMD_DOWNLOAD_FILE, \
			pTask->client_ip,  \
			nInPackLen, pTask->size);
		return EINVAL;
	}

	p = pTask->data + sizeof(TrackerHeader);

	file_offset = buff2long(p);
	p += FDFS_PROTO_PKG_LEN_SIZE;
	download_bytes = buff2long(p);
	p += FDFS_PROTO_PKG_LEN_SIZE;
	if (file_offset < 0)
	{
		logError("file: "__FILE__", line: %d, " \
			"client ip:%s, invalid file offset: " \
			"%"PRId64,  __LINE__, \
			pTask->client_ip, file_offset);
		return EINVAL;
	}
	if (download_bytes < 0)
	{
		logError("file: "__FILE__", line: %d, " \
			"client ip:%s, invalid download file bytes: " \
			"%"PRId64,  __LINE__, \
			pTask->client_ip, download_bytes);
		return EINVAL;
	}

	memcpy(group_name, p, FDFS_GROUP_NAME_MAX_LEN);
	*(group_name + FDFS_GROUP_NAME_MAX_LEN) = '\0';
	p += FDFS_GROUP_NAME_MAX_LEN;
	if (strcmp(group_name, g_group_name) != 0)
	{
		logError("file: "__FILE__", line: %d, " \
			"client ip:%s, group_name: %s " \
			"not correct, should be: %s", \
			__LINE__, pTask->client_ip, \
			group_name, g_group_name);
		return EINVAL;
	}

	filename = p;
	filename_len = nInPackLen - (16 + FDFS_GROUP_NAME_MAX_LEN);
	*(filename + filename_len) = '\0';

	STORAGE_ACCESS_STRCPY_FNAME2LOG(filename, filename_len, \
			pClientInfo);

	if ((result=storage_split_filename_ex(filename, \
		&filename_len, true_filename, &store_path_index)) != 0)
	{
		return result;
	}
	if ((result=fdfs_check_data_filename(true_filename, filename_len)) != 0)
	{
		return result;
	}

	pFileContext->fd = -1;
	result = trunk_file_stat_ex(store_path_index, \
		true_filename, filename_len, &stat_buf, \
		&trunkInfo, &trunkHeader, &pFileContext->fd);
	if (IS_TRUNK_FILE_BY_ID(trunkInfo))
	{
        __sync_add_and_fetch(&g_storage_stat.total_file_open_count, 1);
	}
	if (result == 0)
	{
		if (!S_ISREG(stat_buf.st_mode))
		{
			logError("file: "__FILE__", line: %d, " \
				"logic file %s is not a regular file", \
				__LINE__, filename);
			return EISDIR;
		}

		file_bytes = stat_buf.st_size;
	}
	else
	{
		STORAGE_STAT_FILE_FAIL_LOG(result, pTask->client_ip,
			"logic", filename)
		file_bytes = 0;
		return result;
	}

	if (IS_TRUNK_FILE_BY_ID(trunkInfo))
	{
        __sync_add_and_fetch(&g_storage_stat.success_file_open_count, 1);
	}

	if (download_bytes == 0)
	{
		download_bytes  = file_bytes - file_offset;
	}
	else if (download_bytes > file_bytes - file_offset)
	{
		logError("file: "__FILE__", line: %d, " \
			"client ip:%s, invalid download file bytes: " \
			"%"PRId64" > file remain bytes: " \
			"%"PRId64,  __LINE__, \
			pTask->client_ip, download_bytes, \
			file_bytes - file_offset);
		if (pFileContext->fd >= 0)
		{
			close(pFileContext->fd);
		}
		return EINVAL;
	}

	if (IS_TRUNK_FILE_BY_ID(trunkInfo))
	{
		trunk_get_full_filename((&trunkInfo), pFileContext->filename, \
				sizeof(pFileContext->filename));
		file_offset += TRUNK_FILE_START_OFFSET(trunkInfo);
	}
	else
	{
		sprintf(pFileContext->filename, "%s/data/%s", \
			g_fdfs_store_paths.paths[store_path_index].path, true_filename);
	}

	pFileContext->calc_crc32 = false;
    pFileContext->continue_callback = storage_nio_notify;
	return storage_read_from_file(pTask, file_offset, download_bytes, \
			storage_download_file_done_callback, store_path_index);
}

static int storage_do_delete_file(struct fast_task_info *pTask, \
		DeleteFileLogCallback log_callback, \
		FileDealDoneCallback done_callback, \
		const int store_path_index)
{
	StorageClientInfo *pClientInfo;
	StorageFileContext *pFileContext;
	int result;

	pClientInfo = (StorageClientInfo *)pTask->arg;
	pFileContext =  &(pClientInfo->file_context);

	pFileContext->fd = -1;
	pFileContext->op = FDFS_STORAGE_FILE_OP_DELETE;
	pFileContext->dio_thread_index = storage_dio_get_thread_index( \
		pTask, store_path_index, pFileContext->op);
	pFileContext->log_callback = log_callback;
	pFileContext->done_callback = done_callback;

	if ((result=storage_dio_queue_push(pTask)) != 0)
	{
		return result;
	}

	return TASK_STATUS_CONTINUE;
}

static int storage_read_from_file(struct fast_task_info *pTask, \
		const int64_t file_offset, const int64_t download_bytes, \
		FileDealDoneCallback done_callback, \
		const int store_path_index)
{
	StorageClientInfo *pClientInfo;
	StorageFileContext *pFileContext;
	TrackerHeader *pHeader;
	int result;

	pClientInfo = (StorageClientInfo *)pTask->arg;
	pFileContext =  &(pClientInfo->file_context);

	pClientInfo->deal_func = dio_read_file;
	pClientInfo->clean_func = dio_read_finish_clean_up;
	pClientInfo->total_length = sizeof(TrackerHeader) + download_bytes;
	pClientInfo->total_offset = 0;

	pFileContext->op = FDFS_STORAGE_FILE_OP_READ;
	pFileContext->open_flags = O_RDONLY | g_extra_open_file_flags;
	pFileContext->offset = file_offset;
	pFileContext->start = file_offset;
	pFileContext->end = file_offset + download_bytes;
	pFileContext->dio_thread_index = storage_dio_get_thread_index( \
		pTask, store_path_index, pFileContext->op);
	pFileContext->done_callback = done_callback;

	pTask->length = sizeof(TrackerHeader);

	pHeader = (TrackerHeader *)pTask->data;
	pHeader->status = 0;
	pHeader->cmd = STORAGE_PROTO_CMD_RESP;
	long2buff(download_bytes, pHeader->pkg_len);

	if (pFileContext->calc_crc32)
	{
		pFileContext->crc32 = CRC32_XINIT;
	}
	if ((result=storage_dio_queue_push(pTask)) != 0)
	{
		if (pFileContext->fd >= 0)
		{
			close(pFileContext->fd);
		}
		return result;
	}

	return TASK_STATUS_CONTINUE;
}

static int storage_write_to_file(struct fast_task_info *pTask, \
		const int64_t file_offset, const int64_t upload_bytes, \
		const int buff_offset, TaskDealFunc deal_func, \
		FileDealDoneCallback done_callback, \
		DisconnectCleanFunc clean_func, const int store_path_index)
{
	StorageClientInfo *pClientInfo;
	StorageFileContext *pFileContext;
	int result;

	pClientInfo = (StorageClientInfo *)pTask->arg;
	pFileContext =  &(pClientInfo->file_context);

	pClientInfo->deal_func = deal_func;
	pClientInfo->clean_func = clean_func;

	pFileContext->fd = -1;
	pFileContext->buff_offset = buff_offset;
	pFileContext->offset = file_offset;
	pFileContext->start = file_offset;
	pFileContext->end = file_offset + upload_bytes;
	pFileContext->dio_thread_index = storage_dio_get_thread_index( \
		pTask, store_path_index, pFileContext->op);
	pFileContext->done_callback = done_callback;

	if (pFileContext->calc_crc32)
	{
		pFileContext->crc32 = CRC32_XINIT;
	}

	if (pFileContext->calc_file_hash)
	{
		if (g_file_signature_method == STORAGE_FILE_SIGNATURE_METHOD_HASH)
		{
			INIT_HASH_CODES4(pFileContext->file_hash_codes)
		}
		else
		{
			my_md5_init(&pFileContext->md5_context);
		}
	}

	if ((result=storage_dio_queue_push(pTask)) != 0)
	{
		return result;
	}

	return TASK_STATUS_CONTINUE;
}

/**
pkg format:
Header
4 bytes: source delete timestamp
FDFS_GROUP_NAME_MAX_LEN bytes: group_name
filename
**/
static int storage_sync_delete_file(struct fast_task_info *pTask)
{
	StorageClientInfo *pClientInfo;
	StorageFileContext *pFileContext;
	char *p;
	FDFSTrunkHeader trunkHeader;
	struct stat stat_buf;
	char group_name[FDFS_GROUP_NAME_MAX_LEN + 1];
	char true_filename[128];
	char *filename;
	int filename_len;
	int result;
	int store_path_index;
	int64_t nInPackLen;

	pClientInfo = (StorageClientInfo *)pTask->arg;
	pFileContext =  &(pClientInfo->file_context);

	nInPackLen = pClientInfo->total_length - sizeof(TrackerHeader);
	pClientInfo->total_length = sizeof(TrackerHeader);

	if (nInPackLen <= 4 + FDFS_GROUP_NAME_MAX_LEN)
	{
		logError("file: "__FILE__", line: %d, " \
			"cmd=%d, client ip: %s, package size " \
			"%"PRId64" is not correct, " \
			"expect length <= %d", __LINE__, \
			STORAGE_PROTO_CMD_SYNC_DELETE_FILE, \
			pTask->client_ip,  \
			nInPackLen, 4 + FDFS_GROUP_NAME_MAX_LEN);
		return EINVAL;
	}

	if (nInPackLen >= pTask->size)
	{
		logError("file: "__FILE__", line: %d, " \
			"cmd=%d, client ip: %s, package size " \
			"%"PRId64" is too large, " \
			"expect length should < %d", __LINE__, \
			STORAGE_PROTO_CMD_SYNC_DELETE_FILE, \
			pTask->client_ip,  nInPackLen, pTask->size);
		return EINVAL;
	}

	p = pTask->data + sizeof(TrackerHeader);
	pFileContext->timestamp2log = buff2int(p);
	p += 4;
	memcpy(group_name, p, FDFS_GROUP_NAME_MAX_LEN);
	*(group_name + FDFS_GROUP_NAME_MAX_LEN) = '\0';
	p += FDFS_GROUP_NAME_MAX_LEN;
	if (strcmp(group_name, g_group_name) != 0)
	{
		logError("file: "__FILE__", line: %d, " \
			"client ip:%s, group_name: %s " \
			"not correct, should be: %s", \
			__LINE__, pTask->client_ip, \
			group_name, g_group_name);
		return EINVAL;
	}

	filename = p;
	filename_len = nInPackLen - (4 + FDFS_GROUP_NAME_MAX_LEN);
	*(filename + filename_len) = '\0';
	if ((result=storage_split_filename_ex(filename, \
		&filename_len, true_filename, &store_path_index)) != 0)
	{
		return result;
	}
	if ((result=fdfs_check_data_filename(true_filename, filename_len)) != 0)
	{
		return result;
	}

	if ((result=trunk_file_lstat(store_path_index, true_filename, \
			filename_len, &stat_buf, \
			&(pFileContext->extra_info.upload.trunk_info), \
			&trunkHeader)) != 0)
	{
		STORAGE_STAT_FILE_FAIL_LOG(result, pTask->client_ip,
			"logic", filename)
		return result;
	}
	if (S_ISREG(stat_buf.st_mode))
	{
		pFileContext->delete_flag = STORAGE_DELETE_FLAG_FILE;
	}
	else if (S_ISLNK(stat_buf.st_mode))
	{
		pFileContext->delete_flag = STORAGE_DELETE_FLAG_LINK;
	}
	else
	{
		logError("file: "__FILE__", line: %d, " \
			"client ip: %s, logic file %s is NOT a file", \
			__LINE__, pTask->client_ip, filename);
		return EINVAL;
	}

	if (IS_TRUNK_FILE_BY_ID(pFileContext->extra_info.upload.trunk_info))
	{
		pClientInfo->deal_func = dio_delete_trunk_file;
		trunk_get_full_filename((&pFileContext->extra_info.upload.\
				trunk_info), pFileContext->filename, \
				sizeof(pFileContext->filename));
	}
	else
	{
		pClientInfo->deal_func = dio_delete_normal_file;
		sprintf(pFileContext->filename, "%s/data/%s", \
			g_fdfs_store_paths.paths[store_path_index].path, true_filename);
	}

	strcpy(pFileContext->fname2log, filename);
	pFileContext->sync_flag = STORAGE_OP_TYPE_REPLICA_DELETE_FILE;
	return storage_do_delete_file(pTask, storage_sync_delete_file_log_error, \
		storage_sync_delete_file_done_callback, store_path_index);
}

/**
pkg format:
Header
FDFS_GROUP_NAME_MAX_LEN bytes: group_name
filename
**/
static int storage_server_delete_file(struct fast_task_info *pTask)
{
	StorageClientInfo *pClientInfo;
	StorageFileContext *pFileContext;
	char *p;
	FDFSTrunkHeader trunkHeader;
	char group_name[FDFS_GROUP_NAME_MAX_LEN + 1];
	char true_filename[128];
	char *filename;
	int filename_len;
	int true_filename_len;
	struct stat stat_buf;
	int result;
	int store_path_index;
	int64_t nInPackLen;

	pClientInfo = (StorageClientInfo *)pTask->arg;
	pFileContext =  &(pClientInfo->file_context);

	nInPackLen = pClientInfo->total_length - sizeof(TrackerHeader);
	pClientInfo->total_length = sizeof(TrackerHeader);

	pFileContext->delete_flag = STORAGE_DELETE_FLAG_NONE;
	if (nInPackLen <= FDFS_GROUP_NAME_MAX_LEN)
	{
		logError("file: "__FILE__", line: %d, " \
			"cmd=%d, client ip: %s, package size " \
			"%"PRId64" is not correct, " \
			"expect length <= %d", __LINE__, \
			STORAGE_PROTO_CMD_DELETE_FILE, \
			pTask->client_ip,  \
			nInPackLen, FDFS_GROUP_NAME_MAX_LEN);
		return EINVAL;
	}

	if (nInPackLen >= pTask->size)
	{
		logError("file: "__FILE__", line: %d, " \
			"cmd=%d, client ip: %s, package size " \
			"%"PRId64" is too large, " \
			"expect length should < %d", __LINE__, \
			STORAGE_PROTO_CMD_DELETE_FILE, \
			pTask->client_ip,  nInPackLen, pTask->size);
		return EINVAL;
	}

	p = pTask->data + sizeof(TrackerHeader);
	memcpy(group_name, p, FDFS_GROUP_NAME_MAX_LEN);
	*(group_name + FDFS_GROUP_NAME_MAX_LEN) = '\0';
	p += FDFS_GROUP_NAME_MAX_LEN;
	if (strcmp(group_name, g_group_name) != 0)
	{
		logError("file: "__FILE__", line: %d, " \
			"client ip:%s, group_name: %s " \
			"not correct, should be: %s", \
			__LINE__, pTask->client_ip, \
			group_name, g_group_name);
		return EINVAL;
	}

	filename = p;
	filename_len = nInPackLen - FDFS_GROUP_NAME_MAX_LEN;
	*(filename + filename_len) = '\0';

	STORAGE_ACCESS_STRCPY_FNAME2LOG(filename, filename_len, \
		pClientInfo);

	true_filename_len = filename_len;
	if ((result=storage_split_filename_ex(filename, \
		&true_filename_len, true_filename, &store_path_index)) != 0)
	{
		return result;
	}
	if ((result=fdfs_check_data_filename(true_filename, \
				true_filename_len)) != 0)
	{
		return result;
	}

	if ((result=trunk_file_lstat(store_path_index, true_filename, \
			true_filename_len, &stat_buf, \
			&(pFileContext->extra_info.upload.trunk_info), \
			&trunkHeader)) != 0)
	{
		STORAGE_STAT_FILE_FAIL_LOG(result, pTask->client_ip,
			"logic", filename)
		return result;
	}
	if (S_ISREG(stat_buf.st_mode))
	{
		pFileContext->extra_info.upload.file_type = \
					_FILE_TYPE_REGULAR;
		pFileContext->delete_flag |= STORAGE_DELETE_FLAG_FILE;
	}
	else if (S_ISLNK(stat_buf.st_mode))
	{
		pFileContext->extra_info.upload.file_type = _FILE_TYPE_LINK;
		pFileContext->delete_flag |= STORAGE_DELETE_FLAG_LINK;
	}
	else
	{
		logError("file: "__FILE__", line: %d, " \
			"client ip: %s, file %s is NOT a file", \
			__LINE__, pTask->client_ip, \
			pFileContext->filename);
		return EINVAL;
	}

	if (IS_TRUNK_FILE_BY_ID(pFileContext->extra_info.upload.trunk_info))
	{
		pFileContext->extra_info.upload.file_type |= _FILE_TYPE_TRUNK;
		pClientInfo->deal_func = dio_delete_trunk_file;
		trunk_get_full_filename((&pFileContext->extra_info.upload.\
				trunk_info), pFileContext->filename, \
				sizeof(pFileContext->filename));
	}
	else
	{
		pClientInfo->deal_func = dio_delete_normal_file;
		sprintf(pFileContext->filename, "%s/data/%s", \
			g_fdfs_store_paths.paths[store_path_index].path, true_filename);
	}

	if ((pFileContext->extra_info.upload.file_type & _FILE_TYPE_LINK) && \
		storage_is_slave_file(filename, filename_len))
	{
		char full_filename[MAX_PATH_SIZE + 128];
		char src_filename[MAX_PATH_SIZE + 128];
		char src_fname2log[128];
		char *src_true_filename;
		int src_filename_len;
		int src_store_path_index;
		int i;

		sprintf(full_filename, "%s/data/%s", \
			g_fdfs_store_paths.paths[store_path_index].path, true_filename);
		do
		{
			if ((src_filename_len=readlink(full_filename, \
				src_filename, sizeof(src_filename))) < 0)
			{
				result = errno != 0 ? errno : EPERM;
				logError("file: "__FILE__", line: %d, " \
					"client ip:%s, call readlink file %s " \
					"fail, errno: %d, error info: %s", \
					__LINE__, pTask->client_ip, \
					true_filename, result, STRERROR(result));
				return result;
			}

			*(src_filename + src_filename_len) = '\0';
			if (unlink(src_filename) != 0)
			{
				result = errno != 0 ? errno : ENOENT;
				logWarning("file: "__FILE__", line: %d, " \
					"client ip:%s, unlink file %s " \
					"fail, errno: %d, error info: %s", \
					__LINE__, pTask->client_ip, \
					src_filename, result, STRERROR(result));
				if (result == ENOENT)
				{
					break;
				}
				return result;
			}

			if (src_filename_len > g_fdfs_store_paths.paths
                    [store_path_index].path_len && memcmp(
                        src_filename, g_fdfs_store_paths.paths
                        [store_path_index].path, g_fdfs_store_paths.
                        paths[store_path_index].path_len) == 0)
			{
				src_store_path_index = store_path_index;
			}
			else
			{
			src_store_path_index = -1;
			for (i=0; i<g_fdfs_store_paths.count; i++)
			{
				if (src_filename_len > g_fdfs_store_paths.paths[i].path_len &&
					memcmp(src_filename, g_fdfs_store_paths.paths
					[i].path, g_fdfs_store_paths.paths[i].path_len) == 0)
				{
					src_store_path_index = i;
					break;
				}
			}
			if (src_store_path_index < 0)
			{
				logWarning("file: "__FILE__", line: %d, " \
					"client ip:%s, can't get store base " \
					"path of file %s", __LINE__, \
					pTask->client_ip, src_filename);
				break;
			}
			}

			src_true_filename = src_filename + (g_fdfs_store_paths.
                    paths[src_store_path_index].path_len +
                    (sizeof("/data/") -1));
			snprintf(src_fname2log, sizeof(src_fname2log), \
				"%c"FDFS_STORAGE_DATA_DIR_FORMAT"/%s", \
				FDFS_STORAGE_STORE_PATH_PREFIX_CHAR, \
				src_store_path_index, src_true_filename);
			storage_binlog_write(g_current_time, \
				STORAGE_OP_TYPE_SOURCE_DELETE_FILE, \
				src_fname2log);
		} while (0);
	}

	strcpy(pFileContext->fname2log, filename);
	return storage_do_delete_file(pTask, storage_delete_file_log_error, \
			storage_delete_fdfs_file_done_callback, \
			store_path_index);
}

static int storage_create_link_core(struct fast_task_info *pTask, \
		SourceFileInfo *pSourceFileInfo, \
		const char *src_filename, const char *master_filename, \
		const int master_filename_len, \
		const char *prefix_name, const char *file_ext_name, \
		char *filename, int *filename_len, const bool bNeedReponse)
{
	StorageClientInfo *pClientInfo;
	StorageFileContext *pFileContext;
	FDFSTrunkFullInfo *pTrunkInfo;
	int result;
	struct stat stat_buf;
	char true_filename[128];
	char full_filename[MAX_PATH_SIZE];
	char binlog_buff[256];
	int store_path_index;
	FDFSTrunkHeader trunk_header;

	pClientInfo = (StorageClientInfo *)pTask->arg;
	pFileContext =  &(pClientInfo->file_context);
	store_path_index = pFileContext->extra_info.
				upload.trunk_info.path.store_path_index;

	do
	{
	pTrunkInfo = &(pFileContext->extra_info.upload.trunk_info);
	result = trunk_file_lstat(store_path_index, \
			pSourceFileInfo->src_true_filename, \
			strlen(pSourceFileInfo->src_true_filename), \
			&stat_buf, pTrunkInfo, &trunk_header);
	if (result != 0 || !S_ISREG(stat_buf.st_mode))
	{
		FDHTKeyInfo key_info;
		GroupArray *pGroupArray;

		result = result != 0 ? result : EINVAL;
		logError("file: "__FILE__", line: %d, " \
				"client ip: %s, logic file: %s call stat fail "\
				"or it is not a regular file, " \
				"errno: %d, error info: %s", \
				__LINE__, pTask->client_ip, \
				src_filename, result, STRERROR(result));
		if (g_check_file_duplicate)
		{
            pGroupArray = pTask->thread_data->arg;
			//clean invalid entry
			memset(&key_info, 0, sizeof(key_info));
			key_info.namespace_len = g_namespace_len;
			memcpy(key_info.szNameSpace, g_key_namespace, \
					g_namespace_len);

			key_info.obj_id_len = pSourceFileInfo->src_file_sig_len;
			memcpy(key_info.szObjectId, pSourceFileInfo->src_file_sig,
					key_info.obj_id_len);
			key_info.key_len = sizeof(FDHT_KEY_NAME_FILE_ID) - 1;
			memcpy(key_info.szKey, FDHT_KEY_NAME_FILE_ID, \
					sizeof(FDHT_KEY_NAME_FILE_ID) - 1);
			fdht_delete_ex(pGroupArray, g_keep_alive, &key_info);

			key_info.obj_id_len = snprintf(key_info.szObjectId, \
					sizeof(key_info.szObjectId), "%s/%s", \
					g_group_name, src_filename);
			key_info.key_len = sizeof(FDHT_KEY_NAME_REF_COUNT) - 1;
			memcpy(key_info.szKey, FDHT_KEY_NAME_REF_COUNT, \
					key_info.key_len);
			fdht_delete_ex(pGroupArray, g_keep_alive, &key_info);
		}

		break;
	}

	if (master_filename_len == 0 && IS_TRUNK_FILE_BY_ID((*pTrunkInfo)))
	{
		if (!g_if_use_trunk_file)
		{
			logError("file: "__FILE__", line: %d, " \
				"client ip: %s, invalid trunked src file: %s, "\
				"because i don't support trunked file!", \
				__LINE__, pTask->client_ip, src_filename);
			result = EINVAL;
			break;
		}

		pFileContext->extra_info.upload.file_type |= _FILE_TYPE_TRUNK;
	}

	if (master_filename_len > 0)
	{
		int master_store_path_index;

		*filename_len = master_filename_len;
		if ((result=storage_split_filename_ex( \
			master_filename, filename_len, true_filename, \
			&master_store_path_index)) != 0)
		{
			break;
		}

		if (master_store_path_index != store_path_index)
		{
			logError("file: "__FILE__", line: %d, " \
				"client ip:%s, invalid master store " \
				"path index: %d != source store path " \
				"index: %d", __LINE__, pTask->client_ip, \
				master_store_path_index, store_path_index);
			result = EINVAL;
			break;
		}

		if ((result=fdfs_check_data_filename(true_filename, \
					*filename_len)) != 0)
		{
			break;
		}

		if ((result=fdfs_gen_slave_filename( \
			true_filename, prefix_name, file_ext_name, \
			filename, filename_len)) != 0)
		{
			break;
		}

		snprintf(full_filename, sizeof(full_filename), \
			"%s/data/%s", g_fdfs_store_paths.paths[store_path_index].path, \
			filename);
		if (fileExists(full_filename))
		{
			logError("file: "__FILE__", line: %d, " \
				"client ip: %s, slave file: %s " \
				"already exist", __LINE__, \
				pTask->client_ip, full_filename);
			result = EEXIST;
			break;
		}
	}
	else
	{
		*filename = '\0';
		*filename_len = 0;
	}

	pFileContext->extra_info.upload.file_type |= _FILE_TYPE_LINK;
	pClientInfo->file_context.extra_info.upload.trunk_info.path. \
			store_path_index = store_path_index;
	if (pFileContext->extra_info.upload.file_type & _FILE_TYPE_TRUNK)
	{
	pFileContext->calc_crc32 = false;
	pFileContext->calc_file_hash = false;
	pFileContext->extra_info.upload.if_gen_filename = true;
	pFileContext->extra_info.upload.start_time = g_current_time;
	pFileContext->crc32 = rand();
	strcpy(pFileContext->extra_info.upload.file_ext_name, file_ext_name);
	storage_format_ext_name(file_ext_name, \
			pFileContext->extra_info.upload.formatted_ext_name);
	return storage_trunk_create_link(pTask, src_filename, \
			pSourceFileInfo, bNeedReponse);
	}

	pClientInfo->file_context.extra_info.upload.if_sub_path_alloced = false;
	result = storage_service_do_create_link(pTask, pSourceFileInfo, \
			stat_buf.st_size, master_filename, \
			prefix_name, file_ext_name, filename, filename_len);
	if (result != 0)
	{
		break;
	}

	snprintf(binlog_buff, sizeof(binlog_buff), "%s %s", \
		filename, src_filename);
	result = storage_binlog_write(g_current_time, \
			STORAGE_OP_TYPE_SOURCE_CREATE_LINK, binlog_buff);
	} while (0);

	if (result == 0)
	{
		CHECK_AND_WRITE_TO_STAT_FILE3( \
			g_storage_stat.total_create_link_count, \
			g_storage_stat.success_create_link_count, \
			g_storage_stat.last_source_update)
	}
	else
	{
        __sync_add_and_fetch(&g_storage_stat.total_create_link_count, 1);
	}

	return result;
}

/**
pkg format:
Header
8 bytes: master filename len
8 bytes: source filename len
8 bytes: source file signature len
FDFS_GROUP_NAME_MAX_LEN bytes: group_name
FDFS_FILE_PREFIX_MAX_LEN bytes  : filename prefix, can be empty
FDFS_FILE_EXT_NAME_MAX_LEN bytes: file ext name, do not include dot (.)
master filename len: master filename
source filename len: source filename
source file signature len: source file signature
**/
static int storage_do_create_link(struct fast_task_info *pTask)
{
	StorageClientInfo *pClientInfo;
	TrackerHeader *pHeader;
	char *p;
	char group_name[FDFS_GROUP_NAME_MAX_LEN + 1];
	char prefix_name[FDFS_FILE_PREFIX_MAX_LEN + 1];
	char file_ext_name[FDFS_FILE_EXT_NAME_MAX_LEN + 1];
	char src_filename[128];
	char master_filename[128];
	char filename[128];
	int src_filename_len;
	int master_filename_len;
	int filename_len;
	int len;
	int result;
	int store_path_index;
	SourceFileInfo sourceFileInfo;
	int64_t nInPackLen;

	pClientInfo = (StorageClientInfo *)pTask->arg;

	nInPackLen = pClientInfo->total_length - sizeof(TrackerHeader);
	pClientInfo->total_length = sizeof(TrackerHeader);

	do
	{
	if (nInPackLen <= 3 * FDFS_PROTO_PKG_LEN_SIZE + \
		FDFS_GROUP_NAME_MAX_LEN + FDFS_FILE_PREFIX_MAX_LEN + \
		FDFS_FILE_EXT_NAME_MAX_LEN)
	{
		logError("file: "__FILE__", line: %d, " \
			"cmd=%d, client ip: %s, package size " \
			"%"PRId64" is not correct, " \
			"expect length > %d", __LINE__, \
			STORAGE_PROTO_CMD_CREATE_LINK, pTask->client_ip, \
			 nInPackLen, 4 * FDFS_PROTO_PKG_LEN_SIZE + \
			FDFS_GROUP_NAME_MAX_LEN + FDFS_FILE_PREFIX_MAX_LEN + \
			FDFS_FILE_EXT_NAME_MAX_LEN);
		result = EINVAL;
		break;
	}

	p = pTask->data + sizeof(TrackerHeader);
	master_filename_len = buff2long(p);
	p += FDFS_PROTO_PKG_LEN_SIZE;
	src_filename_len = buff2long(p);
	p += FDFS_PROTO_PKG_LEN_SIZE;
	sourceFileInfo.src_file_sig_len = buff2long(p);
	p += FDFS_PROTO_PKG_LEN_SIZE;
	if (master_filename_len < 0 || master_filename_len >= \
			sizeof(master_filename))
	{
		logError("file: "__FILE__", line: %d, " \
			"client ip: %s, pkg length is not correct, " \
			"invalid master filename length: %d", \
			__LINE__, pTask->client_ip, master_filename_len);
		result = EINVAL;
		break;
	}

	if (src_filename_len <= 0 || src_filename_len >= \
			sizeof(src_filename))
	{
		logError("file: "__FILE__", line: %d, " \
			"client ip: %s, pkg length is not correct, " \
			"invalid filename length: %d", \
			__LINE__, pTask->client_ip, src_filename_len);
		result = EINVAL;
		break;
	}

	if (sourceFileInfo.src_file_sig_len <= 0 || \
		sourceFileInfo.src_file_sig_len >= \
			sizeof(sourceFileInfo.src_file_sig))
	{
		logError("file: "__FILE__", line: %d, " \
			"client ip: %s, pkg length is not correct, " \
			"invalid file signature length: %d", \
			__LINE__, pTask->client_ip, \
			sourceFileInfo.src_file_sig_len);
		result = EINVAL;
		break;
	}

	if (sourceFileInfo.src_file_sig_len != nInPackLen - \
		(3 * FDFS_PROTO_PKG_LEN_SIZE+FDFS_GROUP_NAME_MAX_LEN + \
		 FDFS_FILE_PREFIX_MAX_LEN + FDFS_FILE_EXT_NAME_MAX_LEN +\
		 master_filename_len + src_filename_len))
	{
		logError("file: "__FILE__", line: %d, " \
			"client ip: %s, pkg length is not correct, " \
			"invalid src_file_sig_len : %d", \
			__LINE__, pTask->client_ip, \
			sourceFileInfo.src_file_sig_len);
		result = EINVAL;
		break;
	}

	memcpy(group_name, p, FDFS_GROUP_NAME_MAX_LEN);
	*(group_name + FDFS_GROUP_NAME_MAX_LEN) = '\0';
	p += FDFS_GROUP_NAME_MAX_LEN;
	if (strcmp(group_name, g_group_name) != 0)
	{
		logError("file: "__FILE__", line: %d, " \
			"client ip:%s, group_name: %s " \
			"not correct, should be: %s", \
			__LINE__, pTask->client_ip, \
			group_name, g_group_name);
		result = EINVAL;
		break;
	}

	memcpy(prefix_name, p, FDFS_FILE_PREFIX_MAX_LEN);
	*(prefix_name + FDFS_FILE_PREFIX_MAX_LEN) = '\0';
	p += FDFS_FILE_PREFIX_MAX_LEN;

	memcpy(file_ext_name, p, FDFS_FILE_EXT_NAME_MAX_LEN);
	*(file_ext_name + FDFS_FILE_EXT_NAME_MAX_LEN) = '\0';
	p += FDFS_FILE_EXT_NAME_MAX_LEN;

	len = master_filename_len + src_filename_len + \
	      sourceFileInfo.src_file_sig_len;
	if (len > 256)
	{
		logError("file: "__FILE__", line: %d, " \
			"client ip:%s, invalid pkg length, " \
			"file relative length: %d > %d", \
			__LINE__, pTask->client_ip, len, 256);
		result = EINVAL;
		break;
	}

	if (master_filename_len > 0)
	{
		memcpy(master_filename, p, master_filename_len);
		*(master_filename + master_filename_len) = '\0';
		p += master_filename_len;
	}
	else
	{
		*master_filename = '\0';
	}

	memcpy(src_filename, p, src_filename_len);
	*(src_filename + src_filename_len) = '\0';
	p += src_filename_len;

	memcpy(sourceFileInfo.src_file_sig, p, sourceFileInfo.src_file_sig_len);
	*(sourceFileInfo.src_file_sig + sourceFileInfo.src_file_sig_len) = '\0';

	if ((result=storage_split_filename_ex(src_filename, \
		&src_filename_len, sourceFileInfo.src_true_filename, \
		&store_path_index)) != 0)
	{
		break;
	}
	if ((result=fdfs_check_data_filename( \
		sourceFileInfo.src_true_filename, src_filename_len)) != 0)
	{
		break;
	}

	pClientInfo->file_context.extra_info.upload.trunk_info.path. \
		store_path_index = store_path_index;
	result = storage_create_link_core(pTask, \
			&sourceFileInfo, src_filename, \
			master_filename, master_filename_len, \
			prefix_name, file_ext_name, \
			filename, &filename_len, true);
	if (result == TASK_STATUS_CONTINUE)
	{
		return 0;
	}
	} while (0);

	if (result == 0)
	{
		pClientInfo->total_length += FDFS_GROUP_NAME_MAX_LEN + filename_len;
		p = pTask->data + sizeof(TrackerHeader);
		memcpy(p, g_group_name, FDFS_GROUP_NAME_MAX_LEN);
		memcpy(p + FDFS_GROUP_NAME_MAX_LEN, filename, filename_len);
	}

	pClientInfo->total_offset = 0;
	pTask->length = pClientInfo->total_length;
	pHeader = (TrackerHeader *)pTask->data;
	pHeader->status = result;
	pHeader->cmd = STORAGE_PROTO_CMD_RESP;
	long2buff(pClientInfo->total_length - sizeof(TrackerHeader), \
			pHeader->pkg_len);

	sf_nio_notify(pTask, SF_NIO_STAGE_SEND);
	return result;
}

static int storage_create_link(struct fast_task_info *pTask)
{
	StorageClientInfo *pClientInfo;
	StorageFileContext *pFileContext;
	char *p;
	char src_filename[128];
	char src_true_filename[128];
	int src_filename_len;
	int result;
	int store_path_index;
	int64_t nInPackLen;

	pClientInfo = (StorageClientInfo *)pTask->arg;
	pFileContext =  &(pClientInfo->file_context);

	nInPackLen = pClientInfo->total_length - sizeof(TrackerHeader);

	if (nInPackLen <= 3 * FDFS_PROTO_PKG_LEN_SIZE + \
		FDFS_GROUP_NAME_MAX_LEN + FDFS_FILE_PREFIX_MAX_LEN + \
		FDFS_FILE_EXT_NAME_MAX_LEN)
	{
		logError("file: "__FILE__", line: %d, " \
			"cmd=%d, client ip: %s, package size " \
			"%"PRId64" is not correct, " \
			"expect length > %d", __LINE__, \
			STORAGE_PROTO_CMD_CREATE_LINK, pTask->client_ip, \
			 nInPackLen, 4 * FDFS_PROTO_PKG_LEN_SIZE + \
			FDFS_GROUP_NAME_MAX_LEN + FDFS_FILE_PREFIX_MAX_LEN + \
			FDFS_FILE_EXT_NAME_MAX_LEN);
		return EINVAL;
	}

	p = pTask->data + sizeof(TrackerHeader) + FDFS_PROTO_PKG_LEN_SIZE;
	src_filename_len = buff2long(p);
	if (src_filename_len <= 0 || src_filename_len >= \
			sizeof(src_filename))
	{
		logError("file: "__FILE__", line: %d, " \
			"client ip: %s, pkg length is not correct, " \
			"invalid filename length: %d", \
			__LINE__, pTask->client_ip, src_filename_len);
		return EINVAL;
	}

	p += 2 * FDFS_PROTO_PKG_LEN_SIZE + FDFS_GROUP_NAME_MAX_LEN + \
		FDFS_FILE_PREFIX_MAX_LEN + FDFS_FILE_EXT_NAME_MAX_LEN;
	memcpy(src_filename, p, src_filename_len);
	*(src_filename + src_filename_len) = '\0';

	if ((result=storage_split_filename_ex(src_filename, \
		&src_filename_len, src_true_filename, &store_path_index)) != 0)
	{
		return result;
	}

	pClientInfo->deal_func = storage_do_create_link;

	pFileContext->fd = -1;
	pFileContext->op = FDFS_STORAGE_FILE_OP_WRITE;
	pFileContext->dio_thread_index = storage_dio_get_thread_index( \
		pTask, store_path_index, pFileContext->op);

	if ((result=storage_dio_queue_push(pTask)) != 0)
	{
		return result;
	}

	return TASK_STATUS_CONTINUE;
}

int fdfs_stat_file_sync_func(void *args)
{
	int result;

	if (last_stat_change_count != g_stat_change_count)
	{
		if ((result=storage_write_to_stat_file()) == 0)
		{
			last_stat_change_count = g_stat_change_count;
		}

		return result;
	}
	else
	{
		return 0;
	}
}

#define ACCESS_LOG_INIT_FIELDS() \
	do \
	{ \
		if (g_use_access_log) \
		{ \
			*(pClientInfo->file_context.fname2log) = '-'; \
			*(pClientInfo->file_context.fname2log+1)='\0';\
			pClientInfo->request_length = \
				pClientInfo->total_length; \
			gettimeofday(&(pClientInfo->file_context. \
				tv_deal_start), NULL); \
		} \
	} while (0)

static int storage_deal_task(struct fast_task_info *pTask, const int stage)
{
	TrackerHeader *pHeader;
	StorageClientInfo *pClientInfo;
	int result;

	pClientInfo = (StorageClientInfo *)pTask->arg;
	pHeader = (TrackerHeader *)pTask->data;

    if (pClientInfo->total_offset == 0)
    {
        pClientInfo->total_offset = pTask->length;
    }
    else
    {
        pClientInfo->total_offset += pTask->length;

        /* continue write to file */
        return storage_dio_queue_push(pTask);
    }

	switch(pHeader->cmd)
	{
		case STORAGE_PROTO_CMD_DOWNLOAD_FILE:
			ACCESS_LOG_INIT_FIELDS();
			result = storage_server_download_file(pTask);
			STORAGE_ACCESS_LOG(pTask, \
				ACCESS_LOG_ACTION_DOWNLOAD_FILE, \
				result);
			break;
		case STORAGE_PROTO_CMD_GET_METADATA:
			ACCESS_LOG_INIT_FIELDS();
			result = storage_server_get_metadata(pTask);
			STORAGE_ACCESS_LOG(pTask, \
				ACCESS_LOG_ACTION_GET_METADATA, \
				result);
			break;
		case STORAGE_PROTO_CMD_UPLOAD_FILE:
			ACCESS_LOG_INIT_FIELDS();
			result = storage_upload_file(pTask, false);
			STORAGE_ACCESS_LOG(pTask, \
				ACCESS_LOG_ACTION_UPLOAD_FILE, \
				result);
			break;
		case STORAGE_PROTO_CMD_UPLOAD_APPENDER_FILE:
			ACCESS_LOG_INIT_FIELDS();
			result = storage_upload_file(pTask, true);
			STORAGE_ACCESS_LOG(pTask, \
				ACCESS_LOG_ACTION_UPLOAD_FILE, \
				result);
			break;
		case STORAGE_PROTO_CMD_APPEND_FILE:
			ACCESS_LOG_INIT_FIELDS();
			result = storage_append_file(pTask);
			STORAGE_ACCESS_LOG(pTask, \
				ACCESS_LOG_ACTION_APPEND_FILE, \
				result);
			break;
		case STORAGE_PROTO_CMD_MODIFY_FILE:
			ACCESS_LOG_INIT_FIELDS();
			result = storage_modify_file(pTask);
			STORAGE_ACCESS_LOG(pTask, \
				ACCESS_LOG_ACTION_MODIFY_FILE, \
				result);
			break;
		case STORAGE_PROTO_CMD_TRUNCATE_FILE:
			ACCESS_LOG_INIT_FIELDS();
			result = storage_do_truncate_file(pTask);
			STORAGE_ACCESS_LOG(pTask, \
				ACCESS_LOG_ACTION_TRUNCATE_FILE, \
				result);
			break;
		case STORAGE_PROTO_CMD_UPLOAD_SLAVE_FILE:
			ACCESS_LOG_INIT_FIELDS();
			result = storage_upload_slave_file(pTask);
			STORAGE_ACCESS_LOG(pTask, \
				ACCESS_LOG_ACTION_UPLOAD_FILE, \
				result);
			break;
		case STORAGE_PROTO_CMD_DELETE_FILE:
			ACCESS_LOG_INIT_FIELDS();
			result = storage_server_delete_file(pTask);
			STORAGE_ACCESS_LOG(pTask, \
				ACCESS_LOG_ACTION_DELETE_FILE, \
				result);
			break;
		case STORAGE_PROTO_CMD_SET_METADATA:
			ACCESS_LOG_INIT_FIELDS();
			result = storage_server_set_metadata(pTask);
			STORAGE_ACCESS_LOG(pTask, \
				ACCESS_LOG_ACTION_SET_METADATA, \
				result);
			break;
		case STORAGE_PROTO_CMD_QUERY_FILE_INFO:
			ACCESS_LOG_INIT_FIELDS();
			result = storage_server_query_file_info(pTask);
			STORAGE_ACCESS_LOG(pTask,
				ACCESS_LOG_ACTION_QUERY_FILE,
				result);
			break;
		case STORAGE_PROTO_CMD_CREATE_LINK:
			result = storage_create_link(pTask);
			break;
		case STORAGE_PROTO_CMD_SYNC_CREATE_FILE:
			result = storage_sync_copy_file(pTask, pHeader->cmd);
			break;
		case STORAGE_PROTO_CMD_SYNC_DELETE_FILE:
			result = storage_sync_delete_file(pTask);
			break;
		case STORAGE_PROTO_CMD_SYNC_UPDATE_FILE:
			result = storage_sync_copy_file(pTask, pHeader->cmd);
			break;
		case STORAGE_PROTO_CMD_SYNC_APPEND_FILE:
			result = storage_sync_append_file(pTask);
			break;
		case STORAGE_PROTO_CMD_SYNC_MODIFY_FILE:
			result = storage_sync_modify_file(pTask);
			break;
		case STORAGE_PROTO_CMD_SYNC_TRUNCATE_FILE:
			result = storage_sync_truncate_file(pTask);
			break;
        case STORAGE_PROTO_CMD_SYNC_RENAME_FILE:
			result = storage_sync_rename_file(pTask);
			break;
		case STORAGE_PROTO_CMD_SYNC_CREATE_LINK:
			result = storage_sync_link_file(pTask);
			break;
		case STORAGE_PROTO_CMD_FETCH_ONE_PATH_BINLOG:
			result = storage_server_fetch_one_path_binlog(pTask);
			break;
		case FDFS_PROTO_CMD_QUIT:
			ioevent_add_to_deleted_list(pTask);
			return 0;
		case FDFS_PROTO_CMD_ACTIVE_TEST:
			result = storage_deal_active_test(pTask);
			break;
		case STORAGE_PROTO_CMD_REPORT_SERVER_ID:
			result = storage_server_report_server_id(pTask);
			break;
		case STORAGE_PROTO_CMD_TRUNK_ALLOC_SPACE:
			result = storage_server_trunk_alloc_space(pTask);
			break;
		case STORAGE_PROTO_CMD_TRUNK_ALLOC_CONFIRM:
			result = storage_server_trunk_alloc_confirm(pTask);
			break;
		case STORAGE_PROTO_CMD_TRUNK_FREE_SPACE:
			result = storage_server_trunk_free_space(pTask);
			break;
		case STORAGE_PROTO_CMD_TRUNK_SYNC_BINLOG:
			result = storage_server_trunk_sync_binlog(pTask);
			break;
		case STORAGE_PROTO_CMD_TRUNK_GET_BINLOG_SIZE:
			result = storage_server_trunk_get_binlog_size(pTask);
			break;
		case STORAGE_PROTO_CMD_TRUNK_DELETE_BINLOG_MARKS:
			result = storage_server_trunk_delete_binlog_marks(pTask);
			break;
		case STORAGE_PROTO_CMD_TRUNK_TRUNCATE_BINLOG_FILE:
			result = storage_server_trunk_truncate_binlog_file(pTask);
			break;
		case STORAGE_PROTO_CMD_REGENERATE_APPENDER_FILENAME:
			ACCESS_LOG_INIT_FIELDS();
			result = storage_server_regenerate_appender_filename(pTask);
			STORAGE_ACCESS_LOG(pTask,
				ACCESS_LOG_ACTION_RENAME_FILE,
				result);
			break;
		default:
			logError("file: "__FILE__", line: %d, "  \
				"client ip: %s, unkown cmd: %d", \
				__LINE__, pTask->client_ip, \
				pHeader->cmd);
			result = EINVAL;
			break;
	}

    if (result == TASK_STATUS_CONTINUE) {
        return 0;
    }
    else
    {
        pClientInfo->total_offset = 0;
        if (result != 0)
        {
            pClientInfo->total_length = sizeof(TrackerHeader);
        }
        pTask->length = pClientInfo->total_length;

        pHeader = (TrackerHeader *)pTask->data;
        pHeader->status = result;
        pHeader->cmd = STORAGE_PROTO_CMD_RESP;
        long2buff(pClientInfo->total_length - sizeof(TrackerHeader), \
                pHeader->pkg_len);
        sf_send_add_event(pTask);
        return result;
    }
}
