int do_normal_ls(const char *remote_path, int option_show_detail) { //{{{ int ret = 0; PCSFile *file = NULL; PCSFileList *list = NULL; PCSFile *tmp = NULL; const char *error = NULL; file = BaiduPCS_NewRemoteFile(api, remote_path); error = BaiduPCS_GetError(api); if (error != NULL || file == NULL) { color_log(COLOR_LOG_ERROR, "%s 获取文件信息失败:%s\n", remote_path, error); ret = 1; goto free; } if (!file->is_dir) { print_file(file, option_show_detail); } else { list = BaiduPCS_ListRemoteDir(api, file->path); error = BaiduPCS_GetError(api); if (error != NULL || list == NULL) { color_log(COLOR_LOG_ERROR, "%s 获取文件信息失败:%s\n", file->path, error); ret = 1; goto free; } tmp = list->first; while (tmp) { print_file(tmp, option_show_detail); tmp = tmp->next; } PCSFileList_Free(list); list = NULL; } free: if (file != NULL) { PCSFile_Free(file); } if (list != NULL) { PCSFileList_Free(list); } return ret; }
int do_download(const char *remote_path, const char *local_path, int overwrite, /* 是否覆盖 */ int create_new /* 是否新建 */ ) { //{{{ int ret = 0; int stdout_output = 0; PCSFile *file = NULL; /* 需要释放 */ PCSFile *t_file = NULL; const char *error = NULL; int remote_root_offset = 0; char *tmp; char t_local_root[PATH_MAX + 1]; char t_local_file[PATH_MAX + 1]; PCSFileList *stack = NULL; /* 需要释放 */ PCSFileList *list = NULL; /* 需要释放 */ /* 获取远程路径信息 */ file = BaiduPCS_NewRemoteFile(api, remote_path); error = BaiduPCS_GetError(api); if (error != NULL || file == NULL) { color_log(COLOR_LOG_ERROR, "%s 获取文件信息失败:%s\n", remote_path, error); ret = 1; goto free; } stdout_output = strcmp(local_path, "-") == 0; sprintf(t_local_file, "%s", local_path); /* 保存路径修正 */ if (!stdout_output) { /* 远端为目录 */ if (file->is_dir) { sprintf(t_local_root, "%s", local_path); remote_root_offset = strlen(file->path); if (stat(local_path, &(api->file_st)) != -1) { if (S_ISDIR(api->file_st.st_mode)){ t_local_root[0] = '\0'; strcat(t_local_root, local_path); strcat(t_local_root, "/"); strcat(t_local_root, basename(file->path)); #ifdef DEBUG fprintf(stderr, "本地根目录修正为:%s\n", t_local_root); #endif } else { color_log(COLOR_LOG_ERROR, "%s -> %s 本地已存与目录同名的文件\n", file->path, local_path); ret = 1; goto free; } } } else { if (stat(local_path, &(api->file_st)) != -1) { if (S_ISDIR(api->file_st.st_mode)){ sprintf(t_local_file, "%s/%s", local_path, basename(file->path)); } } } } /* 下载单个文件 */ if (!file->is_dir) { ret = _do_download(remote_path, t_local_file, overwrite, create_new); } else { stack = PCSFileList_New(); while(file != NULL) { tmp = file->path + remote_root_offset; sprintf(t_local_file, "%s%s", t_local_root, tmp); /* 如果是普通文件 */ if (!file->is_dir) { #ifdef DEBUG PCSFile_Dump(file); #endif _do_download(file->path, t_local_file, overwrite, create_new); PCSFile_Free(file); file = PCSFileList_Shift(stack); /* 如果是目录 */ } else { /* 创建本地目录 */ if (stat(t_local_file, &(api->file_st)) != -1) { if (!S_ISDIR(api->file_st.st_mode)){ color_log(COLOR_LOG_ERROR, "%s -> %s 本地已存与目录同名的文件\n", file->path, t_local_file); ret = 1; goto free; } } else { if (0 != mkdir(t_local_file, 0755)) { color_log(COLOR_LOG_ERROR, "%s -> %s 本地目录创建失败\n", file->path, t_local_file); ret = 1; goto free; } } list = BaiduPCS_ListRemoteDir(api, file->path); error = BaiduPCS_GetError(api); if (error != NULL || list == NULL) { color_log(COLOR_LOG_ERROR, "%s 获取目录列表失败:%s\n", file->path, error); } /* 列出目录 */ if (list != NULL) { t_file = PCSFileList_Shift(list); while(t_file != NULL) { PCSFileList_Prepend(stack, t_file); t_file = PCSFileList_Shift(list); } PCSFileList_Free(list); list = NULL; } PCSFile_Free(file); file = PCSFileList_Shift(stack); } } } free: if (file != NULL) { PCSFile_Free(file); } if (stack != NULL) { PCSFileList_Free(stack); } if (list != NULL) { PCSFileList_Free(list); } return ret; }
int do_upload(const char *local_path, const char *remote_path, int overwrite, /* 是否覆盖 */ int create_new, /* 是否新建 */ int follow_link, /* 跟随软链 */ int split_size /* 分片大小 */ ) { //{{{ int ret = 0; int is_first = 1; PCSFile *new_file = NULL; PCSFile *t_file = NULL; struct dirent *item = NULL; const char *error = NULL; const char *ondup = NULL; char t_path[PATH_MAX + 1]; /* 临时路径 */ char t_remote_path[PATH_MAX + 1]; /* 临时路径 */ /* 需要释放 */ PCSFile *c_file = NULL; PCSFileList *stack = NULL; PCSFile *remote_file = NULL; PCSFileList *r_list = NULL; DIR *dir = NULL; /* 遍历栈 */ stack = PCSFileList_New(); c_file = BaiduPCS_NewLocalFile(api, local_path); error = BaiduPCS_GetError(api); if (error != NULL || c_file == NULL) { color_log(COLOR_LOG_ERROR, "文件对象创建失败 %s\n", error); ret = 1; goto free; } /* 当前要上传的远程路径 */ c_file->userdata = strdup(remote_path); if (create_new) { ondup = "newcopy"; } else { ondup = "overwrite"; } while(c_file != NULL) { remote_path = (char *)c_file->userdata; /* 普通文件 */ if (!c_file->is_dir && !c_file->is_link) { if (is_first) { remote_file = BaiduPCS_NewRemoteFile(api, remote_path); if (remote_file != NULL) { /* upload xx.txt /apps/xx/ * 对于这种情况,远端路径修正为/apps/xx/xx.txt */ if (remote_file->is_dir) { t_remote_path[0] = '\0'; strcat(t_remote_path, remote_path); strcat(t_remote_path, "/"); strcat(t_remote_path, basename(c_file->path)); #ifdef DEBUG fprintf(stderr, "上传路径 %s 修正为 %s\n", remote_path, t_remote_path); #endif free(c_file->userdata); c_file->userdata = strdup(t_remote_path); remote_path = c_file->userdata; PCSFile_Free(remote_file); remote_file = NULL; continue; /* upload xx.txt /apps/xx/xx.txt */ } else if (!overwrite && !create_new) { color_log(COLOR_LOG_IGNORE, "%s -> %s 远端已存在同名文件\n", c_file->path, remote_file->path); goto free; } PCSFile_Free(remote_file); remote_file = NULL; } } remote_file = BaiduPCS_Upload(api, c_file, remote_path, 0, ondup); error = BaiduPCS_GetError(api); /* 上传失败 */ if (error != NULL || remote_file == NULL) { color_log(COLOR_LOG_ERROR, "%s -> %s %s\n", c_file->path, remote_path, error); /* 如果上传单个文件,失败后会返回error code */ if (is_first) { ret = 1; goto free; } /* 上传成功 */ } else { color_log(COLOR_LOG_OK, "%s -> %s\n", c_file->path, remote_file->path); PCSFile_Free(remote_file); remote_file = NULL; } free(c_file->userdata); PCSFile_Free(c_file); c_file = PCSFileList_Shift(stack); is_first = 0; //如果是目录 } else if (c_file->is_dir) { /* 遍历目录 */ dir = opendir(c_file->path); /* 读取目录失败 */ if (dir == NULL) { color_log(COLOR_LOG_ERROR, "%s -> %s 目录读取失败\n", c_file->path, remote_path); /* 如果当前为用户指定的根目录,直接返回错误 */ if (is_first) { ret = 1; goto free; } } else { /* 进行目录修正 */ if (is_first) { remote_file = BaiduPCS_NewRemoteFile(api, remote_path); if (remote_file != NULL) { /* upload ./dir/ /apps/xx/ * 对于这种情况,远端路径修正为/apps/xx/dir */ if (remote_file->is_dir) { t_remote_path[0] = '\0'; strcat(t_remote_path, remote_file->path); strcat(t_remote_path, "/"); strcat(t_remote_path, basename(c_file->path)); #ifdef DEBUG fprintf(stderr, "上传目录 %s 修正为 %s\n", remote_path, t_remote_path); #endif free(c_file->userdata); c_file->userdata = strdup(t_remote_path); remote_path = c_file->userdata; } else if (!remote_file->is_dir) { color_log(COLOR_LOG_ERROR, "%s -> %s 远端路径不是目录\n", c_file->path, remote_file->path); ret = 1; goto free; } PCSFile_Free(remote_file); remote_file = NULL; } } /* 获取远程目录列表,用于排除远端已存在的文件 */ remote_file = BaiduPCS_NewRemoteFile(api, remote_path); if (remote_file != NULL) { /* 远端已存在同名文件 */ if (!remote_file->is_dir) { color_log(COLOR_LOG_ERROR, "%s -> %s 远端已存与目录同名的文件\n", c_file->path, remote_file->path); if (is_first) { ret = 1; goto free; } } else { /* 获取远端目录文件列表,用于对比本地目录列表 */ r_list = BaiduPCS_ListRemoteDir(api, remote_path); } PCSFile_Free(remote_file); remote_file = NULL; } while ((item = readdir(dir)) != NULL) { if (strcmp(item->d_name, ".") == 0 || strcmp(item->d_name, "..") == 0) { continue; } /* 构建本地文件完整路径 */ t_path[0] = '\0'; strcat(t_path, c_file->path); strcat(t_path, "/"); strcat(t_path, item->d_name); /* 构建上传路径 */ t_remote_path[0] = '\0'; strcat(t_remote_path, remote_path); strcat(t_remote_path, "/"); strcat(t_remote_path, item->d_name); new_file = BaiduPCS_NewLocalFile(api, t_path); error = BaiduPCS_GetError(api); if (error != NULL || new_file == NULL) { color_log(COLOR_LOG_ERROR, "%s -> %s %s\n", t_path, t_remote_path, error); } else { if (r_list != NULL) { t_file = PCSFileList_Find(r_list, t_remote_path); /* 远程已存在同名文件 */ if (t_file != NULL) { if (new_file->is_dir && !t_file->is_dir) { color_log(COLOR_LOG_ERROR, "%s -> %s 远程已存在与目录同名的文件\n", t_path, t_remote_path); PCSFile_Free(new_file); new_file = NULL; continue; } else if (!new_file->is_dir && t_file->is_dir) { color_log(COLOR_LOG_ERROR, "%s -> %s 远程已存在与文件同名的目录\n", t_path, t_remote_path); PCSFile_Free(new_file); new_file = NULL; continue; } else if (!new_file->is_dir && !new_file->is_link && !overwrite && !create_new) { color_log(COLOR_LOG_IGNORE, "%s -> %s 远程已存在同名文件\n", t_path, t_remote_path); PCSFile_Free(new_file); new_file = NULL; continue; } } } new_file->userdata = strdup(t_remote_path); //放入栈中 PCSFileList_Prepend(stack, new_file); new_file = NULL; } } if (r_list != NULL) { PCSFileList_Free(r_list); r_list = NULL; } closedir(dir); dir = NULL; } free(c_file->userdata); PCSFile_Free(c_file); c_file = PCSFileList_Shift(stack); is_first = 0; /* 软链接 */ } else if (c_file->is_link) { if (follow_link) { realpath(c_file->path, t_path); #ifdef DEBUG fprintf(stderr, "跟随软链 %s -> %s\n", c_file->path, t_path); #endif new_file = BaiduPCS_NewLocalFile(api, t_path); new_file->userdata = c_file->userdata; PCSFile_Free(c_file); c_file = new_file; } else { color_log(COLOR_LOG_IGNORE, "忽略软链接 %s\n", c_file->path); free(c_file->userdata); PCSFile_Free(c_file); c_file = PCSFileList_Shift(stack); is_first = 0; } /* 忽略其他类型 */ } else { color_log(COLOR_LOG_ERROR, "不支持的文件类型 %s\n", c_file->path); free(c_file->userdata); PCSFile_Free(c_file); c_file = PCSFileList_Shift(stack); is_first = 0; } } free: PCSFileList_Free(stack); if (dir != NULL) { closedir(dir); } if (c_file != NULL) { free(c_file->userdata); PCSFile_Free(c_file); } if (remote_file != NULL) { PCSFile_Free(remote_file); } if (r_list != NULL) { PCSFileList_Free(r_list); } return ret; }
/* 递归列表 */ int do_recursion_ls(const char *remote_path, int option_show_detail) { //{{{ int ret = 0; PCSFileList *stack = NULL; PCSFileList *list = NULL; PCSFile *c_file = NULL; PCSFile *t_file = NULL; const char *error = NULL; /* 遍历栈 */ stack = PCSFileList_New(); c_file = BaiduPCS_NewRemoteFile(api, remote_path); error = BaiduPCS_GetError(api); if (error != NULL || c_file == NULL) { color_log(COLOR_LOG_ERROR, "%s 获取文件信息失败:%s\n", remote_path, error); ret = 1; goto free; } while(c_file != NULL) { /* 如果是普通文件 */ if (!c_file->is_dir) { print_file(c_file, option_show_detail); PCSFile_Free(c_file); c_file = PCSFileList_Shift(stack); /* 如果是目录 */ } else { print_file(c_file, option_show_detail); list = BaiduPCS_ListRemoteDir(api, c_file->path); error = BaiduPCS_GetError(api); if (error != NULL || list == NULL) { color_log(COLOR_LOG_ERROR, "%s 获取文件信息失败:%s\n", c_file->path, error); } /* 列出目录 */ if (list != NULL) { t_file = PCSFileList_Shift(list); while(t_file != NULL) { if (t_file->is_dir) { PCSFileList_Prepend(stack, t_file); } else { print_file(t_file, option_show_detail); PCSFile_Free(t_file); } t_file = PCSFileList_Shift(list); } PCSFileList_Free(list); list = NULL; } PCSFile_Free(c_file); c_file = PCSFileList_Shift(stack); } } free: if (stack != NULL) { PCSFileList_Free(stack); } if (c_file != NULL) { PCSFile_Free(c_file); } return ret; }
PCSFile *BaiduPCS_NewRemoteFile(BaiduPCS *api, const char *path) { //{{{ PCSFile *file = NULL; HttpClient *client = api->client; char *url_buffer = api->util_buffer0; const char *token = api->token; const char *error = NULL; const char *response = NULL; char *path_encode = NULL; cJSON *json = NULL; cJSON *array = NULL; cJSON *item = NULL; BaiduPCS_ResetError(api); file = PCSFile_New(); path_encode = curl_easy_escape(client->curl, path, 0); sprintf(url_buffer, "https://pcs.baidu.com/rest/2.0/pcs/file?" "access_token=%s" "&method=meta" "&path=%s", token, path_encode); curl_free(path_encode); path_encode = NULL; #ifdef DEBUG fprintf(stderr, "request %s\n", url_buffer); #endif HttpClient_Init(client); HttpClient_Get(client, url_buffer); MAKE_JSON(); item = cJSON_GetObjectItem(json, "list"); if (item == NULL || item->type != cJSON_Array) { BaiduPCS_ThrowError(api, "can't find json.list"); goto free; } array = item; if (cJSON_GetArraySize(array) == 0) { BaiduPCS_ThrowError(api, "json.list is blank"); goto free; } item = cJSON_GetArrayItem(array, 0); if (item == NULL || item->type != cJSON_Object) { BaiduPCS_ThrowError(api, "json.list.item is not object"); goto free; } _BaiduPCS_Json2File(api, file, item); free: if (json != NULL) { cJSON_Delete(json); } if (api->error[0] != '\0') { if (file != NULL) { PCSFile_Free(file); } return NULL; } return file; }
static PCSFile *_BaiduPCS_UploadSmallFile( BaiduPCS *api, PCSFile *local_file, const char *remote_file, const char *ondup ) { //{{{ PCSFile *result = NULL; HttpClient *client = api->client; char *url_buffer = api->util_buffer0; const char *token = api->token; int timeout = 0; const char *error = NULL; const char *response = NULL; char *remote_path_encode = NULL; struct curl_httppost *post = NULL; struct curl_httppost *last = NULL; cJSON *json = NULL; cJSON *item = NULL; remote_path_encode = curl_easy_escape(client->curl, remote_file, 0); //合并文件分片 sprintf(url_buffer, "https://c.pcs.baidu.com/rest/2.0/pcs/file?" "access_token=%s" "&method=upload" "&path=%s" "&ondup=%s", token, remote_path_encode, ondup); curl_free(remote_path_encode); remote_path_encode = NULL; #ifdef DEBUG fprintf(stderr, "开始上传小文件\n"); #endif HttpClient_Init(client); curl_formadd(&post, &last, CURLFORM_COPYNAME, "file", CURLFORM_FILE, local_file->path, CURLFORM_END); curl_easy_setopt(client->curl, CURLOPT_READFUNCTION, _BaiduPCS_UploadReadCallback); /* 设置一个较为合理的超时时间 */ timeout = MAX(20, local_file->size / (10 * 1024)); curl_easy_setopt(client->curl, CURLOPT_TIMEOUT, timeout); HttpClient_PostHttpData(client, url_buffer, post); curl_formfree(post); post = NULL; last = NULL; MAKE_JSON(); result = PCSFile_New(); _BaiduPCS_Json2File(api, result, json); if (api->error[0] != '\0') { PCSFile_Free(result); result = NULL; } free: if (post != NULL) { curl_formfree(post); } if (json != NULL) { cJSON_Delete(json); } return result; }
static PCSFile *_BaiduPCS_UploadBigFile( BaiduPCS *api, PCSFile *local_file, const char *remote_file, const char *ondup ) { //{{{ PCSFile *result = NULL; HttpClient *client = api->client; char *url_buffer = api->util_buffer0; const char *token = api->token; FILE *fp = NULL; PCSFileBlock *block = NULL; int i = 0; int timeout = 0; const char *error = NULL; char *tmp = NULL; const char *response = NULL; char *remote_path_encode = NULL; struct curl_httppost *post = NULL; struct curl_httppost *last = NULL; cJSON *json = NULL; cJSON *item = NULL; cJSON *array = NULL; sprintf(url_buffer, "https://c.pcs.baidu.com/rest/2.0/pcs/file?" "access_token=%s" "&method=upload" "&type=tmpfile", token); fp = fopen(local_file->path, "rb"); if (fp == NULL) { BaiduPCS_ThrowError(api, "本地文件无法读取 %s", local_file->path); goto free; } //上传切片 i = 0; block = local_file->block; while (block != NULL) { #ifdef DEBUG fprintf(stderr, "开始上传分片%d\n", i); #endif block->fp = fp; HttpClient_Init(client); curl_formadd(&post, &last, CURLFORM_COPYNAME, "file", CURLFORM_STREAM, block, CURLFORM_CONTENTSLENGTH, block->size, CURLFORM_CONTENTTYPE, "application/octet-stream", CURLFORM_FILENAME, basename(local_file->path), CURLFORM_END); curl_easy_setopt(client->curl, CURLOPT_READFUNCTION, _BaiduPCS_UploadReadCallback); /* 失败重试前,重置block */ HttpClient_SetFailRetryCallback(client, _BaiduPCS_UploadResetCallback, block); /* 设置一个较为合理的超时时间 */ timeout = MAX(20, block->size / (10 * 1024)); curl_easy_setopt(client->curl, CURLOPT_TIMEOUT, timeout); HttpClient_PostHttpData(client, url_buffer, post); MAKE_JSON(); item = cJSON_GetObjectItem(json, "md5"); if (item == NULL || item->type != cJSON_String) { BaiduPCS_ThrowError(api, "can't find json.md5"); goto free; } sprintf(block->md5, "%s", item->valuestring); cJSON_Delete(json); json = NULL; curl_formfree(post); post = NULL; last = NULL; #ifdef DEBUG fprintf(stderr, "分片MD5 %s\n", block->md5); #endif block = block->next; i ++; } remote_path_encode = curl_easy_escape(client->curl, remote_file, 0); //合并文件分片 sprintf(url_buffer, "https://c.pcs.baidu.com/rest/2.0/pcs/file?" "access_token=%s" "&method=createsuperfile" "&path=%s" "&ondup=%s", token, remote_path_encode, ondup); curl_free(remote_path_encode); remote_path_encode = NULL; #ifdef DEBUG fprintf(stderr, "request %s\n", url_buffer); #endif array = cJSON_CreateArray(); block = local_file->block; while (block != NULL) { cJSON_AddItemToArray(array, cJSON_CreateString(block->md5)); block = block->next; } json = cJSON_CreateObject(); cJSON_AddItemToObject(json, "block_list", array); tmp = cJSON_Print(json); #ifdef DEBUG fprintf(stderr, "param %s\n", tmp); #endif curl_formadd(&post, &last, CURLFORM_COPYNAME, "param", CURLFORM_COPYCONTENTS, tmp, CURLFORM_END); cJSON_Delete(json); json = NULL; free(tmp); tmp = NULL; HttpClient_Init(client); HttpClient_PostHttpData(client, url_buffer, post); MAKE_JSON(); result = PCSFile_New(); _BaiduPCS_Json2File(api, result, json); if (api->error[0] != '\0') { PCSFile_Free(result); result = NULL; } free: if (post != NULL) { curl_formfree(post); } if (fp != NULL) { fclose(fp); } if (json != NULL) { cJSON_Delete(json); } return result; }