diff --git a/apps/lang/english.lang b/apps/lang/english.lang
index 4d73592..333e8ea 100644
--- a/apps/lang/english.lang
+++ b/apps/lang/english.lang
@@ -13287,3 +13287,31 @@
*: "of"
+
+ id: LANG_PLUGIN_LEAK_FILE_HANDLES
+ desc: inform the user that a plugin has file handle leaks
+ user: core
+
+ *: "Plugin leaks file handles"
+
+
+ *: "Plugin leaks file handles"
+
+
+ *: "Plugin leaks file handles"
+
+
+
+ id: LANG_REPORT_PROBLEM
+ desc: inform the user that he/she should report the problem
+ user: core
+
+ *: "Please report this problem"
+
+
+ *: "Please report this problem"
+
+
+ *: "Please report this problem"
+
+
diff --git a/apps/plugin.c b/apps/plugin.c
index 47f2465..687eee1 100644
--- a/apps/plugin.c
+++ b/apps/plugin.c
@@ -63,6 +63,15 @@
#define PREFIX
#endif
+#if defined(HAVE_PLUGIN_CHECK_OPEN_CLOSE) && (MAX_OPEN_FILES>32)
+#warning "MAX_OPEN_FILES>32, disabling plugin file open/close checking"
+#undef HAVE_PLUGIN_CHECK_OPEN_CLOSE
+#endif
+
+#ifdef HAVE_PLUGIN_CHECK_OPEN_CLOSE
+static unsigned int open_files;
+#endif
+
#ifdef SIMULATOR
static unsigned char pluginbuf[PLUGIN_BUFFER_SIZE];
void *sim_plugin_load(char *plugin, void **pd);
@@ -83,6 +92,13 @@ static char current_plugin[MAX_PATH];
char *plugin_get_current_filename(void);
+#ifdef HAVE_PLUGIN_CHECK_OPEN_CLOSE
+/* Some wrappers used to monitor open and close and detect leaks*/
+static int open_wrapper(const char* pathname, int flags);
+static int close_wrapper(int fd);
+static int creat_wrapper(const char *pathname);
+#endif
+
static const struct plugin_api rockbox_api = {
/* lcd */
@@ -276,11 +292,20 @@ static const struct plugin_api rockbox_api = {
#endif /* HAVE_BUTTON_LIGHT */
/* file */
+#ifdef HAVE_PLUGIN_CHECK_OPEN_CLOSE
+ (open_func)open_wrapper,
+ close_wrapper,
+#else
(open_func)PREFIX(open),
PREFIX(close),
+ #endif
(read_func)PREFIX(read),
PREFIX(lseek),
+#ifdef HAVE_PLUGIN_CHECK_OPEN_CLOSE
+ (creat_func)creat_wrapper,
+#else
(creat_func)PREFIX(creat),
+#endif
(write_func)PREFIX(write),
PREFIX(remove),
PREFIX(rename),
@@ -804,8 +829,12 @@ int plugin_load(const char* plugin, const void* parameter)
touchscreen_set_mode(TOUCHSCREEN_BUTTON);
#endif
+#ifdef HAVE_PLUGIN_CHECK_OPEN_CLOSE
+ open_files = 0;
+#endif
+
rc = hdr->entry_point(parameter);
-
+
/* Go back to the global setting in case the plugin changed it */
#ifdef HAVE_TOUCHSCREEN
touchscreen_set_mode(global_settings.touch_mode);
@@ -849,6 +878,25 @@ int plugin_load(const char* plugin, const void* parameter)
if (pfn_tsr_exit == NULL)
plugin_loaded = false;
+#ifdef HAVE_PLUGIN_CHECK_OPEN_CLOSE
+ if(open_files != 0 && !plugin_loaded)
+ {
+ int fd;
+ logf("Plugin '%s' leaks file handles", plugin);
+
+ static const char *lines[] =
+ { ID2P(LANG_PLUGIN_LEAK_FILE_HANDLES),
+ ID2P(LANG_REPORT_PROBLEM) };
+ static const struct text_message message={ lines, 2 };
+ button_clear_queue(); /* Empty the keyboard buffer */
+ gui_syncyesno_run(&message, NULL, NULL);
+
+ for(fd=0; fd < MAX_OPEN_FILES; fd++)
+ if(open_files & (1<= 0)
+ open_files |= 1<= 0)
+ open_files &= (~(1<= 0)
+ open_files |= (1<