diff options
author | Werner Koch <[email protected]> | 2010-01-28 20:48:51 +0000 |
---|---|---|
committer | Werner Koch <[email protected]> | 2010-01-28 20:48:51 +0000 |
commit | 46783cbb85e9a0cc50e57acaaa62d41c07fa6c13 (patch) | |
tree | 2d23d20b6bb1c601cb8241ccc4fd1a3b9c4bb79a /tests | |
parent | First take on Server for W32CE (diff) | |
download | libassuan-46783cbb85e9a0cc50e57acaaa62d41c07fa6c13.tar.gz libassuan-46783cbb85e9a0cc50e57acaaa62d41c07fa6c13.zip |
Add some commands to the test server.
Diffstat (limited to 'tests')
-rw-r--r-- | tests/ce-server.c | 299 | ||||
-rw-r--r-- | tests/common.h | 99 |
2 files changed, 391 insertions, 7 deletions
diff --git a/tests/ce-server.c b/tests/ce-server.c index 1f4a46d..06f67af 100644 --- a/tests/ce-server.c +++ b/tests/ce-server.c @@ -38,6 +38,11 @@ #endif #include <errno.h> +#ifdef HAVE_W32CE_SYSTEM +#ifndef FILE_ATTRIBUTE_ROMSTATICREF +#define FILE_ATTRIBUTE_ROMSTATICREF FILE_ATTRIBUTE_OFFLINE +#endif +#endif #include "../src/assuan.h" @@ -49,8 +54,25 @@ static short server_port = 15898; /* Flag set to indicate a shutdown. */ static int shutdown_pending; +/* The local state of a connection. */ +struct state_s +{ + char *cwd; /* The current working directory - access using get_cwd(). */ +}; +typedef struct state_s *state_t; + +static void +release_state (state_t state) +{ + if (!state) + return; + xfree (state->cwd); + xfree (state); +} + + /* Helper to print a message while leaving a command. */ static gpg_error_t leave_cmd (assuan_context_t ctx, gpg_error_t err) @@ -70,6 +92,114 @@ leave_cmd (assuan_context_t ctx, gpg_error_t err) } +#ifdef HAVE_W32CE_SYSTEM +static char * +wchar_to_utf8 (const wchar_t *string) +{ + int n; + size_t length = wcslen (string); + char *result; + + n = WideCharToMultiByte (CP_UTF8, 0, string, length, NULL, 0, NULL, NULL); + if (n < 0 || (n+1) <= 0) + log_fatal ("WideCharToMultiByte failed\n"); + + result = xmalloc (n+1); + n = WideCharToMultiByte (CP_ACP, 0, string, length, result, n, NULL, NULL); + if (n < 0) + log_fatal ("WideCharToMultiByte failed\n"); + + result[n] = 0; + return result; +} + +static wchar_t * +utf8_to_wchar (const char *string) +{ + int n; + size_t length = strlen (string); + wchar_t *result; + size_t nbytes; + + n = MultiByteToWideChar (CP_UTF8, 0, string, length, NULL, 0); + if (n < 0 || (n+1) <= 0) + log_fatal ("MultiByteToWideChar failed\n"); + + nbytes = (size_t)(n+1) * sizeof(*result); + if (nbytes / sizeof(*result) != (n+1)) + log_fatal ("utf8_to_wchar: integer overflow\n"); + result = xmalloc (nbytes); + n = MultiByteToWideChar (CP_UTF8, 0, string, length, result, n); + if (n < 0) + log_fatal ("MultiByteToWideChar failed\n"); + result[n] = 0; + + return result; +} +#endif /*HAVE_W32CE_SYSTEM*/ + +#ifndef HAVE_W32CE_SYSTEM +static char * +gnu_getcwd (void) +{ + size_t size = 100; + + while (1) + { + char *buffer = xmalloc (size); + if (getcwd (buffer, size) == buffer) + return buffer; + xfree (buffer); + if (errno != ERANGE) + return 0; + size *= 2; + } +} +#endif /*!HAVE_W32CE_SYSTEM*/ + + +/* Return the current working directory. The returned string is valid + as long as STATE->cwd is not changed. */ +static const char * +get_cwd (state_t state) +{ + if (!state->cwd) + { + /* No working directory yet. On WindowsCE make it the module + directory of this process. */ + char *p; +#ifdef HAVE_W32CE_SYSTEM + wchar_t buf[MAX_PATH+1]; + size_t n; + + n = GetModuleFileName (NULL, buf, MAX_PATH); + if (!n) + state->cwd = xstrdup ("/"); + else + { + buf[n] = 0; + state->cwd = wchar_to_utf8 (buf); + p = strrchr (state->cwd, '\\'); + if (p) + *p = 0; + } +#else + state->cwd = gnu_getcwd (); +#endif +#ifdef HAVE_W32_SYSTEM + for (p=state->cwd; *p; p++) + if (*p == '\\') + *p = '/'; +#endif /*HAVE_W32_SYSTEM*/ + } + + return state->cwd; +} + + + + + @@ -88,13 +218,155 @@ cmd_echo (assuan_context_t ctx, char *line) } +static const char hlp_pwd[] = + "PWD\n" + "\n" + "Print the curent working directory of this session.\n"; +static gpg_error_t +cmd_pwd (assuan_context_t ctx, char *line) +{ + state_t state = assuan_get_pointer (ctx); + gpg_error_t err; + const char *string; + + string = get_cwd (state); + err = assuan_send_data (ctx, string, strlen (string)); -static const char hlp_killserver[] = - "KILLSERVER\n" + return leave_cmd (ctx, err); +} + + +static const char hlp_cd[] = + "CD [dir]\n" "\n" - "Kill the server process.\n"; + "Change the curretn directory of the session.\n"; static gpg_error_t -cmd_killserver (assuan_context_t ctx, char *line) +cmd_cd (assuan_context_t ctx, char *line) +{ + state_t state = assuan_get_pointer (ctx); + gpg_error_t err = 0; + char *newdir, *p; + + for (p=line; *p; p++) + if (*p == '\\') + *p = '/'; + + if (!*line) + { + xfree (state->cwd); + state->cwd = NULL; + get_cwd (state); + } + else + { + if (*line == '/') + newdir = xstrdup (line); + else + newdir = xstrconcat (get_cwd (state), "/", line, NULL); + + while (strlen(newdir) > 1 && line[strlen(newdir)-1] == '/') + line[strlen(newdir)-1] = 0; + xfree (state->cwd); + state->cwd = newdir; + } + + return leave_cmd (ctx, err); +} + + + + + +#ifdef HAVE_W32CE_SYSTEM +static const char hlp_ls[] = + "LS [<pattern>]\n" + "\n" + "List the files described by PATTERN.\n"; +static gpg_error_t +cmd_ls (assuan_context_t ctx, char *line) +{ + state_t state = assuan_get_pointer (ctx); + gpg_error_t err; + WIN32_FIND_DATA fi; + char buf[500]; + HANDLE hd; + char *p, *fname; + wchar_t *wfname; + + if (!*line) + fname = xstrconcat (get_cwd (state), "/*", NULL); + else if (*line == '/' || *line == '\\') + fname = xstrdup (line); + else + fname = xstrconcat (get_cwd (state), "/", line, NULL); + for (p=fname; *p; p++) + if (*p == '/') + *p = '\\'; + assuan_write_status (ctx, "PATTERN", fname); + wfname = utf8_to_wchar (fname); + xfree (fname); + hd = FindFirstFile (wfname, &fi); + free (wfname); + if (hd == INVALID_HANDLE_VALUE) + { + log_info ("FindFirstFile returned %d\n", GetLastError ()); + err = gpg_error_from_syserror (); /* Works for W32CE. */ + goto leave; + } + + do + { + DWORD attr = fi.dwFileAttributes; + + fname = wchar_to_utf8 (fi.cFileName); + snprintf (buf, sizeof buf, + "%c%c%c%c%c%c%c%c%c%c%c%c%c %7lu%c %s\n", + (attr & FILE_ATTRIBUTE_DIRECTORY) + ? ((attr & FILE_ATTRIBUTE_DEVICE)? 'c':'d'):'-', + (attr & FILE_ATTRIBUTE_READONLY)? 'r':'-', + (attr & FILE_ATTRIBUTE_HIDDEN)? 'h':'-', + (attr & FILE_ATTRIBUTE_SYSTEM)? 's':'-', + (attr & FILE_ATTRIBUTE_ARCHIVE)? 'a':'-', + (attr & FILE_ATTRIBUTE_COMPRESSED)? 'c':'-', + (attr & FILE_ATTRIBUTE_ENCRYPTED)? 'e':'-', + (attr & FILE_ATTRIBUTE_INROM)? 'R':'-', + (attr & FILE_ATTRIBUTE_REPARSE_POINT)? 'P':'-', + (attr & FILE_ATTRIBUTE_ROMMODULE)? 'M':'-', + (attr & FILE_ATTRIBUTE_ROMSTATICREF)? 'R':'-', + (attr & FILE_ATTRIBUTE_SPARSE_FILE)? 'S':'-', + (attr & FILE_ATTRIBUTE_TEMPORARY)? 't':'-', + (unsigned long)fi.nFileSizeLow, + fi.nFileSizeHigh? 'X':' ', + fname); + free (fname); + err = assuan_send_data (ctx, buf, strlen (buf)); + if (!err) + err = assuan_send_data (ctx, NULL, 0); + } + while (!err && FindNextFile (hd, &fi)); + if (err) + ; + else if (GetLastError () == ERROR_NO_MORE_FILES) + err = 0; + else + { + log_info ("FindNextFile returned %d\n", GetLastError ()); + err = gpg_error_from_syserror (); + } + FindClose (hd); + + leave: + return leave_cmd (ctx, err); +} +#endif /*HAVE_W32CE_SYSTEM*/ + + +static const char hlp_shutdown[] = + "SHUTDOWN\n" + "\n" + "Shutdown the server process after ending this connection\n"; +static gpg_error_t +cmd_shutdown (assuan_context_t ctx, char *line) { (void)ctx; (void)line; @@ -113,10 +385,15 @@ register_commands (assuan_context_t ctx) const char * const help; } table[] = { +#ifdef HAVE_W32CE_SYSTEM + { "LS", cmd_ls, hlp_ls }, +#endif + { "PWD", cmd_pwd, hlp_pwd }, + { "CD", cmd_cd, hlp_cd }, { "ECHO", cmd_echo, hlp_echo }, { "INPUT", NULL }, { "OUTPUT", NULL }, - { "KILLSERVER", cmd_killserver, hlp_killserver }, + { "SHUTDOWN", cmd_shutdown, hlp_shutdown }, { NULL, NULL } }; int i; @@ -143,6 +420,7 @@ server (void) int one = 1; struct sockaddr_in name; assuan_context_t ctx; + state_t state = NULL; err = assuan_new (&ctx); if (err) @@ -184,7 +462,12 @@ server (void) if (err) log_fatal ("register_commands failed: %s\n", gpg_strerror(err)); - assuan_set_log_stream (ctx, stderr); + if (debug) + assuan_set_log_stream (ctx, stderr); + + + state = xcalloc (1, sizeof state); + assuan_set_pointer (ctx, state); while (!shutdown_pending) { @@ -206,6 +489,7 @@ server (void) assuan_sock_close (server_fd); assuan_release (ctx); + release_state (state); } @@ -254,7 +538,8 @@ main (int argc, char **argv) } assuan_set_assuan_log_prefix (log_prefix); - assuan_set_assuan_log_stream (stderr); + if (debug) + assuan_set_assuan_log_stream (stderr); err = assuan_sock_init (); if (err) diff --git a/tests/common.h b/tests/common.h index 3f2a848..4aca63a 100644 --- a/tests/common.h +++ b/tests/common.h @@ -19,6 +19,13 @@ #include <stdarg.h> +#if __GNUC__ >= 4 +# define MY_GCC_A_SENTINEL(a) __attribute__ ((sentinel(a))) +#else +# define MY_GCC_A_SENTINEL(a) +#endif + + #ifdef HAVE_W32CE_SYSTEM #define getpid() GetCurrentProcessId () #define getenv(a) (NULL) @@ -32,6 +39,12 @@ #define HANDLE2SOCKET(h) (h) #endif +#define DIM(v) (sizeof(v)/sizeof((v)[0])) +#define DIMof(type,member) DIM(((type *)0)->member) + + +char *xstrconcat (const char *s1, ...) MY_GCC_A_SENTINEL(0); + static const char *log_prefix; static int errorcount; @@ -73,6 +86,14 @@ xfree (void *a) free (a); } +void * +xstrdup (const char *string) +{ + char *p = xmalloc (strlen (string) + 1); + strcpy (p, string); + return p; +} + void log_set_prefix (const char *s) @@ -168,3 +189,81 @@ prepend_srcdir (const char *fname) return result; } + +#ifndef HAVE_STPCPY +#undef __stpcpy +#undef stpcpy +#ifndef weak_alias +# define __stpcpy stpcpy +#endif +char * +__stpcpy (char *a,const char *b) +{ + while (*b) + *a++ = *b++; + *a = 0; + return (char*)a; +} +#ifdef libc_hidden_def +libc_hidden_def (__stpcpy) +#endif +#ifdef weak_alias +weak_alias (__stpcpy, stpcpy) +#endif +#ifdef libc_hidden_builtin_def +libc_hidden_builtin_def (stpcpy) +#endif +#endif + + +static char * +do_strconcat (const char *s1, va_list arg_ptr) +{ + const char *argv[48]; + size_t argc; + size_t needed; + char *buffer, *p; + + argc = 0; + argv[argc++] = s1; + needed = strlen (s1); + while (((argv[argc] = va_arg (arg_ptr, const char *)))) + { + needed += strlen (argv[argc]); + if (argc >= DIM (argv)-1) + { + fprintf (stderr, "too many args in strconcat\n"); + exit (1); + } + argc++; + } + needed++; + buffer = xmalloc (needed); + if (buffer) + { + for (p = buffer, argc=0; argv[argc]; argc++) + p = stpcpy (p, argv[argc]); + } + return buffer; +} + + +/* Concatenate the string S1 with all the following strings up to a + NULL. Returns a malloced buffer or dies on malloc error. */ +char * +xstrconcat (const char *s1, ...) +{ + va_list arg_ptr; + char *result; + + if (!s1) + result = xstrdup (""); + else + { + va_start (arg_ptr, s1); + result = do_strconcat (s1, arg_ptr); + va_end (arg_ptr); + } + return result; +} + |