s3 ftp实现原理
S3 FTP 实现原理和使用方式
特性描述
s3 ftp 主要是实现对象存储协议转换成ftp协议
目的
为了提供ftp方式访问MOS对象存储,兼容客户使用场景。为客户更好的解决应用问题。
使用方式
Linux 客户端连接方式
连接ftp服务端 ftp 10.10.1.39 put 本地文件名 ftp服务端文件名 #上传文件到服务端 get 本地文件名 ftp服务端文件名 #从服务端下载文件 ls 参数 #遍历目录,参数为文件夹名字(可选参数) cd 参数 #目录切换 参数为需切换的文件夹 pwd #获取当前路径 rm 文件夹名字 #这个命令只能用于删除文件夹,删除文件无效,不能强制删除有文件的文件夹 delete 文件名 #用户删除文件名字 mkd 文件夹名字 #创建一个文件夹


具体的ftp指令集:http://blog.csdn.net/weiyuefei/article/details/51758288
windows 客户端连接方式

功能
主要功能列表如下:
1. 数据上传
2. 数据下载
3. 文件夹创建
4. 文件夹删除
5. 文件删除
6. 遍历文件夹
7. 获取文件大小
8. 二进制传输和ASCII传输
9. 目录切换
还不支持的功能如下:
1. 文件重命名
2. 文件夹重命名
3. 文件追加写
4. 文件所属用户权限
5. SSL加密传输
数据上传
数据上传现在分为两种方式,如果文件大于16M就会自动启动分片上传。
// handle put op
if (tunable_write_enable && (tunable_anon_upload_enable || !p_sess->is_anonymous) && str_equal_text(&p_sess->ftp_cmd_str, "STOR")) { if (tunable_s3_enable) handle_stor_s3(p_sess); else handle_stor(p_sess); }
// put or get op entra // if is_recv = 1 is put otherwise is get
struct vsf_transfer_ret vsf_ftpdataio_transfer_s3_file(struct vsf_session* p_sess, int remote_fd, struct mystr* bucket, struct mystr* object, filesize_t curr_offset, filesize_t num_send, int is_recv, int is_ascii) { if (!is_recv) { if (is_ascii || p_sess->data_use_ssl) { return do_s3_file_send_rwloop( p_sess, bucket, object, curr_offset, is_ascii); } else { return do_s3_file_send_sendfile( p_sess, remote_fd, bucket, object, curr_offset, num_send); } } else { return do_s3_file_recv(p_sess, bucket, object, is_ascii); } }
数据下载
客户端发送get请求,vsftp会得到get请求指令,然后调用具体get请求函数开始执行数据上传操作。
s3接口支持分片下载,可以get任意一段数据。所以无需做任何多余的缓存操作,只是不支持s3直接对客户端进行数据拷贝。
首先在get文件时,先判断文件是否存在。
// handle get op if (tunable_download_enable && str_equal_text(&p_sess->ftp_cmd_str, "RETR")) { if (tunable_s3_enable) handle_retr_s3(p_sess, 0); else handle_retr(p_sess, 0); }
文件夹创建
文件夹创建分为两种情况一种是create bucket 一种是create object。如果是一级目录那就是创建bucket,如果不是就创建带"/"结束的object,里面不写入任何数据。
//handle mkd op if (tunable_write_enable && (tunable_anon_mkdir_write_enable || !p_sess->is_anonymous) && (str_equal_text(&p_sess->ftp_cmd_str, "MKD") || str_equal_text(&p_sess->ftp_cmd_str, "XMKD"))) { if (tunable_s3_enable) handle_mkd_s3(p_sess); else handle_mkd(p_sess); }
// create bucket or create object if (str_isempty(&object)) retval = vsf_s3_create_bucket(p_sess->s3_client, &bucket); else retval = vsf_s3_create_object(p_sess->s3_client, &bucket, &object);
文件夹删除
文件夹删除是rm操作,这个操作不能用于文件,rm操作没有-f的参数所以只有当文件夹没有文件的时候才能删除成功,这里分为三种情况
删除bucket:直接调用删除bucket操作,如果有对象就会返回失败。
删除文件夹对象:先判断是否还有以这个文件夹为前缀的对象,如果有就删除失败。没有就直接删除这个文件夹对象。
只用判断是不是有这个为前缀的对象,如果有就表示目录存在,并且无法删除。
//handle rmd op if (tunable_write_enable && (tunable_anon_other_write_enable || !p_sess->is_anonymous) && (str_equal_text(&p_sess->ftp_cmd_str, "RMD") || str_equal_text(&p_sess->ftp_cmd_str, "XRMD"))) { if (tunable_s3_enable) handle_rmd_s3(p_sess); else handle_rmd(p_sess); }
//remove bucket or remove object if (!str_isempty(&object)) { retval = vsf_s3_dir_file(p_sess->s3_client, &bucket, &object); if (!retval) { vsf_cmdio_write(p_sess, FTP_FILEFAIL, "Remove directory operation failed."); goto out; } } if (str_isempty(&object)) retval = vsf_s3_delete_bucket(p_sess->s3_client, &bucket); else { retval = vsf_s3_delete_object(p_sess->s3_client, &bucket, &object); }
文件删除
文件删除操作是属于delete操作,所带参数是文件的名字
//handle delete file op if (tunable_write_enable && (tunable_anon_other_write_enable || !p_sess->is_anonymous) && str_equal_text(&p_sess->ftp_cmd_str, "DELE")) { if (tunable_s3_enable) handle_dele_s3(p_sess); else handle_dele(p_sess); }
遍历文件夹
获取某个目录的所有文件和子文件夹,分两种情况,一种是list bucket,一种是list object。
list 也可能会带参数,如果不带参数就默认为list当前目录。
//handle list op if (tunable_dirlist_enable && str_equal_text(&p_sess->ftp_cmd_str, "LIST")) { if (tunable_s3_enable) handle_list_s3(p_sess); else handle_list(p_sess); }
//list bucket or list object while(is_truncate) { if (str_isempty(bucket)) { failed = vsf_s3_list_bucket(p_sess->s3_client, &dir_list); is_truncate = 0; } else { failed = vsf_s3_list_object(p_sess->s3_client, bucket, object, 1, &dir_list, &marker, &is_truncate); } if (!failed) { failed = write_dir_list(p_sess, &dir_list, target); str_list_free(&dir_list); } else { break; } }
获取文件大小
size file 指令
//handle size file op if (str_equal_text(&p_sess->ftp_cmd_str, "SIZE")) { if (tunable_s3_enable) handle_size_s3(p_sess); else handle_size(p_sess); }
目录切换
cwd 指令,把当前目录切换到指定目录
// cdup or cwd if (str_equal_text(&p_sess->ftp_cmd_str, "CWD") || str_equal_text(&p_sess->ftp_cmd_str, "XCWD")) { if (tunable_s3_enable) handle_cwd_s3(p_sess); else handle_cwd(p_sess); } else if (str_equal_text(&p_sess->ftp_cmd_str, "CDUP") || str_equal_text(&p_sess->ftp_cmd_str, "XCUP")) { if (tunable_s3_enable) handle_cdup_s3(p_sess); else handle_cdup(p_sess); }
// find dir or file static int get_s3_object_path(struct mystr* p_str, struct mystr* curr_dir, int is_file) { struct mystr curr_file = INIT_MYSTR; unsigned int i =0; unsigned int len = 0; int ret = 0; struct str_locate_result res; if (!str_isempty(curr_dir) && str_get_char_at(p_str, 0) == '/') str_alloc_text(curr_dir, "/"); len = str_getlen(p_str); if(len == 2 && str_equal_text(p_str, "..")) { if (is_file) { ret = 1; goto out; } if (str_equal_text(curr_dir, "/")) { ret = 0; goto out; } if (!str_isempty(curr_dir) && str_get_char_at(curr_dir, str_getlen(curr_dir) - 1) == '/') str_split_char_reverse(curr_dir, &curr_file, '/'); res = str_locate_text_reverse(curr_dir, "/"); if (!res.found) { ret = 1; goto out; } str_split_char_reverse(curr_dir, &curr_file, '/'); if (str_isempty(curr_dir)) str_append_char(curr_dir, '/'); if (!str_isempty(curr_dir) && str_get_char_at(curr_dir, str_getlen(curr_dir) - 1) != '/') str_append_char(curr_dir, '/'); ret = 0; goto out; } if (!str_isempty(curr_dir) && str_get_char_at(curr_dir, str_getlen(curr_dir) - 1) != '/') str_append_char(curr_dir, '/'); for (i = 0; i < len; i++) { if (str_get_char_at(p_str, i) == '.') { if (str_get_char_at(p_str, i + 1) == '.' && str_get_char_at(p_str, i + 2) == '/' && (i + 2) < len) { if (str_equal_text(curr_dir, "/")) { i += 2; continue; } if (!str_isempty(curr_dir) && str_get_char_at(curr_dir, str_getlen(curr_dir) - 1) == '/') str_split_char_reverse(curr_dir, &curr_file, '/'); str_split_char_reverse(curr_dir, &curr_file, '/'); i += 2; continue; } else if (str_get_char_at(p_str, i + 1) == '/' && (i + 1) < len) { continue; } } if (!str_isempty(curr_dir) && str_get_char_at(curr_dir, str_getlen(curr_dir) - 1) == '/' && str_get_char_at(p_str, i) == '/') continue; str_append_char(curr_dir, str_get_char_at(p_str, i)); continue; } if (!str_isempty(curr_dir) && str_get_char_at(curr_dir, str_getlen(curr_dir) - 1) != '/' && !is_file) str_append_char(curr_dir, '/'); out: str_free(&curr_file); return ret; }
注意事项
根目录下面只能创建文件夹(因为一级文件夹是bucket,文件只能放在bucket里面)
浙公网安备 33010602011771号