{
while (optind < argc) {
#if defined(CLIENT_read)
- char *val = xs_read(xsh, xth, argv[optind], NULL);
+ struct expanding_buffer ebuf;
+ unsigned len;
+ char *val = xs_read(xsh, xth, argv[optind], &len);
if (val == NULL) {
warnx("couldn't read path %s", argv[optind]);
return 1;
}
if (prefix)
output("%s: ", argv[optind]);
- output("%s\n", val);
+ output("%s\n", sanitise_value(&ebuf, val, len));
free(val);
optind++;
#elif defined(CLIENT_write)
- if (!xs_write(xsh, xth, argv[optind], argv[optind + 1],
- strlen(argv[optind + 1]))) {
+ struct expanding_buffer ebuf;
+ char *val_spec = argv[optind + 1];
+ unsigned len;
+ expanding_buffer_ensure(&ebuf, strlen(val_spec)+1);
+ unsanitise_value(ebuf.buf, &len, val_spec);
+ if (!xs_write(xsh, xth, argv[optind], ebuf.buf, len)) {
warnx("could not write path %s", argv[optind]);
return 1;
}
slash = strrchr(p, '/');
if (slash) {
char *val;
+ unsigned len;
*slash = '\0';
- val = xs_read(xsh, xth, p, NULL);
- if (val && strlen(val) == 0) {
+ val = xs_read(xsh, xth, p, &len);
+ if (val && len == 0) {
unsigned int num;
char ** list = xs_directory(xsh, xth, p, &num);
#include <string.h>
#include <stdlib.h>
#include <errno.h>
+#include <assert.h>
#include "xs_lib.h"
/* Common routines for the Xen store daemon and client library. */
return num;
}
+
+char *expanding_buffer_ensure(struct expanding_buffer *ebuf, int min_avail)
+{
+ int want;
+ char *got;
+
+ if (ebuf->avail >= min_avail)
+ return ebuf->buf;
+
+ if (min_avail >= INT_MAX/3)
+ return 0;
+
+ want = ebuf->avail + min_avail + 10;
+ got = realloc(ebuf->buf, want);
+ if (!got)
+ return 0;
+
+ ebuf->buf = got;
+ ebuf->avail = want;
+ return ebuf->buf;
+}
+
+char *sanitise_value(struct expanding_buffer *ebuf,
+ const char *val, unsigned len)
+{
+ int used, remain, c;
+ unsigned char *ip;
+
+#define ADD(c) (ebuf->buf[used++] = (c))
+#define ADDF(f,c) (used += sprintf(ebuf->buf+used, (f), (c)))
+
+ assert(len < INT_MAX/5);
+
+ ip = (unsigned char *)val;
+ used = 0;
+ remain = len;
+
+ if (!expanding_buffer_ensure(ebuf, remain + 1))
+ return NULL;
+
+ while (remain-- > 0) {
+ c= *ip++;
+
+ if (c >= ' ' && c <= '~' && c != '\\') {
+ ADD(c);
+ continue;
+ }
+
+ if (!expanding_buffer_ensure(ebuf, used + remain + 5))
+ /* for "<used>\\nnn<remain>\0" */
+ return 0;
+
+ ADD('\\');
+ switch (c) {
+ case '\t': ADD('t'); break;
+ case '\n': ADD('n'); break;
+ case '\r': ADD('r'); break;
+ case '\\': ADD('\\'); break;
+ default:
+ if (c < 010) ADDF("%03o", c);
+ else ADDF("x%02x", c);
+ }
+ }
+
+ ADD(0);
+ assert(used <= ebuf->avail);
+ return ebuf->buf;
+
+#undef ADD
+#undef ADDF
+}
+
+void unsanitise_value(char *out, unsigned *out_len_r, const char *in)
+{
+ const char *ip;
+ char *op;
+ unsigned c;
+ int n;
+
+ for (ip = in, op = out; (c = *ip++); *op++ = c) {
+ if (c == '\\') {
+ c = *ip++;
+
+#define GETF(f) do { \
+ n = 0; \
+ sscanf(ip, f "%n", &c, &n); \
+ ip += n; \
+ } while (0)
+
+ switch (c) {
+ case 't': c= '\t'; break;
+ case 'n': c= '\n'; break;
+ case 'r': c= '\r'; break;
+ case '\\': c= '\\'; break;
+ case 'x': GETF("%2x"); break;
+ case '0': case '4':
+ case '1': case '5':
+ case '2': case '6':
+ case '3': case '7': --ip; GETF("%3o"); break;
+ case 0: --ip; break;
+ default:;
+ }
+#undef GETF
+ }
+ }
+
+ *op = 0;
+
+ if (out_len_r)
+ *out_len_r = op - out;
+}
/* Given a string and a length, count how many strings (nul terms). */
unsigned int xs_count_strings(const char *strings, unsigned int len);
+/* Sanitising (quoting) possibly-binary strings. */
+struct expanding_buffer {
+ char *buf;
+ int avail;
+};
+
+/* Ensure that given expanding buffer has at least min_avail characters. */
+char *expanding_buffer_ensure(struct expanding_buffer *, int min_avail);
+
+/* sanitise_value() may return NULL if malloc fails. */
+char *sanitise_value(struct expanding_buffer *, const char *val, unsigned len);
+
+/* *out_len_r on entry is ignored; out must be at least strlen(in)+1 bytes. */
+void unsanitise_value(char *out, unsigned *out_len_r, const char *in);
+
#endif /* _XS_LIB_H */
void print_dir(struct xs_handle *h, char *path, int cur_depth, int show_perms)
{
+ static struct expanding_buffer ebuf;
char **e;
char newpath[STRING_MAX], *val;
int newpath_len;
}
else {
if (max_width < (linewid + len + TAG_LEN)) {
- printf(" = \"%.*s...\"",
- (int)(max_width - TAG_LEN - linewid), val);
+ printf(" = \"%.*s\\...\"",
+ (int)(max_width - TAG_LEN - linewid),
+ sanitise_value(&ebuf, val, len));
}
else {
- linewid += printf(" = \"%s\"", val);
+ linewid += printf(" = \"%s\"",
+ sanitise_value(&ebuf, val, len));
if (show_perms) {
putchar(' ');
for (linewid++;