#define _GNU_SOURCE #include #include #include #include #include #include #include #include #include int debug = 1; /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ int patch_one_file(char *path, unsigned char *search, unsigned char *replace) { struct stat stat_value; unsigned char *curr_pos, *end_pos, *file_map; int fd, result; size_t search_len, replace_len, local_len, tail_len; search_len = strlen((const char *) search); // length of string without trailing \0 replace_len = strlen((const char *) replace); result = 0; fd = -1; file_map = MAP_FAILED; if(replace_len > search_len){ fprintf(stderr, "[%s] search-len < replace-len\n", __func__); result = -EINVAL; goto err_out; } fd = open(path, O_RDWR, 0666); if(fd < 0){ fprintf(stderr, "[%s] unable to open %s for RDWR: %s\n", __func__, path, strerror(errno)); result = -errno; goto err_out; } result = fstat(fd, &stat_value); if(result < 0){ fprintf(stderr, "[%s] unable to query file attributes for file %s: %s\n", __func__, path, strerror(errno)); result = -errno; goto err_out; } if((size_t) stat_value.st_size <= search_len){ goto err_out; } file_map = mmap(NULL, (size_t) stat_value.st_size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_POPULATE, fd, 0); if(file_map == MAP_FAILED){ fprintf(stderr, "[%s] unable to map file %s (size %ld): %s\n", __func__, path, stat_value.st_size, strerror(errno)); result = -errno; goto err_out; } curr_pos = file_map; end_pos = file_map + stat_value.st_size; while((curr_pos + search_len + 1) < end_pos){ curr_pos = memmem(curr_pos, end_pos - curr_pos, search, search_len); if(curr_pos == NULL){ // pattern not found, finished break; } /* before: * ------------------------------------------------------------ * XXX| search string | tail |0|XXXXXXXXXXXXXXXXXX * ------------------------------------------------------------ * after: * ------------------------------------------------------------ * XXX| replace string | tail |000000000000|XXXXXXXXXXXXXXXXXX * ------------------------------------------------------------ */ local_len = strlen((char *) curr_pos); tail_len = local_len - search_len; // copy replacement string memmove(curr_pos, replace, replace_len); // if found string has a tail part, move it to the end of the replaced string if(tail_len > 0){ memmove(curr_pos + replace_len, curr_pos + search_len, tail_len); } // make sure the new string is properly terminated and fill the // gap between moved tail end and original end of string with '\0' memset(curr_pos + replace_len + tail_len, 0x0, (search_len - replace_len) + 1); curr_pos += replace_len; }; msync(file_map, stat_value.st_size, MS_SYNC); err_out: if(file_map != MAP_FAILED){ munmap(file_map, stat_value.st_size); } if(fd >= 0){ close(fd); } return result; } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ int main(int argc, char *argv[]) { if(argc != 4){ return -1; } return patch_one_file(argv[1], (unsigned char *) argv[2], (unsigned char *) argv[3]); }