diff --git a/docs/html/config_dvr.html b/docs/html/config_dvr.html
index c5417002..703ef47a 100644
--- a/docs/html/config_dvr.html
+++ b/docs/html/config_dvr.html
@@ -75,7 +75,7 @@
Recording system path
Path to where Tvheadend will write recorded events. If components of the path does not exist, Tvheadend will try to create them.
- File permissions for recordings (3-byte octal)
+ File permissions
The permissions to be set on the resultant recording files. This is useful if you need to manipulate the files after recording under a different user ID, e.g. to chop out commercials.
@@ -86,7 +86,9 @@
666 == rw-rw-rw- |
- See also Directory permissions for recordings in Subdirectory Options.
+ Note that your default user umask applies, so 666 with umask 002 will produce 664.
+
+ See also Directory permissions in Subdirectory Options.
Rewrite PAT in passthrough mode
Rewrite the original Program Association Table to only include the active service. When this option is disabled, Tvheadend will write the original PAT as broadcast, which lists all services from the original multiplex.
@@ -105,7 +107,7 @@
Subdirectory Options
- Directory permissions for recordings (3-byte octal)
+ Directory permissions
The permissions to be set on any sub-directories created for recordings. This is useful if you need to manipulate the files after recording under a different user ID, e.g. to chop out commercials.
@@ -116,7 +118,9 @@
777 == rwxrwxrwx |
- See also File permissions for recordings in Recroding File Options.
+ Note that your default user umask applies, so 777 with umask 002 will produce 775.
+
+ See also File permissions in Recording File Options.
Make sub-directories per day
If checked, create a new directory per day in the recording system path. Only days when anything is recorded will be created. The format of the directory will be 'YYYY-MM-DD' (ISO standard)
diff --git a/src/dvr/dvr.h b/src/dvr/dvr.h
index 4b8c6529..301aba63 100644
--- a/src/dvr/dvr.h
+++ b/src/dvr/dvr.h
@@ -29,8 +29,6 @@
typedef struct dvr_config {
char *dvr_config_name;
char *dvr_storage;
- char *dvr_file_permissions;
- char *dvr_directory_permissions;
uint32_t dvr_retention_days;
int dvr_flags;
char *dvr_postproc;
@@ -334,9 +332,9 @@ void dvr_storage_set(dvr_config_t *cfg, const char *storage);
void dvr_container_set(dvr_config_t *cfg, const char *container);
-void dvr_file_permissions_set(dvr_config_t *cfg, const char *permissions);
+void dvr_file_permissions_set(dvr_config_t *cfg, int permissions);
-void dvr_directory_permissions_set(dvr_config_t *cfg, const char *permissions);
+void dvr_directory_permissions_set(dvr_config_t *cfg, int permissions);
void dvr_mux_cache_set(dvr_config_t *cfg, int mcache);
diff --git a/src/dvr/dvr_db.c b/src/dvr/dvr_db.c
index 3bc68d1f..70e3983e 100644
--- a/src/dvr/dvr_db.c
+++ b/src/dvr/dvr_db.c
@@ -1133,9 +1133,9 @@ dvr_init(void)
htsmsg_get_s32(m, "post-extra-time", &cfg->dvr_extra_time_post);
htsmsg_get_u32(m, "retention-days", &cfg->dvr_retention_days);
tvh_str_set(&cfg->dvr_storage, htsmsg_get_str(m, "storage"));
- tvh_str_set(&cfg->dvr_file_permissions, htsmsg_get_str(m, "file-permissions"));
- tvh_str_set(&cfg->dvr_directory_permissions, htsmsg_get_str(m, "directory-permissions"));
-
+ htsmsg_get_s32(m, "file-permissions", &cfg->dvr_muxcnf.m_file_permissions);
+ htsmsg_get_s32(m, "directory-permissions", &cfg->dvr_muxcnf.m_directory_permissions);
+
if(!htsmsg_get_u32(m, "day-dir", &u32) && u32)
cfg->dvr_flags |= DVR_DIR_PER_DAY;
@@ -1315,9 +1315,10 @@ dvr_config_create(const char *name)
/* dup detect */
cfg->dvr_dup_detect_episode = 1; // detect dup episodes
- /* Recording file and directory permissions */
- strcpy(cfg->dvr_file_permissions,"664");
- strcpy(cfg->dvr_directory_permissions,"775");
+ /* Default recording file and directory permissions */
+ /* Note that these are decimal literal equivalents of the octal - they get converted later. Yes, it's a kludge. Sue me. */
+ cfg->dvr_muxcnf.m_file_permissions = 664;
+ cfg->dvr_muxcnf.m_directory_permissions = 775;
LIST_INSERT_HEAD(&dvrconfigs, cfg, config_link);
@@ -1357,11 +1358,12 @@ static void
dvr_save(dvr_config_t *cfg)
{
htsmsg_t *m = htsmsg_create_map();
+
if (cfg->dvr_config_name != NULL && strlen(cfg->dvr_config_name) != 0)
htsmsg_add_str(m, "config_name", cfg->dvr_config_name);
htsmsg_add_str(m, "storage", cfg->dvr_storage);
- htsmsg_add_str(m, "file-permissions", cfg->dvr_file_permissions);
- htsmsg_add_str(m, "directory-permissions", cfg->dvr_directory_permissions);
+ htsmsg_add_u32(m, "file-permissions", cfg->dvr_muxcnf.m_file_permissions);
+ htsmsg_add_u32(m, "directory-permissions", cfg->dvr_muxcnf.m_directory_permissions);
htsmsg_add_u32(m, "container", cfg->dvr_mc);
htsmsg_add_u32(m, "cache", cfg->dvr_muxcnf.m_cache);
htsmsg_add_u32(m, "rewrite-pat",
@@ -1410,12 +1412,12 @@ dvr_storage_set(dvr_config_t *cfg, const char *storage)
*
*/
void
-dvr_file_permissions_set(dvr_config_t *cfg, const char *permissions)
+dvr_file_permissions_set(dvr_config_t *cfg, int permissions)
{
- if(cfg->dvr_file_permissions != NULL && !strcmp(cfg->dvr_file_permissions, permissions))
+ if(cfg->dvr_muxcnf.m_file_permissions == permissions)
return;
- tvh_str_set(&cfg->dvr_file_permissions, permissions);
+ cfg->dvr_muxcnf.m_file_permissions = permissions;
dvr_save(cfg);
}
@@ -1423,12 +1425,12 @@ dvr_file_permissions_set(dvr_config_t *cfg, const char *permissions)
*
*/
void
-dvr_directory_permissions_set(dvr_config_t *cfg, const char *permissions)
+dvr_directory_permissions_set(dvr_config_t *cfg, int permissions)
{
- if(cfg->dvr_directory_permissions != NULL && !strcmp(cfg->dvr_directory_permissions, permissions))
+ if(cfg->dvr_muxcnf.m_directory_permissions == permissions)
return;
- tvh_str_set(&cfg->dvr_directory_permissions, permissions);
+ cfg->dvr_muxcnf.m_directory_permissions = permissions;
dvr_save(cfg);
}
@@ -1496,7 +1498,7 @@ dvr_retention_set(dvr_config_t *cfg, int days)
cfg->dvr_retention_days = days;
- /* Also, rearm all timres */
+ /* Also, rearm all timers */
LIST_FOREACH(de, &dvrentries, de_global_link)
if(de->de_sched_state == DVR_COMPLETED)
diff --git a/src/dvr/dvr_rec.c b/src/dvr/dvr_rec.c
index b4a8596d..2d9938ab 100644
--- a/src/dvr/dvr_rec.c
+++ b/src/dvr/dvr_rec.c
@@ -204,13 +204,15 @@ pvr_generate_filename(dvr_entry_t *de, const streaming_start_t *ss)
free(title);
}
-/* IH DEBUG */
-
- tvhlog(LOG_DEBUG, "dvr_rec - pvr_generate_filename", "Using string directory permissions: \"%s\"", cfg->dvr_directory_permissions);
- tvhlog(LOG_DEBUG, "dvr_rec - pvr_generate_filename", "Using int directory permissions: \"%i\"", atoi(cfg->dvr_directory_permissions));
+// Very ugly hack alert!
+// Convert my nasty stored-as-decimal permissions into literal octal equivalent (i.e. 777 => 0777)
- /* */
- if(makedirs(path, atoi(cfg->dvr_directory_permissions)) != 0) {
+ int decimal_perms = cfg->dvr_muxcnf.m_directory_permissions;
+ int octal_perms = ((decimal_perms / 100) << 6) | ((decimal_perms % 100 / 10) << 3) | (decimal_perms % 10);
+
+// Create directory path
+
+ if(makedirs(path, octal_perms) != 0) {
return -1;
}
@@ -324,11 +326,6 @@ dvr_rec_start(dvr_entry_t *de, const streaming_start_t *ss)
}
}
- /* IH DEBUG */
-
- tvhlog(LOG_DEBUG, "dvr - dvr_rec_start", "Using file/directory permissions: \"%s\", \"%s\"",
- cfg->dvr_file_permissions, cfg->dvr_directory_permissions);
-
tvhlog(LOG_INFO, "dvr", "%s from "
"adapter: \"%s\", "
"network: \"%s\", mux: \"%s\", provider: \"%s\", "
diff --git a/src/muxer.h b/src/muxer.h
index a89c2884..1f85822f 100644
--- a/src/muxer.h
+++ b/src/muxer.h
@@ -47,8 +47,10 @@ typedef enum {
typedef struct muxer_config {
int m_flags;
muxer_cache_type_t m_cache;
- char *m_file_permissions;
- char *m_directory_permissions;
+// directory_permissions should really be in dvr.h as it's not really needed for the muxer
+// but it's kept with file_permissions for neatness
+ int m_file_permissions;
+ int m_directory_permissions;
} muxer_config_t;
struct muxer;
diff --git a/src/muxer/muxer_pass.c b/src/muxer/muxer_pass.c
index 4914c5f4..abde3689 100644
--- a/src/muxer/muxer_pass.c
+++ b/src/muxer/muxer_pass.c
@@ -378,11 +378,15 @@ pass_muxer_open_file(muxer_t *m, const char *filename)
int fd;
pass_muxer_t *pm = (pass_muxer_t*)m;
-/* IH DEBUG */
-
- tvhlog(LOG_DEBUG, "muxer_pass - pass_muxer_open_file", "Using file permissions: \"%s\"", pm->m_config.m_file_permissions);
+// Very ugly hack alert!
+// Convert my nasty stored-as-decimal permissions into literal octal equivalent (i.e. 777 => 0777)
- fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, pm->m_config.m_file_permissions);
+ int decimal_perms = pm->m_config.m_file_permissions;
+ int octal_perms = ((decimal_perms / 100) << 6) | ((decimal_perms % 100 / 10) << 3) | (decimal_perms % 10);
+
+ tvhlog(LOG_DEBUG, "pass", "Creating file \"%s\" with octal permissions \"%o\"", filename, octal_perms);
+ fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, octal_perms);
+
if(fd < 0) {
pm->pm_error = errno;
tvhlog(LOG_ERR, "pass", "%s: Unable to create file, open failed -- %s",
@@ -551,11 +555,6 @@ pass_muxer_create(muxer_container_type_t mc, const muxer_config_t *m_cfg)
if(mc != MC_PASS && mc != MC_RAW)
return NULL;
-/* debugging to see if the variable is available here */
-/* IH 26 March */
-
- tvhlog(LOG_DEBUG, "muxer_pass - pass_muxer_create", "Using file permissions: \"%s\"", m_cfg->m_file_permissions);
-
pm = calloc(1, sizeof(pass_muxer_t));
pm->m_open_stream = pass_muxer_open_stream;
pm->m_open_file = pass_muxer_open_file;
diff --git a/src/muxer/muxer_tvh.c b/src/muxer/muxer_tvh.c
index 4cd2e126..715328ce 100644
--- a/src/muxer/muxer_tvh.c
+++ b/src/muxer/muxer_tvh.c
@@ -138,10 +138,6 @@ tvh_muxer_open_file(muxer_t *m, const char *filename)
{
tvh_muxer_t *tm = (tvh_muxer_t*)m;
-/* IH DEBUG */
-
- tvhlog(LOG_DEBUG, "muxer_tvh - tvh_muxer_open", "Using file permissions: \"%s\"", tm->m_config.m_file_permissions);
-
if(mk_mux_open_file(tm->tm_ref, filename, tm->m_config.m_file_permissions)) {
tm->m_errors++;
return -1;
@@ -231,11 +227,6 @@ tvh_muxer_create(muxer_container_type_t mc, const muxer_config_t *m_cfg)
if(mc != MC_MATROSKA && mc != MC_WEBM)
return NULL;
-/* debugging to see if the variable is available here */
-/* IH 26 March */
-
- tvhlog(LOG_DEBUG, "muxer_tvh - tvh_muxer_create", "Using file permissions: \"%s\"", m_cfg->m_file_permissions);
-
tm = calloc(1, sizeof(tvh_muxer_t));
tm->m_open_stream = tvh_muxer_open_stream;
tm->m_open_file = tvh_muxer_open_file;
diff --git a/src/muxer/tvh/mkmux.c b/src/muxer/tvh/mkmux.c
index 2199676a..a810cb35 100644
--- a/src/muxer/tvh/mkmux.c
+++ b/src/muxer/tvh/mkmux.c
@@ -1046,15 +1046,17 @@ mk_mux_open_stream(mk_mux_t *mkm, int fd)
*
*/
int
-mk_mux_open_file(mk_mux_t *mkm, const char *filename, const char *permissions)
+mk_mux_open_file(mk_mux_t *mkm, const char *filename, int permissions)
{
int fd;
-/* IH DEBUG */
-
- tvhlog(LOG_DEBUG, "mkmux - tmk_mux_open_file", "Using file permissions: \"%s\"", permissions);
+// Very ugly hack alert!
+// Convert my nasty stored-as-decimal permissions into literal octal equivalent (i.e. 777 => 0777)
- fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, permissions);
+ int octal_perms = ((permissions / 100) << 6) | ((permissions % 100 / 10) << 3) | (permissions % 10);
+
+ tvhlog(LOG_DEBUG, "mkv", "Creating file \"%s\" with octal permissions \"%o\"", filename, octal_perms);
+ fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, octal_perms);
if(fd < 0) {
mkm->error = errno;
tvhlog(LOG_ERR, "mkv", "%s: Unable to create file, open failed -- %s",
diff --git a/src/muxer/tvh/mkmux.h b/src/muxer/tvh/mkmux.h
index c9a3908f..a107ff40 100644
--- a/src/muxer/tvh/mkmux.h
+++ b/src/muxer/tvh/mkmux.h
@@ -30,7 +30,7 @@ struct event;
mk_mux_t *mk_mux_create(muxer_t *m, int webm);
-int mk_mux_open_file (mk_mux_t *mkm, const char *filename, const char *permissions);
+int mk_mux_open_file (mk_mux_t *mkm, const char *filename, int permissions);
int mk_mux_open_stream(mk_mux_t *mkm, int fd);
int mk_mux_init(mk_mux_t *mkm, const char *title,
diff --git a/src/utils.c b/src/utils.c
index 69f51c28..6eab4ec7 100644
--- a/src/utils.c
+++ b/src/utils.c
@@ -397,6 +397,7 @@ makedirs ( const char *inpath, int mode )
path[x] = 0;
if (stat(path, &st)) {
err = mkdir(path, mode);
+ tvhlog(LOG_DEBUG, "settings", "Creating directory \"%s\" with octal permissions \"%o\"", path, mode);
} else {
err = S_ISDIR(st.st_mode) ? 0 : 1;
errno = ENOTDIR;
diff --git a/src/webui/extjs.c b/src/webui/extjs.c
index 8c0de11c..9e369644 100755
--- a/src/webui/extjs.c
+++ b/src/webui/extjs.c
@@ -1126,8 +1126,8 @@ extjs_dvr(http_connection_t *hc, const char *remain, void *opaque)
r = htsmsg_create_map();
htsmsg_add_str(r, "storage", cfg->dvr_storage);
htsmsg_add_str(r, "container", muxer_container_type2txt(cfg->dvr_mc));
- htsmsg_add_str(r, "file-permissions", cfg->dvr_muxcnf.m_file_permissions);
- htsmsg_add_str(r, "directory-permissions", cfg->dvr_muxcnf.m_directory_permissions);
+ htsmsg_add_u32(r, "filePermissions", cfg->dvr_muxcnf.m_file_permissions);
+ htsmsg_add_u32(r, "dirPermissions", cfg->dvr_muxcnf.m_directory_permissions);
htsmsg_add_u32(r, "cache", cfg->dvr_muxcnf.m_cache);
htsmsg_add_u32(r, "rewritePAT",
!!(cfg->dvr_muxcnf.m_flags & MC_REWRITE_PAT));
@@ -1168,12 +1168,12 @@ extjs_dvr(http_connection_t *hc, const char *remain, void *opaque)
if((s = http_arg_get(&hc->hc_req_args, "container")) != NULL)
dvr_container_set(cfg,s);
-
+
if((s = http_arg_get(&hc->hc_req_args, "filePermissions")) != NULL)
- dvr_file_permissions_set(cfg,s);
-
- if((s = http_arg_get(&hc->hc_req_args, "directoryPermissions")) != NULL)
- dvr_directory_permissions_set(cfg,s);
+ dvr_file_permissions_set(cfg,atoi(s));
+
+ if((s = http_arg_get(&hc->hc_req_args, "dirPermissions")) != NULL)
+ dvr_directory_permissions_set(cfg,atoi(s));
if((s = http_arg_get(&hc->hc_req_args, "cache")) != NULL)
dvr_mux_cache_set(cfg,atoi(s));
diff --git a/src/webui/static/app/dvr.js b/src/webui/static/app/dvr.js
index 324045d9..63fde3f5 100644
--- a/src/webui/static/app/dvr.js
+++ b/src/webui/static/app/dvr.js
@@ -744,11 +744,11 @@ tvheadend.dvrsettings = function() {
var confreader = new Ext.data.JsonReader({
root : 'dvrSettings'
- }, [ 'storage', 'postproc', 'retention', 'dayDirs', 'channelDirs',
+ }, [ 'storage', 'filePermissions', 'dirPermissions', 'postproc', 'retention', 'dayDirs', 'channelDirs',
'channelInTitle', 'container', 'cache', 'dateInTitle', 'timeInTitle',
'preExtraTime', 'postExtraTime', 'whitespaceInTitle', 'titleDirs',
'episodeInTitle', 'cleanTitle', 'tagFiles', 'commSkip', 'subtitleInTitle',
- 'episodeBeforeDate', 'rewritePAT', 'rewritePMT', 'filePermissions', 'dirPermissions' ]);
+ 'episodeBeforeDate', 'rewritePAT', 'rewritePMT' ]);
var confcombo = new Ext.form.ComboBox({
store : tvheadend.configNames,
@@ -828,13 +828,20 @@ tvheadend.dvrsettings = function() {
fieldLabel : 'Recording system path',
name : 'storage'
});
+
+/* NB: recordingPermissions is defined as a TextField for validation purposes (leading zeros), but is ultimately a decimal number */
var recordingPermissions = new Ext.form.TextField({
- regex : /^[0-7]{3}$/,
+ regex : /^[0-7]{3}$/,
maskRe : /[0-7]/,
- fieldLabel : 'File permissions for recordings (3-byte octal)',
+ width : 100,
+ allowBlank : false,
+ blankText : 'You must provide a value - use octal chmod notation, e.g. 664',
+ fieldLabel : 'File permissions (octal, e.g. 664)',
name : 'filePermissions'
});
+
+/* TO DO - Add 'override user umask?' option, then trigger fchmod in mkmux.c, muxer_pass.c after file created */
var PATrewrite = new Ext.form.Checkbox({
fieldLabel : 'Rewrite PAT in passthrough mode',
@@ -858,13 +865,20 @@ tvheadend.dvrsettings = function() {
/* Subdirectories and filename handling */
+/* NB: directoryPermissions is defined as a TextField for validation purposes (leading zeros), but is ultimately a decimal number */
+
var directoryPermissions = new Ext.form.TextField({
- regex : /^[0-7]{3}$/,
+ regex : /^[0-7]{3}$/,
maskRe : /[0-7]/,
- fieldLabel : 'Directory permissions for recordings (3-byte octal)',
+ width : 100,
+ allowBlank : false,
+ blankText : 'You must provide a value - use octal chmod notation, e.g. 775',
+ fieldLabel : 'Directory permissions (octal, e.g. 775)',
name : 'dirPermissions'
});
+/* TO DO - Add 'override user umask?' option, then trigger fchmod in utils.c after directory created */
+
var dirsPerDay = new Ext.form.Checkbox({
fieldLabel : 'Make subdirectories per day',
name : 'dayDirs'
@@ -963,7 +977,7 @@ tvheadend.dvrsettings = function() {
});
/* Main (form) panel */
-
+
var confpanel = new Ext.FormPanel({
title : 'Digital Video Recorder',
iconCls : 'drive',