/** * Assemble a filepath from its directory and filename. * * @param dir_path directory path * @param filename file name * @return filepath */ char* make_path(const char* dir_path, const char* filename) { char* buf; size_t len; assert(dir_path); assert(filename); /* remove leading path separators from filename */ while (IS_PATH_SEPARATOR(*filename)) filename++; if (dir_path[0] == '.' && dir_path[1] == 0) { /* do not extend filename for dir_path="." */ return rsh_strdup(filename); } /* copy directory path */ len = strlen(dir_path); buf = (char*)rsh_malloc(len + strlen(filename) + 2); strcpy(buf, dir_path); /* separate directory from filename */ if (len > 0 && !IS_PATH_SEPARATOR(buf[len-1])) { buf[len++] = SYS_PATH_SEPARATOR; } /* append filename */ strcpy(buf+len, filename); return buf; }
/** * Allocate an empty vector. * * @param destructor pointer to the cleanup/deallocate function called * on each element when the vector is destructed, * NULL if items doesn't need to be freed * @return allocated vector */ vector_t* rsh_vector_new(void (*destructor)(void*)) { vector_t* ptr = (vector_t*)rsh_malloc(sizeof(vector_t)); memset(ptr, 0, sizeof(vector_t)); ptr->destructor = destructor; return ptr; }
/** * Print EDonkey 2000 url for given file to a stream. * * @param out the stream where to print url to * @param filename the file name * @param filesize the file size * @param sums the file hash sums */ static void fprint_ed2k_url(FILE* out, struct file_info *info, int print_type) { const char *filename = get_basename(file_info_get_utf8_print_path(info)); int upper_case = (print_type & PRINT_FLAG_UPPERCASE ? RHPR_UPPERCASE : 0); int len = urlencode(NULL, filename) + int_len(info->size) + (info->sums_flags & RHASH_AICH ? 84 : 49); char* buf = (char*)rsh_malloc( len + 1 ); char* dst = buf; assert(info->sums_flags & (RHASH_ED2K|RHASH_AICH)); assert(info->rctx); strcpy(dst, "ed2k://|file|"); dst += 13; dst += urlencode(dst, filename); *dst++ = '|'; sprintI64(dst, info->size, 0); dst += strlen(dst); *dst++ = '|'; rhash_print(dst, info->rctx, RHASH_ED2K, upper_case); dst += 32; if((info->sums_flags & RHASH_AICH) != 0) { strcpy(dst, "|h="); rhash_print(dst += 3, info->rctx, RHASH_AICH, RHPR_BASE32 | upper_case); dst += 32; } strcpy(dst, "|/"); fprintf(out, "%s", buf); free(buf); }
/** * Concatenate directory path with filename, unicode version. * * @param dir_path directory path * @param dir_len length of directory path in characters * @param filename the file name to append to the directory * @return concatenated path */ wchar_t* make_pathw(const wchar_t* dir_path, size_t dir_len, wchar_t* filename) { wchar_t* res; size_t len; if(dir_path == 0) dir_len = 0; else { /* remove leading path separators from filename */ while(IS_PATH_SEPARATOR_W(*filename)) filename++; if(dir_len == (size_t)-1) dir_len = wcslen(dir_path); } len = wcslen(filename); res = (wchar_t*)rsh_malloc((dir_len + len + 2) * sizeof(wchar_t)); if(dir_len > 0) { memcpy(res, dir_path, dir_len * sizeof(wchar_t)); if(res[dir_len - 1] != (wchar_t)SYS_PATH_SEPARATOR) { /* append path separator to the directory */ res[dir_len++] = (wchar_t)SYS_PATH_SEPARATOR; } } /* append filename */ memcpy(res + dir_len, filename, (len + 1) * sizeof(wchar_t)); return res; }
/** * Convert a c-string to wide character string using given codepage * * @param str the string to convert * @param codepage the codepage to use * @return converted string on success, NULL on fail */ static wchar_t* cstr_to_wchar(const char* str, int codepage) { wchar_t* buf; int size = MultiByteToWideChar(codepage, MB_ERR_INVALID_CHARS, str, -1, NULL, 0); if(size == 0) return NULL; /* conversion failed */ buf = (wchar_t*)rsh_malloc(size * sizeof(wchar_t)); MultiByteToWideChar(codepage, 0, str, -1, buf, size); return buf; }
/** * Allocate new print_item. * * @param flags the print_item flags * @param hash_id optional hash_id * @param data optional string to store * @return allocated print_item */ static print_item* new_print_item(unsigned flags, unsigned hash_id, const char *data) { print_item* item = (print_item*)rsh_malloc(sizeof(print_item)); item->flags = flags; item->hash_id = hash_id; item->width = 0; item->data = (data ? rsh_strdup(data) : NULL); item->next = NULL; return item; }
/** * Concatenates two strings and returns allocated buffer with result. * * @param orig original string * @param append the string to append * @return the buffer */ char* str_append(const char* orig, const char* append) { size_t len1 = strlen(orig); size_t len2 = strlen(append); char* res = (char*)rsh_malloc(len1 + len2 + 1); /* concatenate two strings */ memcpy(res, orig, len1); memcpy(res + len1, append, len2 + 1); return res; }
/** * Output aligned uint64_t number to specified output stream. * * @param out the stream to output to * @param filesize the 64-bit integer to output, usually a file size * @param width minimal width of integer to output * @param flag =1 if the integer shall be prepent by zeros */ static void fprintI64(FILE* out, uint64_t filesize, int width, int zero_pad) { char *buf = (char*)rsh_malloc(width > 40 ? width + 1 : 41); int len = int_len(filesize); sprintI64(buf, filesize, width); if(len < width && zero_pad) { memset(buf, '0', width-len); } fprintf(out, "%s", buf); free(buf); }
/** * Find long option info, by it's name and retrieve its parameter if required. * Error is reported for unknown options. * * @param option structure to receive the parsed option info * @param parg pointer to a command line argument */ static void parse_long_option(parsed_option_t* option, rsh_tchar ***parg) { size_t length; rsh_tchar* eq_sign; cmdline_opt_t *t; char* name; #ifdef _WIN32 rsh_tchar* wname = **parg; /* "--<option name>" */ int fail = 0; assert((**parg)[0] == L'-' && (**parg)[1] == L'-'); /* search for the '=' sign */ length = ((eq_sign = wcschr(wname, L'=')) ? (size_t)(eq_sign - wname) : wcslen(wname)); option->name = name = (char*)rsh_malloc(length + 1); rsh_vector_add_ptr(opt.mem, name); if(length < 30) { size_t i = 0; for(; i < length; i++) { if(((unsigned)wname[i]) <= 128) name[i] = (char)wname[i]; else { fail = 1; break; } } name[i] = '\0'; name += 2; /* skip "--" */ length -= 2; } else fail = 1; if(fail) fail_on_unknow_option(w2c(**parg)); #else option->name = **parg; name = **parg + 2; /* skip "--" */ length = ((eq_sign = strchr(name, '=')) ? (size_t)(eq_sign - name) : strlen(name)); name[length] = '\0'; #endif /* search for the option by its name */ for(t = cmdline_opt; t->type && (strncmp(name, t->long_name, length) != 0 || strlen(t->long_name) != length); t++) { } if(!t->type) { fail_on_unknow_option(option->name); /* report error and exit */ } option->o = t; /* store the option found */ if(is_param_required(t->type)) { /* store parameter without a code page conversion */ option->parameter = (eq_sign ? eq_sign + 1 : *(++(*parg))); } }
/** * Parse format string. * * @return a print_item list with parsed information */ print_item* parse_print_string(const char* format, unsigned *sum_mask) { char *buf, *p; print_item *list = NULL, **tail, *item = NULL; buf = p = (char*)rsh_malloc( strlen(format) + 1 ); tail = &list; *sum_mask = 0; for(;;) { while(*format && *format != '%' && *format != '\\') *(p++) = *(format++); if(*format == '\\') { if(*(++format) == '0') { item = new_print_item(PRINT_ZERO, 0, NULL); format++; } else { *p++ = parse_escaped_char(&format); continue; } } else if(*format == '%') { if( *(++format) == '%' ) { *(p++) = *format++; continue; } else { item = parse_percent_item(&format); if(!item) { *(p++) = '%'; continue; } if(item->hash_id) *sum_mask |= item->hash_id; } } if(p > buf || (!*format && list == NULL && item == NULL)) { *p = '\0'; *tail = new_print_item(PRINT_STR, 0, buf); tail = &(*tail)->next; p = buf; } if(item) { *tail = item; tail = &item->next; item = NULL; } if(!*format) break; }; free(buf); return list; }
/** * Allocate a file_set_item structure and initialize it with a filepath. * * @param filepath a filepath to initialize the file_set_item * @return allocated file_set_item structure */ static file_set_item* file_set_item_new(const char* filepath) { file_set_item *item = (file_set_item*)rsh_malloc(sizeof(file_set_item)); memset(item, 0, sizeof(file_set_item)); if(filepath) { if(!file_set_item_set_filepath(item, filepath)) { free(item); return NULL; } } return item; }
/** * Add a file info into the batch of files of given torrent. * * @param ctx torrent algorithm context * @param path file path * @param size file size */ void torrent_add_file(torrent_ctx *ctx, const char* path, uint64_t filesize) { size_t len = strlen(path); file_n_size_info* info = (file_n_size_info*)rsh_malloc(sizeof(uint64_t) + len + 1); info->size = filesize; memcpy(info->path, path, len + 1); vector_add_ptr(&ctx->files, info); /* recalculate piece length (but only if hashing not started yet) */ if(ctx->blocks_hashes.size == 0 && ctx->index == 0) { /* note: in case of batch of files should use a total batch size */ ctx->piece_length = torrent_default_piece_length(filesize); } }
/** * Return allocated buffer with the directory part of the path. * The buffer must be freed by calling free(). * * @param path file path * @return directory */ char* get_dirname(const char* path) { const char *p = path + strlen(path) - 1; char *res; for (; p > path && !IS_PATH_SEPARATOR(*p); p--); if ((p - path) > 1) { res = (char*)rsh_malloc(p-path+1); memcpy(res, path, p-path); res[p-path] = 0; return res; } else { return rsh_strdup("."); } }
/** * Convert a wide character string to c-string using given codepage. * Optionally set a flag if conversion failed. * * @param wstr the wide string to convert * @param codepage the codepage to use * @param failed pointer to the flag, to on failed conversion, can be NULL * @return converted string on success, NULL on fail */ char* wchar_to_cstr(const wchar_t* wstr, int codepage, int* failed) { int size; char *buf; BOOL bUsedDefChar, *lpUsedDefaultChar; if(codepage == -1) { codepage = (opt.flags & OPT_UTF8 ? CP_UTF8 : (opt.flags & OPT_OEM) ? CP_OEMCP : CP_ACP); } /* note: lpUsedDefaultChar must be NULL for CP_UTF8, otrherwise WideCharToMultiByte() will fail */ lpUsedDefaultChar = (failed && codepage != CP_UTF8 ? &bUsedDefChar : NULL); size = WideCharToMultiByte(codepage, 0, wstr, -1, 0, 0, 0, 0); if(size == 0) return NULL; /* conversion failed */ buf = (char*)rsh_malloc(size); WideCharToMultiByte(codepage, 0, wstr, -1, buf, size, 0, lpUsedDefaultChar); if(failed) *failed = (lpUsedDefaultChar && *lpUsedDefaultChar); return buf; }
/** * Open a directory for reading its content. * For simplicity the function supposes that dir_path points to an * existing directory and doesn't check for this error. * The Unicode version of the function. * * @param dir_path directory path * @return pointer to directory iterator */ WIN_DIR* win_wopendir(const wchar_t* dir_path) { WIN_DIR* d; /* append '\*' to the dir_path */ wchar_t *wpath = make_pathw(dir_path, (size_t)-1, L"*"); d = (WIN_DIR*)rsh_malloc(sizeof(WIN_DIR)); d->hFind = FindFirstFileW(wpath, &d->findFileData); free(wpath); if(d->hFind == INVALID_HANDLE_VALUE && GetLastError() == ERROR_ACCESS_DENIED) { free(d); errno = EACCES; return NULL; } /* note: we suppose if INVALID_HANDLE_VALUE was returned, then the file listing is empty */ d->state = (d->hFind == INVALID_HANDLE_VALUE ? -1 : 0); d->dir.d_name = NULL; return d; }
/** * Assemble a filepath from its directory and filename. * * @param dir_path directory path * @param filename file name * @return filepath */ char* make_path(const char* dir_path, const char* filename) { char* buf; size_t len; assert(dir_path); assert(filename); /* remove leading path separators from filename */ while(IS_PATH_SEPARATOR(*filename)) filename++; /* copy directory path */ len = strlen(dir_path); buf = (char*)rsh_malloc(len + strlen(filename) + 2); strcpy(buf, dir_path); /* separate directory from filename */ if(len > 0 && !IS_PATH_SEPARATOR(buf[len-1])) buf[len++] = SYS_PATH_SEPARATOR; /* append filename */ strcpy(buf+len, filename); return buf; }
/** * Check hash sums in a hash file. * Lines beginning with ';' and '#' are ignored. * * @param hash_file_path - the path of the file with hash sums to verify. * @param chdir - true if function should emulate chdir to directory of filepath before checking it. * @return zero on success, -1 on fail */ int check_hash_file(file_t* file, int chdir) { FILE *fd; char buf[2048]; size_t pos; const char *ralign; timedelta_t timer; struct file_info info; const char* hash_file_path = file->path; int res = 0, line_num = 0; double time; /* process --check-embedded option */ if(opt.mode & MODE_CHECK_EMBEDDED) { unsigned crc32_be; if(find_embedded_crc32(hash_file_path, &crc32_be)) { /* initialize file_info structure */ memset(&info, 0, sizeof(info)); info.full_path = rsh_strdup(hash_file_path); info.file = file; file_info_set_print_path(&info, info.full_path); info.sums_flags = info.hc.hash_mask = RHASH_CRC32; info.hc.flags = HC_HAS_EMBCRC32; info.hc.embedded_crc32_be = crc32_be; res = verify_sums(&info); fflush(rhash_data.out); if(!rhash_data.interrupted) { if(res == 0) rhash_data.ok++; else if(res == -1 && errno == ENOENT) rhash_data.miss++; rhash_data.processed++; } free(info.full_path); file_info_destroy(&info); } else { log_warning(_("file name doesn't contain a CRC32: %s\n"), hash_file_path); return -1; } return 0; } /* initialize statistics */ rhash_data.processed = rhash_data.ok = rhash_data.miss = 0; rhash_data.total_size = 0; if(file->mode & FILE_IFSTDIN) { fd = stdin; hash_file_path = "<stdin>"; } else if( !(fd = rsh_fopen_bin(hash_file_path, "rb") )) { log_file_error(hash_file_path); return -1; } pos = strlen(hash_file_path)+16; ralign = str_set(buf, '-', (pos < 80 ? 80 - (int)pos : 2)); fprintf(rhash_data.out, _("\n--( Verifying %s )%s\n"), hash_file_path, ralign); fflush(rhash_data.out); rhash_timer_start(&timer); /* mark the directory part of the path, by setting the pos index */ if(chdir) { pos = strlen(hash_file_path); for(; pos > 0 && !IS_PATH_SEPARATOR(hash_file_path[pos]); pos--); if(IS_PATH_SEPARATOR(hash_file_path[pos])) pos++; } else pos = 0; /* read crc file line by line */ for(line_num = 0; fgets(buf, 2048, fd); line_num++) { char* line = buf; char* path_without_ext = NULL; /* skip unicode BOM */ if(line_num == 0 && buf[0] == (char)0xEF && buf[1] == (char)0xBB && buf[2] == (char)0xBF) line += 3; if(*line == 0) continue; /* skip empty lines */ if(is_binary_string(line)) { log_error(_("file is binary: %s\n"), hash_file_path); if(fd != stdin) fclose(fd); return -1; } /* skip comments and empty lines */ if(IS_COMMENT(*line) || *line == '\r' || *line == '\n') continue; memset(&info, 0, sizeof(info)); if(!hash_check_parse_line(line, &info.hc, !feof(fd))) continue; if(info.hc.hash_mask == 0) continue; info.print_path = info.hc.file_path; info.sums_flags = info.hc.hash_mask; /* see if crc file contains a hash sum without a filename */ if(info.print_path == NULL) { char* point; path_without_ext = rsh_strdup(hash_file_path); point = strrchr(path_without_ext, '.'); if(point) { *point = '\0'; file_info_set_print_path(&info, path_without_ext); } } if(info.print_path != NULL) { file_t file_to_check; int is_absolute = IS_PATH_SEPARATOR(info.print_path[0]); IF_WINDOWS(is_absolute = is_absolute || (info.print_path[0] && info.print_path[1] == ':')); /* if filename shall be prepended by a directory path */ if(pos && !is_absolute) { size_t len = strlen(info.print_path); info.full_path = (char*)rsh_malloc(pos + len + 1); memcpy(info.full_path, hash_file_path, pos); strcpy(info.full_path + pos, info.print_path); } else { info.full_path = rsh_strdup(info.print_path); } memset(&file_to_check, 0, sizeof(file_t)); file_to_check.path = info.full_path; rsh_file_stat(&file_to_check); info.file = &file_to_check; /* verify hash sums of the file */ res = verify_sums(&info); fflush(rhash_data.out); rsh_file_cleanup(&file_to_check); file_info_destroy(&info); if(rhash_data.interrupted) { free(path_without_ext); break; } /* update statistics */ if(res == 0) rhash_data.ok++; else if(res == -1 && errno == ENOENT) rhash_data.miss++; rhash_data.processed++; } free(path_without_ext); } time = rhash_timer_stop(&timer); fprintf(rhash_data.out, "%s\n", str_set(buf, '-', 80)); print_check_stats(); if(rhash_data.processed != rhash_data.ok) rhash_data.error_flag = 1; if(opt.flags & OPT_SPEED && rhash_data.processed > 1) { print_time_stats(time, rhash_data.total_size, 1); } rhash_data.processed = 0; res = ferror(fd); /* check that crc file has been read without errors */ if(fd != stdin) fclose(fd); return (res == 0 ? 0 : -1); }
/** * Rename given file inserting its crc32 sum enclosed into square braces * and placing it right before the file extension. * * @param info pointer to the data of the file to rename. * @return 0 on success, -1 on fail with error code in errno */ int rename_file_by_embeding_crc32(struct file_info *info) { size_t len = strlen(info->full_path); const char* p = info->full_path + len; const char* c = p - 1; char* new_path; char* insertion_point; unsigned crc32_be; assert((info->rctx->hash_id & RHASH_CRC32) != 0); /* check if the filename contains a CRC32 hash sum */ if(find_embedded_crc32(info->print_path, &crc32_be)) { unsigned char* c = (unsigned char*)rhash_get_context_ptr(info->rctx, RHASH_CRC32); unsigned actual_crc32 = ((unsigned)c[0] << 24) | ((unsigned)c[1] << 16) | ((unsigned)c[2] << 8) | (unsigned)c[3]; /* compare with calculated CRC32 */ if(crc32_be != actual_crc32) { char crc32_str[9]; rhash_print(crc32_str, info->rctx, RHASH_CRC32, RHPR_UPPERCASE); /* TRANSLATORS: sample filename with embedded CRC32: file_[A1B2C3D4].mkv */ log_warning(_("wrong embedded CRC32, should be %s\n"), crc32_str); } else return 0; } /* find file extension (as the place to insert the hash sum) */ for(; c >= info->full_path && !IS_PATH_SEPARATOR(*c); c--) { if(*c == '.') { p = c; break; } } /* now p is the point to insert delimiter + hash string in brackets */ new_path = (char*)rsh_malloc(len + 12); insertion_point = new_path + (p - info->full_path); memcpy(new_path, info->full_path, p - info->full_path); if(opt.embed_crc_delimiter && *opt.embed_crc_delimiter) *(insertion_point++) = *opt.embed_crc_delimiter; rhash_print(insertion_point+1, info->rctx, RHASH_CRC32, RHPR_UPPERCASE); insertion_point[0] = '['; insertion_point[9] = ']'; /* ']' overrides '\0' inserted by rhash_print_sum() */ strcpy(insertion_point + 10, p); /* append file extension */ /* rename the file */ if(rename(info->full_path, new_path) < 0) { log_error(_("can't move %s to %s: %s\n"), info->full_path, new_path, strerror(errno)); free(new_path); return -1; } /* change file name in the file info structure */ if(info->print_path >= info->full_path && info->print_path < p) { file_info_set_print_path(info, new_path + len - strlen(info->print_path)); } else { file_info_set_print_path(info, new_path); } free(info->full_path); info->full_path = new_path; return 0; }
/** * Parse command line arguments. * * @param cmd_line structure to store parsed options data */ static void parse_cmdline_options(struct parsed_cmd_line_t* cmd_line) { int argc; int n_files = 0, b_opt_end = 0; rsh_tchar** files; rsh_tchar **parg, **end_arg; parsed_option_t *next_opt; #ifdef _WIN32 parg = cmd_line->warg = CommandLineToArgvW(GetCommandLineW(), &argc); if( NULL == parg || argc < 1) { die(_("CommandLineToArgvW failed\n")); } #else argc = cmd_line->argc; parg = cmd_line->argv; #endif /* allocate array for files */ files = (rsh_tchar**)rsh_malloc(argc * sizeof(rsh_tchar*)); end_arg = parg + argc; /* loop by program arguments */ for(parg++; parg < end_arg; parg++) { /* if argument is not an option */ if((*parg)[0] != RSH_T('-') || (*parg)[1] == 0 || b_opt_end) { /* it's a file, note that '-' is interpreted as stdin */ files[n_files++] = *parg; continue; } assert((*parg)[0] == RSH_T('-') && (*parg)[1] != 0); if((*parg)[1] == L'-' && (*parg)[2] == 0) { b_opt_end = 1; /* string "--" means end of options */ continue; } /* check for "--" */ if((*parg)[1] == RSH_T('-')) { cmdline_opt_t *t; /* allocate parsed_option */ rsh_blocks_vector_add_empty(&cmd_line->options, 16, sizeof(parsed_option_t)); next_opt = rsh_blocks_vector_get_item(&cmd_line->options, cmd_line->options.size - 1, 16, parsed_option_t); /* find the long option */ parse_long_option(next_opt, &parg); t = next_opt->o; /* process encoding and -o/-l options early */ if(is_output_modifier(t->type)) { apply_option(&opt, next_opt); } } else if((*parg)[1] != 0) { /* found '-'<some string> */ rsh_tchar* ptr; /* parse short options. A string of several characters is interpreted * as separate short options */ for(ptr = *parg + 1; *ptr; ptr++) { cmdline_opt_t *t; char ch = (char)*ptr; #ifdef _WIN32 if(((unsigned)*ptr) >= 128) { ptr[1] = 0; fail_on_unknow_option(w2c(ptr)); } #endif /* allocate parsed_option */ rsh_blocks_vector_add_empty(&cmd_line->options, 16, sizeof(parsed_option_t)); next_opt = rsh_blocks_vector_get_item(&cmd_line->options, cmd_line->options.size - 1, 16, parsed_option_t); next_opt->buf[0] = '-', next_opt->buf[1] = ch, next_opt->buf[2] = '\0'; next_opt->name = next_opt->buf; next_opt->parameter = NULL; /* search for the short option */ for(t = cmdline_opt; t->type && ch != t->short1 && ch != t->short2; t++); if(!t->type) fail_on_unknow_option(next_opt->buf); next_opt->o = t; if(is_param_required(t->type)) { next_opt->parameter = (ptr[1] ? ptr + 1 : *(++parg)); if(!next_opt->parameter) { /* note: need to check for parameter here, for early -o/-l options processing */ log_error(_("argument is required for option %s\n"), next_opt->name); rsh_exit(2); } } /* process encoding and -o/-l options early */ if(is_output_modifier(t->type)) { apply_option(&opt, next_opt); } if(next_opt->parameter) break; /* a parameter ends the short options string */ } } } /* for */ cmd_line->n_files = n_files; cmd_line->files = files; }
/** * Print formated file information to given output stream. * * @param out the stream to print information to * @param list the format according to which information shall be printed * @param info the file information */ void print_line(FILE* out, print_item* list, struct file_info *info) { const char* basename = get_basename(info->print_path), *tmp; char *url = NULL, *ed2k_url = NULL; char buffer[130]; for(; list; list = list->next) { int print_type = list->flags & ~(PRINT_FLAGS_ALL); size_t len; /* output a hash function digest */ if(list->hash_id && print_type != PRINT_ED2K_LINK) { unsigned hash_id = list->hash_id; int print_flags = (list->flags & PRINT_FLAG_UPPERCASE ? RHPR_UPPERCASE : 0) | (list->flags & PRINT_FLAG_RAW ? RHPR_RAW : 0) | (list->flags & PRINT_FLAG_BASE32 ? RHPR_BASE32 : 0) | (list->flags & PRINT_FLAG_BASE64 ? RHPR_BASE64 : 0) | (list->flags & PRINT_FLAG_HEX ? RHPR_HEX : 0); if((hash_id == RHASH_GOST || hash_id == RHASH_GOST_CRYPTOPRO) && (opt.flags & OPT_GOST_REVERSE)) print_flags |= RHPR_REVERSE; len = rhash_print(buffer, info->rctx, hash_id, print_flags); assert(len < sizeof(buffer)); /* output the hash, exit on fail */ if(fwrite(buffer, 1, len, out) != len) break; continue; } /* output other special items: filepath, URL-encoded filename etc. */ switch(print_type) { case PRINT_STR: fprintf(out, "%s", list->data); break; case PRINT_ZERO: /* the '\0' character */ fprintf(out, "%c", 0); break; case PRINT_FILEPATH: fprintf(out, "%s", info->print_path); break; case PRINT_BASENAME: /* the filename without directory */ fprintf(out, "%s", basename); break; case PRINT_URLNAME: /* URL-encoded filename */ if(!url) { tmp = get_basename(file_info_get_utf8_print_path(info)); url = (char*)rsh_malloc(urlencode(NULL, tmp) + 1); urlencode(url, tmp); } fprintf(out, "%s", url); break; case PRINT_MTIME: /* the last-modified tine of the filename */ print_time(out, info->stat_buf.st_mtime); break; case PRINT_SIZE: /* file size */ fprintI64(out, info->size, list->width, (list->flags & PRINT_FLAG_PAD_WITH_ZERO)); break; case PRINT_ED2K_LINK: fprint_ed2k_url(out, info, list->flags); break; } } free(url); free(ed2k_url); }
/* allocate and fill the file_search_data */ file_search_data* create_file_search_data(rsh_tchar** paths, size_t count, int max_depth) { size_t i; file_search_data* data = (file_search_data*)rsh_malloc(sizeof(file_search_data)); memset(data, 0, sizeof(file_search_data)); rsh_blocks_vector_init(&data->root_files); data->max_depth = max_depth; #ifdef _WIN32 /* expand wildcards and fill the root_files */ for (i = 0; i < count; i++) { int added = 0; size_t length, index; wchar_t* path = paths[i]; wchar_t* p = wcschr(path, L'\0') - 1; /* strip trailing '\','/' symbols (if not preceded by ':') */ for (; p > path && IS_PATH_SEPARATOR_W(*p) && p[-1] != L':'; p--) *p = 0; /* Expand a wildcard in the current file path and store results into data->root_files. * If a wildcard is not found then just the file path is stored. * NB, only wildcards in the last filename of the path are expanded. */ length = p - path + 1; index = wcscspn(path, L"*?"); if (index < length && wcscspn(path + index, L"/\\") >= (length - index)) { /* a wildcard is found without a directory separator after it */ wchar_t* parent; WIN32_FIND_DATAW d; HANDLE handle; /* find a directory separator before the file name */ for (; index > 0 && !IS_PATH_SEPARATOR(path[index]); index--); parent = (IS_PATH_SEPARATOR(path[index]) ? path : 0); handle = FindFirstFileW(path, &d); if (INVALID_HANDLE_VALUE != handle) { do { file_t file; int failed; if (IS_CURRENT_OR_PARENT_DIRW(d.cFileName)) continue; memset(&file, 0, sizeof(file)); file.wpath = make_pathw(parent, index + 1, d.cFileName); if (!file.wpath) continue; /* skip directories if not in recursive mode */ if (data->max_depth == 0 && (d.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) continue; /* convert file name */ file.path = wchar_to_cstr(file.wpath, WIN_DEFAULT_ENCODING, &failed); if (!failed) { failed = (file_statw(&file) < 0); } /* quietly skip unconvertible file names */ if (!file.path || failed) { if (failed) { data->errors_count++; } free(file.path); free(file.wpath); continue; } /* fill the file information */ file.mode |= FILE_IFROOT; add_root_file(data, &file); added++; } while (FindNextFileW(handle, &d)); FindClose(handle); } else { /* report error on the specified wildcard */ char * cpath = wchar_to_cstr(path, WIN_DEFAULT_ENCODING, NULL); set_errno_from_last_file_error(); log_file_error(cpath); free(cpath); data->errors_count++; } } else { int failed; file_t file; memset(&file, 0, sizeof(file)); /* if filepath is a dash string "-" */ if ((path[0] == L'-' && path[1] == L'\0')) { file.mode = FILE_IFSTDIN; file.path = rsh_strdup("(stdin)"); } else { file.path = wchar_to_cstr(path, WIN_DEFAULT_ENCODING, &failed); if (failed) { log_error(_("Can't convert the path to local encoding: %s\n"), file.path); free(file.path); data->errors_count++; continue; } file.wpath = path; if (file_statw(&file) < 0) { log_file_error(file.path); free(file.path); data->errors_count++; continue; } } /* mark the file as obtained from the command line */ file.mode |= FILE_IFROOT; file.wpath = rsh_wcsdup(path); add_root_file(data, &file); } } /* for */ #else /* copy file paths */ for (i = 0; i < count; i++) { file_t file; file_init(&file, paths[i], 0); if (IS_DASH_STR(file.path)) { file.mode = FILE_IFSTDIN; } else if (file_stat2(&file, USE_LSTAT) < 0) { log_file_error(file.path); file_cleanup(&file); data->errors_count++; continue; } file.mode |= FILE_IFROOT; add_root_file(data, &file); } #endif return data; }