From c1fc3392ae93ca90e34cb32c5d2e6b00c1fd4134 Mon Sep 17 00:00:00 2001 From: Paul Wayper Date: Thu, 13 Oct 2016 14:36:05 +1100 Subject: [PATCH 1/4] Add '-m'/'--mkdir' options to make file path like mkdir -p --- fswebcam.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 60 insertions(+), 2 deletions(-) diff --git a/fswebcam.c b/fswebcam.c index d855088..27143cc 100644 --- a/fswebcam.c +++ b/fswebcam.c @@ -93,6 +93,7 @@ enum fswc_options { OPT_EXEC, OPT_DUMPFRAME, OPT_FPS, + OPT_MKDIR, }; typedef struct { @@ -174,6 +175,7 @@ typedef struct { char *filename; char format; char compression; + uint8_t mkdir_output_file; } fswebcam_config_t; @@ -436,6 +438,47 @@ gdImage* fswc_gdImageDuplicate(gdImage* src) return(dst); } +int fswc_create_output_dir(char *filename) +{ + /* Step through the filename checking each segment of the path in turn. + * If one does not exist, try creating it. Return an error or 0 if + * all paths created successfully. Modifies but repairs filename */ + int pos; + int len = strlen(filename); + struct stat st = {0}; + + for (pos = 0; pos < len; pos++) + { + /* Look for a / character that divides the path. */ + for (pos = 0; pos < len && filename[pos] != '/'; pos++); + /* Terminate the string here for now */ + filename[pos] = '\0'; + /* Now stat and create if not found */ + if (stat(filename, &st) == -1) + { + if (errno == ENOENT) { + if (mkdir(filename, 0700) == -1) + { + if (pos < len) + { + filename[pos] = '/'; + } + return -1; + } + } + else + { + if (pos < len) + { + filename[pos] = '/'; + } + return -1; + } + } + } + return 0; +} + int fswc_output(fswebcam_config_t *config, char *name, gdImage *image) { char filename[FILENAME_MAX]; @@ -476,13 +519,22 @@ int fswc_output(fswebcam_config_t *config, char *name, gdImage *image) { /* Can't load the font - display a warning */ WARN("Unable to load font '%s': %s", config->font, err); - WARN("Disabling the the banner."); + WARN("Disabling the banner."); } } /* Draw the overlay. */ fswc_draw_overlay(config, config->overlay, im); + /* Do we need to check that the output directory exists? */ + if (config->mkdir_output_file) + { + int err = fswc_create_output_dir(filename); + if (err < 0) { + WARN("Unable to create path to file '%s': %s", filename, strerror(errno)); + } + } + /* Write to a file if a filename was given, otherwise stdout. */ if(strncmp(name, "-", 2)) f = fopen(filename, "wb"); else f = stdout; @@ -1143,6 +1195,7 @@ int fswc_usage() " --png Outputs a PNG image. (-1, 0 - 9)\n" " --save Save image to file.\n" " --exec Execute a command and wait for it to complete.\n" + " -m, --mkdir Make all the directories in the path\n" "\n"); return(0); @@ -1387,9 +1440,10 @@ int fswc_getopts(fswebcam_config_t *config, int argc, char *argv[]) {"png", required_argument, 0, OPT_PNG}, {"save", required_argument, 0, OPT_SAVE}, {"exec", required_argument, 0, OPT_EXEC}, + {"mkdir", no_argument, 0, OPT_MKDIR}, {0, 0, 0, 0} }; - char *opts = "-qc:vl:bL:d:i:t:f:D:T:r:F:s:S:p:R"; + char *opts = "-qc:vl:bL:d:i:t:f:D:T:r:F:s:S:p:Rm"; s.opts = opts; s.long_opts = long_opts; @@ -1424,6 +1478,7 @@ int fswc_getopts(fswebcam_config_t *config, int argc, char *argv[]) config->dumpframe = NULL; config->jobs = 0; config->job = NULL; + config->mkdir_output_file = 0; /* Don't report errors. */ opterr = 0; @@ -1530,6 +1585,9 @@ int fswc_getopts(fswebcam_config_t *config, int argc, char *argv[]) case 'R': config->use_read = -1; break; + case 'm': + config->mkdir_output_file = 1; + break; case OPT_LIST_FORMATS: config->list |= SRC_LIST_FORMATS; break; From f2aefa6b59b8db9c462833a6f87233caf6459ca2 Mon Sep 17 00:00:00 2001 From: Paul Wayper Date: Thu, 20 Oct 2016 09:31:21 +1100 Subject: [PATCH 2/4] Fixing logic in create_output_dir * Start from position 1 in string (no use looking at zero length paths) * Break if we hit the end of string (last part must be filename) * Better replacement of / in path. * Message if creating a directory. --- fswebcam.c | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/fswebcam.c b/fswebcam.c index 27143cc..5cb93d9 100644 --- a/fswebcam.c +++ b/fswebcam.c @@ -445,36 +445,41 @@ int fswc_create_output_dir(char *filename) * all paths created successfully. Modifies but repairs filename */ int pos; int len = strlen(filename); + int result; struct stat st = {0}; - for (pos = 0; pos < len; pos++) + /* We have to start with at least _some_ path, hence pos = 1 */ + for (pos = 1; pos < len; pos++) { /* Look for a / character that divides the path. */ - for (pos = 0; pos < len && filename[pos] != '/'; pos++); + for (; pos < len && filename[pos] != '/'; pos++); + if (pos == len) { + /* If we hit the end of the string - and there should not be a + * / there - then break. */ + break; + } /* Terminate the string here for now */ filename[pos] = '\0'; /* Now stat and create if not found */ - if (stat(filename, &st) == -1) + result = stat(filename, &st); + /* Can't put / back until after mkdir */ + if (result == -1) { if (errno == ENOENT) { - if (mkdir(filename, 0700) == -1) + result = mkdir(filename, 0700); + MSG("Creating path for '%s'", filename); + filename[pos] = '/'; + if (result == -1) { - if (pos < len) - { - filename[pos] = '/'; - } return -1; } } else { - if (pos < len) - { - filename[pos] = '/'; - } return -1; } } + filename[pos] = '/'; } return 0; } From 3c3392e618e90be04a76eed372a04b79f0a8408b Mon Sep 17 00:00:00 2001 From: Paul Wayper Date: Wed, 26 Oct 2016 09:34:01 +1100 Subject: [PATCH 3/4] Improvement: don't examine the file name, only the paths --- fswebcam.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/fswebcam.c b/fswebcam.c index 5cb93d9..265e402 100644 --- a/fswebcam.c +++ b/fswebcam.c @@ -448,14 +448,21 @@ int fswc_create_output_dir(char *filename) int result; struct stat st = {0}; + /* First move the 'length' back to the last slash, since we don't want to + * create a directory with the name of the filename */ + for (len > 0; filename[len] != '/'; len--); + if (len == 0) + { + return 0; + } /* We have to start with at least _some_ path, hence pos = 1 */ for (pos = 1; pos < len; pos++) { /* Look for a / character that divides the path. */ - for (; pos < len && filename[pos] != '/'; pos++); - if (pos == len) { - /* If we hit the end of the string - and there should not be a - * / there - then break. */ + for (; pos <= len && filename[pos] != '/'; pos++); + if (pos > len) { + /* If went past the last directory, then we've got no more path + * to create. */ break; } /* Terminate the string here for now */ From f2ae7f61db4c74747b1052f8ee6b7bf34fd97818 Mon Sep 17 00:00:00 2001 From: Paul Wayper Date: Wed, 26 Oct 2016 13:47:18 +1100 Subject: [PATCH 4/4] --mkdir option now works as well --- fswebcam.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/fswebcam.c b/fswebcam.c index 265e402..bfe4190 100644 --- a/fswebcam.c +++ b/fswebcam.c @@ -93,7 +93,6 @@ enum fswc_options { OPT_EXEC, OPT_DUMPFRAME, OPT_FPS, - OPT_MKDIR, }; typedef struct { @@ -1452,7 +1451,7 @@ int fswc_getopts(fswebcam_config_t *config, int argc, char *argv[]) {"png", required_argument, 0, OPT_PNG}, {"save", required_argument, 0, OPT_SAVE}, {"exec", required_argument, 0, OPT_EXEC}, - {"mkdir", no_argument, 0, OPT_MKDIR}, + {"mkdir", no_argument, 0, 'm'}, {0, 0, 0, 0} }; char *opts = "-qc:vl:bL:d:i:t:f:D:T:r:F:s:S:p:Rm";