question regarding fopen - what am I doing wrong here? - c

#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.

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?

searching for a file name using only an extension

prev problem was not described well.
I need to retrieve a file name and assign that name to a variable. The only thing is that the file can have any name.
The thing that I know is the file extension and there can only be one file of this extension.
Is there any way to implement this in C?
Update #1
File extension is *.knb and target is Linux system.
#include <stdio.h>
#include <dirent.h>
#define LOG_() do{fprintf(stdout, " UNIT TESTING...\n");}while(0)
char* knbname;
void fName(void);
int main()
{
LOG_();
fName(void);
//do some more code
return 0;
}
void fName(void){
DIR *d;
struct dirent *dir;
d = opendir(".");
if (d)
{
//find file with *.knb extension and place name into knbname
}
closedir(d);
}
I don't know how to find for a *.knb file in the fName() function and how to assign name to knbname. Any help will be appreciated
You are reinventing POSIX's glob() function. Here is an example of how to use it (see the flags in manpage for more options):
#include <glob.h>
int main(void)
{
glob_t glob_res = { 0 };
glob("*.knb", 0, NULL, &glob_res);
if (glob_res.gl_pathc == 0) puts("No match.");
else printf("First match is %s\n", glob_res.gl_pathv[0]);
globfree(&glob_res);
return 0;
}
After Andrew pointed out some major flaw in the previous design, i will make another attempt for a solution...
int hasExtension(char *filename, char *extension);
int main(void)
{
DIR *directory;
struct dirent *entry;
if(NULL == (directory = opendir(".")))
{
perror("Failed to open directory\n");
exit(1);
}
while( NULL != (entry = readdir(directory)) )
{
if(DT_REG == entry->d_type) { // Regualar files only
if(hasExtension(entry->d_name, ".knb"))
{
printf("Match - %s\n", entry->d_name);
} else {
printf("No match - %s\n", entry->d_name);
}
}
}
closedir(directory);
return 0;
}
int hasExtension(char *filename, char *extension)
{
size_t filename_len, extension_len;
if((NULL == filename) || (NULL ==extension))
return 0;
filename_len = strlen(filename);
extension_len = strlen(extension);
if(filename_len < extension_len)
return 0;
return !strcmp(filename + filename_len - extension_len, extension);
}

Can't get the reason for segfault

EDIT : Note that It's not that I can't access the memory allocated by storeContents() in main() if you think so. Program crashes during the execution of storeContents()
The program fails here :
strcpy(contents[count], dir->d_name);
printf("Stored %s(out hiddenVisible)\n", dir->d_name); // for testing
It's strcpy() not the printf(), I added it just for the reference.
The debugger(gdb) says :
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7f3cd72 in __strcpy_ssse3 () from /usr/lib/libc.so.6
I am making a program that involves the following function "storeContents"(It stores contents' names of a directory in a dynamic array). There are two issues with this function : (1) It says "Stored file_name" twice for the first file and (2) says "Segmentation fault". I can't figure out either of them. Thanks for your efforts!
#include <stdio.h>
#include <string.h>
#include <dirent.h>
#include <stdlib.h>
#include <sys/types.h>
#include <limits.h>
static short hiddenVisible = 0;
/* Store directory's contents in **contents */
static char ** storeContents(struct dirent *dir, DIR *dirp, unsigned numOfContents);
/* Count files/directories in a directory */
static unsigned getNumOfContents(struct dirent *dir, DIR *dirp);
int main(int argc, char const *argv[])
{
char **contents;
DIR *dirp;
struct dirent *dir;
unsigned numOfContents;
dirp = opendir("/home/gaurav");
if((dir = readdir(dirp)) == NULL) {
perror("readdir");
exit(1);
}
/* Getting number of files/directories */
numOfContents = getNumOfContents(dir, dirp);
printf("There are %u files.\n", numOfContents);
/* To position again to the first entry */
rewinddir(dirp);
contents = storeContents(dir, dirp, numOfContents);
/* Print contents */
for(unsigned i = 0; i < numOfContents; ++i)
printf("%s\n", contents[i]);
closedir(dirp);
return 0;
}
char **
storeContents(struct dirent *dir, DIR *dirp, unsigned numOfContents) {
char **contents;
unsigned count = 0;
/* Allocating memory for entries */
contents = malloc(numOfContents * sizeof(*contents));
/* Allocating memory for each '*contents' */
for(unsigned i = 0; i < numOfContents; i++)
contents[i] = (char *)malloc(NAME_MAX); /* we know char is 1 byte, so no "sizeof" */
while(count < numOfContents) {
/* Ignore "." and ".." */
if(!(strcmp(dir->d_name, ".")) || !(strcmp(dir->d_name, ".."))) {
if((dir = readdir(dirp)) == NULL) {
perror("readdir");
exit(1);
}
continue;
}
if(hiddenVisible) {
strcpy(contents[count], dir->d_name);
if((dir = readdir(dirp)) == NULL) {
perror("readdir");
exit(1);
}
count++;
} else {
if(dir->d_name[0] == '.')
if((dir = readdir(dirp)) == NULL) {
perror("readdir");
exit(1);
}
else {
strcpy(contents[count], dir->d_name);
if((dir = readdir(dirp)) == NULL) {
perror("readdir");
exit(1);
}
count++;
}
}
}
return contents;
}
unsigned
getNumOfContents(struct dirent *dir, DIR *dirp) {
unsigned count = 0;
while(dir) {
if(hiddenVisible) {
/* Ignore "." and ".." */
if(!(strcmp(dir->d_name, ".")) || !(strcmp(dir->d_name, ".."))) {
if((dir = readdir(dirp)) == NULL) {
perror("readdir a");
exit(1);
}
continue;
}
count++;
if((dir = readdir(dirp)) == NULL) {
perror("readdir b");
exit(1);
}
} else {
if(dir->d_name[0] == '.') {
if((dir = readdir(dirp)) == NULL) {
perror("readdir c");
exit(1);
}
}
else {
count++;
if((dir = readdir(dirp)) == NULL) {
perror("readdir d");
exit(1);
}
}
}
}
return count;
}
contents in the function storeContents is a local copy of contents from main.
Changing it in the function does not change the variable in main.
You should return the array. Change
static void storeContents(struct dirent *dir, DIR *dirp, char **contents, unsigned numOfContents);
to
static char **storeContents(struct dirent *dir, DIR *dirp, unsigned numOfContents);
,return contents; in the function and call it like char **contents = storeContents(...);
Some bugs:
contents is a local parameter to the function, it will not get returned to main(). See Dynamic memory access only works inside function.
contents = (char **)malloc(numOfContents); is wrong, you need to allocate room for numOfContents pointers. Change this to contents = malloc(numOfContents * sizeof(*contents)).
You should check each call to readdir and make sure it doesn't return NULL.

miniz C can't zip file with absolute path

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.

Get (NOT display) the list of files and folder in C

I want to be able to get the list of folders and file (if possible with sub folders) and return it (array for example)
So i have this script:
DIR *dir;
struct dirent *ent;
if ((dir = opendir ("c:\\src\\")) != NULL) {
/* print all the files and directories within directory */
while ((ent = readdir (dir)) != NULL) {
printf ("%s\n", ent->d_name); // I dont want to print, I want to add it to a array
}
closedir (dir);
} else {
/* could not open directory */
perror ("");
return EXIT_FAILURE;
}
So i can do:
array = getFolders('.');
now if I loop thru the array i can see all folders and files.
eg:
array[0] = 'file1.txt';
array[1] = 'folder1/';
array[2] = 'folder1/file2.txt';
array[3] = 'folder1/file3.txt';
array[4] = 'folder2/';
array[5] = 'folder3/';
array[6] = 'folder3/filez.txt';
etc...
You can allocate a list of pointers and store each entry by allocating memory for the directory entry:
char **getFolder()
{
char **list = malloc(4096* sizeof *list);
size_t i = 0;
....
while ((ent = readdir (dir)) != NULL) {
list[i]=strdup(ent->d_name);
i++;
if( i >=4096 ) { /* time to realloc */}
}
return list;
}
and from the caller, you can use receive it as:
char **list=getFolder();
If you are going to have too many entries than you can use realloc() to increase the size of the list inside the loop. If strdup is not available, it can be easily implemented by using malloc() and strlen() functions.
I have excluded error checking for simplicity. Ideally, malloc() ans strdup should be checked for errors.
use DIR command in popen, and malloc and realloc
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#define INC 1024
char **getFolders(const char *path, /* out */ size_t *count){
char buff[1024];
snprintf(buff, sizeof buff, "dir /B /S /ON \"%s\"", path);
FILE *fp = popen(buff, "r");
size_t capacity = INC;
char **entry;
struct stat finfo;
if(NULL==(entry=malloc(capacity*sizeof(*entry)))){
perror("malloc");
exit(EXIT_FAILURE);
}
*count = 0;
while(fgets(buff, sizeof buff, fp)){
size_t len;
for(len = 0; buff[len]; ++len){
if(buff[len] == '\\')
buff[len] = '/';
}
buff[len-1] = '\0';
stat(buff, &finfo);
if(S_ISDIR(finfo.st_mode))
buff[len-1] = '/';
entry[*count] = strdup(buff);
if(++*count == capacity){
capacity += INC;
if(NULL==(entry=realloc(entry, capacity*sizeof(*entry)))){
perror("realloc");
exit(EXIT_FAILURE);
}
}
}
pclose(fp);
return entry;
}
int main(void){
size_t i, count = 0;
char **entry = getFolders("c:/src/", &count);
for(i = 0; i < count; ++i){
printf("%s\n", entry[i]);
free(entry[i]);
}
free(entry);
return 0;
}

Resources