1313// limitations under the License.
1414
1515#include " vfs_api.h"
16+ #include < errno.h>
17+ #include < stdlib.h>
18+ #include < string.h>
1619
1720using namespace fs ;
1821
@@ -38,67 +41,49 @@ FileImplPtr VFSImpl::open(const char *fpath, const char *mode, const bool create
3841 strcpy (temp, _mountpoint);
3942 strcat (temp, fpath);
4043
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+ }
8573 }
8674
87- token = strchr (token + 1 , ' /' );
88- if (token != NULL ) {
89- end_index = (token - fpath);
90- memset (folder, 0 , strlen (folder));
91- }
75+ free (folder);
9276 }
9377
94- free (folder);
78+ // Try to open the file directly - let fopen handle errors
9579 free (temp);
9680 return std::make_shared<VFSFileImpl>(this , fpath, mode);
9781 }
9882
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
10085 free (temp);
101- return FileImplPtr ( );
86+ return std::make_shared<VFSFileImpl>( this , fpath, mode );
10287}
10388
10489bool VFSImpl::exists (const char *fpath) {
@@ -125,10 +110,7 @@ bool VFSImpl::rename(const char *pathFrom, const char *pathTo) {
125110 log_e (" bad arguments" );
126111 return false ;
127112 }
128- if (!exists (pathFrom)) {
129- log_e (" %s does not exists" , pathFrom);
130- return false ;
131- }
113+
132114 size_t mountpointLen = strlen (_mountpoint);
133115 char *temp1 = (char *)malloc (strlen (pathFrom) + mountpointLen + 1 );
134116 if (!temp1) {
@@ -148,6 +130,7 @@ bool VFSImpl::rename(const char *pathFrom, const char *pathTo) {
148130 strcpy (temp2, _mountpoint);
149131 strcat (temp2, pathTo);
150132
133+ // Let rename() handle the error if source doesn't exist
151134 auto rc = ::rename (temp1, temp2);
152135 free (temp1);
153136 free (temp2);
@@ -165,16 +148,6 @@ bool VFSImpl::remove(const char *fpath) {
165148 return false ;
166149 }
167150
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-
178151 char *temp = (char *)malloc (strlen (fpath) + strlen (_mountpoint) + 1 );
179152 if (!temp) {
180153 log_e (" malloc failed" );
@@ -184,6 +157,7 @@ bool VFSImpl::remove(const char *fpath) {
184157 strcpy (temp, _mountpoint);
185158 strcat (temp, fpath);
186159
160+ // Let unlink() handle the error if file doesn't exist
187161 auto rc = unlink (temp);
188162 free (temp);
189163 return rc == 0 ;
@@ -231,16 +205,6 @@ bool VFSImpl::rmdir(const char *fpath) {
231205 return false ;
232206 }
233207
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-
244208 char *temp = (char *)malloc (strlen (fpath) + strlen (_mountpoint) + 1 );
245209 if (!temp) {
246210 log_e (" malloc failed" );
@@ -250,6 +214,7 @@ bool VFSImpl::rmdir(const char *fpath) {
250214 strcpy (temp, _mountpoint);
251215 strcat (temp, fpath);
252216
217+ // Let rmdir() handle the error if directory doesn't exist
253218 auto rc = ::rmdir (temp);
254219 free (temp);
255220 return rc == 0 ;
@@ -271,29 +236,30 @@ VFSFileImpl::VFSFileImpl(VFSImpl *fs, const char *fpath, const char *mode) : _fs
271236 return ;
272237 }
273238
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);
290260 }
291261 } 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
297263 // try to open as directory
298264 _d = opendir (temp);
299265 if (_d) {
@@ -302,16 +268,16 @@ VFSFileImpl::VFSFileImpl(VFSImpl *fs, const char *fpath, const char *mode) : _fs
302268 _isDirectory = false ;
303269 // log_w("stat(%s) failed", temp);
304270 }
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);
315281 }
316282 }
317283 free (temp);
0 commit comments