String concatenation in c spread in two lines - c

I am trying to concatenate two string to use in for a stat function, but when I strcat the char* and then print it shows over two lines like so.
./
boot
tmp
./
tmp
lib
./
lib
lost+found
./
lost+found
sbin
./
sbin
etc
I have tried a few things but i am probably going about this all wrong. Here is my code.
#include <dirent.h>
#include <stdio.h>
#include <errno.h>
#include <sys/stat.h>
#include <string.h>
#include <time.h>
int printDetails(char *path, char *name){
struct stat fileInfo;
char file[100];
strcpy(file, path);
strcat(file, name);
printf("%s\n", file);
return 1;
}
int main(int argc, char *argv[]) {
struct dirent *direntp;
DIR *dirp;
printf("Please Enter directory path\n");
char data[64];
if (fgets(data, sizeof data, stdin)) {
if ((dirp = opendir("/")) == NULL) {
perror ("Failed to open directory");
return 1;
}
while ((direntp = readdir(dirp)) != NULL)
{
printf("%s\n", direntp->d_name);
if(direntp->d_name != "." && direntp->d_name != ".."){
printDetails(data, direntp->d_name);
}
}
while ((closedir(dirp) == -1) && (errno == EINTR)) ;
}
return 0;
}
Any help on this issue would be great.
Thanks very much

fgets will include the \n character at the end of each line. That is, assuming the line of text isn't longer than the size you pass in - otherwise you'll get only part of the line.

Related

How to list all files of a directory recursively in c

This is a c program that list all files of a directory recursively , so it can list all files in c: drive for example .
The above program works fine but i've been trying for 5 days and i can't get it to work without using a function (only main , not main and the other function (listFilesRecursively) )
#include <stdio.h>
#include <string.h>
#include <dirent.h>
void listFilesRecursively(char *path);
int main()
{
// Directory path to list files
char path[100];
// Input path from user
strcpy(path , "c://");
listFilesRecursively(path);
return 0;
}
/**
* Lists all files and sub-directories recursively
* considering path as base path.
*/
void listFilesRecursively(char *basePath)
{
char path[1000];
struct dirent *dp;
DIR *dir = opendir(basePath);
// Unable to open directory stream
if (!dir)
return;
while ((dp = readdir(dir)) != NULL)
{
if (strcmp(dp->d_name, ".") != 0 && strcmp(dp->d_name, "..") != 0)
{
printf("%s\n", dp->d_name);
// Construct new path from our base path
strcpy(path, basePath);
strcat(path, "/");
strcat(path, dp->d_name);
listFilesRecursively(path);
}
}
closedir(dir);
}
Thanks :)
I can't for the life of me think why anybody would want to enumerate directories by calling main() recursively. But, since I can't resist a pointless challenge, here's a version that does. Do I get the prize for "most fruitless waste of ten minutes?" ;)
#include <stdio.h>
#include <string.h>
#include <dirent.h>
#include <errno.h>
#include <stdlib.h>
int main (int argc, char **argv)
{
const char *path;
if (argc != 2) path = "/etc"; /* Set starting directory, if not passed */
else
path = argv[1];
DIR *dir = opendir (path);
if (dir)
{
struct dirent *dp;
while ((dp = readdir(dir)) != NULL)
{
if (dp->d_name[0] != '.')
{
char *fullpath = malloc (strlen (path) + strlen (dp->d_name) + 2);
strcpy (fullpath, path);
strcat (fullpath, "/");
strcat (fullpath, dp->d_name);
if (dp->d_type == DT_DIR)
{
char **new_argv = malloc (2 * sizeof (char *));
new_argv[0] = argv[0];
new_argv[1] = fullpath;
main (2, new_argv);
free (new_argv);
}
else
printf ("%s\n", fullpath);
free (fullpath);
}
}
closedir(dir);
}
else
fprintf (stderr, "Can't open dir %s: %s", path, strerror (errno));
return 0;
}

How to fix segmentation fault in the use of struct dirent in C

My code prints the files/directory names in a given path(user enters it as a command-line argument). When executing with a given path in the directory, it just works fine but it is supposed to do the same for the current working directory if user does not provide any command-line argument.
I am getting seg fault if I just run as: ./a.out
It works when I run as: ./a.out /path
Please fix my code by providing the necessary code fragment
I have tried to do debugging and found out that it gives the error right after it executes the line following line in the depthFirst function
printf("%s\n", sd->d_name);
My faulty code:
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <dirent.h>
#include <sys/stat.h>
#include <limits.h>
void depthFirst(char * path){
struct dirent *sd;
DIR *dir;
//char path[PATH_MAX];
dir = opendir(path);
if(dir == NULL){
printf("Error, unable to open\n");
exit(1);
}
while( (sd = readdir(dir)) != NULL){
if(strcmp(sd->d_name, ".") != 0 && strcmp(sd->d_name, "..") != 0){
printf("%s\n", sd->d_name);
realpath(sd->d_name,path);
if(isdirectory(path)){
printf("\t");
depthFirst(sd->d_name);
}
}
}
closedir(dir);
}
int isdirectory(char *path) {
struct stat statbuf;
if (stat(path, &statbuf) == -1)
return 0;
else
return S_ISDIR(statbuf.st_mode);
}
int main(int argc, char *argv[]){
char * path;
char * currentDirectory;
if(argc<2){
currentDirectory = ".";
depthFirst(currentDirectory);
}
else{
path = argv[1];
depthFirst(path);
}
return 0;
}
The output is shown below:
.git
Segmentation fault
Jonathan beat me to it in the comments, but this change prevents the problem.
## -9,7 +9,7 ##
void depthFirst(char * path){
struct dirent *sd;
DIR *dir;
- //char path[PATH_MAX];
+ char rpath[PATH_MAX];
dir = opendir(path);
## -22,8 +22,8 ##
while( (sd = readdir(dir)) != NULL){
if(strcmp(sd->d_name, ".") != 0 && strcmp(sd->d_name, "..") != 0){
printf("%s\n", sd->d_name);
- realpath(sd->d_name,path);
- if(isdirectory(path)){
+ realpath(sd->d_name,rpath);
+ if(isdirectory(rpath)){
printf("\t");
depthFirst(sd->d_name);
As another comment pointed out, you cannot reuse the char* path because it is stored in a page of memory that is not writable by your program. Therefore, realpath() will crash upon attempting to write to it.

Find Argv[i] in /bin and /sbin in C

I cannot locate argv[i] in /bin (or /sbin), package only checks the directory it was run from. How do I check for argv[i] in /bin and /sbin?
I am currently working on my own package manager and I am writing it in pure C. I am currently writing the check to see if the package(s) passed (using argv[]) are already installed. The issue I am having is that when I run for the check my code only checks in the directory it was run from and I need it to check /bin and /sbin (I am going to handle to checking of /sbin) and I am trying to get it to check /bin, but am having zero luck. I cannot seem to get this to work, each time they just check the current working directory and I need them to check /bin. I can't figure this out, has anyone by chance done this in pure C before? Thank you
These are all the methods I have tried so far, none of them work...
using stat()
#include <stdio.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <dirent.h>
int main(int argc, char *argv[])
{
struct dirent *de = calloc(1, sizeof(struct dirent));
DIR *dr = opendir("/bin"); /* directory to open */
short i;
struct stat *program = calloc(1, sizeof(struct stat));
if (dr == NULL) {
printf("directory could not be opened");
return 0;
}
while ((de = readdir(dr)) != NULL) {
for (i = 1; i < argc; i++) {
if (stat(argv[i], program) == 0) {
printf("found\n");
closedir(dr);
}
else {
printf("not found\n");
closedir(dr);
}
}
}
}
using realpath
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
int main(int argc, char *argv[])
{
struct dirent *de = calloc(1, sizeof(struct dirent));
DIR *dr = opendir("/bin"); /* directory to open */
short i;
char *res = realpath(argv[i], NULL);
if (dr == NULL) {
printf("directory could not be opened");
return 0;
}
while ((de = readdir(dr)) != NULL) {
for (i = 1; i < argc; i++) {
if (res == NULL) {
printf("found\n");
closedir(dr);
}
else {
printf("not found\n");
closedir(dr);
}
}
}
}
using strcmp
#include <stdio.h>
#include <string.h>
#include <dirent.h>
int main(int argc, char *argv[])
{
struct dirent *de;
DIR *dr = opendir("/bin"); /* directory to open */
short i;
struct stat program;
if (dr == NULL) {
printf("directory could not be opened");
return 0;
}
while ((de = readdir(dr)) != NULL) {
for (i = 1; i < argc; i++) {
if (strcmp(de->d_name, argv[i]) == 0) {
printf("found\n");
closedir(dr);
}
else {
printf("not found\n");
closedir(dr);
}
}
}
}
I am expecting them all to work as follows:
check echo
// it would go to /bin and find echo and then print
found
but when I run them they only check the current working directory, so for example:
check connection.c
// finds connection.c in the same directory
found
Solution
Naha! I found a way to do it! So using the function chdir() I can run stat() in /bin like so:
#include <stdio.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
short i;
struct stat *program = calloc(1, sizeof(struct stat));
for (i = 1; i < argc; i++) {
chdir("/bin"); /* move to /bin */
if (chdir("/bin") != 0)
return 1;
if (stat(argv[i], program) == 0)
return 0;
else
return 1;
}
}
I tried simplifying your code just to output the contents of the folder, I get the contents of the '/bin' folder each time.
As a general rule of thumb, I like to get my code to compile without warnings, test it does what I expect it to, then work on the next bit.
The 'struct stat program' was causing the code not to compile, my guess is you were running an old version of the code.
#include <stdio.h>
#include <dirent.h>
#include <string.h>
int main(int argc, char *argv[])
{
struct dirent *de;
DIR *dr = opendir("/bin"); /* directory to open */
short i;
// struct stat program;
if (dr == NULL) {
printf("directory could not be opened");
return 0;
}
while ((de = readdir(dr)) != NULL) {
printf(de->d_name);
printf("\n");
}
}
If I understand you correctly then you’re confusing the semantics of opendir/readdir with those of chdir:
opendir does not change the working directory. This means that, e.g. realpath("echo", resolved_path) won’t resolve echo as /bin/echo but as $PWD/echo (where $PWD is the environment variable holding your current working directory).
That said, as a general rule you should not chdir inside your process. Instead, you can construct the path explicitly … e.g. via sprintf:
const char *binpath = "/bin";
char *fullpath = malloc(strlen(binpath) + 1 + strlen(argv[1]) + 1);
sprintf(fullpath, "%s/%s", binpath, argv[1]);
… and then stat the result (no need to dynamically allocate your struct stat either):
struct stat st;
if (stat(fullpath, &st) != 0) {
fprintf(stderr, "error in stat(): %s", strerror(errno));
}
printf("%s has inode %ju\n", fullpath, (unsigned long) st.st_ino);

How to compare multiple files based on only file type and size

The goal is to compare files by size and filter those of the same size.
For that you need to compare every file to every file.
However the first loop doesnt work so the search of the first directory is stuck at the first file.
#include <dirent.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/stat.h>
int main(int argc, char *v[]) {
struct dirent *d_verzeichnis1;
struct dirent *d_verzeichnis2;
DIR *dir1;
DIR *dir2;
FILE *file = fopen(v[3], "W");
dir1 = opendir(v[1]);
dir2 = opendir(v[2]);
struct stat filesize1;
struct stat filesize2;
while ((d_verzeichnis1 = readdir(dir1)) != NULL) {
stat((d_verzeichnis1->d_name), &filesize1);
while ((d_verzeichnis2 = readdir(dir2)) != NULL) {
stat((d_verzeichnis2->d_name), &filesize2);
if (filesize1.st_size == filesize2.st_size);
{
printf("%s und %s sind gleich\n",
d_verzeichnis1->d_name, d_verzeichnis2->d_name);
}
}
d_verzeichnis1 = readdir(dir1);
}
}
There are multiple problems in your code:
you should verify the actual number of arguments provided on the command line to avoid undefined behavior if fewer than 3 were provided.
fopen(v[3], "W"); uses an invalid mode string, you should use "w". It is unclear what this stream pointer is used for anyway.
dir1 and dir2 are not tested: you have undefined behavior if opendir() fails.
stat is called with the directory entry name, which is not a relative pathname to the file if the directory is different from the current directory. You should construct the path name from the directory name and entry name.
if (filesize1.st_size == filesize2.st_size); has an extra ; at the end of the line, causing the following block to execute unconditionally. You should use K&R style with{` at the end of the line to avoid such silly mistakes.
the logic of parallel scan is incorrect: you should reopen or at least rewind the second directory for each entry in the first to allow a full scan for potential matches.
Here is a corrected version:
#include <dirent.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/stat.h>
char *buildpath(char *dest, size_t size, const char *dir, const char *name) {
size_t len = strlen(dir);
const char *sep = "";
if (len > 0 && dir[len - 1] != '/')
sep = "/";
if ((unsigned)snprintf(dest, size, "%s%s%s", dir, sep, name) < size)
return dest;
else
return NULL;
}
int main(int argc, char *argv[]) {
char path1[1024];
char path2[1024];
struct dirent *dp1;
struct dirent *dp2;
DIR *dir1;
DIR *dir2;
struct stat filesize1;
struct stat filesize2;
if (argc < 3) {
fprintf(stderr, "missing argument\n");
fprintf(stderr, "usage: cmpdir dir1 dir2\n");
return 1;
}
dir1 = opendir(argv[1]);
if (dir1 == NULL) {
fprintf(stderr, "cannt open directory %s: %s\n", argv[1], strerror(errno));
return 1;
}
dir2 = opendir(argv[2]);
if (dir2 == NULL) {
fprintf(stderr, "cannt open directory %s: %s\n", argv[2], strerror(errno));
return 1;
}
while ((dp1 = readdir(dir1)) != NULL) {
/* ignore . and .. entries */
if (!strcmp(dp1->d_name, ".")
|| !strcmp(dp1->d_name, ".."))
continue;
if (!buildpath(path1, sizeof path1, argv[1], dp1->d_name)) {
/* path too long */
continue;
}
if (stat(path1, &filesize1)) {
/* cannot stat entry */
continue;
}
if (!S_ISREG(filesize1.st_mode)) {
/* not a regular file */
continue;
}
rewinddir(dir2);
while ((dp2 = readdir(dir2)) != NULL) {
/* ignore . and .. entries */
if (!strcmp(dp2->d_name, ".")
|| !strcmp(dp2->d_name, ".."))
continue;
if (!buildpath(path2, sizeof path2, argv[2], dp2->d_name)) {
/* path too long */
continue;
}
if (stat(path2, &filesize2)) {
/* cannot stat entry */
continue;
}
if (!S_ISREG(filesize2.st_mode)) {
/* not a regular file */
continue;
}
if (filesize1.st_size == filesize2.st_size) {
printf("%s and %s have the same size %llu\n",
path1, path2, (unsigned long long)filesize1.st_size);
/* perform actual comparison... */
}
}
}
closedir(dir1);
closedir(dir2);
return 0;
}

Program not working in declared directory path, only in current directory

I'm writing a program that takes all the files from a directory declared in the command line. The command line takes 2 arguments, the directory path and a optional flag "-s" which spits out directory information in non-decreasing order if applied. I'm 90% done but my program only spits out files and file information from the current directory, not the directory specified in the command line. Any advice would be appreciated
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/syscall.h>
#include <string.h>
#include <ctype.h>
int mygetFstat(char *name);
char *removeWhiteSpaces(char *str);
#define PATH 1
#define FLAG 2
#define LEN 10
#define STRLEN 54
#define MAXLEN 100
struct stat fileStat;
time_t t;
struct tm lt;
char timbuf[MAXLEN];
int main(int argc, char *argv[]){
DIR *dir;
struct dirent *ent;
FILE *ptr;
char myBuf[MAXLEN];
char filename[MAXLEN];
char finalfile[MAXLEN];
char length;
char str[MAXLEN];
char cmd[MAXLEN];
if ((dir = opendir (argv[PATH])) != NULL) {
// print all the files and directories within directory
if(argv[FLAG] != NULL){
if(strcmp(argv[FLAG], "-s") == 0){
system("ls -al | sort -k5n >> tempfile.txt");
//sprintf(finalfile, "cd %s | ls -al | sort -k5n >> tempfile.txt", (char *)argv[PATH]);
// printf("\nfinal file = %s\n", finalfile);
// system(finalfile);
if(NULL == (ptr = fopen("tempfile.txt","rw"))){
printf("\nCan't open file.\n");
exit(1);
}
while(!feof(ptr)){ // loop through every line in tempfile.txt
fgets(myBuf, MAXLEN, ptr);
if(strlen(myBuf) > LEN){ // I chose 11 here because some lines were only 10 characters
// And they were unnecessary.
length = strlen(myBuf); // Grabs length of entire line from ptr
strncpy(filename, myBuf + STRLEN, length); // the file names start at bit position 54,
if((filename[0] == '.') && (filename[1] != '.') && (strlen(filename) != 2)){
removeWhiteSpaces(filename);
mygetFstat(filename);
}
}
}
system("rm tempfile.txt");
exit(1);
}else{
printf("Error: Flag not recognized.\n");
return 0;
}
}else{
while((ent = readdir(dir)) != NULL){
if((ent->d_name[0] == '.') && (ent->d_name[1] != '.') && (strlen(ent->d_name) != 1))
mygetFstat(ent->d_name);
}
closedir (dir);
}
} else {
// could not open directory
printf("No such File or Directory.\n");
return EXIT_FAILURE;
}
}
int mygetFstat(char *name)
{
// Function for finding info about files.
int file = 0;
if((file = open(name,O_RDONLY)) < -1)
return 1;
if(fstat(file,&fileStat) < 0)
return 1;
printf("Information for %s\n",name);
printf("---------------------------\n");
printf("File Size: \t\t%d bytes\n",fileStat.st_size);
// Adjusts time to display date. Not just seconds from epoch
t = fileStat.st_mtime;
localtime_r(&t, &lt);
strftime(timbuf, sizeof(timbuf), "%c", &lt);
printf("Date Last Modified: \t%s\n",timbuf);
printf("\n");
//return 0;
}
char *removeWhiteSpaces(char *str){ //removes white spaces from input
char *end;
while(isspace(*str)) str++;
if(*str == 0)
return str;
end = str + strlen(str)-1;
while(end > str && isspace(*end)) end--;
*(end+1) = 0;
return str;
}
ent->d_name only contains the name of the entry in that directory. It does not include the full path to the entry.
If the first argument is "folder1" and there are files "file-1.txt" and "file-2.txt" in that directory, ent->d_name will be "file-1.txt" and "file-2.txt". You need to pass "folder1/file-1.txt" to mygetFstat(), not just "file-1.txt".
You should change the while loop to:
while((ent = readdir(dir)) != NULL){
if((ent->d_name[0] == '.') && (ent->d_name[1] != '.') && (strlen(ent->d_name) != 1))
{
strcpy(filename, argv[PATH]);
strcat(filename, "/");
strcat(filename, ent->d_name);
mygetFstat(filename);
}
}
Update
I would add a function
int is_dot_or_dot_dot(char const* entryName)
{
return (strcmp(entryName, ".") == 0) || (strcmp(entryName, "..") == 0);
}
and change the code inside the while loop to:
while((ent = readdir(dir)) != NULL){
if ( is_dot_or_dot_dot(ent->d_name) )
{
continue;
}
strcpy(filename, argv[PATH]);
strcat(filename, "/");
strcat(filename, ent->d_name);
mygetFstat(filename);
}
Keep your code, do a chdir right after you open the directory:
if ((dir = opendir (argv[PATH])) != NULL) {
// print all the files and directories within directory
// Change the working directory to the one given.
if (chdir(argv[PATH]) == -1) {
perror(argv[PATH]); exit(1);
}
P.S I would recommend using perror but you have to include errno.h.
Improvement on the rest of your code.
system("ls -al | sort -k5n >> tempfile.txt");
While you can do that it would be a faster way to insert it into a linked list sorting it as you insert them. But if you want to keep it see below for improvements.
The whole point of this project is to use system calls.See http://www.albany.edu/~csi402/pdfs/lect_10.pdf
while(!feof(ptr)){ // loop through every line in tempfile.txt
fgets(myBuf, MAXLEN, ptr);
feof is not reliable, use
while( fgets (myBuf, MAXLEN, ptr)!=NULL ){

Resources