miniz C can't zip file with absolute path - c

I'm using miniz to create a .zip file in C, on Windows.
I used the doc to produce my code and it works. I can create an archive with the files I want, ONLY if I give relative path to the zip function.
I don't get why the "file_name" variable must be something like "../test/file.txt" and not "C:/../test/file.txt".
if (!(status = mz_zip_add_mem_to_archive_file_in_place(archive, file_name, data, strlen(data) + 1, s_pComment,
(uint16) strlen(s_pComment), MZ_BEST_COMPRESSION)))
return (merror("add file to archive failed !!"));
Before this function, I open my file, get the data inside and call the zip_function with it.
if (!(src = fopen(file_name, "r")))
return (merror("can't open this file"));
char *line = NULL;
char *data= NULL;
size_t n = 0;
getline(&line, &n, src);
data= strdup(line);
while (getline(&line, &n, src) != -1){
data = realloc(save, sizeof(char) * (strlen(data) + strlen(line)) + 1);
data = strcat(data, line);
}
fopen(src);
So I call the zip function with the archive name, the file name (with the absolute path) and the datas inside it (in char * format).
This is the "full" code : the function init_zip is the first function called by my program. The arg parameter is the archive name I want to be create(it can be an absolute path and works) and the args parameter are the names of the differents files I want to add to the archive file (relative path works but not absolute).
typedef unsigned char uint8;
typedef unsigned short uint16;
typedef unsigned int uint;
static const char *s_pComment = "";
static int isDirectory(const char *path) {
struct stat statbuf;
if (stat(path, &statbuf) != 0)
return 0;
return S_ISDIR(statbuf.st_mode);
}
int get_data(const char *archive, const char *file)
{
FILE *src;
if (!isDirectory(file)) {
if (!(src = fopen(file, "r")))
return (merror("can't open this file"));
char *line = NULL;
char *save = NULL;
size_t n = 0;
getline(&line, &n, src);
save = strdup(line);
while (getline(&line, &n, src) != -1) {
save = realloc(save, sizeof(char) * (strlen(save) + strlen(line)) + 1);
save = strcat(save, line);
}
printf("compressing %s ..\n", file);
if (m_compress(archive, file, save))
return (merror("compress function failed"));
printf(("\tOK.\n"));
fclose(src);
}
else
{
DIR *dir;
struct dirent *entry;
char *new_file;
if (!(dir = opendir(file)))
return (merror("opendir failed: ", "wrong directory path in init_zip.get_data command : ", file, NULL));
while ((entry = readdir(dir)) != NULL)
{
if (strcmp(entry->d_name, ".") && strcmp(entry->d_name, "..")) {
new_file = add_path(file, entry->d_name);
get_data(archive, new_file);
}
}
if (new_file)
free(new_file);
closedir(dir);
}
}
int init_zip(const char *arg, const char **args)
{
printf("\nZIP cmd:\n >");
remove(arg);
for (int counter = 0; args[counter]; ++counter)
{
get_data(arg, args[counter]);
}
printf("All the files are added to %s archive file.\n", arg);
return (0);
}
int m_compress(const char *archive, const char *file_name, const char *data)
{
mz_bool status;
if (data)
if (!(status = mz_zip_add_mem_to_archive_file_in_place(archive, file_name, data, strlen(data) + 1, s_pComment,
(uint16) strlen(s_pComment), MZ_BEST_COMPRESSION)))
return (merror("add file to archive failed !!"));
else
if (!(status = mz_zip_add_mem_to_archive_file_in_place(archive, file_name, NULL, 0, "no comment", (uint16)strlen("no comment"), MZ_BEST_COMPRESSION)))
return (merror("add directory to archive failed !!"));
return (0);
}
This is the add_path() function used in get_data():
char *add_path(const char *str1, const char *str2)
{
char *path;
path = malloc(sizeof(char) * (strlen(str1) + 1 + strlen(str2) + 1));
path = strcpy(path, str1);
path = strcat(path, "/");
path = strcat(path, str2);
return (path);
}
Anyone knows something about it?

If nothing helps, then you should lookup the sources. Following the code in miniz on Github, file miniz_zip.c line 4297 I see:
mz_bool mz_zip_add_mem_to_archive_file_in_place(...
which calls function mz_zip_writer_validate_archive_name to check the second filename provided that it cannot start with a drive letter (line 3069) and if so
returns FALSE with error set to MZ_ZIP_INVALID_FILENAME.
As to why this second filename may not be an absolute path, I don't know. If it is important to you, you could get the code from Github and adapt it.

Related

Write a String to filename in c

I have this code and canĀ“t get it properly to work. I want to write the String Output into a file.
static void wr_message_user_info_login(wi_p7_message_t *message) {
wi_date_t *date;
wi_string_t *string, *interval;
wi_p7_uint32_t uid, build, bits;
wr_printf_block(WI_STR("Login: %#"),
wi_p7_message_string_for_name(message, WI_STR("wired.user.login")));
char *filename = "/.wirebot/wirebot.login";
char *home_dir = getenv("HOME");
char *filepath = malloc(strlen(home_dir) + strlen(filename) + 1);
sprintf(filepath, "%s%s", home_dir, filename);
FILE *fp;
fp = fopen(filepath, "w");
if (fp == NULL)
{
}
else
{
fputs((WI_STR("Login: %#")), fp);
);
fclose(fp);
}
"Login: %#" should be writed to file. Echoing is working fine.
You provided a snippet of code with a lot of stuff missing. If you strip the stuff you haven't told us about it seems to work:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static void wr_message_user_info_login() {
const char *filename = "/.wirebot/wirebot.login";
const char *home_dir = getenv("HOME");
char *filepath = malloc(strlen(home_dir) + strlen(filename) + 1);
if(!filepath) {
printf("malloc failed\n");
return;
}
sprintf(filepath, "%s%s", home_dir, filename);
FILE *fp = fopen(filepath, "w");
if (!fp) {
printf("fopen failed\n");
free(filepath);
return;
}
free(filepath);
fputs("Login: %#", fp);
fclose(fp);
}
int main() {
wr_message_user_info_login();
}
and example run:
$ mkdir ~/.wirebot && ./a.out && cat ~/.wirebot/wirebot.login
Login: %#
Maybe the directory ~/.wirebot doesn't exist on your host?

File isn't closing and read access violation exception in C?

I'm making kind of an antivirus as a part of a project I got. I need to find if a binary file includes a certain string anywhere in it. What I'm trying to do is add 7 chars to an array, because i know the virus signature is 7 chars long, then compare to the string and if they are equal, means the file is infected. But, it doesn't work. it says "Exception thrown: read access violation.
currStr was 0x1110113.". Also, whenever I try to free arrays or free files, the program crashed. Any help would be appreciated.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#define ARR_SIZE 250
void Search_in_File(char* dir, char* str)
{
FILE *fp;
DIR *folder;
char currFilePath[ARR_SIZE] = { 0 };
struct dirent *entry;
int files = 0;
char ch = 0;
char* virusStr;
char* currStr;
char* buffer;
int fSize = 0;
int index = 0;
folder = opendir(dir); //Opening the folder
if (folder == NULL)
{
perror("Unable to read directory");
return(1);
}
virusStr = (char*)malloc(sizeof(char) * ARR_SIZE);
strcpy(virusStr, str); // Getting the virus detection string
while ((entry = readdir(folder))) // Reading each file in the folder
{
if ((entry->d_name)[0] != '.') //Making sure that we will go over valid files only
{
strcpy(currFilePath, dir); //Coppy the folder name into the file path
files++;
printf("File %3d: %s\n",
files,
entry->d_name
);
strcat(currFilePath, "/"); //Add slash so we can add the filename and get full path
strcat(currFilePath, entry->d_name); // Adding file name after the slash
fp = fopen(currFilePath, "rb"); //Opening the file with the full path
if (fp == NULL)
{
printf("Error opening file!\n");
}
fseek(fp, 0, SEEK_END);
fSize = ftell(fp);
fseek(fp, 0, SEEK_SET);
buffer = (char*)malloc(fSize + 1);
fread(buffer, sizeof(char), fSize, fp); // Reading the file content into a string
currStr = (char*)malloc(sizeof(char) * strlen(str) + 1); //Memory for the checking string
printf("%d", strlen(currStr));
printf("%p", &currStr);
for (index; index < fSize; index++)
{
printf("%c", buffer[index]);
if (buffer[index] != EOF)
{
//Error happens here
strcat(currStr[index], buffer[index]); // Adding the current char to the current string
// Checking if we have a string the same length as the virus signature
if ((index % strlen(virusStr)) == 0)
{
if (strcmp(currStr, virusStr) == 0) // Checking if we have the same string
{
printf("%s - Infected!", entry->d_name);
break;
}
}
}
currStr = '\0'; // Reset the current string
}
index = 0;
currFilePath[0] = '\0'; // Resetting the file path in order to get the new one
}
}
closedir(folder);
//fclose(fp); //Doesnt Work - ????
//free(virusStr); //Doesnt Work - ????
//free(currStr);//Doesnt Work - ????
//free(buffer);//Doesnt Work - ????
}

fseek() and ftell() fail in a loop

I need to loop trough a directory, data and read each file, that meets certain conditions, in a string and do something with it. For some reason it fails after the fseek call (the output is only the name of the first file in the directory).
Any idea what am I doing wrong?
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <string.h>
void doAlgorithm(char *input) {
printf("%s\n", input);
}
int main(int argc, char** argv) {
struct dirent *dir;
DIR *d = opendir("data");
FILE *file;
while ((dir = readdir(d)) != NULL) {
if (strlen(dir->d_name) > 6 && dir->d_name[6] == 'i') {
printf("Filename: %s\n", dir->d_name);
file = fopen(dir->d_name, "r");
fseek(file, 0, SEEK_END);
long length = ftell(file);
fseek(file, 0, SEEK_SET);
printf(", Filesize: %ld\n", length);
char *buffer = malloc(length + 1);
fread(buffer, 1, length, file);
buffer[length] = '\0';
fclose(file);
doAlgorithm(buffer);
}
}
closedir(d);
return (EXIT_SUCCESS);
}
Your problem is that you file = fopen(dir->d_name, "r"); doesn't know where that file is in the directory. you need to give it the full path. You can do this;
struct dirent *dir;
// put the directory path here. on windows is \ instead of /
char *path = "/Users/adnis/CLion/Stackoverflow/testdir";
char *slash = "";
DIR *d = opendir(path);
FILE *file;
while ((dir = readdir(d)) != NULL) {
if (strlen(dir->d_name) > 6 && dir->d_name[6] == 'i') {
printf("Filename: %s\n", dir->d_name);
int length = strlen(path);
/*check if the path already contains a '/' at
the end before joining the filename to the directory*/
if(path[strlen(path)-1] != '/'){ //on windows is '\'
slash = "/";
}
length += strlen(dir->d_name)+2;
// allocate memory for the new path
// and make sure we have enough memory.
char *newpath = malloc(length);
assert(newpath != NULL);
snprintf(newpath,length,"%s%s%s",path,slash,dir->d_name);
file = fopen(newpath, "r");
if(file == NULL){
fprintf(stderr, "fopen: %s\n", strerror(errno));
break;
}
fseek(file, 0, SEEK_END);
long len = ftell(file);
fseek(file, SEEK_SET, 0);
char *buffer = malloc(len + 1);
fread(buffer, 1, len, file);
buffer[strlen(buffer)] = '\0';
printf("%s \n",buffer);
fclose(file);
}
}
closedir(d);
return (EXIT_SUCCESS);
I suggest that when reading directory you have to also try and avoid reading "." and ".." since they are just current directory and previous directory. something like this will help. In your while loop
if(strcmp(dir->d_name,".") == 0 || strcmp(dir->d_name,"..") == 0)
continue;

C get contents of file recursivley

I am trying to print out the contents of every file given a directory recursively. I have some logical error in my code and I can't figure out where it's going wrong.
Go through directory/subdirectories and get filename:
char filename[500], filepath[500];
void listdir(char *dir)
{
DIR *dp;
struct dirent *name;
struct stat statbuf;
if((dp = opendir(dir)) == NULL)
{
fprintf(stderr,"cannot open directory: %s\n", dir);
return;
}
chdir(dir);
while((name = readdir(dp)) != NULL)
{
if(lstat(name->d_name, &statbuf) == 0)
{
if(statbuf.st_mode & S_IFDIR)
{
/* Found a directory, but ignore . and .. */
if(strcmp(".", name->d_name) == 0 || strcmp("..", name->d_name) == 0)
continue;
// Directory name
int len = strlen(filepath);
strcat(filepath, name->d_name);
strcat(filepath, "/");
/* Recurse at a new indent level */
listdir(name->d_name);
filepath[len] = '\0';
}
else
{
// Filename
strcpy(filename, filepath);
strcat(filename, name->d_name);
// Prevent double printing
if(file[strlen(filename) - 1] != '~')
readFile(filename);
}
}
}
chdir("..");
closedir(dp);
}
Open/Read file contents:
void readFile(char *filepath)
{
char ch;
FILE *file;
file = fopen(filepath, "r");
if(file)
{
while((ch = fgetc(file)) != EOF)
printf("%c", ch);
fclose(file);
}
}
Main:
int main(int argc, int *argv[])
{
listdir(argv[1]);
return 0;
}
So if I run the program like this ./fileread ~/Desktop and I have this on the Desktop:
Songs.txt, test/test.txt, test/random.txt
It will print out the contents of Songs.txt, but won't print out anything inside the test folder. If I take out "Prevent double printing" line, then it will print out the contents of Songs.txt twice and still not print out anything inside the test folder.
What am I doing wrong? Any help would be appreciated!
UPDATED
I added local strings:
void getdir(char *dir)
{
char *direct;
char filepath[250];
...
direct = malloc(strlen(dir) + strlen(name->d_name) + 2);
strcpy(direct, dir);
strcat(direct, "/");
strcat(direct, name->d_name);
getdir(direct);
free(direct);
}
else
{
// Concatenate file name
strcpy(filepath, dir);
strcat(filepath, "/");
strcat(filepath, name->d_name);
if(filepath[strlen(filepath) - 1] != '~')
readFile(filepath);
}
This seems to work great. If there's anything I shouldn't do, please let me know. Thanks for the help everyone!

question regarding fopen - what am I doing wrong here?

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
static char *dup_str(const char *s)
{
size_t n = strlen(s) + 1;
char *t = (char*) malloc(n);
if (t)
{
memcpy(t, s, n);
}
return t;
}
static char **get_all_files(const char *path)
{
DIR *dir;
struct dirent *dp;
char **files;
size_t alloc, used;
if (!(dir = opendir(path)))
{
goto error;
}
used = 0;
alloc = 10;
if (!(files = (char**) malloc(alloc * sizeof *files)))
{
goto error_close;
}
while ((dp = readdir(dir)))
{
if (used + 1 >= alloc)
{
size_t new_thing = alloc / 2 * 3;
char **tmp = (char**) realloc(files, new_thing * sizeof *files);
if (!tmp)
{
goto error_free;
}
files = tmp;
alloc = new_thing;
}
if (!(files[used] = dup_str(dp->d_name)))
{
goto error_free;
}
++used;
}
files[used] = NULL;
closedir(dir);
return files;
error_free:
while (used--)
{
free(files[used]);
}
free(files);
error_close:
closedir(dir);
error:
return NULL;
}
int main(int argc, char **argv)
{
char **files;
size_t i;
if (argc != 2)
{
fprintf(stderr, "Usage: %s DIRECTORY\n", argv[0]);
return EXIT_FAILURE;
}
files = get_all_files(argv[1]);
if (!files)
{
fprintf(stderr, "%s: %s: something went wrong\n", argv[0], argv[1]);
return EXIT_FAILURE;
}
for (i = 0; files[i]; ++i)
{
FILE *fp;
if((fp = fopen(files[i],"r"))==NULL)
{
printf("error cannot open file\n");
exit(1);
}
fclose(fp);
}
for (i = 0; files[i]; ++i)
{
free(files[i]);
}
free(files);
return EXIT_SUCCESS;
}
I am just getting "error cannot open file".
If I invoke your program passing it /tmp as the argument.
files = get_all_files(argv[1]);
will return all the files in /tmp but when you do:
for (i = 0; files[i]; ++i) {
FILE *fp;
if((fp = fopen(files[i],"r"))==NULL)
you are trying to open those files from the present working directory. But they are present in the directory you passed as argument making your fopens fail.
To fix this
you prefix the dir name to the file
to be opened. or
You can change your pwd using chdir and then do the fopens.
A couple problems, I think:
readdir() returns subdirectories in the path, even entries like "." and "..".
you try to open the files returned, but in whatever the current directory might be - you need to concatenate the path to the filename you're opening.

Resources