I'm writing a function that should read a string of unknown length. I can use read, malloc, open, close and my own library that behaves like a normal one. It includes functions from the standard library and a few additional.
The problem is that fill_append() copies string from gnl->buf to *line incorrectly. In addition to copying the string itself, it adds other characters. Functions with ft_ prefix work accurately.
int fill_append(t_gnl* gnl, char** line)
{
char* append;
int index;
char* sub;
char* tmp;
append = ft_strchr(gnl->buf, '\n');
if (append == NULL)
{
*line = ft_strdup(gnl->buf);
return (0);
}
index = (int)(append - gnl->buf);
sub = ft_strsub(gnl->buf, 0, index);
tmp = ft_strnew(ft_strlen(*line) + ft_strlen(sub) + 1);
ft_strcpy(tmp, *line);
ft_strcat(tmp, sub);
*line = tmp;
// tmp = (char *)malloc(ft_strlen(*line) + ft_strlen(sub) + 1);
// memcpy(tmp, *line, ft_strlen(*line));
// memcpy(tmp + ft_strlen(*line), sub, ft_strlen(sub) + 1);
// *line = tmp;
gnl->buf = ft_strdup(&gnl->buf[index + 1]);
return (1);
}
int read_fd(t_gnl* gnl, char** line)
{
int bsize;
char* tmp;
while ((bsize = read(gnl->fd, gnl->buf, BUFF_SIZE)))
{
gnl->buf[bsize] = '\0';
if (ft_strchr(gnl->buf, '\n') == NULL)
{
tmp = *line;
*line = ft_strjoin(*line, gnl->buf);
free(tmp);
free(gnl->buf);
gnl->buf = ft_strnew(BUFF_SIZE);
}
else
return (fill_append(gnl, line));
}
if (bsize == 0 && *line[0] == 0)
{
free(gnl->buf);
return (0);
}
return (1);
}
int get_next_line(const int fd, char** line)
{
static t_gnl* gnl;
if (fd < 0 || line == NULL)
return (-1);
*line = ft_strnew(0);
if (gnl)
if (gnl->buf)
if (fill_append(gnl, line))
return (1);
if (!gnl)
gnl = (t_gnl*)malloc(sizeof(t_gnl));
gnl->buf = ft_strnew(BUFF_SIZE);
gnl->fd = fd;
return (read_fd(gnl, line));
}
For example, with input is sfesefsefsefwefsefsefsef
sfesefsefsefwefsefsefsef function returns sfesefsefsefwefsefsefsef1
sfesefsefsefwefsefsefsef!
Header:
#ifndef GET_NEXT_LINE_H
#define GET_NEXT_LINE_H
#define BUFF_SIZE 150
#include <unistd.h>
#include <stdlib.h>
#include "libft/libft.h"
typedef struct s_gnl
{
char* buf;
int fd;
} t_gnl;
int get_next_line(const int fd, char** line);
#endif
Main:
#include <stdlib.h>
#include <fcntl.h>
#include "get_next_line.h"
#include "libft/libft.h"
int main(void)
{
int fd;
char* line;
fd = open("gnl.txt", O_RDONLY);
while (get_next_line(fd, &line))
{
ft_putendl(line);
ft_strdel(&line);
}
close(fd);
}
Related
I am currently developing a function in C that parses a file into a double dimensional array of characters (char **), the problem is that I get an extra line at the end, and I don't see how to fix that.
Can you help me?
Ps: My school requires me to use getline() and fopen().
Here is the code:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
void my_free_word_array(char **word_array)
{
size_t i = 0;
if (!word_array) {
return;
}
while (word_array[i] != NULL) {
free(word_array[i]);
++i;
}
free(word_array);
}
ssize_t my_put_str_arr(char **arr, int fd)
{
char cr = '\n';
ssize_t count = 0;
size_t i = 0;
if (!arr)
return -1;
while (arr[i]) {
count += write(fd, arr[i], strlen(arr[i]));
count += write(fd, &cr, 1);
i++;
}
return count;
}
void append_word_array(char ***array, char *line)
{
size_t array_len = 0;
while ((*array)[array_len] != NULL) {
array_len++;
}
size_t len = strlen(line);
if (line[len - 1] == '\n') {
line[len - 1] = '\0';
}
(*array)[array_len] = strdup(line);
(*array) = realloc((*array), (array_len + 2) * sizeof(char *));
(*array)[array_len + 1] = NULL;
}
void fill_from_file(char ***array, FILE *file)
{
char *line_buff = NULL;
size_t line_buff_size = 0;
ssize_t line_size = getline(&line_buff, &line_buff_size, file);
while (line_size >= 0) {
append_word_array(array, line_buff);
free(line_buff);
line_buff = NULL;
line_size = getline(&line_buff, &line_buff_size, file);
}
free(line_buff);
}
char **my_load_file_to_word_array(const char *filepath)
{
char **word_array = NULL;
FILE *file = fopen(filepath, "r");
if (!file) {
return NULL;
}
word_array = malloc(sizeof(char *));
if (!word_array) {
return NULL;
}
word_array[0] = NULL;
fill_from_file(&word_array, file);
fclose(file);
return word_array;
}
int main (int argc, char **argv)
{
char **file = my_load_file_to_word_array(argv[1]);
my_put_str_arr(file, 1);
my_free_word_array(file);
return 0;
}
Here is the content of the tested file (I added the \n \0 to make it easier for you to see):
My name is Saul.\n
I am Saul Goodman.\n
Better call Saul.\0
And this is the result I get :
My name is Saul.
I am Saul Goodman.
Better call Saul.
The "problem" with your code is that the function my_put_str_arr() prints the stored lines eached followed by a single \n character. If you don't want to print the last \n you would need to test if a next line exists. You could change your loop as follows:
while (arr[i]) {
count += write(fd, arr[i], strlen(arr[i]));
i++;
if (arr[i]) {
count += write(fd, &cr, 1);
}
}
Get specific content from a file and store it in a variable. So far I get that I can convert the file content into a string. But I'm not sure how can I 'extract' the content from the string I converted and would like some help.
The original file looks something like this:
XXXXXX
XXXXX
Addr = 12:23:34:45:45
XXX
XXX
I need to extract and store the Addr as a string. Want to look for the prefix Addr = and just copy it into a buffer. But I don't know how can I do it...
So far my code looks like below:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
//So far I'm looking for it using the MAC addr format
const char *get_mac_addr(char *str, char *dest) {
if (str == NULL)
return 0;
char *start = NULL;
int token_count = 0;
char *ptr = str;
if (*ptr && *(ptr + 1)) // skip two chars in the beginning of the string
ptr += 2;
else
return 0;
while (*ptr != '\0' && *ptr != '\n' && *ptr != '\r') {
if (token_count == 5)
break;
/* if ':' found and previous two characters are hexidecimal digits then
the substring could be part of MAC
*/
if (*ptr == ':' && isxdigit(*(ptr - 1)) && isxdigit(*(ptr - 2))) {
token_count++;
if (start == NULL)
start = ptr - 2;
int i = 0;
while (*ptr != '\0' && i++ < 3)
ptr++;
} else {
start = NULL;
token_count = 0;
ptr++;
}
}
strcpy(dest, start);
return dest;
}
const char *file2str(){
/* declare a file pointer */
FILE *infile;
char *buffer;
long numbytes;
char dest[18];
/* open an existing file for reading */
infile = fopen("~/Desktop/file.config", "r");
/* quit if the file does not exist */
//if (infile == NULL)
// return 1;
/* Get the number of bytes */
fseek(infile, 0L, SEEK_END);
numbytes = ftell(infile);
/* reset the file position indicator to
the beginning of the file */
fseek(infile, 0L, SEEK_SET);
/* grab sufficient memory for the
buffer to hold the text */
buffer = (char *)calloc(numbytes, sizeof(char));
/* memory error */
//if(buffer == NULL)
// return 1;
/* copy all the text into the buffer */
fread(buffer, sizeof(char), numbytes, infile);
fclose(infile);
/* confirm we have read the file by
outputing it to the console */
printf("The file called test.dat contains this text\n\n%s", buffer);
//memset(dest, '/0', sizeof(dest));
get_mac_addr(buffer, dest);
/* free the memory we used for the buffer */
//free(buffer);
printf("Dest is \n\n%s", dest);
return dest;
}
int main() {
printf(file2str);
return 0;
}
I really appreciate your help. Please bare with me as I'm not very good at c programming. I would like to convert the main function into one function so I can directly call it and return a string. I converted the main function as following, but I'm not sure why when I print it, there is nothing show up:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
FILE * xfopen(const char *path, const char *mode);
const char *MACadd()
{
char buf[256];
char *addr = NULL;
FILE *in = xfopen("~Desktop/file.config", "r");
while( fgets(buf, sizeof buf, in) ){
addr = strstr(buf, "Addr = ");
if( addr && addr < buf + sizeof buf - ADDRLEN){
addr += strlen("Addr = ");
addr[ADDRLEN] = '\0';
break;
}
}
//printf("addr = %s\n", addr);
return addr;
}
FILE *xfopen(const char *path, const char *mode)
{
FILE *fp = fopen(path, mode);
if( fp == NULL ){
perror(path);
exit(EXIT_FAILURE);
}
return fp;
}
int main(){
printf("%s", MACadd());
return 0;
}
You could read the file line by line with the fgets function and use the sscanf function to extract the relevant portion like that:
#include <stdio.h>
#include <ctype.h>
#include <stdbool.h>
#define ISXDGT(c) isxdigit((unsigned char)(c))
static bool is_macaddr (const char *s)
{
return ISXDGT(s[0]) && ISXDGT(s[1]) && s[2] == ':'
&& ISXDGT(s[3]) && ISXDGT(s[4]) && s[5] == ':'
&& ISXDGT(s[6]) && ISXDGT(s[7]) && s[8] == ':'
&& ISXDGT(s[9]) && ISXDGT(s[10]) && s[11] == ':'
&& ISXDGT(s[12]) && ISXDGT(s[13]) && s[14] == ':'
&& ISXDGT(s[15]) && ISXDGT(s[16]);
}
bool get_macaddr_from_file (const char *filename, char *macaddr)
{
char line[4096];
bool done = false;
FILE *fp = fopen(filename, "r");
if (fp == NULL) {
fprintf(stderr, "Cannot open the file '%s'\n", filename);
return false;
}
while (fgets(line, sizeof line, fp) != NULL) {
/* Modify the prefix (" Addr = " here) at your convenience */
if (sscanf(line, " Addr = %17s", macaddr) == 1 && is_macaddr(macaddr)) {
done = true;
break;
}
}
fclose(fp);
return done;
}
int main (void)
{
char macaddr[18];
if (get_macaddr_from_file("file.conf", macaddr)) {
printf("MAC: %s\n", macaddr);
}
}
char *extract(const char *str, char *buff)
{
char *addr = strstr(str, "Addr");
if(addr)
{
addr += sizeof("Addr") - 1;
while(!isdigit((unsigned char)*addr))
{
if(*addr == '\n' || !*addr)
{
addr = NULL;
break;
}
addr++;
}
if(addr)
{
while(*addr && *addr != '\n' && (isdigit(*addr) || *addr == ':'))
{
*buff++ = *addr++;
}
*buff = 0;
}
}
return addr ? buff : NULL;
}
void main(int argc, char** argv)
{
char *str = "XXXXXX\nXXXXX\n\nAddr = 12:23:234:145:45 \nXXX\nXXX\n";
char mac[30];
if(extract(str,mac)) printf("Hurray!!! `%s`\n", mac);
else printf("MIsareble failure\n");
}
https://godbolt.org/z/6TjK8b
This gets a little tricky if you don't want to restrict yourself to a fixed maximum line length, but it's probably sufficient to do something like:
#define ADDRLEN 14
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
FILE * xfopen(const char *path, const char *mode);
int
main(int argc, char **argv)
{
char buf[256];
char *addr = NULL;
FILE *in = xfopen(argc > 1 ? argv[1] : "-", "r");
while( fgets(buf, sizeof buf, in) ){
addr = strstr(buf, "Addr = ");
if( addr && addr < buf + sizeof buf - ADDRLEN){
addr += strlen("Addr = ");
addr[ADDRLEN] = '\0';
break;
}
}
printf("addr = %s\n", addr);
}
FILE *
xfopen(const char *path, const char *mode)
{
FILE *fp = path[0] != '-' || path[1] != '\0' ? fopen(path, mode) :
*mode == 'r' ? stdin : stdout;
if( fp == NULL ){
perror(path);
exit(EXIT_FAILURE);
}
return fp;
}
To break this into a function, you need to be a little bit careful. In your attempt, you've passed back references to local variables which cease to exist after the function returns. Perhaps you want something like:
#define ADDRLEN 14
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
FILE * xfopen(const char *path, const char *mode);
const char *
MACadd(const char *path, char *buf, size_t s)
{
char *addr = NULL;
FILE *in = xfopen(path, "r");
while( fgets(buf, s, in) ){
addr = strstr(buf, "Addr = ");
if( addr && addr < buf + s - ADDRLEN){
addr += strlen("Addr = ");
addr[ADDRLEN] = '\0';
break;
}
}
return addr;
}
FILE *xfopen(const char *path, const char *mode)
{
FILE *fp = fopen(path, mode);
if( fp == NULL ){
perror(path);
exit(EXIT_FAILURE);
}
return fp;
}
int
main(void)
{
char buf[256];
printf("%s", MACadd("input", buf, sizeof buf));
return 0;
}
I think that is easier than you are doing, once you moved the file contnent in a string, use strstr() - here ther is the description http://www.cplusplus.com/reference/cstring/strstr/ - to find "addr = " and then get the string from there to the character "\n"
follow this example
#include<string.h>
#include<stdio.h>
#define endchrptr(ptr1, ptr2, ptr3) (ptr1 < ptr2 ? (ptr1<ptr3?ptr1:ptr3) : (ptr2<ptr3?ptr2:ptr3))
bool get_mac_addr(const char* source, char *dest) {
if(source!=NULL&&dest!=NULL) {
char* addr_pointer=strstr(source, "Addr = ")+7;//find where the address start
char* end_addr_pointer=endchrptr(strchr(addr_pointer, '\n'), strchr(addr_pointer, '\r'), strchr(addr_pointer, '\0'));//find where the address ends
if(end_addr!=NULL) {
for(int i=0; i<end_addr_pointer-addr_pointer; ++i) {//copy the address
dest[i]=addr_pointer[i];
}
dest[end_addr_pointer-addr_pointer],
}
else return false;
}
else return false;
}
int main()
{
char *str = "XXXXXX\nXXXXX\n\nAddr = 12:23:234:145:45 \nXXX\nXXX\n";
char mac[30];
get_mac_addr(str, mac);
printf("%s", mac);
}
I just tried in DevC++ and it works.
Let me know if it works.
There are multiple problems in the code:
fopen("~/Desktop/file.config", "r"); will fail because the ~ in the filename is not expanded to the home directory by fopen, it is a feature of the command shell. Use the full path instead, or take the filename as an argument.
you do not check for fopen() failure: passing a null stream pointer to fseek has undefined behavior and will probably crash the program.
printf(file2str); is a major mistake: you try to use the bytes from the function as a format string, you will get garbage output and possibly a crash because of undefined behavior. Use printf("%s\n", file2str()); instead.
there is no need to read the whole file in memory at once for this problem, just reading one line at a time is much simpler. Furthermore, you do not allocate enough memory for the null terminator, so you get undefined behavior with using buffer as a C string.
get_mac_addr is way too complicated: you could use strstr to locate the string "Addr = " and extract the following word.
Here is a simpler version:
#include <ctype.h>
#include <stdio.h>
#include <string.h>
const char *get_mac_address(const char *str, char *dest) {
if (!strncmp(buf, "Addr = ", 7)) {
const char *p = buf + 7;
for (i = 0; i < 17; i++) {
if (i % 3 == 2) {
if (p[i] != ':')
break;
} else {
if (!isxdigit((unsigned char)p[i]))
break;
}
}
if (i == 17 && !isalnum((unsigned char)p[i]) {
memcpy(dest, p, 17);
dest[17] = '\0';
return dest;
}
}
return NULL;
}
int main() {
char buf[256];
char address[20];
FILE *fp = fopen("/home/ImTrying/Desktop/file.config", "r");
if (fp != NULL) {
while (fgets(fp, buf, sizeof buf)) {
if (get_mac_address(buf, address)) {
printf("Dest is %s\n", address);
break;
}
}
fclose(fp);
}
return 0;
}
I am trying to get the read() system call to read my file line by line and reverse each line to stdout. My issue is getting read() to read my file line by line because normally it just reads the whole file. I want the LINE_BUFFER size to be the max size a line can be.
I tried implementing a function to try to do this but it seems to break the program and I am a little lost on how to approach this problem.
Here is my code:
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#define LINE_BUFFER 1024
int charCount(const char *name1);
ssize_t readline (char *buf, size_t a, int b, off_t *offset);
int main(int argc, char* argv[]) {
if(argc ==2){
charCount(argv[1]);
}else{
printf("Provide a file\n");
}
return 0;
}
int charCount(const char *name1)
{
char buffer[LINE_BUFFER];
int fd;
ssize_t len = 0;
int nread;
int i = 0;
off_t offset = 0;
if ((fd = open(name1, O_RDONLY)) == -1)
{
perror("Error in opening file");
return (-1);
}
int size = lseek(fd,-1, SEEK_END);
while(size>=0)
{
while((len = readline(buffer,LINE_BUFFER,fd,&offset)) != -1){
write(1,buffer,1);
lseek(fd, -2,SEEK_CUR);
size--;
}
}
close(fd);
return(0);
}
ssize_t readline(char *buf, size_t a, int b, off_t *offset)
{
int fd;
ssize_t nchr =0;
ssize_t idx =0;
char *p = NULL;
if ((nchr = lseek(fd, *offset, SEEK_SET)) != -1){
nchr = read(fd,buf,a);
}
p = buf;
while(idx<nchr && *p != '\n') p++,idx++;
*p =0;
if(idx == nchr) {
*offset + nchr;
return nchr < (ssize_t)a ? nchr : 0;
}
*offset += idx+1;
return idx;
}
I'm not sure what you mean when you say that "normally it just reads the whole file". read has a fairly low maximum size it will read, typically 4KiB or 8KiB. In any case, I put together some code to reverse line of a file.
#include <assert.h>
#include <fcntl.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int xopen(const char *, int);
void * Realloc(void *, size_t);
void reverse(char *, char *);
char * findchr(char *, char *, char);
int
main(int argc, char **argv)
{
ssize_t rc;
size_t siz = BUFSIZ; /* size available to read into */
char *buf = Realloc(NULL, BUFSIZ + siz); /* Pad the front */
char *s = buf + BUFSIZ; /* first char of a line */
char *prev = s; /* start of data from previous read */
char *end = s; /* one past last char read from input */
int fd = argc > 1 ? xopen(argv[1], O_RDONLY) : STDIN_FILENO;
while(( rc = read( fd, s, BUFSIZ )) > 0 ) {
char *eol; /* A newline, or one past valid data */
end = s + rc;
if( (eol = findchr(s, end, '\n')) == end ) {
/* No newlines found in the last read. Read more. */
if( end > buf + siz ) {
ptrdiff_t e_off = end - buf;
ptrdiff_t p_off = prev - buf;
siz += BUFSIZ;
buf = Realloc(buf, BUFSIZ + siz);
eol = end = buf + e_off;
prev = buf + p_off;
}
s = end;
assert( s <= buf + siz );
continue;
}
s = prev;
do {
assert(*eol == '\n');
assert(eol < end);
reverse(s, eol-1);
s = eol + 1;
assert(s <= end);
} while( (eol = findchr(s, end, '\n')) < end );
assert(eol == end);
assert(eol[-1] != '\n' || s == end);
fwrite(prev, 1, s - prev, stdout);
prev = buf + BUFSIZ - (end - s);
memcpy(prev, s, end - s);
eol = s = buf + BUFSIZ;
}
if(rc == -1) {
perror(argc > 1 ? argv[1] : "stdin");
return EXIT_FAILURE;
}
if(prev < s) {
reverse(prev, s-1);
fwrite(prev, 1, s - prev, stdout);
}
return EXIT_SUCCESS;
}
/*
* Find v between str and end. If not found,
* return end. (This is basically strchr, but
* doesn't care about nul.)
*/
char *
findchr(char *str, char *end, char v) {
assert(str <= end);
while( str < end && *str != v )
str += 1;
return str;
}
void
reverse(char *start, char *end)
{
for( ; start < end; start++, end-- ) {
char tmp = *end;
*end = *start;
*start = tmp;
}
}
void *
Realloc( void *buf, size_t s )
{
buf = realloc( buf, s );
if( buf == NULL) { perror("realloc"); exit(EXIT_FAILURE); }
return buf;
}
int
xopen(const char *path, int flag)
{
int fd = open(path, flag);
if( fd == -1 ) { perror(path); exit(EXIT_FAILURE); }
return fd;
}
I wrote the next function that tries to read and enter each line from text file into a string array in c :
int main(int argc,char* argv[])
{
char ** lines;
readFile(argv[1],lines);
}
int readFile(char* filePath,char** lines)
{
char file_char;
int letter_in_line=0;
int line=1;
char* line_string=malloc(1024);
int j=1;
int fd=open(filePath,O_RDONLY);
if (fd < 0)
{
return 0;
}
while (read(fd,&file_char,1) >0)
{
if(file_char != '\n' && file_char != '0x0')
{
line_string[letter_in_line] = file_char;
letter_in_line++;
}
else
{
if(lines != NULL)
{
lines=(char**)realloc(lines,sizeof(char*)*line);
}
else
{
lines=(char**)malloc(sizeof(char*));
}
char* line_s_copy=strdup(line_string);
lines[line-1]=line_s_copy;
line++;
letter_in_line=0;
memset(line_string,0,strlen(line_string));
}
j++;
}
printf("cell 0 : %s",lines[0]);
return 1;
}
I have 2 questions :
1)Whenever the code reaches the print of cell 0, I'm getting
Segmentation fault (core dumped) error. What is wrong ?
2)In case I
want to see the changes in the lines array in my main, I should pass
&lines to the func and get char*** lines as an argument ? In
addition, I will need to replace every 'line' keyword with '*line' ?
*I know that I can use fopen,fget, etc... I decided to implement it in this way for a reason.
There is many issues that make your code core dump.
Here a version very similar to your code. I hope it will help you to understand this.
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <stdlib.h>
int read_file(const char *filename, char ***result)
{
/* open the file */
const int fd = open(filename, O_RDONLY);
if (fd < 0) {
*result = NULL;
return -1;
}
/* read the file characters by characters */
char *buffer = (char *)malloc(sizeof(char) * 1024);
char c;
int column = 0;
int line = 0;
*result = NULL;
/* for each characters in the file */
while (read(fd, &c, 1) > 0) {
/* check for end of line */
if (c != '\n' && c != 0 && column < 1024 - 1)
buffer[column++] = c;
else {
/* string are null terminated in C */
buffer[column] = 0;
column = 0;
/* alloc memory for this line in result */
*result = (char **)realloc(*result, sizeof(char *) *
(line + 1));
/* duplicate buffer and store it in result */
(*result)[line++] = strdup(buffer);
}
}
free(buffer);
return line;
}
int main(int argc, char *argv[])
{
if (argc != 2) {
fprintf(stderr, "usage: %s [filename]", argv[0]);
return 1;
}
char **lines;
int line_count = read_file(argv[1], &lines);
if (line_count < 0) {
fprintf(stderr, "cannot open file %s\n", argv[1]);
return 1;
}
for(int i=0; i < line_count; i++)
printf("%s\n", lines[i]);
return 0;
}
Here an other version:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int read_file(const char *filename, char ***result)
{
/* init result */
*result = NULL;
/* open the file */
FILE *file = fopen(filename, "r");
if (file == NULL)
return -1;
/* read the file line by line */
char *buffer = (char *)malloc(sizeof(char) * 1024);
int line = 0;
while (fgets(buffer, 1024, file)) {
*result = (char **)realloc(*result, sizeof(char *) *
(line + 1));
(*result)[line++] = strdup(buffer);
}
free(buffer);
return line;
}
int main(int argc, char *argv[])
{
if (argc != 2) {
fprintf(stderr, "usage: %s [filename]", argv[0]);
return 1;
}
char **lines;
int line_count = read_file(argv[1], &lines);
if (line_count < 0) {
fprintf(stderr, "cannot open file %s\n", argv[1]);
return 1;
}
for(int i=0; i < line_count; i++)
printf("%s\n", lines[i]);
return 0;
}
I have created two C-functions to encrypt and decrypt entire folders.
#include "myaes.h"
#define SUFFIX ".crypt" //the file suffix for encrypted files
#define MASTER "6ADAC6D678CF49EEF4BB9C16A61F4"
int aesEncryptDir(const char *d)
//encrypts every file in directory d
{
AES_KEY key;
DIR *dp = opendir(d);
FILE *fp,*fp_c;
struct dirent *entry;
char fullpath[strlen(d) + 300];
char cryppath[strlen(fullpath) + 20];
char buffer[10000];
void *in = malloc(16);
void *out = malloc(16);
int sz;
size_t s_read;
if(AES_set_encrypt_key(MASTER,256,&key) != 0)
return -1;
const AES_KEY *static_key = &key;
if(!dp) //could not dir file pointer, maybe the folder does not exist
return -1;
while(entry = readdir(dp))
{
if(strncmp(entry->d_name,".",1) != 0 && strncmp(entry->d_name,"..",2) != 0)
{
memset(fullpath,0,sizeof(fullpath));
memset(cryppath,0,sizeof(cryppath));
memset(buffer,0,sizeof(buffer));
snprintf(fullpath,sizeof(fullpath),"%s/%s",d,entry->d_name);
snprintf(cryppath,sizeof(fullpath),"%s%s",fullpath,SUFFIX);
if(strstr(fullpath,SUFFIX) != NULL)
continue;
fp = fopen(fullpath,"r+");
fp_c = fopen(cryppath,"w");
fseek(fp,0L,SEEK_END);
sz = ftell(fp);
rewind(fp);
fwrite(&sz,sizeof(int),1,fp_c);
while((s_read = fread(buffer,1,1000,fp)))
{
for(int v = 0; v < s_read; v+= 16)
{
memcpy(in,buffer+v,16);
AES_encrypt(in,out,static_key);
fwrite(out,1,16,fp_c);
}
}
}
fclose(fp);
remove(fullpath);
fclose(fp_c);
}
if(closedir(dp) != 0)
return -1;
free(in);
free(out);
return 0;
}
int aesDecryptDir(const char *d)
//decrypts every file in directory d
{
AES_KEY key;
DIR *dp = opendir(d);
FILE *fp,*fp_c;
struct dirent *entry;
char fullpath[strlen(d) + 300];
char comppath[strlen(d) + 300];
char recoverpath[strlen(fullpath)];
char buffer[10000];
int sz = 0;
void *in = malloc(16);
void *out= malloc(16);
if(AES_set_decrypt_key(MASTER,256,&key) != 0)
return -1;
const AES_KEY *static_key = &key;
if(!dp) //could not dir file pointer, maybe the folder does not exist
return -1;
while(entry = readdir(dp))
{
if(strncmp(entry->d_name,".",1) != 0 && strncmp(entry->d_name,"..",2) != 0)
{
memset(fullpath,0,sizeof(fullpath));
memset(recoverpath,0,sizeof(recoverpath));
snprintf(fullpath,sizeof(fullpath),"%s/%s",d,entry->d_name);
strcpy(comppath,fullpath);
if(strstr(comppath,SUFFIX) == NULL)
continue;
strcpy(recoverpath,fullpath);
recoverpath[strlen(fullpath) - strlen(SUFFIX)] = '\0';
fp = fopen(fullpath,"r+");
fp_c = fopen(recoverpath,"w");
fread(&sz,sizeof(int),1,fp);
while(fread(in,16,1,fp))
{
AES_decrypt(in,out,static_key);
fwrite(out,(sz>=16)?16:sz,1,fp_c);
sz-=16;
}
fclose(fp);
fclose(fp_c);
}
}
if(closedir(dp) != 0)
return -1;
free(in);
free(out);
return 0;
}
myaes.h
#ifndef MYAES_H
#define MYAES_H
#include <dirent.h>
#include <openssl/aes.h>
#include <openssl/rand.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
int aesEncryptDir(const char *d);
int aesDecryptDir(const char *d);
#endif
If i now run a plain text file through aesEncryptDir and then aesDecryptDir, it comes out unchanged. A diff also indicates no changes. A binary file (.jpg) however gets corrupted in the process.
Why does this happen? Has it got something to do with the encoding of the binary files? Do I have to handle binary files differently for en-/decryption?