int delete_file(char* path) { debugf(DBG_LEVEL_NORM, KYEL"delete_file(%s)", path); char file_path_safe[NAME_MAX] = ""; get_safe_cache_file_path(path, file_path_safe, temp_dir); int result = unlink(file_path_safe); debugf(DBG_LEVEL_EXT, KYEL"delete_file(%s) (%s) result=%s", path, file_path_safe, strerror(result)); return result; }
// open (download) file from cloud // todo: implement etag optimisation, download only if content changed, http://www.17od.com/2012/12/19/ten-useful-openstack-swift-features/ static int cfs_open(const char* path, struct fuse_file_info* info) { debugf(DBG_LEVEL_NORM, KBLU "cfs_open(%s)", path); FILE* temp_file = NULL; int errsv; dir_entry* de = path_info(path); if (*temp_dir) { char file_path_safe[NAME_MAX]; get_safe_cache_file_path(path, file_path_safe, temp_dir); debugf(DBG_LEVEL_EXT, "cfs_open: try open (%s)", file_path_safe); if (access(file_path_safe, F_OK) != -1) { // file exists temp_file = fopen(file_path_safe, "r"); errsv = errno; if (temp_file == NULL) { debugf(DBG_LEVEL_NORM, KRED"exit 0: cfs_open can't open temp_file=[%s] err=%d:%s", file_path_safe, errsv, strerror(errsv)); return -ENOENT; } else debugf(DBG_LEVEL_EXT, "cfs_open: file exists"); } else { errsv = errno; debugf(DBG_LEVEL_EXT, "cfs_open: file not in cache, err=%s", strerror(errsv)); //FIXME: commented out as this condition will not be meet in some odd cases and program will crash //if (!(info->flags & O_WRONLY)) { debugf(DBG_LEVEL_EXT, "cfs_open: opening for write"); // we need to lock on the filename another process could open the file // while we are writing to it and then only read part of the file // duplicate the directory caching datastructure to make the code easier // to understand. // each file in the cache needs: // filename, is_writing, last_closed, is_removing // the first time a file is opened a new entry is created in the cache // setting the filename and is_writing to true. This check needs to be // wrapped with a lock. // // each time a file is closed we set the last_closed for the file to now // and we check the cache for files whose last // closed is greater than cache_timeout, then start a new thread rming // that file. // TODO: just to prevent this craziness for now temp_file = fopen(file_path_safe, "w+b"); errsv = errno; if (temp_file == NULL) { debugf(DBG_LEVEL_NORM, KRED"exit 1: cfs_open cannot open temp_file=[%s] err=%d:%s", file_path_safe, errsv, strerror(errsv)); return -ENOENT; } if (!cloudfs_object_write_fp(path, temp_file)) { fclose(temp_file); debugf(DBG_LEVEL_NORM, KRED "exit 2: cfs_open(%s) cannot download/write", path); return -ENOENT; } } } else { temp_file = tmpfile(); if (temp_file == NULL) { debugf(DBG_LEVEL_NORM, KRED"exit 3: cfs_open cannot create temp_file err=%s", strerror(errno)); return -ENOENT; } if (!(info->flags & O_TRUNC)) { if (!cloudfs_object_write_fp(path, temp_file) && !(info->flags & O_CREAT)) { fclose(temp_file); debugf(DBG_LEVEL_NORM, KRED"exit 4: cfs_open(%s) cannot download/write", path); return -ENOENT; } } } update_dir_cache(path, (de ? de->size : 0), 0, 0); openfile* of = (openfile*)malloc(sizeof(openfile)); of->fd = dup(fileno(temp_file)); if (of->fd == -1) { //FIXME: potential leak if free not used? free(of); debugf(DBG_LEVEL_NORM, KRED "exit 5: cfs_open(%s) of->fd", path); return -ENOENT; } fclose(temp_file); //TODO: why this allocation to of? of->flags = info->flags; info->fh = (uintptr_t)of; info->direct_io = 1; info->nonseekable = 0; //FIXME: potential leak if free(of) not used? although if free(of) is used will generate bad descriptor errors debugf(DBG_LEVEL_NORM, KBLU "exit 6: cfs_open(%s)", path); return 0; }
static int cfs_create(const char* path, mode_t mode, struct fuse_file_info* info) { debugf(DBG_LEVEL_NORM, KBLU "cfs_create(%s)", path); FILE* temp_file; int errsv; char file_path_safe[NAME_MAX] = ""; if (*temp_dir) { get_safe_cache_file_path(path, file_path_safe, temp_dir); temp_file = fopen(file_path_safe, "w+b"); errsv = errno; if (temp_file == NULL) { debugf(DBG_LEVEL_NORM, KRED "exit 0: cfs_create cannot open temp file %s.error %s\n", file_path_safe, strerror(errsv)); return -EIO; } } else { temp_file = tmpfile(); errsv = errno; if (temp_file == NULL) { debugf(DBG_LEVEL_NORM, KRED "exit 1: cfs_create cannot open tmp file for path %s.error %s\n", path, strerror(errsv)); return -EIO; } } openfile* of = (openfile*)malloc(sizeof(openfile)); of->fd = dup(fileno(temp_file)); fclose(temp_file); of->flags = info->flags; info->fh = (uintptr_t)of; update_dir_cache(path, 0, 0, 0); info->direct_io = 1; dir_entry* de = check_path_info(path); if (de) { debugf(DBG_LEVEL_EXT, KCYN"cfs_create(%s): found in cache", path); struct timespec now; clock_gettime(CLOCK_REALTIME, &now); debugf(DBG_LEVEL_EXT, KCYN"cfs_create(%s) set utimes as now", path); de->atime.tv_sec = now.tv_sec; de->atime.tv_nsec = now.tv_nsec; de->mtime.tv_sec = now.tv_sec; de->mtime.tv_nsec = now.tv_nsec; de->ctime.tv_sec = now.tv_sec; de->ctime.tv_nsec = now.tv_nsec; char time_str[TIME_CHARS] = ""; get_timespec_as_str(&(de->atime), time_str, sizeof(time_str)); debugf(DBG_LEVEL_EXT, KCYN"cfs_create: atime=[%s]", time_str); get_timespec_as_str(&(de->mtime), time_str, sizeof(time_str)); debugf(DBG_LEVEL_EXT, KCYN"cfs_create: mtime=[%s]", time_str); get_timespec_as_str(&(de->ctime), time_str, sizeof(time_str)); debugf(DBG_LEVEL_EXT, KCYN"cfs_create: ctime=[%s]", time_str); //set chmod & chown de->chmod = mode; de->uid = geteuid(); de->gid = getegid(); } else debugf(DBG_LEVEL_EXT, KBLU "cfs_create(%s) "KYEL"dir-entry not found", path); debugf(DBG_LEVEL_NORM, KBLU "exit 2: cfs_create(%s)=(%s) result=%d:%s", path, file_path_safe, errsv, strerror(errsv)); return 0; }