@@ -72,6 +72,19 @@ static void TRACE_LOG(const char *fmt, ...) {
7272
7373using namespace sqlitevfs ;
7474
75+
76+ // / Checks whether zName is a path to a regular file
77+ static bool isRegularFile (const char *zName) {
78+ struct stat st;
79+ if (stat (zName, &st) == 0 ) {
80+ if (S_ISREG (st.st_mode )) {
81+ return true ;
82+ }
83+ }
84+ return false ;
85+ }
86+
87+
7588class IdbPage {
7689public:
7790 IdbPage () {}
@@ -90,8 +103,7 @@ class IdbPage {
90103 }
91104
92105 bool exists () const {
93- if (FILE *f = fopen (filename.c_str (), " r" )) {
94- fclose (f);
106+ if (isRegularFile (filename.c_str ())) {
95107 return true ;
96108 }
97109 else {
@@ -164,11 +176,7 @@ class IdbPage {
164176
165177struct IdbFileSize : public IdbPage {
166178 IdbFileSize () : IdbPage() {}
167- IdbFileSize (sqlite3_filename file_name, bool autoload = true ) : IdbPage(file_name, IDBVFS_SIZE_KEY) {
168- if (autoload) {
169- load ();
170- }
171- }
179+ IdbFileSize (sqlite3_filename file_name) : IdbPage(file_name, IDBVFS_SIZE_KEY) {}
172180
173181 void load () {
174182 scan_into (" %lu" , &file_size);
@@ -210,28 +218,49 @@ struct IdbFile : public SQLiteFileImpl {
210218 sqlite3_filename file_name;
211219 IdbFileSize file_size;
212220 std::vector<uint8_t > journal_data;
221+ FILE *regular_file;
213222 bool is_db;
214223
215224 IdbFile () {}
216- IdbFile (sqlite3_filename file_name, bool is_db) : file_name(file_name), file_size(file_name), is_db(is_db) {}
225+ IdbFile (sqlite3_filename file_name, bool is_db)
226+ : file_name(file_name)
227+ , file_size(file_name)
228+ , is_db(is_db)
229+ {
230+ if (isRegularFile (file_name)) {
231+ regular_file = fopen (file_name, " r+" );
232+ }
233+ else {
234+ regular_file = nullptr ;
235+ file_size.load ();
236+ }
237+ }
217238
218239 int iVersion () const override {
219240 return 1 ;
220241 }
221242
222243 int xClose () override {
244+ if (regular_file) {
245+ fclose (regular_file);
246+ }
223247 return SQLITE_OK;
224248 }
225249
226250 int xRead (void *p, int iAmt, sqlite3_int64 iOfst) override {
227251 TRACE_LOG (" READ %s %d @ %ld" , file_name, iAmt, iOfst);
228- if (iAmt + iOfst > file_size.get ()) {
229- TRACE_LOG (" > %d" , false );
230- return SQLITE_IOERR_SHORT_READ;
231- }
232-
233252 int result;
234- if (is_db) {
253+ if (regular_file) {
254+ fseek (regular_file, iOfst, SEEK_SET);
255+ size_t bytes_read = fread (p, 1 , iAmt, regular_file);
256+ if (bytes_read < iAmt) {
257+ result = SQLITE_IOERR_SHORT_READ;
258+ }
259+ else {
260+ result = SQLITE_OK;
261+ }
262+ }
263+ else if (is_db) {
235264 result = readDb (p, iAmt, iOfst);
236265 }
237266 else {
@@ -244,7 +273,17 @@ struct IdbFile : public SQLiteFileImpl {
244273 int xWrite (const void *p, int iAmt, sqlite3_int64 iOfst) override {
245274 TRACE_LOG (" WRITE %s %d @ %ld" , file_name, iAmt, iOfst);
246275 int result;
247- if (is_db) {
276+ if (regular_file) {
277+ fseek (regular_file, iOfst, SEEK_SET);
278+ size_t stored_bytes = fwrite (p, 1 , iAmt, regular_file);
279+ if (stored_bytes < iAmt) {
280+ result = SQLITE_IOERR_WRITE;
281+ }
282+ else {
283+ result = SQLITE_OK;
284+ }
285+ }
286+ else if (is_db) {
248287 result = writeDb (p, iAmt, iOfst);
249288 }
250289 else {
@@ -256,8 +295,14 @@ struct IdbFile : public SQLiteFileImpl {
256295
257296 int xTruncate (sqlite3_int64 size) override {
258297 TRACE_LOG (" TRUNCATE %s to %ld" , file_name, size);
259- file_size.set (size);
260- TRACE_LOG (" > %d" , true );
298+ if (regular_file) {
299+ int fd = fileno (regular_file);
300+ ftruncate (fd, size);
301+ }
302+ else {
303+ file_size.set (size);
304+ }
305+ TRACE_LOG (" > %d" , SQLITE_OK);
261306 return SQLITE_OK;
262307 }
263308
@@ -269,7 +314,13 @@ struct IdbFile : public SQLiteFileImpl {
269314 file.store (journal_data);
270315 file_size.set (journal_data.size ());
271316 }
272- bool success = file_size.sync ();
317+ bool success;
318+ if (regular_file) {
319+ success = fflush (regular_file) == 0 && fsync (fileno (regular_file)) == 0 ;
320+ }
321+ else {
322+ success = file_size.sync ();
323+ }
273324 INLINE_JS ({
274325 Module.idbvfsSyncfs ();
275326 });
@@ -279,7 +330,11 @@ struct IdbFile : public SQLiteFileImpl {
279330
280331 int xFileSize (sqlite3_int64 *pSize) override {
281332 TRACE_LOG (" FILE SIZE %s" , file_name);
282- if (!journal_data.empty ()) {
333+ if (regular_file) {
334+ fseek (regular_file, 0 , SEEK_END);
335+ *pSize = ftell (regular_file);
336+ }
337+ else if (!journal_data.empty ()) {
283338 *pSize = journal_data.size ();
284339 }
285340 else {
@@ -391,7 +446,16 @@ struct IdbVfs : public SQLiteVfsImpl<IdbFile> {
391446
392447 int xDelete (const char *zName, int syncDir) override {
393448 TRACE_LOG (" DELETE %s" , zName);
394- IdbFileSize file_size (zName, false );
449+ if (isRegularFile (zName)) {
450+ if (unlink (zName) == 0 ) {
451+ return SQLITE_OK;
452+ }
453+ else {
454+ return SQLITE_IOERR_DELETE;
455+ }
456+ }
457+
458+ IdbFileSize file_size (zName);
395459 if (!file_size.remove ()) {
396460 return SQLITE_IOERR_DELETE;
397461 }
@@ -412,8 +476,13 @@ struct IdbVfs : public SQLiteVfsImpl<IdbFile> {
412476 case SQLITE_ACCESS_EXISTS:
413477 case SQLITE_ACCESS_READWRITE:
414478 case SQLITE_ACCESS_READ:
415- IdbFileSize file_size (zName, false );
416- *pResOut = file_size.exists ();
479+ if (isRegularFile (zName)) {
480+ *pResOut = 1 ;
481+ }
482+ else {
483+ IdbFileSize file_size (zName);
484+ *pResOut = file_size.exists ();
485+ }
417486 TRACE_LOG (" > %d" , *pResOut);
418487 return SQLITE_OK;
419488 }
0 commit comments