s3fs-fuse/src/s3fs.cpp

4766 lines
128 KiB
C++
Raw Normal View History

/*
* s3fs - FUSE-based file system backed by Amazon S3
*
* Copyright 2007-2008 Randy Rizun <rrizun@gmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <dirent.h>
#include <errno.h>
#include <time.h>
#include <utime.h>
#include <sys/stat.h>
#include <libgen.h>
#include <libxml/xpath.h>
#include <libxml/xpathInternals.h>
#include <libxml/parser.h>
#include <libxml/tree.h>
#include <curl/curl.h>
#include <openssl/md5.h>
#include <pwd.h>
#include <grp.h>
#include <syslog.h>
#include <getopt.h>
#include <fstream>
#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include "s3fs.h"
#include "curl.h"
#include "cache.h"
#include "string_util.h"
using namespace std;
struct s3_object {
char *name;
struct s3_object *next;
};
class auto_curl_slist {
public:
auto_curl_slist() : slist(0) { }
~auto_curl_slist() { curl_slist_free_all(slist); }
struct curl_slist* get() const { return slist; }
void append(const string& s) {
slist = curl_slist_append(slist, s.c_str());
}
private:
struct curl_slist* slist;
};
typedef struct mvnode {
char *old_path;
char *new_path;
bool is_dir;
struct mvnode *prev;
struct mvnode *next;
} MVNODE;
struct head_data {
string path;
string *url;
struct curl_slist *requestHeaders;
headers_t *responseHeaders;
};
typedef map<CURL*, head_data> headMap_t;
struct cleanup_head_data {
void operator()(pair<CURL*, head_data> qqq) {
head_data response = qqq.second;
delete response.url;
curl_slist_free_all(response.requestHeaders);
delete response.responseHeaders;
}
};
struct case_insensitive_compare_func {
bool operator ()(const string &a, const string &b) {
return strcasecmp(a.c_str(), b.c_str()) < 0;
}
};
typedef map<string, string, case_insensitive_compare_func> mimes_t;
static mimes_t mimeTypes;
class auto_head {
public:
auto_head() {}
~auto_head() {
for_each(headMap.begin(), headMap.end(), cleanup_head_data());
}
headMap_t& get() { return headMap; }
private:
headMap_t headMap;
};
time_t get_mtime(const char *s) {
return (time_t) strtoul(s, (char **) NULL, 10);
}
off_t get_size(const char *s) {
return (off_t) strtoul(s, (char **) NULL, 10);
}
mode_t get_mode(const char *s) {
return (mode_t) strtoul(s, (char **) NULL, 10);
}
uid_t get_uid(const char *s) {
return (uid_t) strtoul(s, (char **) NULL, 10);
}
gid_t get_gid(const char *s) {
return (gid_t) strtoul(s, (char **) NULL, 10);
}
blkcnt_t get_blocks(off_t size) {
return size / 512 + 1;
}
Summary of Changes(1.62 -> 1.63) 1) Lifetime for the stats cache Added the new option "stat_cache_expire". This option which is specified by seconds means the lifetime for each stats cache entry. If this option is not specified, the stats cache is kept in s3fs process until the stats cache grown to maximum size. (default) If this option is specified, the stats cache entry is out from the memory when the entry expires time. 2) Enable file permission s3fs before 1.62 did not consider the file access permission. s3fs after this version can consider it. For access permission, the s3fs_getattr() function was divided into sub function which can check the file access permission. It is like access() function. And the function calling the s3fs_getattr() calls this new sub function instead of s3fs_getattr(). Last the s3fs_opendir() function which is called by FUSE was added for checking directory access permission when listing the files in directory. 3) UID/GUID When a file or a directory was created, the s3fs could not set the UID/GID as the user who executed a command. (Almost the UID/GID are root, because the s3fs run by root.) After this version, the s3fs set correct UID/GID as the user who executes the commond. 4) About the mtime If the object does not have "x-amz-meta-mtime" meta, the s3fs uses the "Last-Modified" header instead of it. But the s3fs had a bug in this code, and this version fixed this bug. When user modified the file, the s3fs did not update the mtime of the file. This version fixed this bug. In the get_local_fd() function, the local file's mtime was changed only when s3fs run with "use_cache" option. This version always updates the mtime whether the local cache file is used or not. And s3fs_flush ( ) function set the mtime of local cache file from S3 object mtime, but it was wrong . This version is that the s3fs_flush ( ) changes the mtime of S3 object from the local cache file or the tmpfile . The s3fs cuts some requests, because the s3fs can always check mtime whether the s3fs uses or does not use the local cache file. 5) A case of no "x-amz-meta-mode" If the object did not have "x-amz-meta-mtime" mete, the s3fs recognized the file as not regular file. After this version, the s3fs recognizes the file as regular file. 6) "." and ".." directory The s3fs_readdir() did not return "X" and "XX" directory name. After this version, the s3fs is changed that it returns "X" and "XX". Example, the result of "ls" lists "X" and "XX" directory. 7) Fixed a bug The insert_object() had a bug, and it is fixed. git-svn-id: http://s3fs.googlecode.com/svn/trunk@390 df820570-a93a-0410-bd06-b72b767a4274
2013-02-24 08:58:54 +00:00
static int insert_object(const char *name, struct s3_object **head) {
struct s3_object *new_object;
new_object = (struct s3_object *) malloc(sizeof(struct s3_object));
if(new_object == NULL) {
printf("insert_object: could not allocate memory\n");
exit(EXIT_FAILURE);
}
Summary of Changes(1.62 -> 1.63) 1) Lifetime for the stats cache Added the new option "stat_cache_expire". This option which is specified by seconds means the lifetime for each stats cache entry. If this option is not specified, the stats cache is kept in s3fs process until the stats cache grown to maximum size. (default) If this option is specified, the stats cache entry is out from the memory when the entry expires time. 2) Enable file permission s3fs before 1.62 did not consider the file access permission. s3fs after this version can consider it. For access permission, the s3fs_getattr() function was divided into sub function which can check the file access permission. It is like access() function. And the function calling the s3fs_getattr() calls this new sub function instead of s3fs_getattr(). Last the s3fs_opendir() function which is called by FUSE was added for checking directory access permission when listing the files in directory. 3) UID/GUID When a file or a directory was created, the s3fs could not set the UID/GID as the user who executed a command. (Almost the UID/GID are root, because the s3fs run by root.) After this version, the s3fs set correct UID/GID as the user who executes the commond. 4) About the mtime If the object does not have "x-amz-meta-mtime" meta, the s3fs uses the "Last-Modified" header instead of it. But the s3fs had a bug in this code, and this version fixed this bug. When user modified the file, the s3fs did not update the mtime of the file. This version fixed this bug. In the get_local_fd() function, the local file's mtime was changed only when s3fs run with "use_cache" option. This version always updates the mtime whether the local cache file is used or not. And s3fs_flush ( ) function set the mtime of local cache file from S3 object mtime, but it was wrong . This version is that the s3fs_flush ( ) changes the mtime of S3 object from the local cache file or the tmpfile . The s3fs cuts some requests, because the s3fs can always check mtime whether the s3fs uses or does not use the local cache file. 5) A case of no "x-amz-meta-mode" If the object did not have "x-amz-meta-mtime" mete, the s3fs recognized the file as not regular file. After this version, the s3fs recognizes the file as regular file. 6) "." and ".." directory The s3fs_readdir() did not return "X" and "XX" directory name. After this version, the s3fs is changed that it returns "X" and "XX". Example, the result of "ls" lists "X" and "XX" directory. 7) Fixed a bug The insert_object() had a bug, and it is fixed. git-svn-id: http://s3fs.googlecode.com/svn/trunk@390 df820570-a93a-0410-bd06-b72b767a4274
2013-02-24 08:58:54 +00:00
if(NULL == (new_object->name = strdup(name))){
free(new_object);
printf("insert_object: could not allocate memory\n");
exit(EXIT_FAILURE);
}
if((*head) == NULL)
new_object->next = NULL;
else
new_object->next = (*head);
*head = new_object;
return 0;
}
static unsigned int count_object_list(struct s3_object *list) {
unsigned int count = 0;
struct s3_object *head = list;
while(head != NULL) {
count++;
head = head->next;
}
return count;
}
static int free_object(struct s3_object *object) {
free(object->name);
free(object);
object = NULL;
return 0;
}
static int free_object_list(struct s3_object *head) {
struct s3_object *tmp = NULL;
struct s3_object *current = head;
current = head;
while(current != NULL) {
tmp = current;
current = current->next;
free_object(tmp);
}
return 0;
}
MVNODE *create_mvnode(char *old_path, char *new_path, bool is_dir) {
MVNODE *p;
char *p_old_path;
char *p_new_path;
p = (MVNODE *) malloc(sizeof(MVNODE));
if (p == NULL) {
printf("create_mvnode: could not allocation memory for p\n");
exit(EXIT_FAILURE);
}
p_old_path = (char *)malloc(strlen(old_path)+1);
if (p_old_path == NULL) {
free(p);
printf("create_mvnode: could not allocation memory for p_old_path\n");
exit(EXIT_FAILURE);
}
strcpy(p_old_path, old_path);
p_new_path = (char *)malloc(strlen(new_path)+1);
if (p_new_path == NULL) {
free(p);
free(p_old_path);
printf("create_mvnode: could not allocation memory for p_new_path\n");
exit(EXIT_FAILURE);
}
strcpy(p_new_path, new_path);
p->old_path = p_old_path;
p->new_path = p_new_path;
p->is_dir = is_dir;
p->prev = NULL;
p->next = NULL;
return p;
}
MVNODE *add_mvnode(MVNODE *head, char *old_path, char *new_path, bool is_dir) {
MVNODE *p;
MVNODE *tail;
tail = create_mvnode(old_path, new_path, is_dir);
for (p = head; p->next != NULL; p = p->next);
;
p->next = tail;
tail->prev = p;
return tail;
}
void free_mvnodes(MVNODE *head) {
MVNODE *my_head;
MVNODE *next;
char *p_old_path;
char *p_new_path;
if(head == NULL)
return;
my_head = head;
next = NULL;
do {
next = my_head->next;
p_old_path = my_head->old_path;
p_new_path = my_head->new_path;
free(p_old_path);
free(p_new_path);
free(my_head);
my_head = next;
} while(my_head != NULL);
return;
}
static size_t header_callback(void *data, size_t blockSize, size_t numBlocks, void *userPtr) {
headers_t* headers = reinterpret_cast<headers_t*>(userPtr);
string header(reinterpret_cast<char*>(data), blockSize * numBlocks);
string key;
stringstream ss(header);
if (getline(ss, key, ':')) {
string value;
getline(ss, value);
(*headers)[key] = trim(value);
}
return blockSize * numBlocks;
}
// safe variant of dirname
// dirname clobbers path so let it operate on a tmp copy
static string mydirname(string path) {
return string(dirname(&path[0]));
}
// safe variant of basename
// basename clobbers path so let it operate on a tmp copy
static string mybasename(string path) {
return string(basename(&path[0]));
}
// mkdir --parents
static int mkdirp(const string& path, mode_t mode) {
string base;
string component;
stringstream ss(path);
while (getline(ss, component, '/')) {
base += "/" + component;
mkdir(base.c_str(), mode);
}
return 0;
}
Summary of Changes(1.62 -> 1.63) 1) Lifetime for the stats cache Added the new option "stat_cache_expire". This option which is specified by seconds means the lifetime for each stats cache entry. If this option is not specified, the stats cache is kept in s3fs process until the stats cache grown to maximum size. (default) If this option is specified, the stats cache entry is out from the memory when the entry expires time. 2) Enable file permission s3fs before 1.62 did not consider the file access permission. s3fs after this version can consider it. For access permission, the s3fs_getattr() function was divided into sub function which can check the file access permission. It is like access() function. And the function calling the s3fs_getattr() calls this new sub function instead of s3fs_getattr(). Last the s3fs_opendir() function which is called by FUSE was added for checking directory access permission when listing the files in directory. 3) UID/GUID When a file or a directory was created, the s3fs could not set the UID/GID as the user who executed a command. (Almost the UID/GID are root, because the s3fs run by root.) After this version, the s3fs set correct UID/GID as the user who executes the commond. 4) About the mtime If the object does not have "x-amz-meta-mtime" meta, the s3fs uses the "Last-Modified" header instead of it. But the s3fs had a bug in this code, and this version fixed this bug. When user modified the file, the s3fs did not update the mtime of the file. This version fixed this bug. In the get_local_fd() function, the local file's mtime was changed only when s3fs run with "use_cache" option. This version always updates the mtime whether the local cache file is used or not. And s3fs_flush ( ) function set the mtime of local cache file from S3 object mtime, but it was wrong . This version is that the s3fs_flush ( ) changes the mtime of S3 object from the local cache file or the tmpfile . The s3fs cuts some requests, because the s3fs can always check mtime whether the s3fs uses or does not use the local cache file. 5) A case of no "x-amz-meta-mode" If the object did not have "x-amz-meta-mtime" mete, the s3fs recognized the file as not regular file. After this version, the s3fs recognizes the file as regular file. 6) "." and ".." directory The s3fs_readdir() did not return "X" and "XX" directory name. After this version, the s3fs is changed that it returns "X" and "XX". Example, the result of "ls" lists "X" and "XX" directory. 7) Fixed a bug The insert_object() had a bug, and it is fixed. git-svn-id: http://s3fs.googlecode.com/svn/trunk@390 df820570-a93a-0410-bd06-b72b767a4274
2013-02-24 08:58:54 +00:00
// get user name from uid
static string get_username(uid_t uid)
{
struct passwd* ppw;
if(NULL == (ppw = getpwuid(uid)) || NULL == ppw->pw_name){
if(foreground){
printf(" could not get username(errno=%d).\n", (int)errno);
}
if(debug){
syslog(LOG_DEBUG, "could not get username(errno=%d).\n", (int)errno);
}
return NULL;
}
return string(ppw->pw_name);
}
// check uid in group(gid)
static int is_uid_inculde_group(uid_t uid, gid_t gid)
{
static size_t maxlen = 0; // set onece
int result;
char* pbuf;
struct group ginfo;
struct group* pginfo = NULL;
// make buffer
if(0 == maxlen){
if(0 > (maxlen = (size_t)sysconf(_SC_GETGR_R_SIZE_MAX))){
if(foreground){
printf(" could not get max name length.\n");
}
if(debug){
syslog(LOG_DEBUG, "could not get max name length.\n");
}
maxlen = 0;
return -ERANGE;
}
}
if(NULL == (pbuf = (char*)malloc(sizeof(char) * maxlen))){
if(foreground){
printf(" failed to allocate memory.\n");
}
syslog(LOG_ERR, "failed to allocate memory.\n");
return -ENOMEM;
}
// get group infomation
if(0 != (result = getgrgid_r(gid, &ginfo, pbuf, maxlen, &pginfo))){
if(foreground){
printf(" could not get group infomation.\n");
}
if(debug){
syslog(LOG_DEBUG, "could not get group infomation.\n");
}
free(pbuf);
return -result;
}
// check group
if(NULL == pginfo){
// there is not gid in group.
free(pbuf);
return -EINVAL;
}
string username = get_username(uid);
char** ppgr_mem;
for(ppgr_mem = pginfo->gr_mem; ppgr_mem && *ppgr_mem; ppgr_mem++){
if(username == *ppgr_mem){
// Found username in group.
free(pbuf);
return 1;
}
}
free(pbuf);
return 0;
}
//
// Get object attributes with stat cache.
// This function is base for s3fs_getattr().
//
static int get_object_attribute(const char *path, struct stat *stbuf) {
int result;
headers_t meta;
char *s3_realpath;
//if(foreground)
// printf(" get_object_attribute[path=%s]\n", path);
memset(stbuf, 0, sizeof(struct stat));
if(strcmp(path, "/") == 0) {
stbuf->st_nlink = 1; // see fuse faq
stbuf->st_mode = root_mode | S_IFDIR;
return 0;
}
if(get_stat_cache_entry(path, stbuf) == 0) {
return 0;
}
s3_realpath = get_realpath(path);
if((result = curl_get_headers(s3_realpath, meta)) != 0) {
free(s3_realpath);
return result;
}
free(s3_realpath);
stbuf->st_nlink = 1; // see fuse faq
stbuf->st_mtime = get_mtime(meta["x-amz-meta-mtime"].c_str());
if(stbuf->st_mtime == 0){
struct tm tm;
strptime(meta["Last-Modified"].c_str(), "%a, %d %b %Y %H:%M:%S %Z", &tm);
stbuf->st_mtime = mktime(&tm); // GMT
}
stbuf->st_mode = get_mode(meta["x-amz-meta-mode"].c_str());
if(strstr(meta["Content-Type"].c_str(), "x-directory"))
stbuf->st_mode |= S_IFDIR;
else
stbuf->st_mode |= S_IFREG;
stbuf->st_size = get_size(meta["Content-Length"].c_str());
if(S_ISREG(stbuf->st_mode))
stbuf->st_blocks = get_blocks(stbuf->st_size);
stbuf->st_uid = get_uid(meta["x-amz-meta-uid"].c_str());
stbuf->st_gid = get_gid(meta["x-amz-meta-gid"].c_str());
add_stat_cache_entry(path, stbuf);
return 0;
}
//
// Check the object uid and gid for write/read/execute.
// The param "mask" is as same as access() function.
// If there is not a target file, this function returns -ENOENT.
// If the target file can be accessed, the result always is 0.
//
// path: the target object path
// mask: bit field(F_OK, R_OK, W_OK, X_OK) like access().
// stat: NULL or the pointer of struct stat.
//
static int check_object_access(const char *path, int mask, struct stat* pstbuf)
{
int result;
struct stat st;
struct stat* pst = (pstbuf ? pstbuf : &st);
struct fuse_context* pcxt;
//if(foreground)
// printf(" check_object_access[path=%s]\n", path);
if(NULL == (pcxt = fuse_get_context())){
return -EIO;
}
memset(pst, 0, sizeof(struct stat));
if(0 != (result = get_object_attribute(path, pst))){
// If there is not tha target file(object), reusult is -ENOENT.
return result;
}
if(0 == pcxt->uid){
// root is allowed all accessing.
return 0;
}
if(F_OK == mask){
// if there is a file, always return allowed.
return 0;
}
// compare file mode and uid/gid + mask.
mode_t mode = pst->st_mode;
mode_t base_mask = 0;
if(pcxt->uid == pst->st_uid){
base_mask = S_IRWXU;
}else if(pcxt->gid == pst->st_gid){
base_mask = S_IRWXG;
}else{
if(1 == is_uid_inculde_group(pcxt->uid, pst->st_gid)){
base_mask = S_IRWXG;
}else{
base_mask = S_IRWXO;
}
}
mode &= base_mask;
if(X_OK == (mask & X_OK)){
if(0 == (mode & (S_IXUSR | S_IXGRP | S_IXOTH))){
return -EPERM;
}
}
if(W_OK == (mask & W_OK)){
if(0 == (mode & (S_IWUSR | S_IWGRP | S_IWOTH))){
return -EACCES;
}
}
if(R_OK == (mask & R_OK)){
if(0 == (mode & (S_IRUSR | S_IRGRP | S_IROTH))){
return -EACCES;
}
}
if(0 == mode){
return -EACCES;
}
return 0;
}
//
// Check accessing the parent directories of the object by uid and gid.
//
static int check_parent_object_access(const char *path, int mask)
{
string parent;
int result;
//if(foreground)
// printf(" check_parent_object_access[path=%s]\n", path);
for(parent = mydirname(path); 0 < parent.size(); parent = mydirname(parent.c_str())){
if(parent == "."){
parent = "/";
}
if(0 != (result = check_object_access(parent.c_str(), mask, NULL))){
return result;
}
if(parent == "/" || parent == "."){
break;
}
}
return 0;
}
// Get fd in mapping data by path
static int get_opened_fd(const char* path)
{
int fd = -1;
pthread_mutex_lock( &s3fs_descriptors_lock );
if(s3fs_pathtofd.find(string(path)) != s3fs_pathtofd.end()){
fd = s3fs_pathtofd[string(path)];
if(foreground){
cout << " get_opened_fd: found fd [path=" << path << "][fd=" << fd << "]" << endl;
}
}
pthread_mutex_unlock( &s3fs_descriptors_lock );
return fd;
}
int get_local_fd(const char* path) {
int fd = -1;
int result;
struct stat st;
char *s3_realpath;
CURL *curl = NULL;
string url;
string resource;
string local_md5;
string baseName = mybasename(path);
string resolved_path(use_cache + "/" + bucket);
string cache_path(resolved_path + path);
headers_t responseHeaders;
if(foreground)
cout << " get_local_fd[path=" << path << "]" << endl;
s3_realpath = get_realpath(path);
resource = urlEncode(service_path + bucket + s3_realpath);
url = host + resource;
Summary of Changes(1.62 -> 1.63) 1) Lifetime for the stats cache Added the new option "stat_cache_expire". This option which is specified by seconds means the lifetime for each stats cache entry. If this option is not specified, the stats cache is kept in s3fs process until the stats cache grown to maximum size. (default) If this option is specified, the stats cache entry is out from the memory when the entry expires time. 2) Enable file permission s3fs before 1.62 did not consider the file access permission. s3fs after this version can consider it. For access permission, the s3fs_getattr() function was divided into sub function which can check the file access permission. It is like access() function. And the function calling the s3fs_getattr() calls this new sub function instead of s3fs_getattr(). Last the s3fs_opendir() function which is called by FUSE was added for checking directory access permission when listing the files in directory. 3) UID/GUID When a file or a directory was created, the s3fs could not set the UID/GID as the user who executed a command. (Almost the UID/GID are root, because the s3fs run by root.) After this version, the s3fs set correct UID/GID as the user who executes the commond. 4) About the mtime If the object does not have "x-amz-meta-mtime" meta, the s3fs uses the "Last-Modified" header instead of it. But the s3fs had a bug in this code, and this version fixed this bug. When user modified the file, the s3fs did not update the mtime of the file. This version fixed this bug. In the get_local_fd() function, the local file's mtime was changed only when s3fs run with "use_cache" option. This version always updates the mtime whether the local cache file is used or not. And s3fs_flush ( ) function set the mtime of local cache file from S3 object mtime, but it was wrong . This version is that the s3fs_flush ( ) changes the mtime of S3 object from the local cache file or the tmpfile . The s3fs cuts some requests, because the s3fs can always check mtime whether the s3fs uses or does not use the local cache file. 5) A case of no "x-amz-meta-mode" If the object did not have "x-amz-meta-mtime" mete, the s3fs recognized the file as not regular file. After this version, the s3fs recognizes the file as regular file. 6) "." and ".." directory The s3fs_readdir() did not return "X" and "XX" directory name. After this version, the s3fs is changed that it returns "X" and "XX". Example, the result of "ls" lists "X" and "XX" directory. 7) Fixed a bug The insert_object() had a bug, and it is fixed. git-svn-id: http://s3fs.googlecode.com/svn/trunk@390 df820570-a93a-0410-bd06-b72b767a4274
2013-02-24 08:58:54 +00:00
result = curl_get_headers(s3_realpath, responseHeaders);
if(result != 0) {
free(s3_realpath);
return -result;
}
Summary of Changes(1.62 -> 1.63) 1) Lifetime for the stats cache Added the new option "stat_cache_expire". This option which is specified by seconds means the lifetime for each stats cache entry. If this option is not specified, the stats cache is kept in s3fs process until the stats cache grown to maximum size. (default) If this option is specified, the stats cache entry is out from the memory when the entry expires time. 2) Enable file permission s3fs before 1.62 did not consider the file access permission. s3fs after this version can consider it. For access permission, the s3fs_getattr() function was divided into sub function which can check the file access permission. It is like access() function. And the function calling the s3fs_getattr() calls this new sub function instead of s3fs_getattr(). Last the s3fs_opendir() function which is called by FUSE was added for checking directory access permission when listing the files in directory. 3) UID/GUID When a file or a directory was created, the s3fs could not set the UID/GID as the user who executed a command. (Almost the UID/GID are root, because the s3fs run by root.) After this version, the s3fs set correct UID/GID as the user who executes the commond. 4) About the mtime If the object does not have "x-amz-meta-mtime" meta, the s3fs uses the "Last-Modified" header instead of it. But the s3fs had a bug in this code, and this version fixed this bug. When user modified the file, the s3fs did not update the mtime of the file. This version fixed this bug. In the get_local_fd() function, the local file's mtime was changed only when s3fs run with "use_cache" option. This version always updates the mtime whether the local cache file is used or not. And s3fs_flush ( ) function set the mtime of local cache file from S3 object mtime, but it was wrong . This version is that the s3fs_flush ( ) changes the mtime of S3 object from the local cache file or the tmpfile . The s3fs cuts some requests, because the s3fs can always check mtime whether the s3fs uses or does not use the local cache file. 5) A case of no "x-amz-meta-mode" If the object did not have "x-amz-meta-mtime" mete, the s3fs recognized the file as not regular file. After this version, the s3fs recognizes the file as regular file. 6) "." and ".." directory The s3fs_readdir() did not return "X" and "XX" directory name. After this version, the s3fs is changed that it returns "X" and "XX". Example, the result of "ls" lists "X" and "XX" directory. 7) Fixed a bug The insert_object() had a bug, and it is fixed. git-svn-id: http://s3fs.googlecode.com/svn/trunk@390 df820570-a93a-0410-bd06-b72b767a4274
2013-02-24 08:58:54 +00:00
if(use_cache.size() > 0) {
fd = open(cache_path.c_str(), O_RDWR); // ### TODO should really somehow obey flags here
if(fd != -1) {
if((fstat(fd, &st)) == -1) {
close(fd);
free(s3_realpath);
YIKES(-errno);
}
// if the local and remote mtime/size
// do not match we have an invalid cache entry
if(str(st.st_size) != responseHeaders["Content-Length"] ||
(str(st.st_mtime) != responseHeaders["x-amz-meta-mtime"])) {
if(close(fd) == -1){
free(s3_realpath);
YIKES(-errno);
}
fd = -1;
}
}
}
free(s3_realpath);
// need to download?
if(fd == -1) {
mode_t mode = get_mode(responseHeaders["x-amz-meta-mode"].c_str());
if(use_cache.size() > 0) {
// only download files, not folders
if (S_ISREG(mode)) {
mkdirp(resolved_path + mydirname(path), 0777);
fd = open(cache_path.c_str(), O_CREAT|O_RDWR|O_TRUNC, mode);
} else {
// its a folder; do *not* create anything in local cache...
// TODO: do this in a better way)
fd = fileno(tmpfile());
}
} else {
fd = fileno(tmpfile());
}
if(fd == -1)
YIKES(-errno);
FILE *f = fdopen(fd, "w+");
if(f == 0){
close(fd);
YIKES(-errno);
}
if(foreground)
cout << " downloading[path=" << path << "][fd=" << fd << "]" << endl;
if(debug)
syslog(LOG_DEBUG, "LOCAL FD");
auto_curl_slist headers;
string date = get_date();
string my_url = prepare_url(url.c_str());
headers.append("Date: " + date);
headers.append("Content-Type: ");
if(public_bucket.substr(0,1) != "1") {
headers.append("Authorization: AWS " + AWSAccessKeyId + ":" +
calc_signature("GET", "", date, headers.get(), resource));
}
curl = create_curl_handle();
curl_easy_setopt(curl, CURLOPT_FILE, f);
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers.get());
curl_easy_setopt(curl, CURLOPT_URL, my_url.c_str());
result = my_curl_easy_perform(curl, NULL, f);
if(result != 0) {
destroy_curl_handle(curl);
fclose(f);
return -result;
}
// only one of these is needed...
fflush(f);
fsync(fd);
if(fd == -1)
YIKES(-errno);
Summary of Changes(1.62 -> 1.63) 1) Lifetime for the stats cache Added the new option "stat_cache_expire". This option which is specified by seconds means the lifetime for each stats cache entry. If this option is not specified, the stats cache is kept in s3fs process until the stats cache grown to maximum size. (default) If this option is specified, the stats cache entry is out from the memory when the entry expires time. 2) Enable file permission s3fs before 1.62 did not consider the file access permission. s3fs after this version can consider it. For access permission, the s3fs_getattr() function was divided into sub function which can check the file access permission. It is like access() function. And the function calling the s3fs_getattr() calls this new sub function instead of s3fs_getattr(). Last the s3fs_opendir() function which is called by FUSE was added for checking directory access permission when listing the files in directory. 3) UID/GUID When a file or a directory was created, the s3fs could not set the UID/GID as the user who executed a command. (Almost the UID/GID are root, because the s3fs run by root.) After this version, the s3fs set correct UID/GID as the user who executes the commond. 4) About the mtime If the object does not have "x-amz-meta-mtime" meta, the s3fs uses the "Last-Modified" header instead of it. But the s3fs had a bug in this code, and this version fixed this bug. When user modified the file, the s3fs did not update the mtime of the file. This version fixed this bug. In the get_local_fd() function, the local file's mtime was changed only when s3fs run with "use_cache" option. This version always updates the mtime whether the local cache file is used or not. And s3fs_flush ( ) function set the mtime of local cache file from S3 object mtime, but it was wrong . This version is that the s3fs_flush ( ) changes the mtime of S3 object from the local cache file or the tmpfile . The s3fs cuts some requests, because the s3fs can always check mtime whether the s3fs uses or does not use the local cache file. 5) A case of no "x-amz-meta-mode" If the object did not have "x-amz-meta-mtime" mete, the s3fs recognized the file as not regular file. After this version, the s3fs recognizes the file as regular file. 6) "." and ".." directory The s3fs_readdir() did not return "X" and "XX" directory name. After this version, the s3fs is changed that it returns "X" and "XX". Example, the result of "ls" lists "X" and "XX" directory. 7) Fixed a bug The insert_object() had a bug, and it is fixed. git-svn-id: http://s3fs.googlecode.com/svn/trunk@390 df820570-a93a-0410-bd06-b72b767a4274
2013-02-24 08:58:54 +00:00
if(S_ISREG(mode) && !S_ISLNK(mode)) {
// make the file's mtime match that of the file on s3
Summary of Changes(1.62 -> 1.63) 1) Lifetime for the stats cache Added the new option "stat_cache_expire". This option which is specified by seconds means the lifetime for each stats cache entry. If this option is not specified, the stats cache is kept in s3fs process until the stats cache grown to maximum size. (default) If this option is specified, the stats cache entry is out from the memory when the entry expires time. 2) Enable file permission s3fs before 1.62 did not consider the file access permission. s3fs after this version can consider it. For access permission, the s3fs_getattr() function was divided into sub function which can check the file access permission. It is like access() function. And the function calling the s3fs_getattr() calls this new sub function instead of s3fs_getattr(). Last the s3fs_opendir() function which is called by FUSE was added for checking directory access permission when listing the files in directory. 3) UID/GUID When a file or a directory was created, the s3fs could not set the UID/GID as the user who executed a command. (Almost the UID/GID are root, because the s3fs run by root.) After this version, the s3fs set correct UID/GID as the user who executes the commond. 4) About the mtime If the object does not have "x-amz-meta-mtime" meta, the s3fs uses the "Last-Modified" header instead of it. But the s3fs had a bug in this code, and this version fixed this bug. When user modified the file, the s3fs did not update the mtime of the file. This version fixed this bug. In the get_local_fd() function, the local file's mtime was changed only when s3fs run with "use_cache" option. This version always updates the mtime whether the local cache file is used or not. And s3fs_flush ( ) function set the mtime of local cache file from S3 object mtime, but it was wrong . This version is that the s3fs_flush ( ) changes the mtime of S3 object from the local cache file or the tmpfile . The s3fs cuts some requests, because the s3fs can always check mtime whether the s3fs uses or does not use the local cache file. 5) A case of no "x-amz-meta-mode" If the object did not have "x-amz-meta-mtime" mete, the s3fs recognized the file as not regular file. After this version, the s3fs recognizes the file as regular file. 6) "." and ".." directory The s3fs_readdir() did not return "X" and "XX" directory name. After this version, the s3fs is changed that it returns "X" and "XX". Example, the result of "ls" lists "X" and "XX" directory. 7) Fixed a bug The insert_object() had a bug, and it is fixed. git-svn-id: http://s3fs.googlecode.com/svn/trunk@390 df820570-a93a-0410-bd06-b72b767a4274
2013-02-24 08:58:54 +00:00
// if fd is tmpfile, but we force tor set mtime.
struct timeval tv[2];
tv[0].tv_sec = get_mtime(responseHeaders["x-amz-meta-mtime"].c_str());
tv[0].tv_usec= 0L;
tv[1].tv_sec = tv[0].tv_sec;
tv[1].tv_usec= 0L;
if(-1 == futimes(fd, tv)){
fclose(f);
YIKES(-errno);
}
}
}
destroy_curl_handle(curl);
return fd;
}
/**
* create or update s3 meta
* @return fuse return code
*/
static int put_headers(const char *path, headers_t meta) {
int result;
char *s3_realpath;
string url;
string resource;
struct stat buf;
struct BodyStruct body;
CURL *curl = NULL;
if(foreground)
cout << " put_headers[path=" << path << "]" << endl;
// files larger than 5GB must be modified via the multipart interface
Summary of Changes(1.62 -> 1.63) 1) Lifetime for the stats cache Added the new option "stat_cache_expire". This option which is specified by seconds means the lifetime for each stats cache entry. If this option is not specified, the stats cache is kept in s3fs process until the stats cache grown to maximum size. (default) If this option is specified, the stats cache entry is out from the memory when the entry expires time. 2) Enable file permission s3fs before 1.62 did not consider the file access permission. s3fs after this version can consider it. For access permission, the s3fs_getattr() function was divided into sub function which can check the file access permission. It is like access() function. And the function calling the s3fs_getattr() calls this new sub function instead of s3fs_getattr(). Last the s3fs_opendir() function which is called by FUSE was added for checking directory access permission when listing the files in directory. 3) UID/GUID When a file or a directory was created, the s3fs could not set the UID/GID as the user who executed a command. (Almost the UID/GID are root, because the s3fs run by root.) After this version, the s3fs set correct UID/GID as the user who executes the commond. 4) About the mtime If the object does not have "x-amz-meta-mtime" meta, the s3fs uses the "Last-Modified" header instead of it. But the s3fs had a bug in this code, and this version fixed this bug. When user modified the file, the s3fs did not update the mtime of the file. This version fixed this bug. In the get_local_fd() function, the local file's mtime was changed only when s3fs run with "use_cache" option. This version always updates the mtime whether the local cache file is used or not. And s3fs_flush ( ) function set the mtime of local cache file from S3 object mtime, but it was wrong . This version is that the s3fs_flush ( ) changes the mtime of S3 object from the local cache file or the tmpfile . The s3fs cuts some requests, because the s3fs can always check mtime whether the s3fs uses or does not use the local cache file. 5) A case of no "x-amz-meta-mode" If the object did not have "x-amz-meta-mtime" mete, the s3fs recognized the file as not regular file. After this version, the s3fs recognizes the file as regular file. 6) "." and ".." directory The s3fs_readdir() did not return "X" and "XX" directory name. After this version, the s3fs is changed that it returns "X" and "XX". Example, the result of "ls" lists "X" and "XX" directory. 7) Fixed a bug The insert_object() had a bug, and it is fixed. git-svn-id: http://s3fs.googlecode.com/svn/trunk@390 df820570-a93a-0410-bd06-b72b767a4274
2013-02-24 08:58:54 +00:00
get_object_attribute(path, &buf);
if(buf.st_size >= FIVE_GB)
return(put_multipart_headers(path, meta));
s3_realpath = get_realpath(path);
resource = urlEncode(service_path + bucket + s3_realpath);
url = host + resource;
body.text = (char *)malloc(1);
body.size = 0;
auto_curl_slist headers;
string date = get_date();
headers.append("Date: " + date);
meta["x-amz-acl"] = default_acl;
string ContentType = meta["Content-Type"];
for (headers_t::iterator iter = meta.begin(); iter != meta.end(); ++iter) {
string key = (*iter).first;
string value = (*iter).second;
if (key == "Content-Type")
headers.append(key + ":" + value);
if (key.substr(0,9) == "x-amz-acl")
headers.append(key + ":" + value);
if (key.substr(0,10) == "x-amz-meta")
headers.append(key + ":" + value);
if (key == "x-amz-copy-source")
headers.append(key + ":" + value);
}
if(use_rrs.substr(0,1) == "1")
headers.append("x-amz-storage-class:REDUCED_REDUNDANCY");
if(public_bucket.substr(0,1) != "1")
headers.append("Authorization: AWS " + AWSAccessKeyId + ":" +
calc_signature("PUT", ContentType, date, headers.get(), resource));
curl = create_curl_handle();
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&body);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
curl_easy_setopt(curl, CURLOPT_UPLOAD, true); // HTTP PUT
curl_easy_setopt(curl, CURLOPT_INFILESIZE, 0); // Content-Length
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers.get());
if(debug)
syslog(LOG_DEBUG, "copy path=%s", path);
if(foreground)
cout << " copying[path=" << path << "]" << endl;
string my_url = prepare_url(url.c_str());
curl_easy_setopt(curl, CURLOPT_URL, my_url.c_str());
result = my_curl_easy_perform(curl, &body);
destroy_curl_handle(curl);
if(body.text)
free(body.text);
free(s3_realpath);
if(result != 0)
return result;
// Update mtime in local file cache.
if(meta.count("x-amz-meta-mtime") > 0 && use_cache.size() > 0) {
struct stat st;
struct utimbuf n_mtime;
string cache_path(use_cache + "/" + bucket + path);
if((stat(cache_path.c_str(), &st)) == 0) {
n_mtime.modtime = get_mtime(meta["x-amz-meta-mtime"].c_str());
n_mtime.actime = n_mtime.modtime;
if((utime(cache_path.c_str(), &n_mtime)) == -1) {
YIKES(-errno);
}
}
}
return 0;
}
static int put_multipart_headers(const char *path, headers_t meta) {
int result;
char *s3_realpath;
string url;
string resource;
string upload_id;
struct stat buf;
struct BodyStruct body;
vector <file_part> parts;
if(foreground)
cout << " put_multipart_headers[path=" << path << "]" << endl;
s3_realpath = get_realpath(path);
resource = urlEncode(service_path + bucket + s3_realpath);
url = host + resource;
free(s3_realpath);
body.text = (char *)malloc(1);
body.size = 0;
Summary of Changes(1.62 -> 1.63) 1) Lifetime for the stats cache Added the new option "stat_cache_expire". This option which is specified by seconds means the lifetime for each stats cache entry. If this option is not specified, the stats cache is kept in s3fs process until the stats cache grown to maximum size. (default) If this option is specified, the stats cache entry is out from the memory when the entry expires time. 2) Enable file permission s3fs before 1.62 did not consider the file access permission. s3fs after this version can consider it. For access permission, the s3fs_getattr() function was divided into sub function which can check the file access permission. It is like access() function. And the function calling the s3fs_getattr() calls this new sub function instead of s3fs_getattr(). Last the s3fs_opendir() function which is called by FUSE was added for checking directory access permission when listing the files in directory. 3) UID/GUID When a file or a directory was created, the s3fs could not set the UID/GID as the user who executed a command. (Almost the UID/GID are root, because the s3fs run by root.) After this version, the s3fs set correct UID/GID as the user who executes the commond. 4) About the mtime If the object does not have "x-amz-meta-mtime" meta, the s3fs uses the "Last-Modified" header instead of it. But the s3fs had a bug in this code, and this version fixed this bug. When user modified the file, the s3fs did not update the mtime of the file. This version fixed this bug. In the get_local_fd() function, the local file's mtime was changed only when s3fs run with "use_cache" option. This version always updates the mtime whether the local cache file is used or not. And s3fs_flush ( ) function set the mtime of local cache file from S3 object mtime, but it was wrong . This version is that the s3fs_flush ( ) changes the mtime of S3 object from the local cache file or the tmpfile . The s3fs cuts some requests, because the s3fs can always check mtime whether the s3fs uses or does not use the local cache file. 5) A case of no "x-amz-meta-mode" If the object did not have "x-amz-meta-mtime" mete, the s3fs recognized the file as not regular file. After this version, the s3fs recognizes the file as regular file. 6) "." and ".." directory The s3fs_readdir() did not return "X" and "XX" directory name. After this version, the s3fs is changed that it returns "X" and "XX". Example, the result of "ls" lists "X" and "XX" directory. 7) Fixed a bug The insert_object() had a bug, and it is fixed. git-svn-id: http://s3fs.googlecode.com/svn/trunk@390 df820570-a93a-0410-bd06-b72b767a4274
2013-02-24 08:58:54 +00:00
// already checked by check_object_access(), so only get attr.
get_object_attribute(path, &buf);
upload_id = initiate_multipart_upload(path, buf.st_size, meta);
if(upload_id.size() == 0){
if(body.text)
free(body.text);
return(-EIO);
}
off_t chunk = 0;
off_t bytes_written = 0;
off_t bytes_remaining = buf.st_size;
while(bytes_remaining > 0) {
file_part part;
if(bytes_remaining > MAX_COPY_SOURCE_SIZE)
chunk = MAX_COPY_SOURCE_SIZE;
else
chunk = bytes_remaining - 1;
stringstream ss;
ss << "bytes=" << bytes_written << "-" << (bytes_written + chunk);
meta["x-amz-copy-source-range"] = ss.str();
part.etag = copy_part(path, path, parts.size() + 1, upload_id, meta);
parts.push_back(part);
bytes_written += (chunk + 1);
bytes_remaining = buf.st_size - bytes_written;
}
result = complete_multipart_upload(path, upload_id, parts);
if(result != 0) {
if(body.text)
free(body.text);
return -EIO;
}
// Update mtime in local file cache.
if(meta.count("x-amz-meta-mtime") > 0 && use_cache.size() > 0) {
struct stat st;
struct utimbuf n_mtime;
string cache_path(use_cache + "/" + bucket + path);
if((stat(cache_path.c_str(), &st)) == 0) {
n_mtime.modtime = get_mtime(meta["x-amz-meta-mtime"].c_str());
n_mtime.actime = n_mtime.modtime;
if((utime(cache_path.c_str(), &n_mtime)) == -1) {
if(body.text)
free(body.text);
YIKES(-errno);
}
}
}
if(body.text)
free(body.text);
return 0;
}
static int put_local_fd_small_file(const char* path, headers_t meta, int fd) {
string resource;
string url;
char *s3_realpath;
struct stat st;
CURL *curl = NULL;
if(foreground)
printf(" put_local_fd_small_file[path=%s][fd=%d]\n", path, fd);
if(fstat(fd, &st) == -1)
YIKES(-errno);
s3_realpath = get_realpath(path);
resource = urlEncode(service_path + bucket + s3_realpath);
url = host + resource;
free(s3_realpath);
int result;
struct BodyStruct body;
auto_curl_slist headers;
string date = get_date();
body.text = (char *) malloc(1);
body.size = 0;
curl = create_curl_handle();
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&body);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
curl_easy_setopt(curl, CURLOPT_UPLOAD, true); // HTTP PUT
curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, static_cast<curl_off_t>(st.st_size)); // Content-Length
FILE* f = fdopen(fd, "rb");
if(f == 0){
if(body.text)
free(body.text);
YIKES(-errno);
}
curl_easy_setopt(curl, CURLOPT_INFILE, f);
string ContentType = meta["Content-Type"];
headers.append("Date: " + date);
meta["x-amz-acl"] = default_acl;
for (headers_t::iterator iter = meta.begin(); iter != meta.end(); ++iter) {
string key = (*iter).first;
string value = (*iter).second;
if (key == "Content-Type")
headers.append(key + ":" + value);
if (key.substr(0,9) == "x-amz-acl")
headers.append(key + ":" + value);
if (key.substr(0,10) == "x-amz-meta")
headers.append(key + ":" + value);
}
if(use_rrs.substr(0,1) == "1")
headers.append("x-amz-storage-class:REDUCED_REDUNDANCY");
if(public_bucket.substr(0,1) != "1")
headers.append("Authorization: AWS " + AWSAccessKeyId + ":" +
calc_signature("PUT", ContentType, date, headers.get(), resource));
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers.get());
if(foreground)
printf(" uploading[path=%s][fd=%d][size=%zd]\n", path, fd, st.st_size);
string my_url = prepare_url(url.c_str());
curl_easy_setopt(curl, CURLOPT_URL, my_url.c_str());
result = my_curl_easy_perform(curl, &body, f);
if(body.text)
free(body.text);
destroy_curl_handle(curl);
if(result != 0)
return result;
return 0;
}
static int put_local_fd_big_file(const char* path, headers_t meta, int fd) {
struct stat st;
off_t lSize;
int partfd = -1;
FILE* pSourceFile;
FILE* pPartFile;
char *buffer;
unsigned long lBufferSize = 0;
size_t bytesRead;
size_t bytesWritten;
string uploadId;
vector <file_part> parts;
if(foreground)
printf(" put_local_fd_big_file[path=%s][fd=%d]\n", path, fd);
if(fstat(fd, &st) == -1)
YIKES(-errno);
uploadId = initiate_multipart_upload(path, st.st_size, meta);
if(uploadId.size() == 0) {
syslog(LOG_ERR, "Could not determine UploadId");
return(-EIO);
}
// Open the source file
pSourceFile = fdopen(fd, "rb");
if(pSourceFile == NULL) {
syslog(LOG_ERR, "%d###result=%d", __LINE__, errno); \
return(-errno);
}
// Source sucessfully opened, obtain file size:
lSize = st.st_size;
lBufferSize = 0;
// cycle through open fd, pulling off 10MB chunks at a time
while(lSize > 0) {
file_part part;
if(lSize >= MULTIPART_SIZE)
lBufferSize = MULTIPART_SIZE;
else
lBufferSize = lSize;
lSize = lSize - lBufferSize;
if((buffer = (char *) malloc(sizeof(char) * lBufferSize)) == NULL) {
syslog(LOG_CRIT, "Could not allocate memory for buffer\n");
exit(EXIT_FAILURE);
}
// copy the file portion into the buffer:
bytesRead = fread(buffer, 1, lBufferSize, pSourceFile);
if(bytesRead != lBufferSize) {
syslog(LOG_ERR, "%d ### bytesRead:%zu does not match lBufferSize: %lu\n",
__LINE__, bytesRead, lBufferSize);
if(buffer)
free(buffer);
return(-EIO);
}
// create uniq temporary file
strncpy(part.path, "/tmp/s3fs.XXXXXX", sizeof part.path);
if((partfd = mkstemp(part.path)) == -1) {
if(buffer)
free(buffer);
YIKES(-errno);
}
// open a temporary file for upload
if((pPartFile = fdopen(partfd, "wb")) == NULL) {
syslog(LOG_ERR, "%d ### Could not open temporary file: errno %i\n",
__LINE__, errno);
close(partfd);
if(buffer)
free(buffer);
return(-errno);
}
// copy buffer to temporary file
bytesWritten = fwrite(buffer, 1, (size_t)lBufferSize, pPartFile);
if(bytesWritten != lBufferSize) {
syslog(LOG_ERR, "%d ### bytesWritten:%zu does not match lBufferSize: %lu\n",
__LINE__, bytesWritten, lBufferSize);
fclose(pPartFile);
if(buffer)
free(buffer);
return(-EIO);
}
fclose(pPartFile);
if(buffer)
free(buffer);
part.etag = upload_part(path, part.path, parts.size() + 1, uploadId);
// delete temporary part file
if(remove(part.path) != 0)
YIKES(-errno);
parts.push_back(part);
} // while(lSize > 0)
return complete_multipart_upload(path, uploadId, parts);
}
/**
* create or update s3 object
* @return fuse return code
*/
static int put_local_fd(const char* path, headers_t meta, int fd) {
int result;
struct stat st;
if(foreground)
cout << " put_local_fd[path=" << path << "][fd=" << fd << "]" << endl;
if(fstat(fd, &st) == -1)
YIKES(-errno);
/*
* Make decision to do multi upload (or not) based upon file size
*
* According to the AWS spec:
* - 1 to 10,000 parts are allowed
* - minimum size of parts is 5MB (expect for the last part)
*
* For our application, we will define part size to be 10MB (10 * 2^20 Bytes)
* maximum file size will be ~64 GB - 2 ** 36
*
* Initially uploads will be done serially
*
* If file is > 20MB, then multipart will kick in
*/
if(st.st_size > 68719476735LL ) { // 64GB - 1
// close f ?
return -ENOTSUP;
}
if(st.st_size >= 20971520 && !nomultipart) { // 20MB
// Additional time is needed for large files
if(readwrite_timeout < 120)
readwrite_timeout = 120;
result = put_local_fd_big_file(path, meta, fd);
} else {
result = put_local_fd_small_file(path, meta, fd);
}
return result;
}
/*
* initiate_multipart_upload
*
* Example :
* POST /example-object?uploads HTTP/1.1
* Host: example-bucket.s3.amazonaws.com
* Date: Mon, 1 Nov 2010 20:34:56 GMT
* Authorization: AWS VGhpcyBtZXNzYWdlIHNpZ25lZCBieSBlbHZpbmc=
*/
string initiate_multipart_upload(const char *path, off_t size, headers_t meta) {
CURL *curl = NULL;
int result;
string auth;
string acl;
string url;
string my_url;
string date;
string raw_date;
string resource;
string upload_id = "";
string ContentType;
char *s3_realpath;
struct BodyStruct body;
struct curl_slist *slist=NULL;
if(foreground)
cout << " initiate_multipart_upload [path=" << path << "][size=" << size << "]" << endl;
body.text = (char *)malloc(1);
body.size = 0;
s3_realpath = get_realpath(path);
resource = urlEncode(service_path + bucket + s3_realpath);
resource.append("?uploads");
url = host + resource;
my_url = prepare_url(url.c_str());
free(s3_realpath);
curl = create_curl_handle();
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&body);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
curl_easy_setopt(curl, CURLOPT_POST, true);
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, 0);
date.assign("Date: ");
raw_date = get_date();
date.append(raw_date);
slist = curl_slist_append(slist, date.c_str());
slist = curl_slist_append(slist, "Accept:");
slist = curl_slist_append(slist, "Content-Length:");
ContentType.assign("Content-Type: ");
string ctype_data;
ctype_data.assign(lookupMimeType(path));
ContentType.append(ctype_data);
slist = curl_slist_append(slist, ContentType.c_str());
// x-amz headers: (a) alphabetical order and (b) no spaces after colon
acl.assign("x-amz-acl:");
acl.append(default_acl);
slist = curl_slist_append(slist, acl.c_str());
for(headers_t::iterator iter = meta.begin(); iter != meta.end(); ++iter) {
string key = (*iter).first;
string value = (*iter).second;
if(key.substr(0,10) == "x-amz-meta") {
string entry;
entry.assign(key);
entry.append(":");
entry.append(value);
slist = curl_slist_append(slist, entry.c_str());
}
}
if(use_rrs.substr(0,1) == "1")
slist = curl_slist_append(slist, "x-amz-storage-class:REDUCED_REDUNDANCY");
if(public_bucket.substr(0,1) != "1") {
auth.assign("Authorization: AWS ");
auth.append(AWSAccessKeyId);
auth.append(":");
auth.append(calc_signature("POST", ctype_data, raw_date, slist, resource));
slist = curl_slist_append(slist, auth.c_str());
}
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist);
curl_easy_setopt(curl, CURLOPT_URL, my_url.c_str());
result = my_curl_easy_perform(curl, &body);
curl_slist_free_all(slist);
destroy_curl_handle(curl);
if(result != 0) {
if(body.text)
free(body.text);
return upload_id;
}
// XML returns UploadId
// Parse XML body for UploadId
upload_id.clear();
xmlDocPtr doc = xmlReadMemory(body.text, body.size, "", NULL, 0);
if(doc != NULL && doc->children != NULL) {
for(xmlNodePtr cur_node = doc->children->children;
cur_node != NULL;
cur_node = cur_node->next) {
// string cur_node_name(reinterpret_cast<const char *>(cur_node->name));
// printf("cur_node_name: %s\n", cur_node_name.c_str());
if(cur_node->type == XML_ELEMENT_NODE) {
string elementName = reinterpret_cast<const char*>(cur_node->name);
// printf("elementName: %s\n", elementName.c_str());
if(cur_node->children != NULL) {
if(cur_node->children->type == XML_TEXT_NODE) {
if(elementName == "UploadId") {
upload_id = reinterpret_cast<const char *>(cur_node->children->content);
}
}
}
}
} // for (xmlNodePtr cur_node = doc->children->children;
} // if (doc != NULL && doc->children != NULL)
xmlFreeDoc(doc);
// clean up
if(body.text)
free(body.text);
body.size = 0;
return upload_id;
}
static int complete_multipart_upload(const char *path, string upload_id,
vector <file_part> parts) {
CURL *curl = NULL;
char *pData;
int result;
int i, j;
string auth;
string date;
string raw_date;
string url;
string my_url;
string resource;
string postContent;
char *s3_realpath;
struct BodyStruct body;
struct WriteThis pooh;
struct curl_slist *slist = NULL;
if(foreground)
cout << " complete_multipart_upload [path=" << path << "]" << endl;
// initialization of variables
curl = NULL;
postContent.clear();
postContent.append("<CompleteMultipartUpload>\n");
for(i = 0, j = parts.size(); i < j; i++) {
postContent.append(" <Part>\n");
postContent.append(" <PartNumber>");
postContent.append(IntToStr(i+1));
postContent.append("</PartNumber>\n");
postContent.append(" <ETag>");
postContent.append(parts[i].etag.insert(0, "\"").append("\""));
postContent.append("</ETag>\n");
postContent.append(" </Part>\n");
}
postContent.append("</CompleteMultipartUpload>\n");
if((pData = (char *)malloc(postContent.size() + 1)) == NULL)
YIKES(-errno)
pooh.readptr = pData;
pooh.sizeleft = postContent.size();
strcpy(pData, postContent.c_str());
postContent.clear();
s3_realpath = get_realpath(path);
resource = urlEncode(service_path + bucket + s3_realpath);
resource.append("?uploadId=");
resource.append(upload_id);
url = host + resource;
my_url = prepare_url(url.c_str());
body.text = (char *)malloc(1);
body.size = 0;
curl = create_curl_handle();
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&body);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
curl_easy_setopt(curl, CURLOPT_POST, true);
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, (curl_off_t)pooh.sizeleft);
curl_easy_setopt(curl, CURLOPT_READFUNCTION, read_callback);
curl_easy_setopt(curl, CURLOPT_READDATA, &pooh);
date.assign("Date: ");
raw_date = get_date();
date.append(raw_date);
slist = NULL;
slist = curl_slist_append(slist, date.c_str());
slist = curl_slist_append(slist, "Accept:");
slist = curl_slist_append(slist, "Content-Type:");
if(public_bucket.substr(0,1) != "1") {
auth.assign("Authorization: AWS ");
auth.append(AWSAccessKeyId);
auth.append(":");
auth.append(calc_signature("POST", "", raw_date, slist, resource));
slist = curl_slist_append(slist, auth.c_str());
}
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist);
curl_easy_setopt(curl, CURLOPT_URL, my_url.c_str());
result = my_curl_easy_perform(curl, &body);
curl_slist_free_all(slist);
destroy_curl_handle(curl);
if(body.text)
free(body.text);
free(pData);
free(s3_realpath);
return result;
}
string upload_part(const char *path, const char *source, int part_number, string upload_id) {
int fd;
CURL *curl = NULL;
FILE *part_file;
int result;
string url;
string my_url;
string auth;
string resource;
string date;
string raw_date;
string ETag;
char *s3_realpath;
struct stat st;
struct BodyStruct body;
struct BodyStruct header;
struct curl_slist *slist = NULL;
// Now upload the file as the nth part
if(foreground)
cout << " multipart upload [path=" << path << "][part=" << part_number << "]" << endl;
// PUT /ObjectName?partNumber=PartNumber&uploadId=UploadId HTTP/1.1
// Host: BucketName.s3.amazonaws.com
// Date: date
// Content-Length: Size
// Authorization: Signature
// PUT /my-movie.m2ts?partNumber=1&uploadId=VCVsb2FkIElEIGZvciBlbZZpbmcncyBteS1tb3ZpZS5tMnRzIHVwbG9hZR HTTP/1.1
// Host: example-bucket.s3.amazonaws.com
// Date: Mon, 1 Nov 2010 20:34:56 GMT
// Content-Length: 10485760
// Content-MD5: pUNXr/BjKK5G2UKvaRRrOA==
// Authorization: AWS VGhpcyBtZXNzYWdlIHNpZ25lZGGieSRlbHZpbmc=
part_file = fopen(source, "rb");
if(part_file == NULL) {
syslog(LOG_ERR, "%d###result=%d", __LINE__, errno); \
return "";
}
if(fstat(fileno(part_file), &st) == -1) {
fclose(part_file);
syslog(LOG_ERR, "%d###result=%d", __LINE__, errno); \
return "";
}
s3_realpath = get_realpath(path);
resource = urlEncode(service_path + bucket + s3_realpath);
free(s3_realpath);
resource.append("?partNumber=");
resource.append(IntToStr(part_number));
resource.append("&uploadId=");
resource.append(upload_id);
url = host + resource;
my_url = prepare_url(url.c_str());
body.text = (char *)malloc(1);
body.size = 0;
header.text = (char *)malloc(1);
header.size = 0;
curl = create_curl_handle();
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&body);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
curl_easy_setopt(curl, CURLOPT_HEADERDATA, (void *)&header);
curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, WriteMemoryCallback);
curl_easy_setopt(curl, CURLOPT_UPLOAD, true); // HTTP PUT
curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, static_cast<curl_off_t>(st.st_size)); // Content-Length
curl_easy_setopt(curl, CURLOPT_INFILE, part_file);
date.assign("Date: ");
raw_date = get_date();
date.append(raw_date);
slist = NULL;
slist = curl_slist_append(slist, date.c_str());
slist = curl_slist_append(slist, "Accept:");
if(public_bucket.substr(0,1) != "1") {
auth.assign("Authorization: AWS ");
auth.append(AWSAccessKeyId);
auth.append(":");
auth.append(calc_signature("PUT", "", raw_date, slist, resource));
slist = curl_slist_append(slist, auth.c_str());
}
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist);
curl_easy_setopt(curl, CURLOPT_URL, my_url.c_str());
result = my_curl_easy_perform(curl, &body, part_file);
curl_slist_free_all(slist);
destroy_curl_handle(curl);
fclose(part_file);
if(result != 0) {
if(header.text)
free(header.text);
if(body.text)
free(body.text);
return "";
}
// calculate local md5sum, if it matches the header
// ETag value, the upload was successful.
if((fd = open(source, O_RDONLY)) == -1) {
if(header.text)
free(header.text);
if(body.text)
free(body.text);
syslog(LOG_ERR, "%d###result=%d", __LINE__, -fd);
return "";
}
string md5 = md5sum(fd);
close(fd);
if(!md5.empty() && strstr(header.text, md5.c_str())) {
ETag.assign(md5);
} else {
if(header.text)
free(header.text);
if(body.text)
free(body.text);
return "";
}
// clean up
if(header.text)
free(header.text);
if(body.text)
free(body.text);
return ETag;
}
string copy_part(const char *from, const char *to, int part_number, string upload_id, headers_t meta) {
CURL *curl = NULL;
int result;
string url;
string my_url;
string auth;
string resource;
string raw_date;
string ETag;
char *s3_realpath;
struct BodyStruct body;
struct BodyStruct header;
// Now copy the file as the nth part
if(foreground)
printf("copy_part [from=%s] [to=%s]\n", from, to);
s3_realpath = get_realpath(to);
resource = urlEncode(service_path + bucket + s3_realpath);
free(s3_realpath);
resource.append("?partNumber=");
resource.append(IntToStr(part_number));
resource.append("&uploadId=");
resource.append(upload_id);
url = host + resource;
my_url = prepare_url(url.c_str());
body.text = (char *)malloc(1);
body.size = 0;
header.text = (char *)malloc(1);
header.size = 0;
auto_curl_slist headers;
string date = get_date();
headers.append("Date: " + date);
string ContentType = meta["Content-Type"];
meta["x-amz-acl"] = default_acl;
for(headers_t::iterator iter = meta.begin(); iter != meta.end(); ++iter) {
string key = (*iter).first;
string value = (*iter).second;
if (key == "Content-Type")
headers.append(key + ":" + value);
if (key == "x-amz-copy-source")
headers.append(key + ":" + value);
if (key == "x-amz-copy-source-range")
headers.append(key + ":" + value);
}
if(use_rrs.substr(0,1) == "1")
headers.append("x-amz-storage-class:REDUCED_REDUNDANCY");
if(public_bucket.substr(0,1) != "1")
headers.append("Authorization: AWS " + AWSAccessKeyId + ":" +
calc_signature("PUT", ContentType, date, headers.get(), resource));
curl = create_curl_handle();
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&body);
curl_easy_setopt(curl, CURLOPT_HEADERDATA, (void *)&header);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, WriteMemoryCallback);
curl_easy_setopt(curl, CURLOPT_UPLOAD, true); // HTTP PUT
curl_easy_setopt(curl, CURLOPT_INFILESIZE, 0); // Content-Length
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers.get());
curl_easy_setopt(curl, CURLOPT_URL, my_url.c_str());
result = my_curl_easy_perform(curl, &body);
destroy_curl_handle(curl);
if(result != 0) {
if(body.text)
free(body.text);
if(header.text)
free(header.text);
return "";
}
char *start_etag;
char *end_etag;
start_etag = strstr(body.text, "ETag");
end_etag = strstr(body.text, "/ETag>");
start_etag += 11;
ETag.assign(start_etag, (size_t)(end_etag - start_etag - 7));
// clean up
if(body.text)
free(body.text);
if(header.text)
free(header.text);
return ETag;
}
string md5sum(int fd) {
MD5_CTX c;
char buf[512];
char hexbuf[3];
ssize_t bytes;
char md5[2 * MD5_DIGEST_LENGTH + 1];
unsigned char *result = (unsigned char *) malloc(MD5_DIGEST_LENGTH);
memset(buf, 0, 512);
MD5_Init(&c);
while((bytes = read(fd, buf, 512)) > 0) {
MD5_Update(&c, buf, bytes);
memset(buf, 0, 512);
}
MD5_Final(result, &c);
memset(md5, 0, 2 * MD5_DIGEST_LENGTH + 1);
for(int i = 0; i < MD5_DIGEST_LENGTH; i++) {
snprintf(hexbuf, 3, "%02x", result[i]);
strncat(md5, hexbuf, 2);
}
free(result);
lseek(fd, 0, 0);
return string(md5);
}
Summary of Changes(1.62 -> 1.63) 1) Lifetime for the stats cache Added the new option "stat_cache_expire". This option which is specified by seconds means the lifetime for each stats cache entry. If this option is not specified, the stats cache is kept in s3fs process until the stats cache grown to maximum size. (default) If this option is specified, the stats cache entry is out from the memory when the entry expires time. 2) Enable file permission s3fs before 1.62 did not consider the file access permission. s3fs after this version can consider it. For access permission, the s3fs_getattr() function was divided into sub function which can check the file access permission. It is like access() function. And the function calling the s3fs_getattr() calls this new sub function instead of s3fs_getattr(). Last the s3fs_opendir() function which is called by FUSE was added for checking directory access permission when listing the files in directory. 3) UID/GUID When a file or a directory was created, the s3fs could not set the UID/GID as the user who executed a command. (Almost the UID/GID are root, because the s3fs run by root.) After this version, the s3fs set correct UID/GID as the user who executes the commond. 4) About the mtime If the object does not have "x-amz-meta-mtime" meta, the s3fs uses the "Last-Modified" header instead of it. But the s3fs had a bug in this code, and this version fixed this bug. When user modified the file, the s3fs did not update the mtime of the file. This version fixed this bug. In the get_local_fd() function, the local file's mtime was changed only when s3fs run with "use_cache" option. This version always updates the mtime whether the local cache file is used or not. And s3fs_flush ( ) function set the mtime of local cache file from S3 object mtime, but it was wrong . This version is that the s3fs_flush ( ) changes the mtime of S3 object from the local cache file or the tmpfile . The s3fs cuts some requests, because the s3fs can always check mtime whether the s3fs uses or does not use the local cache file. 5) A case of no "x-amz-meta-mode" If the object did not have "x-amz-meta-mtime" mete, the s3fs recognized the file as not regular file. After this version, the s3fs recognizes the file as regular file. 6) "." and ".." directory The s3fs_readdir() did not return "X" and "XX" directory name. After this version, the s3fs is changed that it returns "X" and "XX". Example, the result of "ls" lists "X" and "XX" directory. 7) Fixed a bug The insert_object() had a bug, and it is fixed. git-svn-id: http://s3fs.googlecode.com/svn/trunk@390 df820570-a93a-0410-bd06-b72b767a4274
2013-02-24 08:58:54 +00:00
static int s3fs_getattr(const char *path, struct stat *stbuf)
{
int result;
if(foreground)
printf("s3fs_getattr[path=%s]\n", path);
Summary of Changes(1.62 -> 1.63) 1) Lifetime for the stats cache Added the new option "stat_cache_expire". This option which is specified by seconds means the lifetime for each stats cache entry. If this option is not specified, the stats cache is kept in s3fs process until the stats cache grown to maximum size. (default) If this option is specified, the stats cache entry is out from the memory when the entry expires time. 2) Enable file permission s3fs before 1.62 did not consider the file access permission. s3fs after this version can consider it. For access permission, the s3fs_getattr() function was divided into sub function which can check the file access permission. It is like access() function. And the function calling the s3fs_getattr() calls this new sub function instead of s3fs_getattr(). Last the s3fs_opendir() function which is called by FUSE was added for checking directory access permission when listing the files in directory. 3) UID/GUID When a file or a directory was created, the s3fs could not set the UID/GID as the user who executed a command. (Almost the UID/GID are root, because the s3fs run by root.) After this version, the s3fs set correct UID/GID as the user who executes the commond. 4) About the mtime If the object does not have "x-amz-meta-mtime" meta, the s3fs uses the "Last-Modified" header instead of it. But the s3fs had a bug in this code, and this version fixed this bug. When user modified the file, the s3fs did not update the mtime of the file. This version fixed this bug. In the get_local_fd() function, the local file's mtime was changed only when s3fs run with "use_cache" option. This version always updates the mtime whether the local cache file is used or not. And s3fs_flush ( ) function set the mtime of local cache file from S3 object mtime, but it was wrong . This version is that the s3fs_flush ( ) changes the mtime of S3 object from the local cache file or the tmpfile . The s3fs cuts some requests, because the s3fs can always check mtime whether the s3fs uses or does not use the local cache file. 5) A case of no "x-amz-meta-mode" If the object did not have "x-amz-meta-mtime" mete, the s3fs recognized the file as not regular file. After this version, the s3fs recognizes the file as regular file. 6) "." and ".." directory The s3fs_readdir() did not return "X" and "XX" directory name. After this version, the s3fs is changed that it returns "X" and "XX". Example, the result of "ls" lists "X" and "XX" directory. 7) Fixed a bug The insert_object() had a bug, and it is fixed. git-svn-id: http://s3fs.googlecode.com/svn/trunk@390 df820570-a93a-0410-bd06-b72b767a4274
2013-02-24 08:58:54 +00:00
// check parent directory attribute.
if(0 != (result = check_parent_object_access(path, X_OK))){
return result;
}
Summary of Changes(1.62 -> 1.63) 1) Lifetime for the stats cache Added the new option "stat_cache_expire". This option which is specified by seconds means the lifetime for each stats cache entry. If this option is not specified, the stats cache is kept in s3fs process until the stats cache grown to maximum size. (default) If this option is specified, the stats cache entry is out from the memory when the entry expires time. 2) Enable file permission s3fs before 1.62 did not consider the file access permission. s3fs after this version can consider it. For access permission, the s3fs_getattr() function was divided into sub function which can check the file access permission. It is like access() function. And the function calling the s3fs_getattr() calls this new sub function instead of s3fs_getattr(). Last the s3fs_opendir() function which is called by FUSE was added for checking directory access permission when listing the files in directory. 3) UID/GUID When a file or a directory was created, the s3fs could not set the UID/GID as the user who executed a command. (Almost the UID/GID are root, because the s3fs run by root.) After this version, the s3fs set correct UID/GID as the user who executes the commond. 4) About the mtime If the object does not have "x-amz-meta-mtime" meta, the s3fs uses the "Last-Modified" header instead of it. But the s3fs had a bug in this code, and this version fixed this bug. When user modified the file, the s3fs did not update the mtime of the file. This version fixed this bug. In the get_local_fd() function, the local file's mtime was changed only when s3fs run with "use_cache" option. This version always updates the mtime whether the local cache file is used or not. And s3fs_flush ( ) function set the mtime of local cache file from S3 object mtime, but it was wrong . This version is that the s3fs_flush ( ) changes the mtime of S3 object from the local cache file or the tmpfile . The s3fs cuts some requests, because the s3fs can always check mtime whether the s3fs uses or does not use the local cache file. 5) A case of no "x-amz-meta-mode" If the object did not have "x-amz-meta-mtime" mete, the s3fs recognized the file as not regular file. After this version, the s3fs recognizes the file as regular file. 6) "." and ".." directory The s3fs_readdir() did not return "X" and "XX" directory name. After this version, the s3fs is changed that it returns "X" and "XX". Example, the result of "ls" lists "X" and "XX" directory. 7) Fixed a bug The insert_object() had a bug, and it is fixed. git-svn-id: http://s3fs.googlecode.com/svn/trunk@390 df820570-a93a-0410-bd06-b72b767a4274
2013-02-24 08:58:54 +00:00
return check_object_access(path, F_OK, stbuf);
}
static int s3fs_readlink(const char *path, char *buf, size_t size) {
int fd = -1;
if (size > 0) {
--size; // reserve nil terminator
if(foreground)
cout << "s3fs_readlink[path=" << path << "]" << endl;
fd = get_local_fd(path);
if(fd < 0) {
syslog(LOG_ERR, "line %d: get_local_fd: %d", __LINE__, -fd);
return -EIO;
}
struct stat st;
if(fstat(fd, &st) == -1) {
syslog(LOG_ERR, "line %d: fstat: %d", __LINE__, -errno);
if(fd > 0)
close(fd);
return -errno;
}
if(st.st_size < (off_t)size)
size = st.st_size;
if(pread(fd, buf, size, 0) == -1) {
syslog(LOG_ERR, "line %d: pread: %d", __LINE__, -errno);
if(fd > 0)
close(fd);
return -errno;
}
buf[size] = 0;
}
if(fd > 0)
close(fd);
return 0;
}
/**
* @param s e.g., "index.html"
* @return e.g., "text/html"
*/
string lookupMimeType(string s) {
string result("application/octet-stream");
string::size_type last_pos = s.find_last_of('.');
string::size_type first_pos = s.find_first_of('.');
string prefix, ext, ext2;
// No dots in name, just return
if(last_pos == string::npos)
return result;
// extract the last extension
if(last_pos != string::npos)
ext = s.substr(1+last_pos, string::npos);
if (last_pos != string::npos) {
// one dot was found, now look for another
if (first_pos != string::npos && first_pos < last_pos) {
prefix = s.substr(0, last_pos);
// Now get the second to last file extension
string::size_type next_pos = prefix.find_last_of('.');
if (next_pos != string::npos) {
ext2 = prefix.substr(1+next_pos, string::npos);
}
}
}
// if we get here, then we have an extension (ext)
mimes_t::const_iterator iter = mimeTypes.find(ext);
// if the last extension matches a mimeType, then return
// that mime type
if (iter != mimeTypes.end()) {
result = (*iter).second;
return result;
}
// return with the default result if there isn't a second extension
if(first_pos == last_pos)
return result;
// Didn't find a mime-type for the first extension
// Look for second extension in mimeTypes, return if found
iter = mimeTypes.find(ext2);
if (iter != mimeTypes.end()) {
result = (*iter).second;
return result;
}
// neither the last extension nor the second-to-last extension
// matched a mimeType, return the default mime type
return result;
}
// common function for creation of a plain object
Summary of Changes(1.62 -> 1.63) 1) Lifetime for the stats cache Added the new option "stat_cache_expire". This option which is specified by seconds means the lifetime for each stats cache entry. If this option is not specified, the stats cache is kept in s3fs process until the stats cache grown to maximum size. (default) If this option is specified, the stats cache entry is out from the memory when the entry expires time. 2) Enable file permission s3fs before 1.62 did not consider the file access permission. s3fs after this version can consider it. For access permission, the s3fs_getattr() function was divided into sub function which can check the file access permission. It is like access() function. And the function calling the s3fs_getattr() calls this new sub function instead of s3fs_getattr(). Last the s3fs_opendir() function which is called by FUSE was added for checking directory access permission when listing the files in directory. 3) UID/GUID When a file or a directory was created, the s3fs could not set the UID/GID as the user who executed a command. (Almost the UID/GID are root, because the s3fs run by root.) After this version, the s3fs set correct UID/GID as the user who executes the commond. 4) About the mtime If the object does not have "x-amz-meta-mtime" meta, the s3fs uses the "Last-Modified" header instead of it. But the s3fs had a bug in this code, and this version fixed this bug. When user modified the file, the s3fs did not update the mtime of the file. This version fixed this bug. In the get_local_fd() function, the local file's mtime was changed only when s3fs run with "use_cache" option. This version always updates the mtime whether the local cache file is used or not. And s3fs_flush ( ) function set the mtime of local cache file from S3 object mtime, but it was wrong . This version is that the s3fs_flush ( ) changes the mtime of S3 object from the local cache file or the tmpfile . The s3fs cuts some requests, because the s3fs can always check mtime whether the s3fs uses or does not use the local cache file. 5) A case of no "x-amz-meta-mode" If the object did not have "x-amz-meta-mtime" mete, the s3fs recognized the file as not regular file. After this version, the s3fs recognizes the file as regular file. 6) "." and ".." directory The s3fs_readdir() did not return "X" and "XX" directory name. After this version, the s3fs is changed that it returns "X" and "XX". Example, the result of "ls" lists "X" and "XX" directory. 7) Fixed a bug The insert_object() had a bug, and it is fixed. git-svn-id: http://s3fs.googlecode.com/svn/trunk@390 df820570-a93a-0410-bd06-b72b767a4274
2013-02-24 08:58:54 +00:00
static int create_file_object(const char *path, mode_t mode, uid_t uid, gid_t gid) {
int result;
char *s3_realpath;
CURL *curl = NULL;
if(foreground)
printf(" create_file_object[path=%s][mode=%d]\n", path, mode);
s3_realpath = get_realpath(path);
string resource = urlEncode(service_path + bucket + s3_realpath);
string url = host + resource;
string date = get_date();
string my_url = prepare_url(url.c_str());
auto_curl_slist headers;
headers.append("Date: " + date);
string contentType(lookupMimeType(path));
headers.append("Content-Type: " + contentType);
// x-amz headers: (a) alphabetical order and (b) no spaces after colon
headers.append("x-amz-acl:" + default_acl);
Summary of Changes(1.62 -> 1.63) 1) Lifetime for the stats cache Added the new option "stat_cache_expire". This option which is specified by seconds means the lifetime for each stats cache entry. If this option is not specified, the stats cache is kept in s3fs process until the stats cache grown to maximum size. (default) If this option is specified, the stats cache entry is out from the memory when the entry expires time. 2) Enable file permission s3fs before 1.62 did not consider the file access permission. s3fs after this version can consider it. For access permission, the s3fs_getattr() function was divided into sub function which can check the file access permission. It is like access() function. And the function calling the s3fs_getattr() calls this new sub function instead of s3fs_getattr(). Last the s3fs_opendir() function which is called by FUSE was added for checking directory access permission when listing the files in directory. 3) UID/GUID When a file or a directory was created, the s3fs could not set the UID/GID as the user who executed a command. (Almost the UID/GID are root, because the s3fs run by root.) After this version, the s3fs set correct UID/GID as the user who executes the commond. 4) About the mtime If the object does not have "x-amz-meta-mtime" meta, the s3fs uses the "Last-Modified" header instead of it. But the s3fs had a bug in this code, and this version fixed this bug. When user modified the file, the s3fs did not update the mtime of the file. This version fixed this bug. In the get_local_fd() function, the local file's mtime was changed only when s3fs run with "use_cache" option. This version always updates the mtime whether the local cache file is used or not. And s3fs_flush ( ) function set the mtime of local cache file from S3 object mtime, but it was wrong . This version is that the s3fs_flush ( ) changes the mtime of S3 object from the local cache file or the tmpfile . The s3fs cuts some requests, because the s3fs can always check mtime whether the s3fs uses or does not use the local cache file. 5) A case of no "x-amz-meta-mode" If the object did not have "x-amz-meta-mtime" mete, the s3fs recognized the file as not regular file. After this version, the s3fs recognizes the file as regular file. 6) "." and ".." directory The s3fs_readdir() did not return "X" and "XX" directory name. After this version, the s3fs is changed that it returns "X" and "XX". Example, the result of "ls" lists "X" and "XX" directory. 7) Fixed a bug The insert_object() had a bug, and it is fixed. git-svn-id: http://s3fs.googlecode.com/svn/trunk@390 df820570-a93a-0410-bd06-b72b767a4274
2013-02-24 08:58:54 +00:00
headers.append("x-amz-meta-gid:" + str(gid));
headers.append("x-amz-meta-mode:" + str(mode));
headers.append("x-amz-meta-mtime:" + str(time(NULL)));
Summary of Changes(1.62 -> 1.63) 1) Lifetime for the stats cache Added the new option "stat_cache_expire". This option which is specified by seconds means the lifetime for each stats cache entry. If this option is not specified, the stats cache is kept in s3fs process until the stats cache grown to maximum size. (default) If this option is specified, the stats cache entry is out from the memory when the entry expires time. 2) Enable file permission s3fs before 1.62 did not consider the file access permission. s3fs after this version can consider it. For access permission, the s3fs_getattr() function was divided into sub function which can check the file access permission. It is like access() function. And the function calling the s3fs_getattr() calls this new sub function instead of s3fs_getattr(). Last the s3fs_opendir() function which is called by FUSE was added for checking directory access permission when listing the files in directory. 3) UID/GUID When a file or a directory was created, the s3fs could not set the UID/GID as the user who executed a command. (Almost the UID/GID are root, because the s3fs run by root.) After this version, the s3fs set correct UID/GID as the user who executes the commond. 4) About the mtime If the object does not have "x-amz-meta-mtime" meta, the s3fs uses the "Last-Modified" header instead of it. But the s3fs had a bug in this code, and this version fixed this bug. When user modified the file, the s3fs did not update the mtime of the file. This version fixed this bug. In the get_local_fd() function, the local file's mtime was changed only when s3fs run with "use_cache" option. This version always updates the mtime whether the local cache file is used or not. And s3fs_flush ( ) function set the mtime of local cache file from S3 object mtime, but it was wrong . This version is that the s3fs_flush ( ) changes the mtime of S3 object from the local cache file or the tmpfile . The s3fs cuts some requests, because the s3fs can always check mtime whether the s3fs uses or does not use the local cache file. 5) A case of no "x-amz-meta-mode" If the object did not have "x-amz-meta-mtime" mete, the s3fs recognized the file as not regular file. After this version, the s3fs recognizes the file as regular file. 6) "." and ".." directory The s3fs_readdir() did not return "X" and "XX" directory name. After this version, the s3fs is changed that it returns "X" and "XX". Example, the result of "ls" lists "X" and "XX" directory. 7) Fixed a bug The insert_object() had a bug, and it is fixed. git-svn-id: http://s3fs.googlecode.com/svn/trunk@390 df820570-a93a-0410-bd06-b72b767a4274
2013-02-24 08:58:54 +00:00
headers.append("x-amz-meta-uid:" + str(uid));
if(public_bucket.substr(0,1) != "1")
headers.append("Authorization: AWS " + AWSAccessKeyId + ":" +
calc_signature("PUT", contentType, date, headers.get(), resource));
curl = create_curl_handle();
curl_easy_setopt(curl, CURLOPT_UPLOAD, true); // HTTP PUT
curl_easy_setopt(curl, CURLOPT_INFILESIZE, 0); // Content-Length: 0
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers.get());
curl_easy_setopt(curl, CURLOPT_URL, my_url.c_str());
result = my_curl_easy_perform(curl);
destroy_curl_handle(curl);
free(s3_realpath);
if(result != 0)
return result;
return 0;
}
static int s3fs_mknod(const char *path, mode_t mode, dev_t rdev)
{
if(foreground)
printf("s3fs_mknod[path=%s][mode=%d]\n", path, mode);
// Could not make block or character special files on S3,
// always return a error.
return -EPERM;
}
static int s3fs_create(const char *path, mode_t mode, struct fuse_file_info *fi) {
int result;
headers_t meta;
Summary of Changes(1.62 -> 1.63) 1) Lifetime for the stats cache Added the new option "stat_cache_expire". This option which is specified by seconds means the lifetime for each stats cache entry. If this option is not specified, the stats cache is kept in s3fs process until the stats cache grown to maximum size. (default) If this option is specified, the stats cache entry is out from the memory when the entry expires time. 2) Enable file permission s3fs before 1.62 did not consider the file access permission. s3fs after this version can consider it. For access permission, the s3fs_getattr() function was divided into sub function which can check the file access permission. It is like access() function. And the function calling the s3fs_getattr() calls this new sub function instead of s3fs_getattr(). Last the s3fs_opendir() function which is called by FUSE was added for checking directory access permission when listing the files in directory. 3) UID/GUID When a file or a directory was created, the s3fs could not set the UID/GID as the user who executed a command. (Almost the UID/GID are root, because the s3fs run by root.) After this version, the s3fs set correct UID/GID as the user who executes the commond. 4) About the mtime If the object does not have "x-amz-meta-mtime" meta, the s3fs uses the "Last-Modified" header instead of it. But the s3fs had a bug in this code, and this version fixed this bug. When user modified the file, the s3fs did not update the mtime of the file. This version fixed this bug. In the get_local_fd() function, the local file's mtime was changed only when s3fs run with "use_cache" option. This version always updates the mtime whether the local cache file is used or not. And s3fs_flush ( ) function set the mtime of local cache file from S3 object mtime, but it was wrong . This version is that the s3fs_flush ( ) changes the mtime of S3 object from the local cache file or the tmpfile . The s3fs cuts some requests, because the s3fs can always check mtime whether the s3fs uses or does not use the local cache file. 5) A case of no "x-amz-meta-mode" If the object did not have "x-amz-meta-mtime" mete, the s3fs recognized the file as not regular file. After this version, the s3fs recognizes the file as regular file. 6) "." and ".." directory The s3fs_readdir() did not return "X" and "XX" directory name. After this version, the s3fs is changed that it returns "X" and "XX". Example, the result of "ls" lists "X" and "XX" directory. 7) Fixed a bug The insert_object() had a bug, and it is fixed. git-svn-id: http://s3fs.googlecode.com/svn/trunk@390 df820570-a93a-0410-bd06-b72b767a4274
2013-02-24 08:58:54 +00:00
struct fuse_context* pcxt;
if(foreground)
cout << "s3fs_create[path=" << path << "][mode=" << mode << "]" << "[flags=" << fi->flags << "]" << endl;
Summary of Changes(1.62 -> 1.63) 1) Lifetime for the stats cache Added the new option "stat_cache_expire". This option which is specified by seconds means the lifetime for each stats cache entry. If this option is not specified, the stats cache is kept in s3fs process until the stats cache grown to maximum size. (default) If this option is specified, the stats cache entry is out from the memory when the entry expires time. 2) Enable file permission s3fs before 1.62 did not consider the file access permission. s3fs after this version can consider it. For access permission, the s3fs_getattr() function was divided into sub function which can check the file access permission. It is like access() function. And the function calling the s3fs_getattr() calls this new sub function instead of s3fs_getattr(). Last the s3fs_opendir() function which is called by FUSE was added for checking directory access permission when listing the files in directory. 3) UID/GUID When a file or a directory was created, the s3fs could not set the UID/GID as the user who executed a command. (Almost the UID/GID are root, because the s3fs run by root.) After this version, the s3fs set correct UID/GID as the user who executes the commond. 4) About the mtime If the object does not have "x-amz-meta-mtime" meta, the s3fs uses the "Last-Modified" header instead of it. But the s3fs had a bug in this code, and this version fixed this bug. When user modified the file, the s3fs did not update the mtime of the file. This version fixed this bug. In the get_local_fd() function, the local file's mtime was changed only when s3fs run with "use_cache" option. This version always updates the mtime whether the local cache file is used or not. And s3fs_flush ( ) function set the mtime of local cache file from S3 object mtime, but it was wrong . This version is that the s3fs_flush ( ) changes the mtime of S3 object from the local cache file or the tmpfile . The s3fs cuts some requests, because the s3fs can always check mtime whether the s3fs uses or does not use the local cache file. 5) A case of no "x-amz-meta-mode" If the object did not have "x-amz-meta-mtime" mete, the s3fs recognized the file as not regular file. After this version, the s3fs recognizes the file as regular file. 6) "." and ".." directory The s3fs_readdir() did not return "X" and "XX" directory name. After this version, the s3fs is changed that it returns "X" and "XX". Example, the result of "ls" lists "X" and "XX" directory. 7) Fixed a bug The insert_object() had a bug, and it is fixed. git-svn-id: http://s3fs.googlecode.com/svn/trunk@390 df820570-a93a-0410-bd06-b72b767a4274
2013-02-24 08:58:54 +00:00
if(NULL == (pcxt = fuse_get_context())){
return -EIO;
}
// check parent directory attribute.
if(0 != (result = check_parent_object_access(path, W_OK | X_OK))){
return result;
}
result = check_object_access(path, W_OK, NULL);
if(0 != result && -ENOENT != result){
return result;
}
result = create_file_object(path, mode, pcxt->uid, pcxt->gid);
if(result != 0)
return result;
// object created, open it
if((fi->fh = get_local_fd(path)) <= 0)
return -EIO;
// remember flags and headers...
pthread_mutex_lock( &s3fs_descriptors_lock );
s3fs_descriptors[fi->fh] = fi->flags;
s3fs_pathtofd[string(path)] = fi->fh;
pthread_mutex_unlock( &s3fs_descriptors_lock );
return 0;
}
static int create_directory_object(const char *path, mode_t mode, time_t time, uid_t uid, gid_t gid)
{
CURL *curl = NULL;
int result;
char *s3_realpath;
string url;
string resource;
string date = get_date();
auto_curl_slist headers;
if(foreground)
cout << " create_directory_object[path=" << path << "][mode=" << mode <<
"][time=" << time << "][uid=" << uid << "][gid=" << gid << "]" << endl;
s3_realpath = get_realpath(path);
resource = urlEncode(service_path + bucket + s3_realpath);
free(s3_realpath);
url = host + resource;
curl = create_curl_handle();
curl_easy_setopt(curl, CURLOPT_UPLOAD, true); // HTTP PUT
curl_easy_setopt(curl, CURLOPT_INFILESIZE, 0); // Content-Length: 0
headers.append("Date: " + date);
headers.append("Content-Type: application/x-directory");
// x-amz headers: (a) alphabetical order and (b) no spaces after colon
headers.append("x-amz-acl:" + default_acl);
headers.append("x-amz-meta-gid:" + str(gid));
headers.append("x-amz-meta-mode:" + str(mode));
headers.append("x-amz-meta-mtime:" + str(time));
headers.append("x-amz-meta-uid:" + str(uid));
if (use_rrs.substr(0,1) == "1") {
headers.append("x-amz-storage-class:REDUCED_REDUNDANCY");
}
if (public_bucket.substr(0,1) != "1") {
headers.append("Authorization: AWS " + AWSAccessKeyId + ":" +
calc_signature("PUT", "application/x-directory", date, headers.get(), resource));
}
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers.get());
string my_url = prepare_url(url.c_str());
curl_easy_setopt(curl, CURLOPT_URL, my_url.c_str());
result = my_curl_easy_perform(curl);
destroy_curl_handle(curl);
if(result != 0)
return result;
return 0;
}
static int s3fs_mkdir(const char *path, mode_t mode)
{
Summary of Changes(1.62 -> 1.63) 1) Lifetime for the stats cache Added the new option "stat_cache_expire". This option which is specified by seconds means the lifetime for each stats cache entry. If this option is not specified, the stats cache is kept in s3fs process until the stats cache grown to maximum size. (default) If this option is specified, the stats cache entry is out from the memory when the entry expires time. 2) Enable file permission s3fs before 1.62 did not consider the file access permission. s3fs after this version can consider it. For access permission, the s3fs_getattr() function was divided into sub function which can check the file access permission. It is like access() function. And the function calling the s3fs_getattr() calls this new sub function instead of s3fs_getattr(). Last the s3fs_opendir() function which is called by FUSE was added for checking directory access permission when listing the files in directory. 3) UID/GUID When a file or a directory was created, the s3fs could not set the UID/GID as the user who executed a command. (Almost the UID/GID are root, because the s3fs run by root.) After this version, the s3fs set correct UID/GID as the user who executes the commond. 4) About the mtime If the object does not have "x-amz-meta-mtime" meta, the s3fs uses the "Last-Modified" header instead of it. But the s3fs had a bug in this code, and this version fixed this bug. When user modified the file, the s3fs did not update the mtime of the file. This version fixed this bug. In the get_local_fd() function, the local file's mtime was changed only when s3fs run with "use_cache" option. This version always updates the mtime whether the local cache file is used or not. And s3fs_flush ( ) function set the mtime of local cache file from S3 object mtime, but it was wrong . This version is that the s3fs_flush ( ) changes the mtime of S3 object from the local cache file or the tmpfile . The s3fs cuts some requests, because the s3fs can always check mtime whether the s3fs uses or does not use the local cache file. 5) A case of no "x-amz-meta-mode" If the object did not have "x-amz-meta-mtime" mete, the s3fs recognized the file as not regular file. After this version, the s3fs recognizes the file as regular file. 6) "." and ".." directory The s3fs_readdir() did not return "X" and "XX" directory name. After this version, the s3fs is changed that it returns "X" and "XX". Example, the result of "ls" lists "X" and "XX" directory. 7) Fixed a bug The insert_object() had a bug, and it is fixed. git-svn-id: http://s3fs.googlecode.com/svn/trunk@390 df820570-a93a-0410-bd06-b72b767a4274
2013-02-24 08:58:54 +00:00
int result;
struct fuse_context* pcxt;
if(foreground)
cout << "s3fs_mkdir[path=" << path << "][mode=" << mode << "]" << endl;
Summary of Changes(1.62 -> 1.63) 1) Lifetime for the stats cache Added the new option "stat_cache_expire". This option which is specified by seconds means the lifetime for each stats cache entry. If this option is not specified, the stats cache is kept in s3fs process until the stats cache grown to maximum size. (default) If this option is specified, the stats cache entry is out from the memory when the entry expires time. 2) Enable file permission s3fs before 1.62 did not consider the file access permission. s3fs after this version can consider it. For access permission, the s3fs_getattr() function was divided into sub function which can check the file access permission. It is like access() function. And the function calling the s3fs_getattr() calls this new sub function instead of s3fs_getattr(). Last the s3fs_opendir() function which is called by FUSE was added for checking directory access permission when listing the files in directory. 3) UID/GUID When a file or a directory was created, the s3fs could not set the UID/GID as the user who executed a command. (Almost the UID/GID are root, because the s3fs run by root.) After this version, the s3fs set correct UID/GID as the user who executes the commond. 4) About the mtime If the object does not have "x-amz-meta-mtime" meta, the s3fs uses the "Last-Modified" header instead of it. But the s3fs had a bug in this code, and this version fixed this bug. When user modified the file, the s3fs did not update the mtime of the file. This version fixed this bug. In the get_local_fd() function, the local file's mtime was changed only when s3fs run with "use_cache" option. This version always updates the mtime whether the local cache file is used or not. And s3fs_flush ( ) function set the mtime of local cache file from S3 object mtime, but it was wrong . This version is that the s3fs_flush ( ) changes the mtime of S3 object from the local cache file or the tmpfile . The s3fs cuts some requests, because the s3fs can always check mtime whether the s3fs uses or does not use the local cache file. 5) A case of no "x-amz-meta-mode" If the object did not have "x-amz-meta-mtime" mete, the s3fs recognized the file as not regular file. After this version, the s3fs recognizes the file as regular file. 6) "." and ".." directory The s3fs_readdir() did not return "X" and "XX" directory name. After this version, the s3fs is changed that it returns "X" and "XX". Example, the result of "ls" lists "X" and "XX" directory. 7) Fixed a bug The insert_object() had a bug, and it is fixed. git-svn-id: http://s3fs.googlecode.com/svn/trunk@390 df820570-a93a-0410-bd06-b72b767a4274
2013-02-24 08:58:54 +00:00
if(NULL == (pcxt = fuse_get_context())){
return -EIO;
}
// check parent directory attribute.
if(0 != (result = check_parent_object_access(path, W_OK | X_OK))){
return result;
}
if(-ENOENT != (result = check_object_access(path, F_OK, NULL))){
if(0 == result){
result = -EEXIST;
}
return result;
}
return create_directory_object(path, mode, time(NULL), pcxt->uid, pcxt->gid);
}
static int s3fs_unlink(const char *path) {
int result;
char *s3_realpath;
if(foreground)
printf("s3fs_unlink[path=%s]\n", path);
Summary of Changes(1.62 -> 1.63) 1) Lifetime for the stats cache Added the new option "stat_cache_expire". This option which is specified by seconds means the lifetime for each stats cache entry. If this option is not specified, the stats cache is kept in s3fs process until the stats cache grown to maximum size. (default) If this option is specified, the stats cache entry is out from the memory when the entry expires time. 2) Enable file permission s3fs before 1.62 did not consider the file access permission. s3fs after this version can consider it. For access permission, the s3fs_getattr() function was divided into sub function which can check the file access permission. It is like access() function. And the function calling the s3fs_getattr() calls this new sub function instead of s3fs_getattr(). Last the s3fs_opendir() function which is called by FUSE was added for checking directory access permission when listing the files in directory. 3) UID/GUID When a file or a directory was created, the s3fs could not set the UID/GID as the user who executed a command. (Almost the UID/GID are root, because the s3fs run by root.) After this version, the s3fs set correct UID/GID as the user who executes the commond. 4) About the mtime If the object does not have "x-amz-meta-mtime" meta, the s3fs uses the "Last-Modified" header instead of it. But the s3fs had a bug in this code, and this version fixed this bug. When user modified the file, the s3fs did not update the mtime of the file. This version fixed this bug. In the get_local_fd() function, the local file's mtime was changed only when s3fs run with "use_cache" option. This version always updates the mtime whether the local cache file is used or not. And s3fs_flush ( ) function set the mtime of local cache file from S3 object mtime, but it was wrong . This version is that the s3fs_flush ( ) changes the mtime of S3 object from the local cache file or the tmpfile . The s3fs cuts some requests, because the s3fs can always check mtime whether the s3fs uses or does not use the local cache file. 5) A case of no "x-amz-meta-mode" If the object did not have "x-amz-meta-mtime" mete, the s3fs recognized the file as not regular file. After this version, the s3fs recognizes the file as regular file. 6) "." and ".." directory The s3fs_readdir() did not return "X" and "XX" directory name. After this version, the s3fs is changed that it returns "X" and "XX". Example, the result of "ls" lists "X" and "XX" directory. 7) Fixed a bug The insert_object() had a bug, and it is fixed. git-svn-id: http://s3fs.googlecode.com/svn/trunk@390 df820570-a93a-0410-bd06-b72b767a4274
2013-02-24 08:58:54 +00:00
if(0 != (result = check_parent_object_access(path, W_OK | X_OK))){
return result;
}
s3_realpath = get_realpath(path);
result = curl_delete(s3_realpath);
free(s3_realpath);
delete_stat_cache_entry(path);
return result;
}
static int directory_empty(const char *path) {
int result;
char *s3_realpath;
string url;
string my_url;
string date;
string resource = urlEncode(service_path + bucket);
string query = "delimiter=/&prefix=";
CURL *curl = NULL;
struct BodyStruct body;
auto_curl_slist headers;
s3_realpath = get_realpath(path);
body.text = (char *)malloc(1);
body.size = 0;
if(strcmp(path, "/") != 0){
query += urlEncode(string(s3_realpath).substr(1) + "/");
}else{
query += urlEncode(string(s3_realpath).substr(1));
}
free(s3_realpath);
query += "&max-keys=1";
url = host + resource + "?"+ query;
curl = create_curl_handle();
my_url = prepare_url(url.c_str());
curl_easy_setopt(curl, CURLOPT_URL, my_url.c_str());
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&body);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
date = get_date();
headers.append("Date: " + date);
headers.append("ContentType: ");
if(public_bucket.substr(0,1) != "1") {
headers.append("Authorization: AWS " + AWSAccessKeyId + ":" +
calc_signature("GET", "", date, headers.get(), resource + "/"));
}
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers.get());
result = my_curl_easy_perform(curl, &body);
destroy_curl_handle(curl);
if(result != 0) {
if(body.text)
free(body.text);
return result;
}
// is the directory empty?
if(strstr(body.text, "<CommonPrefixes>") != NULL ||
strstr(body.text, "<ETag>") != NULL ) {
if(body.text)
free(body.text);
return -ENOTEMPTY;
}
if(body.text)
free(body.text);
return 0;
}
static int s3fs_rmdir(const char *path) {
int result;
char *s3_realpath;
if(foreground)
printf("s3fs_rmdir [path=%s]\n", path);
Summary of Changes(1.62 -> 1.63) 1) Lifetime for the stats cache Added the new option "stat_cache_expire". This option which is specified by seconds means the lifetime for each stats cache entry. If this option is not specified, the stats cache is kept in s3fs process until the stats cache grown to maximum size. (default) If this option is specified, the stats cache entry is out from the memory when the entry expires time. 2) Enable file permission s3fs before 1.62 did not consider the file access permission. s3fs after this version can consider it. For access permission, the s3fs_getattr() function was divided into sub function which can check the file access permission. It is like access() function. And the function calling the s3fs_getattr() calls this new sub function instead of s3fs_getattr(). Last the s3fs_opendir() function which is called by FUSE was added for checking directory access permission when listing the files in directory. 3) UID/GUID When a file or a directory was created, the s3fs could not set the UID/GID as the user who executed a command. (Almost the UID/GID are root, because the s3fs run by root.) After this version, the s3fs set correct UID/GID as the user who executes the commond. 4) About the mtime If the object does not have "x-amz-meta-mtime" meta, the s3fs uses the "Last-Modified" header instead of it. But the s3fs had a bug in this code, and this version fixed this bug. When user modified the file, the s3fs did not update the mtime of the file. This version fixed this bug. In the get_local_fd() function, the local file's mtime was changed only when s3fs run with "use_cache" option. This version always updates the mtime whether the local cache file is used or not. And s3fs_flush ( ) function set the mtime of local cache file from S3 object mtime, but it was wrong . This version is that the s3fs_flush ( ) changes the mtime of S3 object from the local cache file or the tmpfile . The s3fs cuts some requests, because the s3fs can always check mtime whether the s3fs uses or does not use the local cache file. 5) A case of no "x-amz-meta-mode" If the object did not have "x-amz-meta-mtime" mete, the s3fs recognized the file as not regular file. After this version, the s3fs recognizes the file as regular file. 6) "." and ".." directory The s3fs_readdir() did not return "X" and "XX" directory name. After this version, the s3fs is changed that it returns "X" and "XX". Example, the result of "ls" lists "X" and "XX" directory. 7) Fixed a bug The insert_object() had a bug, and it is fixed. git-svn-id: http://s3fs.googlecode.com/svn/trunk@390 df820570-a93a-0410-bd06-b72b767a4274
2013-02-24 08:58:54 +00:00
if(0 != (result = check_parent_object_access(path, W_OK | X_OK))){
return result;
}
s3_realpath = get_realpath(path);
// directory must be empty
if(directory_empty(path) != 0)
return -ENOTEMPTY;
result = curl_delete(s3_realpath);
delete_stat_cache_entry(path);
free(s3_realpath);
return result;
}
static int s3fs_symlink(const char *from, const char *to) {
int result;
int fd = -1;
if(foreground)
cout << "s3fs_symlink[from=" << from << "][to=" << to << "]" << endl;
Summary of Changes(1.62 -> 1.63) 1) Lifetime for the stats cache Added the new option "stat_cache_expire". This option which is specified by seconds means the lifetime for each stats cache entry. If this option is not specified, the stats cache is kept in s3fs process until the stats cache grown to maximum size. (default) If this option is specified, the stats cache entry is out from the memory when the entry expires time. 2) Enable file permission s3fs before 1.62 did not consider the file access permission. s3fs after this version can consider it. For access permission, the s3fs_getattr() function was divided into sub function which can check the file access permission. It is like access() function. And the function calling the s3fs_getattr() calls this new sub function instead of s3fs_getattr(). Last the s3fs_opendir() function which is called by FUSE was added for checking directory access permission when listing the files in directory. 3) UID/GUID When a file or a directory was created, the s3fs could not set the UID/GID as the user who executed a command. (Almost the UID/GID are root, because the s3fs run by root.) After this version, the s3fs set correct UID/GID as the user who executes the commond. 4) About the mtime If the object does not have "x-amz-meta-mtime" meta, the s3fs uses the "Last-Modified" header instead of it. But the s3fs had a bug in this code, and this version fixed this bug. When user modified the file, the s3fs did not update the mtime of the file. This version fixed this bug. In the get_local_fd() function, the local file's mtime was changed only when s3fs run with "use_cache" option. This version always updates the mtime whether the local cache file is used or not. And s3fs_flush ( ) function set the mtime of local cache file from S3 object mtime, but it was wrong . This version is that the s3fs_flush ( ) changes the mtime of S3 object from the local cache file or the tmpfile . The s3fs cuts some requests, because the s3fs can always check mtime whether the s3fs uses or does not use the local cache file. 5) A case of no "x-amz-meta-mode" If the object did not have "x-amz-meta-mtime" mete, the s3fs recognized the file as not regular file. After this version, the s3fs recognizes the file as regular file. 6) "." and ".." directory The s3fs_readdir() did not return "X" and "XX" directory name. After this version, the s3fs is changed that it returns "X" and "XX". Example, the result of "ls" lists "X" and "XX" directory. 7) Fixed a bug The insert_object() had a bug, and it is fixed. git-svn-id: http://s3fs.googlecode.com/svn/trunk@390 df820570-a93a-0410-bd06-b72b767a4274
2013-02-24 08:58:54 +00:00
if(0 != (result = check_parent_object_access(to, W_OK | X_OK))){
return result;
}
if(-ENOENT != (result = check_object_access(to, F_OK, NULL))){
if(0 == result){
result = -EEXIST;
}
return result;
}
headers_t headers;
headers["x-amz-meta-mode"] = str(S_IFLNK | S_IRWXU | S_IRWXG | S_IRWXO);
headers["x-amz-meta-mtime"] = str(time(NULL));
fd = fileno(tmpfile());
if(fd == -1) {
syslog(LOG_ERR, "line %d: error: fileno(tmpfile()): %d", __LINE__, -errno);
return -errno;
}
if(pwrite(fd, from, strlen(from), 0) == -1) {
syslog(LOG_ERR, "line %d: error: pwrite: %d", __LINE__, -errno);
if(fd > 0)
close(fd);
return -errno;
}
result = put_local_fd(to, headers, fd);
if(result != 0) {
if(fd > 0)
close(fd);
return result;
}
if(fd > 0)
close(fd);
return 0;
}
static int rename_object(const char *from, const char *to) {
int result;
char *s3_realpath;
headers_t meta;
if(foreground)
printf("rename_object [from=%s] [to=%s]\n", from , to);
if(debug)
syslog(LOG_DEBUG, "rename_object [from=%s] [to=%s]", from, to);
Summary of Changes(1.62 -> 1.63) 1) Lifetime for the stats cache Added the new option "stat_cache_expire". This option which is specified by seconds means the lifetime for each stats cache entry. If this option is not specified, the stats cache is kept in s3fs process until the stats cache grown to maximum size. (default) If this option is specified, the stats cache entry is out from the memory when the entry expires time. 2) Enable file permission s3fs before 1.62 did not consider the file access permission. s3fs after this version can consider it. For access permission, the s3fs_getattr() function was divided into sub function which can check the file access permission. It is like access() function. And the function calling the s3fs_getattr() calls this new sub function instead of s3fs_getattr(). Last the s3fs_opendir() function which is called by FUSE was added for checking directory access permission when listing the files in directory. 3) UID/GUID When a file or a directory was created, the s3fs could not set the UID/GID as the user who executed a command. (Almost the UID/GID are root, because the s3fs run by root.) After this version, the s3fs set correct UID/GID as the user who executes the commond. 4) About the mtime If the object does not have "x-amz-meta-mtime" meta, the s3fs uses the "Last-Modified" header instead of it. But the s3fs had a bug in this code, and this version fixed this bug. When user modified the file, the s3fs did not update the mtime of the file. This version fixed this bug. In the get_local_fd() function, the local file's mtime was changed only when s3fs run with "use_cache" option. This version always updates the mtime whether the local cache file is used or not. And s3fs_flush ( ) function set the mtime of local cache file from S3 object mtime, but it was wrong . This version is that the s3fs_flush ( ) changes the mtime of S3 object from the local cache file or the tmpfile . The s3fs cuts some requests, because the s3fs can always check mtime whether the s3fs uses or does not use the local cache file. 5) A case of no "x-amz-meta-mode" If the object did not have "x-amz-meta-mtime" mete, the s3fs recognized the file as not regular file. After this version, the s3fs recognizes the file as regular file. 6) "." and ".." directory The s3fs_readdir() did not return "X" and "XX" directory name. After this version, the s3fs is changed that it returns "X" and "XX". Example, the result of "ls" lists "X" and "XX" directory. 7) Fixed a bug The insert_object() had a bug, and it is fixed. git-svn-id: http://s3fs.googlecode.com/svn/trunk@390 df820570-a93a-0410-bd06-b72b767a4274
2013-02-24 08:58:54 +00:00
if(0 != (result = check_parent_object_access(to, W_OK | X_OK))){
// not permmit writing "to" object parent dir.
return result;
}
if(0 != (result = check_parent_object_access(from, W_OK | X_OK))){
// not permmit removing "from" object parent dir.
return result;
}
s3_realpath = get_realpath(from);
result = curl_get_headers(s3_realpath, meta);
if(result != 0) {
free(s3_realpath);
return result;
}
meta["x-amz-copy-source"] = urlEncode("/" + bucket + s3_realpath);
meta["Content-Type"] = lookupMimeType(to);
meta["x-amz-metadata-directive"] = "REPLACE";
free(s3_realpath);
result = put_headers(to, meta);
if(result != 0)
return result;
result = s3fs_unlink(from);
return result;
}
static int rename_object_nocopy(const char *from, const char *to) {
int result;
char* s3_realpath;
headers_t meta;
int fd;
int isclose = 1;
if(foreground)
printf("rename_object_nocopy [from=%s] [to=%s]\n", from , to);
if(debug)
syslog(LOG_DEBUG, "rename_object_nocopy [from=%s] [to=%s]", from, to);
Summary of Changes(1.62 -> 1.63) 1) Lifetime for the stats cache Added the new option "stat_cache_expire". This option which is specified by seconds means the lifetime for each stats cache entry. If this option is not specified, the stats cache is kept in s3fs process until the stats cache grown to maximum size. (default) If this option is specified, the stats cache entry is out from the memory when the entry expires time. 2) Enable file permission s3fs before 1.62 did not consider the file access permission. s3fs after this version can consider it. For access permission, the s3fs_getattr() function was divided into sub function which can check the file access permission. It is like access() function. And the function calling the s3fs_getattr() calls this new sub function instead of s3fs_getattr(). Last the s3fs_opendir() function which is called by FUSE was added for checking directory access permission when listing the files in directory. 3) UID/GUID When a file or a directory was created, the s3fs could not set the UID/GID as the user who executed a command. (Almost the UID/GID are root, because the s3fs run by root.) After this version, the s3fs set correct UID/GID as the user who executes the commond. 4) About the mtime If the object does not have "x-amz-meta-mtime" meta, the s3fs uses the "Last-Modified" header instead of it. But the s3fs had a bug in this code, and this version fixed this bug. When user modified the file, the s3fs did not update the mtime of the file. This version fixed this bug. In the get_local_fd() function, the local file's mtime was changed only when s3fs run with "use_cache" option. This version always updates the mtime whether the local cache file is used or not. And s3fs_flush ( ) function set the mtime of local cache file from S3 object mtime, but it was wrong . This version is that the s3fs_flush ( ) changes the mtime of S3 object from the local cache file or the tmpfile . The s3fs cuts some requests, because the s3fs can always check mtime whether the s3fs uses or does not use the local cache file. 5) A case of no "x-amz-meta-mode" If the object did not have "x-amz-meta-mtime" mete, the s3fs recognized the file as not regular file. After this version, the s3fs recognizes the file as regular file. 6) "." and ".." directory The s3fs_readdir() did not return "X" and "XX" directory name. After this version, the s3fs is changed that it returns "X" and "XX". Example, the result of "ls" lists "X" and "XX" directory. 7) Fixed a bug The insert_object() had a bug, and it is fixed. git-svn-id: http://s3fs.googlecode.com/svn/trunk@390 df820570-a93a-0410-bd06-b72b767a4274
2013-02-24 08:58:54 +00:00
if(0 != (result = check_parent_object_access(to, W_OK | X_OK))){
// not permmit writing "to" object parent dir.
return result;
}
if(0 != (result = check_parent_object_access(from, W_OK | X_OK))){
// not permmit removing "from" object parent dir.
return result;
}
// Downloading
if(0 > (fd = get_opened_fd(from))){
if(0 > (fd = get_local_fd(from))){
if(foreground) {
printf(" rename_object_nocopy line %d: get_local_fd result: %d", __LINE__, fd);
}
syslog(LOG_ERR, "rename_object_nocopy line %d: get_local_fd result: %d", __LINE__, fd);
return -EIO;
}
}else{
isclose = 0;
}
// Get attributes
s3_realpath = get_realpath(from);
result = curl_get_headers(s3_realpath, meta);
free(s3_realpath);
if(result != 0){
if(isclose){
close(fd);
}
return result;
}
// Set header
meta["Content-Type"] = lookupMimeType(to);
// Re-uploading
result = put_local_fd(to, meta, fd);
if(isclose){
close(fd);
}
if(0 != result){
if(foreground) {
printf(" rename_object_nocopy line %d: put_local_fd result: %d\n", __LINE__, result);
}
return result;
}
// Remove file
result = s3fs_unlink(from);
// Stats
delete_stat_cache_entry(to);
return result;
}
static int rename_large_object(const char *from, const char *to) {
int result;
char *s3_realpath;
struct stat buf;
headers_t meta;
string upload_id;
vector <file_part> parts;
if(foreground)
printf("rename_large_object [from=%s] [to=%s]\n", from , to);
if(debug)
syslog(LOG_DEBUG, "rename_large_object [from=%s] [to=%s]", from, to);
Summary of Changes(1.62 -> 1.63) 1) Lifetime for the stats cache Added the new option "stat_cache_expire". This option which is specified by seconds means the lifetime for each stats cache entry. If this option is not specified, the stats cache is kept in s3fs process until the stats cache grown to maximum size. (default) If this option is specified, the stats cache entry is out from the memory when the entry expires time. 2) Enable file permission s3fs before 1.62 did not consider the file access permission. s3fs after this version can consider it. For access permission, the s3fs_getattr() function was divided into sub function which can check the file access permission. It is like access() function. And the function calling the s3fs_getattr() calls this new sub function instead of s3fs_getattr(). Last the s3fs_opendir() function which is called by FUSE was added for checking directory access permission when listing the files in directory. 3) UID/GUID When a file or a directory was created, the s3fs could not set the UID/GID as the user who executed a command. (Almost the UID/GID are root, because the s3fs run by root.) After this version, the s3fs set correct UID/GID as the user who executes the commond. 4) About the mtime If the object does not have "x-amz-meta-mtime" meta, the s3fs uses the "Last-Modified" header instead of it. But the s3fs had a bug in this code, and this version fixed this bug. When user modified the file, the s3fs did not update the mtime of the file. This version fixed this bug. In the get_local_fd() function, the local file's mtime was changed only when s3fs run with "use_cache" option. This version always updates the mtime whether the local cache file is used or not. And s3fs_flush ( ) function set the mtime of local cache file from S3 object mtime, but it was wrong . This version is that the s3fs_flush ( ) changes the mtime of S3 object from the local cache file or the tmpfile . The s3fs cuts some requests, because the s3fs can always check mtime whether the s3fs uses or does not use the local cache file. 5) A case of no "x-amz-meta-mode" If the object did not have "x-amz-meta-mtime" mete, the s3fs recognized the file as not regular file. After this version, the s3fs recognizes the file as regular file. 6) "." and ".." directory The s3fs_readdir() did not return "X" and "XX" directory name. After this version, the s3fs is changed that it returns "X" and "XX". Example, the result of "ls" lists "X" and "XX" directory. 7) Fixed a bug The insert_object() had a bug, and it is fixed. git-svn-id: http://s3fs.googlecode.com/svn/trunk@390 df820570-a93a-0410-bd06-b72b767a4274
2013-02-24 08:58:54 +00:00
if(0 != (result = check_parent_object_access(to, W_OK | X_OK))){
// not permmit writing "to" object parent dir.
return result;
}
if(0 != (result = check_parent_object_access(from, W_OK | X_OK))){
// not permmit removing "from" object parent dir.
return result;
}
get_object_attribute(from, &buf);
Summary of Changes(1.62 -> 1.63) 1) Lifetime for the stats cache Added the new option "stat_cache_expire". This option which is specified by seconds means the lifetime for each stats cache entry. If this option is not specified, the stats cache is kept in s3fs process until the stats cache grown to maximum size. (default) If this option is specified, the stats cache entry is out from the memory when the entry expires time. 2) Enable file permission s3fs before 1.62 did not consider the file access permission. s3fs after this version can consider it. For access permission, the s3fs_getattr() function was divided into sub function which can check the file access permission. It is like access() function. And the function calling the s3fs_getattr() calls this new sub function instead of s3fs_getattr(). Last the s3fs_opendir() function which is called by FUSE was added for checking directory access permission when listing the files in directory. 3) UID/GUID When a file or a directory was created, the s3fs could not set the UID/GID as the user who executed a command. (Almost the UID/GID are root, because the s3fs run by root.) After this version, the s3fs set correct UID/GID as the user who executes the commond. 4) About the mtime If the object does not have "x-amz-meta-mtime" meta, the s3fs uses the "Last-Modified" header instead of it. But the s3fs had a bug in this code, and this version fixed this bug. When user modified the file, the s3fs did not update the mtime of the file. This version fixed this bug. In the get_local_fd() function, the local file's mtime was changed only when s3fs run with "use_cache" option. This version always updates the mtime whether the local cache file is used or not. And s3fs_flush ( ) function set the mtime of local cache file from S3 object mtime, but it was wrong . This version is that the s3fs_flush ( ) changes the mtime of S3 object from the local cache file or the tmpfile . The s3fs cuts some requests, because the s3fs can always check mtime whether the s3fs uses or does not use the local cache file. 5) A case of no "x-amz-meta-mode" If the object did not have "x-amz-meta-mtime" mete, the s3fs recognized the file as not regular file. After this version, the s3fs recognizes the file as regular file. 6) "." and ".." directory The s3fs_readdir() did not return "X" and "XX" directory name. After this version, the s3fs is changed that it returns "X" and "XX". Example, the result of "ls" lists "X" and "XX" directory. 7) Fixed a bug The insert_object() had a bug, and it is fixed. git-svn-id: http://s3fs.googlecode.com/svn/trunk@390 df820570-a93a-0410-bd06-b72b767a4274
2013-02-24 08:58:54 +00:00
s3_realpath = get_realpath(from);
if((curl_get_headers(s3_realpath, meta) != 0)) {
free(s3_realpath);
return -1;
}
meta["Content-Type"] = lookupMimeType(to);
meta["x-amz-copy-source"] = urlEncode("/" + bucket + s3_realpath);
free(s3_realpath);
upload_id = initiate_multipart_upload(to, buf.st_size, meta);
if(upload_id.size() == 0)
return(-EIO);
off_t chunk = 0;
off_t bytes_written = 0;
off_t bytes_remaining = buf.st_size;
while(bytes_remaining > 0) {
file_part part;
if(bytes_remaining > MAX_COPY_SOURCE_SIZE)
chunk = MAX_COPY_SOURCE_SIZE;
else
chunk = bytes_remaining - 1;
stringstream ss;
ss << "bytes=" << bytes_written << "-" << (bytes_written + chunk);
meta["x-amz-copy-source-range"] = ss.str();
part.etag = copy_part(from, to, parts.size() + 1, upload_id, meta);
parts.push_back(part);
bytes_written += (chunk + 1);
bytes_remaining = buf.st_size - bytes_written;
}
result = complete_multipart_upload(to, upload_id, parts);
if(result != 0)
return -EIO;
return s3fs_unlink(from);
}
static int clone_directory_object(const char *from, const char *to)
{
int result;
mode_t mode;
time_t time;
uid_t uid;
gid_t gid;
headers_t meta;
char *s3_realpath;
if(foreground)
printf("clone_directory_object [from=%s] [to=%s]\n", from, to);
if(debug)
syslog(LOG_DEBUG, "clone_directory_object [from=%s] [to=%s]", from, to);
// get target's attributes
s3_realpath = get_realpath(from);
result = curl_get_headers(s3_realpath, meta);
free(s3_realpath);
if(result != 0) {
return result;
}
mode = get_mode(meta["x-amz-meta-mode"].c_str());
time = get_mtime(meta["x-amz-meta-mtime"].c_str());
uid = get_uid(meta["x-amz-meta-uid"].c_str());
gid = get_gid(meta["x-amz-meta-gid"].c_str());
result = create_directory_object(to, mode, time, uid, gid);
return result;
}
static int rename_directory(const char *from, const char *to) {
int result;
// mode_t mode;
headers_t meta;
int num_keys = 0;
int max_keys = 50;
string path;
string new_path;
string to_path;
string from_path;
MVNODE *head = NULL;
MVNODE *tail = NULL;
if(foreground)
cout << "rename_directory[from=" << from << "][to=" << to << "]" << endl;
if(debug)
syslog(LOG_DEBUG, "rename_directory [from=%s] [to=%s]", from, to);
CURL *curl;
struct BodyStruct body;
string NextMarker;
string IsTruncated("true");
string object_type;
string Key;
bool is_dir;
body.text = (char *)malloc(1);
body.size = 0;
// create the head/tail of the linked list
from_path.assign(from);
to_path.assign(to);
is_dir = 1;
// printf("calling create_mvnode\n");
// head = create_mvnode((char *)from, (char *)to, is_dir);
head = create_mvnode((char *)from_path.c_str(), (char *)to_path.c_str(), is_dir);
tail = head;
// printf("back from create_mvnode\n");
while (IsTruncated == "true") {
string query;
string resource = urlEncode(service_path + bucket);
if(mount_prefix.size() > 0)
query = "prefix=" + mount_prefix .substr(1, mount_prefix.size() - 1) + "/";
else
query = "prefix=";
if (strcmp(from, "/") != 0)
query += urlEncode(string(from).substr(1) + "/");
if (NextMarker.size() > 0)
query += "&marker=" + urlEncode(NextMarker);
query += "&max-keys=";
query.append(IntToStr(max_keys));
string url = host + resource + "?" + query;
{
curl = create_curl_handle();
string my_url = prepare_url(url.c_str());
if(body.text) {
free(body.text);
body.size = 0;
body.text = (char *)malloc(1);
}
curl_easy_setopt(curl, CURLOPT_URL, my_url.c_str());
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&body);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
auto_curl_slist headers;
string date = get_date();
headers.append("Date: " + date);
headers.append("ContentType: ");
if (public_bucket.substr(0,1) != "1") {
headers.append("Authorization: AWS " + AWSAccessKeyId + ":" +
calc_signature("GET", "", date, headers.get(), resource + "/"));
}
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers.get());
result = my_curl_easy_perform(curl, &body);
destroy_curl_handle(curl);
if(result != 0) {
if(body.text)
free(body.text);
free_mvnodes(head);
return result;
}
}
xmlDocPtr doc = xmlReadMemory(body.text, body.size, "", NULL, 0);
if (doc != NULL && doc->children != NULL) {
for (xmlNodePtr cur_node = doc->children->children;
cur_node != NULL;
cur_node = cur_node->next) {
string cur_node_name(reinterpret_cast<const char *>(cur_node->name));
if(cur_node_name == "IsTruncated")
IsTruncated = reinterpret_cast<const char *>(cur_node->children->content);
if (cur_node_name == "Contents") {
if (cur_node->children != NULL) {
string LastModified;
string Size;
for (xmlNodePtr sub_node = cur_node->children;
sub_node != NULL;
sub_node = sub_node->next) {
if (sub_node->type == XML_ELEMENT_NODE) {
string elementName = reinterpret_cast<const char*>(sub_node->name);
if (sub_node->children != NULL) {
if (sub_node->children->type == XML_TEXT_NODE) {
if (elementName == "Key") {
Key = reinterpret_cast<const char *>(sub_node->children->content);
}
if (elementName == "LastModified") {
LastModified = reinterpret_cast<const char *>(sub_node->children->content);
}
if (elementName == "Size") {
Size = reinterpret_cast<const char *>(sub_node->children->content);
}
}
}
}
}
if (Key.size() > 0) {
num_keys++;
path = "/" + Key;
new_path = path;
if(mount_prefix.size() > 0)
new_path.replace(0, mount_prefix.substr(0, mount_prefix.size()).size() + from_path.size(), to_path);
else
new_path.replace(0, from_path.size(), to_path);
if(mount_prefix.size() > 0)
result = curl_get_headers(path.replace(0, mount_prefix.size(), "").c_str(), meta);
else
result = curl_get_headers(path.c_str(), meta);
if(result != 0) {
xmlFreeDoc(doc);
free_mvnodes(head);
if(body.text)
free(body.text);
body.text = NULL;
return result;
}
// process the Key appropriately
// if it is a directory move the directory object
object_type = meta["Content-Type"];
if(object_type.compare("application/x-directory") == 0)
is_dir = 1;
else
is_dir = 0;
// push this one onto the stack
tail = add_mvnode(head, (char *)path.c_str(), (char *)new_path.c_str(), is_dir);
}
} // if (cur_node->children != NULL) {
} // if (cur_node_name == "Contents") {
} // for (xmlNodePtr cur_node = doc->children->children;
} // if (doc != NULL && doc->children != NULL) {
xmlFreeDoc(doc);
if(IsTruncated == "true")
NextMarker = Key;
} // while (IsTruncated == "true") {
if(body.text)
free(body.text);
body.text = NULL;
// iterate over the list - clone directories first - top down
if(head == NULL)
return 0;
MVNODE *my_head;
MVNODE *my_tail;
MVNODE *next;
MVNODE *prev;
my_head = head;
my_tail = tail;
next = NULL;
prev = NULL;
do {
if(my_head->is_dir) {
result = clone_directory_object( my_head->old_path, my_head->new_path);
if(result != 0) {
free_mvnodes(head);
syslog(LOG_ERR, "clone_directory_object returned an error");
return -EIO;
}
}
next = my_head->next;
my_head = next;
} while(my_head != NULL);
// iterate over the list - copy the files with rename_object
// does a safe copy - copies first and then deletes old
my_head = head;
next = NULL;
do {
if(my_head->is_dir != 1) {
if(!nocopyapi){
result = rename_object( my_head->old_path, my_head->new_path);
}else{
result = rename_object_nocopy( my_head->old_path, my_head->new_path);
}
if(result != 0) {
free_mvnodes(head);
syslog(LOG_ERR, "rename_dir: rename_object returned an error");
return -EIO;
}
}
next = my_head->next;
my_head = next;
} while(my_head != NULL);
// Iterate over old the directories, bottoms up and remove
do {
if(my_tail->is_dir) {
result = s3fs_unlink( my_tail->old_path);
if(result != 0) {
free_mvnodes(head);
syslog(LOG_ERR, "rename_dir: s3fs_unlink returned an error");
return -EIO;
}
}
prev = my_tail->prev;
my_tail = prev;
} while(my_tail != NULL);
free_mvnodes(head);
return 0;
}
static int s3fs_rename(const char *from, const char *to) {
struct stat buf;
int result;
if(foreground)
printf("s3fs_rename [from=%s] [to=%s]\n", from, to);
if(debug)
syslog(LOG_DEBUG, "s3fs_rename [from=%s] [to=%s]", from, to);
Summary of Changes(1.62 -> 1.63) 1) Lifetime for the stats cache Added the new option "stat_cache_expire". This option which is specified by seconds means the lifetime for each stats cache entry. If this option is not specified, the stats cache is kept in s3fs process until the stats cache grown to maximum size. (default) If this option is specified, the stats cache entry is out from the memory when the entry expires time. 2) Enable file permission s3fs before 1.62 did not consider the file access permission. s3fs after this version can consider it. For access permission, the s3fs_getattr() function was divided into sub function which can check the file access permission. It is like access() function. And the function calling the s3fs_getattr() calls this new sub function instead of s3fs_getattr(). Last the s3fs_opendir() function which is called by FUSE was added for checking directory access permission when listing the files in directory. 3) UID/GUID When a file or a directory was created, the s3fs could not set the UID/GID as the user who executed a command. (Almost the UID/GID are root, because the s3fs run by root.) After this version, the s3fs set correct UID/GID as the user who executes the commond. 4) About the mtime If the object does not have "x-amz-meta-mtime" meta, the s3fs uses the "Last-Modified" header instead of it. But the s3fs had a bug in this code, and this version fixed this bug. When user modified the file, the s3fs did not update the mtime of the file. This version fixed this bug. In the get_local_fd() function, the local file's mtime was changed only when s3fs run with "use_cache" option. This version always updates the mtime whether the local cache file is used or not. And s3fs_flush ( ) function set the mtime of local cache file from S3 object mtime, but it was wrong . This version is that the s3fs_flush ( ) changes the mtime of S3 object from the local cache file or the tmpfile . The s3fs cuts some requests, because the s3fs can always check mtime whether the s3fs uses or does not use the local cache file. 5) A case of no "x-amz-meta-mode" If the object did not have "x-amz-meta-mtime" mete, the s3fs recognized the file as not regular file. After this version, the s3fs recognizes the file as regular file. 6) "." and ".." directory The s3fs_readdir() did not return "X" and "XX" directory name. After this version, the s3fs is changed that it returns "X" and "XX". Example, the result of "ls" lists "X" and "XX" directory. 7) Fixed a bug The insert_object() had a bug, and it is fixed. git-svn-id: http://s3fs.googlecode.com/svn/trunk@390 df820570-a93a-0410-bd06-b72b767a4274
2013-02-24 08:58:54 +00:00
if(0 != (result = check_parent_object_access(to, W_OK | X_OK))){
// not permmit writing "to" object parent dir.
return result;
}
if(0 != (result = check_parent_object_access(from, W_OK | X_OK))){
// not permmit removing "from" object parent dir.
return result;
}
get_object_attribute(from, &buf);
// files larger than 5GB must be modified via the multipart interface
if(S_ISDIR(buf.st_mode)){
result = rename_directory(from, to);
}else if(!nomultipart && buf.st_size >= FIVE_GB){
result = rename_large_object(from, to);
}else{
if(!nocopyapi){
result = rename_object(from, to);
}else{
result = rename_object_nocopy(from, to);
}
}
return result;
}
static int s3fs_link(const char *from, const char *to) {
if(foreground)
cout << "s3fs_link[from=" << from << "][to=" << to << "]" << endl;
return -EPERM;
}
static int s3fs_chmod(const char *path, mode_t mode) {
int result;
char *s3_realpath;
headers_t meta;
if(foreground)
printf("s3fs_chmod [path=%s] [mode=%d]\n", path, mode);
Summary of Changes(1.62 -> 1.63) 1) Lifetime for the stats cache Added the new option "stat_cache_expire". This option which is specified by seconds means the lifetime for each stats cache entry. If this option is not specified, the stats cache is kept in s3fs process until the stats cache grown to maximum size. (default) If this option is specified, the stats cache entry is out from the memory when the entry expires time. 2) Enable file permission s3fs before 1.62 did not consider the file access permission. s3fs after this version can consider it. For access permission, the s3fs_getattr() function was divided into sub function which can check the file access permission. It is like access() function. And the function calling the s3fs_getattr() calls this new sub function instead of s3fs_getattr(). Last the s3fs_opendir() function which is called by FUSE was added for checking directory access permission when listing the files in directory. 3) UID/GUID When a file or a directory was created, the s3fs could not set the UID/GID as the user who executed a command. (Almost the UID/GID are root, because the s3fs run by root.) After this version, the s3fs set correct UID/GID as the user who executes the commond. 4) About the mtime If the object does not have "x-amz-meta-mtime" meta, the s3fs uses the "Last-Modified" header instead of it. But the s3fs had a bug in this code, and this version fixed this bug. When user modified the file, the s3fs did not update the mtime of the file. This version fixed this bug. In the get_local_fd() function, the local file's mtime was changed only when s3fs run with "use_cache" option. This version always updates the mtime whether the local cache file is used or not. And s3fs_flush ( ) function set the mtime of local cache file from S3 object mtime, but it was wrong . This version is that the s3fs_flush ( ) changes the mtime of S3 object from the local cache file or the tmpfile . The s3fs cuts some requests, because the s3fs can always check mtime whether the s3fs uses or does not use the local cache file. 5) A case of no "x-amz-meta-mode" If the object did not have "x-amz-meta-mtime" mete, the s3fs recognized the file as not regular file. After this version, the s3fs recognizes the file as regular file. 6) "." and ".." directory The s3fs_readdir() did not return "X" and "XX" directory name. After this version, the s3fs is changed that it returns "X" and "XX". Example, the result of "ls" lists "X" and "XX" directory. 7) Fixed a bug The insert_object() had a bug, and it is fixed. git-svn-id: http://s3fs.googlecode.com/svn/trunk@390 df820570-a93a-0410-bd06-b72b767a4274
2013-02-24 08:58:54 +00:00
if(0 != (result = check_parent_object_access(path, W_OK | X_OK))){
return result;
}
if(0 != (result = check_object_access(path, W_OK, NULL))){
return result;
}
s3_realpath = get_realpath(path);
result = curl_get_headers(s3_realpath, meta);
if(result != 0) {
free(s3_realpath);
return result;
}
meta["x-amz-meta-mode"] = str(mode);
meta["x-amz-copy-source"] = urlEncode("/" + bucket + s3_realpath);
meta["x-amz-metadata-directive"] = "REPLACE";
free(s3_realpath);
if(put_headers(path, meta) != 0)
return -EIO;
delete_stat_cache_entry(path);
return 0;
}
static int s3fs_chmod_nocopy(const char *path, mode_t mode) {
int result;
char *s3_realpath;
headers_t meta;
int fd;
int isclose = 1;
if(foreground)
printf("s3fs_chmod_nocopy [path=%s] [mode=%d]\n", path, mode);
Summary of Changes(1.62 -> 1.63) 1) Lifetime for the stats cache Added the new option "stat_cache_expire". This option which is specified by seconds means the lifetime for each stats cache entry. If this option is not specified, the stats cache is kept in s3fs process until the stats cache grown to maximum size. (default) If this option is specified, the stats cache entry is out from the memory when the entry expires time. 2) Enable file permission s3fs before 1.62 did not consider the file access permission. s3fs after this version can consider it. For access permission, the s3fs_getattr() function was divided into sub function which can check the file access permission. It is like access() function. And the function calling the s3fs_getattr() calls this new sub function instead of s3fs_getattr(). Last the s3fs_opendir() function which is called by FUSE was added for checking directory access permission when listing the files in directory. 3) UID/GUID When a file or a directory was created, the s3fs could not set the UID/GID as the user who executed a command. (Almost the UID/GID are root, because the s3fs run by root.) After this version, the s3fs set correct UID/GID as the user who executes the commond. 4) About the mtime If the object does not have "x-amz-meta-mtime" meta, the s3fs uses the "Last-Modified" header instead of it. But the s3fs had a bug in this code, and this version fixed this bug. When user modified the file, the s3fs did not update the mtime of the file. This version fixed this bug. In the get_local_fd() function, the local file's mtime was changed only when s3fs run with "use_cache" option. This version always updates the mtime whether the local cache file is used or not. And s3fs_flush ( ) function set the mtime of local cache file from S3 object mtime, but it was wrong . This version is that the s3fs_flush ( ) changes the mtime of S3 object from the local cache file or the tmpfile . The s3fs cuts some requests, because the s3fs can always check mtime whether the s3fs uses or does not use the local cache file. 5) A case of no "x-amz-meta-mode" If the object did not have "x-amz-meta-mtime" mete, the s3fs recognized the file as not regular file. After this version, the s3fs recognizes the file as regular file. 6) "." and ".." directory The s3fs_readdir() did not return "X" and "XX" directory name. After this version, the s3fs is changed that it returns "X" and "XX". Example, the result of "ls" lists "X" and "XX" directory. 7) Fixed a bug The insert_object() had a bug, and it is fixed. git-svn-id: http://s3fs.googlecode.com/svn/trunk@390 df820570-a93a-0410-bd06-b72b767a4274
2013-02-24 08:58:54 +00:00
if(0 != (result = check_parent_object_access(path, W_OK | X_OK))){
return result;
}
if(0 != (result = check_object_access(path, W_OK, NULL))){
return result;
}
// Downloading
if(0 > (fd = get_opened_fd(path))){
if(0 > (fd = get_local_fd(path))){
if(foreground) {
printf(" s3fs_chmod_nocopy line %d: get_local_fd result: %d\n", __LINE__, fd);
}
syslog(LOG_ERR, "s3fs_chmod_nocopy line %d: get_local_fd result: %d", __LINE__, fd);
return -EIO;
}
}else{
isclose = 0;
}
// Get attributes
s3_realpath = get_realpath(path);
result = curl_get_headers(s3_realpath, meta);
free(s3_realpath);
if(result != 0){
if(isclose){
close(fd);
}
return result;
}
// Change file mode
meta["x-amz-meta-mode"] = str(mode);
// Change local file mode
if(-1 == fchmod(fd, mode)){
if(isclose){
close(fd);
}
if(foreground) {
printf(" s3fs_chmod_nocopy line %d: fchmod(fd=%d) error(%d)\n", __LINE__, fd, errno);
}
syslog(LOG_ERR, "s3fs_chmod_nocopy line %d: fchmod(fd=%d) error(%d)", __LINE__, fd, errno);
return -errno;
}
// Re-uploading
if(0 != (result = put_local_fd(path, meta, fd))){
if(foreground) {
printf(" s3fs_chmod_nocopy line %d: put_local_fd result: %d\n", __LINE__, result);
}
}
if(isclose){
close(fd);
}
delete_stat_cache_entry(path);
return result;
}
static int s3fs_chown(const char *path, uid_t uid, gid_t gid) {
int result;
char *s3_realpath;
if(foreground)
printf("s3fs_chown [path=%s] [uid=%d] [gid=%d]\n", path, uid, gid);
Summary of Changes(1.62 -> 1.63) 1) Lifetime for the stats cache Added the new option "stat_cache_expire". This option which is specified by seconds means the lifetime for each stats cache entry. If this option is not specified, the stats cache is kept in s3fs process until the stats cache grown to maximum size. (default) If this option is specified, the stats cache entry is out from the memory when the entry expires time. 2) Enable file permission s3fs before 1.62 did not consider the file access permission. s3fs after this version can consider it. For access permission, the s3fs_getattr() function was divided into sub function which can check the file access permission. It is like access() function. And the function calling the s3fs_getattr() calls this new sub function instead of s3fs_getattr(). Last the s3fs_opendir() function which is called by FUSE was added for checking directory access permission when listing the files in directory. 3) UID/GUID When a file or a directory was created, the s3fs could not set the UID/GID as the user who executed a command. (Almost the UID/GID are root, because the s3fs run by root.) After this version, the s3fs set correct UID/GID as the user who executes the commond. 4) About the mtime If the object does not have "x-amz-meta-mtime" meta, the s3fs uses the "Last-Modified" header instead of it. But the s3fs had a bug in this code, and this version fixed this bug. When user modified the file, the s3fs did not update the mtime of the file. This version fixed this bug. In the get_local_fd() function, the local file's mtime was changed only when s3fs run with "use_cache" option. This version always updates the mtime whether the local cache file is used or not. And s3fs_flush ( ) function set the mtime of local cache file from S3 object mtime, but it was wrong . This version is that the s3fs_flush ( ) changes the mtime of S3 object from the local cache file or the tmpfile . The s3fs cuts some requests, because the s3fs can always check mtime whether the s3fs uses or does not use the local cache file. 5) A case of no "x-amz-meta-mode" If the object did not have "x-amz-meta-mtime" mete, the s3fs recognized the file as not regular file. After this version, the s3fs recognizes the file as regular file. 6) "." and ".." directory The s3fs_readdir() did not return "X" and "XX" directory name. After this version, the s3fs is changed that it returns "X" and "XX". Example, the result of "ls" lists "X" and "XX" directory. 7) Fixed a bug The insert_object() had a bug, and it is fixed. git-svn-id: http://s3fs.googlecode.com/svn/trunk@390 df820570-a93a-0410-bd06-b72b767a4274
2013-02-24 08:58:54 +00:00
if(0 != (result = check_parent_object_access(path, W_OK | X_OK))){
return result;
}
if(0 != (result = check_object_access(path, W_OK, NULL))){
return result;
}
s3_realpath = get_realpath(path);
headers_t meta;
result = curl_get_headers(s3_realpath, meta);
if(result != 0) {
free(s3_realpath);
return result;
}
struct passwd *aaa = getpwuid(uid);
if(aaa != 0)
meta["x-amz-meta-uid"] = str((*aaa).pw_uid);
struct group *bbb = getgrgid(gid);
if(bbb != 0)
meta["x-amz-meta-gid"] = str((*bbb).gr_gid);
meta["x-amz-copy-source"] = urlEncode("/" + bucket + s3_realpath);
meta["x-amz-metadata-directive"] = "REPLACE";
free(s3_realpath);
if(put_headers(path, meta) != 0)
return -EIO;
delete_stat_cache_entry(path);
return 0;
}
static int s3fs_chown_nocopy(const char *path, uid_t uid, gid_t gid) {
int result;
char *s3_realpath;
headers_t meta;
int fd;
int isclose = 1;
if(foreground)
printf("s3fs_chown_nocopy [path=%s] [uid=%d] [gid=%d]\n", path, uid, gid);
Summary of Changes(1.62 -> 1.63) 1) Lifetime for the stats cache Added the new option "stat_cache_expire". This option which is specified by seconds means the lifetime for each stats cache entry. If this option is not specified, the stats cache is kept in s3fs process until the stats cache grown to maximum size. (default) If this option is specified, the stats cache entry is out from the memory when the entry expires time. 2) Enable file permission s3fs before 1.62 did not consider the file access permission. s3fs after this version can consider it. For access permission, the s3fs_getattr() function was divided into sub function which can check the file access permission. It is like access() function. And the function calling the s3fs_getattr() calls this new sub function instead of s3fs_getattr(). Last the s3fs_opendir() function which is called by FUSE was added for checking directory access permission when listing the files in directory. 3) UID/GUID When a file or a directory was created, the s3fs could not set the UID/GID as the user who executed a command. (Almost the UID/GID are root, because the s3fs run by root.) After this version, the s3fs set correct UID/GID as the user who executes the commond. 4) About the mtime If the object does not have "x-amz-meta-mtime" meta, the s3fs uses the "Last-Modified" header instead of it. But the s3fs had a bug in this code, and this version fixed this bug. When user modified the file, the s3fs did not update the mtime of the file. This version fixed this bug. In the get_local_fd() function, the local file's mtime was changed only when s3fs run with "use_cache" option. This version always updates the mtime whether the local cache file is used or not. And s3fs_flush ( ) function set the mtime of local cache file from S3 object mtime, but it was wrong . This version is that the s3fs_flush ( ) changes the mtime of S3 object from the local cache file or the tmpfile . The s3fs cuts some requests, because the s3fs can always check mtime whether the s3fs uses or does not use the local cache file. 5) A case of no "x-amz-meta-mode" If the object did not have "x-amz-meta-mtime" mete, the s3fs recognized the file as not regular file. After this version, the s3fs recognizes the file as regular file. 6) "." and ".." directory The s3fs_readdir() did not return "X" and "XX" directory name. After this version, the s3fs is changed that it returns "X" and "XX". Example, the result of "ls" lists "X" and "XX" directory. 7) Fixed a bug The insert_object() had a bug, and it is fixed. git-svn-id: http://s3fs.googlecode.com/svn/trunk@390 df820570-a93a-0410-bd06-b72b767a4274
2013-02-24 08:58:54 +00:00
if(0 != (result = check_parent_object_access(path, W_OK | X_OK))){
return result;
}
if(0 != (result = check_object_access(path, W_OK, NULL))){
return result;
}
// Downloading
if(0 > (fd = get_opened_fd(path))){
if(0 > (fd = get_local_fd(path))){
if(foreground) {
printf(" s3fs_chown_nocopy line %d: get_local_fd result: %d\n", __LINE__, fd);
}
syslog(LOG_ERR, "s3fs_chown_nocopy line %d: get_local_fd result: %d", __LINE__, fd);
return -EIO;
}
}else{
isclose = 0;
}
// Get attributes
s3_realpath = get_realpath(path);
result = curl_get_headers(s3_realpath, meta);
free(s3_realpath);
if(result != 0){
if(isclose){
close(fd);
}
return result;
}
// Change owner
struct passwd *aaa = getpwuid(uid);
if(aaa != 0){
meta["x-amz-meta-uid"] = str((*aaa).pw_uid);
}
struct group *bbb = getgrgid(gid);
if(bbb != 0){
meta["x-amz-meta-gid"] = str((*bbb).gr_gid);
}
// Change local file owner
if(-1 == fchown(fd, uid, gid)){
if(isclose){
close(fd);
}
if(foreground) {
printf(" s3fs_chown_nocopy line %d: fchown(fd=%d, uid=%d, gid=%d) is error(%d)\n", __LINE__, fd, (int)uid, (int)gid, errno);
}
syslog(LOG_ERR, "s3fs_chown_nocopy line %d: fchown(fd=%d, uid=%d, gid=%d) is error(%d)", __LINE__, fd, (int)uid, (int)gid, errno);
return -errno;
}
// Re-uploading
if(0 != (result = put_local_fd(path, meta, fd))){
if(foreground) {
printf(" s3fs_chown_nocopy line %d: put_local_fd result: %d\n", __LINE__, result);
}
}
if(isclose){
close(fd);
}
delete_stat_cache_entry(path);
return 0;
}
static int s3fs_truncate(const char *path, off_t size) {
int fd = -1;
int result;
headers_t meta;
char *s3_realpath;
int isclose = 1;
if(foreground)
printf("s3fs_truncate[path=%s][size=%zd]\n", path, size);
Summary of Changes(1.62 -> 1.63) 1) Lifetime for the stats cache Added the new option "stat_cache_expire". This option which is specified by seconds means the lifetime for each stats cache entry. If this option is not specified, the stats cache is kept in s3fs process until the stats cache grown to maximum size. (default) If this option is specified, the stats cache entry is out from the memory when the entry expires time. 2) Enable file permission s3fs before 1.62 did not consider the file access permission. s3fs after this version can consider it. For access permission, the s3fs_getattr() function was divided into sub function which can check the file access permission. It is like access() function. And the function calling the s3fs_getattr() calls this new sub function instead of s3fs_getattr(). Last the s3fs_opendir() function which is called by FUSE was added for checking directory access permission when listing the files in directory. 3) UID/GUID When a file or a directory was created, the s3fs could not set the UID/GID as the user who executed a command. (Almost the UID/GID are root, because the s3fs run by root.) After this version, the s3fs set correct UID/GID as the user who executes the commond. 4) About the mtime If the object does not have "x-amz-meta-mtime" meta, the s3fs uses the "Last-Modified" header instead of it. But the s3fs had a bug in this code, and this version fixed this bug. When user modified the file, the s3fs did not update the mtime of the file. This version fixed this bug. In the get_local_fd() function, the local file's mtime was changed only when s3fs run with "use_cache" option. This version always updates the mtime whether the local cache file is used or not. And s3fs_flush ( ) function set the mtime of local cache file from S3 object mtime, but it was wrong . This version is that the s3fs_flush ( ) changes the mtime of S3 object from the local cache file or the tmpfile . The s3fs cuts some requests, because the s3fs can always check mtime whether the s3fs uses or does not use the local cache file. 5) A case of no "x-amz-meta-mode" If the object did not have "x-amz-meta-mtime" mete, the s3fs recognized the file as not regular file. After this version, the s3fs recognizes the file as regular file. 6) "." and ".." directory The s3fs_readdir() did not return "X" and "XX" directory name. After this version, the s3fs is changed that it returns "X" and "XX". Example, the result of "ls" lists "X" and "XX" directory. 7) Fixed a bug The insert_object() had a bug, and it is fixed. git-svn-id: http://s3fs.googlecode.com/svn/trunk@390 df820570-a93a-0410-bd06-b72b767a4274
2013-02-24 08:58:54 +00:00
if(0 != (result = check_parent_object_access(path, W_OK | X_OK))){
return result;
}
if(0 != (result = check_object_access(path, W_OK, NULL))){
return result;
}
// Get file information
s3_realpath = get_realpath(path);
result = curl_get_headers(s3_realpath, meta);
free(s3_realpath);
if(0 == result){
// Exists -> Get file
if(0 > (fd = get_opened_fd(path))){
if(0 > (fd = get_local_fd(path))){
if(foreground) {
printf(" s3fs_truncate line %d: get_local_fd result: %d\n", __LINE__, fd);
}
syslog(LOG_ERR, "s3fs_truncate line %d: get_local_fd result: %d", __LINE__, fd);
return -EIO;
}
}else{
isclose = 0;
}
}else{
// Not found -> Make tmpfile
if(-1 == (fd = fileno(tmpfile()))){
syslog(LOG_ERR, "error: line %d: %d", __LINE__, -errno);
return -errno;
}
}
// Truncate
if(0 != ftruncate(fd, size) || 0 != fsync(fd)){
if(foreground) {
printf(" s3fs_truncate line %d: ftruncate or fsync returned err(%d)\n", __LINE__, errno);
}
syslog(LOG_ERR, "s3fs_truncate line %d: ftruncate or fsync returned err(%d)", __LINE__, errno);
if(isclose){
close(fd);
}
return -errno;
}
// Re-uploading
if(0 != (result = put_local_fd(path, meta, fd))){
if(foreground) {
printf(" s3fs_truncate line %d: put_local_fd result: %d\n", __LINE__, result);
}
}
if(isclose){
close(fd);
}
delete_stat_cache_entry(path);
return 0;
}
static int s3fs_open(const char *path, struct fuse_file_info *fi) {
int result;
headers_t meta;
if(foreground)
cout << "s3fs_open[path=" << path << "][flags=" << fi->flags << "]" << endl;
Summary of Changes(1.62 -> 1.63) 1) Lifetime for the stats cache Added the new option "stat_cache_expire". This option which is specified by seconds means the lifetime for each stats cache entry. If this option is not specified, the stats cache is kept in s3fs process until the stats cache grown to maximum size. (default) If this option is specified, the stats cache entry is out from the memory when the entry expires time. 2) Enable file permission s3fs before 1.62 did not consider the file access permission. s3fs after this version can consider it. For access permission, the s3fs_getattr() function was divided into sub function which can check the file access permission. It is like access() function. And the function calling the s3fs_getattr() calls this new sub function instead of s3fs_getattr(). Last the s3fs_opendir() function which is called by FUSE was added for checking directory access permission when listing the files in directory. 3) UID/GUID When a file or a directory was created, the s3fs could not set the UID/GID as the user who executed a command. (Almost the UID/GID are root, because the s3fs run by root.) After this version, the s3fs set correct UID/GID as the user who executes the commond. 4) About the mtime If the object does not have "x-amz-meta-mtime" meta, the s3fs uses the "Last-Modified" header instead of it. But the s3fs had a bug in this code, and this version fixed this bug. When user modified the file, the s3fs did not update the mtime of the file. This version fixed this bug. In the get_local_fd() function, the local file's mtime was changed only when s3fs run with "use_cache" option. This version always updates the mtime whether the local cache file is used or not. And s3fs_flush ( ) function set the mtime of local cache file from S3 object mtime, but it was wrong . This version is that the s3fs_flush ( ) changes the mtime of S3 object from the local cache file or the tmpfile . The s3fs cuts some requests, because the s3fs can always check mtime whether the s3fs uses or does not use the local cache file. 5) A case of no "x-amz-meta-mode" If the object did not have "x-amz-meta-mtime" mete, the s3fs recognized the file as not regular file. After this version, the s3fs recognizes the file as regular file. 6) "." and ".." directory The s3fs_readdir() did not return "X" and "XX" directory name. After this version, the s3fs is changed that it returns "X" and "XX". Example, the result of "ls" lists "X" and "XX" directory. 7) Fixed a bug The insert_object() had a bug, and it is fixed. git-svn-id: http://s3fs.googlecode.com/svn/trunk@390 df820570-a93a-0410-bd06-b72b767a4274
2013-02-24 08:58:54 +00:00
int mask = (O_RDONLY != (fi->flags & O_ACCMODE) ? W_OK : R_OK);
if(0 != (result = check_parent_object_access(path, mask | X_OK))){
return result;
}
if(0 != (result = check_object_access(path, mask, NULL))){
return result;
}
// Go do the truncation if called for
if((unsigned int)fi->flags & O_TRUNC) {
result = s3fs_truncate(path, 0);
if(result != 0)
return result;
}
if((fi->fh = get_local_fd(path)) <= 0)
return -EIO;
// remember flags and headers...
pthread_mutex_lock( &s3fs_descriptors_lock );
s3fs_descriptors[fi->fh] = fi->flags;
s3fs_pathtofd[string(path)] = fi->fh;
pthread_mutex_unlock( &s3fs_descriptors_lock );
return 0;
}
static int s3fs_read(
const char *path, char *buf, size_t size, off_t offset, struct fuse_file_info *fi) {
int res;
if(foreground)
cout << "s3fs_read[path=" << path << "]" << endl;
res = pread(fi->fh, buf, size, offset);
if(res == -1)
YIKES(-errno);
return res;
}
static int s3fs_write(
const char *path, const char *buf, size_t size, off_t offset, struct fuse_file_info *fi) {
int res = pwrite(fi->fh, buf, size, offset);
Summary of Changes(1.62 -> 1.63) 1) Lifetime for the stats cache Added the new option "stat_cache_expire". This option which is specified by seconds means the lifetime for each stats cache entry. If this option is not specified, the stats cache is kept in s3fs process until the stats cache grown to maximum size. (default) If this option is specified, the stats cache entry is out from the memory when the entry expires time. 2) Enable file permission s3fs before 1.62 did not consider the file access permission. s3fs after this version can consider it. For access permission, the s3fs_getattr() function was divided into sub function which can check the file access permission. It is like access() function. And the function calling the s3fs_getattr() calls this new sub function instead of s3fs_getattr(). Last the s3fs_opendir() function which is called by FUSE was added for checking directory access permission when listing the files in directory. 3) UID/GUID When a file or a directory was created, the s3fs could not set the UID/GID as the user who executed a command. (Almost the UID/GID are root, because the s3fs run by root.) After this version, the s3fs set correct UID/GID as the user who executes the commond. 4) About the mtime If the object does not have "x-amz-meta-mtime" meta, the s3fs uses the "Last-Modified" header instead of it. But the s3fs had a bug in this code, and this version fixed this bug. When user modified the file, the s3fs did not update the mtime of the file. This version fixed this bug. In the get_local_fd() function, the local file's mtime was changed only when s3fs run with "use_cache" option. This version always updates the mtime whether the local cache file is used or not. And s3fs_flush ( ) function set the mtime of local cache file from S3 object mtime, but it was wrong . This version is that the s3fs_flush ( ) changes the mtime of S3 object from the local cache file or the tmpfile . The s3fs cuts some requests, because the s3fs can always check mtime whether the s3fs uses or does not use the local cache file. 5) A case of no "x-amz-meta-mode" If the object did not have "x-amz-meta-mtime" mete, the s3fs recognized the file as not regular file. After this version, the s3fs recognizes the file as regular file. 6) "." and ".." directory The s3fs_readdir() did not return "X" and "XX" directory name. After this version, the s3fs is changed that it returns "X" and "XX". Example, the result of "ls" lists "X" and "XX" directory. 7) Fixed a bug The insert_object() had a bug, and it is fixed. git-svn-id: http://s3fs.googlecode.com/svn/trunk@390 df820570-a93a-0410-bd06-b72b767a4274
2013-02-24 08:58:54 +00:00
// Commented - This message is output too much
//if(foreground)
// cout << "s3fs_write[path=" << path << "]" << endl;
if(res == -1)
YIKES(-errno);
return res;
}
static int s3fs_statfs(const char *path, struct statvfs *stbuf) {
// 256T
stbuf->f_bsize = 0X1000000;
stbuf->f_blocks = 0X1000000;
stbuf->f_bfree = 0x1000000;
stbuf->f_bavail = 0x1000000;
stbuf->f_namemax = NAME_MAX;
return 0;
}
static int get_flags(int fd) {
int flags;
pthread_mutex_lock( &s3fs_descriptors_lock );
flags = s3fs_descriptors[fd];
pthread_mutex_unlock( &s3fs_descriptors_lock );
return flags;
}
static int s3fs_flush(const char *path, struct fuse_file_info *fi) {
int flags;
int result;
int fd = fi->fh;
char *s3_realpath;
if(foreground)
cout << "s3fs_flush[path=" << path << "][fd=" << fd << "]" << endl;
Summary of Changes(1.62 -> 1.63) 1) Lifetime for the stats cache Added the new option "stat_cache_expire". This option which is specified by seconds means the lifetime for each stats cache entry. If this option is not specified, the stats cache is kept in s3fs process until the stats cache grown to maximum size. (default) If this option is specified, the stats cache entry is out from the memory when the entry expires time. 2) Enable file permission s3fs before 1.62 did not consider the file access permission. s3fs after this version can consider it. For access permission, the s3fs_getattr() function was divided into sub function which can check the file access permission. It is like access() function. And the function calling the s3fs_getattr() calls this new sub function instead of s3fs_getattr(). Last the s3fs_opendir() function which is called by FUSE was added for checking directory access permission when listing the files in directory. 3) UID/GUID When a file or a directory was created, the s3fs could not set the UID/GID as the user who executed a command. (Almost the UID/GID are root, because the s3fs run by root.) After this version, the s3fs set correct UID/GID as the user who executes the commond. 4) About the mtime If the object does not have "x-amz-meta-mtime" meta, the s3fs uses the "Last-Modified" header instead of it. But the s3fs had a bug in this code, and this version fixed this bug. When user modified the file, the s3fs did not update the mtime of the file. This version fixed this bug. In the get_local_fd() function, the local file's mtime was changed only when s3fs run with "use_cache" option. This version always updates the mtime whether the local cache file is used or not. And s3fs_flush ( ) function set the mtime of local cache file from S3 object mtime, but it was wrong . This version is that the s3fs_flush ( ) changes the mtime of S3 object from the local cache file or the tmpfile . The s3fs cuts some requests, because the s3fs can always check mtime whether the s3fs uses or does not use the local cache file. 5) A case of no "x-amz-meta-mode" If the object did not have "x-amz-meta-mtime" mete, the s3fs recognized the file as not regular file. After this version, the s3fs recognizes the file as regular file. 6) "." and ".." directory The s3fs_readdir() did not return "X" and "XX" directory name. After this version, the s3fs is changed that it returns "X" and "XX". Example, the result of "ls" lists "X" and "XX" directory. 7) Fixed a bug The insert_object() had a bug, and it is fixed. git-svn-id: http://s3fs.googlecode.com/svn/trunk@390 df820570-a93a-0410-bd06-b72b767a4274
2013-02-24 08:58:54 +00:00
int mask = (O_RDONLY != (fi->flags & O_ACCMODE) ? W_OK : R_OK);
if(0 != (result = check_parent_object_access(path, mask | X_OK))){
return result;
}
if(0 != (result = check_object_access(path, mask, NULL))){
return result;
}
// NOTE- fi->flags is not available here
flags = get_flags(fd);
Summary of Changes(1.62 -> 1.63) 1) Lifetime for the stats cache Added the new option "stat_cache_expire". This option which is specified by seconds means the lifetime for each stats cache entry. If this option is not specified, the stats cache is kept in s3fs process until the stats cache grown to maximum size. (default) If this option is specified, the stats cache entry is out from the memory when the entry expires time. 2) Enable file permission s3fs before 1.62 did not consider the file access permission. s3fs after this version can consider it. For access permission, the s3fs_getattr() function was divided into sub function which can check the file access permission. It is like access() function. And the function calling the s3fs_getattr() calls this new sub function instead of s3fs_getattr(). Last the s3fs_opendir() function which is called by FUSE was added for checking directory access permission when listing the files in directory. 3) UID/GUID When a file or a directory was created, the s3fs could not set the UID/GID as the user who executed a command. (Almost the UID/GID are root, because the s3fs run by root.) After this version, the s3fs set correct UID/GID as the user who executes the commond. 4) About the mtime If the object does not have "x-amz-meta-mtime" meta, the s3fs uses the "Last-Modified" header instead of it. But the s3fs had a bug in this code, and this version fixed this bug. When user modified the file, the s3fs did not update the mtime of the file. This version fixed this bug. In the get_local_fd() function, the local file's mtime was changed only when s3fs run with "use_cache" option. This version always updates the mtime whether the local cache file is used or not. And s3fs_flush ( ) function set the mtime of local cache file from S3 object mtime, but it was wrong . This version is that the s3fs_flush ( ) changes the mtime of S3 object from the local cache file or the tmpfile . The s3fs cuts some requests, because the s3fs can always check mtime whether the s3fs uses or does not use the local cache file. 5) A case of no "x-amz-meta-mode" If the object did not have "x-amz-meta-mtime" mete, the s3fs recognized the file as not regular file. After this version, the s3fs recognizes the file as regular file. 6) "." and ".." directory The s3fs_readdir() did not return "X" and "XX" directory name. After this version, the s3fs is changed that it returns "X" and "XX". Example, the result of "ls" lists "X" and "XX" directory. 7) Fixed a bug The insert_object() had a bug, and it is fixed. git-svn-id: http://s3fs.googlecode.com/svn/trunk@390 df820570-a93a-0410-bd06-b72b767a4274
2013-02-24 08:58:54 +00:00
if(O_RDONLY != (flags & O_ACCMODE)) {
headers_t meta;
s3_realpath = get_realpath(path);
result = curl_get_headers(s3_realpath, meta);
free(s3_realpath);
if(result != 0)
return result;
// if the cached file matches the remote file skip uploading
Summary of Changes(1.62 -> 1.63) 1) Lifetime for the stats cache Added the new option "stat_cache_expire". This option which is specified by seconds means the lifetime for each stats cache entry. If this option is not specified, the stats cache is kept in s3fs process until the stats cache grown to maximum size. (default) If this option is specified, the stats cache entry is out from the memory when the entry expires time. 2) Enable file permission s3fs before 1.62 did not consider the file access permission. s3fs after this version can consider it. For access permission, the s3fs_getattr() function was divided into sub function which can check the file access permission. It is like access() function. And the function calling the s3fs_getattr() calls this new sub function instead of s3fs_getattr(). Last the s3fs_opendir() function which is called by FUSE was added for checking directory access permission when listing the files in directory. 3) UID/GUID When a file or a directory was created, the s3fs could not set the UID/GID as the user who executed a command. (Almost the UID/GID are root, because the s3fs run by root.) After this version, the s3fs set correct UID/GID as the user who executes the commond. 4) About the mtime If the object does not have "x-amz-meta-mtime" meta, the s3fs uses the "Last-Modified" header instead of it. But the s3fs had a bug in this code, and this version fixed this bug. When user modified the file, the s3fs did not update the mtime of the file. This version fixed this bug. In the get_local_fd() function, the local file's mtime was changed only when s3fs run with "use_cache" option. This version always updates the mtime whether the local cache file is used or not. And s3fs_flush ( ) function set the mtime of local cache file from S3 object mtime, but it was wrong . This version is that the s3fs_flush ( ) changes the mtime of S3 object from the local cache file or the tmpfile . The s3fs cuts some requests, because the s3fs can always check mtime whether the s3fs uses or does not use the local cache file. 5) A case of no "x-amz-meta-mode" If the object did not have "x-amz-meta-mtime" mete, the s3fs recognized the file as not regular file. After this version, the s3fs recognizes the file as regular file. 6) "." and ".." directory The s3fs_readdir() did not return "X" and "XX" directory name. After this version, the s3fs is changed that it returns "X" and "XX". Example, the result of "ls" lists "X" and "XX" directory. 7) Fixed a bug The insert_object() had a bug, and it is fixed. git-svn-id: http://s3fs.googlecode.com/svn/trunk@390 df820570-a93a-0410-bd06-b72b767a4274
2013-02-24 08:58:54 +00:00
struct stat st;
if((fstat(fd, &st)) == -1)
YIKES(-errno);
Summary of Changes(1.62 -> 1.63) 1) Lifetime for the stats cache Added the new option "stat_cache_expire". This option which is specified by seconds means the lifetime for each stats cache entry. If this option is not specified, the stats cache is kept in s3fs process until the stats cache grown to maximum size. (default) If this option is specified, the stats cache entry is out from the memory when the entry expires time. 2) Enable file permission s3fs before 1.62 did not consider the file access permission. s3fs after this version can consider it. For access permission, the s3fs_getattr() function was divided into sub function which can check the file access permission. It is like access() function. And the function calling the s3fs_getattr() calls this new sub function instead of s3fs_getattr(). Last the s3fs_opendir() function which is called by FUSE was added for checking directory access permission when listing the files in directory. 3) UID/GUID When a file or a directory was created, the s3fs could not set the UID/GID as the user who executed a command. (Almost the UID/GID are root, because the s3fs run by root.) After this version, the s3fs set correct UID/GID as the user who executes the commond. 4) About the mtime If the object does not have "x-amz-meta-mtime" meta, the s3fs uses the "Last-Modified" header instead of it. But the s3fs had a bug in this code, and this version fixed this bug. When user modified the file, the s3fs did not update the mtime of the file. This version fixed this bug. In the get_local_fd() function, the local file's mtime was changed only when s3fs run with "use_cache" option. This version always updates the mtime whether the local cache file is used or not. And s3fs_flush ( ) function set the mtime of local cache file from S3 object mtime, but it was wrong . This version is that the s3fs_flush ( ) changes the mtime of S3 object from the local cache file or the tmpfile . The s3fs cuts some requests, because the s3fs can always check mtime whether the s3fs uses or does not use the local cache file. 5) A case of no "x-amz-meta-mode" If the object did not have "x-amz-meta-mtime" mete, the s3fs recognized the file as not regular file. After this version, the s3fs recognizes the file as regular file. 6) "." and ".." directory The s3fs_readdir() did not return "X" and "XX" directory name. After this version, the s3fs is changed that it returns "X" and "XX". Example, the result of "ls" lists "X" and "XX" directory. 7) Fixed a bug The insert_object() had a bug, and it is fixed. git-svn-id: http://s3fs.googlecode.com/svn/trunk@390 df820570-a93a-0410-bd06-b72b767a4274
2013-02-24 08:58:54 +00:00
if(str(st.st_size) == meta["Content-Length"] &&
(str(st.st_mtime) == meta["x-amz-meta-mtime"])) {
return result;
}
Summary of Changes(1.62 -> 1.63) 1) Lifetime for the stats cache Added the new option "stat_cache_expire". This option which is specified by seconds means the lifetime for each stats cache entry. If this option is not specified, the stats cache is kept in s3fs process until the stats cache grown to maximum size. (default) If this option is specified, the stats cache entry is out from the memory when the entry expires time. 2) Enable file permission s3fs before 1.62 did not consider the file access permission. s3fs after this version can consider it. For access permission, the s3fs_getattr() function was divided into sub function which can check the file access permission. It is like access() function. And the function calling the s3fs_getattr() calls this new sub function instead of s3fs_getattr(). Last the s3fs_opendir() function which is called by FUSE was added for checking directory access permission when listing the files in directory. 3) UID/GUID When a file or a directory was created, the s3fs could not set the UID/GID as the user who executed a command. (Almost the UID/GID are root, because the s3fs run by root.) After this version, the s3fs set correct UID/GID as the user who executes the commond. 4) About the mtime If the object does not have "x-amz-meta-mtime" meta, the s3fs uses the "Last-Modified" header instead of it. But the s3fs had a bug in this code, and this version fixed this bug. When user modified the file, the s3fs did not update the mtime of the file. This version fixed this bug. In the get_local_fd() function, the local file's mtime was changed only when s3fs run with "use_cache" option. This version always updates the mtime whether the local cache file is used or not. And s3fs_flush ( ) function set the mtime of local cache file from S3 object mtime, but it was wrong . This version is that the s3fs_flush ( ) changes the mtime of S3 object from the local cache file or the tmpfile . The s3fs cuts some requests, because the s3fs can always check mtime whether the s3fs uses or does not use the local cache file. 5) A case of no "x-amz-meta-mode" If the object did not have "x-amz-meta-mtime" mete, the s3fs recognized the file as not regular file. After this version, the s3fs recognizes the file as regular file. 6) "." and ".." directory The s3fs_readdir() did not return "X" and "XX" directory name. After this version, the s3fs is changed that it returns "X" and "XX". Example, the result of "ls" lists "X" and "XX" directory. 7) Fixed a bug The insert_object() had a bug, and it is fixed. git-svn-id: http://s3fs.googlecode.com/svn/trunk@390 df820570-a93a-0410-bd06-b72b767a4274
2013-02-24 08:58:54 +00:00
// If both mtime are not same, force to change mtime based on fd.
if(str(st.st_mtime) != meta["x-amz-meta-mtime"]){
meta["x-amz-meta-mtime"] = str(st.st_mtime);
}
return put_local_fd(path, meta, fd);
}
return 0;
}
static int s3fs_release(const char *path, struct fuse_file_info *fi) {
if(foreground)
cout << "s3fs_release[path=" << path << "][fd=" << fi->fh << "]" << endl;
// clear file discriptor mapping.
s3fs_pathtofd_t::iterator it;
pthread_mutex_lock( &s3fs_descriptors_lock );
if(s3fs_pathtofd.end() != (it = s3fs_pathtofd.find(string(path)))){
if(fi->fh == (uint)s3fs_pathtofd[string(path)]){
s3fs_pathtofd.erase(it);
}else{
if(foreground) {
printf("s3fs_release line %d: file discriptor is not same(%d : %d)\n", __LINE__, (int)fi->fh, s3fs_pathtofd[string(path)]);
}
}
}
pthread_mutex_unlock( &s3fs_descriptors_lock );
if(close(fi->fh) == -1)
YIKES(-errno);
if((fi->flags & O_RDWR) || (fi->flags & O_WRONLY))
delete_stat_cache_entry(path);
return 0;
}
static CURL *create_head_handle(head_data *request_data) {
CURL *curl_handle = create_curl_handle();
string resource = urlEncode(service_path + bucket + request_data->path);
string url = host + resource;
// libcurl 7.17 does deep copy of url, deep copy "stable" url
string my_url = prepare_url(url.c_str());
request_data->url = new string(my_url.c_str());
request_data->requestHeaders = 0;
request_data->responseHeaders = new headers_t;
curl_easy_setopt(curl_handle, CURLOPT_URL, request_data->url->c_str());
curl_easy_setopt(curl_handle, CURLOPT_NOBODY, true); // HEAD
curl_easy_setopt(curl_handle, CURLOPT_FILETIME, true); // Last-Modified
// requestHeaders
string date = get_date();
request_data->requestHeaders = curl_slist_append(
request_data->requestHeaders, string("Date: " + date).c_str());
request_data->requestHeaders = curl_slist_append(
request_data->requestHeaders, string("Content-Type: ").c_str());
if(public_bucket.substr(0,1) != "1") {
request_data->requestHeaders = curl_slist_append(
request_data->requestHeaders, string("Authorization: AWS " + AWSAccessKeyId + ":" +
calc_signature("HEAD", "", date, request_data->requestHeaders, resource)).c_str());
}
curl_easy_setopt(curl_handle, CURLOPT_HTTPHEADER, request_data->requestHeaders);
// responseHeaders
curl_easy_setopt(curl_handle, CURLOPT_HEADERDATA, request_data->responseHeaders);
curl_easy_setopt(curl_handle, CURLOPT_HEADERFUNCTION, header_callback);
return curl_handle;
}
Summary of Changes(1.62 -> 1.63) 1) Lifetime for the stats cache Added the new option "stat_cache_expire". This option which is specified by seconds means the lifetime for each stats cache entry. If this option is not specified, the stats cache is kept in s3fs process until the stats cache grown to maximum size. (default) If this option is specified, the stats cache entry is out from the memory when the entry expires time. 2) Enable file permission s3fs before 1.62 did not consider the file access permission. s3fs after this version can consider it. For access permission, the s3fs_getattr() function was divided into sub function which can check the file access permission. It is like access() function. And the function calling the s3fs_getattr() calls this new sub function instead of s3fs_getattr(). Last the s3fs_opendir() function which is called by FUSE was added for checking directory access permission when listing the files in directory. 3) UID/GUID When a file or a directory was created, the s3fs could not set the UID/GID as the user who executed a command. (Almost the UID/GID are root, because the s3fs run by root.) After this version, the s3fs set correct UID/GID as the user who executes the commond. 4) About the mtime If the object does not have "x-amz-meta-mtime" meta, the s3fs uses the "Last-Modified" header instead of it. But the s3fs had a bug in this code, and this version fixed this bug. When user modified the file, the s3fs did not update the mtime of the file. This version fixed this bug. In the get_local_fd() function, the local file's mtime was changed only when s3fs run with "use_cache" option. This version always updates the mtime whether the local cache file is used or not. And s3fs_flush ( ) function set the mtime of local cache file from S3 object mtime, but it was wrong . This version is that the s3fs_flush ( ) changes the mtime of S3 object from the local cache file or the tmpfile . The s3fs cuts some requests, because the s3fs can always check mtime whether the s3fs uses or does not use the local cache file. 5) A case of no "x-amz-meta-mode" If the object did not have "x-amz-meta-mtime" mete, the s3fs recognized the file as not regular file. After this version, the s3fs recognizes the file as regular file. 6) "." and ".." directory The s3fs_readdir() did not return "X" and "XX" directory name. After this version, the s3fs is changed that it returns "X" and "XX". Example, the result of "ls" lists "X" and "XX" directory. 7) Fixed a bug The insert_object() had a bug, and it is fixed. git-svn-id: http://s3fs.googlecode.com/svn/trunk@390 df820570-a93a-0410-bd06-b72b767a4274
2013-02-24 08:58:54 +00:00
static int s3fs_opendir(const char *path, struct fuse_file_info *fi)
{
int result;
int mask = (O_RDONLY != (fi->flags & O_ACCMODE) ? W_OK : R_OK) | X_OK;
if(foreground)
cout << "s3fs_opendir [path=" << path << "][flags=" << fi->flags << "]" << endl;
if(0 == (result = check_object_access(path, mask, NULL))){
result = check_parent_object_access(path, mask);
}
return result;
}
static int s3fs_readdir(
const char *path, void *buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *fi) {
CURLM *mh;
CURLMsg *msg;
CURLMcode curlm_code;
int n_reqs;
int n_objects;
int remaining_messages;
struct s3_object *head = NULL;
struct s3_object *headref = NULL;
auto_head curl_map;
if(foreground)
cout << "s3fs_readdir[path=" << path << "]" << endl;
int result;
Summary of Changes(1.62 -> 1.63) 1) Lifetime for the stats cache Added the new option "stat_cache_expire". This option which is specified by seconds means the lifetime for each stats cache entry. If this option is not specified, the stats cache is kept in s3fs process until the stats cache grown to maximum size. (default) If this option is specified, the stats cache entry is out from the memory when the entry expires time. 2) Enable file permission s3fs before 1.62 did not consider the file access permission. s3fs after this version can consider it. For access permission, the s3fs_getattr() function was divided into sub function which can check the file access permission. It is like access() function. And the function calling the s3fs_getattr() calls this new sub function instead of s3fs_getattr(). Last the s3fs_opendir() function which is called by FUSE was added for checking directory access permission when listing the files in directory. 3) UID/GUID When a file or a directory was created, the s3fs could not set the UID/GID as the user who executed a command. (Almost the UID/GID are root, because the s3fs run by root.) After this version, the s3fs set correct UID/GID as the user who executes the commond. 4) About the mtime If the object does not have "x-amz-meta-mtime" meta, the s3fs uses the "Last-Modified" header instead of it. But the s3fs had a bug in this code, and this version fixed this bug. When user modified the file, the s3fs did not update the mtime of the file. This version fixed this bug. In the get_local_fd() function, the local file's mtime was changed only when s3fs run with "use_cache" option. This version always updates the mtime whether the local cache file is used or not. And s3fs_flush ( ) function set the mtime of local cache file from S3 object mtime, but it was wrong . This version is that the s3fs_flush ( ) changes the mtime of S3 object from the local cache file or the tmpfile . The s3fs cuts some requests, because the s3fs can always check mtime whether the s3fs uses or does not use the local cache file. 5) A case of no "x-amz-meta-mode" If the object did not have "x-amz-meta-mtime" mete, the s3fs recognized the file as not regular file. After this version, the s3fs recognizes the file as regular file. 6) "." and ".." directory The s3fs_readdir() did not return "X" and "XX" directory name. After this version, the s3fs is changed that it returns "X" and "XX". Example, the result of "ls" lists "X" and "XX" directory. 7) Fixed a bug The insert_object() had a bug, and it is fixed. git-svn-id: http://s3fs.googlecode.com/svn/trunk@390 df820570-a93a-0410-bd06-b72b767a4274
2013-02-24 08:58:54 +00:00
if(0 != (result = check_object_access(path, X_OK, NULL))){
return result;
}
// get a list of all the objects
if((result = list_bucket(path, &head)) != 0){
if(foreground)
printf(" s3fs_readdir list_bucket returns error.\n");
return result;
}
Summary of Changes(1.62 -> 1.63) 1) Lifetime for the stats cache Added the new option "stat_cache_expire". This option which is specified by seconds means the lifetime for each stats cache entry. If this option is not specified, the stats cache is kept in s3fs process until the stats cache grown to maximum size. (default) If this option is specified, the stats cache entry is out from the memory when the entry expires time. 2) Enable file permission s3fs before 1.62 did not consider the file access permission. s3fs after this version can consider it. For access permission, the s3fs_getattr() function was divided into sub function which can check the file access permission. It is like access() function. And the function calling the s3fs_getattr() calls this new sub function instead of s3fs_getattr(). Last the s3fs_opendir() function which is called by FUSE was added for checking directory access permission when listing the files in directory. 3) UID/GUID When a file or a directory was created, the s3fs could not set the UID/GID as the user who executed a command. (Almost the UID/GID are root, because the s3fs run by root.) After this version, the s3fs set correct UID/GID as the user who executes the commond. 4) About the mtime If the object does not have "x-amz-meta-mtime" meta, the s3fs uses the "Last-Modified" header instead of it. But the s3fs had a bug in this code, and this version fixed this bug. When user modified the file, the s3fs did not update the mtime of the file. This version fixed this bug. In the get_local_fd() function, the local file's mtime was changed only when s3fs run with "use_cache" option. This version always updates the mtime whether the local cache file is used or not. And s3fs_flush ( ) function set the mtime of local cache file from S3 object mtime, but it was wrong . This version is that the s3fs_flush ( ) changes the mtime of S3 object from the local cache file or the tmpfile . The s3fs cuts some requests, because the s3fs can always check mtime whether the s3fs uses or does not use the local cache file. 5) A case of no "x-amz-meta-mode" If the object did not have "x-amz-meta-mtime" mete, the s3fs recognized the file as not regular file. After this version, the s3fs recognizes the file as regular file. 6) "." and ".." directory The s3fs_readdir() did not return "X" and "XX" directory name. After this version, the s3fs is changed that it returns "X" and "XX". Example, the result of "ls" lists "X" and "XX" directory. 7) Fixed a bug The insert_object() had a bug, and it is fixed. git-svn-id: http://s3fs.googlecode.com/svn/trunk@390 df820570-a93a-0410-bd06-b72b767a4274
2013-02-24 08:58:54 +00:00
// force to add "." and ".." name.
if(0 != insert_object("..", &head) || 0 != insert_object(".", &head) || !head){
if(foreground)
printf(" s3fs_readdir list_bucket returns empty head.\n");
return 0;
}
n_objects = count_object_list(head);
// populate fuse buffer
headref = head;
while(headref != NULL) {
filler(buf, headref->name, 0, 0);
headref = headref->next;
}
headref = head;
// populate the multi interface with an initial set of requests
n_reqs = 0;
mh = curl_multi_init();
while(n_reqs < MAX_REQUESTS && head != NULL) {
string fullpath = path;
if(strcmp(path, "/") != 0)
fullpath += "/" + string(head->name);
else
fullpath += string(head->name);
if(get_stat_cache_entry(fullpath.c_str(), NULL) == 0) {
head = head->next;
continue;
}
// file not cached, prepare a call to get_headers
head_data request_data;
request_data.path = fullpath;
CURL *curl_handle = create_head_handle(&request_data);
curl_map.get()[curl_handle] = request_data;
// add this handle to the multi handle
n_reqs++;
curlm_code = curl_multi_add_handle(mh, curl_handle);
if(curlm_code != CURLM_OK) {
syslog(LOG_ERR, "readdir: curl_multi_add_handle code: %d msg: %s",
curlm_code, curl_multi_strerror(curlm_code));
return -EIO;
}
// go to the next object.
head = head->next;
}
// Start making requests.
int still_running = 0;
do {
curlm_code = curl_multi_perform(mh, &still_running);
} while(curlm_code == CURLM_CALL_MULTI_PERFORM);
if(curlm_code != CURLM_OK) {
syslog(LOG_ERR, "readdir: curl_multi_perform code: %d msg: %s",
curlm_code, curl_multi_strerror(curlm_code));
}
while(still_running) {
do {
curlm_code = curl_multi_perform(mh, &still_running);
} while(curlm_code == CURLM_CALL_MULTI_PERFORM);
if(curlm_code != CURLM_OK) {
syslog(LOG_ERR, "s3fs_readdir: curl_multi_perform code: %d msg: %s",
curlm_code, curl_multi_strerror(curlm_code));
}
if(still_running) {
fd_set r_fd;
fd_set w_fd;
fd_set e_fd;
FD_ZERO(&r_fd);
FD_ZERO(&w_fd);
FD_ZERO(&e_fd);
long milliseconds;
curlm_code = curl_multi_timeout(mh, &milliseconds);
if(curlm_code != CURLM_OK) {
syslog(LOG_ERR, "readdir: curl_multi_perform code: %d msg: %s",
curlm_code, curl_multi_strerror(curlm_code));
}
if(milliseconds < 0)
milliseconds = 50;
if(milliseconds > 0) {
struct timeval timeout;
timeout.tv_sec = 1000 * milliseconds / 1000000;
timeout.tv_usec = 1000 * milliseconds % 1000000;
int max_fd;
curlm_code = curl_multi_fdset(mh, &r_fd, &w_fd, &e_fd, &max_fd);
if(curlm_code != CURLM_OK) {
syslog(LOG_ERR, "readdir: curl_multi_fdset code: %d msg: %s",
curlm_code, curl_multi_strerror(curlm_code));
return -EIO;
}
if(select(max_fd + 1, &r_fd, &w_fd, &e_fd, &timeout) == -1)
YIKES(-errno);
}
}
while((msg = curl_multi_info_read(mh, &remaining_messages))) {
if(msg->msg == CURLMSG_DONE) {
CURLcode code = msg->data.result;
if(code != 0) {
syslog(LOG_DEBUG, "s3fs_readdir: remaining_msgs: %i code: %d msg: %s",
remaining_messages, code, curl_easy_strerror(code));
return -EIO;
}
CURL *curl_handle = msg->easy_handle;
head_data response = curl_map.get()[curl_handle];
struct stat st;
memset(&st, 0, sizeof(st));
st.st_nlink = 1; // see fuse FAQ
// mode
st.st_mode = get_mode((*response.responseHeaders)["x-amz-meta-mode"].c_str());
// content-type
char *ContentType = 0;
if(curl_easy_getinfo(curl_handle, CURLINFO_CONTENT_TYPE, &ContentType) == 0)
if(ContentType)
st.st_mode |= strcmp(ContentType, "application/x-directory") == 0 ? S_IFDIR : S_IFREG;
// mtime
st.st_mtime = get_mtime((*response.responseHeaders)["x-amz-meta-mtime"].c_str());
if(st.st_mtime == 0) {
long LastModified;
if(curl_easy_getinfo(curl_handle, CURLINFO_FILETIME, &LastModified) == 0)
st.st_mtime = LastModified;
}
// size
double ContentLength;
if(curl_easy_getinfo(curl_handle, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &ContentLength) == 0)
st.st_size = static_cast<off_t>(ContentLength);
if(S_ISREG(st.st_mode))
st.st_blocks = get_blocks(st.st_size);
st.st_uid = get_uid((*response.responseHeaders)["x-amz-meta-uid"].c_str());
st.st_gid = get_gid((*response.responseHeaders)["x-amz-meta-gid"].c_str());
add_stat_cache_entry(response.path.c_str(), &st);
// cleanup
curl_multi_remove_handle(mh, curl_handle);
destroy_curl_handle(curl_handle);
n_reqs--;
// add additional requests
while(n_reqs < MAX_REQUESTS && head != NULL) {
string fullpath = path;
if(strcmp(path, "/") != 0)
fullpath += "/" + string(head->name);
else
fullpath += string(head->name);
if(get_stat_cache_entry(fullpath.c_str(), NULL) == 0) {
head = head->next;
continue;
}
// file not cached, prepare a call to get_headers
head_data request_data;
request_data.path = fullpath;
CURL *curl_handle = create_head_handle(&request_data);
curl_map.get()[curl_handle] = request_data;
// add this handle to the multi handle
n_reqs++;
curlm_code = curl_multi_add_handle(mh, curl_handle);
if(curlm_code != CURLM_OK) {
syslog(LOG_ERR, "readdir: curl_multi_add_handle code: %d msg: %s",
curlm_code, curl_multi_strerror(curlm_code));
return -EIO;
}
// prevent this from sitting at 0, we may have requests to finish
still_running++;
// go to the next object.
head = head->next;
}
} else {
syslog(LOG_ERR, "readdir: curl_multi_add_handle code: %d msg: %s",
curlm_code, curl_multi_strerror(curlm_code));
curl_multi_cleanup(mh);
free_object_list(headref);
return -EIO;
}
}
}
curl_multi_cleanup(mh);
free_object_list(headref);
return 0;
}
static int list_bucket(const char *path, struct s3_object **head) {
CURL *curl;
int result;
char *s3_realpath;
struct BodyStruct body;
bool truncated = true;
string next_marker = "";
if(foreground)
printf("list_bucket [path=%s]\n", path);
body.text = (char *) malloc(1);
body.size = 0;
s3_realpath = get_realpath(path);
string resource = urlEncode(service_path + bucket); // this is what gets signed
string query = "delimiter=/&prefix=";
if(strcmp(path, "/") != 0)
query += urlEncode(string(s3_realpath).substr(1) + "/");
else
query += urlEncode(string(s3_realpath).substr(1));
free(s3_realpath);
query += "&max-keys=1000";
while(truncated) {
string url = host + resource + "?" + query;
if(next_marker != ""){
url += "&marker=" + urlEncode(next_marker);
next_marker = "";
}
string my_url = prepare_url(url.c_str());
auto_curl_slist headers;
string date = get_date();
headers.append("Date: " + date);
headers.append("ContentType: ");
if(public_bucket.substr(0,1) != "1") {
headers.append("Authorization: AWS " + AWSAccessKeyId + ":" +
calc_signature("GET", "", date, headers.get(), resource + "/"));
}
curl = create_curl_handle();
curl_easy_setopt(curl, CURLOPT_URL, my_url.c_str());
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *) &body);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers.get());
result = my_curl_easy_perform(curl, &body);
destroy_curl_handle(curl);
if(result != 0) {
if(body.text)
free(body.text);
if(foreground)
printf(" list_bucket my_curl_easy_perform returns with error.\n");
return result;
}
if((append_objects_from_xml(path, body.text, head)) != 0) {
if(body.text)
free(body.text);
if(foreground)
printf(" list_bucket append_objects_from_xml returns with error.\n");
return -1;
}
truncated = is_truncated(body.text);
if(truncated){
xmlChar* tmpch = (xmlChar*)get_next_marker(body.text);
if(tmpch){
next_marker = (char*)tmpch;
xmlFree(tmpch);
}
}
if(body.text)
free(body.text);
body.size = 0;
body.text = (char *) malloc(1);
}
if(body.text)
free(body.text);
return 0;
}
const char* c_strErrorObjectName = "FILE or SUBDIR in DIR";
static int append_objects_from_xml(const char* path, const char *xml, struct s3_object **head) {
xmlDocPtr doc;
xmlXPathContextPtr ctx;
xmlXPathObjectPtr contents_xp;
xmlNodeSetPtr content_nodes;
string exp_contents = noxmlns ? "//Contents" : "//s3:Contents";
string exp_Key = noxmlns ? "Key" : "s3:Key";
doc = xmlReadMemory(xml, strlen(xml), "", NULL, 0);
if(doc == NULL){
if(foreground)
printf(" append_objects_from_xml xmlReadMemory returns with error.\n");
return -1;
}
ctx = xmlXPathNewContext(doc);
if(!noxmlns){
xmlXPathRegisterNs(ctx, (xmlChar *) "s3",
(xmlChar *) "http://s3.amazonaws.com/doc/2006-03-01/");
}
contents_xp = xmlXPathEvalExpression((xmlChar *)exp_contents.c_str(), ctx);
content_nodes = contents_xp->nodesetval;
int i;
for(i = 0; i < content_nodes->nodeNr; i++) {
ctx->node = content_nodes->nodeTab[i];
// object name
xmlXPathObjectPtr key = xmlXPathEvalExpression((xmlChar *)exp_Key.c_str(), ctx);
xmlNodeSetPtr key_nodes = key->nodesetval;
char *name = get_object_name(doc, key_nodes->nodeTab[0]->xmlChildrenNode, path);
if(!name){
if(foreground)
printf(" append_objects_from_xml name is something wrong. but continue.\n");
}else if((const char*)name != c_strErrorObjectName){
if((insert_object(name, head)) != 0){
if(foreground)
printf(" append_objects_from_xml insert_object returns with error.\n");
xmlXPathFreeObject(key);
xmlXPathFreeObject(contents_xp);
xmlXPathFreeContext(ctx);
xmlFreeDoc(doc);
Summary of Changes(1.62 -> 1.63) 1) Lifetime for the stats cache Added the new option "stat_cache_expire". This option which is specified by seconds means the lifetime for each stats cache entry. If this option is not specified, the stats cache is kept in s3fs process until the stats cache grown to maximum size. (default) If this option is specified, the stats cache entry is out from the memory when the entry expires time. 2) Enable file permission s3fs before 1.62 did not consider the file access permission. s3fs after this version can consider it. For access permission, the s3fs_getattr() function was divided into sub function which can check the file access permission. It is like access() function. And the function calling the s3fs_getattr() calls this new sub function instead of s3fs_getattr(). Last the s3fs_opendir() function which is called by FUSE was added for checking directory access permission when listing the files in directory. 3) UID/GUID When a file or a directory was created, the s3fs could not set the UID/GID as the user who executed a command. (Almost the UID/GID are root, because the s3fs run by root.) After this version, the s3fs set correct UID/GID as the user who executes the commond. 4) About the mtime If the object does not have "x-amz-meta-mtime" meta, the s3fs uses the "Last-Modified" header instead of it. But the s3fs had a bug in this code, and this version fixed this bug. When user modified the file, the s3fs did not update the mtime of the file. This version fixed this bug. In the get_local_fd() function, the local file's mtime was changed only when s3fs run with "use_cache" option. This version always updates the mtime whether the local cache file is used or not. And s3fs_flush ( ) function set the mtime of local cache file from S3 object mtime, but it was wrong . This version is that the s3fs_flush ( ) changes the mtime of S3 object from the local cache file or the tmpfile . The s3fs cuts some requests, because the s3fs can always check mtime whether the s3fs uses or does not use the local cache file. 5) A case of no "x-amz-meta-mode" If the object did not have "x-amz-meta-mtime" mete, the s3fs recognized the file as not regular file. After this version, the s3fs recognizes the file as regular file. 6) "." and ".." directory The s3fs_readdir() did not return "X" and "XX" directory name. After this version, the s3fs is changed that it returns "X" and "XX". Example, the result of "ls" lists "X" and "XX" directory. 7) Fixed a bug The insert_object() had a bug, and it is fixed. git-svn-id: http://s3fs.googlecode.com/svn/trunk@390 df820570-a93a-0410-bd06-b72b767a4274
2013-02-24 08:58:54 +00:00
free(name);
return -1;
}
Summary of Changes(1.62 -> 1.63) 1) Lifetime for the stats cache Added the new option "stat_cache_expire". This option which is specified by seconds means the lifetime for each stats cache entry. If this option is not specified, the stats cache is kept in s3fs process until the stats cache grown to maximum size. (default) If this option is specified, the stats cache entry is out from the memory when the entry expires time. 2) Enable file permission s3fs before 1.62 did not consider the file access permission. s3fs after this version can consider it. For access permission, the s3fs_getattr() function was divided into sub function which can check the file access permission. It is like access() function. And the function calling the s3fs_getattr() calls this new sub function instead of s3fs_getattr(). Last the s3fs_opendir() function which is called by FUSE was added for checking directory access permission when listing the files in directory. 3) UID/GUID When a file or a directory was created, the s3fs could not set the UID/GID as the user who executed a command. (Almost the UID/GID are root, because the s3fs run by root.) After this version, the s3fs set correct UID/GID as the user who executes the commond. 4) About the mtime If the object does not have "x-amz-meta-mtime" meta, the s3fs uses the "Last-Modified" header instead of it. But the s3fs had a bug in this code, and this version fixed this bug. When user modified the file, the s3fs did not update the mtime of the file. This version fixed this bug. In the get_local_fd() function, the local file's mtime was changed only when s3fs run with "use_cache" option. This version always updates the mtime whether the local cache file is used or not. And s3fs_flush ( ) function set the mtime of local cache file from S3 object mtime, but it was wrong . This version is that the s3fs_flush ( ) changes the mtime of S3 object from the local cache file or the tmpfile . The s3fs cuts some requests, because the s3fs can always check mtime whether the s3fs uses or does not use the local cache file. 5) A case of no "x-amz-meta-mode" If the object did not have "x-amz-meta-mtime" mete, the s3fs recognized the file as not regular file. After this version, the s3fs recognizes the file as regular file. 6) "." and ".." directory The s3fs_readdir() did not return "X" and "XX" directory name. After this version, the s3fs is changed that it returns "X" and "XX". Example, the result of "ls" lists "X" and "XX" directory. 7) Fixed a bug The insert_object() had a bug, and it is fixed. git-svn-id: http://s3fs.googlecode.com/svn/trunk@390 df820570-a93a-0410-bd06-b72b767a4274
2013-02-24 08:58:54 +00:00
free(name);
}else{
//if(foreground)
// printf("append_objects_from_xml name is file or subdir in dir. but continue.\n");
}
xmlXPathFreeObject(key);
}
xmlXPathFreeObject(contents_xp);
xmlXPathFreeContext(ctx);
xmlFreeDoc(doc);
return 0;
}
static const char *get_next_marker(const char *xml) {
xmlDocPtr doc;
xmlXPathContextPtr ctx;
xmlXPathObjectPtr marker_xp;
xmlNodeSetPtr nodes;
char *next_marker;
string exp_nextmarker = noxmlns ? "//NextMarker" : "//s3:NextMarker";
doc = xmlReadMemory(xml, strlen(xml), "", NULL, 0);
ctx = xmlXPathNewContext(doc);
if(!noxmlns){
xmlXPathRegisterNs(ctx, (xmlChar *) "s3",
(xmlChar *) "http://s3.amazonaws.com/doc/2006-03-01/");
}
marker_xp = xmlXPathEvalExpression((xmlChar *)exp_nextmarker.c_str(), ctx);
nodes = marker_xp->nodesetval;
if(nodes->nodeNr < 1)
return "";
next_marker = (char *) xmlNodeListGetString(doc, nodes->nodeTab[0]->xmlChildrenNode, 1);
xmlXPathFreeObject(marker_xp);
xmlXPathFreeContext(ctx);
xmlFreeDoc(doc);
return next_marker;
}
static bool is_truncated(const char *xml) {
if(strstr(xml, "<IsTruncated>true</IsTruncated>"))
return true;
return false;
}
Summary of Changes(1.62 -> 1.63) 1) Lifetime for the stats cache Added the new option "stat_cache_expire". This option which is specified by seconds means the lifetime for each stats cache entry. If this option is not specified, the stats cache is kept in s3fs process until the stats cache grown to maximum size. (default) If this option is specified, the stats cache entry is out from the memory when the entry expires time. 2) Enable file permission s3fs before 1.62 did not consider the file access permission. s3fs after this version can consider it. For access permission, the s3fs_getattr() function was divided into sub function which can check the file access permission. It is like access() function. And the function calling the s3fs_getattr() calls this new sub function instead of s3fs_getattr(). Last the s3fs_opendir() function which is called by FUSE was added for checking directory access permission when listing the files in directory. 3) UID/GUID When a file or a directory was created, the s3fs could not set the UID/GID as the user who executed a command. (Almost the UID/GID are root, because the s3fs run by root.) After this version, the s3fs set correct UID/GID as the user who executes the commond. 4) About the mtime If the object does not have "x-amz-meta-mtime" meta, the s3fs uses the "Last-Modified" header instead of it. But the s3fs had a bug in this code, and this version fixed this bug. When user modified the file, the s3fs did not update the mtime of the file. This version fixed this bug. In the get_local_fd() function, the local file's mtime was changed only when s3fs run with "use_cache" option. This version always updates the mtime whether the local cache file is used or not. And s3fs_flush ( ) function set the mtime of local cache file from S3 object mtime, but it was wrong . This version is that the s3fs_flush ( ) changes the mtime of S3 object from the local cache file or the tmpfile . The s3fs cuts some requests, because the s3fs can always check mtime whether the s3fs uses or does not use the local cache file. 5) A case of no "x-amz-meta-mode" If the object did not have "x-amz-meta-mtime" mete, the s3fs recognized the file as not regular file. After this version, the s3fs recognizes the file as regular file. 6) "." and ".." directory The s3fs_readdir() did not return "X" and "XX" directory name. After this version, the s3fs is changed that it returns "X" and "XX". Example, the result of "ls" lists "X" and "XX" directory. 7) Fixed a bug The insert_object() had a bug, and it is fixed. git-svn-id: http://s3fs.googlecode.com/svn/trunk@390 df820570-a93a-0410-bd06-b72b767a4274
2013-02-24 08:58:54 +00:00
// return: the pointer to object name on allocated memory.
// the pointer to "c_strErrorObjectName".(not allocated)
// NULL(a case of something error occured)
static char *get_object_name(xmlDocPtr doc, xmlNodePtr node, const char* path)
{
// Get full path
xmlChar* fullpath= xmlNodeListGetString(doc, node, 1);
if(!fullpath){
if(foreground)
printf(" get_object_name could not get object full path name..\n");
return NULL;
}
// Make dir path and filename
string strfullpath= (char*)fullpath;
string strdirpath = mydirname((char*)fullpath);
string strmybpath = mybasename((char*)fullpath);
const char* dirpath = strdirpath.c_str();
const char* mybname = strmybpath.c_str();
const char* basepath= (!path || '\0' == path[0] || '/' != path[0] ? path : &path[1]);
xmlFree(fullpath);
if(!mybname || '\0' == mybname[0]){
return NULL;
}
// check subdir & file in subdir
if(dirpath && 0 < strlen(dirpath)){
// case of "/"
if(0 == strcmp(mybname, "/") && 0 == strcmp(dirpath, "/")){
return (char*)c_strErrorObjectName;
}
// case of "."
if(0 == strcmp(mybname, ".") && 0 == strcmp(dirpath, ".")){
return (char*)c_strErrorObjectName;
}
// case of ".."
if(0 == strcmp(mybname, "..") && 0 == strcmp(dirpath, ".")){
return (char*)c_strErrorObjectName;
}
// case of "name"
if(0 == strcmp(dirpath, ".")){
// OK
Summary of Changes(1.62 -> 1.63) 1) Lifetime for the stats cache Added the new option "stat_cache_expire". This option which is specified by seconds means the lifetime for each stats cache entry. If this option is not specified, the stats cache is kept in s3fs process until the stats cache grown to maximum size. (default) If this option is specified, the stats cache entry is out from the memory when the entry expires time. 2) Enable file permission s3fs before 1.62 did not consider the file access permission. s3fs after this version can consider it. For access permission, the s3fs_getattr() function was divided into sub function which can check the file access permission. It is like access() function. And the function calling the s3fs_getattr() calls this new sub function instead of s3fs_getattr(). Last the s3fs_opendir() function which is called by FUSE was added for checking directory access permission when listing the files in directory. 3) UID/GUID When a file or a directory was created, the s3fs could not set the UID/GID as the user who executed a command. (Almost the UID/GID are root, because the s3fs run by root.) After this version, the s3fs set correct UID/GID as the user who executes the commond. 4) About the mtime If the object does not have "x-amz-meta-mtime" meta, the s3fs uses the "Last-Modified" header instead of it. But the s3fs had a bug in this code, and this version fixed this bug. When user modified the file, the s3fs did not update the mtime of the file. This version fixed this bug. In the get_local_fd() function, the local file's mtime was changed only when s3fs run with "use_cache" option. This version always updates the mtime whether the local cache file is used or not. And s3fs_flush ( ) function set the mtime of local cache file from S3 object mtime, but it was wrong . This version is that the s3fs_flush ( ) changes the mtime of S3 object from the local cache file or the tmpfile . The s3fs cuts some requests, because the s3fs can always check mtime whether the s3fs uses or does not use the local cache file. 5) A case of no "x-amz-meta-mode" If the object did not have "x-amz-meta-mtime" mete, the s3fs recognized the file as not regular file. After this version, the s3fs recognizes the file as regular file. 6) "." and ".." directory The s3fs_readdir() did not return "X" and "XX" directory name. After this version, the s3fs is changed that it returns "X" and "XX". Example, the result of "ls" lists "X" and "XX" directory. 7) Fixed a bug The insert_object() had a bug, and it is fixed. git-svn-id: http://s3fs.googlecode.com/svn/trunk@390 df820570-a93a-0410-bd06-b72b767a4274
2013-02-24 08:58:54 +00:00
return strdup(mybname);
}else{
if(0 == strcmp(dirpath, basepath)){
// OK
Summary of Changes(1.62 -> 1.63) 1) Lifetime for the stats cache Added the new option "stat_cache_expire". This option which is specified by seconds means the lifetime for each stats cache entry. If this option is not specified, the stats cache is kept in s3fs process until the stats cache grown to maximum size. (default) If this option is specified, the stats cache entry is out from the memory when the entry expires time. 2) Enable file permission s3fs before 1.62 did not consider the file access permission. s3fs after this version can consider it. For access permission, the s3fs_getattr() function was divided into sub function which can check the file access permission. It is like access() function. And the function calling the s3fs_getattr() calls this new sub function instead of s3fs_getattr(). Last the s3fs_opendir() function which is called by FUSE was added for checking directory access permission when listing the files in directory. 3) UID/GUID When a file or a directory was created, the s3fs could not set the UID/GID as the user who executed a command. (Almost the UID/GID are root, because the s3fs run by root.) After this version, the s3fs set correct UID/GID as the user who executes the commond. 4) About the mtime If the object does not have "x-amz-meta-mtime" meta, the s3fs uses the "Last-Modified" header instead of it. But the s3fs had a bug in this code, and this version fixed this bug. When user modified the file, the s3fs did not update the mtime of the file. This version fixed this bug. In the get_local_fd() function, the local file's mtime was changed only when s3fs run with "use_cache" option. This version always updates the mtime whether the local cache file is used or not. And s3fs_flush ( ) function set the mtime of local cache file from S3 object mtime, but it was wrong . This version is that the s3fs_flush ( ) changes the mtime of S3 object from the local cache file or the tmpfile . The s3fs cuts some requests, because the s3fs can always check mtime whether the s3fs uses or does not use the local cache file. 5) A case of no "x-amz-meta-mode" If the object did not have "x-amz-meta-mtime" mete, the s3fs recognized the file as not regular file. After this version, the s3fs recognizes the file as regular file. 6) "." and ".." directory The s3fs_readdir() did not return "X" and "XX" directory name. After this version, the s3fs is changed that it returns "X" and "XX". Example, the result of "ls" lists "X" and "XX" directory. 7) Fixed a bug The insert_object() had a bug, and it is fixed. git-svn-id: http://s3fs.googlecode.com/svn/trunk@390 df820570-a93a-0410-bd06-b72b767a4274
2013-02-24 08:58:54 +00:00
return strdup(mybname);
}
}
}
// case of something wrong
return (char*)c_strErrorObjectName;
}
static int remote_mountpath_exists(const char *path) {
struct stat stbuf;
if(foreground)
printf("remote_mountpath_exists [path=%s]\n", path);
// getattr will prefix the path with the remote mountpoint
Summary of Changes(1.62 -> 1.63) 1) Lifetime for the stats cache Added the new option "stat_cache_expire". This option which is specified by seconds means the lifetime for each stats cache entry. If this option is not specified, the stats cache is kept in s3fs process until the stats cache grown to maximum size. (default) If this option is specified, the stats cache entry is out from the memory when the entry expires time. 2) Enable file permission s3fs before 1.62 did not consider the file access permission. s3fs after this version can consider it. For access permission, the s3fs_getattr() function was divided into sub function which can check the file access permission. It is like access() function. And the function calling the s3fs_getattr() calls this new sub function instead of s3fs_getattr(). Last the s3fs_opendir() function which is called by FUSE was added for checking directory access permission when listing the files in directory. 3) UID/GUID When a file or a directory was created, the s3fs could not set the UID/GID as the user who executed a command. (Almost the UID/GID are root, because the s3fs run by root.) After this version, the s3fs set correct UID/GID as the user who executes the commond. 4) About the mtime If the object does not have "x-amz-meta-mtime" meta, the s3fs uses the "Last-Modified" header instead of it. But the s3fs had a bug in this code, and this version fixed this bug. When user modified the file, the s3fs did not update the mtime of the file. This version fixed this bug. In the get_local_fd() function, the local file's mtime was changed only when s3fs run with "use_cache" option. This version always updates the mtime whether the local cache file is used or not. And s3fs_flush ( ) function set the mtime of local cache file from S3 object mtime, but it was wrong . This version is that the s3fs_flush ( ) changes the mtime of S3 object from the local cache file or the tmpfile . The s3fs cuts some requests, because the s3fs can always check mtime whether the s3fs uses or does not use the local cache file. 5) A case of no "x-amz-meta-mode" If the object did not have "x-amz-meta-mtime" mete, the s3fs recognized the file as not regular file. After this version, the s3fs recognizes the file as regular file. 6) "." and ".." directory The s3fs_readdir() did not return "X" and "XX" directory name. After this version, the s3fs is changed that it returns "X" and "XX". Example, the result of "ls" lists "X" and "XX" directory. 7) Fixed a bug The insert_object() had a bug, and it is fixed. git-svn-id: http://s3fs.googlecode.com/svn/trunk@390 df820570-a93a-0410-bd06-b72b767a4274
2013-02-24 08:58:54 +00:00
get_object_attribute("", &stbuf);
if(!S_ISDIR(stbuf.st_mode))
return -1;
return 0;
}
/**
* OpenSSL locking function.
*
* @param mode lock mode
* @param n lock number
* @param file source file name
* @param line source file line number
* @return none
*/
static void locking_function(int mode, int n, const char *file, int line) {
if(mode & CRYPTO_LOCK)
pthread_mutex_lock(&mutex_buf[n]);
else
pthread_mutex_unlock(&mutex_buf[n]);
}
// OpenSSL uniq thread id function.
static unsigned long id_function(void) {
return((unsigned long) pthread_self());
}
static void* s3fs_init(struct fuse_conn_info *conn) {
syslog(LOG_INFO, "init $Rev$");
if(foreground)
cout << "s3fs_init" << endl;
// openssl
mutex_buf = static_cast<pthread_mutex_t*>(malloc(CRYPTO_num_locks() * sizeof(pthread_mutex_t)));
for (int i = 0; i < CRYPTO_num_locks(); i++)
pthread_mutex_init(&mutex_buf[i], NULL);
CRYPTO_set_locking_callback(locking_function);
CRYPTO_set_id_callback(id_function);
curl_global_init(CURL_GLOBAL_ALL);
pthread_mutex_init(&curl_handles_lock, NULL);
pthread_mutex_init(&s3fs_descriptors_lock, NULL);
pthread_mutex_init(&stat_cache_lock, NULL);
string line;
ifstream MT("/etc/mime.types");
if (MT.good()) {
while (getline(MT, line)) {
if(line[0]=='#')
continue;
if(line.size() == 0)
continue;
stringstream tmp(line);
string mimeType;
tmp >> mimeType;
while (tmp) {
string ext;
tmp >> ext;
if (ext.size() == 0)
continue;
mimeTypes[ext] = mimeType;
}
}
}
// Investigate system capabilities
if((unsigned int)conn->capable & FUSE_CAP_ATOMIC_O_TRUNC)
conn->want |= FUSE_CAP_ATOMIC_O_TRUNC;
return 0;
}
static void s3fs_destroy(void*) {
if(debug)
syslog(LOG_DEBUG, "destroy");
if(foreground)
cout << "s3fs_destroy" << endl;
// openssl
CRYPTO_set_id_callback(NULL);
CRYPTO_set_locking_callback(NULL);
for(int i = 0; i < CRYPTO_num_locks(); i++)
pthread_mutex_destroy(&mutex_buf[i]);
free(mutex_buf);
mutex_buf = NULL;
curl_global_cleanup();
pthread_mutex_destroy(&curl_handles_lock);
pthread_mutex_destroy(&s3fs_descriptors_lock);
pthread_mutex_destroy(&stat_cache_lock);
}
static int s3fs_access(const char *path, int mask) {
if(foreground)
Summary of Changes(1.62 -> 1.63) 1) Lifetime for the stats cache Added the new option "stat_cache_expire". This option which is specified by seconds means the lifetime for each stats cache entry. If this option is not specified, the stats cache is kept in s3fs process until the stats cache grown to maximum size. (default) If this option is specified, the stats cache entry is out from the memory when the entry expires time. 2) Enable file permission s3fs before 1.62 did not consider the file access permission. s3fs after this version can consider it. For access permission, the s3fs_getattr() function was divided into sub function which can check the file access permission. It is like access() function. And the function calling the s3fs_getattr() calls this new sub function instead of s3fs_getattr(). Last the s3fs_opendir() function which is called by FUSE was added for checking directory access permission when listing the files in directory. 3) UID/GUID When a file or a directory was created, the s3fs could not set the UID/GID as the user who executed a command. (Almost the UID/GID are root, because the s3fs run by root.) After this version, the s3fs set correct UID/GID as the user who executes the commond. 4) About the mtime If the object does not have "x-amz-meta-mtime" meta, the s3fs uses the "Last-Modified" header instead of it. But the s3fs had a bug in this code, and this version fixed this bug. When user modified the file, the s3fs did not update the mtime of the file. This version fixed this bug. In the get_local_fd() function, the local file's mtime was changed only when s3fs run with "use_cache" option. This version always updates the mtime whether the local cache file is used or not. And s3fs_flush ( ) function set the mtime of local cache file from S3 object mtime, but it was wrong . This version is that the s3fs_flush ( ) changes the mtime of S3 object from the local cache file or the tmpfile . The s3fs cuts some requests, because the s3fs can always check mtime whether the s3fs uses or does not use the local cache file. 5) A case of no "x-amz-meta-mode" If the object did not have "x-amz-meta-mtime" mete, the s3fs recognized the file as not regular file. After this version, the s3fs recognizes the file as regular file. 6) "." and ".." directory The s3fs_readdir() did not return "X" and "XX" directory name. After this version, the s3fs is changed that it returns "X" and "XX". Example, the result of "ls" lists "X" and "XX" directory. 7) Fixed a bug The insert_object() had a bug, and it is fixed. git-svn-id: http://s3fs.googlecode.com/svn/trunk@390 df820570-a93a-0410-bd06-b72b767a4274
2013-02-24 08:58:54 +00:00
printf("s3fs_access[path=%s][mask=%s%s%s%s]\n", path,
((mask & R_OK) == R_OK) ? "R_OK " : "",
((mask & W_OK) == W_OK) ? "W_OK " : "",
((mask & X_OK) == X_OK) ? "X_OK " : "",
(mask == F_OK) ? "F_OK" : "");
Summary of Changes(1.62 -> 1.63) 1) Lifetime for the stats cache Added the new option "stat_cache_expire". This option which is specified by seconds means the lifetime for each stats cache entry. If this option is not specified, the stats cache is kept in s3fs process until the stats cache grown to maximum size. (default) If this option is specified, the stats cache entry is out from the memory when the entry expires time. 2) Enable file permission s3fs before 1.62 did not consider the file access permission. s3fs after this version can consider it. For access permission, the s3fs_getattr() function was divided into sub function which can check the file access permission. It is like access() function. And the function calling the s3fs_getattr() calls this new sub function instead of s3fs_getattr(). Last the s3fs_opendir() function which is called by FUSE was added for checking directory access permission when listing the files in directory. 3) UID/GUID When a file or a directory was created, the s3fs could not set the UID/GID as the user who executed a command. (Almost the UID/GID are root, because the s3fs run by root.) After this version, the s3fs set correct UID/GID as the user who executes the commond. 4) About the mtime If the object does not have "x-amz-meta-mtime" meta, the s3fs uses the "Last-Modified" header instead of it. But the s3fs had a bug in this code, and this version fixed this bug. When user modified the file, the s3fs did not update the mtime of the file. This version fixed this bug. In the get_local_fd() function, the local file's mtime was changed only when s3fs run with "use_cache" option. This version always updates the mtime whether the local cache file is used or not. And s3fs_flush ( ) function set the mtime of local cache file from S3 object mtime, but it was wrong . This version is that the s3fs_flush ( ) changes the mtime of S3 object from the local cache file or the tmpfile . The s3fs cuts some requests, because the s3fs can always check mtime whether the s3fs uses or does not use the local cache file. 5) A case of no "x-amz-meta-mode" If the object did not have "x-amz-meta-mtime" mete, the s3fs recognized the file as not regular file. After this version, the s3fs recognizes the file as regular file. 6) "." and ".." directory The s3fs_readdir() did not return "X" and "XX" directory name. After this version, the s3fs is changed that it returns "X" and "XX". Example, the result of "ls" lists "X" and "XX" directory. 7) Fixed a bug The insert_object() had a bug, and it is fixed. git-svn-id: http://s3fs.googlecode.com/svn/trunk@390 df820570-a93a-0410-bd06-b72b767a4274
2013-02-24 08:58:54 +00:00
return check_object_access(path, mask, NULL);
}
static int s3fs_utimens(const char *path, const struct timespec ts[2]) {
int result;
char *s3_realpath;
headers_t meta;
if(foreground)
printf("s3fs_utimens[path=%s][mtime=%zd]\n", path, ts[1].tv_sec);
Summary of Changes(1.62 -> 1.63) 1) Lifetime for the stats cache Added the new option "stat_cache_expire". This option which is specified by seconds means the lifetime for each stats cache entry. If this option is not specified, the stats cache is kept in s3fs process until the stats cache grown to maximum size. (default) If this option is specified, the stats cache entry is out from the memory when the entry expires time. 2) Enable file permission s3fs before 1.62 did not consider the file access permission. s3fs after this version can consider it. For access permission, the s3fs_getattr() function was divided into sub function which can check the file access permission. It is like access() function. And the function calling the s3fs_getattr() calls this new sub function instead of s3fs_getattr(). Last the s3fs_opendir() function which is called by FUSE was added for checking directory access permission when listing the files in directory. 3) UID/GUID When a file or a directory was created, the s3fs could not set the UID/GID as the user who executed a command. (Almost the UID/GID are root, because the s3fs run by root.) After this version, the s3fs set correct UID/GID as the user who executes the commond. 4) About the mtime If the object does not have "x-amz-meta-mtime" meta, the s3fs uses the "Last-Modified" header instead of it. But the s3fs had a bug in this code, and this version fixed this bug. When user modified the file, the s3fs did not update the mtime of the file. This version fixed this bug. In the get_local_fd() function, the local file's mtime was changed only when s3fs run with "use_cache" option. This version always updates the mtime whether the local cache file is used or not. And s3fs_flush ( ) function set the mtime of local cache file from S3 object mtime, but it was wrong . This version is that the s3fs_flush ( ) changes the mtime of S3 object from the local cache file or the tmpfile . The s3fs cuts some requests, because the s3fs can always check mtime whether the s3fs uses or does not use the local cache file. 5) A case of no "x-amz-meta-mode" If the object did not have "x-amz-meta-mtime" mete, the s3fs recognized the file as not regular file. After this version, the s3fs recognizes the file as regular file. 6) "." and ".." directory The s3fs_readdir() did not return "X" and "XX" directory name. After this version, the s3fs is changed that it returns "X" and "XX". Example, the result of "ls" lists "X" and "XX" directory. 7) Fixed a bug The insert_object() had a bug, and it is fixed. git-svn-id: http://s3fs.googlecode.com/svn/trunk@390 df820570-a93a-0410-bd06-b72b767a4274
2013-02-24 08:58:54 +00:00
if(0 != (result = check_parent_object_access(path, W_OK | X_OK))){
return result;
}
if(0 != (result = check_object_access(path, W_OK, NULL))){
return result;
}
s3_realpath = get_realpath(path);
if((result = curl_get_headers(s3_realpath, meta) != 0)) {
free(s3_realpath);
return result;
}
meta["x-amz-meta-mtime"] = str(ts[1].tv_sec);
meta["x-amz-copy-source"] = urlEncode("/" + bucket + s3_realpath);
meta["x-amz-metadata-directive"] = "REPLACE";
free(s3_realpath);
return put_headers(path, meta);
}
static int s3fs_utimens_nocopy(const char *path, const struct timespec ts[2]) {
int result;
char *s3_realpath;
headers_t meta;
int fd;
int isclose = 1;
struct timeval tv[2];
if(foreground)
cout << "s3fs_utimens_nocopy [path=" << path << "][mtime=" << str(ts[1].tv_sec) << "]" << endl;
Summary of Changes(1.62 -> 1.63) 1) Lifetime for the stats cache Added the new option "stat_cache_expire". This option which is specified by seconds means the lifetime for each stats cache entry. If this option is not specified, the stats cache is kept in s3fs process until the stats cache grown to maximum size. (default) If this option is specified, the stats cache entry is out from the memory when the entry expires time. 2) Enable file permission s3fs before 1.62 did not consider the file access permission. s3fs after this version can consider it. For access permission, the s3fs_getattr() function was divided into sub function which can check the file access permission. It is like access() function. And the function calling the s3fs_getattr() calls this new sub function instead of s3fs_getattr(). Last the s3fs_opendir() function which is called by FUSE was added for checking directory access permission when listing the files in directory. 3) UID/GUID When a file or a directory was created, the s3fs could not set the UID/GID as the user who executed a command. (Almost the UID/GID are root, because the s3fs run by root.) After this version, the s3fs set correct UID/GID as the user who executes the commond. 4) About the mtime If the object does not have "x-amz-meta-mtime" meta, the s3fs uses the "Last-Modified" header instead of it. But the s3fs had a bug in this code, and this version fixed this bug. When user modified the file, the s3fs did not update the mtime of the file. This version fixed this bug. In the get_local_fd() function, the local file's mtime was changed only when s3fs run with "use_cache" option. This version always updates the mtime whether the local cache file is used or not. And s3fs_flush ( ) function set the mtime of local cache file from S3 object mtime, but it was wrong . This version is that the s3fs_flush ( ) changes the mtime of S3 object from the local cache file or the tmpfile . The s3fs cuts some requests, because the s3fs can always check mtime whether the s3fs uses or does not use the local cache file. 5) A case of no "x-amz-meta-mode" If the object did not have "x-amz-meta-mtime" mete, the s3fs recognized the file as not regular file. After this version, the s3fs recognizes the file as regular file. 6) "." and ".." directory The s3fs_readdir() did not return "X" and "XX" directory name. After this version, the s3fs is changed that it returns "X" and "XX". Example, the result of "ls" lists "X" and "XX" directory. 7) Fixed a bug The insert_object() had a bug, and it is fixed. git-svn-id: http://s3fs.googlecode.com/svn/trunk@390 df820570-a93a-0410-bd06-b72b767a4274
2013-02-24 08:58:54 +00:00
if(0 != (result = check_parent_object_access(path, W_OK | X_OK))){
return result;
}
if(0 != (result = check_object_access(path, W_OK, NULL))){
return result;
}
// Downloading
if(0 > (fd = get_opened_fd(path))){
if(0 > (fd = get_local_fd(path))){
if(foreground) {
printf(" s3fs_utimens_nocopy line %d: get_local_fd result: %d\n", __LINE__, fd);
}
syslog(LOG_ERR, "s3fs_utimens_nocopy line %d: get_local_fd result: %d", __LINE__, fd);
return -EIO;
}
}else{
isclose = 0;
}
// Get attributes
s3_realpath = get_realpath(path);
result = curl_get_headers(s3_realpath, meta);
free(s3_realpath);
if(result != 0){
if(isclose){
close(fd);
}
return result;
}
// Change date
meta["x-amz-meta-mtime"] = str(ts[1].tv_sec);
// Change local file date
TIMESPEC_TO_TIMEVAL(&tv[0], &ts[0]);
TIMESPEC_TO_TIMEVAL(&tv[1], &ts[1]);
if(-1 == futimes(fd, tv)){
if(isclose){
close(fd);
}
if(foreground) {
printf(" s3fs_utimens_nocopy line %d: futimes(fd=%d, ...) is error(%d)\n", __LINE__, fd, errno);
}
syslog(LOG_ERR, "s3fs_utimens_nocopy line %d: futimes(fd=%d, ...) is error(%d)", __LINE__, fd, errno);
return -errno;
}
// Re-uploading
if(0 != (result = put_local_fd(path, meta, fd))){
if(foreground) {
printf(" s3fs_utimens_nocopy line %d: put_local_fd result: %d\n", __LINE__, result);
}
}
if(isclose){
close(fd);
}
delete_stat_cache_entry(path);
return result;
}
///////////////////////////////////////////////////////////
// List Multipart Uploads for bucket
///////////////////////////////////////////////////////////
static int list_multipart_uploads(void) {
CURL *curl = NULL;
string resource;
string url;
struct BodyStruct body;
int result;
string date;
string raw_date;
string auth;
string my_url;
struct curl_slist *slist=NULL;
// Initialization of variables
body.text = (char *)malloc(1);
body.size = 0;
printf("List Multipart Uploads\n");
resource = urlEncode(service_path + bucket + "/");
resource.append("?uploads");
url = host + resource;
my_url = prepare_url(url.c_str());
curl = create_curl_handle();
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&body);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
date.assign("Date: ");
raw_date = get_date();
date.append(raw_date);
slist = curl_slist_append(slist, date.c_str());
slist = curl_slist_append(slist, "Accept:");
if (public_bucket.substr(0,1) != "1") {
auth.assign("Authorization: AWS ");
auth.append(AWSAccessKeyId);
auth.append(":");
auth.append(calc_signature("GET", "", raw_date, slist, resource));
slist = curl_slist_append(slist, auth.c_str());
}
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist);
curl_easy_setopt(curl, CURLOPT_URL, my_url.c_str());
result = my_curl_easy_perform(curl, &body);
curl_slist_free_all(slist);
destroy_curl_handle(curl);
if(result != 0) {
if(body.text)
free(body.text);
return result;
}
if(body.size > 0)
printf("body.text:\n%s\n", body.text);
if(body.text)
free(body.text);
return 0;
}
static void s3fs_check_service(void) {
CURL *curl = NULL;
int result = CURLE_OK;
CURLcode responseCode;
if(foreground)
printf("s3fs_check_service\n");
struct BodyStruct body;
body.text = (char *) malloc(1);
body.size = 0;
string resource = urlEncode(service_path + bucket);
string url = host + resource;
auto_curl_slist headers;
string date = get_date();
headers.append("Date: " + date);
if (public_bucket.substr(0,1) != "1") {
headers.append("Authorization: AWS " + AWSAccessKeyId + ":" +
calc_signature("GET", "", date, headers.get(), resource));
} else {
if(body.text) free(body.text);
return;
}
curl = create_curl_handle();
curl_easy_setopt(curl, CURLOPT_FAILONERROR, true);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&body);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers.get());
result = my_curl_easy_perform(curl);
// connect either successful or too many timeouts
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &responseCode);
if(responseCode == 403) {
destroy_curl_handle(curl);
if(body.text)
free(body.text);
body.text = NULL;
fprintf(stderr, "%s: invalid credentials\n", program_name.c_str());
exit(EXIT_FAILURE);
}
if(responseCode == 404) {
destroy_curl_handle(curl);
if(body.text)
free(body.text);
body.text = NULL;
fprintf(stderr, "%s: bucket not found\n", program_name.c_str());
exit(EXIT_FAILURE);
}
// unable to connect
if(responseCode == CURLE_OPERATION_TIMEDOUT) {
destroy_curl_handle(curl);
if(body.text) free(body.text);
body.text = NULL;
return;
}
if(responseCode != 200 && responseCode != 301) {
if(debug) syslog(LOG_DEBUG, "responseCode: %i\n", (int)responseCode);
if(body.text) free(body.text);
destroy_curl_handle(curl);
fprintf(stderr, "%s: unable to connect\n", program_name.c_str());
exit(EXIT_FAILURE);
}
// make sure remote mountpath exists and is a directory
if(mount_prefix.size() > 0) {
if(remote_mountpath_exists(mount_prefix.c_str()) != 0) {
fprintf(stderr, "%s: remote mountpath %s not found.\n",
program_name.c_str(), mount_prefix.c_str());
destroy_curl_handle(curl);
if(body.text)
free(body.text);
body.text = NULL;
exit(EXIT_FAILURE);
}
}
// success
service_validated = true;
if(body.text) free(body.text);
body.text = NULL;
destroy_curl_handle(curl);
return;
}
static bool check_for_aws_format (void) {
size_t first_pos = string::npos;
string line;
bool got_access_key_id_line = 0;
bool got_secret_key_line = 0;
string str1 ("AWSAccessKeyId=");
string str2 ("AWSSecretKey=");
size_t found;
ifstream PF(passwd_file.c_str());
if (PF.good()) {
while (getline(PF, line)) {
if(line[0]=='#')
continue;
if(line.size() == 0)
continue;
first_pos = line.find_first_of(" \t");
if (first_pos != string::npos) {
printf ("%s: invalid line in passwd file, found whitespace character\n",
program_name.c_str());
exit(EXIT_FAILURE);
}
first_pos = line.find_first_of("[");
if (first_pos != string::npos && first_pos == 0) {
printf ("%s: invalid line in passwd file, found a bracket \"[\" character\n",
program_name.c_str());
exit(EXIT_FAILURE);
}
found = line.find(str1);
if (found != string::npos) {
first_pos = line.find_first_of("=");
AWSAccessKeyId = line.substr(first_pos + 1, string::npos);
got_access_key_id_line = 1;
continue;
}
found = line.find(str2);
if (found != string::npos) {
first_pos = line.find_first_of("=");
AWSSecretAccessKey = line.substr(first_pos + 1, string::npos);
got_secret_key_line = 1;
continue;
}
}
}
if(got_access_key_id_line && got_secret_key_line)
return 1;
else
return 0;
}
//////////////////////////////////////////////////////////////////
// check_passwd_file_perms
//
// expect that global passwd_file variable contains
// a non-empty value and is readable by the current user
//
// Check for too permissive access to the file
// help save users from themselves via a security hole
//
// only two options: return or error out
//////////////////////////////////////////////////////////////////
static void check_passwd_file_perms (void) {
struct stat info;
// let's get the file info
if (stat(passwd_file.c_str(), &info) != 0) {
fprintf (stderr, "%s: unexpected error from stat(%s, ) \n",
program_name.c_str(), passwd_file.c_str());
exit(EXIT_FAILURE);
}
// return error if any file has others permissions
if ((info.st_mode & S_IROTH) ||
(info.st_mode & S_IWOTH) ||
(info.st_mode & S_IXOTH)) {
fprintf (stderr, "%s: credentials file %s should not have others permissions\n",
program_name.c_str(), passwd_file.c_str());
exit(EXIT_FAILURE);
}
// Any local file should not have any group permissions
// /etc/passwd-s3fs can have group permissions
if (passwd_file != "/etc/passwd-s3fs") {
if ((info.st_mode & S_IRGRP) ||
(info.st_mode & S_IWGRP) ||
(info.st_mode & S_IXGRP)) {
fprintf (stderr, "%s: credentials file %s should not have group permissions\n",
program_name.c_str(), passwd_file.c_str());
exit(EXIT_FAILURE);
}
}
return;
}
//////////////////////////////////////////////////////////////////
// read_passwd_file
//
// Support for per bucket credentials
//
// Format for the credentials file:
// [bucket:]AccessKeyId:SecretAccessKey
//
// Lines beginning with # are considered comments
// and ignored, as are empty lines
//
// Uncommented lines without the ":" character are flagged as
// an error, so are lines with spaces or tabs
//
// only one default key pair is allowed, but not required
//////////////////////////////////////////////////////////////////
static void read_passwd_file (void) {
string line;
string field1, field2, field3;
size_t first_pos = string::npos;
size_t last_pos = string::npos;
bool default_found = 0;
bool aws_format;
// if you got here, the password file
// exists and is readable by the
// current user, check for permissions
check_passwd_file_perms();
aws_format = check_for_aws_format();
if (aws_format)
return;
ifstream PF(passwd_file.c_str());
if (PF.good()) {
while (getline(PF, line)) {
if (line[0]=='#') {
continue;
}
if (line.size() == 0) {
continue;
}
first_pos = line.find_first_of(" \t");
if (first_pos != string::npos) {
printf ("%s: invalid line in passwd file, found whitespace character\n",
program_name.c_str());
exit(EXIT_FAILURE);
}
first_pos = line.find_first_of("[");
if (first_pos != string::npos && first_pos == 0) {
printf ("%s: invalid line in passwd file, found a bracket \"[\" character\n",
program_name.c_str());
exit(EXIT_FAILURE);
}
first_pos = line.find_first_of(":");
if (first_pos == string::npos) {
printf ("%s: invalid line in passwd file, no \":\" separator found\n",
program_name.c_str());
exit(EXIT_FAILURE);
}
last_pos = line.find_last_of(":");
if (first_pos != last_pos) {
// bucket specified
field1 = line.substr(0,first_pos);
field2 = line.substr(first_pos + 1, last_pos - first_pos - 1);
field3 = line.substr(last_pos + 1, string::npos);
} else {
// no bucket specified - original style - found default key
if (default_found == 1) {
printf ("%s: more than one default key pair found in passwd file\n",
program_name.c_str());
exit(EXIT_FAILURE);
}
default_found = 1;
field1.assign("");
field2 = line.substr(0,first_pos);
field3 = line.substr(first_pos + 1, string::npos);
AWSAccessKeyId = field2;
AWSSecretAccessKey = field3;
}
// does the bucket we are mounting match this passwd file entry?
// if so, use that key pair, otherwise use the default key, if found,
// will be used
if (field1.size() != 0 && field1 == bucket) {
AWSAccessKeyId = field2;
AWSSecretAccessKey = field3;
break;
}
}
}
return;
}
/////////////////////////////////////////////////////////////
// get_access_keys
//
// called only when were are not mounting a
// public bucket
//
// Here is the order precedence for getting the
// keys:
//
// 1 - from the command line (security risk)
// 2 - from a password file specified on the command line
// 3 - from environment variables
// 4 - from the users ~/.passwd-s3fs
// 5 - from /etc/passwd-s3fs
/////////////////////////////////////////////////////////////
static void get_access_keys (void) {
// should be redundant
if (public_bucket.substr(0,1) == "1") {
return;
}
// 1 - keys specified on the command line
if (AWSAccessKeyId.size() > 0 && AWSSecretAccessKey.size() > 0) {
return;
}
// 2 - was specified on the command line
if (passwd_file.size() > 0) {
ifstream PF(passwd_file.c_str());
if (PF.good()) {
PF.close();
read_passwd_file();
return;
} else {
fprintf(stderr, "%s: specified passwd_file is not readable\n",
program_name.c_str());
exit(EXIT_FAILURE);
}
}
// 3 - environment variables
char * AWSACCESSKEYID;
char * AWSSECRETACCESSKEY;
AWSACCESSKEYID = getenv("AWSACCESSKEYID");
AWSSECRETACCESSKEY = getenv("AWSSECRETACCESSKEY");
if (AWSACCESSKEYID != NULL || AWSSECRETACCESSKEY != NULL) {
if ((AWSACCESSKEYID == NULL && AWSSECRETACCESSKEY != NULL) ||
(AWSACCESSKEYID != NULL && AWSSECRETACCESSKEY == NULL) ){
fprintf(stderr, "%s: if environment variable AWSACCESSKEYID is set then AWSSECRETACCESSKEY must be set too\n",
program_name.c_str());
exit(EXIT_FAILURE);
}
AWSAccessKeyId.assign(AWSACCESSKEYID);
AWSSecretAccessKey.assign(AWSSECRETACCESSKEY);
return;
}
// 3a - from the AWS_CREDENTIAL_FILE environment variable
char * AWS_CREDENTIAL_FILE;
AWS_CREDENTIAL_FILE = getenv("AWS_CREDENTIAL_FILE");
if (AWS_CREDENTIAL_FILE != NULL) {
passwd_file.assign(AWS_CREDENTIAL_FILE);
if (passwd_file.size() > 0) {
ifstream PF(passwd_file.c_str());
if (PF.good()) {
PF.close();
read_passwd_file();
return;
} else {
fprintf(stderr, "%s: AWS_CREDENTIAL_FILE: \"%s\" is not readable\n",
program_name.c_str(), passwd_file.c_str());
exit(EXIT_FAILURE);
}
}
}
// 4 - from the default location in the users home directory
char * HOME;
HOME = getenv ("HOME");
if (HOME != NULL) {
passwd_file.assign(HOME);
passwd_file.append("/.passwd-s3fs");
ifstream PF(passwd_file.c_str());
if (PF.good()) {
PF.close();
read_passwd_file();
// It is possible that the user's file was there but
// contained no key pairs i.e. commented out
// in that case, go look in the final location
if (AWSAccessKeyId.size() > 0 && AWSSecretAccessKey.size() > 0) {
return;
}
}
}
// 5 - from the system default location
passwd_file.assign("/etc/passwd-s3fs");
ifstream PF(passwd_file.c_str());
if (PF.good()) {
PF.close();
read_passwd_file();
return;
}
fprintf(stderr, "%s: could not determine how to establish security credentials\n",
program_name.c_str());
exit(EXIT_FAILURE);
}
static void show_usage (void) {
printf("Usage: %s BUCKET:[PATH] MOUNTPOINT [OPTION]...\n",
program_name.c_str());
}
static void show_help (void) {
show_usage();
printf(
"\n"
"Mount an Amazon S3 bucket as a file system.\n"
"\n"
" General forms for s3fs and FUSE/mount options:\n"
" -o opt[,opt...]\n"
" -o opt [-o opt] ...\n"
"\n"
"s3fs Options:\n"
"\n"
" Most s3fs options are given in the form where \"opt\" is:\n"
"\n"
" <option_name>=<option_value>\n"
"\n"
" default_acl (default=\"private\")\n"
" - the default canned acl to apply to all written s3 objects\n"
" see http://aws.amazon.com/documentation/s3/ for the \n"
" full list of canned acls\n"
"\n"
" retries (default=\"2\")\n"
" - number of times to retry a failed s3 transaction\n"
"\n"
" use_cache (default=\"\" which means disabled)\n"
" - local folder to use for local file cache\n"
"\n"
" use_rrs (default=\"\" which means diabled)\n"
" - use Amazon's Reduced Redundancy Storage when set to 1\n"
"\n"
" public_bucket (default=\"\" which means disabled)\n"
" - anonymously mount a public bucket when set to 1\n"
"\n"
" passwd_file (default=\"\")\n"
" - specify which s3fs password file to use\n"
"\n"
" connect_timeout (default=\"10\" seconds)\n"
" - time to wait for connection before giving up\n"
"\n"
" readwrite_timeout (default=\"30\" seconds)\n"
" - time to wait between read/write activity before giving up\n"
"\n"
" max_stat_cache_size (default=\"10000\" entries (about 4MB))\n"
" - maximum number of entries in the stat cache\n"
"\n"
Summary of Changes(1.62 -> 1.63) 1) Lifetime for the stats cache Added the new option "stat_cache_expire". This option which is specified by seconds means the lifetime for each stats cache entry. If this option is not specified, the stats cache is kept in s3fs process until the stats cache grown to maximum size. (default) If this option is specified, the stats cache entry is out from the memory when the entry expires time. 2) Enable file permission s3fs before 1.62 did not consider the file access permission. s3fs after this version can consider it. For access permission, the s3fs_getattr() function was divided into sub function which can check the file access permission. It is like access() function. And the function calling the s3fs_getattr() calls this new sub function instead of s3fs_getattr(). Last the s3fs_opendir() function which is called by FUSE was added for checking directory access permission when listing the files in directory. 3) UID/GUID When a file or a directory was created, the s3fs could not set the UID/GID as the user who executed a command. (Almost the UID/GID are root, because the s3fs run by root.) After this version, the s3fs set correct UID/GID as the user who executes the commond. 4) About the mtime If the object does not have "x-amz-meta-mtime" meta, the s3fs uses the "Last-Modified" header instead of it. But the s3fs had a bug in this code, and this version fixed this bug. When user modified the file, the s3fs did not update the mtime of the file. This version fixed this bug. In the get_local_fd() function, the local file's mtime was changed only when s3fs run with "use_cache" option. This version always updates the mtime whether the local cache file is used or not. And s3fs_flush ( ) function set the mtime of local cache file from S3 object mtime, but it was wrong . This version is that the s3fs_flush ( ) changes the mtime of S3 object from the local cache file or the tmpfile . The s3fs cuts some requests, because the s3fs can always check mtime whether the s3fs uses or does not use the local cache file. 5) A case of no "x-amz-meta-mode" If the object did not have "x-amz-meta-mtime" mete, the s3fs recognized the file as not regular file. After this version, the s3fs recognizes the file as regular file. 6) "." and ".." directory The s3fs_readdir() did not return "X" and "XX" directory name. After this version, the s3fs is changed that it returns "X" and "XX". Example, the result of "ls" lists "X" and "XX" directory. 7) Fixed a bug The insert_object() had a bug, and it is fixed. git-svn-id: http://s3fs.googlecode.com/svn/trunk@390 df820570-a93a-0410-bd06-b72b767a4274
2013-02-24 08:58:54 +00:00
" stat_cache_expire (default is no expire)\n"
" - specify expire time(seconds) for entries in the stat cache.\n"
"\n"
" url (default=\"http://s3.amazonaws.com\")\n"
" - sets the url to use to access amazon s3\n"
"\n"
" nomultipart - disable multipart uploads\n"
"\n"
" noxmlns - disable registing xml name space.\n"
" disable registing xml name space for response of \n"
" ListBucketResult and ListVersionsResult etc. Default name \n"
" space is looked up from \"http://s3.amazonaws.com/doc/2006-03-01\".\n"
"\n"
" nocopyapi - for other incomplete compatibility object storage.\n"
" For a distributed object storage which is compatibility S3\n"
" API without PUT(copy api).\n"
" If you set this option, s3fs do not use PUT with \n"
" \"x-amz-copy-source\"(copy api). Because traffic is increased\n"
" 2-3 times by this option, we do not recommend this.\n"
"\n"
"FUSE/mount Options:\n"
"\n"
" Most of the generic mount options described in 'man mount' are\n"
" supported (ro, rw, suid, nosuid, dev, nodev, exec, noexec, atime,\n"
" noatime, sync async, dirsync). Filesystems are mounted with\n"
" '-onodev,nosuid' by default, which can only be overridden by a\n"
" privileged user.\n"
" \n"
" There are many FUSE specific mount options that can be specified.\n"
" e.g. allow_other See the FUSE's README for the full set.\n"
"\n"
"Miscellaneous Options:\n"
"\n"
" -h, --help Output this help.\n"
" --version Output version info.\n"
" -d --debug Turn on DEBUG messages to syslog. Specifying -d\n"
" twice turns on FUSE debug messages to STDOUT.\n"
" -f FUSE foreground option - do not run as daemon.\n"
" -s FUSE singlethread option\n"
" disable multi-threaded operation\n"
"\n"
"\n"
"Report bugs to <s3fs-devel@googlegroups.com>\n"
"s3fs home page: <http://code.google.com/p/s3fs/>\n"
);
exit(EXIT_SUCCESS);
}
static void show_version(void) {
printf(
"Amazon Simple Storage Service File System %s\n"
"Copyright (C) 2010 Randy Rizun <rrizun@gmail.com>\n"
"License GPL2: GNU GPL version 2 <http://gnu.org/licenses/gpl.html>\n"
"This is free software: you are free to change and redistribute it.\n"
"There is NO WARRANTY, to the extent permitted by law.\n", VERSION );
exit(EXIT_SUCCESS);
}
char *get_realpath(const char *path) {
size_t size;
char *realpath;
size = (strlen(path) + 1) + (mount_prefix.size() + 1);
realpath = (char *) malloc(size);
snprintf(realpath, size, "%s%s", mount_prefix.c_str(), path);
return(realpath);
}
// This is repeatedly called by the fuse option parser
// if the key is equal to FUSE_OPT_KEY_OPT, it's an option passed in prefixed by
// '-' or '--' e.g.: -f -d -ousecache=/tmp
//
// if the key is equal to FUSE_OPT_KEY_NONOPT, it's either the bucket name
// or the mountpoint. The bucket name will always come before the mountpoint
static int my_fuse_opt_proc(void *data, const char *arg, int key, struct fuse_args *outargs) {
if(key == FUSE_OPT_KEY_NONOPT) {
// the first NONOPT option is the bucket name
if(bucket.size() == 0) {
// extract remote mount path
char *bucket_name = (char *) arg;
if(strstr(arg, ":")) {
bucket = strtok(bucket_name, ":");
mount_prefix = strtok(NULL, ":");
// remove trailing slash
if(mount_prefix.at(mount_prefix.size() - 1) == '/')
mount_prefix = mount_prefix.substr(0, mount_prefix.size() - 1);
} else {
bucket = arg;
}
return 0;
}
// save the mountpoint and do some basic error checking
mountpoint = arg;
struct stat stbuf;
if(stat(arg, &stbuf) == -1) {
fprintf(stderr, "%s: unable to access MOUNTPOINT %s: %s\n",
program_name.c_str(), mountpoint.c_str(), strerror(errno));
exit(EXIT_FAILURE);
}
root_mode = stbuf.st_mode; // save mode for later usage
if(!(S_ISDIR(stbuf.st_mode ))) {
fprintf(stderr, "%s: MOUNTPOINT: %s is not a directory\n",
program_name.c_str(), mountpoint.c_str());
exit(EXIT_FAILURE);
}
struct dirent *ent;
DIR *dp = opendir(mountpoint.c_str());
if(dp == NULL) {
fprintf(stderr, "%s: failed to open MOUNTPOINT: %s: %s\n",
program_name.c_str(), mountpoint.c_str(), strerror(errno));
exit(EXIT_FAILURE);
}
while((ent = readdir(dp)) != NULL) {
if(strcmp(ent->d_name, ".") != 0 && strcmp(ent->d_name, "..") != 0) {
closedir(dp);
fprintf(stderr, "%s: MOUNTPOINT directory %s is not empty\n",
program_name.c_str(), mountpoint.c_str());
exit(EXIT_FAILURE);
}
}
closedir(dp);
}
if (key == FUSE_OPT_KEY_OPT) {
if (strstr(arg, "default_acl=") != 0) {
default_acl = strchr(arg, '=') + 1;
return 0;
}
if (strstr(arg, "retries=") != 0) {
retries = atoi(strchr(arg, '=') + 1);
return 0;
}
if (strstr(arg, "use_cache=") != 0) {
use_cache = strchr(arg, '=') + 1;
return 0;
}
if(strstr(arg, "nomultipart") != 0) {
nomultipart = true;
return 0;
}
if (strstr(arg, "use_rrs=") != 0) {
use_rrs = strchr(arg, '=') + 1;
if (strcmp(use_rrs.c_str(), "1") == 0 ||
strcmp(use_rrs.c_str(), "") == 0 ) {
return 0;
} else {
fprintf(stderr, "%s: poorly formed argument to option: use_rrs\n",
program_name.c_str());
exit(EXIT_FAILURE);
}
}
if (strstr(arg, "ssl_verify_hostname=") != 0) {
ssl_verify_hostname = strchr(arg, '=') + 1;
if (strcmp(ssl_verify_hostname.c_str(), "1") == 0 ||
strcmp(ssl_verify_hostname.c_str(), "0") == 0 ) {
return 0;
} else {
fprintf(stderr, "%s: poorly formed argument to option: ssl_verify_hostname\n",
program_name.c_str());
exit(EXIT_FAILURE);
}
}
if (strstr(arg, "passwd_file=") != 0) {
passwd_file = strchr(arg, '=') + 1;
return 0;
}
if (strstr(arg, "public_bucket=") != 0) {
public_bucket = strchr(arg, '=') + 1;
if (strcmp(public_bucket.c_str(), "1") == 0 ||
strcmp(public_bucket.c_str(), "") == 0 ) {
return 0;
} else {
fprintf(stderr, "%s: poorly formed argument to option: public_bucket\n",
program_name.c_str());
exit(EXIT_FAILURE);
}
}
if (strstr(arg, "host=") != 0) {
host = strchr(arg, '=') + 1;
return 0;
}
if (strstr(arg, "servicepath=") != 0) {
service_path = strchr(arg, '=') + 1;
return 0;
}
if (strstr(arg, "connect_timeout=") != 0) {
connect_timeout = strtol(strchr(arg, '=') + 1, 0, 10);
return 0;
}
if (strstr(arg, "readwrite_timeout=") != 0) {
readwrite_timeout = strtoul(strchr(arg, '=') + 1, 0, 10);
return 0;
}
if (strstr(arg, "max_stat_cache_size=") != 0) {
max_stat_cache_size = strtoul(strchr(arg, '=') + 1, 0, 10);
return 0;
}
Summary of Changes(1.62 -> 1.63) 1) Lifetime for the stats cache Added the new option "stat_cache_expire". This option which is specified by seconds means the lifetime for each stats cache entry. If this option is not specified, the stats cache is kept in s3fs process until the stats cache grown to maximum size. (default) If this option is specified, the stats cache entry is out from the memory when the entry expires time. 2) Enable file permission s3fs before 1.62 did not consider the file access permission. s3fs after this version can consider it. For access permission, the s3fs_getattr() function was divided into sub function which can check the file access permission. It is like access() function. And the function calling the s3fs_getattr() calls this new sub function instead of s3fs_getattr(). Last the s3fs_opendir() function which is called by FUSE was added for checking directory access permission when listing the files in directory. 3) UID/GUID When a file or a directory was created, the s3fs could not set the UID/GID as the user who executed a command. (Almost the UID/GID are root, because the s3fs run by root.) After this version, the s3fs set correct UID/GID as the user who executes the commond. 4) About the mtime If the object does not have "x-amz-meta-mtime" meta, the s3fs uses the "Last-Modified" header instead of it. But the s3fs had a bug in this code, and this version fixed this bug. When user modified the file, the s3fs did not update the mtime of the file. This version fixed this bug. In the get_local_fd() function, the local file's mtime was changed only when s3fs run with "use_cache" option. This version always updates the mtime whether the local cache file is used or not. And s3fs_flush ( ) function set the mtime of local cache file from S3 object mtime, but it was wrong . This version is that the s3fs_flush ( ) changes the mtime of S3 object from the local cache file or the tmpfile . The s3fs cuts some requests, because the s3fs can always check mtime whether the s3fs uses or does not use the local cache file. 5) A case of no "x-amz-meta-mode" If the object did not have "x-amz-meta-mtime" mete, the s3fs recognized the file as not regular file. After this version, the s3fs recognizes the file as regular file. 6) "." and ".." directory The s3fs_readdir() did not return "X" and "XX" directory name. After this version, the s3fs is changed that it returns "X" and "XX". Example, the result of "ls" lists "X" and "XX" directory. 7) Fixed a bug The insert_object() had a bug, and it is fixed. git-svn-id: http://s3fs.googlecode.com/svn/trunk@390 df820570-a93a-0410-bd06-b72b767a4274
2013-02-24 08:58:54 +00:00
if (strstr(arg, "stat_cache_expire=") != 0) {
is_stat_cache_expire_time = 1;
stat_cache_expire_time = strtoul(strchr(arg, '=') + 1, 0, 10);
return 0;
}
if(strstr(arg, "noxmlns") != 0) {
noxmlns = true;
return 0;
}
if(strstr(arg, "nocopyapi") != 0) {
nocopyapi = true;
return 0;
}
if (strstr(arg, "url=") != 0) {
host = strchr(arg, '=') + 1;
// strip the trailing '/', if any, off the end of the host
// string
size_t found, length;
found = host.find_last_of('/');
length = host.length();
while ( found == (length - 1) && length > 0 ) {
host.erase(found);
found = host.find_last_of('/');
length = host.length();
}
return 0;
}
// debug option
//
// The first -d (or --debug) enables s3fs debug
// the second -d option is passed to fuse to turn on its
// debug output
if ( (strcmp(arg, "-d") == 0) || (strcmp(arg, "--debug") == 0) ) {
if (!debug) {
debug = 1;
return 0;
} else {
// fuse doesn't understand "--debug", but it
// understands -d, but we can't pass -d back
// to fuse, in this case just ignore the
// second --debug if is was provided. If we
// do not ignore this, fuse emits an error
if(strcmp(arg, "--debug") == 0) {
return 0;
}
}
}
if (strstr(arg, "accessKeyId=") != 0) {
fprintf(stderr, "%s: option accessKeyId is no longer supported\n",
program_name.c_str());
exit(EXIT_FAILURE);
}
if (strstr(arg, "secretAccessKey=") != 0) {
fprintf(stderr, "%s: option secretAccessKey is no longer supported\n",
program_name.c_str());
exit(EXIT_FAILURE);
}
}
return 1;
}
int main(int argc, char *argv[]) {
int ch;
int fuse_res;
int option_index = 0;
static const struct option long_opts[] = {
{"help", no_argument, NULL, 'h'},
{"version", no_argument, 0, 0},
{"debug", no_argument, NULL, 'd'},
{0, 0, 0, 0}};
// get progam name - emulate basename
size_t found = string::npos;
program_name.assign(argv[0]);
found = program_name.find_last_of("/");
if(found != string::npos) {
program_name.replace(0, found+1, "");
}
while ((ch = getopt_long(argc, argv, "dho:fsu", long_opts, &option_index)) != -1) {
switch (ch) {
case 0:
if(strcmp(long_opts[option_index].name, "version") == 0)
show_version();
break;
case 'h':
show_help();
break;
case 'o':
break;
case 'd':
break;
case 'f':
foreground = 1;
break;
case 's':
break;
case 'u':
utility_mode = 1;
break;
default:
exit(EXIT_FAILURE);
}
}
// clear this structure
memset(&s3fs_oper, 0, sizeof(s3fs_oper));
// This is the fuse-style parser for the arguments
// after which the bucket name and mountpoint names
// should have been set
struct fuse_args custom_args = FUSE_ARGS_INIT(argc, argv);
fuse_opt_parse(&custom_args, NULL, NULL, my_fuse_opt_proc);
// The first plain argument is the bucket
if (bucket.size() == 0) {
fprintf(stderr, "%s: missing BUCKET argument\n", program_name.c_str());
show_usage();
exit(EXIT_FAILURE);
}
// bucket names cannot contain upper case characters
if (lower(bucket) != bucket) {
fprintf(stderr, "%s: BUCKET %s, upper case characters are not supported\n",
program_name.c_str(), bucket.c_str());
exit(EXIT_FAILURE);
}
// check bucket name for illegal characters
found = bucket.find_first_of("/:\\;!@#$%^&*?|+=");
if(found != string::npos) {
fprintf(stderr, "%s: BUCKET %s -- bucket name contains an illegal character\n",
program_name.c_str(), bucket.c_str());
exit(EXIT_FAILURE);
}
// The second plain argument is the mountpoint
// if the option was given, we all ready checked for a
// readable, non-empty directory, this checks determines
// if the mountpoint option was ever supplied
if (utility_mode == 0) {
if (mountpoint.size() == 0) {
fprintf(stderr, "%s: missing MOUNTPOINT argument\n", program_name.c_str());
show_usage();
exit(EXIT_FAILURE);
}
}
// error checking of command line arguments for compatability
if ((AWSSecretAccessKey.size() > 0 && AWSAccessKeyId.size() == 0) ||
(AWSSecretAccessKey.size() == 0 && AWSAccessKeyId.size() > 0)) {
fprintf(stderr, "%s: if one access key is specified, both keys need to be specified\n",
program_name.c_str());
exit(EXIT_FAILURE);
}
if (public_bucket.substr(0,1) == "1" &&
(AWSSecretAccessKey.size() > 0 || AWSAccessKeyId.size() > 0)) {
fprintf(stderr, "%s: specifying both public_bucket and the access keys options is invalid\n",
program_name.c_str());
exit(EXIT_FAILURE);
}
if (passwd_file.size() > 0 &&
(AWSSecretAccessKey.size() > 0 || AWSAccessKeyId.size() > 0)) {
fprintf(stderr, "%s: specifying both passwd_file and the access keys options is invalid\n",
program_name.c_str());
exit(EXIT_FAILURE);
}
if (public_bucket.substr(0,1) != "1") {
get_access_keys();
if(AWSSecretAccessKey.size() == 0 || AWSAccessKeyId.size() == 0) {
fprintf(stderr, "%s: could not establish security credentials, check documentation\n",
program_name.c_str());
exit(EXIT_FAILURE);
}
// More error checking on the access key pair can be done
// like checking for appropriate lengths and characters
}
// There's room for more command line error checking
// Check to see if the bucket name contains periods and https (SSL) is
// being used. This is a known limitation:
// http://docs.amazonwebservices.com/AmazonS3/latest/dev/
// The Developers Guide suggests that either use HTTP of for us to write
// our own certificate verification logic.
// For now, this will be unsupported unless we get a request for it to
// be supported. In that case, we have a couple of options:
// - implement a command line option that bypasses the verify host
// but doesn't bypass verifying the certificate
// - write our own host verification (this might be complex)
// See issue #128strncasecmp
/*
if (ssl_verify_hostname.substr(0,1) == "1") {
found = bucket.find_first_of(".");
if(found != string::npos) {
found = host.find("https:");
if(found != string::npos) {
fprintf(stderr, "%s: Using https and a bucket name with periods is unsupported.\n",
program_name.c_str());
exit(1);
}
}
}
*/
// Does the bucket exist?
// if the network is up, check for valid credentials and if the bucket
// exists. skip check if mounting a public bucket
if(public_bucket.substr(0,1) != "1")
s3fs_check_service();
if (utility_mode) {
printf("Utility Mode\n");
int result;
result = list_multipart_uploads();
exit(EXIT_SUCCESS);
}
s3fs_oper.getattr = s3fs_getattr;
s3fs_oper.readlink = s3fs_readlink;
s3fs_oper.mknod = s3fs_mknod;
s3fs_oper.mkdir = s3fs_mkdir;
s3fs_oper.unlink = s3fs_unlink;
s3fs_oper.rmdir = s3fs_rmdir;
s3fs_oper.symlink = s3fs_symlink;
s3fs_oper.rename = s3fs_rename;
s3fs_oper.link = s3fs_link;
if(!nocopyapi){
s3fs_oper.chmod = s3fs_chmod;
s3fs_oper.chown = s3fs_chown;
s3fs_oper.utimens = s3fs_utimens;
}else{
s3fs_oper.chmod = s3fs_chmod_nocopy;
s3fs_oper.chown = s3fs_chown_nocopy;
s3fs_oper.utimens = s3fs_utimens_nocopy;
}
s3fs_oper.truncate = s3fs_truncate;
s3fs_oper.open = s3fs_open;
s3fs_oper.read = s3fs_read;
s3fs_oper.write = s3fs_write;
s3fs_oper.statfs = s3fs_statfs;
s3fs_oper.flush = s3fs_flush;
s3fs_oper.release = s3fs_release;
Summary of Changes(1.62 -> 1.63) 1) Lifetime for the stats cache Added the new option "stat_cache_expire". This option which is specified by seconds means the lifetime for each stats cache entry. If this option is not specified, the stats cache is kept in s3fs process until the stats cache grown to maximum size. (default) If this option is specified, the stats cache entry is out from the memory when the entry expires time. 2) Enable file permission s3fs before 1.62 did not consider the file access permission. s3fs after this version can consider it. For access permission, the s3fs_getattr() function was divided into sub function which can check the file access permission. It is like access() function. And the function calling the s3fs_getattr() calls this new sub function instead of s3fs_getattr(). Last the s3fs_opendir() function which is called by FUSE was added for checking directory access permission when listing the files in directory. 3) UID/GUID When a file or a directory was created, the s3fs could not set the UID/GID as the user who executed a command. (Almost the UID/GID are root, because the s3fs run by root.) After this version, the s3fs set correct UID/GID as the user who executes the commond. 4) About the mtime If the object does not have "x-amz-meta-mtime" meta, the s3fs uses the "Last-Modified" header instead of it. But the s3fs had a bug in this code, and this version fixed this bug. When user modified the file, the s3fs did not update the mtime of the file. This version fixed this bug. In the get_local_fd() function, the local file's mtime was changed only when s3fs run with "use_cache" option. This version always updates the mtime whether the local cache file is used or not. And s3fs_flush ( ) function set the mtime of local cache file from S3 object mtime, but it was wrong . This version is that the s3fs_flush ( ) changes the mtime of S3 object from the local cache file or the tmpfile . The s3fs cuts some requests, because the s3fs can always check mtime whether the s3fs uses or does not use the local cache file. 5) A case of no "x-amz-meta-mode" If the object did not have "x-amz-meta-mtime" mete, the s3fs recognized the file as not regular file. After this version, the s3fs recognizes the file as regular file. 6) "." and ".." directory The s3fs_readdir() did not return "X" and "XX" directory name. After this version, the s3fs is changed that it returns "X" and "XX". Example, the result of "ls" lists "X" and "XX" directory. 7) Fixed a bug The insert_object() had a bug, and it is fixed. git-svn-id: http://s3fs.googlecode.com/svn/trunk@390 df820570-a93a-0410-bd06-b72b767a4274
2013-02-24 08:58:54 +00:00
s3fs_oper.opendir = s3fs_opendir;
s3fs_oper.readdir = s3fs_readdir;
s3fs_oper.init = s3fs_init;
s3fs_oper.destroy = s3fs_destroy;
s3fs_oper.access = s3fs_access;
s3fs_oper.create = s3fs_create;
// now passing things off to fuse, fuse will finish evaluating the command line args
fuse_res = fuse_main(custom_args.argc, custom_args.argv, &s3fs_oper, NULL);
fuse_opt_free_args(&custom_args);
return fuse_res;
}