From 92736802f68e7e17149871fba9ee15b27e67a695 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Sat, 2 May 2015 18:38:42 +0200 Subject: [PATCH] deferred_unlink: add (fix) the directory tree removal, fixes #2814 --- src/dvr/dvr_db.c | 37 +++++++----------------------------- src/tvheadend.h | 2 +- src/utils.c | 49 ++++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 55 insertions(+), 33 deletions(-) diff --git a/src/dvr/dvr_db.c b/src/dvr/dvr_db.c index 1187a789e..ce9c91a9f 100644 --- a/src/dvr/dvr_db.c +++ b/src/dvr/dvr_db.c @@ -2208,9 +2208,10 @@ dvr_val2pri(dvr_prio_t v) void dvr_entry_delete(dvr_entry_t *de) { + dvr_config_t *cfg = de->de_config; time_t t; struct tm tm; - char tbuf[64]; + char tbuf[64], *rdir; int r; t = dvr_entry_get_start_time(de); @@ -2229,38 +2230,14 @@ dvr_entry_delete(dvr_entry_t *de) #if ENABLE_INOTIFY dvr_inotify_del(de); #endif - r = deferred_unlink(de->de_filename); + rdir = NULL; + if(cfg->dvr_title_dir || cfg->dvr_channel_dir || cfg->dvr_dir_per_day || de->de_directory) + rdir = cfg->dvr_storage; + + r = deferred_unlink(de->de_filename, rdir); if(r && r != -ENOENT) tvhlog(LOG_WARNING, "dvr", "Unable to remove file '%s' from disk -- %s", de->de_filename, strerror(-errno)); - - /* Also delete directories, if they were created for the recording and if they are empty */ - - dvr_config_t *cfg = de->de_config; - char path[500]; - - snprintf(path, sizeof(path), "%s", cfg->dvr_storage); - - if(cfg->dvr_title_dir || cfg->dvr_channel_dir || cfg->dvr_dir_per_day || de->de_directory) { - char *p; - int l; - - l = strlen(de->de_filename); - p = alloca(l + 1); - memcpy(p, de->de_filename, l); - p[l--] = 0; - - for(; l >= 0; l--) { - if(p[l] == '/') { - p[l] = 0; - if(strncmp(p, cfg->dvr_storage, strlen(p)) == 0) - break; - if(rmdir(p) == -1) - break; - } - } - } - } dvr_entry_destroy(de, 1); } diff --git a/src/tvheadend.h b/src/tvheadend.h index 81b8930f2..be0948d5c 100644 --- a/src/tvheadend.h +++ b/src/tvheadend.h @@ -759,7 +759,7 @@ char *url_encode(char *str); int mpegts_word_count(const uint8_t *tsb, int len, uint32_t mask); -int deferred_unlink(const char *filename); +int deferred_unlink(const char *filename, const char *rootdir); static inline int32_t deltaI32(int32_t a, int32_t b) { return (a > b) ? (a - b) : (b - a); } static inline uint32_t deltaU32(uint32_t a, uint32_t b) { return (a > b) ? (a - b) : (b - a); } diff --git a/src/utils.c b/src/utils.c index 4e8030d96..0e621c71f 100644 --- a/src/utils.c +++ b/src/utils.c @@ -653,9 +653,45 @@ deferred_unlink_cb(void *s, int dearmed) free(s); } +typedef struct { + char *filename; + char *rootdir; +} deferred_unlink_t; + +static void +deferred_unlink_dir_cb(void *s, int dearmed) +{ + deferred_unlink_t *du = s; + char *p; + int l; + + if (unlink((const char *)du->filename)) + tvherror("main", "unable to remove file '%s'", (const char *)du->filename); + + /* Remove all directories up to rootdir */ + + l = strlen(du->filename) - 1; + p = du->filename; + + for(; l >= 0; l--) { + if(p[l] == '/') { + p[l] = 0; + if(strncmp(p, du->rootdir, l) == 0) + break; + if(rmdir(p) == -1) + break; + } + } + + free(du->filename); + free(du->rootdir); + free(du); +} + int -deferred_unlink(const char *filename) +deferred_unlink(const char *filename, const char *rootdir) { + deferred_unlink_t *du; char *s; size_t l; int r; @@ -672,6 +708,15 @@ deferred_unlink(const char *filename) free(s); return r; } - tasklet_arm_alloc(deferred_unlink_cb, s); + if (rootdir == NULL) + tasklet_arm_alloc(deferred_unlink_cb, s); + else { + du = calloc(1, sizeof(*du)); + if (du == NULL) + return -ENOMEM; + du->filename = s; + du->rootdir = strdup(rootdir); + tasklet_arm_alloc(deferred_unlink_dir_cb, du); + } return 0; } -- 2.47.2