I am doing an assignment that requires me to create a function similar to ls.
My code works fine but when it comes to implementing the behaviour of
ls -l child //where child is a folder
there is a weird behaviour.
Let's say i am in the folder 'parent' and in it i have a subfolder, 'child' which contains some text files. When i run my program from the parent folder, it finds the folder and prints out the attributes of the text files in it. However, it will only print the files in the child folder only if the same files itself exists in the parent folder.
Here is a snippet of the code that i am using,
char CurrDir[100];
DIR *pDir = NULL;
struct dirent *pFileNames = NULL;
getcwd(CurrDir, sizeof(CurrDir))
strncat(CurrDir, "/", strlen(CurrDir));
unsigned int CurrDirLen = strlen(CurrDir);
unsigned int CombSize = CurrDirLen + strlen(argv[1]);
char SuperCharArr[CombSize];
for(int i = 0; i < CombSize; ++i)
{
if( i < strlen(CurrDir) )
SuperCharArr[i] = CurrDir[i];
else
SuperCharArr[i] = argv[1][i%CurrDirLen];
}//for
//insert null character at the end of the character
SuperCharArr[CombSize] = '\0';
pDir = opendir( SuperCharArr );
printf("%s\n", SuperCharArr);
if( pDir != NULL )
{
//Directory detected as pDir is a DirectoryStream
printf("%s\n", "pDir not null");
PrintHeader();
while( (pFileNames = readdir(pDir)) != NULL )
{
PrintFileDeails(pFileNames);
}
}//if
In my original code posted here, there was a function called, PrintFileDeails(pFileNames), which takes in a parameter of type direct.
Within PrintFileDeails(), there is a function that checks on the status of the file and the code is as follows,
struct stat FileStat;
if( stat(pFileNames->d_name, &FileStat) == -1 )
{
perror("stat");
exit(EXIT_FAILURE);
}//if
This line of code would print out an error where they couldn't find the file and with AAT's comment made me go thru my code again as i suspect that it was not reading the correct folder. Hence, after i passed the full path of where it is supposed to read the file from and it worked fine. Hence, the code was changed to this instead.
if( stat(pFullPath, &FileStat) == -1 )
{
perror("stat");
exit(EXIT_FAILURE);
}//if
where pFullPath was passed the variable of SuperCharArr which contained the full path of where the file to be searched was.
The man page for stat() helped too and it can be found here
Related
The following function is written in c:
void store_files(char *pathname){
printf("pathname = %s\n", pathname);
char nextPath[PATH_MAX];
DIR *dir;
struct dirent *sd;
struct stat stat_buffer;
int fileNum = 0;
int dirCount = 0;
if((dir = opendir(pathname)) == NULL){
printf("Cannot open directory!\n");
exit(EXIT_FAILURE);
}
while((sd = readdir(dir)) != NULL){
if(strcmp(sd->d_name, ".") == 0 || strcmp(sd->d_name, "..") == 0){
continue;
}
if(stat(pathname, &stat_buffer) != 0){
perror(pathname);
}
if(S_ISDIR(stat_buffer.st_mode)){
//Defines archive number
for(int i = 0; i < 100; i++){
if(strcmp(tmpDirPathNames[i], pathname) == 0){
dirCount++;
break;
}
}
//BUILD PATH
sprintf(nextPath, "%s/%s", pathname, sd->d_name);
store_files(nextPath);
}
else if(S_ISREG(stat_buffer.st_mode)){
printf("filename = %s & filesize = %ld\n", sd->d_name, stat_buffer.st_size);
time_t time = getFileModDate(pathname);
archiveNum[dirCount - 1].fileData[fileNum].size = stat_buffer.st_size;
archiveNum[dirCount - 1].fileData[fileNum].absolutePath = pathname;
printf("modification date = %s ", ctime(&time));
printf("fileNum = %i\n", fileNum);
fileNum++;
}
}
closedir(dir);
}
I don't see a real need to explain what each of the if statements in the while loop do since they aren't really relevant to the question. But I'll explain the issue I'm having in more detail here:
One of my other function will create a tmp file with a lot of tmpdir.XXX inside it from an extraction process I do on compressed files.
example of tmp file with a lot of tmpdir.XXX inside it:
tmp
->tmpdir.XXX
->TestFolder1
->TestFolder2
->tmpdir.XXX
->TestFolder3
->TestFolder4
The propose of my function is I want to extract information from every file in tmp. Right now, the function is fine in going into the first tmpdir.xxx and go through all the folders in that fine, i.e. TestFolder1 and TestFolder2. However, it doesn't go into the second tmpdir.XXX because this happens: (what printf("pathname = %s\n", pathname); prints):
pathname = /mnt/c/Users/.../Desktop/.../.../.../Project2/tmp
pathname = /mnt/c/Users/.../Desktop/.../.../.../Project2/tmp/tmpdir.JlzQFY
pathname = /mnt/c/Users/.../Desktop/.../.../.../Project2/tmp/tmpdir.JlzQFY/Testfile1in2
pathname = /mnt/c/Users/.../Desktop/.../.../.../Project2/tmp/tmpdir.JlzQFY/Testfile2in2
pathname = /mnt/c/Users/.../Desktop/.../.../.../Project2/tmp/tmpdir.JlzQFY/tmpdir.QE1nk2
Notice the last print, it tacks on the next tmpdir.XXX onto the first one. I dont really understand what's going on here and ive been staring at this for ages trying to work it out.
I am trying to read a given directory filePath and get the names of all non folder files into a array of strings. So the issue that I need solved is how to specifically not get folder type files but also get all the other file type names and store them into the string array. Later I plan to use threads to read these individual files as well, but I need to be able to store the files names properly. The code that I am currently using is below. It should also be noted that this code is being executed by a child process from the fork() command, but I am not sure if that is relevant to the issue anyway. Any help would be appreciated. Thanks.
Example:
In the Home/Documents there are 4 files: hello.txt something.dat folder1 something2.dat
My string array should have the values hello.txt, something.dat, and something2.dat
Note: It is okay for me not to do the files as a I go through the directory as the files themselves are not going to be changed at all content wise.
//char* directory is an absolute filePath to the directory
void getFilesFromDirectory(char* directory, pid_t process)
{
int index =0;
DIR *dir;
struct dirent *ent;
//Can hold only 500 valid files in the folder
char *stringArray[500];
if ((dir = opendir (directory)) != NULL)
{
while ((ent = readdir (dir)) != NULL)
{
strcpy(stringArray[index],ent->d_name);
index++;
}
closedir (dir);
}
else
{
/* could not open directory */
perror ("");
}
//Everything Below is not related to the problem. Just what I am using it for.
pthread_t threadArray[index];
pthread_t senderThread;
//thread_param_t parameterSender;
thread_param_t paramterArray[index];
sem_init(&empty,0,bufferSize);
sem_init(&full, 0, 0);
sem_init(&mutex, 0, 1);
//parameterSender.listItem = listHead;
pthread_create(&senderThread, NULL, senderFunction, NULL);
//int threadCounter = 0;
for(int i =0; i<index; i++)
{
paramterArray[i].fileLocation = strcat(directory, stringArray[i]);
pthread_create(&threadArray[i], NULL, threadFunction, paramterArray + i);
}
}
You could check stringArray for files without "." and set this pointer to Null. (There are files missing)
A better option is this:
#include <stdio.h>
#include <dirent.h>
int main()
{
DIR *folder;
struct dirent *entry;
int files = 0;
folder = opendir(".");
if(folder == NULL)
{
perror("Unable to read directory");
return(1);
}
printf("debug\n");
while( (entry=readdir(folder)) )
{
files++;
printf("File %3d: %s :: %s\n",
files,
entry->d_name,
(entry->d_type == DT_DIR)?"Directory" : "File"
);
}
closedir(folder);
return(0);
}
I'm trying to copy directory contents to another directory
but I'm having a problem with writing to the second directory without using sprintf; Any suggestions?
void Copying(char *folder1, char *folder2) {
DIR *s1, *s2;
struct dirent *dep;
if ((s1 = opendir(folder1)) == NULL) {
printf("Error\n");
return;
}
if ((s2 = opendir(folder2)) == NULL) {
printf("Error \n");
return;
}
while ((dep = readdir(s1)) != NULL) {
//write(s2 , dep->d_name , sizeof(dep) ) ; // <-
}
closedir(s1);
closedir(s2);
return;
}
This approach won't work. Directory handles are not writable.
If you want to copy the contents of a directory, you will need to copy each file, directory, and link in the source directory individually. To copy each file, you will need to create a new file in the target directory and write the contents of the source file into it.
In my program stat is only working for a current directory. Can any one please help me with this.
even though I am passing parameter from main it is only working for current directory.
and source path is good it is printing correct path which I have passed from the main.
DIR *dr;
struct dirent *cur;
struct stat fi;
long int total_size = 0;
dr = opendir(source);
char *name;
printf("%s\n\n\n", source);
if (!(dr))
{
perror("opendir()");
return(1);
}
while (cur = readdir(dr))
{
if(cur->d_name[0] != '.')
{
if(stat(cur->d_name, &fi) == -1)
{
printf("error \n\n");
}
else
{
printf("%s ",cur->d_name);
printf("%ld ",fi.st_blocks);
total_size = total_size + fi.st_blocks;
}
}
}
printf("\n\ntotal_size = %ld \n", total_size);
printf("\n\n\n");
return 0;
}
cur->d_name only contains the file name.
to get a 'stat()' outside the current directory,
need to prefix with the path string.
Also need to check if the returned struct from readdir()
is a file or a sub directory.
The main problem is that stat expects a file path but d_name is just the file name. You can find a working example of how to use stat with d_name here
I am working on a simple project to implement "ls -R" from scratch. Whenever I run what I have, my program just keeps searching the root directory over and over again. What am I doing wrong?
void lsR(char dirName[]) {
/*
The recursive function call.
*/
DIR *dir;
struct dirent *directory;
struct stat fileStat;
char type;
char **nameList[MAX_RECURSIVE_FILES];
struct passwd *user;
int count = 0;
int i = 0;
printf("\n");
printf("./%s :\n", dirName);
printf("\n");
if ((dir = opendir(dirName)) == NULL) {
perror("opendir error:");
return;
}
while ((directory = readdir(dir)) != NULL) {
if (stat(directory->d_name, &fileStat) < 0) {
perror("fstat error:");
return;
}
if (fileStat.st_uid == 1) {
continue;
}
user = getpwuid(fileStat.st_uid);
printf("%s ", directory->d_name);
fileType(&fileStat, &type);
if ((type == 'd') && (count < MAX_RECURSIVE_FILES)) {
nameList[count] = malloc(sizeof(char)*MAX_STRING_LENGTH);
strncpy(nameList[count++], directory->d_name, MAX_STRING_LENGTH);
}
}
closedir(dir);
printf("\n");
for (i=0; i<count; i++) {
printf("Calling lsR on: %s\n", nameList[i]);
lsR(nameList[i]);
}
}
When it executes, I get the following output:
"./. :
., .., ... all other files in my current working directory ....
./. :
., .., ... all other files in my current working directory...
"
Among the list of files in the current directory you've noticed . and .. The first one is a hardlink to the current directory and the second one to the parent directory. So when you recurse through your dir entries you will want to skip those two. Otherwise the first directory you will recurse into will be ., in other words the directory you've just gone through.
This is the reason of your program current behavior, but once you fix that you will run into the issue lurker mentioned in his answer.
Additional notes :
Are you sure about the char **nameList[MAX_RECURSIVE_FILES]; variable? Seems to me you want an array of char * not an array of char **.
Are you aware you can use the S_ISDIR macro on the st_mode field of your stat struct, in order to check that the current file is not a directory instead of your custom function?
You need to include the path relative to your program's current directory. Each nameList element will need to be dirName + "/" + directory->d_name.
If you started out calling lsR on the local directory, ./foo and foo has directory named bar under it, then to open bar you need to open ./foo/bar since your program is running from the directory represented by ..