363 lines
9.3 KiB
Diff
363 lines
9.3 KiB
Diff
From c5ce534c03d0698509f3eb7ff90ca41610625570 Mon Sep 17 00:00:00 2001
|
|
From: Michael R Sweet <msweet@msweet.org>
|
|
Date: Thu, 19 Feb 2026 18:44:33 -0500
|
|
Subject: [PATCH] Updated and to escape more characters.
|
|
|
|
---
|
|
cups/file.c | 147 +++++++++++++++++++++++++++++++++---------------
|
|
cups/testfile.c | 63 +++++++++++++++++++--
|
|
3 files changed, 161 insertions(+), 50 deletions(-)
|
|
|
|
diff --git a/cups/file.c b/cups/file.c
|
|
index 7f48706335..a053368c82 100644
|
|
--- a/cups/file.c
|
|
+++ b/cups/file.c
|
|
@@ -725,11 +725,9 @@ cupsFileGetConf(cups_file_t *fp, /* I - CUPS file */
|
|
* Range check input...
|
|
*/
|
|
|
|
- DEBUG_printf(("2cupsFileGetConf(fp=%p, buf=%p, buflen=" CUPS_LLFMT
|
|
- ", value=%p, linenum=%p)", (void *)fp, (void *)buf, CUPS_LLCAST buflen, (void *)value, (void *)linenum));
|
|
+ DEBUG_printf(("2cupsFileGetConf(fp=%p, buf=%p, buflen=" CUPS_LLFMT ", value=%p, linenum=%p)", (void *)fp, (void *)buf, CUPS_LLCAST buflen, (void *)value, (void *)linenum));
|
|
|
|
- if (!fp || (fp->mode != 'r' && fp->mode != 's') ||
|
|
- !buf || buflen < 2 || !value)
|
|
+ if (!fp || (fp->mode != 'r' && fp->mode != 's') || !buf || buflen < 2 || !value)
|
|
{
|
|
if (value)
|
|
*value = NULL;
|
|
@@ -748,28 +746,30 @@ cupsFileGetConf(cups_file_t *fp, /* I - CUPS file */
|
|
(*linenum) ++;
|
|
|
|
/*
|
|
- * Strip any comments...
|
|
+ * Handle escaped characters and strip any comments...
|
|
*/
|
|
|
|
- if ((ptr = strchr(buf, '#')) != NULL)
|
|
+ for (ptr = buf; *ptr; ptr ++)
|
|
{
|
|
- if (ptr > buf && ptr[-1] == '\\')
|
|
+ if (*ptr == '#')
|
|
{
|
|
- // Unquote the #...
|
|
- _cups_strcpy(ptr - 1, ptr);
|
|
+ // Strip comment text...
|
|
+ *ptr = '\0';
|
|
+ break;
|
|
}
|
|
- else
|
|
+ else if (*ptr == '\\' && (ptr[1] == '\\' || ptr[1] == '#' || ptr[1] == 'n' || ptr[1] == 'r'))
|
|
{
|
|
- // Strip the comment and any trailing whitespace...
|
|
- while (ptr > buf)
|
|
- {
|
|
- if (!_cups_isspace(ptr[-1]))
|
|
- break;
|
|
+ /*
|
|
+ * \\, \#, \n, or \r, remove backslash and update the escaped char as
|
|
+ * needed...
|
|
+ */
|
|
|
|
- ptr --;
|
|
- }
|
|
+ _cups_strcpy(ptr, ptr + 1);
|
|
|
|
- *ptr = '\0';
|
|
+ if (*ptr == 'n')
|
|
+ *ptr = '\n';
|
|
+ else if (*ptr == 'r')
|
|
+ *ptr = '\r';
|
|
}
|
|
}
|
|
|
|
@@ -777,7 +777,11 @@ cupsFileGetConf(cups_file_t *fp, /* I - CUPS file */
|
|
* Strip leading whitespace...
|
|
*/
|
|
|
|
- for (ptr = buf; _cups_isspace(*ptr); ptr ++);
|
|
+ for (ptr = buf; *ptr; ptr ++)
|
|
+ {
|
|
+ if (!_cups_isspace(*ptr))
|
|
+ break;
|
|
+ }
|
|
|
|
if (ptr > buf)
|
|
_cups_strcpy(buf, ptr);
|
|
@@ -793,14 +797,16 @@ cupsFileGetConf(cups_file_t *fp, /* I - CUPS file */
|
|
*/
|
|
|
|
for (ptr = buf; *ptr; ptr ++)
|
|
+ {
|
|
if (_cups_isspace(*ptr))
|
|
break;
|
|
+ }
|
|
|
|
if (*ptr)
|
|
{
|
|
/*
|
|
* Have a value, skip any other spaces...
|
|
- */
|
|
+ */
|
|
|
|
while (_cups_isspace(*ptr))
|
|
*ptr++ = '\0';
|
|
@@ -810,12 +816,14 @@ cupsFileGetConf(cups_file_t *fp, /* I - CUPS file */
|
|
|
|
/*
|
|
* Strip trailing whitespace and > for lines that begin with <...
|
|
- */
|
|
+ */
|
|
|
|
ptr += strlen(ptr) - 1;
|
|
|
|
if (buf[0] == '<' && *ptr == '>')
|
|
+ {
|
|
*ptr-- = '\0';
|
|
+ }
|
|
else if (buf[0] == '<' && *ptr != '>')
|
|
{
|
|
/*
|
|
@@ -1497,19 +1505,18 @@ cupsFilePutChar(cups_file_t *fp, /* I - CUPS file */
|
|
/*
|
|
* 'cupsFilePutConf()' - Write a configuration line.
|
|
*
|
|
- * This function handles any comment escaping of the value.
|
|
+ * This function handles any escaping of the value.
|
|
*
|
|
* @since CUPS 1.4/macOS 10.6@
|
|
*/
|
|
|
|
ssize_t /* O - Number of bytes written or -1 on error */
|
|
cupsFilePutConf(cups_file_t *fp, /* I - CUPS file */
|
|
- const char *directive, /* I - Directive */
|
|
- const char *value) /* I - Value */
|
|
+ const char *directive, /* I - Directive */
|
|
+ const char *value) /* I - Value */
|
|
{
|
|
ssize_t bytes, /* Number of bytes written */
|
|
temp; /* Temporary byte count */
|
|
- const char *ptr; /* Pointer into value */
|
|
|
|
|
|
if (!fp || !directive || !*directive)
|
|
@@ -1518,34 +1525,84 @@ cupsFilePutConf(cups_file_t *fp, /* I - CUPS file */
|
|
if ((bytes = cupsFilePuts(fp, directive)) < 0)
|
|
return (-1);
|
|
|
|
- if (cupsFilePutChar(fp, ' ') < 0)
|
|
- return (-1);
|
|
- bytes ++;
|
|
-
|
|
if (value && *value)
|
|
{
|
|
- if ((ptr = strchr(value, '#')) != NULL)
|
|
+ const char *start, // Start of current fragment
|
|
+ *ptr; // Pointer into value
|
|
+
|
|
+ if (cupsFilePutChar(fp, ' ') < 0)
|
|
+ return (-1);
|
|
+ bytes ++;
|
|
+
|
|
+ for (start = ptr = value; *ptr; ptr ++)
|
|
+ {
|
|
+ if (strchr("#\\\n\r", *ptr) != NULL)
|
|
+ {
|
|
+ /*
|
|
+ * Character that needs to be escaped...
|
|
+ */
|
|
+
|
|
+ if (ptr > start)
|
|
+ {
|
|
+ /*
|
|
+ * Write unescaped portion...
|
|
+ */
|
|
+
|
|
+ if ((temp = cupsFileWrite(fp, start, (size_t)(ptr - start))) < 0)
|
|
+ return (-1);
|
|
+
|
|
+ bytes += temp;
|
|
+ }
|
|
+
|
|
+ start = ptr + 1;
|
|
+
|
|
+ if (*ptr == '\\')
|
|
+ {
|
|
+ /*
|
|
+ * "\" (for escaping)
|
|
+ */
|
|
+
|
|
+ if (cupsFilePuts(fp, "\\\\") < 0)
|
|
+ return (-1);
|
|
+ }
|
|
+ else if (*ptr == '#')
|
|
+ {
|
|
+ /*
|
|
+ * "#" (for comment)
|
|
+ */
|
|
+
|
|
+ if (cupsFilePuts(fp, "\\#") < 0)
|
|
+ return (-1);
|
|
+ }
|
|
+ else if (*ptr == '\n')
|
|
+ {
|
|
+ /*
|
|
+ * LF
|
|
+ */
|
|
+
|
|
+ if (cupsFilePuts(fp, "\\n") < 0)
|
|
+ return (-1);
|
|
+ }
|
|
+ else if (cupsFilePuts(fp, "\\r") < 0)
|
|
+ {
|
|
+ return (-1);
|
|
+ }
|
|
+
|
|
+ bytes += 2;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (ptr > start)
|
|
{
|
|
/*
|
|
- * Need to quote the first # in the info string...
|
|
+ * Write remaining unescaped portion...
|
|
*/
|
|
|
|
- if ((temp = cupsFileWrite(fp, value, (size_t)(ptr - value))) < 0)
|
|
- return (-1);
|
|
- bytes += temp;
|
|
-
|
|
- if (cupsFilePutChar(fp, '\\') < 0)
|
|
- return (-1);
|
|
- bytes ++;
|
|
+ if ((temp = cupsFileWrite(fp, start, (size_t)(ptr - start))) < 0)
|
|
+ return (-1);
|
|
|
|
- if ((temp = cupsFilePuts(fp, ptr)) < 0)
|
|
- return (-1);
|
|
bytes += temp;
|
|
}
|
|
- else if ((temp = cupsFilePuts(fp, value)) < 0)
|
|
- return (-1);
|
|
- else
|
|
- bytes += temp;
|
|
}
|
|
|
|
if (cupsFilePutChar(fp, '\n') < 0)
|
|
diff --git a/cups/testfile.c b/cups/testfile.c
|
|
index 4f8fbefaf4..97293f9399 100644
|
|
--- a/cups/testfile.c
|
|
+++ b/cups/testfile.c
|
|
@@ -552,6 +552,17 @@ read_write_tests(int compression) /* I - Use compression? */
|
|
off_t length; /* Length of file */
|
|
static const char *partial_line = "partial line";
|
|
/* Partial line */
|
|
+ static const char * const values[] = /* cupsFileGet/PutConf values */
|
|
+ {
|
|
+ "simple",
|
|
+ "'single-quoted value'",
|
|
+ "\"double-quoted value\"",
|
|
+ "value with # comment",
|
|
+ "value with \n newline",
|
|
+ "value with \r carriage return",
|
|
+ "value with \\ backslash",
|
|
+ "pathological\r\nvalue\\#with comment"
|
|
+ };
|
|
|
|
|
|
/*
|
|
@@ -628,6 +639,27 @@ read_write_tests(int compression) /* I - Use compression? */
|
|
status ++;
|
|
}
|
|
|
|
+ /*
|
|
+ * cupsFilePutConf()
|
|
+ */
|
|
+
|
|
+ fputs("cupsFilePutConf(): ", stdout);
|
|
+ for (i = 0; i < (int)(sizeof(values) / sizeof(values[0])); i ++)
|
|
+ {
|
|
+ if (cupsFilePutConf(fp, "TestConf", values[i]) < 0)
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ if (i >= (int)(sizeof(values) / sizeof(values[0])))
|
|
+ {
|
|
+ puts("PASS");
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ printf("FAIL (%s)\n", strerror(errno));
|
|
+ status ++;
|
|
+ }
|
|
+
|
|
/*
|
|
* cupsFilePutChar()
|
|
*/
|
|
@@ -684,11 +716,11 @@ read_write_tests(int compression) /* I - Use compression? */
|
|
|
|
fputs("cupsFileTell(): ", stdout);
|
|
|
|
- if ((length = cupsFileTell(fp)) == 81933283)
|
|
+ if ((length = cupsFileTell(fp)) == 81933542)
|
|
puts("PASS");
|
|
else
|
|
{
|
|
- printf("FAIL (" CUPS_LLFMT " instead of 81933283)\n", CUPS_LLCAST length);
|
|
+ printf("FAIL (" CUPS_LLFMT " instead of 81933542)\n", CUPS_LLCAST length);
|
|
status ++;
|
|
}
|
|
|
|
@@ -766,7 +798,7 @@ read_write_tests(int compression) /* I - Use compression? */
|
|
|
|
linenum = 1;
|
|
|
|
- fputs("cupsFileGetConf(): ", stdout);
|
|
+ fputs("cupsFileGetConf(TestLine): ", stdout);
|
|
|
|
for (i = 0, value = NULL; i < 1000; i ++)
|
|
if (!cupsFileGetConf(fp, line, sizeof(line), &value, &linenum))
|
|
@@ -789,6 +821,27 @@ read_write_tests(int compression) /* I - Use compression? */
|
|
status ++;
|
|
}
|
|
|
|
+ fputs("cupsFileGetConf(TestConf): ", stdout);
|
|
+
|
|
+ for (i = 0; i < (int)(sizeof(values) / sizeof(values[0])); i ++)
|
|
+ {
|
|
+ if (!cupsFileGetConf(fp, line, sizeof(line), &value, &linenum))
|
|
+ {
|
|
+ printf("FAIL (%s)\n", strerror(errno));
|
|
+ status ++;
|
|
+ break;
|
|
+ }
|
|
+ else if (_cups_strcasecmp(line, "TestConf") || !value || strcmp(value, values[i]))
|
|
+ {
|
|
+ printf("FAIL (Expected 'TestConf %s', got '%s %s')\n", values[i], line, value);
|
|
+ status ++;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (i >= (int)(sizeof(values) / sizeof(values[0])))
|
|
+ puts("PASS");
|
|
+
|
|
/*
|
|
* cupsFileGetChar()
|
|
*/
|
|
@@ -869,11 +922,11 @@ read_write_tests(int compression) /* I - Use compression? */
|
|
|
|
fputs("cupsFileTell(): ", stdout);
|
|
|
|
- if ((length = cupsFileTell(fp)) == 81933283)
|
|
+ if ((length = cupsFileTell(fp)) == 81933542)
|
|
puts("PASS");
|
|
else
|
|
{
|
|
- printf("FAIL (" CUPS_LLFMT " instead of 81933283)\n", CUPS_LLCAST length);
|
|
+ printf("FAIL (" CUPS_LLFMT " instead of 81933542)\n", CUPS_LLCAST length);
|
|
status ++;
|
|
}
|
|
|