Here's part of code for my application I'm porting to windowsXp initially written on Ubuntu.
#include <stdio.h>
#include <string.h>
#include <dirent.h>
#include <unistd.h>
#include <sys/stat.h>
int list_files(char *parentdir)
{
DIR *dir;
struct dirent *de = NULL;
char subdirs[1000][1000];
int isubdirs = 0;
char rootdir[1000];
strcpy(rootdir, parentdir);
FILE *fp = fopen("list.txt", "w");
seek:
dir = opendir(rootdir);
if (!dir) {
printf("ERROR: [ %s ]", rootdir);
perror("Couldn't opendir: ");
}
else {
de = readdir(dir);
if (!de) {
printf("ERROR:[ %s ]", rootdir);
perror("Couldn't readdir ");
goto out;
}
if (strcmp(de->d_name, "..") != 0 && strcmp(de->d_name, ".") != 0) {
fprintf(fp, "%s\\%s\n", rootdir, de->d_name);
printf("ADDED: %s\\%s\n", rootdir, de->d_name);
}
while ((de = readdir(dir)) != NULL)
{
if (!strcmp(de->d_name, "..") || !strcmp(de->d_name, "."))
continue;
fprintf(fp, "%s\\%s\n", rootdir, de->d_name);
printf("ADDED: %s\\%s\n", rootdir, de->d_name);
struct stat s;
stat(de->d_name, &s);
if (S_ISDIR(s.st_mode))
{
strcpy(subdirs[isubdirs], rootdir);
strcat(subdirs[isubdirs], "\\");
strcat(subdirs[isubdirs], de->d_name);
printf("%s\n", subdirs[isubdirs]);
isubdirs++;
}
/* Not working in WinXP
if (de->d_type == 4) {
strcpy(subdirs[isubdirs], rootdir);
strcat(subdirs[isubdirs], "/");
strcat(subdirs[isubdirs], de->d_name);
isubdirs++;
}
*/
}
if (isubdirs > 0) {
strcpy(rootdir, subdirs[--isubdirs]);
goto seek;
}
}
out:
fclose(fp);
return 0;
}
Now problem is in output file i get:
C:\Documents and Settings\user\Desktop\New Folder\00.txt
C:\Documents and Settings\user\Desktop\New Folder\1
C:\Documents and Settings\user\Desktop\New Folder\2
Only files in parentdir listed, but not in subdirs (1 and 2 both not empty "folders")
I'm testing in Virtualbox.
Related
This certain getopt case is supposed to be used as an ls (the unix/linux command) alternative that returns the active files but once compiled and ran nothing is returned in the terminal.
Here is the full code:
#include <errno.h>
#include <getopt.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <dirent.h>
#define DATA_SIZE 1000
void print_help(void)
{
printf("Help\n");
printf("> cast -d (deletes file)\n");
printf("> cast -r (renames file)\n");
printf("> cast -c (create new file)\n");
printf("> cast -s (searches contents of file)\n");
printf("________________________________________\n");
printf("Find an error or a bug? please submit it in the issues section on github\n");
}
case 's': {
int main(void)
{
DIR *directory;
struct dirent *entry;
directory = opendir(".");
if (directory == NULL)
{
printf("Error reading directory\n");
return 1;
}
while ((entry = readdir(directory)) != NULL)
if (entry->d_type == DT_REG)
{
printf("file: %s\n", entry->d_name);
}
}
if (closedir(directory) == -1)
{
printf("Error closing directory\n");
return 1;
}
return 0;
}
}
int main(int argc, char **argv)
{
int option_val = 0;
int opt_delete = 0;
int opt_help = 0;
int opt_rename = 0;
int opt_create = 0;
int opt_search = 0;
while ((option_val = getopt(argc, argv, "dhrcs")) != -1) {
switch (option_val) {
case 'd': {
char filename[65]; //Hope your filename isnt bigger than this
printf("Filename or path to file: ");
scanf("%s", filename); // checks to see if your filename isnt bigger than specified
if (remove(filename) != 0)
{
fprintf(stderr, "Errno: %d\n", errno);
perror("Error msg");
} else printf("%s, deleted.\n", filename);
opt_delete = 1;
break;
case 'r': {
char file[65], new[65];
printf("File: ");
scanf("%s", file);
printf("New name: ");
scanf("%s", new);
if (rename(file, new) != 0)
{
fprintf(stderr, "Errno: %d\n", errno);
perror("Error msg");
} else printf("%s --> %s", file, new);
opt_rename = 1;
break;
case 'c': {
FILE *f = fopen("Castdocument.txt", "w+");
fprintf(f, "Finished with maybe no errors? Rename this file to whatever you would like and change the filename extension with ""cast -r""");
printf("File created! (Check your home directory for ""Castdocument.txt"" file and modify that to fit your needs)");
fclose(f);
opt_create = 1;
case 'h': {
print_help();
opt_help = 1;
break;
default:; /* '?' */
//print_help();
}
if (opt_delete) {
printf("\n");
} if (opt_rename) {
printf("\n");
} if (opt_help) {
print_help();
} if (opt_search) {
printf("\n");
} if (opt_create) {
printf("\n");
}
}
}
}
}
}
}
and here is the 's' case:
case 's': {
int main(void)
{
DIR *directory;
struct dirent *entry;
directory = opendir(".");
if (directory == NULL)
{
printf("Error reading directory\n");
return 1;
}
while ((entry = readdir(directory)) != NULL)
if (entry->d_type == DT_REG)
{
printf("file: %s\n", entry->d_name);
}
}
if (closedir(directory) == -1)
{
printf("Error closing directory\n");
return 1;
}
return 0;
}
}
I attempted to move the case out of the switch statement but to no avail.
#include <stdio.h>
#include <dirent.h>
int main() {
struct dirent *de;
DIR *dr;
int i = 1;
dr = opendir("."); // need to get directory through stdin insted of this
if (dr == NULL) printf("Could not open directory");
while (((de = readdir(dr)) != NULL))
{
printf("\t%d. %s\n", i, de -> d_name);
i++;
}
closedir(dr);
return 0;
}
You read it from stdin and use in place of ".". Here is the full example
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <dirent.h>
int main(){
struct dirent *de;
char dirbuf[BUFSIZ] = {0};
DIR *dr;
int i = 1;
puts("Chose the directory: ");
if (fgets(dirbuf, BUFSIZ, stdin) == NULL) {
perror("fgets");
exit(-1);
}
dirbuf[strlen(dirbuf)-1] = '\0'; // remove \n
dr = opendir(dirbuf); // need to get directory through stdin insted of this
if (dr == NULL) {
perror("opendir");
exit(-1);
}
while(((de = readdir(dr)) != NULL))
{
printf("\t%d. %s\n", i, de -> d_name);
i++;
}
closedir(dr);
return 0;
}
I am working on a version of graphical ls, representing the output of ls with a tree. I have gotten most of my code working but would like to be able to determine what directory to read from in the command line. I have tried using
DIR *d
d = opendir(argv[1]);
But this does not work and results in errors opening files as well as the size and other information not updating for the file.
Any information would be greatly appreciated! Thanks.
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <dirent.h>
#include <stdio.h>
#include <string.h>
#define _GNU_SOURCE
#include <limits.h>
void helper(DIR *, struct dirent *, struct stat, char *, int, char **);
void dircheck(DIR *, struct dirent *, struct stat, char *, int, char **);
int main(int argc, char *argv[]){
DIR *d;
// Create dirent struct
struct dirent *dir;
// Create stat struct
struct stat buf;
// current path for file
char currentPath[FILENAME_MAX];
// Depth for tree
int depth = 0;
// Checking for correct usage
if (argc != 2) {
printf("Usage: './gls <directory_name>'\n");
exit(0);
}
// Checking that file provided in command line actually exists
if (lstat(argv[(argc - 1)], &buf) < 0) {
printf("Error: No such file exists.\n");
return 1;
exit(0);
}
// General resource for printing files: http://stackoverflow.com/questions/4204666/how-to-list-files-in-a-directory-in-a-c-program%20*/
// Open the current directory
d = opendir (".");
if(d == NULL) {
printf("Error opening directory.\n");
return 1;
}
// Store the current directory into currentPath
if((getcwd(currentPath, FILENAME_MAX)) == NULL) {
printf("Error: No such file exists.\n");
return 1;
}
// Iterate through all items in directory
while((dir = readdir(d)) != NULL){
// Do not process . and ..
if(strcmp(dir->d_name, ".") == 0 || strcmp(dir->d_name, "..") == 0)
continue;
// Forms the path for lstat
getcwd(currentPath, FILENAME_MAX);
strcat(currentPath, "/");
strcat(currentPath, dir->d_name);
if(lstat(currentPath, &buf) == -1){
perror("stat");
printf("Error could not open file\n");
}
getcwd(currentPath, FILENAME_MAX);
// Checks if file is a regular file
if(S_ISREG(buf.st_mode))
printf("| %s (regular file - %d - !checksum)\n", dir->d_name, (int)buf.st_size);
// Checks if file is a directory
else if(S_ISDIR(buf.st_mode)) {
printf("| %s (directory)\n", dir->d_name);
dircheck(d, dir, buf, currentPath, depth, argv);
}
// Checks if file is a symbolic link
else if(S_ISLNK(buf.st_mode)) {
// Resource used for absolute and relative paths: http://www.apiexamples.com/c/stdlib/realpath.html
char resolved_path[PATH_MAX];
realpath(currentPath, resolved_path);
printf("| %s (symbolic link - %s)\n", dir->d_name, resolved_path);
}
// Checks if file is a FIFO
else if(S_ISFIFO(buf.st_mode)) {
printf("| %s (fifo (named pipe))\n", dir->d_name);
}
}
// Close the directory and return 0 for success
closedir(d);
return 0;
}
// Recursive helper
// Resource used for some of helper function and dircheck function: http://stackoverflow.com/questions/4989431/how-to-use-s-isreg-and-s-isdir-posix-macros
void helper(DIR *d, struct dirent *dir, struct stat buf, char currentPath[FILENAME_MAX], int depth, char *argv[]){
int i = 0;
// Open directory in currentPath
if((d = opendir(currentPath)) == NULL)
printf("Error: Failed to open Directory ==> %s\n", currentPath);
// Read through directory
while((dir = readdir(d)) != NULL){
// If file is . or .. ignore
if(strcmp(dir->d_name, ".") == 0 || strcmp(dir->d_name, "..") == 0)
continue;
getcwd(currentPath, FILENAME_MAX);
strcat(currentPath, "/");
strcat(currentPath, dir->d_name);
getcwd(currentPath, FILENAME_MAX);
// If file is a register
if(S_ISREG(buf.st_mode)){
for(i = 0; i < depth; i++) {
printf(" ");
printf("%s (%d bytes)\n", dir->d_name, (int)buf.st_size);
}
}
// If file is a directory
if(S_ISDIR(buf.st_mode)) {
if(strcmp(dir->d_name, ".") == 0 || strcmp(dir->d_name, "..") == 0) {
dircheck(d, dir, buf, currentPath, depth, argv);
}
}
}
// Change directory back
chdir("..");
closedir(d);
}
// Resource used as guideline in order to create helper and dircheck functions
// http://stackoverflow.com/questions/4989431/how-to-use-s-isreg-and-s-isdir-posix-macros
void dircheck(DIR *d, struct dirent *dir, struct stat buf, char currentPath[FILENAME_MAX], int depth, char *argv[]){
int i = 0;
strcat(currentPath, "/");
strcat(currentPath, dir->d_name);
// If two directories exists at the same section in the tree
if((chdir(currentPath)) == -1){
getcwd(currentPath, FILENAME_MAX);
strcat(currentPath, "/");
strcat(currentPath, dir->d_name);
getcwd(currentPath, FILENAME_MAX);
// Add --- based on the depth of the tree
for(i = 0; i <= depth; i++)
printf ("---");
printf("| %s (subdirectory)\n", dir->d_name);
depth++;
helper(d, dir, buf, currentPath, depth, argv);
}
else{
// Add --- based on the depth of the tree
for(i =0; i <= depth; i++)
printf("---");
printf("| %s (subdirectory)\n", dir->d_name);
chdir(currentPath);
depth++;
helper(d, dir, buf, currentPath, depth, argv);
}
}
You are reading stat before while loop, this is dir in your case.
Then for every file in directory you are checking st_mode, but this is not updated nowhere in the while loop.
if (stat(argv[(argc - 1)], &statBuf) < 0)
this line just query the dir info, so you will always get directory type.
you should query specific file under that dir,
so you can change the code like this:
#include <stdio.h>
#include <dirent.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
/* Resource: http://stackoverflow.com/questions/4204666/how-to-list-files-in-a-directory-in-a-c-program */
/* Resource: http://cboard.cprogramming.com/linux-programming/131-stat.html */
#define MAX_FILE_NAME_LEN 256
int main(int argc, char *argv[])
{
char path[MAX_FILE_NAME_LEN] = {0};
struct stat statBuf;
if (argc != 2) {
printf("Usage: './gls <directory_name>'\n");
exit(0);
}
if (stat(argv[(argc - 1)], &statBuf) < 0) {
printf("Error: No such file exists.\n");
exit(0);
}
DIR *d;
struct dirent *dir;
//char currentPath[FILENAME_MAX];
d = opendir(argv[1]);
while ((dir = readdir(d)) != NULL) {
//getcwd(currentPath, FILENAME_MAX);
//strcat(currentPath, "/");
//strcat(currentPath, dir->d_name);
//if(stat(currentPath, &statBuf) == -1){
//printf("N")
//}
memset(path, 0, MAX_FILE_NAME_LEN);
snprintf(path,MAX_FILE_NAME_LEN,"%s%s",argv[1],dir->d_name);
//getcwd(currentPath, FILENAME_MAX);
if (stat(path, &statBuf) < 0) {
printf("Error: No such file exists.\n");
continue;
// exit(0);
}
if(S_ISREG(statBuf.st_mode)) {
printf("| %s (regular file - %d - !checksum!)\n", dir->d_name, (int)statBuf.st_size); /* If regular file */
}
if(S_ISDIR(statBuf.st_mode)) {
printf("| %s (directory - size)\n", dir->d_name);
}
if(S_ISLNK(statBuf.st_mode)) {
printf("| %s (symbolic link - points to !!!\n", dir->d_name);
}
if(S_ISFIFO(statBuf.st_mode)) {
printf("| %s (fifo (named pipe))\n", dir->d_name);
}
}
closedir(d);
return(0);
}
I saw below code and change only checking file mode, I want to use stat, st_mode. But result is not same. Difference is just checking function.
#include <unistd.h>
#include <sys/types.h>
#include <dirent.h>
#include <stdio.h>
void listdir(const char *name, int level)
{
DIR *dir;
struct dirent *entry;
if (!(dir = opendir(name)))
return;
if (!(entry = readdir(dir)))
return;
do {
if (entry->d_type == DT_DIR) {
char path[1024];
int len = snprintf(path, sizeof(path)-1, "%s/%s", name, entry->d_name);
path[len] = 0;
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
continue;
printf("%*s[%s]\n", level*2, "", entry->d_name);
listdir(path, level + 1);
}
else
printf("%*s- %s\n", level*2, "", entry->d_name);
} while (entry = readdir(dir));
closedir(dir);
}
int main(void)
{
listdir(".", 0);
return 0;
}
and just change check file_mode
void filelist(const char*loc, int dep){
DIR*dirpt;
struct dirent* dir;
if (!(dirpt = opendir(loc)))
return;
while((dir = readdir(dirpt))!=NULL)
{
struct stat buf;
lstat(dir->d_name, &buf);
if(S_ISDIR(buf.st_mode)){
char p[1024];
int l = snprintf(p, sizeof(p)-1, "%s/%s", loc, dir->d_name);
p[l] = 0;
if (strcmp(dir->d_name, ".") == 0 || strcmp(dir->d_name, "..") == 0)
continue;
printf("%*s[%s]\n", dep*2,"", dir->d_name);
filelist(p,dep + 1);
}
else
printf("%*s- %s\n", dep*2,"", dir->d_name);
}
closedir(dirpt);
}
int main(void){
filelist(".",0);
return 0;
}
but result is not same, cannot exploring all directory....I don't know why....
lstat(dir->d_name, &buf);
In this call, dir->d_name does not capture the complete path. It is only the name of the entry in that directory. You should capture the return value of the function and make sure that it was able to get the values you need.
if ( lstat(dir->d_name, &buf) == -1 )
{
// Deal with error
}
You'll have to use something like:
while((dir = readdir(dirpt))!=NULL)
{
char p[1024];
struct stat buf;
int l = snprintf(p, sizeof(p)-1, "%s/%s", loc, dir->d_name);
p[l] = 0;
if ( lstat(dir->d_name, &buf) == -1 )
{
// Problem
continue;
}
if(S_ISDIR(buf.st_mode)){
if (strcmp(dir->d_name, ".") == 0 || strcmp(dir->d_name, "..") == 0)
continue;
printf("%*s[%s]\n", dep*2,"", dir->d_name);
filelist(p,dep + 1);
}
else
printf("%*s- %s\n", dep*2,"", dir->d_name);
}
I am trying to read directories recursively and print out some metadata about the files. I have the program work for the single directory. But for the sub-directories, when I apply the stat method, the files keep giving an error of no such file or directory exists.
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
void scan( const char *dir) // process one directory
{
DIR *dp;
struct dirent *de;
struct stat sbuf;
dp = opendir( dir);
if( dp == NULL)
{
// perror( dir);
printf("Cannot open directory %s\n",dir);
return;
}
while( 1)
{
const char * d_name;
de = readdir( dp);
if( de == NULL)
break;//Empty Directory
d_name = de->d_name;
printf("d_name: %s\n",d_name);
// if(strcmp(d_name,"..") != 0 && strcmp(d_name,".") != 0)
// printf("%s/%s\n",dir,d_name);//Print File or Directory
if( stat( de->d_name, &sbuf) )
{
// perror( de->d_name);
printf("Error in stat %s\n",de->d_name);
continue;
}
if( S_ISDIR(sbuf.st_mode) && (strcmp(d_name,"..") != 0 && strcmp(d_name,".") != 0))
{
// printf("d_name: %s\n",d_name);
printf( "d\t");
}
else
if (strcmp(d_name,"..") == 0 || strcmp(d_name,".") == 0)
{
// printf("d_name: %s\n",d_name);
// continue;
}
else
{
// printf("d_name tab: %s\n",d_name);
printf( "\t");
}
if(strcmp(d_name,"..") != 0 && strcmp(d_name,".") != 0)
printf( "%lu\t%s\n", (unsigned long) sbuf.st_size, de->d_name);
if(de->d_type == DT_DIR)
{
if(strcmp(d_name,"..") != 0 && strcmp(d_name,".") != 0)
{
char path[1024];
snprintf(path,1024,"%s/%s",dir,d_name);
scan(path);
}
}
}
closedir( dp);
}
int main( int argc, char *argv[])
{
int i;
scan(argv[1]);
return 0;
}
You forgot to prepend your dir to your de->d_name when stating. You're still in your original directory, as you haven't chdired elsewhere.