/* we keep a list of opened transports. The atransport struct knows to which
 * local transport it is connected. The list is used to detect when we're
 * trying to connect twice to a given local transport.
 */
#define  SDB_LOCAL_TRANSPORT_MAX  16

SDB_MUTEX_DEFINE( local_transports_lock );

static atransport*  local_transports[ SDB_LOCAL_TRANSPORT_MAX ];
#endif /* SDB_HOST */

static int remote_read(apacket *p, atransport *t)
{
    if(readx(t->sfd, &p->msg, sizeof(amessage))){
        D("remote local: read terminated (message)\n");
        return -1;
    }

    fix_endians(p);

#if 0 && defined __ppc__
    D("read remote packet: %04x arg0=%0x arg1=%0x data_length=%0x data_check=%0x magic=%0x\n",
      p->msg.command, p->msg.arg0, p->msg.arg1, p->msg.data_length, p->msg.data_check, p->msg.magic);
#endif
    if(check_header(p)) {
        D("bad header: terminated (data)\n");
        return -1;
    }

    if(readx(t->sfd, p->data, p->msg.data_length)){
        D("remote local: terminated (data)\n");
        return -1;
    }

    if(check_data(p)) {
        D("bad data: terminated (data)\n");
        return -1;
    }

    return 0;
}

static int remote_write(apacket *p, atransport *t)
{
    int   length = p->msg.data_length;

    fix_endians(p);

#if 0 && defined __ppc__
    D("write remote packet: %04x arg0=%0x arg1=%0x data_length=%0x data_check=%0x magic=%0x\n",
      p->msg.command, p->msg.arg0, p->msg.arg1, p->msg.data_length, p->msg.data_check, p->msg.magic);
#endif
    if(writex(t->sfd, &p->msg, sizeof(amessage) + length)) {
        D("remote local: write terminated\n");
        return -1;
    }

    return 0;
}


int local_connect(int port, const char *device_name) {
    return local_connect_arbitrary_ports(port-1, port, device_name);
}

int local_connect_arbitrary_ports(int console_port, int sdb_port, const char *device_name)
{
    char buf[64];
    int  fd = -1;

#if SDB_HOST
    const char *host = getenv("SDBHOST");
    if (host) {
        fd = socket_network_client(host, sdb_port, SOCK_STREAM);
    }
#endif
    if (fd < 0) {
        fd = socket_loopback_client(sdb_port, SOCK_STREAM);
    }

    if (fd >= 0) {
        D("client: connected on remote on fd %d\n", fd);
        close_on_exec(fd);
        disable_tcp_nagle(fd);
        snprintf(buf, sizeof buf, "%s%d", LOCAL_CLIENT_PREFIX, console_port);
        register_socket_transport(fd, buf, sdb_port, 1, device_name);
        return 0;
    }
    return -1;
}

#if SDB_HOST /* tizen specific */
int get_devicename(int port, char *device_name)
{
    int fd;
    char buffer[MAX_PAYLOAD];
    char *tok = NULL;
    int found = 0;

    fd = unix_open(DEVICEMAP_FILENAME, O_RDONLY);
    if (fd > 0) {
        for(;;) {
            if(read_line(fd, buffer, MAX_PAYLOAD) < 0)
                break;
            tok = strtok(buffer, DEVICEMAP_SEPARATOR);
            if (tok != NULL) {
                strncpy(device_name, tok, DEVICENAME_MAX);
                tok = strtok(NULL, DEVICEMAP_SEPARATOR);
                if (tok != NULL) {
                    if (port == atoi(tok)) {
                        found = 1;
                        break;
                    }
                }
            }
        }
        sdb_close(fd);
    }
    if (found != 1)
        strncpy(device_name, DEFAULT_DEVICENAME, DEVICENAME_MAX);
    D("init device name %s on port %d\n", device_name, port);

    return found;
}
Beispiel #2
0
static void sdb_close_conn(void *conn)
{
    if (conn == NULL)
        return;

    sdb_close(conn);
}
void remount_service(int fd, void *cookie)
{
    int ret = remount_system();

    if (!ret)
       write_string(fd, "remount succeeded\n");
    else {
        char    buffer[200];
        snprintf(buffer, sizeof(buffer), "remount failed: %s\n", strerror(errno));
        write_string(fd, buffer);
    }

    sdb_close(fd);
}
static void remote_kick(atransport *t)
{
    int fd = t->sfd;
    t->sfd = -1;
    sdb_shutdown(fd);
    sdb_close(fd);

#if SDB_HOST
    if(HOST) {
        int  nn;
        sdb_mutex_lock( &local_transports_lock );
        for (nn = 0; nn < SDB_LOCAL_TRANSPORT_MAX; nn++) {
            if (local_transports[nn] == t) {
                local_transports[nn] = NULL;
                break;
            }
        }
        sdb_mutex_unlock( &local_transports_lock );
    }
#endif
}
int sync_ls(int fd, const char *path, sync_ls_cb func, void *cookie)
{
    syncmsg msg;
    char buf[257];
    int len;

    len = strlen(path);
    if(len > 1024) goto fail;

    msg.req.id = ID_LIST;
    msg.req.namelen = htoll(len);

    if(writex(fd, &msg.req, sizeof(msg.req)) ||
       writex(fd, path, len)) {
        goto fail;
    }

    for(;;) {
        if(readx(fd, &msg.dent, sizeof(msg.dent))) break;
        if(msg.dent.id == ID_DONE) return 0;
        if(msg.dent.id != ID_DENT) break;

        len = ltohl(msg.dent.namelen);
        if(len > 256) break;

        if(readx(fd, buf, len)) break;
        buf[len] = 0;

        func(ltohl(msg.dent.mode),
             ltohl(msg.dent.size),
             ltohl(msg.dent.time),
             buf, cookie);
    }

fail:
    sdb_close(fd);
    return -1;
}
/* Returns the device used to mount a directory in /proc/mounts */
static char *find_mount(const char *dir)
{
    int fd;
    int res;
    int size;
    char *token = NULL;
    const char delims[] = "\n";
    char buf[4096];

    fd = unix_open("/proc/mounts", O_RDONLY);
    if (fd < 0)
        return NULL;

    buf[sizeof(buf) - 1] = '\0';
    size = sdb_read(fd, buf, sizeof(buf) - 1);
    sdb_close(fd);

    token = strtok(buf, delims);

    while (token) {
        char mount_dev[256];
        char mount_dir[256];
        int mount_freq;
        int mount_passno;

        res = sscanf(token, "%255s %255s %*s %*s %d %d\n",
                     mount_dev, mount_dir, &mount_freq, &mount_passno);
        mount_dev[255] = 0;
        mount_dir[255] = 0;
        if (res == 4 && (strcmp(dir, mount_dir) == 0))
            return strdup(mount_dev);

        token = strtok(NULL, delims);
    }
    return NULL;
}
static int write_data_file(int fd, const char *path, syncsendbuf *sbuf)
{
    int lfd, err = 0;

    lfd = sdb_open(path, O_RDONLY);
    if(lfd < 0) {
        fprintf(stderr,"cannot open '%s': %s\n", path, strerror(errno));
        return -1;
    }

    sbuf->id = ID_DATA;
    for(;;) {
        int ret;

        ret = sdb_read(lfd, sbuf->data, SYNC_DATA_MAX);
        if(!ret)
            break;

        if(ret < 0) {
            if(errno == EINTR)
                continue;
            fprintf(stderr,"cannot read '%s': %s\n", path, strerror(errno));
            break;
        }

        sbuf->size = htoll(ret);
        if(writex(fd, sbuf, sizeof(unsigned) * 2 + ret)){
            err = -1;
            break;
        }
        total_bytes += ret;
    }

    sdb_close(lfd);
    return err;
}
static void remote_close(atransport *t)
{
    sdb_close(t->fd);
}
Beispiel #9
0
R_API bool r_syscall_setup(RSyscall *s, const char *arch, const char *os, int bits) {
	const char *file;
	if (!os || !*os) {
		os = R_SYS_OS;
	}
	if (!arch) {
		arch = R_SYS_ARCH;
	}
	free (s->os);
	s->os = strdup (os);

	if (!strcmp (os, "any")) { // ignored
		return true;
	}
	if (!strcmp (arch, "mips")) {
		s->regs = fastcall_mips;
	} else if (!strcmp (arch,"avr")) {
		s->sysport = sysport_avr;
	} else if (!strcmp (arch,"sh")) {
		s->regs = fastcall_sh;
	} else if (!strcmp (arch, "arm")) {
		switch (bits) {
		case 16:
		case 32:
			s->regs = fastcall_arm;
			break;
		case 64:
			s->regs = fastcall_arm64;
			break;
		}
	} else if (!strcmp (arch, "x86")) {
		s->sysport = sysport_x86;
		switch (bits) {
		case 8:
			s->regs = fastcall_x86_8;
			break;
		case 32:
			s->regs = fastcall_x86_32;
			break;
		case 64:
			s->regs = fastcall_x86_64;
			break;
		}
	}

#define SYSCALLPATH R2_PREFIX "/share/radare2/" R2_VERSION "/syscall"
	file = sdb_fmt (0, "%s/%s-%s-%d.sdb",
		SYSCALLPATH, os, arch, bits);
	if (!r_file_exists (file)) {
		// eprintf ("r_syscall_setup: Cannot find '%s'\n", file);
		return false;
	}

	//eprintf ("DBG098: syscall->db must be reindexed for k\n");
	sdb_close (s->db);
	sdb_reset (s->db);
	sdb_open (s->db, file);
//	s->db = sdb_new (0, file, 0);
#if 1
	if (s->fd) {
		fclose (s->fd);
	}
	s->fd = NULL;
#endif
	return true;
}
Beispiel #10
0
static int cmd_type(void *data, const char *input) {
	RCore *core = (RCore *)data;

	switch (input[0]) {
	// t [typename] - show given type in C syntax
	case 'u': // "tu"
		switch (input[1]) {
		case '?': {
			const char *help_message[] = {
				"USAGE tu[...]", "", "",
				"tu", "", "List all loaded unions",
				"tu?", "", "show this help",
				NULL };
			r_core_cmd_help (core, help_message);
		} break;
		case 0:
			sdb_foreach (core->anal->sdb_types, stdprintifunion, core);
			break;
		}
		break;
	case 'k': // "tk"
		if (input[1] == ' ') {
			sdb_query (core->anal->sdb_types, input + 2);
		} else sdb_query (core->anal->sdb_types, "*");
		fflush (stdout);
		break;
	case 's': // "ts"
		switch (input[1]) {
		case '?': {
			const char *help_message[] = {
				"USAGE ts[...]", "", "",
				"ts", "", "List all loaded structs",
				"ts?", "", "show this help",
				NULL };
			r_core_cmd_help (core, help_message);
		} break;
		case 0:
			sdb_foreach (core->anal->sdb_types, stdprintifstruct, core);
			break;
		}
		break;
	case 'b': {
		char *p, *s = (strlen (input) > 1)? strdup (input + 2): NULL;
		const char *isenum;
		p = s? strchr (s, ' '): NULL;
		if (p) {
			*p++ = 0;
			// dupp in core.c (see getbitfield())
			isenum = sdb_const_get (core->anal->sdb_types, s, 0);
			if (isenum && !strcmp (isenum, "enum")) {
				*--p = '.';
				const char *res = sdb_const_get (core->anal->sdb_types, s, 0);
				if (res)
					r_cons_println (res);
				else eprintf ("Invalid enum member\n");
			} else {
				eprintf ("This is not an enum\n");
			}
		} else {
			eprintf ("Missing value\n");
		}
		free (s);
	} break;
	case 'e': {
		if (!input[1]) {
			char *name = NULL;
			SdbKv *kv;
			SdbListIter *iter;
			SdbList *l = sdb_foreach_list (core->anal->sdb_types);
			ls_foreach (l, iter, kv) {
				if (!strcmp (kv->value, "enum")) {
					if (!name || strcmp (kv->value, name)) {
						free (name);
						name = strdup (kv->key);
						r_cons_println (name);
					}
				}
			}
			free (name);
			ls_free (l);
			break;
		}
		if (input[1] == '?') {
			const char *help_message[] = {
				"USAGE te[...]", "", "",
				"te", "", "List all loaded enums",
				"te", " <enum> <value>", "Show name for given enum number",
				"te?", "", "show this help",
				NULL };
			r_core_cmd_help (core, help_message);
			break;
		}
		char *p, *s = strdup (input + 2);
		const char *isenum;
		p = strchr (s, ' ');
		if (p) {
			*p++ = 0;
			isenum = sdb_const_get (core->anal->sdb_types, s, 0);
			if (isenum && !strncmp (isenum, "enum", 4)) {
				const char *q = sdb_fmt (0, "%s.0x%x", s, (ut32)r_num_math (core->num, p));
				const char *res = sdb_const_get (core->anal->sdb_types, q, 0);
				if (res)
					r_cons_println (res);
			} else {
				eprintf ("This is not an enum\n");
			}
		} else {
			//eprintf ("Missing value\n");
			r_core_cmdf (core, "t~&%s,=0x", s);
		}
		free (s);
	} break;
	case ' ': {
		const char *isenum = sdb_const_get (core->anal->sdb_types, input + 1, 0);
		if (isenum && !strcmp (isenum, "enum")) {
			eprintf ("IS ENUM! \n");
		} else {
			char *fmt = r_anal_type_format (core->anal, input + 1);
			if (fmt) {
				r_str_chop (fmt);
				r_cons_printf ("pf %s\n", fmt);
				free (fmt);
			} else eprintf ("Cannot find '%s' type\n", input + 1);
		}
	} break;
	// t* - list all types in 'pf' syntax
	case '*':
		sdb_foreach (core->anal->sdb_types, typelist, core);
		break;
	case 0:
		sdb_foreach (core->anal->sdb_types, sdbforcb, core);
		break;
	case 'o':
		if (!r_sandbox_enable (0)) {
			if (input[1] == ' ') {
				const char *filename = input + 2;
				char *homefile = NULL;
				if (*filename == '~') {
					if (filename[1] && filename[2]) {
						homefile = r_str_home (filename + 2);
						filename = homefile;
					}
				}
				if (!strcmp (filename, "-")) {
					char *out, *tmp;
					tmp = r_core_editor (core, NULL, "");
					if (tmp) {
						out = r_parse_c_string (tmp);
						if (out) {
							//		r_cons_strcat (out);
							save_parsed_type (core, out);
							free (out);
						}
						free (tmp);
					}
				} else {
					char *out = r_parse_c_file (filename);
					if (out) {
						//r_cons_strcat (out);
						save_parsed_type (core, out);
						free (out);
					}
					//r_anal_type_loadfile (core->anal, filename);
				}
				free (homefile);
			} else if (input[1] == 's') {
				const char *dbpath = input + 3;
				if (r_file_exists (dbpath)) {
					Sdb *db_tmp = sdb_new (0, dbpath, 0);
					sdb_merge (core->anal->sdb_types, db_tmp);
					sdb_close (db_tmp);
					sdb_free (db_tmp);
				}
			}
		} else {
			eprintf ("Sandbox: system call disabled\n");
		}
		break;
	// td - parse string with cparse engine and load types from it
	case 'd':
		if (input[1] == '?') {
			const char *help_message[] = {
				"Usage:", "\"td [...]\"", "",
				"td", "[string]", "Load types from string",
				NULL };
			r_core_cmd_help (core, help_message);
			r_cons_printf ("Note: The td command should be put between double quotes\n"
				"Example: \" td struct foo {int bar;int cow};\""
				"\nt");

		} else if (input[1] == ' ') {
			char tmp[8192];
			snprintf (tmp, sizeof (tmp) - 1, "%s;", input + 2);
			//const char *string = input + 2;
			//r_anal_str_to_type (core->anal, string);
			char *out = r_parse_c_string (tmp);
			if (out) {
				//r_cons_strcat (out);
				save_parsed_type (core, out);
				free (out);
			}
		} else {
			eprintf ("Invalid use of td. See td? for help\n");
		}
		break;
	// tl - link a type to an address
	case 'l':
		switch (input[1]) {
		case '?': {
			const char *help_message[] = {
				"Usage:", "", "",
				"tl", "", "list all links in readable format",
				"tl", "[typename]", "link a type to current adress.",
				"tl", "[typename] = [address]", "link type to given address.",
				"tls", "[address]", "show link at given address",
				"tl-*", "", "delete all links.",
				"tl-", "[address]", "delete link at given address.",
				"tl*", "", "list all links in radare2 command format",
				"tl?", "", "print this help.",
				NULL };
			r_core_cmd_help (core, help_message);
			} break;
		case ' ': {
			char *type = strdup (input + 2);
			char *ptr = strchr (type, '=');
			ut64 addr;

			if (ptr) {
				*ptr++ = 0;
				r_str_chop (ptr);
				if (ptr && *ptr) {
					addr = r_num_math (core->num, ptr);
				} else {
					eprintf ("address is unvalid\n");
					free (type);
					break;
				}
			} else {
				addr = core->offset;
			}
			r_str_chop (type);
			char *tmp = sdb_get (core->anal->sdb_types, type, 0);
			if (tmp && *tmp) {
				r_anal_type_link (core->anal, type, addr);
				free (tmp);
			} else {
				eprintf ("unknown type %s\n", type);
			}
			free (type);
			}
			break;
		case 's': {
			int ptr;
			char *addr = strdup (input + 2);
			SdbKv *kv;
			SdbListIter *sdb_iter;
			SdbList *sdb_list = sdb_foreach_list (core->anal->sdb_types);
			r_str_chop (addr);
			ptr = r_num_math (NULL, addr);
			//r_core_cmdf (core, "tl~0x%08"PFMT64x" = ", addr);
			ls_foreach (sdb_list, sdb_iter, kv) {
				char *linkptr;
				if (strncmp (kv->key, "link.", strlen ("link."))) {
					continue;
				}
				linkptr = sdb_fmt (-1,"0x%s", kv->key + strlen ("link."));
				if (ptr == r_num_math (NULL, linkptr)) {
					linklist_readable (core, kv->key, kv->value);
				}
			}
			free (addr);
			ls_free (sdb_list);
			}
			break;
		case '-':
			switch (input[2]) {
			case '*':
				sdb_foreach (core->anal->sdb_types, sdbdeletelink, core);
				break;
			case ' ': {
				const char *ptr = input + 3;
				ut64 addr = r_num_math (core->num, ptr);
				r_anal_type_unlink (core->anal, addr);
				}
				break;
			}
			break;
		case '*':
			sdb_foreach (core->anal->sdb_types, linklist, core);
			break;
		case '\0':
			sdb_foreach (core->anal->sdb_types, linklist_readable, core);
			break;
		}
Beispiel #11
0
// mysdb :close()
static int api_close( lua_State *L) {
    sdb_close( lua_sdb_checktable( L, 1));
    lua_pushboolean( L, 1);
    return 1;
}
Beispiel #12
0
/* sdb :newconsolidation(id, storage, { col1=CM1, ..., coln=CMn })
 * sdb :newconsolidation(id, storage, { <columnspec>, ... })
 * CM are Consolidation Methods. <columnspec> are standard column
 * specifications with the `consolidation` field set.
 *
 * Column names are shared between src and dst: the column src.foobar,
 * if it is consolidated, is consolidated in dst.foobar.
 *
 * The dst consolidation table is created on the fly, rather than passed
 * as a parameter. */
static int api_newconsolidation( lua_State *L) {
    struct sdb_table_t *src, *dst;
    const char *id;
    enum sdb_storage_kind_t storage;
    int r, i, ncolumns;

    // src, id, storage, columns
    src      = lua_sdb_checktable( L, 1);
    id       = luaL_checkstring(   L, 2);
    storage  = luaL_checkoption(   L, 3, NULL, storage_options);
    ncolumns = gettablencolumns(   L, 4);
    dst      = lua_newuserdata(    L, sizeof( *dst));
    // src, id, storage, columns, dst

    r = sdb_initwithoutcolumns( dst, id, ncolumns, storage);
    if( r) { lua_pushnil( L); lua_pushinteger( L, r); return 2; }

    lua_getfield(     L, LUA_REGISTRYINDEX, MT_NAME); // id, storage, columns, udata, mt
    lua_setmetatable( L, -2); // id, storage, columns, udata

    luaL_checktype( L, 4, LUA_TTABLE);

    r = sdb_setconstable( src, dst);
    if( r) {
      sdb_close( dst);
      return push_sdb_error( L, r);
    }

    if( lua_objlen(L, 4) == ncolumns) {
        // full column description sequence
        for(i=1, lua_rawgeti( L, 4, 1); !lua_isnil( L, -1); lua_rawgeti( L, 4, ++i)) { // src, id, storage, columns, dst, val
            const char *colname;
            enum sdb_serialization_method_t s_method;
            enum sdb_consolidation_method_t c_method;
            double arg;
            sdb_ncolumn_t src_col;

            lua_sdb_getcolumnspec( L, &arg, &s_method, &c_method, 4, i); // src, id, storage, columns, dst, colname
            colname = lua_tostring( L, -1);
            src_col = sdb_getcolnum( src, colname);
            if( SDB_NCOLUMN_INVALID == src_col) {
                lua_sdb_fargerror( L, 4, "Unknown column %s.", colname);
            }

            r = sdb_setcolumn( dst, colname, s_method, arg);
            if( r) { sdb_close( dst); return push_sdb_error( L, r); }

            r = sdb_setconscolumn( src, src_col, c_method);
            if( r) { sdb_close( dst); return push_sdb_error( L, r); }

            lua_pop( L, 1); // src, id, storage, columns, dst
        }
        // src, id, storage, columns, dst, nil
        lua_pop( L, 1); // src, id, storage, columns, dst
    } else {
        // short colname/consolidation method mapping
        for( lua_pushnil( L); lua_next( L, 4);) { // src, id, storage, columns, dst, key, val
            if( !lua_isstring(L, -2))
                lua_sdb_fargerror( L, 4, "Expected string for columns names, got %s", lua_typename( L, lua_type( L, -1)));
            const char *colname = luaL_checkstring( L, -2);
            enum sdb_serialization_method_t s_method = SDB_DEFAULT_SERIALIZATION_METHOD;
            enum sdb_consolidation_method_t c_method = lua_sdb_getoption( L, -1, consolidation_methods);
            if( !consolidation_methods[c_method]) {
                lua_sdb_fargerror( L, 4, "Invalid consolidation method for %s", colname);
            }

            sdb_ncolumn_t src_col = sdb_getcolnum( src, colname);
            if( SDB_NCOLUMN_INVALID == src_col) {
                lua_sdb_fargerror( L, 4, "Unknown column %s", colname);
            }

            r = sdb_setcolumn( dst, colname, s_method, 0.0);
            if( r) { sdb_close( dst); return push_sdb_error( L, r); }

            r = sdb_setconscolumn( src, src_col, c_method);
            if( r) { sdb_close( dst); return push_sdb_error( L, r); }

            lua_pop( L, 1); // src, id, storage, columns, dst
        }
    }
    // src, id, storage, columns, dst
    return 1;
}
int sync_recv(int fd, const char *rpath, const char *lpath)
{
    syncmsg msg;
    int len;
    int lfd = -1;
    char *buffer = send_buffer.data;
    unsigned id;

    len = strlen(rpath);
    if(len > 1024) return -1;

    msg.req.id = ID_RECV;
    msg.req.namelen = htoll(len);
    if(writex(fd, &msg.req, sizeof(msg.req)) ||
       writex(fd, rpath, len)) {
        return -1;
    }

    if(readx(fd, &msg.data, sizeof(msg.data))) {
        return -1;
    }
    id = msg.data.id;

    if((id == ID_DATA) || (id == ID_DONE)) {
        sdb_unlink(lpath);
        mkdirs((char *)lpath);
        lfd = sdb_creat(lpath, 0644);
        if(lfd < 0) {
            fprintf(stderr,"cannot create '%s': %s\n", lpath, strerror(errno));
            return -1;
        }
        goto handle_data;
    } else {
        goto remote_error;
    }

    for(;;) {
        if(readx(fd, &msg.data, sizeof(msg.data))) {
            return -1;
        }
        id = msg.data.id;

    handle_data:
        len = ltohl(msg.data.size);
        if(id == ID_DONE) break;
        if(id != ID_DATA) goto remote_error;
        if(len > SYNC_DATA_MAX) {
            fprintf(stderr,"data overrun\n");
            sdb_close(lfd);
            return -1;
        }

        if(readx(fd, buffer, len)) {
            sdb_close(lfd);
            return -1;
        }

        if(writex(lfd, buffer, len)) {
            fprintf(stderr,"cannot write '%s': %s\n", rpath, strerror(errno));
            sdb_close(lfd);
            return -1;
        }

        total_bytes += len;
    }

    sdb_close(lfd);
    return 0;

remote_error:
    sdb_close(lfd);
    sdb_unlink(lpath);

    if(id == ID_FAIL) {
        len = ltohl(msg.data.size);
        if(len > 256) len = 256;
        if(readx(fd, buffer, len)) {
            return -1;
        }
        buffer[len] = 0;
    } else {
        memcpy(buffer, &id, 4);
        buffer[4] = 0;
//        strcpy(buffer,"unknown reason");
    }
    fprintf(stderr,"failed to copy '%s' to '%s': %s\n", rpath, lpath, buffer);
    return 0;
}
static int sync_send(int fd, const char *lpath, const char *rpath,
                     unsigned mtime, mode_t mode, int verifyApk)
{
    syncmsg msg;
    int len, r;
    syncsendbuf *sbuf = &send_buffer;
    char* file_buffer = NULL;
    int size = 0;
    char tmp[64];

    len = strlen(rpath);
    if(len > 1024) goto fail;

    snprintf(tmp, sizeof(tmp), ",%d", mode);
    r = strlen(tmp);

    if (verifyApk) {
#if 0 //eric
        int lfd;
        zipfile_t zip;
        zipentry_t entry;
        int amt;

        // if we are transferring an APK file, then sanity check to make sure
        // we have a real zip file that contains an AndroidManifest.xml
        // this requires that we read the entire file into memory.
        lfd = sdb_open(lpath, O_RDONLY);
        if(lfd < 0) {
            fprintf(stderr,"cannot open '%s': %s\n", lpath, strerror(errno));
            return -1;
        }

        size = sdb_lseek(lfd, 0, SEEK_END);
        if (size == -1 || -1 == sdb_lseek(lfd, 0, SEEK_SET)) {
            fprintf(stderr, "error seeking in file '%s'\n", lpath);
            sdb_close(lfd);
            return 1;
        }

        file_buffer = (char *)malloc(size);
        if (file_buffer == NULL) {
            fprintf(stderr, "could not allocate buffer for '%s'\n",
                    lpath);
            sdb_close(lfd);
            return 1;
        }
        amt = sdb_read(lfd, file_buffer, size);
        if (amt != size) {
            fprintf(stderr, "error reading from file: '%s'\n", lpath);
            sdb_close(lfd);
            free(file_buffer);
            return 1;
        }

        sdb_close(lfd);

        zip = init_zipfile(file_buffer, size);
        if (zip == NULL) {
            fprintf(stderr, "file '%s' is not a valid zip file\n",
                    lpath);
            free(file_buffer);
            return 1;
        }

        entry = lookup_zipentry(zip, "AndroidManifest.xml");
        release_zipfile(zip);
        if (entry == NULL) {
            fprintf(stderr, "file '%s' does not contain AndroidManifest.xml\n",
                    lpath);
            free(file_buffer);
            return 1;
        }
#endif
    }

    msg.req.id = ID_SEND;
    msg.req.namelen = htoll(len + r);

    if(writex(fd, &msg.req, sizeof(msg.req)) ||
       writex(fd, rpath, len) || writex(fd, tmp, r)) {
        free(file_buffer);
        goto fail;
    }

    if (file_buffer) {
        write_data_buffer(fd, file_buffer, size, sbuf);
        free(file_buffer);
    } else if (S_ISREG(mode))
        write_data_file(fd, lpath, sbuf);
#ifdef HAVE_SYMLINKS
    else if (S_ISLNK(mode))
        write_data_link(fd, lpath, sbuf);
#endif
    else
        goto fail;

    msg.data.id = ID_DONE;
    msg.data.size = htoll(mtime);
    if(writex(fd, &msg.data, sizeof(msg.data)))
        goto fail;

    if(readx(fd, &msg.status, sizeof(msg.status)))
        return -1;

    if(msg.status.id != ID_OKAY) {
        if(msg.status.id == ID_FAIL) {
            len = ltohl(msg.status.msglen);
            if(len > 256) len = 256;
            if(readx(fd, sbuf->data, len)) {
                return -1;
            }
            sbuf->data[len] = 0;
        } else
            strcpy(sbuf->data, "unknown reason");

        fprintf(stderr,"failed to copy '%s' to '%s': %s\n", lpath, rpath, sbuf->data);
        return -1;
    }

    return 0;

fail:
    fprintf(stderr,"protocol failure\n");
    sdb_close(fd);
    return -1;
}