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 ;
@@ -195,17 +169,6 @@ bool VFSImpl::mkdir(const char *fpath) {
195169 return false ;
196170 }
197171
198- VFSFileImpl f (this , fpath, " r" );
199- if (f && f.isDirectory ()) {
200- f.close ();
201- // log_w("%s already exists", fpath);
202- return true ;
203- } else if (f) {
204- f.close ();
205- log_e (" %s is a file" , fpath);
206- return false ;
207- }
208-
209172 char *temp = (char *)malloc (strlen (fpath) + strlen (_mountpoint) + 1 );
210173 if (!temp) {
211174 log_e (" malloc failed" );
@@ -215,9 +178,15 @@ bool VFSImpl::mkdir(const char *fpath) {
215178 strcpy (temp, _mountpoint);
216179 strcat (temp, fpath);
217180
181+ // Let mkdir() handle the error if directory already exists
218182 auto rc = ::mkdir (temp, ACCESSPERMS);
219183 free (temp);
220- return rc == 0 ;
184+
185+ // EEXIST means directory already exists, which is fine
186+ if (rc == 0 || errno == EEXIST) {
187+ return true ;
188+ }
189+ return false ;
221190}
222191
223192bool VFSImpl::rmdir (const char *fpath) {
@@ -231,16 +200,6 @@ bool VFSImpl::rmdir(const char *fpath) {
231200 return false ;
232201 }
233202
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-
244203 char *temp = (char *)malloc (strlen (fpath) + strlen (_mountpoint) + 1 );
245204 if (!temp) {
246205 log_e (" malloc failed" );
@@ -250,6 +209,7 @@ bool VFSImpl::rmdir(const char *fpath) {
250209 strcpy (temp, _mountpoint);
251210 strcat (temp, fpath);
252211
212+ // Let rmdir() handle the error if directory doesn't exist
253213 auto rc = ::rmdir (temp);
254214 free (temp);
255215 return rc == 0 ;
@@ -271,29 +231,30 @@ VFSFileImpl::VFSFileImpl(VFSImpl *fs, const char *fpath, const char *mode) : _fs
271231 return ;
272232 }
273233
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);
234+ // For read mode, check if file exists first to determine type
235+ if (!mode || mode[0 ] == ' r' ) {
236+ if (!stat (temp, &_stat)) {
237+ // file found
238+ if (S_ISREG (_stat.st_mode )) {
239+ _isDirectory = false ;
240+ _f = fopen (temp, mode);
241+ if (!_f) {
242+ log_e (" fopen(%s) failed" , temp);
243+ }
244+ if (_f && (_stat.st_blksize == 0 )) {
245+ setvbuf (_f, NULL , _IOFBF, DEFAULT_FILE_BUFFER_SIZE);
246+ }
247+ } else if (S_ISDIR (_stat.st_mode )) {
248+ _isDirectory = true ;
249+ _d = opendir (temp);
250+ if (!_d) {
251+ log_e (" opendir(%s) failed" , temp);
252+ }
253+ } else {
254+ log_e (" Unknown type 0x%08X for file %s" , ((_stat.st_mode ) & _IFMT), temp);
290255 }
291256 } 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' ) {
257+ // file not found
297258 // try to open as directory
298259 _d = opendir (temp);
299260 if (_d) {
@@ -302,16 +263,16 @@ VFSFileImpl::VFSFileImpl(VFSImpl *fs, const char *fpath, const char *mode) : _fs
302263 _isDirectory = false ;
303264 // log_w("stat(%s) failed", temp);
304265 }
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- }
266+ }
267+ } else {
268+ // lets create this new file
269+ _isDirectory = false ;
270+ _f = fopen (temp, mode);
271+ if (!_f) {
272+ log_e ( " fopen(%s) failed " , temp);
273+ }
274+ if (_f && (_stat. st_blksize == 0 )) {
275+ setvbuf (_f, NULL , _IOFBF, DEFAULT_FILE_BUFFER_SIZE);
315276 }
316277 }
317278 free (temp);
0 commit comments