I'm trying to list files and their sizes in "first" folder but I am getting weird repetition of every two files.
#include <stdlib.h>
#include <stdio.h>
#include <dirent.h>
#include <sys/stat.h>
struct dirent *dirPtr;
struct stat st;
void main()
{
DIR * dirp;
if((dirp=opendir("first"))==NULL)
{
printf("There has been an error");
}
while(dirPtr=readdir(dirp))
{
printf("%s - ", dirPtr->d_name);
stat(dirPtr->d_name, &st);
printf(" file size: %lu\n", st.st_size);
}
closedir(dirp);
}
This is my output:
Does anyone know why this is happening?
For starters, you should probably check the return result from "stat()", and print an error # (instead of file size) if stat() fails.
Also: "opendir()" is reading files from some arbitrary directory.
Q: Does "dirPtr->d_name" contain a full filepath ... or just a filename? In other words, are you trying to "stat()" from the wrong directory?
You are basically calling stat("test.c", &st). How is stat supposed to know what directory test.c is in? I don't think it can.
I think you should try doing stat("./first/test.c", &st) or stat("/full/path/to/first/test.c", &st). Better yet, you should find some function like stat that takes a struct dirent as the argument, so you don't have to worry about concatenating strings.
I'll see if there is a such a function and edit my answer if I find one.
Every directory has at least two entries, the current directory - a single dot . - and the parent directory - two dots ..
Related
My goal is to try to get the name, size and last modified of a folder. I have used dirent.h to get the first two types. I don't know what the best way of getting the last modified value is, but the current way I am using does not seem very useful. I am getting type errors when trying to get my path as the dirent folder that I am opening. I'm not sure if there is an easier way to do this or but any guidance would be much appreciated. I found an example of how to get the last modified on stackoverflow and was trying to use that... below is my code:
#include <dirent.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/stat.h>
#include <sys/types.h>
void getFileCreationTime(char *path) {
struct stat attr;
stat(path, &attr);
printf("Last modified time: %s", ctime(&attr.st_mtime));
}
int main()
{
DIR *folder;
struct dirent *entry;
int files = 0;
folder = opendir(".");
if(folder == NULL)
{
perror("Unable to read directory");
return(1);
}
while( (entry=readdir(folder)) )
{
files++;
printf("File %3d: %s\n",files, entry->d_name);
printf("File %3d: %i\n",files, entry->d_reclen);
getFileCreationTime(folder);
}
closedir(folder);
return(0);
}
With error:
main.cpp: In function ‘int main()’:
main.cpp:36:35: error: cannot convert ‘DIR* {aka __dirstream*}’ to ‘char*’ for argument ‘1’ to ‘void getFileCreationTime(char*)’
getFileCreationTime(folder);
Again, I am trying to be able to get the last modified date of each folder that I am getting the name and size of using dirent.
folder is the return value of opendir(".");. opendir returns either a DIR* structure or NULL. Not the directory path expressed using characters.
When you call getFileCreationTime(folder); you are sending a DIR* to your function. But you are expecting a char* path. So do not pass a DIR*, pass it the characters representing your directory. In your case "." (as used in your opendir() statement above).
Obviously, your directory name could be stored in a variable.
[...]
while( (entry=readdir(folder)) )
{
files++;
printf("File %3d: %s\n",files, entry->d_name);
printf("File %3d: %i\n",files, entry->d_reclen);
getFileCreationTime(".");
}
[...]
Using this, you will be able to read the time value. The name you already have.
For directory size, you will have to loop through the directory objects and add their size. You will have to decide what to do with sub-directories. Go down recursively or just take local objects? The source code of du would offer great insight (although it might be too complex for your need).
This question already has answers here:
stat() error 'No such file or directory' when file name is returned by readdir()
(2 answers)
Closed 2 years ago.
I am writing a simple c program which outputs all the contents within a given directory. Files are printed in green, executables are printed in red, and directories are printed in blue. Files and executables have their size printed as well. The code works properly when I open the current directory with either a relative path (".") or an absolute path. However, when I open other directories, all contents are identified as directories and printed in blue. I am unsure why the behavior changes when opening different directories.
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
int main(int argc, char *argv[]){
DIR* dir;
struct dirent* sd;
dir = opendir(".");
if(dir == NULL){
exit(1);
}
int fd;
int size;
while((sd=readdir(dir)) != NULL){
struct stat statstruct;
stat(sd->d_name, &statstruct);
if(S_ISREG(statstruct.st_mode)){
fd = open(sd->d_name, O_RDONLY);
size = lseek(fd, 0, SEEK_END);
if(statstruct.st_mode & S_IXUSR){
printf("\033[1;31m%s %d bytes\n\033[0m", sd->d_name, size);
}
else{
printf("\033[0;32m%s %d bytes\n\033[0m", sd->d_name, size);
}
}
else if(S_ISDIR(statstruct.st_mode)){
printf("\033[0;34m./%s\n\033[0m", sd->d_name);
}
}
closedir(dir);
}
stat(sd->d_name, &statstruct);
stat opens relative to current directory. So the file will be parsed relative to current directory. Instead open the file relative to the directory you are interested in.
int err = fstatat(dirfd(dir), sd->d_name, &statstruct, 0);
if (err) abort(); // yes, handle errors
Here is what I need to do:
Write a C program to calculate the total size of the files in a
directory and the sub-directories of the directory. Note that the
total size should include the sizes of sub-directories (directories
are also files) and size of the top-level directory. If a file is a
symbolic link, the symbolic link should not be dereferenced. So the
size of the symbolic link is added to the total size, not the size of
the file pointed by the link. To facilitate testing, your program
should print out ONLY the total size in bytes, i.e., ONE number,
nothing else.
Here is what I have:
#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>
#include <string.h>
#include <stdio.h>
int main(int argc, char *argv[]){
char* folder = argv[1];
long length;
DIR* dir_p;
struct dirent* dir_element;
struct stat file_info;
dir_p = opendir(folder);
while(dir_element = readdir(dir_p)){
lstat(dir_element->d_name, &file_info);
length+=file_info.st_size;
printf("%s\n" , dir_element->d_name);
}
return 0;
}
The problem here is that I do not get the right number for some reason. I check the output of my program with du -abc "directory_pathname" call in Ubuntu(Linux).
You never initialize length. Also, you need to actually recurse into directories. Put the while into a function, then call that function for each directory you find (check man stat to figure out how to tell if the file is a directory; I forget the exact test off the top of my head but it's a member of struct stat).
Basically, this should be a simple piece of code that opens a directory stream and looks for symbolic links. Whenever a symbolic link is found, it should print ("Symbolic link found");
However, the lstat(dirp->d_name,&bufcall always returns a value < 0, and I don't know why.
I created the two symbolic link opening the file folder, opening a terminal window inside the folder and running
ln -s ciao.txt link1 and
ln -s ciao2.txt link2
I know I should call closedir() later in my code, please don't care about this.
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <unistd.h>
void main (int argc, char* argv[])
{
char buffer[100],dir[100];
struct stat buf;
int x;
DIR *dp;
struct dirent *dirp;
if((dp=opendir(argv[1]))==NULL)
{
printf("\nError opening directory stream, now exiting...\n");
exit(-1);
}
while((dirp=readdir(dp))!=NULL)
{
lstat(dirp->d_name,&buf);
if(S_ISLNK(buf.st_mode))
printf("\n%s Is a symbolic link\n",dirp->d_name);
else
printf("\n%s Is not a symbolic link\n",dirp->d_name);
}
}
Some help would be appreciated. Thanks.
d_name is the file name in the directory, not a full path name. You must eather chdir into the directory you are looking at, or construct full path names for the files.
The simplest solution is to add this line just before your while loop:
chdir(argv[1]);
I'm trying to write a program to open an archive file from Unix, read the files in and print what files are inside the archive and just the filename. Below is my code -- it compiles, but I got some weird output in the terminal -- e.g. ?;?U?. It should just display 2 txt file names. Can someone take a look at my code and give me some guidance on what I'm missing? Thank you!
EDIT: I made some changes to my code, but it's still not working. Any suggestion or help is greatly appreciated.
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/utsname.h>
#include <ctype.h>
#include <string.h>
#include <ar.h>
int main (int argc, char **argv)
{
int input_fd;
//char buffer[25];
struct ar_hdr my_ar;
if (argc != 2) {
printf("Error", argv[0]);
exit(EXIT_FAILURE);
}
//open the archive file (e.g., hw.a)
input_fd = open(argv[1], O_RDONLY);
if (input_fd == -1)
{
perror("Can't open input file\n");
exit(-1);
}
while (read(input_fd, my_ar.ar_name, sizeof(buffer)) > 0) {
printf("%s\n", my_ar.ar_name);
}
close(input_fd);
return 0;
}
I don't see anywhere that you are defining what a my_hdr is, yet you are printing one of its supposed members here:
printf("%s\n", my_ar.ar_name);
You also never set ar_name to anything either.
I see you read some data into a variable named buffer, but you never actually copy that buffer into ar_name which I am assuming is your intent.
while (read(input_fd, buffer, sizeof(buffer)) > 0) {
printf("%s\n", my_ar.ar_name);
}
The POSIX documentation explicitly states that the archive file format is not described, on the grounds that several incompatible such formats already exist, so you'll definitely need to study the documentation provided by your OS if you're going to use <ar.h> instead of the ar command-line utility.
Here are some details that might help, based on the Solaris implementation:
An archive file starts with a magic cookie string which you are neither verifying nor skipping,
Each header object is followed by the content of the actual object in the archive, which you are not stepping over,
The first object in the archive is an unnamed object containing the archive's symbol table,
If an object's name is more than fifteen bytes long, it will be stored in the archive's string table, which appears to be part of the symbol table.
Note that these points, or details thereof, may vary on your OS. As I said at the beginning, study the documentation provided by your OS.