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; }