1 /*
2 * s3fs - FUSE-based file system backed by Amazon S3
3 *
4 * Copyright(C) 2007 Takeshi Nakatani <ggtakec.com>
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 */
20
21 #include <cstdio>
22 #include <cstdlib>
23 #include <cerrno>
24 #include <unistd.h>
25 #include <sys/file.h>
26
27 #include "common.h"
28 #include "s3fs.h"
29 #include "fdcache_stat.h"
30 #include "fdcache.h"
31 #include "s3fs_util.h"
32 #include "string_util.h"
33
34 //------------------------------------------------
35 // CacheFileStat class methods
36 //------------------------------------------------
GetCacheFileStatTopDir()37 std::string CacheFileStat::GetCacheFileStatTopDir()
38 {
39 std::string top_path;
40 if(!FdManager::IsCacheDir() || bucket.empty()){
41 return top_path;
42 }
43
44 // stat top dir( "/<cache_dir>/.<bucket_name>.stat" )
45 top_path += FdManager::GetCacheDir();
46 top_path += "/.";
47 top_path += bucket;
48 top_path += ".stat";
49 return top_path;
50 }
51
MakeCacheFileStatPath(const char * path,std::string & sfile_path,bool is_create_dir)52 bool CacheFileStat::MakeCacheFileStatPath(const char* path, std::string& sfile_path, bool is_create_dir)
53 {
54 std::string top_path = CacheFileStat::GetCacheFileStatTopDir();
55 if(top_path.empty()){
56 S3FS_PRN_ERR("The path to cache top dir is empty.");
57 return false;
58 }
59
60 if(is_create_dir){
61 int result;
62 if(0 != (result = mkdirp(top_path + mydirname(path), 0777))){
63 S3FS_PRN_ERR("failed to create dir(%s) by errno(%d).", path, result);
64 return false;
65 }
66 }
67 if(!path || '\0' == path[0]){
68 sfile_path = top_path;
69 }else{
70 sfile_path = top_path + SAFESTRPTR(path);
71 }
72 return true;
73 }
74
CheckCacheFileStatTopDir()75 bool CacheFileStat::CheckCacheFileStatTopDir()
76 {
77 std::string top_path = CacheFileStat::GetCacheFileStatTopDir();
78 if(top_path.empty()){
79 S3FS_PRN_INFO("The path to cache top dir is empty, thus not need to check permission.");
80 return true;
81 }
82
83 return check_exist_dir_permission(top_path.c_str());
84 }
85
DeleteCacheFileStat(const char * path)86 bool CacheFileStat::DeleteCacheFileStat(const char* path)
87 {
88 if(!path || '\0' == path[0]){
89 return false;
90 }
91 // stat path
92 std::string sfile_path;
93 if(!CacheFileStat::MakeCacheFileStatPath(path, sfile_path, false)){
94 S3FS_PRN_ERR("failed to create cache stat file path(%s)", path);
95 return false;
96 }
97 if(0 != unlink(sfile_path.c_str())){
98 if(ENOENT == errno){
99 S3FS_PRN_DBG("failed to delete file(%s): errno=%d", path, errno);
100 }else{
101 S3FS_PRN_ERR("failed to delete file(%s): errno=%d", path, errno);
102 }
103 return false;
104 }
105 return true;
106 }
107
108 // [NOTE]
109 // If remove stat file directory, it should do before removing
110 // file cache directory.
111 //
DeleteCacheFileStatDirectory()112 bool CacheFileStat::DeleteCacheFileStatDirectory()
113 {
114 std::string top_path = CacheFileStat::GetCacheFileStatTopDir();
115 if(top_path.empty()){
116 S3FS_PRN_INFO("The path to cache top dir is empty, thus not need to remove it.");
117 return true;
118 }
119 return delete_files_in_dir(top_path.c_str(), true);
120 }
121
RenameCacheFileStat(const char * oldpath,const char * newpath)122 bool CacheFileStat::RenameCacheFileStat(const char* oldpath, const char* newpath)
123 {
124 if(!oldpath || '\0' == oldpath[0] || !newpath || '\0' == newpath[0]){
125 return false;
126 }
127
128 // stat path
129 std::string old_filestat;
130 std::string new_filestat;
131 if(!CacheFileStat::MakeCacheFileStatPath(oldpath, old_filestat, false) || !CacheFileStat::MakeCacheFileStatPath(newpath, new_filestat, false)){
132 return false;
133 }
134
135 // check new stat path
136 struct stat st;
137 if(0 == stat(new_filestat.c_str(), &st)){
138 // new stat path is existed, then unlink it.
139 if(-1 == unlink(new_filestat.c_str())){
140 S3FS_PRN_ERR("failed to unlink new cache file stat path(%s) by errno(%d).", new_filestat.c_str(), errno);
141 return false;
142 }
143 }
144
145 // check old stat path
146 if(0 != stat(old_filestat.c_str(), &st)){
147 // old stat path is not existed, then nothing to do any more.
148 return true;
149 }
150
151 // link and unlink
152 if(-1 == link(old_filestat.c_str(), new_filestat.c_str())){
153 S3FS_PRN_ERR("failed to link old cache file stat path(%s) to new cache file stat path(%s) by errno(%d).", old_filestat.c_str(), new_filestat.c_str(), errno);
154 return false;
155 }
156 if(-1 == unlink(old_filestat.c_str())){
157 S3FS_PRN_ERR("failed to unlink old cache file stat path(%s) by errno(%d).", old_filestat.c_str(), errno);
158 return false;
159 }
160 return true;
161 }
162
163 //------------------------------------------------
164 // CacheFileStat methods
165 //------------------------------------------------
CacheFileStat(const char * tpath)166 CacheFileStat::CacheFileStat(const char* tpath) : fd(-1)
167 {
168 if(tpath && '\0' != tpath[0]){
169 SetPath(tpath, true);
170 }
171 }
172
~CacheFileStat()173 CacheFileStat::~CacheFileStat()
174 {
175 Release();
176 }
177
SetPath(const char * tpath,bool is_open)178 bool CacheFileStat::SetPath(const char* tpath, bool is_open)
179 {
180 if(!tpath || '\0' == tpath[0]){
181 return false;
182 }
183 if(!Release()){
184 // could not close old stat file.
185 return false;
186 }
187 path = tpath;
188 if(!is_open){
189 return true;
190 }
191 return Open();
192 }
193
RawOpen(bool readonly)194 bool CacheFileStat::RawOpen(bool readonly)
195 {
196 if(path.empty()){
197 return false;
198 }
199 if(-1 != fd){
200 // already opened
201 return true;
202 }
203 // stat path
204 std::string sfile_path;
205 if(!CacheFileStat::MakeCacheFileStatPath(path.c_str(), sfile_path, true)){
206 S3FS_PRN_ERR("failed to create cache stat file path(%s)", path.c_str());
207 return false;
208 }
209 // open
210 if(readonly){
211 if(-1 == (fd = open(sfile_path.c_str(), O_RDONLY))){
212 S3FS_PRN_ERR("failed to read only open cache stat file path(%s) - errno(%d)", path.c_str(), errno);
213 return false;
214 }
215 }else{
216 if(-1 == (fd = open(sfile_path.c_str(), O_CREAT|O_RDWR, 0600))){
217 S3FS_PRN_ERR("failed to open cache stat file path(%s) - errno(%d)", path.c_str(), errno);
218 return false;
219 }
220 }
221 // lock
222 if(-1 == flock(fd, LOCK_EX)){
223 S3FS_PRN_ERR("failed to lock cache stat file(%s) - errno(%d)", path.c_str(), errno);
224 close(fd);
225 fd = -1;
226 return false;
227 }
228 // seek top
229 if(0 != lseek(fd, 0, SEEK_SET)){
230 S3FS_PRN_ERR("failed to lseek cache stat file(%s) - errno(%d)", path.c_str(), errno);
231 flock(fd, LOCK_UN);
232 close(fd);
233 fd = -1;
234 return false;
235 }
236 S3FS_PRN_DBG("file locked(%s - %s)", path.c_str(), sfile_path.c_str());
237
238 return true;
239 }
240
Open()241 bool CacheFileStat::Open()
242 {
243 return RawOpen(false);
244 }
245
ReadOnlyOpen()246 bool CacheFileStat::ReadOnlyOpen()
247 {
248 return RawOpen(true);
249 }
250
Release()251 bool CacheFileStat::Release()
252 {
253 if(-1 == fd){
254 // already release
255 return true;
256 }
257 // unlock
258 if(-1 == flock(fd, LOCK_UN)){
259 S3FS_PRN_ERR("failed to unlock cache stat file(%s) - errno(%d)", path.c_str(), errno);
260 return false;
261 }
262 S3FS_PRN_DBG("file unlocked(%s)", path.c_str());
263
264 if(-1 == close(fd)){
265 S3FS_PRN_ERR("failed to close cache stat file(%s) - errno(%d)", path.c_str(), errno);
266 return false;
267 }
268 fd = -1;
269
270 return true;
271 }
272
273 /*
274 * Local variables:
275 * tab-width: 4
276 * c-basic-offset: 4
277 * End:
278 * vim600: expandtab sw=4 ts=4 fdm=marker
279 * vim<600: expandtab sw=4 ts=4
280 */
281