diff --git a/configure.ac b/configure.ac
index 7e9912f..f4b8ae6 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,7 +1,7 @@
 dnl Process this file with autoconf to produce a configure script.
 
 AC_PREREQ(2.59)
-AC_INIT(s3fs, 1.62)
+AC_INIT(s3fs, 1.63)
 
 
 AC_CANONICAL_SYSTEM
diff --git a/doc/man/s3fs.1 b/doc/man/s3fs.1
index 524131a..83cb593 100644
--- a/doc/man/s3fs.1
+++ b/doc/man/s3fs.1
@@ -77,6 +77,9 @@ time to wait between read/write activity before giving up.
 \fB\-o\fR max_stat_cache_size (default="10000" entries (about 4MB))
 maximum number of entries in the stat cache
 .TP
+\fB\-o\fR stat_cache_expire (default is no expire)
+specify expire time(seconds) for entries in the stat cache
+.TP
 \fB\-o\fR url (default="http://s3.amazonaws.com")
 sets the url to use to access Amazon S3. If you want to use HTTPS, then you can set url=https://s3.amazonaws.com
 .TP
diff --git a/src/cache.cpp b/src/cache.cpp
index c3e4e52..eb36f23 100644
--- a/src/cache.cpp
+++ b/src/cache.cpp
@@ -36,22 +36,35 @@ static stat_cache_t stat_cache;
 pthread_mutex_t stat_cache_lock;
 
 int get_stat_cache_entry(const char *path, struct stat *buf) {
+  int is_delete_cache = 0;
+
   pthread_mutex_lock(&stat_cache_lock);
   stat_cache_t::iterator iter = stat_cache.find(path);
   if(iter != stat_cache.end()) {
-    if(foreground)
-      cout << "    stat cache hit [path=" << path << "]"
-           << " [hit count=" << (*iter).second.hit_count << "]" << endl;
+    if(!is_stat_cache_expire_time || ((*iter).second.cache_date + stat_cache_expire_time) >= time(NULL)){
+      // hit 
+      if(foreground)
+        cout << "    stat cache hit [path=" << path << "]"
+             << " [time=" << (*iter).second.cache_date << "]"
+             << " [hit count=" << (*iter).second.hit_count << "]" << endl;
 
-    if(buf != NULL)
-      *buf = (*iter).second.stbuf;
+      if(buf != NULL)
+        *buf = (*iter).second.stbuf;
 
-    (*iter).second.hit_count++;
-    pthread_mutex_unlock(&stat_cache_lock);
-    return 0;
+      (*iter).second.hit_count++;
+      pthread_mutex_unlock(&stat_cache_lock);
+      return 0;
+    }else{
+      // timeout
+      is_delete_cache = 1;
+    }
   }
   pthread_mutex_unlock(&stat_cache_lock);
 
+  if(is_delete_cache){
+    delete_stat_cache_entry(path);
+  }
+
   return -1;
 }
 
@@ -67,6 +80,7 @@ void add_stat_cache_entry(const char *path, struct stat *st) {
 
   pthread_mutex_lock(&stat_cache_lock);
   stat_cache[path].stbuf = *st;
+  stat_cache[path].cache_date = time(NULL); // Set time.
   pthread_mutex_unlock(&stat_cache_lock);
 }
 
diff --git a/src/cache.h b/src/cache.h
index 91e38a6..3ff0e1e 100644
--- a/src/cache.h
+++ b/src/cache.h
@@ -8,12 +8,15 @@
 struct stat_cache_entry {
   struct stat stbuf;
   unsigned long hit_count;
+  time_t cache_date;
 
-  stat_cache_entry() : hit_count(0) {}
+  stat_cache_entry() : hit_count(0), cache_date(0) {}
 };
 
 extern bool foreground;
 extern unsigned long max_stat_cache_size;
+extern time_t stat_cache_expire_time;
+extern int is_stat_cache_expire_time;
 
 int get_stat_cache_entry(const char *path, struct stat *buf);
 void add_stat_cache_entry(const char *path, struct stat *st);
diff --git a/src/s3fs.cpp b/src/s3fs.cpp
index 5c5cd2c..d89b4c7 100644
--- a/src/s3fs.cpp
+++ b/src/s3fs.cpp
@@ -145,8 +145,7 @@ blkcnt_t get_blocks(off_t size) {
   return size / 512 + 1;
 }
 
-static int insert_object(char *name, struct s3_object **head) {
-  size_t n_len = strlen(name) + 1;
+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));
@@ -155,15 +154,12 @@ static int insert_object(char *name, struct s3_object **head) {
     exit(EXIT_FAILURE);
   }
 
-  new_object->name = (char *) malloc(n_len);
-  if(new_object->name == NULL) {
+  if(NULL == (new_object->name = strdup(name))){
     free(new_object);
     printf("insert_object: could not allocate memory\n");
     exit(EXIT_FAILURE);
   }
 
-  strncpy(new_object->name, name, n_len);
-
   if((*head) == NULL)
     new_object->next = NULL;
   else
@@ -324,6 +320,241 @@ static int mkdirp(const string& path, mode_t mode) {
   return 0;
 }
 
+// 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)
 {
@@ -362,13 +593,13 @@ int get_local_fd(const char* path) {
   resource = urlEncode(service_path + bucket + s3_realpath);
   url = host + resource;
 
-  if(use_cache.size() > 0) {
-    result = curl_get_headers(s3_realpath, responseHeaders);
-    if(result != 0) {
-      free(s3_realpath);
-      return -result;
-    }
+  result = curl_get_headers(s3_realpath, responseHeaders);
+  if(result != 0) {
+    free(s3_realpath);
+    return -result;
+  }
 
+  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) {
@@ -453,12 +684,15 @@ int get_local_fd(const char* path) {
     if(fd == -1)
       YIKES(-errno);
 
-    if(use_cache.size() > 0 && !S_ISLNK(mode)) {
+    if(S_ISREG(mode) && !S_ISLNK(mode)) {
       // make the file's mtime match that of the file on s3
-      struct utimbuf n_mtime;
-      n_mtime.modtime = get_mtime(responseHeaders["x-amz-meta-mtime"].c_str());
-      n_mtime.actime = n_mtime.modtime;
-      if((utime(cache_path.c_str(), &n_mtime)) == -1) {
+      // 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);
       }
@@ -486,7 +720,8 @@ static int put_headers(const char *path, headers_t meta) {
     cout << "   put_headers[path=" << path << "]" << endl;
 
   // files larger than 5GB must be modified via the multipart interface
-  s3fs_getattr(path, &buf);
+  get_object_attribute(path, &buf);
+
   if(buf.st_size >= FIVE_GB)
     return(put_multipart_headers(path, meta));
 
@@ -589,7 +824,8 @@ static int put_multipart_headers(const char *path, headers_t meta) {
   body.text = (char *)malloc(1);
   body.size = 0;
 
-  s3fs_getattr(path, &buf);
+  // 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){
@@ -1388,54 +1624,18 @@ string md5sum(int fd) {
   return string(md5);
 }
 
-static int s3fs_getattr(const char *path, struct stat *stbuf) {
+static int s3fs_getattr(const char *path, struct stat *stbuf)
+{
   int result;
-  headers_t meta;
-  char *s3_realpath;
 
   if(foreground) 
     printf("s3fs_getattr[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);
+  // check parent directory attribute.
+  if(0 != (result = check_parent_object_access(path, X_OK))){
     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)
-    stbuf->st_mtime = get_mtime(meta["Last-Modified"].c_str());
-
-  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;
+  return check_object_access(path, F_OK, stbuf);
 }
 
 static int s3fs_readlink(const char *path, char *buf, size_t size) {
@@ -1541,7 +1741,7 @@ string lookupMimeType(string s) {
 }
 
 // common function for creation of a plain object
-static int create_file_object(const char *path, mode_t mode) {
+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;
@@ -1561,10 +1761,10 @@ static int create_file_object(const char *path, mode_t mode) {
   headers.append("Content-Type: " + contentType);
   // 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(getgid()));
+  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)));
-  headers.append("x-amz-meta-uid:" + str(getuid()));
+  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));
@@ -1598,11 +1798,24 @@ static int s3fs_mknod(const char *path, mode_t mode, dev_t rdev)
 static int s3fs_create(const char *path, mode_t mode, struct fuse_file_info *fi) {
   int result;
   headers_t meta;
+  struct fuse_context* pcxt;
 
   if(foreground) 
     cout << "s3fs_create[path=" << path << "][mode=" << mode << "]" << "[flags=" << fi->flags << "]" <<  endl;
 
-  result = create_file_object(path, mode);
+  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;
@@ -1675,10 +1888,28 @@ static int create_directory_object(const char *path, mode_t mode, time_t time, u
 
 static int s3fs_mkdir(const char *path, mode_t mode)
 {
+  int result;
+  struct fuse_context* pcxt;
+
   if(foreground) 
     cout << "s3fs_mkdir[path=" << path << "][mode=" << mode << "]" << endl;
 
-  return create_directory_object(path, mode, time(NULL), getuid(), getgid());
+  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) {
@@ -1688,6 +1919,10 @@ static int s3fs_unlink(const char *path) {
   if(foreground) 
     printf("s3fs_unlink[path=%s]\n", path);
 
+  if(0 != (result = check_parent_object_access(path, W_OK | X_OK))){
+    return result;
+  }
+
   s3_realpath = get_realpath(path);
 
   result = curl_delete(s3_realpath);
@@ -1767,6 +2002,10 @@ static int s3fs_rmdir(const char *path) {
   if(foreground) 
     printf("s3fs_rmdir [path=%s]\n", path);
 
+  if(0 != (result = check_parent_object_access(path, W_OK | X_OK))){
+    return result;
+  }
+
   s3_realpath = get_realpath(path);
 
    // directory must be empty
@@ -1788,6 +2027,16 @@ static int s3fs_symlink(const char *from, const char *to) {
   if(foreground) 
     cout << "s3fs_symlink[from=" << from << "][to=" << to << "]" << endl;
 
+  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));
@@ -1831,6 +2080,15 @@ static int rename_object(const char *from, const char *to) {
   if(debug)
     syslog(LOG_DEBUG, "rename_object [from=%s] [to=%s]", from, to);
 
+  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);
 
@@ -1866,6 +2124,15 @@ static int rename_object_nocopy(const char *from, const char *to) {
   if(debug)
     syslog(LOG_DEBUG, "rename_object_nocopy [from=%s] [to=%s]", from, to);
 
+  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))){
@@ -1928,9 +2195,17 @@ static int rename_large_object(const char *from, const char *to) {
   if(debug)
     syslog(LOG_DEBUG, "rename_large_object [from=%s] [to=%s]", from, to);
 
-  s3fs_getattr(from, &buf);
-  s3_realpath = get_realpath(from);
+  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);
 
+  s3_realpath = get_realpath(from);
   if((curl_get_headers(s3_realpath, meta) != 0)) {
     free(s3_realpath);
     return -1;
@@ -2269,7 +2544,15 @@ static int s3fs_rename(const char *from, const char *to) {
   if(debug)
     syslog(LOG_DEBUG, "s3fs_rename [from=%s] [to=%s]", from, to);
 
-  s3fs_getattr(from, &buf);
+  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)){
@@ -2302,6 +2585,13 @@ static int s3fs_chmod(const char *path, mode_t mode) {
   if(foreground) 
     printf("s3fs_chmod [path=%s] [mode=%d]\n", path, mode);
 
+  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) {
@@ -2332,6 +2622,13 @@ static int s3fs_chmod_nocopy(const char *path, mode_t mode) {
   if(foreground) 
     printf("s3fs_chmod_nocopy [path=%s] [mode=%d]\n", path, mode);
 
+  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))){
@@ -2392,6 +2689,13 @@ static int s3fs_chown(const char *path, uid_t uid, gid_t gid) {
   if(foreground) 
     printf("s3fs_chown [path=%s] [uid=%d] [gid=%d]\n", path, uid, gid);
 
+  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);
@@ -2430,6 +2734,13 @@ static int s3fs_chown_nocopy(const char *path, uid_t uid, gid_t gid) {
   if(foreground) 
     printf("s3fs_chown_nocopy [path=%s] [uid=%d] [gid=%d]\n", path, uid, gid);
 
+  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))){
@@ -2500,6 +2811,13 @@ static int s3fs_truncate(const char *path, off_t size) {
   if(foreground) 
     printf("s3fs_truncate[path=%s][size=%zd]\n", path, size);
 
+  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);
@@ -2558,6 +2876,14 @@ static int s3fs_open(const char *path, struct fuse_file_info *fi) {
   if(foreground) 
     cout << "s3fs_open[path=" << path << "][flags=" << fi->flags << "]" <<  endl;
 
+  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);
@@ -2595,8 +2921,9 @@ 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);
 
-  if(foreground) 
-    cout << "s3fs_write[path=" << path << "]" << endl;
+  // Commented - This message is output too much
+//if(foreground) 
+//  cout << "s3fs_write[path=" << path << "]" << endl;
 
   if(res == -1)
     YIKES(-errno);
@@ -2631,9 +2958,17 @@ static int s3fs_flush(const char *path, struct fuse_file_info *fi) {
   if(foreground) 
     cout << "s3fs_flush[path=" << path << "][fd=" << fd << "]" << endl;
 
+  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);
-  if((flags & O_RDWR) || (flags & O_WRONLY)) {
+  if(O_RDONLY != (flags & O_ACCMODE)) {
     headers_t meta;
     s3_realpath = get_realpath(path);
     result = curl_get_headers(s3_realpath, meta);
@@ -2643,31 +2978,18 @@ static int s3fs_flush(const char *path, struct fuse_file_info *fi) {
       return result;
 
     // if the cached file matches the remote file skip uploading
-    if(use_cache.size() > 0) {
-      struct stat st;
+    struct stat st;
+    if((fstat(fd, &st)) == -1)
+      YIKES(-errno);
 
-      if((fstat(fd, &st)) == -1)
-        YIKES(-errno);
-
-      if(str(st.st_size) == meta["Content-Length"] && 
-        (str(st.st_mtime) == meta["x-amz-meta-mtime"])) {
-        return result;
-      }
+    if(str(st.st_size) == meta["Content-Length"] &&
+      (str(st.st_mtime) == meta["x-amz-meta-mtime"])) {
+      return result;
     }
 
-    // force the cached copy to have the same mtime as the remote copy
-    if(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);
-        }
-      }
+    // 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);
@@ -2738,6 +3060,20 @@ static CURL *create_head_handle(head_data *request_data) {
   return curl_handle;
 }
 
+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;
@@ -2753,15 +3089,20 @@ static int s3fs_readdir(
   if(foreground) 
     cout << "s3fs_readdir[path=" << path << "]" << endl;
 
-  // get a list of all the objects
   int result;
+  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;
   }
 
-  if(head == NULL){
+  // 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;
@@ -3109,8 +3450,10 @@ static int append_objects_from_xml(const char* path, const char *xml, struct s3_
         xmlXPathFreeObject(contents_xp);
         xmlXPathFreeContext(ctx);
         xmlFreeDoc(doc);
+        free(name);
         return -1;
       }
+      free(name);
     }else{
       //if(foreground)
       //  printf("append_objects_from_xml name is file or subdir in dir. but continue.\n");
@@ -3161,6 +3504,9 @@ static bool is_truncated(const char *xml) {
   return false;
 }
 
+// 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
@@ -3200,11 +3546,11 @@ static char *get_object_name(xmlDocPtr doc, xmlNodePtr node, const char* path)
     // case of "name"
     if(0 == strcmp(dirpath, ".")){
       // OK
-      return (char*)mybname;
+      return strdup(mybname);
     }else{
       if(0 == strcmp(dirpath, basepath)){
         // OK
-        return (char*)mybname;
+        return strdup(mybname);
       }
     }
   }
@@ -3219,7 +3565,7 @@ static int remote_mountpath_exists(const char *path) {
     printf("remote_mountpath_exists [path=%s]\n", path);
 
   // getattr will prefix the path with the remote mountpoint
-  s3fs_getattr("", &stbuf);
+  get_object_attribute("", &stbuf);
   if(!S_ISDIR(stbuf.st_mode))
     return -1;
 
@@ -3314,9 +3660,13 @@ static void s3fs_destroy(void*) {
 
 static int s3fs_access(const char *path, int mask) {
   if(foreground) 
-    printf("s3fs_access[path=%s]\n", path);
+    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" : "");
 
-  return 0;
+    return check_object_access(path, mask, NULL);
 }
 
 static int s3fs_utimens(const char *path, const struct timespec ts[2]) {
@@ -3327,6 +3677,13 @@ static int s3fs_utimens(const char *path, const struct timespec ts[2]) {
   if(foreground) 
     printf("s3fs_utimens[path=%s][mtime=%zd]\n", path, ts[1].tv_sec);
 
+  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);
@@ -3352,6 +3709,13 @@ static int s3fs_utimens_nocopy(const char *path, const struct timespec ts[2]) {
   if(foreground) 
     cout << "s3fs_utimens_nocopy [path=" << path << "][mtime=" << str(ts[1].tv_sec) << "]" << endl;
 
+  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))){
@@ -3926,6 +4290,9 @@ static void show_help (void) {
     "   max_stat_cache_size (default=\"10000\" entries (about 4MB))\n"
     "      - maximum number of entries in the stat cache\n"
     "\n"
+    "   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"
@@ -4131,6 +4498,11 @@ static int my_fuse_opt_proc(void *data, const char *arg, int key, struct fuse_ar
       max_stat_cache_size = strtoul(strchr(arg, '=') + 1, 0, 10);
       return 0;
     }
+    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;
@@ -4377,6 +4749,7 @@ int main(int argc, char *argv[]) {
   s3fs_oper.statfs = s3fs_statfs;
   s3fs_oper.flush = s3fs_flush;
   s3fs_oper.release = s3fs_release;
+  s3fs_oper.opendir = s3fs_opendir;
   s3fs_oper.readdir = s3fs_readdir;
   s3fs_oper.init = s3fs_init;
   s3fs_oper.destroy = s3fs_destroy;
diff --git a/src/s3fs.h b/src/s3fs.h
index 9a4ae65..6fcb5c4 100644
--- a/src/s3fs.h
+++ b/src/s3fs.h
@@ -47,6 +47,8 @@ static mode_t root_mode = 0;
 static std::string passwd_file = "";
 static bool utility_mode = 0;
 unsigned long max_stat_cache_size = 10000;
+time_t stat_cache_expire_time = 0;
+int is_stat_cache_expire_time = 0;
 bool noxmlns = false;
 bool nocopyapi = false;
 
@@ -104,7 +106,7 @@ uid_t get_uid(const char *s);
 gid_t get_gid(const char *s);
 blkcnt_t get_blocks(off_t size);
 
-static int insert_object(char *name, struct s3_object **head);
+static int insert_object(const char *name, struct s3_object **head);
 static unsigned int count_object_list(struct s3_object *list);
 static int free_object(struct s3_object *object);
 static int free_object_list(struct s3_object *head);
@@ -139,6 +141,7 @@ static int s3fs_write(
 static int s3fs_statfs(const char *path, struct statvfs *stbuf);
 static int s3fs_flush(const char *path, struct fuse_file_info *fi);
 static int s3fs_release(const char *path, struct fuse_file_info *fi);
+static int s3fs_opendir(const char *path, struct fuse_file_info *fi);
 static int s3fs_readdir(
     const char *path, void *buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *fi);
 static int s3fs_access(const char *path, int mask);