void str_printf(str_t *str, const char *fmt, ...) { /* Guess we need no more than 100 bytes. */ int len; va_list ap; int size = 100; str_realloc(str, size); while (1) { /* Try to print in the allocated space. */ va_start(ap, fmt); len = vsnprintf(str->buf, size, fmt, ap); va_end(ap); /* If that worked, return the string. */ if (len > -1 && len < size) { str->len = len; return; } /* Else try again with more space. */ if (len > -1) /* glibc 2.1 */ size = len+1; /* precisely what is needed */ else /* glibc 2.0 */ size *= 2; /* twice the old size */ str_realloc(str, size); } }
char *ssl_getline(CLI *c) { /* get newline-terminated string */ char *line; size_t ptr=0, allocated=32; line=str_alloc(allocated); for(;;) { if(ptr>65536) { /* >64KB --> DoS protection */ s_log(LOG_ERR, "ssl_getline: Line too long"); str_free(line); longjmp(c->err, 1); } if(allocated<ptr+1) { allocated*=2; line=str_realloc(line, allocated); } s_ssl_read(c, line+ptr, 1); if(line[ptr]=='\r') continue; if(line[ptr]=='\n') break; if(line[ptr]=='\0') break; ++ptr; } line[ptr]='\0'; s_log(LOG_DEBUG, " <- %s", line); return line; }
char *fd_getline(CLI *c, int fd) { char *line, *tmpline; int ptr=0, allocated=32; line=str_alloc(allocated); for(;;) { s_poll_init(c->fds); s_poll_add(c->fds, fd, 1, 0); /* read */ switch(s_poll_wait(c->fds, c->opt->timeout_busy, 0)) { case -1: sockerror("fd_getline: s_poll_wait"); str_free(line); longjmp(c->err, 1); /* error */ case 0: s_log(LOG_INFO, "fd_getline: s_poll_wait:" " TIMEOUTbusy exceeded: sending reset"); str_free(line); longjmp(c->err, 1); /* timeout */ case 1: break; /* OK */ default: s_log(LOG_ERR, "fd_getline: s_poll_wait: Unknown result"); str_free(line); longjmp(c->err, 1); /* error */ } if(allocated<ptr+1) { allocated*=2; line=str_realloc(line, allocated); } switch(readsocket(fd, line+ptr, 1)) { case -1: /* error */ sockerror("fd_getline: readsocket"); str_free(line); longjmp(c->err, 1); case 0: /* EOF */ s_log(LOG_ERR, "fd_getline: Unexpected socket close"); str_free(line); longjmp(c->err, 1); } if(line[ptr]=='\r') continue; if(line[ptr]=='\n') break; if(line[ptr]=='\0') break; if(++ptr>65536) { /* >64KB --> DoS protection */ s_log(LOG_ERR, "fd_getline: Line too long"); str_free(line); longjmp(c->err, 1); } } line[ptr]='\0'; tmpline=str_dup(line); safestring(tmpline); s_log(LOG_DEBUG, " <- %s", tmpline); str_free(tmpline); return line; }
static inline void str_strcpy_ensurespace( str *s, unsigned long n ) { unsigned long m = n + 1; if ( !s->data || !s->dim ) str_initalloc( s, m ); else if ( m > s->dim ) str_realloc( s, m ); }
/** Translate the domain name in \p d to a dotted text string in \p out. */ int dns_domain_todot_cat(str *out,const char *d) { unsigned int len = fmt_dns_domain(0, d); if (!str_realloc(out, out->len + len)) return 0; fmt_dns_domain(out->s + out->len, d); out->len += len; out->s[out->len] = 0; return 1; }
inline void str_append_sub(str_t *str, char *append, int start, int app_len) { if (str == NULL) return; str_realloc(str, str->len + app_len + 1); memcpy(str->buf+str->len, append+start, app_len); str->len += app_len; str->buf[str->len] = 0; }
int str_append_buf(struct str *str, char *buf, size_t len) { int ret; if (str->len + len > str->cap) { ret = str_realloc(str, str->len + len); if (ret) return ret; } memmove(str->buf + str->len, buf, len); str->len += len; return 0; }
int get_key(t_struct *my_st, char key) { int i; i = 0; while (my_st->file[i]) i++; if ((my_st->file = str_realloc(my_st->file, i + 2)) == NULL) return (EXIT_ON_ERROR); my_st->file[i] = key; my_st->file[i + 1] = '\0'; return (GO_ON); }
NOEXPORT void s_poll_realloc(s_poll_set *fds) { fds->irfds=str_realloc(fds->irfds, FD_SIZE(fds)); fds->iwfds=str_realloc(fds->iwfds, FD_SIZE(fds)); fds->ixfds=str_realloc(fds->ixfds, FD_SIZE(fds)); fds->orfds=str_realloc(fds->orfds, FD_SIZE(fds)); fds->owfds=str_realloc(fds->owfds, FD_SIZE(fds)); fds->oxfds=str_realloc(fds->oxfds, FD_SIZE(fds)); }
int str_findreplace( str *s, const char *find, const char *replace ) { long diff; size_t findstart, searchstart; size_t p1, p2; size_t find_len, rep_len, curr_len; char empty[2] = ""; unsigned long minsize; char *p; int n = 0; assert( s && find ); return_zero_if_memerr( s ); if ( !s->data || !s->dim ) return 0; if ( !replace ) replace = empty; find_len = strlen( find ); rep_len = strlen( replace ); diff = rep_len - find_len; if ( diff < 0 ) diff = 0; searchstart=0; while ((p=strstr(s->data + searchstart,find))!=NULL) { curr_len = strlen(s->data); findstart=(size_t) p - (size_t) s->data; minsize = curr_len + diff + 1; if (s->dim <= minsize) str_realloc( s, minsize ); if ( find_len > rep_len ) { p1 = findstart + rep_len; p2 = findstart + find_len; while( s->data[p2] ) s->data[p1++]=s->data[p2++]; s->data[p1]='\0'; n++; } else if ( find_len < rep_len ) { for ( p1=curr_len; p1>=findstart+find_len; p1-- ) s->data[p1+diff] = s->data[p1]; n++; } for (p1=0; p1<rep_len; p1++) s->data[findstart+p1]=replace[p1]; searchstart = findstart + rep_len; s->len += rep_len - find_len; } return n; }
int hostport2addrlist(SOCKADDR_LIST *addr_list, char *hostname, char *portname) { struct addrinfo hints, *res=NULL, *cur; int err; memset(&hints, 0, sizeof hints); #if defined(USE_IPv6) || defined(USE_WIN32) hints.ai_family=PF_UNSPEC; #else hints.ai_family=PF_INET; #endif hints.ai_socktype=SOCK_STREAM; hints.ai_protocol=IPPROTO_TCP; do { err=getaddrinfo(hostname, portname, &hints, &res); if(err && res) freeaddrinfo(res); if(err==EAI_AGAIN) { s_log(LOG_DEBUG, "getaddrinfo: EAI_AGAIN received: retrying"); sleep(1); } } while(err==EAI_AGAIN); switch(err) { case 0: break; /* success */ case EAI_SERVICE: s_log(LOG_ERR, "Unknown TCP service '%s'", portname); return 0; /* error */ default: s_log(LOG_ERR, "Error resolving '%s': %s", hostname, s_gai_strerror(err)); return 0; /* error */ } /* copy the list of addresses */ for(cur=res; cur; cur=cur->ai_next) { if(cur->ai_addrlen>sizeof(SOCKADDR_UNION)) { s_log(LOG_ERR, "INTERNAL ERROR: ai_addrlen value too big"); freeaddrinfo(res); return 0; /* no results */ } addr_list->addr=str_realloc(addr_list->addr, (addr_list->num+1)*sizeof(SOCKADDR_UNION)); memcpy(&addr_list->addr[addr_list->num], cur->ai_addr, cur->ai_addrlen); ++(addr_list->num); } freeaddrinfo(res); return addr_list->num; /* ok - return the number of addresses */ }
void str_fill( str *s, unsigned long n, char fillchar ) { unsigned long i; assert( s ); str_clear_status( s ); if ( !s->data || s->dim==0 ) str_initalloc( s, n+1 ); if ( n + 1 > s->dim ) str_realloc( s, n+1 ); for ( i=0; i<n; ++i ) s->data[i] = fillchar; s->data[n] = '\0'; s->len = n; }
NOEXPORT LPTSTR str_vtprintf(LPCTSTR format, va_list start_ap) { int n; size_t size=32; LPTSTR p; va_list ap; p=str_alloc(size*sizeof(TCHAR)); for(;;) { va_copy(ap, start_ap); n=_vsntprintf(p, size, format, ap); if(n>-1 && n<(int)size) return p; size*=2; p=str_realloc(p, size*sizeof(TCHAR)); } }
void str_addchar( str *s, char newchar ) { assert( s ); return_if_memerr( s ); if ( newchar=='\0' ) return; /* appending '\0' is a null operation */ if ( !s->data || s->dim==0 ) str_initalloc( s, str_initlen ); if ( s->len + 2 > s->dim ) str_realloc( s, s->len*2 ); s->data[s->len++] = newchar; s->data[s->len] = '\0'; }
static void scan_remote_file(FileData *file_data, const char *path_dir, int nest, int host) { int num_paths; char *outfile; char *path_file; char *temp; int i; temp = str_concat(path_dir, "/", NULL); message(ENTER, temp, nest, host); num_paths = file_data->num_paths; file_data->num_paths++; file_data->path_state = str_realloc(file_data->path_state, sizeof(PathState) * (num_paths + 1)); file_data->path_state[num_paths].path = str_dup(path_dir); file_data->path_state[num_paths].isremoved = FALSE; file_data->path_state[num_paths].file_state = NULL; outfile = make_temp_file_name(host); if (config.access_method[host] == FTP) { ftp_get_file_list(outfile, path_dir, host); } else if (config.access_method[host] == SCP || config.access_method[host] == RSYNC) { ssh_get_file_list(outfile, path_dir, host); } else { internal_error(__FILE__, __LINE__); } parse_file_list(file_data, num_paths, outfile, path_dir, config.access_method[host], host); for (i = 0; i < file_data->path_state[num_paths].num_files; i++) { if (file_data->path_state[num_paths].file_state[i].isdir) { path_file = str_concat(path_dir, "/", file_data->path_state[num_paths].file_state[i].name, NULL); nest++; scan_remote_file(file_data, path_file, nest, host); nest--; free(path_file); } } message(LEAVE, temp, nest, host); free(temp); }
char *str_vprintf(const char *format, va_list start_ap) { int n; size_t size=32; char *p; va_list ap; p=str_alloc(size); for(;;) { va_copy(ap, start_ap); n=vsnprintf(p, size, format, ap); if(n>-1 && n<(int)size) return p; if(n>-1) /* glibc 2.1 */ size=(size_t)n+1; /* precisely what is needed */ else /* glibc 2.0, WIN32, etc. */ size*=2; /* twice the old size */ p=str_realloc(p, size); } }
/** Join a binary block to this string */ int str_joinb(str* s, char sep, const char* in, unsigned len) { unsigned len1; unsigned off2; unsigned len2; len1 = s->len; while (len1 > 0 && s->s[len1-1] == sep) --len1; off2 = 0; while (off2 < len && in[off2] == sep) ++off2; len2 = len - off2; if (!str_realloc(s, len1+1+len2)) return 0; s->s[len1++] = sep; memcpy(s->s+len1, in+off2, len2); s->len = len1 + len2; s->s[s->len] = 0; return 1; }
char *ssl_getstring(CLI *c) { /* get null-terminated string */ char *line; size_t ptr=0, allocated=32; line=str_alloc(allocated); for(;;) { if(ptr>65536) { /* >64KB --> DoS protection */ s_log(LOG_ERR, "ssl_getstring: Line too long"); str_free(line); longjmp(c->err, 1); } if(allocated<ptr+1) { allocated*=2; line=str_realloc(line, allocated); } s_ssl_read(c, line+ptr, 1); if(line[ptr]=='\0') break; ++ptr; } return line; }
int name2addrlist(SOCKADDR_LIST *addr_list, char *name, char *default_host) { char *tmp, *hostname, *portname; int retval; addr_list->cur=0; /* reset round-robin counter */ /* first check if this is a UNIX socket */ #ifdef HAVE_STRUCT_SOCKADDR_UN if(*name=='/') { if(offsetof(struct sockaddr_un, sun_path)+strlen(name)+1 > sizeof(struct sockaddr_un)) { s_log(LOG_ERR, "Unix socket path is too long"); return 0; /* no results */ } addr_list->addr=str_realloc(addr_list->addr, (addr_list->num+1)*sizeof(SOCKADDR_UNION)); addr_list->addr[addr_list->num].un.sun_family=AF_UNIX; strcpy(addr_list->addr[addr_list->num].un.sun_path, name); return ++(addr_list->num); /* ok - return the number of addresses */ } #endif /* set hostname and portname */ tmp=str_dup(name); portname=strrchr(tmp, ':'); if(portname) { hostname=tmp; *portname++='\0'; } else { /* no ':' - use default host IP */ hostname=default_host; portname=tmp; } /* fill addr_list structure */ retval=hostport2addrlist(addr_list, hostname, portname); str_free(tmp); return retval; }
void str_prepend( str *s, const char *addstr ) { unsigned long lenaddstr, i; assert( s && addstr ); return_if_memerr( s ); lenaddstr = strlen( addstr ); if ( lenaddstr==0 ) return; /* appending an empty string is a null op */ if ( !s->data || !s->dim ) str_initalloc( s, lenaddstr+1 ); else { if ( s->len + lenaddstr + 1 > s->dim ) str_realloc( s, s->len + lenaddstr + 1 ); for ( i=s->len+lenaddstr-1; i>=lenaddstr; i-- ) s->data[i] = s->data[i-lenaddstr]; } strncpy( s->data, addstr, lenaddstr ); s->len += lenaddstr; s->data[ s->len ] = '\0'; }
unsigned hostport2addrlist(SOCKADDR_LIST *addr_list, char *host_name, char *port_name) { struct addrinfo hints, *res=NULL, *cur; int err, retry=0; memset(&hints, 0, sizeof hints); #if defined(USE_IPv6) || defined(USE_WIN32) hints.ai_family=AF_UNSPEC; #else hints.ai_family=AF_INET; #endif hints.ai_socktype=SOCK_STREAM; hints.ai_protocol=IPPROTO_TCP; hints.ai_flags=0; if(addr_list->passive) { hints.ai_family=AF_INET; /* first try IPv4 for passive requests */ hints.ai_flags|=AI_PASSIVE; } for(;;) { err=getaddrinfo(host_name, port_name, &hints, &res); if(!err) break; if(res) freeaddrinfo(res); if(err==EAI_AGAIN && ++retry<=3) { s_log(LOG_DEBUG, "getaddrinfo: EAI_AGAIN received: retrying"); sleep(1); continue; } #if defined(USE_IPv6) || defined(USE_WIN32) if(hints.ai_family==AF_INET) { hints.ai_family=AF_UNSPEC; continue; /* retry for non-IPv4 addresses */ } #endif break; } if(err==EAI_SERVICE) { s_log(LOG_ERR, "Unknown TCP service \"%s\"", port_name); return 0; /* error */ } if(err) { s_log(LOG_ERR, "Error resolving \"%s\": %s", host_name ? host_name : (addr_list->passive ? DEFAULT_ANY : DEFAULT_LOOPBACK), s_gai_strerror(err)); return 0; /* error */ } /* copy the list of addresses */ for(cur=res; cur; cur=cur->ai_next) { if(cur->ai_addrlen>(int)sizeof(SOCKADDR_UNION)) { s_log(LOG_ERR, "INTERNAL ERROR: ai_addrlen value too big"); freeaddrinfo(res); return 0; /* no results */ } addr_list->addr=str_realloc(addr_list->addr, (addr_list->num+1)*sizeof(SOCKADDR_UNION)); memcpy(&addr_list->addr[addr_list->num], cur->ai_addr, (size_t)cur->ai_addrlen); ++(addr_list->num); } freeaddrinfo(res); return addr_list->num; /* ok - return the number of addresses */ }
/* move ready contexts from waiting queue to ready queue */ NOEXPORT void scan_waiting_queue(void) { int retval; CONTEXT *context, *prev; int min_timeout; unsigned int nfds, i; time_t now; static unsigned int max_nfds=0; static struct pollfd *ufds=NULL; time(&now); /* count file descriptors */ min_timeout=-1; nfds=0; for(context=waiting_head; context; context=context->next) { nfds+=context->fds->nfds; if(context->finish>=0) /* finite time */ if(min_timeout<0 || min_timeout>context->finish-now) min_timeout=context->finish-now<0 ? 0 : context->finish-now; } /* setup ufds structure */ if(nfds>max_nfds) { /* need to allocate more memory */ ufds=str_realloc(ufds, nfds*sizeof(struct pollfd)); max_nfds=nfds; } nfds=0; for(context=waiting_head; context; context=context->next) for(i=0; i<context->fds->nfds; i++) { ufds[nfds].fd=context->fds->ufds[i].fd; ufds[nfds].events=context->fds->ufds[i].events; nfds++; } #ifdef DEBUG_UCONTEXT s_log(LOG_DEBUG, "Waiting %d second(s) for %d file descriptor(s)", min_timeout, nfds); #endif do { /* skip "Interrupted system call" errors */ retval=poll(ufds, nfds, min_timeout<0 ? -1 : 1000*min_timeout); } while(retval<0 && get_last_socket_error()==S_EINTR); time(&now); /* process the returned data */ nfds=0; prev=NULL; /* previous element of the waiting queue */ context=waiting_head; while(context) { context->ready=0; /* count ready file descriptors in each context */ for(i=0; i<context->fds->nfds; i++) { context->fds->ufds[i].revents=ufds[nfds].revents; #ifdef DEBUG_UCONTEXT s_log(LOG_DEBUG, "CONTEXT %ld, FD=%d,%s%s ->%s%s%s%s%s", context->id, ufds[nfds].fd, ufds[nfds].events & POLLIN ? " IN" : "", ufds[nfds].events & POLLOUT ? " OUT" : "", ufds[nfds].revents & POLLIN ? " IN" : "", ufds[nfds].revents & POLLOUT ? " OUT" : "", ufds[nfds].revents & POLLERR ? " ERR" : "", ufds[nfds].revents & POLLHUP ? " HUP" : "", ufds[nfds].revents & POLLNVAL ? " NVAL" : ""); #endif if(ufds[nfds].revents) context->ready++; nfds++; } if(context->ready || (context->finish>=0 && context->finish<=now)) { /* remove context from the waiting queue */ if(prev) prev->next=context->next; else waiting_head=context->next; if(!context->next) /* same as context==waiting_tail */ waiting_tail=prev; /* append context context to the ready queue */ context->next=NULL; if(ready_tail) ready_tail->next=context; ready_tail=context; if(!ready_head) ready_head=context; } else { /* leave the context context in the waiting queue */ prev=context; } context=prev ? prev->next : waiting_head; } }
NOEXPORT void s_poll_realloc(s_poll_set *fds) { fds->ufds=str_realloc(fds->ufds, fds->allocated*sizeof(struct pollfd)); }
static void parse_file_list(FileData *file_data, int num_paths, const char *lsfile, const char *path_dir, AccessMethod method, int host) { FileState *file_state = NULL; FILE *fp; char *path_file; char *temp; char *text; char *name; time_t time; off_t size; mode_t mode; int type; char *ssh_command; int num_files = 0; fp = fopen(lsfile, "r"); if (fp == NULL) { perror("fopen"); fprintf(stderr, _("Cannot open file `%s'.\n"), lsfile); fatal_error(host); } while ((text = str_fgets(fp)) != NULL) { if (strncmp(text, "total", 5) == 0) { /* skip */ free(text); continue; } if (strncmp(text, "/bin/ls:", 8) == 0) { fprintf(stderr, _("Listing remote directory contents failed: %s\nThe directory doesn't exist or permission denied.\n"), path_dir); fatal_error(host); } switch (method) { case FTP: ftp_extract_file_status(text, &name, &size, &mode, &type, host); break; case SCP: case RSYNC: ssh_extract_file_status(text, &name, &time, &size, &mode, &type, host); break; default: internal_error(__FILE__, __LINE__); } free(text); if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0) { free(name); continue; } path_file = str_concat(path_dir, "/", name, NULL); if (type == 'l') { /* Check whether the symbolic link is directory or not. */ switch (method) { case FTP: type = ftp_chdir(path_file) ? 'd' : '-'; break; case SCP: case RSYNC: ssh_command = str_dup_printf("ssh %s@%s cd %s", config.login_name[host], config.host_name[host], path_file); type = (system(ssh_command) == 0) ? 'd' : '-'; free(ssh_command); break; default: internal_error(__FILE__, __LINE__); } } if ((type == 'd' && is_match_dir(path_file, config.ignore_remote_dir[host], host)) || (type != 'd' && (is_match_file(path_file, path_dir, config.ignore_remote_file[host], host) || is_match_file(path_file, path_dir, config.ignore_file[host], host)))) { free(path_file); free(name); continue; } if (config.conv_to_lower[host]) { temp = str_tolower(name); free(name); name = temp; free(path_file); path_file = str_concat(path_dir, "/", name, NULL); } if (method == FTP) { if (type != 'd') { time = ftp_get_last_modification_time(path_file, host); } else { time = 0; } } file_state = str_realloc(file_state, (num_files + 1) * sizeof(FileState)); file_state[num_files].name = name; file_state[num_files].time = time; file_state[num_files].size = size; file_state[num_files].mode = mode; file_state[num_files].isdir = (type == 'd'); file_state[num_files].isremoved = FALSE; num_files++; free(path_file); } if (fclose(fp) != 0) { perror("fclose"); fprintf(stderr, _("Cannot close file `%s'.\n"), lsfile); fatal_error(host); } sort_file_state(file_state, num_files); file_data->path_state[num_paths].num_files = num_files; file_data->path_state[num_paths].file_state = file_state; }
static void scan_local_file(FileData *file_data, const char *path_dir, int host) { FileState *file_state = NULL; DIR *dir; struct dirent *ent; struct stat status; struct tm *time; bool isdir; int num_paths; int num_files; char *path_file; dir = opendir(path_dir); if (dir == NULL) { perror("opendir"); fprintf(stderr, _("Cannot open directory `%s'.\n"), path_dir); exit(1); } num_paths = file_data->num_paths; file_data->num_paths++; file_data->path_state = str_realloc(file_data->path_state, sizeof(PathState) * (num_paths + 1)); file_data->path_state[num_paths].path = str_dup(path_dir); file_data->path_state[num_paths].isremoved = FALSE; file_data->path_state[num_paths].file_state = NULL; num_files = 0; while ((ent = readdir(dir)) != NULL) { if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0) { continue; } path_file = str_concat(path_dir, "/", ent->d_name, NULL); if (lstat(path_file, &status) == -1) { perror("lstat"); fprintf(stderr, _("Cannot get file status: %s\n"), path_file); exit(1); } if (config.follow_symlinks[host]) { if (expand_symlink(&status, path_file) == -1) { fprintf(stderr, _("Cannot expand symbolic link `%s'.\nThis file is ignored.\n"), path_file); free(path_file); continue; } } isdir = ((status.st_mode & S_IFDIR) == S_IFDIR); if ((isdir && is_match_dir(path_file, config.ignore_local_dir[host], host)) || (!isdir && (is_match_file(path_file, path_dir, config.ignore_local_file[host], host) || is_match_file(path_file, path_dir, config.ignore_file[host], host)))) { free(path_file); continue; } file_state = str_realloc(file_state, (num_files + 1) * sizeof(FileState)); file_state[num_files].name = str_dup(ent->d_name); time = gmtime(&status.st_mtime); file_state[num_files].time = mktime(time); file_state[num_files].size = status.st_size; file_state[num_files].mode = status.st_mode & 0777; file_state[num_files].isdir = isdir; file_state[num_files].isremoved = FALSE; if (isdir) { scan_local_file(file_data, path_file, host); } num_files++; free(path_file); } if (closedir(dir) == -1){ perror("closedir"); fprintf(stderr, _("Cannot close directory `%s'.\n"), path_dir); exit(1); } sort_file_state(file_state, num_files); if (config.conv_to_lower[host]) { check_conflict_with_conv_to_lower(file_state, num_files); } file_data->path_state[num_paths].num_files = num_files; file_data->path_state[num_paths].file_state = file_state; }