I'm trying to read in a file to buffer and encrypt each byte with my XOR encryption key. I have implemented it like the following but it segfaults for some reason.
int main(char argc, char *argv[]) {
fileIn = fopen("data.bin", "rb"); // open input file (binary)
if (fileIn==NULL) {
puts("Error opening input file");
exit (1);
}
// obtain file size.
fseek(fileIn , 0 , SEEK_END);
lSize = ftell(fileIn);
rewind(fileIn);
printf("Filesize: %d bytes.\n", lSize);
// allocate memory to contain the whole file.
buffer = (unsigned char*) malloc (lSize);
if (buffer == NULL) {
puts("malloc for input file buffer failed (not enough memory?)");
exit (2);
}
// copy the file into the buffer.
fread (buffer, 1, lSize, fileIn);
char *enckey = "enckey123";
unsigned char *buf = buffer;
int index = 0;
while (buf < buf + lSize - 1) {
*buf++ ^= enckey[index++ % 9]; // 9 is the length of the encryption key
}
}
It segfaults right at this like *buf++ ^= enckey[index++ % 9];.
Debugging with gdb, I can see that lSize is something like 2000, but index has the value of 128585.
What am I doing wrong?
This loop:
while (buf < buf + lSize - 1) {
never finishes.
Perhaps you meant
while (buf < buffer + lSize) {
?
P.S. the -1 means it doesn't encrypt the last character.
The loop will never end.
I think the loop needs a better way to iterate over only lSize bytes.
I did it by changing the last few lines to this:
// ...
// Calculate where to stop the iteration
const unsigned char *buf_end = buf + lSize - 1;
// Walk over lSize bytes in the buffer
while (buf < buf_end) {
*buf++ ^= enckey[index++ % 9]; // 9 is the length of the encryption key
}
// ...
Similar to other answers, but I think this is more readable:
Instead of this:
while (buf < buf + lSize - 1) {
*buf++ ^= enckey[index++ % 9]; // 9 is the length of the encryption key
}
This:
for (size_t i = 0; i < lSize; i++) {
buf[i] = enckey[i % 9];
}
Related
char* freadline(FILE* fp){
fseek(fp, 0, SEEK_END);
int lSize = ftell(fp);
fseek(fp, 0, SEEK_SET);
char *buffer = malloc(lSize);
fread(buffer, 1, lSize, fp);
fgets(buffer, sizeof(lSize), fp);
return buffer;
}
but it doesn't read line by line any suggestions as to how this would be read line by line
There are couple solutions here.
The first is to get the size of the entire file using fseek and ftell fseek will allow you to go to the end of file and ftell will give you the current position which can be used as a size indicator. You can then allocate enough of a buffer to read the entire file then split them up into lines.
The other solution is to use a temporary buffer of 1000 or so like you're already doing, read a character at a time using fgetc in a loop and feed it into the temporary buffer until you hit a new line indicator , then use the strlen method to get the length and allocate a buffer of that size, copy the temporary buffer then return the allocated buffer.
There is also errors in your code as pointed out in the comments. You're discarding your allocated memory resulting in a leak. And your freadline doesn't actually read a line it just reads whatever size you're telling it to read.
the lines in the file could be of any length.
realloc() is a classic approach, but how about a simple, slow and plodding one:
Read once to find line length, seek, allocate, then read again to save the line.
#include <stdio.h>
char* freadline(FILE *fp) {
int length = 0;
long offset = ftell(fp);
if (offset == -1)
return NULL;
int scan_count = fscanf(fp, "%*[^\n]%n", &length); // Save scan length
if (scan_count == EOF)
return NULL;
if (fseek(fp, offset, SEEK_SET))
return NULL;
size_t n = length + 1u; // +1 for potential \n
char *buf = malloc(n + 1); // + 1 for \0
if (buf == NULL)
return NULL;
size_t len = fread(buf, 1, n, fp);
buf[len] = '\0';
return buf;
}
Test
#include <assert.h>
#include <stdlib.h>
int main() {
FILE *fp = fopen("tmp.txt", "w+");
assert(fp);
for (int i = 0; i < 10; i++) {
int l = i * 7;
for (int j = 0; j < l; j++) {
fputc(rand() % 26 + 'a', fp);
}
fputc('\n', fp);
}
rewind(fp);
char *s;
while ((s = freadline(fp)) != NULL) {
printf("<%s>", s);
free(s);
}
fclose(fp);
return 0;
}
Output
<
><lvqdyoq
><ykfdbxnqdquhyd
><jaeebzqmtblcabwgmscrn
><oiaftlfpcuqffaxozqegxmwgglkh
><vxtdhnzqankyprbwteazdafeqxtijjtkwea
><zqgmplohyxrutojvbzllqgjaidbtqibygdzcxkujvw
><ghwbmjjmbpksnzkgzgiluiggpkzwhaetclrcyxcsixsutjmrm
><vqlybsjnihnfqyfhyszwgpsvnhnngdnjzjypqcflnztrhcfgbkakzxam
><alsuauxxchqjxqaiddtjszgcbullyyjymytioyawpzshhfpqpsatddbcagjgobm
>
If you're ok targeting POSIX, it already has a function that does what you need: getline.
#include <stdio.h>
#include <stdlib.h>
FILE *fh = ...;
char *line = NULL;
size_t buf_size = 0;
while (1) {
ssize_t line_len = getline(&line, &buf_size, fh);
if (line_len == -1)
break;
// ...
}
free(line);
If not, getline can be implemented using using fgets and realloc in a loop. Just start with a arbitrarily-sized buffer.
I've been picking at this for hours and can't figure out why the loop would try to access out of bounds memory.... Any help would be super appreciated!
int CountCharacters(FILE *fp, const char* filename){
// Get file size
fseek(fp, 0L, SEEK_END);
long size = ftell(fp);
if (size == -1){ perror("Failed: "); return 0;}
rewind(fp); //seek back to file's beginning
// Allocate approrpiately sized buffer ( size + 1 for null-termination)
char *buf = malloc(sizeof (char) * (size + 1));
// Read the entire file into memory
size_t newLen = fread(buf, sizeof(char), size, fp);
if ( ferror( fp ) != 0 ) {
fputs("Error reading file", stderr);
} else {
buf[newLen++] = '\0'; /* Just to be safe. */
}
//Try to get byte count from buffer
int byte_count[256] = {0}; //initialize character counts to 0
for (int i = 0; i < size; ++i){
byte_count[(int) buf[i]]++; //BAD ACCESS ERROR HERE
}
/* Do something with byte_count here */
return (1);
}
basically trying to make an anti virus but all I get when trying to read the infected file into a buffer is EOF... it's a jpg and I have no idea how to fix this
about the file functions I'm allowed to use:
fread/fwrite
fgets
fputs
fclose
fopen
fgetc
fputc
fscanf
fprintf
int fullScan(FILE* sign, FILE* infected);
char* getFile(FILE* file);
int main(int argc, char** argv)
{
FILE* sign = fopen("KittenVirusSign", "rb");
FILE* infected = fopen("kitten_frog.jpg", "rb");
int j = 0;
if (infected == NULL)
{
printf("couldn't open the file (suspicious file)");
return -1;
}
if (sign == NULL)
{
printf("couldn't open the file (virus signature)");
return -1;
}
j = fullScan(sign, infected);
return 0;
}
int fullScan(FILE* sign, FILE* infected)
{
char* sign_c = NULL;
char* infec_c = NULL;
int infect_res = -1;
int sign_len = 0;
int infec_len = 0;
int i = 0;
int j = 0;
sign_c = getFile(sign);
infec_c = getFile(infected);
while (1)
{
if (*(infec_c + i) == *(sign_c + j))
{
infect_res = 1;
if (*(sign_c + j) == EOF)
{
break;
}
else if (*(infec_c + i) == EOF)
{
infect_res = -1;
break;
}
i++;
j++;
continue;
}
else if (*(infec_c + i) != *(sign_c + j))
{
if (*(infec_c + i) == EOF || *(sign_c + j) == EOF)
{
break;
}
i++;
j = 0;
infect_res = -1;
}
}
fclose(infected);
free(sign_c);
free(infec_c);
return infect_res;
}
char* getFile(FILE* file)
{
char* buffer;
long filelen;
int i;
fseek(file, 0, SEEK_END);
filelen = ftell(file);
fseek(file, 0, SEEK_SET);
buffer = (char *)malloc((filelen + 1)*sizeof(char));
for (i = 0; i < filelen; i++)
{
fread(buffer + i, sizeof(char), 1, file);
}
return buffer;
}
EOF is a special integer value returned by some input functions to indicate that the end of the file has been reached, but it is not part of the file data. Your fread() will therefore never store an EOF character into the input buffer you provided. However, if your C implementation features signed default chars, as many do, then there is a char value that is numerically equal to EOF (usually -1).
If either file happens to contain that byte, then your code will misinterpret it as designating the end of that file. If it happens to be the first byte in either file then the program will misinterpret the file as being empty.
Since you are analyzing binary files,
I recommend using buffers of unsigned char rather than default char.
All possible byte values can appear in the file data, so you cannot identify the end of the data by the value of any byte within.
Probably, getFile() should return a struct that contains both a pointer to the buffer and its size.
As other answer suggested, you should also send the file length and iterate over that, rather than waiting for a EOF.
Also, in your getFile() function, when you determine the length of the file you don't have to read byte by byte, you can just send the filelen to fread() like so
fread(buffer, sizeof(char), filelen, file);
fread now reads filelen elements of data each the size of a char (you can write 1 instead) from the stream file to buffer.
I am trying to create a function that appends !! at the very end of each line from(inclusive)-to(exclusive) of a text file. After I had several complications I actually succeeded. But not entirely.
int incldue_auto (char *script, unsigned int offsetLine, unsigned int endLine)
{
size_t fileSize;
size_t content = (endLine - offsetLine) * 3; // New characters
char *buffer;
FILE* fp;
if((fp = fopen(script, "r")) == NULL) //return(1);
if(fseek(fp, 0l, SEEK_END) != 0) //return(2);
if((fileSize = ftell(fp)) == (-1l)) //return(3);
if(fseek(fp, 0l, SEEK_SET) != 0) //return(2);
if((buffer = calloc(fileSize + content, sizeof(char))) == NULL) //return(4);
if(fread(buffer, sizeof(char), fileSize, fp) != fileSize) //return(5);
if(fclose(fp) == EOF) //return(6);
{
int i, i2;
int lines = 0, ln = 0;
for(i = 0; i < fileSize; i++)
{
if(ln >= (endLine - offsetLine) || i[buffer] == '\0') break;
if(i[buffer] == '\n')
{
lines++;
if(lines >= offsetLine && lines < endLine)
{
char* p = (buffer + i); // \n
//if(*(p - 1) == '\n') continue;
memmove(p + 3,
p,
strlen(p)); // <-- Problematic line (I think)
memcpy(p, " !!", 3);
i += 3;
ln++;
}
}
}
fp = fopen(script, "w");
fwrite(buffer, fileSize + content, sizeof(char), fp);
fclose(fp);
}
free(buffer);
return 0;
}
It relatively works just fine, except for that it doesn't append to the last line. And it fills the text file with spaces (NULLs maybe) at the end.
I think it is because I am also moving the enzero-ed additional area content with that:
memmove(p + 3,
p,
strlen(p)); // <-- Problematic line (I think)
So maybe I need to figure out what is the appropriate formula I have to use in order to make this work.
Any ideas of how to make this work ?
Your loop condition is wrong:
for(i = 0; i < fileSize; i++)
After you have appended content to some lines, the end of the last line is moved beyond filesize and thus will no longer be treated.
You test whether the end of the buffer has been reached with i[buffer] == '\0', but that may lead to reading beyond the buffer after having done all shifts and there are nio more trailing zeroes. This shouldn't happen, because the end line condition is checked first, but better be safe by callocing one more char, which will then make buffer a zero-terminated string.
When you shift fewer lines than requested, because the file doesn't have the requested lines – say you shift lines 20 to 40 in a 30-line file – you still print out the trailing zeroes. You could either print the zero-terminated buffer as a string or you should keep track of the actual amount of data being appended.
You keep two redundant line counts, lines and ln. Pick one and remove the other; it only needlessly confuses the code.
Maybe you can put one more condition in your loop:
if(lines >= offsetLine && lines < endLine)
{
...//your code here before 'memcpy(p, " !!", 3);'
if(lines==endline)
{
memmove(p + 3, p, strlen(p));
}
//the end of your code here:
memcpy(p, " !!", 3);//your code here
i += 3;
ln++;
}
Then you will move 3 more characters if this is the last line and put '!!' just after this.
I program a program to split file in C in Ubuntu.
I have error when get buffer in readfile.
here is my code.
int split(char *filename, unsigned long part) {
FILE *fp;
char *buffer;
size_t result; // bytes read
off_t fileSize;
fp = fopen(filename, "rb");
if (fp == NULL) {
fprintf(stderr, "Cannot Open %s", filename);
exit(2);
}
// Get Size
fileSize = get_file_size(filename);
// Buffer
buffer = (char*) malloc(sizeof(char) * (fileSize + 1));
if (buffer == NULL) {
fputs("Memory error", stderr);
fclose(fp);
return 1;
}
// Copy file into buffer
//char buffers[11];
result = fread(buffer, 1, fileSize, fp);
buffer[fileSize] = '\0';
if (result != fileSize) {
fputs("Reading error", stderr);
return 1;
}
// Split file
off_t partSize = fileSize / part;
// Last Part
off_t lastPartSize = fileSize - partSize * part;
unsigned long i;
unsigned long j;
// create part 1 to n-1
for (j = 0; j < part; j++) {
char partName[255];
char *content;
char partNumber[3];
// Content of file part
// for (i = j; i < partSize * (j + 1); i++) {
//
// }
content = (char*) malloc(sizeof(char) * partSize);
content = copychar(buffer, j + i, partSize + i);
i += partSize;
//copy name
strcpy(partName, filename);
// part Number
sprintf(partNumber, "%d", j);
// file name with .part1 2 3 4 ....
strcat(partName, ".part");
strcat(partName, partNumber);
// Write to file
writeFile(partName, content);
free(content);
}
// last part
char *content;
content = (char*) malloc(sizeof(char) * (fileSize - partSize * (part - 1)));
content = copychar(buffer, (part - 1) * partSize + 1, fileSize);
char lastPartNumber[3];
char lastPartName[255];
sprintf(lastPartNumber, "%d", part);
strcpy(lastPartName, filename);
strcat(lastPartName, ".part");
strcat(lastPartName, lastPartNumber);
writeFile(lastPartName, content);
free(content);
free(buffer);
fclose(fp);
return 0;
}
here is function copychar from start to end
char *copychar(char* buffer, unsigned long start, unsigned long end) {
if (start >= end)
return NULL;
char *result;
result = (char*) malloc(sizeof(char) * (end - start) + 1);
unsigned long i;
for (i = start; i <= end; i++)
result[i] = buffer[i];
result[end] = '\0';
return result;
}
here is function to get filesize
off_t get_file_size(char *filename) {
struct stat st;
if (stat(filename, &st) == 0)
return st.st_size;
fprintf(stderr, "Cannot determine size of %s: %s\n", filename);
return -1;
}
here is function to write file
int writeFile(char* filename, char*buffer) {
if (buffer == NULL || filename == NULL)
return 1;
FILE *file;
file = fopen(filename, "wb");
fwrite(buffer, sizeof(char), sizeof(buffer) + 1, file);
fclose(file);
return 0;
}
When I test I use file test 29MB and it dumped.
I debug It return fileSize true but when readfile in buffer get from file it only return 135 characters and when use copychar it error.
Breakpoint 1, 0x0000000000400a0b in copychar (buffer=0x7ffff5e3a010 "!<arch>\ndebian-binary 1342169369 0 0 100644 4 `\n2.0\ncontrol.tar.gz 1342169369 0 0 100644 4557 `\n\037\213\b", start=4154703576, end=4164450461) at final.c:43
Program received signal SIGSEGV, Segmentation fault.
0x0000000000400a0b in copychar (buffer=0x7ffff5e3a010 "!<arch>\ndebian-binary 1342169369 0 0 100644 4 `\n2.0\ncontrol.tar.gz 1342169369 0 0 100644 4557 `\n\037\213\b", start=4154703576, end=4164450461) at final.c:43
Program terminated with signal SIGSEGV, Segmentation fault.
The program no longer exists.
I don't know how to devide buffer into part to write into part when split.
Thank for advance!
It's highly impractical to copy files in 1 big block as you may have noticed. And it's not needed.
At the simplest level you could copy the file byte by byte, like this
while( ( ch = fgetc(source) ) != EOF ) {
fputc(ch, target);
}
Which will work, but it will be quite slow. Better to copy in blocks, like this:
unsigned char buf[4096];
size_t size;
while( (size = fread(buf, 1, sizeof(buf), fpRead) ) > 0) {
fwrite(buf, 1, size, fpWrite);
}
Notice that the resulting code is way simpler and contains no dynamic memory allocation.
You still need to add the splitting logic of course, but that can be done by tracking the number of bytes written and opening a new write-file before actually writing it.
EDIT: how to handle the multipart facet - schematically, you still need to implement extra checks for some special cases and test results of the different system calls of course
unsigned char buf[4096];
size_t size;
size_t partsize = 100000; // asssuming you want to write 100k parts.
size_t stilltobewritten = partsize; // bytes remaining to be written in current part
size_t chunksize = sizeof(buf); // first time around we read full buffersize
while( (size = fread(buf, 1, chunksize, fpRead) ) > 0) {
fwrite(buf, 1, size, fpWrite);
stilltobewritten -= size; // subtract bytes written from saldo
if (stilltobewritten == 0) {
// part is complete, close this part and open next
fclose(fpWrite);
fpWrite = fopen(nextpart,"wb");
// and reinit variables
stilltobewritten = partsize;
chunksize = sizeof(buf);
} else {
// prep next round on present file - just the special case of the last block
// to handle
chunksize = (stilltobewritten > sizeof(buf)) ? sizeof(buf) : stilltobewritten;
}
}
and EDIT 2: the file part name can be made a LOT simpler as well:
sprintf(partName, "%s.part%d",file, j);
concerning the original code, there's some confusion about start and end in the copychar. First, you probably meant sizeof(char) * (end - start + 1) rather than sizeof(char) * (end - start) + 1 in the malloc, second, you're copying end-start+1 symbols from the original buffer (for (i = start; i <= end; i++)) and then overwrite the last one with '\0', which probably isn't the intended behavior.