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?
Related
Im trying to copy the files from a directory into another using system calls but i get a "violation of segment core" and I don't know why, the first argument is the origin directory, the second the destiny directory, the third is not used and the fourth is the bytes position where I start to copy every file of the first directory with this I mean for example if Pos = 4 and the file is helloo the copied file content would be o because I use lseek to move to pointer to the position 4 and start to copy from there, this is my code:
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#define BS 512
#define error(a) {perror(a); exit(1);};
int main(int argc, char *argv[]) //argv1 Dir1 argv2 Dir2 argv3 Fich argv4 Pos
{
DIR *dir1;
DIR *dir2;
struct dirent *lectura1;
struct dirent *lectura2;
struct stat st;
int datos1;
int datos2;
int size;
char path[256] = "";
char path2[256] = "";
char temp[256];
char buf[BS];
int j;
int i;
if(argc != 5)
{
error("Numero de argumentos incorrecto");
}
int Pos = atoi(argv[4]);
if(Pos < 0)
{
error("Pos must be 0 or greater")
}
if((dir1 = opendir(argv[1])) == NULL){error("Failed to open origin dir");}
if((dir2 = opendir(argv[2])) == NULL){error("Failed to open destiny dir");}
while((lectura1 = readdir(dir1)) != NULL)
{
sprintf(path, "%s/%s", argv[1], lectura1->d_name);
lectura2 = readdir(dir2);
sprintf(path2, "%s/%s", argv[2], lectura2->d_name);
if (strcmp(lectura1->d_name, "..") != 0 && strcmp(lectura1->d_name, ".") != 0)
{
if (stat(path, &st) == 0)
{
if (S_ISREG(st.st_mode)) //If is a regular file
{
if((datos1 = open(path, O_RDONLY, 00600)) == -1){error("Failed to open file");} //Opens the target file of Dir1 to copy inside Dir2
size = lseek(datos1,0,SEEK_END);
if (size > Pos) //Check if the size of the file is bigger than the position that indicates the point from which to start copying the file
{
lseek(datos1,Pos,SEEK_SET); //Moves the pointer to the start position of the file1
if((datos2 = open(path2, O_CREAT|O_WRONLY, 00200)) == -1){error("Error al abrir archivo copia");}
lseek(datos2,0,SEEK_SET);
j = BS;
i = 0;
int n = 0;
if ((size - i) < BS)
{
j = size - i;
}
while ((n = read(datos1, buf, BS)) > 0)
{
n = write(datos2, buf, j);
i = i + n;
if ((size - i) < BS)
{
j = size - i;
}
}
close(datos1);
close(datos2);
}
}
}
}
}
close(dir1);
close(dir2);
return 0;
}
Yep, it seems to work like this:
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#define BS 512
#define error(a) {perror(a); exit(1);};
int main(int argc, char *argv[]) //argv1 Dir1 argv2 Dir2 argv3 Fich argv4 Pos
{
DIR *dir1;
DIR *dir2;
struct dirent *lectura1;
struct dirent *lectura2;
struct stat st;
int datos1;
int datos2;
int size;
char path[256] = "";
char path2[256] = "";
char temp[256];
char buf[BS];
int j;
int i;
if(argc != 5)
{
error("Numero de argumentos incorrecto");
}
int Pos = atoi(argv[4]);
if(Pos < 0)
{
error("Pos must be 0 or greater")
}
if((dir1 = opendir(argv[1])) == NULL){error("Failed to open origin dir");}
if((dir2 = opendir(argv[2])) == NULL){error("Failed to open destiny dir");}
while((lectura1 = readdir(dir1)) != NULL)
{
sprintf(path, "%s/%s", argv[1], lectura1->d_name);
sprintf(path2, "%s/%s", argv[2], lectura1->d_name); //<-- changed param
if (strcmp(lectura1->d_name, "..") != 0 && strcmp(lectura1->d_name, ".") != 0)
{
if (stat(path, &st) == 0)
{
if (S_ISREG(st.st_mode)) //If is a regular file
{
if((datos1 = open(path, O_RDONLY, 00600)) == -1){error("Failed to open file");} //Opens the target file of Dir1 to copy inside Dir2
size = lseek(datos1,0,SEEK_END);
if (size > Pos) //Check if the size of the file is bigger than the position that indicates the point from which to start copying the file
{
lseek(datos1,Pos,SEEK_SET); //Moves the pointer to the start position of the file1
if((datos2 = open(path2, O_CREAT|O_WRONLY, 00200)) == -1){error("Error al abrir archivo copia");}
lseek(datos2,0,SEEK_SET);
j = BS;
i = 0;
int n = 0;
if ((size - i) < BS)
{
j = size - i;
}
while ((n = read(datos1, buf, BS)) > 0)
{
n = write(datos2, buf, j);
i = i + n;
if ((size - i) < BS)
{
j = size - i;
}
}
close(datos1);
close(datos2);
}
}
}
}
}
closedir(dir1);
closedir(dir2); // <-- changed call
return 0;
}
I have searched online but didn't a solution. I want to copy the directories/folders from one place to another using C language. Although it could be possible using cp in command line but I want to implement that in C language.
To copy a folder, including all files and subfolders inside, you need to iterate over the content of the folder, and for each "entry" check if it's a file or folder
if the entry is a file then you can open it as binary and write all the content to a new file in the output path.
if the entry is a folder then you need to create the directory in the output path.
To iterate over the content of the folder you can use readdir from dirent.h, to check if an entry is a folder or file lstat and S_ISDIR from sys/stat.h, and to create folder mkdir from sys/stat.h.
This needs some polishing (it ought to handle a full path for a target dir, should think about edge cases, etc.), but this is a reasonable start:
/* Recursively duplicate a directory tree */
#include <dirent.h>
#include <err.h>
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
static DIR * xopendir(const char *);
static void xclosedir(DIR *, const char *);
static void xstat(const char *, struct stat *);
static void xrealpath(const char *s, char *resolved);
static void pathcat(char *p, char *n);
struct dir { DIR *d; char *path, *end; };
static void
build_dir(char *spath, char *dpath, char *name, mode_t mod)
{
struct dirent *f;
struct dir src;
struct dir dst;
src.end = strchr(spath, '\0');
dst.end = strchr(dpath, '\0');
pathcat(dpath, name);
if( mkdir(dpath, mod) == -1 && errno != EEXIST ){
err(EXIT_FAILURE, "%s", name);
}
if( getenv("V") ){
printf("%s -> %s\n", spath, dpath);
}
src.d = xopendir(src.path = spath);
while( (f = readdir(src.d)) != NULL ) {
if( !strcmp(f->d_name, ".") || !strcmp(f->d_name, "..") ){
continue;
}
if( f->d_type == DT_DIR ){
struct stat b;
pathcat(spath, f->d_name);
xstat(spath, &b);
build_dir(spath, dpath, f->d_name, b.st_mode);
*src.end = '\0';
}
}
*src.end = '\0';
*dst.end = '\0';
xclosedir(src.d, spath);
}
int
main(int argc, char **argv)
{
if( argc < 2 ){
errx(EXIT_FAILURE, "src directory missing");
}
if( argc < 3 ){
errx(EXIT_FAILURE, "target directory missing");
}
char spath[PATH_MAX];
char dpath[PATH_MAX];
xrealpath(argv[1], spath);
for( argv += 2; *argv; argv++ ){
char *name = *argv;
if( *name == '/' ){
dpath[0] = '\0';
} else {
getcwd(dpath, sizeof dpath);
}
build_dir(spath, dpath, name, 0777);
}
return 0;
}
static void
xrealpath(const char *s, char *resolved)
{
if( realpath(s, resolved) == NULL ){
err(EXIT_FAILURE, "%s", s);
}
}
static DIR *
xopendir(const char *path)
{
DIR *d = opendir(path);
if( d == NULL ) {
err(EXIT_FAILURE, "%s", path);
}
return d;
}
static void
xstat(const char *path, struct stat *buf)
{
if( stat(path, buf) ){
err(EXIT_FAILURE, "stat %s", path);
}
}
static void
xclosedir(DIR *d, const char *path)
{
if( closedir(d) ) {
err(EXIT_FAILURE, "%s", path);
}
}
static void
pathcat(char *p, char *n)
{
if( snprintf(p, PATH_MAX, "%s/%s", p, n) > PATH_MAX - 1 ){
errx(1, "path too long");
}
}
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);
}
I am using the code below to save file names to an array. I got the code from here save file names to an array. When I run this code it says that there are 5 files in the directory (i.e. count is 5), however, there are only 3. Could somebody verify if this is correct or am I making a bad mistake?
#include <string.h>
#include <stdio.h>
#include <dirent.h>
#include <malloc.h>
size_t file_list(const char *path, char ***ls) {
size_t count = 0;
size_t length = 0;
DIR *dp = NULL;
struct dirent *ep = NULL;
dp = opendir(path);
if(NULL == dp) {
fprintf(stderr, "no such directory: '%s'", path);
return 0;
}
*ls = NULL;
ep = readdir(dp);
while(NULL != ep){
count++;
ep = readdir(dp);
}
rewinddir(dp);
*ls = calloc(count, sizeof(char *));
count = 0;
ep = readdir(dp);
while(NULL != ep){
(*ls)[count++] = strdup(ep->d_name);
ep = readdir(dp);
}
closedir(dp);
return count;
}
int main(int argc, char **argv) {
char **files;
size_t count;
int i;
count = file_list("/home/rgerganov", &files);
for (i = 0; i < count; i++) {
printf("%s\n", files[i]);
}
}
I asked myself the same question for a school project a few months ago. When you use the dirent structure and you list them accessing the element d_name, it actually counts the directories PLUS the "." and the "..", so it's normal. If you don't want to take them as directories, just create an iterator variable for the loop and add a condition like:
int i = 0;
while (condition)
{
if (ep->d_name[i] == '.' )
{
++i;
}
//do stuff here
}
I want to find md5sum of a file in Linux C, Is there any API where I can send file name to get md5sum of that file.
There's code here.
Also, the openssl libs have md5 functions (from here):
#include <openssl/md5.h>
#include <unistd.h>
int main()
{
int n;
MD5_CTX c;
char buf[512];
ssize_t bytes;
unsigned char out[MD5_DIGEST_LENGTH];
MD5_Init(&c);
bytes=read(STDIN_FILENO, buf, 512);
while(bytes > 0)
{
MD5_Update(&c, buf, bytes);
bytes=read(STDIN_FILENO, buf, 512);
}
MD5_Final(out, &c);
for(n=0; n<MD5_DIGEST_LENGTH; n++)
printf("%02x", out[n]);
printf("\n");
return(0);
}
You can use popen to run md5sum and read the output:
#include <stdio.h>
#include <ctype.h>
#define STR_VALUE(val) #val
#define STR(name) STR_VALUE(name)
#define PATH_LEN 256
#define MD5_LEN 32
int CalcFileMD5(char *file_name, char *md5_sum)
{
#define MD5SUM_CMD_FMT "md5sum %." STR(PATH_LEN) "s 2>/dev/null"
char cmd[PATH_LEN + sizeof (MD5SUM_CMD_FMT)];
sprintf(cmd, MD5SUM_CMD_FMT, file_name);
#undef MD5SUM_CMD_FMT
FILE *p = popen(cmd, "r");
if (p == NULL) return 0;
int i, ch;
for (i = 0; i < MD5_LEN && isxdigit(ch = fgetc(p)); i++) {
*md5_sum++ = ch;
}
*md5_sum = '\0';
pclose(p);
return i == MD5_LEN;
}
int main(int argc, char *argv[])
{
char md5[MD5_LEN + 1];
if (!CalcFileMD5("~/testfile", md5)) {
puts("Error occured!");
} else {
printf("Success! MD5 sum is: %s\n", md5);
}
}
You can use the mhash library (license is LGPL). On Debian systems:
sudo apt-get install libmhash-dev
See the man page man 3 mhash
But I don't think you can just give it the name of a file. You have to open the file yourself, read the data, and feed the data to this library's functions.
An easy answer to the question asked by Raja and using answer from sje397, the md5sum of a file can be calculated within the C program as below. Also notice that there is no need of writing the read command twice when you can use the do while loop.
int calculate_md5sum(char *filename)
{
//open file for calculating md5sum
FILE *file_ptr;
file_ptr = fopen(filename, "r");
if (file_ptr==NULL)
{
perror("Error opening file");
fflush(stdout);
return 1;
}
int n;
MD5_CTX c;
char buf[512];
ssize_t bytes;
unsigned char out[MD5_DIGEST_LENGTH];
MD5_Init(&c);
do
{
bytes=fread(buf, 1, 512, file_ptr);
MD5_Update(&c, buf, bytes);
}while(bytes > 0);
MD5_Final(out, &c);
for(n=0; n<MD5_DIGEST_LENGTH; n++)
printf("%02x", out[n]);
printf("\n");
return 0;
}
If you're looking to generate MD5 hash for a file and compare it with a string, you can use this.
Here, I have used D'Nabre's code from another SO answer and Michael Foukarakis's hex string to byte array code from this SO answer.
It needs to be linked against the OpenSSL library (gcc md5.c -o md5 -lssl) to work.
Sample usage:
unsigned char *file_hash = md5_for_file("~/testfile");
if (md5_is_match_str(file_hash, "b7be4ec867f9b0286b91dd40178774d6")) {
printf("Match\n");
} else {
printf("Mismatch\n");
}
free(file_hash);
md5.h:
#ifndef MD5_H
#define MD5_H
/** Caller to free result */
unsigned char *md5_for_file(char *filename);
/** md5_1 & md5_2 maybe NULL */
int md5_is_match(unsigned char *md5_1, unsigned char *md5_2);
/** md5 maybe NULL */
int md5_is_match_str(unsigned char *md5, const char *md5_str);
#endif //MD5_H
md5.c:
#include "md5.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/md5.h>
// Print the MD5 sum as hex-digits.
void print_md5_sum(unsigned char *md) {
int i;
for (i = 0; i < MD5_DIGEST_LENGTH; i++) {
printf("%02x", md[i]);
}
printf("\n");
}
// Get the size of the file by its file descriptor
unsigned long get_size_by_fd(int fd) {
struct stat statbuf;
if (fstat(fd, &statbuf) < 0) exit(-1);
return statbuf.st_size;
}
unsigned char *md5_for_file(char *filename) {
int file_descript;
unsigned long file_size;
char *file_buffer;
unsigned char *result = malloc(sizeof(*result) * MD5_DIGEST_LENGTH);
if (NULL == result) {
printf("malloc failed\n");
goto END;
}
printf("using file:\t%s\n", filename);
file_descript = open(filename, O_RDONLY);
if (file_descript < 0) exit(-1);
file_size = get_size_by_fd(file_descript);
printf("file size:\t%lu\n", file_size);
file_buffer = mmap(0, file_size, PROT_READ, MAP_SHARED, file_descript, 0);
MD5((unsigned char *) file_buffer, file_size, result);
munmap(file_buffer, file_size);
print_md5_sum(result);
END:
return result;
}
int md5_is_match(unsigned char *md5_1, unsigned char *md5_2) {
if (!md5_1 || !md5_2) {
return 0;
}
int i;
for (i = 0; i < MD5_DIGEST_LENGTH; i++) {
if (md5_1[i] != md5_2[i]) {
return 0;
}
}
return 1;
}
int md5_is_match_str(unsigned char *md5, char *md5_str) {
if (!md5 || !md5_str) { return 0; }
/** Make byte arrary from md5_str */
unsigned char md5_arr[MD5_DIGEST_LENGTH] = {0};
const char *pos = md5_str;
size_t count = 0;
/* WARNING: no sanitization or error-checking whatsoever */
for (count = 0; count < sizeof(md5_arr) / sizeof(md5_arr[0]); count++) {
sscanf(pos, "%2hhx", &md5_arr[count]);
pos += 2;
}
for (count = 0; count < sizeof(md5_arr) / sizeof(md5_arr[0]); count++) {
printf("%02x", md5_arr[count]);
}
printf("\n");
/** actual comparison */
if (memcmp(md5, md5_arr, MD5_DIGEST_LENGTH)) {
return 0;
}
return 1;
}