FastDFS中给我们一个非常好的例子,请参考下面的代码:
// 参考FastDFS的文件名称生成算法
/**
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_path_space_list \
[store_path_index].total_mb, g_path_space_list \
[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: %d MB is too small, file bytes: " \
"%"PRId64", reserved space: %s", \
__LINE__, g_path_space_list[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_path_space_list[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;
}
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_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], 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_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;
}