emscripten-core / emscripten

Emscripten: An LLVM-to-WebAssembly Compiler
Other
25.82k stars 3.31k forks source link

Preferred way to clear/delete IDBFS database? #4952

Open dwhipps opened 7 years ago

dwhipps commented 7 years ago

What is the preferred way to delete / empty / clear a filesystem persisted using IDBFS?

I've found the deleteDatabase() and clear() functions that operate on an IDBFactory and IDBObectStore respectively, but there doesn't seem to be any way to get my IDBFS database name.

juj commented 7 years ago

It looks like IDBFS does not offer a direct API to do that. Currently it looks like the mount point name is taken as the database name: https://github.com/kripken/emscripten/blob/master/src/library_idbfs.js#L112. Perhaps that will be static enough to do a deletion?

Here is the code I use in one project for IndexedDB (though that one is not IDBFS based):

function deleteIndexedDBCache(dbName, onsuccess, onerror, onblocked) {
  var idb = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
  if (exinstingDBConnectionInstance) exinstingDBConnectionInstance.close(); // Otherwise .onblocked() event will occur
  var req = indexedDB.deleteDatabase(dbName);
  req.onsuccess = function() { console.log('Deleted IndexedDB cache ' + dbName + '!'); if (onsuccess) onsuccess(); }
  req.onerror = function() { console.error('Failed to delete IndexedDB cache ' + dbName + '!'); if (onerror) onerror(); }
  req.onblocked = function() { console.error('Failed to delete IndexedDB cache ' + dbName + ', DB was blocked!'); if (onblocked) onblocked(); }
}
dwhipps commented 7 years ago

@juj Thanks for this. I decided to go another route... I recursive-delete all files in the local (in memory) FileSystem, then immediately sync that back to the IDBFs. It seemed cleaner and doesn't rely on any undocumented behaviour.

mateusdigital commented 6 years ago

@dwhipps Can you provide an example how you did that?

I mean, I'm trying to do this exact same task and for some reason I could not get it right PS: I'm quite new on JS stuff so I really don't know if I'm missing some obvious thing!

Here's my "example" code:

function DeleteSfuff_Example() { 
  debugger;
  var l = FS.readdir("/Contents/Resources"); // My initial path
  for(var i in l) { 
    var item       = l[i]
    var fullpath = "/Contents/Resources/" + item;

    if(item == "." || item == "..") { 
      console.log("Ignoring -- " + fullpath);
      continue; 
    }

    var is_directory = true; 
    try { 
      console.log("REading dir: " + fullpath);
      FS.readdir(fullpath); // FS.isDir(fullpath) always return false IDK why...
    } catch(e) { 
      is_directory = false; 
      console.log(fullpath + " is not directory");
    }

    if(is_directory) { 
      continue;
    }

    try { 
      // Actually this isn't quite working...
      IDBStore.deleteFile("/Contents/Resources", fullpath, function(){});
    } catch(e) { 
      console.log("Failed to delete: " + fullpath);
    }
  }
}
dwhipps commented 6 years ago

Just write a function that deletes all files in a tree using a c-function (there are lots of examples of this out there), then call that function from JavaScript. Make sure you export the function and call it with ccall().

Here's one example. Use at your own risk!

// Deletes an entire folder tree of its files, but leaves directories
void deleteAllFilesInPath(const char* pathToRM) {
  DIR  *d;
  struct dirent *dir;
  d = opendir(pathToRM);
  if (d)
  {
    while ((dir = readdir(d)) != NULL)
    {
        std::string fullpath(pathToRM);
        fullpath += '/' + std::string(dir->d_name);

        if ((dir->d_type == DT_DIR) && strcmp(dir->d_name,".")!=0 && strcmp(dir->d_name,"..")!=0) {
          deleteAllFilesInPath(fullpath.c_str());
        } else if (dir->d_type != DT_DIR) {
          if (remove(fullpath.c_str()) != 0)
            printf("FAILED to delete file: %s\n",  dir->d_name);
        }
    }

    closedir(d);
  }
}
vadimkantorov commented 4 years ago

Also stumbled on this. Since IDBFS is often used for cache, a purge operation would be very useful @kripken

kripken commented 4 years ago

I agree it would be nice to add a helper function for this on IDBFS, reopening.

stale[bot] commented 2 years ago

This issue has been automatically marked as stale because there has been no activity in the past year. It will be closed automatically if no further activity occurs in the next 30 days. Feel free to re-open at any time if this issue is still relevant.

vadimkantorov commented 2 years ago

stale bump

ericoporto commented 1 year ago

hey, it would be nice to have this in JS land!

From what I can tell it's something like this maybe?

function force_rmdir(path) {
  FS.readdir(path).forEach(function(f) {
    if (f === '.' || f === '..') return;

    fpath = path + '/' + f;
    if (FS.analyzePath(fpath).object.isFolder) {
      force_rmdir(fpath);
      FS.rmdir(fpath);
    } else {
      FS.unlink(fpath);
    }
  });
}

And then later:

force_rmdir(my_path);
Module['FS_syncfs'](false, function(err){});
ericoporto commented 1 year ago

Actually despite that working, I think it's best to first move to a "trash" location, where the user could run the software and verify that the files removed did the intended result and then later actually remove from storage by deleting in the trash location. Essentially the recycle bin functionality.

I can't however figure out how to do a mv operation using FS library.