<dt>Recording system path
<dd>Path to where Tvheadend will write recorded events. If components of the path does not exist, Tvheadend will try to create them.
- <dt>File permissions for recordings (3-byte octal)
+ <dt>File permissions
<dd>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.
<table class="hts-doc-text" border="0">
<tr><td>666 == rw-rw-rw-</td></tr>
</table>
- See also <i>Directory permissions for recordings</i> in <i>Subdirectory Options</i>.
+ Note that your default user umask applies, so 666 with umask 002 will produce 664.
+
+ See also <i>Directory permissions</i> in <i>Subdirectory Options</i>.
<dt>Rewrite PAT in passthrough mode
<dd>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.
<b>Subdirectory Options</b>
<hr>
- <dt>Directory permissions for recordings (3-byte octal)
+ <dt>Directory permissions
<dd>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.
<table class="hts-doc-text" border="0">
<tr><td>777 == rwxrwxrwx</td></tr>
</table>
- See also <i>File permissions for recordings</i> in <i>Recroding File Options</i>.
+ Note that your default user umask applies, so 777 with umask 002 will produce 775.
+
+ See also <i>File permissions</i> in <i>Recording File Options</i>.
<dt>Make sub-directories per day
<dd>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)
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;
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);
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;
/* 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);
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",
*
*/
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);
}
*
*/
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);
}
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)
free(title);
}
-/* IH DEBUG */
+// Very ugly hack alert!
+// Convert my nasty stored-as-decimal permissions into literal octal equivalent (i.e. 777 => 0777)
+
+ int decimal_perms = cfg->dvr_muxcnf.m_directory_permissions;
+ int octal_perms = ((decimal_perms / 100) << 6) | ((decimal_perms % 100 / 10) << 3) | (decimal_perms % 10);
- 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));
+// Create directory path
- /* */
- if(makedirs(path, atoi(cfg->dvr_directory_permissions)) != 0) {
+ if(makedirs(path, octal_perms) != 0) {
return -1;
}
}
}
- /* 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\", "
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;
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",
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;
{
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;
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;
*
*/
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",
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,
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;
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));
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));
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,
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',
/* 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'
});
/* Main (form) panel */
-
+
var confpanel = new Ext.FormPanel({
title : 'Digital Video Recorder',
iconCls : 'drive',