13
13
// limitations under the License.
14
14
15
15
#include " vfs_api.h"
16
+ #include < errno.h>
17
+ #include < stdlib.h>
18
+ #include < string.h>
16
19
17
20
using namespace fs ;
18
21
@@ -38,67 +41,49 @@ FileImplPtr VFSImpl::open(const char *fpath, const char *mode, const bool create
38
41
strcpy (temp, _mountpoint);
39
42
strcat (temp, fpath);
40
43
41
- struct stat st;
42
- // file found
43
- if (!stat (temp, &st)) {
44
- free (temp);
45
- if (S_ISREG (st.st_mode ) || S_ISDIR (st.st_mode )) {
46
- return std::make_shared<VFSFileImpl>(this , fpath, mode);
47
- }
48
- log_e (" %s has wrong mode 0x%08X" , fpath, st.st_mode );
49
- return FileImplPtr ();
50
- }
51
-
52
- // try to open this as directory (might be mount point)
53
- DIR *d = opendir (temp);
54
- if (d) {
55
- closedir (d);
56
- free (temp);
57
- return std::make_shared<VFSFileImpl>(this , fpath, mode);
58
- }
59
-
60
- // file not found but mode permits file creation without folder creation
61
- if ((mode && mode[0 ] != ' r' ) && (!create)) {
62
- free (temp);
63
- return std::make_shared<VFSFileImpl>(this , fpath, mode);
64
- }
65
-
66
- // //file not found but mode permits file creation and folder creation
67
- if ((mode && mode[0 ] != ' r' ) && create) {
68
-
69
- char *token;
70
- char *folder = (char *)malloc (strlen (fpath) + 1 );
71
-
72
- int start_index = 0 ;
73
- int end_index = 0 ;
74
-
75
- token = strchr (fpath + 1 , ' /' );
76
- end_index = (token - fpath);
77
-
78
- while (token != NULL ) {
79
- memcpy (folder, fpath + start_index, end_index - start_index);
80
- folder[end_index - start_index] = ' \0 ' ;
81
-
82
- if (!VFSImpl::mkdir (folder)) {
83
- log_e (" Creating folder: %s failed!" , folder);
84
- return FileImplPtr ();
44
+ // Try to open as file first - let the file operation handle errors
45
+ if (mode && mode[0 ] != ' r' ) {
46
+ // For write modes, attempt to create directories if needed
47
+ if (create) {
48
+ char *token;
49
+ char *folder = (char *)malloc (strlen (fpath) + 1 );
50
+
51
+ int start_index = 0 ;
52
+ int end_index = 0 ;
53
+
54
+ token = strchr (fpath + 1 , ' /' );
55
+ end_index = (token - fpath);
56
+
57
+ while (token != NULL ) {
58
+ memcpy (folder, fpath + start_index, end_index - start_index);
59
+ folder[end_index - start_index] = ' \0 ' ;
60
+
61
+ if (!VFSImpl::mkdir (folder)) {
62
+ log_e (" Creating folder: %s failed!" , folder);
63
+ free (folder);
64
+ free (temp);
65
+ return FileImplPtr ();
66
+ }
67
+
68
+ token = strchr (token + 1 , ' /' );
69
+ if (token != NULL ) {
70
+ end_index = (token - fpath);
71
+ memset (folder, 0 , strlen (folder));
72
+ }
85
73
}
86
74
87
- token = strchr (token + 1 , ' /' );
88
- if (token != NULL ) {
89
- end_index = (token - fpath);
90
- memset (folder, 0 , strlen (folder));
91
- }
75
+ free (folder);
92
76
}
93
77
94
- free (folder);
78
+ // Try to open the file directly - let fopen handle errors
95
79
free (temp);
96
80
return std::make_shared<VFSFileImpl>(this , fpath, mode);
97
81
}
98
82
99
- log_e (" %s does not exist, no permits for creation" , temp);
83
+ // For read mode, let the VFSFileImpl constructor handle the file opening
84
+ // This avoids the TOCTOU race condition while maintaining proper functionality
100
85
free (temp);
101
- return FileImplPtr ( );
86
+ return std::make_shared<VFSFileImpl>( this , fpath, mode );
102
87
}
103
88
104
89
bool VFSImpl::exists (const char *fpath) {
@@ -125,10 +110,7 @@ bool VFSImpl::rename(const char *pathFrom, const char *pathTo) {
125
110
log_e (" bad arguments" );
126
111
return false ;
127
112
}
128
- if (!exists (pathFrom)) {
129
- log_e (" %s does not exists" , pathFrom);
130
- return false ;
131
- }
113
+
132
114
size_t mountpointLen = strlen (_mountpoint);
133
115
char *temp1 = (char *)malloc (strlen (pathFrom) + mountpointLen + 1 );
134
116
if (!temp1) {
@@ -148,6 +130,7 @@ bool VFSImpl::rename(const char *pathFrom, const char *pathTo) {
148
130
strcpy (temp2, _mountpoint);
149
131
strcat (temp2, pathTo);
150
132
133
+ // Let rename() handle the error if source doesn't exist
151
134
auto rc = ::rename (temp1, temp2);
152
135
free (temp1);
153
136
free (temp2);
@@ -165,16 +148,6 @@ bool VFSImpl::remove(const char *fpath) {
165
148
return false ;
166
149
}
167
150
168
- VFSFileImpl f (this , fpath, " r" );
169
- if (!f || f.isDirectory ()) {
170
- if (f) {
171
- f.close ();
172
- }
173
- log_e (" %s does not exists or is directory" , fpath);
174
- return false ;
175
- }
176
- f.close ();
177
-
178
151
char *temp = (char *)malloc (strlen (fpath) + strlen (_mountpoint) + 1 );
179
152
if (!temp) {
180
153
log_e (" malloc failed" );
@@ -184,6 +157,7 @@ bool VFSImpl::remove(const char *fpath) {
184
157
strcpy (temp, _mountpoint);
185
158
strcat (temp, fpath);
186
159
160
+ // Let unlink() handle the error if file doesn't exist
187
161
auto rc = unlink (temp);
188
162
free (temp);
189
163
return rc == 0 ;
@@ -231,16 +205,6 @@ bool VFSImpl::rmdir(const char *fpath) {
231
205
return false ;
232
206
}
233
207
234
- VFSFileImpl f (this , fpath, " r" );
235
- if (!f || !f.isDirectory ()) {
236
- if (f) {
237
- f.close ();
238
- }
239
- log_e (" %s does not exists or is a file" , fpath);
240
- return false ;
241
- }
242
- f.close ();
243
-
244
208
char *temp = (char *)malloc (strlen (fpath) + strlen (_mountpoint) + 1 );
245
209
if (!temp) {
246
210
log_e (" malloc failed" );
@@ -250,6 +214,7 @@ bool VFSImpl::rmdir(const char *fpath) {
250
214
strcpy (temp, _mountpoint);
251
215
strcat (temp, fpath);
252
216
217
+ // Let rmdir() handle the error if directory doesn't exist
253
218
auto rc = ::rmdir (temp);
254
219
free (temp);
255
220
return rc == 0 ;
@@ -271,29 +236,30 @@ VFSFileImpl::VFSFileImpl(VFSImpl *fs, const char *fpath, const char *mode) : _fs
271
236
return ;
272
237
}
273
238
274
- if (!stat (temp, &_stat)) {
275
- // file found
276
- if (S_ISREG (_stat.st_mode )) {
277
- _isDirectory = false ;
278
- _f = fopen (temp, mode);
279
- if (!_f) {
280
- log_e (" fopen(%s) failed" , temp);
281
- }
282
- if (_f && (_stat.st_blksize == 0 )) {
283
- setvbuf (_f, NULL , _IOFBF, DEFAULT_FILE_BUFFER_SIZE);
284
- }
285
- } else if (S_ISDIR (_stat.st_mode )) {
286
- _isDirectory = true ;
287
- _d = opendir (temp);
288
- if (!_d) {
289
- log_e (" opendir(%s) failed" , temp);
239
+ // For read mode, check if file exists first to determine type
240
+ if (!mode || mode[0 ] == ' r' ) {
241
+ if (!stat (temp, &_stat)) {
242
+ // file found
243
+ if (S_ISREG (_stat.st_mode )) {
244
+ _isDirectory = false ;
245
+ _f = fopen (temp, mode);
246
+ if (!_f) {
247
+ log_e (" fopen(%s) failed" , temp);
248
+ }
249
+ if (_f && (_stat.st_blksize == 0 )) {
250
+ setvbuf (_f, NULL , _IOFBF, DEFAULT_FILE_BUFFER_SIZE);
251
+ }
252
+ } else if (S_ISDIR (_stat.st_mode )) {
253
+ _isDirectory = true ;
254
+ _d = opendir (temp);
255
+ if (!_d) {
256
+ log_e (" opendir(%s) failed" , temp);
257
+ }
258
+ } else {
259
+ log_e (" Unknown type 0x%08X for file %s" , ((_stat.st_mode ) & _IFMT), temp);
290
260
}
291
261
} else {
292
- log_e (" Unknown type 0x%08X for file %s" , ((_stat.st_mode ) & _IFMT), temp);
293
- }
294
- } else {
295
- // file not found
296
- if (!mode || mode[0 ] == ' r' ) {
262
+ // file not found
297
263
// try to open as directory
298
264
_d = opendir (temp);
299
265
if (_d) {
@@ -302,16 +268,16 @@ VFSFileImpl::VFSFileImpl(VFSImpl *fs, const char *fpath, const char *mode) : _fs
302
268
_isDirectory = false ;
303
269
// log_w("stat(%s) failed", temp);
304
270
}
305
- } else {
306
- // lets create this new file
307
- _isDirectory = false ;
308
- _f = fopen (temp, mode) ;
309
- if (!_f) {
310
- log_e ( " fopen(%s) failed " , temp);
311
- }
312
- if (_f && (_stat. st_blksize == 0 )) {
313
- setvbuf (_f, NULL , _IOFBF, DEFAULT_FILE_BUFFER_SIZE);
314
- }
271
+ }
272
+ } else {
273
+ // lets create this new file
274
+ _isDirectory = false ;
275
+ _f = fopen (temp, mode);
276
+ if (!_f) {
277
+ log_e ( " fopen(%s) failed " , temp);
278
+ }
279
+ if (_f && (_stat. st_blksize == 0 )) {
280
+ setvbuf (_f, NULL , _IOFBF, DEFAULT_FILE_BUFFER_SIZE);
315
281
}
316
282
}
317
283
free (temp);
0 commit comments