I am using the stat.h header and stat() to read and list files and directories in a directory. I've tried my code with different preset directories to see the result and print the corresponding type of the entry and so far in each test the code shows the current directory and 2 sub directories as directories but shows the other directories as files despite having the correct path listed alongside it
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <dirent.h>
#include <locale.h>
#include <sys/stat.h>
#include <wchar.h>
extern int errno;
int main(int argc, char *argv[]) {
setlocale(LC_ALL,"Turkish");
DIR* dp;
struct dirent dirp;
char test[9999];
getcwd(test,9999);
printf("FOLDERMAIN:%s\n",test);
dp=opendir(".");
searchDirectoryForString(dp,"Mat",test);
return 0;
}
void searchDirectoryForString(DIR* dp,char* str,char* directoryname)
{
int lineno=1,num=0;
FILE* fp;
struct dirent *file;
char temp[99999];
char buf[99999];
char *rpath;
rpath = calloc(99999,1);
char path[99999];
char* temppath;
temppath = calloc(99999,1);
int count = 0;
char dirhold[100];
char* dot;
int line_num = 1;
int find_result=0;
static int check=0;
DIR* fdp;
if(dp==NULL)
{
printf("cant open");
}
struct stat filestat;
while (file=readdir(dp)) {
stat(file->d_name,&filestat);
//printf("%s\n",file->d_name);
if(strcmp(file->d_name,"..")==0||(strcmp(file->d_name,".")==0))
continue;
if ( S_ISDIR(filestat.st_mode))
{
check++;
printf("\n CHECK: %d\n",check);
if(check!=1)
{
strcpy(temppath,directoryname);
printf("temp:%s\n",directoryname);
strcat(directoryname,"\\");
strcat(directoryname,file->d_name);
dot = strrchr(directoryname, '\\');
strcpy(dirhold,dot);
printf("DIR: %s\n",dirhold);
printf("%s KLASÖR\n",directoryname);
chdir(directoryname);
dp=opendir(directoryname);
if(dp==NULL)
{
printf("2\n");
}
strcat(temppath,dirhold);
searchDirectoryForString(dp,str,temppath);
}
else{
strcpy(path,directoryname);
strcat(directoryname,"\\");
strcat(directoryname,file->d_name);
dot = strrchr(directoryname, '\\');
strcpy(dirhold,dot);
printf("DIR: %s\n",dirhold);
printf("%s FOLDER\n",directoryname);
chdir(directoryname);
dp=opendir(directoryname);
if(dp==NULL)
{
printf("2\n");
}
strcat(path,dirhold);
searchDirectoryForString(dp,str,path);
}
}
else
{
snprintf(buf,99999,"%s",directoryname);
strcat(buf,"\\");
//strcat(directoryname,dirhold);
strcat(buf,file->d_name);
printf("%s FILE \n",buf);
//Close the file if still open.
if(fp) {
fclose(fp);
strcpy(rpath," ");
}
}
}
}
}
I tried my best to produce an MCVE below. One new thing i noticed is if i add another folder to a preset folder it is not recognized as a folder. If i add a folder to a folder which is one of the recognized folders it is also recognized as a folder(nested folder) the issue is most likely caused by the stat function so wrote another function for it to be able to seen more clearly as its in its own scope. Im using devc++ as my IDE.
#include <locale.h>
#include <unistd.h>
#include <dirent.h>
#include <stdio.h>
#include <sys/stat.h>
#include <wchar.h>
int main(int argc, char *argv[]) {
setlocale(LC_ALL,"Turkish");
DIR* dp;
struct dirent dirp;
char test[9999];
getcwd(test,9999);
printf("FOLDERMAIN:%s\n",test);
dp=opendir(".");
listDir(dp,test);
return 0;
}
int isDir(const char *name) {
struct stat fileStat;
return !stat(name, &fileStat) && S_ISDIR(fileStat.st_mode);
}
void listDir(DIR* dp,char* directoryname)
{
struct dirent *file;
char buf[99999];
char* temppath;
temppath = calloc(99999,1);
int count = 0;
char dirhold[100];
char* dot;
int line_num = 1;
int find_result=0;
static int check=0;
char* dir;
DIR* fdp;
if(dp==NULL)
{
printf("cant open");
}
while (file=readdir(dp)) {
//printf("%s\n",file->d_name);
if(strcmp(file->d_name,"..")==0||(strcmp(file->d_name,".")==0))
continue;
if (isDir(file->d_name))
{
check++;
printf("\n CHECK: %d\n",check);
strcpy(temppath,directoryname);
printf("temp:%s\n",directoryname);
strcat(directoryname,"\\");
strcat(directoryname,file->d_name);
dot = strrchr(directoryname, '\\');
strcpy(dirhold,dot);
printf("DIR: %s\n",dirhold);
printf("%s FOLDER\n",directoryname);
chdir(directoryname);
dp=opendir(directoryname);
if(dp==NULL)
{
printf("2\n");
}
strcat(temppath,dirhold);
listDir(dp,temppath);
}
else
{
snprintf(buf,99999,"%s",directoryname);
strcat(buf,"\\");
strcat(buf,file->d_name);
printf("%s FILE\n",buf);
}
}
}
This is my code that does more or less what you want. It is also available in my SOQ (Stack Overflow Questions) repository on GitHub as file dirlist43.c in the src/so-7406-2431 sub-directory.
What went wrong in the MCVE code?
There were a fairly large number of problems, including:
Not much error checking for failed calls.
Changing directory with changing back correctly.
No debug code to help determine what is going wrong.
Too many places where opendir() was called.
Too many places where the result of opendir() was checked — one of them in a different function from where the call was made.
Missing headers.
Unused variables.
Not reporting errors on stderr.
Confusion about directoryname vs temppath.
Sequencing of chdir() calls worked downwards, once. But there was no code to change back after finishing a directory.
Missing closedir() — I ran out of file descriptors when run on a directory with about 3000 sub-folders.
More debatable: I've used snprintf() or printf() to concatenate strings. For raw performance, you may find that strcpy() and strcat() are quicker, but using strcat() can slow things down as it scans from the start of the string each time. Clever code determines the length of the string so that you can copy each time you append, but the Standard C functions aren't helpful for that.
And notes from another comment:
Note that using chdir() is error prone — doubly so if there are symlinks lurking around — and should be avoided when possible. (This was an accurate comment.)
You have a large number of occurrences of 99999 (and some occurrences of 9999); there should be a macro (or enumeration constant) for that value.
On Unix systems, you must #include <errno.h> and should never declare extern int errno; because errno is typically not a simple variable but rather an expression that evaluates to a per-thread int value. I think the same is true on Windows.
Other solutions
In a comment, I noted that:
If you were coding on a Unix (POSIX) system, it would be an odds-on bet that the problem and the fixes are described in stat() error "no such file or directory when file name is returned by readdir(). Even on Windows, you are likely to be running into similar problems. However, there are Windows-specific APIs to process directories that could be used instead of readdir().
Since your MCVE code uses Windows-style \ path separators but compiles, the majority of the advice in that question is valid. Note that POSIX provides some functions — fstatat() and dirfd() — that avoid messing around with chdir(). This is advantageous, especially in threaded programs as chdir() changes directory for all threads at the same time, which is apt to cause chaos if the different threads are accessing files in different directories identified by relative rather than absolute pathnames.
Code: dirlist43.c
#include <dirent.h>
#include <errno.h>
#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#ifdef UNIX
#define DIRSEP_STR "/"
#define DIRSEP_CHR '/'
#else
#define DIRSEP_STR "\\"
#define DIRSEP_CHR '\\'
#endif
#define PATH_LEN 99999
extern void listDir(const char *directoryname);
extern int isDir(const char *name);
int main(void)
{
setlocale(LC_ALL, "Turkish");
char pwd[PATH_LEN];
getcwd(pwd, sizeof(pwd));
printf("FOLDERMAIN: %s\n", pwd);
listDir(pwd);
return 0;
}
int isDir(const char *name)
{
struct stat fileStat;
int rc = stat(name, &fileStat) == 0 && S_ISDIR(fileStat.st_mode);
#ifdef DEBUG
printf("%s(): %d [%s]\n", __func__, rc, name);
#endif /* DEBUG */
return rc;
}
#ifdef DEBUG
static void chk_pwd(const char *tag)
{
char pwd[PATH_LEN];
if (getcwd(pwd, sizeof(pwd)) == 0)
{
int errnum = errno;
fprintf(stderr, "%s(): getcwd() failed: %d %s\n",
__func__, errnum, strerror(errnum));
exit(1);
}
printf("PWD: %s [%s]\n", tag, pwd);
}
#else
#define chk_pwd(tag) ((void)0)
#endif /* DEBUG */
static void set_pwd(const char *directoryname)
{
#ifdef DEBUG
printf("CHDIR 1: [%s]\n", directoryname);
#endif /* DEBUG */
if (chdir(directoryname) != 0)
{
int errnum = errno;
fprintf(stderr, "%s(): chdir(%s) failed: %d %s\n",
__func__, directoryname, errnum, strerror(errnum));
exit(1);
}
chk_pwd("CHDIR 1");
}
void listDir(const char *directoryname)
{
#ifdef DEBUG
static int level = 0;
#endif /* DEBUG */
static int check = 0;
#ifdef DEBUG
printf("-->> %s() level %d (%s)\n", __func__, ++level, directoryname);
#endif /* DEBUG */
DIR *dp = opendir(directoryname);
if (dp == NULL)
{
perror(directoryname);
return;
}
set_pwd(directoryname);
struct dirent *file;
while ((file = readdir(dp)) != NULL)
{
if (strcmp(file->d_name, "..") == 0 || (strcmp(file->d_name, ".") == 0))
continue;
if (isDir(file->d_name))
{
printf("CHECK: %d\n", ++check);
char temppath[PATH_LEN];
snprintf(temppath, sizeof(temppath), "%s%s%s",
directoryname, DIRSEP_STR, file->d_name);
printf("FOLDER: %s\n", temppath);
chk_pwd("Before recursion");
listDir(temppath);
set_pwd(directoryname);
chk_pwd("After recursion");
}
else
{
printf("FILE: %s%s%s\n", directoryname, DIRSEP_STR, file->d_name);
}
}
closedir(dp);
#ifdef DEBUG
printf("<<-- %s() level %d (%s)\n", __func__, level--, directoryname);
#endif /* DEBUG */
}
It can be compiled with -DUNIX if you work on a POSIX-like system where slash / is used to separate path components, or without if you work on a Windows-like system where backslash \ is used. It can be compiled with -DDEBUG to get copious extra debugging output.
The makefile is configured for Unix — the code was tested on a MacBook Pro running macOS Big Sur 11.7.
I'm relatively new to C and cannot figure out why this program seg faults.
It could be a stupid error on my behalf but cannot seem to figure it out.
I also know its unusual using the embedding method I am, but this was down for sheer familiarity with Python3 and the ease of use.
#define PY_SSIZE_T_CLEAN
#define PAM_SM_AUTH
#define PAM_SM_ACCOUNT
//#define PAM_SM_SESSION
#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <security/pam_appl.h>
#include <security/pam_modules.h>
#include </usr/include/python3.6m/Python.h>
/* expected hook */
/*
PAM_EXTERN int pam_sm_setcred( pam_handle_t *pamh, int flags, int argc, const char **argv ) {
return PAM_SUCCESS;
}
PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int argc, const char **argv) {
printf("Acct mgmt\n");
return PAM_SUCCESS;
}
*/
/* expected hook, this is where custom stuff happens */
PAM_EXTERN int pam_sm_authenticate( pam_handle_t *pamh, int flags,int argc, const char **argv )
{
chdir("../code/facial"); // this changes it to the correct directory to execute
dlopen("/usr/lib/x86_64-linux-gnu/libpython3.6m.so",RTLD_LAZY | RTLD_GLOBAL);
Py_Initialize(); // Starts python interpreter
PyRun_SimpleString("import os\nimport sys\nsys.path.append(os.getcwd())"); // lets python know where we are
PyObject *mymod, *func1, *ret1;
mymod = PyImport_ImportModule("pam_detect"); // This is the .py
if (mymod != 0){ // check if the file file was loaded
func1 = PyObject_GetAttrString(mymod, "detect"); // hel is the function name in the file you declared earlier
ret1 = PyObject_CallObject(func1, NULL); // Null because the function doesnt take an argument.
if (ret1 == 1){
Py_Finalize();
return PAM_SUCCESS;
}
else{
Py_Finalize();
return PAM_AUTH_ERR;
}
}
else{
//printf("Error: can't find file!\n");
return 1;
}
Py_Finalize();
return 0;
}
You have defined the pointers but haven't assigned them to a memory address.
PyObject *mymod, *func1, *ret1;
This line in your code makes a pointer named mymod which can point to a memory containing PyObject, but you haven't given the memory address to it yet.
I don't know if calling the functions will return pointers correctly or not, So when you try to put anything there, it gives segmentation fault if you are trying to assign a variable to a pointer without a memory address.
I can only say this much without knowing where the fault occurred. try putting printf statement before assigning of all 3 pointers and see.
I have a piece of code when I need to include stdlib.h. When I do not include this header, I have no problems compiling my code, but the moment I include the header, my code refuses to compile. It tells me that it expected an identifier or "(" before numerical constant. I have looked through my code and cannot find any issue, and as stated, the code compiles perfectly without including that header.
I am new to C, so excuse my poor code, I am simply wanting to figure out why it would be giving me this error.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int execute(char **args)
{
}
char** parse(void)
{
char command[256];
fgets(command, sizeof(command), stdin);
char delimiter[] = " ";
char * pointer = strtok(command, delimiter);
int tokens = 0;
char ** final_command;
while (pointer != NULL)
{
// final_command = (char**)realloc(final_command,
// (tokens+1)*sizeof(char*));
//printf("%s\n", pointer);
//pointer = strtok(NULL, delimiter);
}
}
int main(int argc, char **argv)
{
int EXIT_SUCCESS = 1;
do
{
printf("MyShell> ");
char ** command = parse();
} while (EXIT_SUCCESS);
return EXIT_SUCCESS;
}
I compile using the command gcc -o MyShell MyShell.c
The exact error I am getting says "error: expected identifier or '(' before numeric constant int EXIT_SUCCESS = 1;"
EXIT_SUCCESS is a standard macro (definition) in C. Do not use it as a variable name.
Like NULL, EXIT_SUCCESS is a macro defined in <stdlib.h>, if you include <stdlib.h> you must not use this identifier for other purposes.
In any case your code does not make much sense because it looks like you've got an infinite loop there in main.
I have very little knowledge about C and I can't get this simple task to work:
#include <stdio.h>
#include <string.h>
void load_hex_fw() {
char *warea = getenv("WORKAREA");
char hex[] = "/path/to/fw.hex";
char hexfile; // several trials done here (*hexfile, hexfile[500], etc.)
strcat(hexfile, *warea);
strcat(hexfile, hex);
printf("## %s\n", hexfile);
FILE *file = fopen(hexfile, "r");
fclose(file);
}
The above code basically opens a file for reading. But since the absolute path of the hex file is very long (and I'm also thinking of reusing this function in the future), I need to feed fopen() with a flexible hexfile variable. Googling string concatenation always gives me strcat(), or strncat, but I'm always getting a segmentation fault. I'm getting confused with pointers and references. Any help is greatly appreciated. Thanks in advance!
I have added some corrections and comments in your code, this should help you:
void load_hex_fw() {
char *warea = getenv("WORKAREA"); //check if getenv returns null
if(warea == NULL)
{
return;
}
char hex[] = "/path/to/fw.hex";
char *hexfile = NULL;//you need char buffer to store string
hexfile = malloc(strlen(warea) + stren(hex) + 1);//ENsure hexfile holds full filename
strcpy(hexfile,warea); //assuming you hold path in warea
strcat(hexfile, hex);//Assuming ypu hold filename in hex
printf("## %s\n", hexfile);
FILE *file = fopen(hexfile, "r");// check if fopen returns NULL
fclose(file);
free(hexfile);
}
asprintf allocates memory for you
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
void main() {
char *warea = getenv("WORKAREA");
if (!warea) {
warea = "default"; // or exit
}
char hex[] = "/path/to/fw.hex";
char *hexfile;
asprintf(&hexfile, "%s%s", warea, hex);
printf("## %s\n", hexfile);
// ...
free(hexfile);
}
it accepts 0 but result is hardly what you want for fopen
## (null)/path/to/fw.hex
I am new in C. I want to create a file in linux C program and write environment variables in it. If file already exist I want to open and append. I have written the following code.
char *envFile=getenv("FILENAME");
int fdEnv=-1;
fdEnv=open(envFile,O_CREAT,O_RDWR,O_APPEND);
printf("%d",fdEnv);
char** env;
if(fdEnv>0)
{
for (env = environ; *env != 0; env++)
{
char *thisEnv = *env;
printf("%s",thisEnv);
write(fdEnv,thisEnv,strlen(thisEnv));
}
close(fdEnv);
}
But when I run it first time. A blank file is created. And it stays locked after execution. Looks like some error. Second time it fdEnv stays less than 0.
I really don't understand what is happening here. Please help.
Try using | to separate the flags.
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
extern char **environ;
int main(void)
{
char *envFile = getenv("FILENAME");
int fdEnv = -1;
fdEnv = open(envFile, O_CREAT|O_RDWR|O_APPEND, 0644);
printf("%d\n", fdEnv);
int i = 0;
while (environ[i]) {
printf("%s\n", environ[i]);
write(fdEnv, environ[i], strlen(environ[i]));
char lf = '\n';
write(fdEnv, &lf, 1);
i++;
}
close(fdEnv);
return 0;
}
I've run above code on my linux computer and it works.
extern char **environ;
int main()
{
char **env;
char* filename = getenv("FILENAME")
const char* mode = "a";
FILE* file = fopen( filename, mode );
for ( env = environ; *env; ++env )
fprintf( file, "%s\n", *env );
fclose(file);
return(0);
}
You should think about handling when getenv fails, is blank, etc; let me know if you have any questions.