I am using execvp to find certain files. This is the code I am using:
char *argv1[] = {"find", "-name", "*.jpg", NULL};
execvp("find",argv1);
I was wondering is there a way to store/hold the results from the execvp into an array for later user?
Also is there a way I can get only the desired file instead of the whole path?
This is my readdir() functoin.
static void list_dir (const char * dir_name)
{
char *ArrayFiles[100];
DIR * d;
/* Open the directory specified by "dir_name". */
int i = 0;
d = opendir (dir_name);
/* Check it was opened. */
if (!d) {
fprintf (stderr, "Cannot open directory '%s': %s\n",
dir_name, strerror (errno));
exit (EXIT_FAILURE);
}
while (1) {
struct dirent * entry;
const char * d_name;
/* "Readdir" gets subsequent entries from "d". */
entry = readdir (d);
if (! entry) {
/* There are no more entries in this directory, so break
out of the while loop. */
break;
}
d_name = entry->d_name;
if ((strstr(d_name, ".jpg")) || (strstr(d_name, ".JPG"))){
/* skip printing directories */
if (! (entry->d_type & DT_DIR)) {
char *filename = entry->d_name;
printf ("%s\n", d_name);
}
}
if (entry->d_type & DT_DIR) {
/* skip the root directories ("." and "..")*/
if (strcmp (d_name, "..") != 0 && strcmp (d_name, ".") != 0) {
int path_length;
char path[PATH_MAX];
path_length = snprintf (path, PATH_MAX,
"%s/%s", dir_name, d_name);
if (path_length >= PATH_MAX) {
fprintf (stderr, "Path length has got too long.\n");
exit (EXIT_FAILURE);
}
/* Recursively call "list_dir" with the new path. */
list_dir (path);
}
}
}
/* After going through all the entries, close the directory. */
if (closedir (d)) {
fprintf (stderr, "Could not close '%s': %s\n",
dir_name, strerror (errno));
exit (EXIT_FAILURE);
}
}
Related
I'm writing a code that reads the first line from a file, where this line includes a path to directory. Then the list_dir() function would enter all subfolders..
I checked the list_dir() and it's works great when I'm sending the path manually -
For example: list_dir ("/home/Desktop/example");
Here is my code:
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <dirent.h>
#include <limits.h>
static void list_dir (const char *dirPath)
{
// Open the directory in dir_name
DIR *d;
d = opendir (dirPath);
/* Check it was opened. */
printf("%s",dirPath);
if (!d) {
printf ("Cannot open directory\n");
exit (1);
}
while (1) {
struct dirent * entry;
const char * d_name;
/* "Readdir" gets subsequent entries from "d". */
entry = readdir (d);
/* if There are no more entries in this directory */
if (!entry) {
break;
}
/* Print the name of the file and directory. */
d_name = entry->d_name;
printf ("%s/%s\n", dirPath, d_name);
if (entry->d_type & DT_DIR) {
/* Check that the directory is not "d" or d's parent. */
if (strcmp (d_name, "..") != 0 && strcmp (d_name, ".") != 0) {
int path_length;
char path[PATH_MAX];
path_length = snprintf (path, PATH_MAX,"%s/%s", dirPath, d_name);
printf ("%s\n", path);
if (path_length >= PATH_MAX) {
fprintf (stderr, "Path length has got too long.\n");
exit (EXIT_FAILURE);
}
/* Recursively call "list_dir" with the new path. */
list_dir(path);
}
}
}
/* After going through all the entries, close the directory. */
if (closedir (d)) {
printf ("Cannot Close directory");
exit (1);
}
}
void main(int argc, char *argv[])
{
//configuration file path
char* dirPath = argv[1];
FILE *f1 = fopen(dirPath, "r");
if (f1 == NULL) {
printf("Cannot open the file for reading");
exit(1);
}
char *line = NULL;
size_t len = 0;
ssize_t read;
while ((read = getline(&line, &len, f1)) != -1) {
break;
}
list_dir (line);
fclose (f1);
free(line);
}
example for the txt file:
/home/Desktop/example/
bla bla bla
bla bla bla
As you understand, the problem is when I'm sending the path from main() function, list_dir() can't open the path and I get "Cannot open directory" as an error. Help?
As the commenters above said there is a newline at the end of dirPath and that's why you get Cannot open directory, add strtok(dirPath, "\n"); just before opendir to get rid of the trailing newline.
Also note that you are including some headers more than once and that main should return an int.
I have this code I modified but the problem is, I can't get it to jet me only files with certain extensions. I tried so many things and every time I don't get the desired output. Any help would be appreciated. This part of a very big project and I got stuck at this specific function.
static void list_dir (const char * dir_name)
{
DIR * d;
/* Open the directory specified by "dir_name". */
d = opendir (dir_name);
/* Check it was opened. */
if (! d) {
fprintf (stderr, "Cannot open directory '%s': %s\n",
dir_name, strerror (errno));
exit (EXIT_FAILURE);
}
while (1) {
struct dirent * entry;
char * d_name;
/* "Readdir" gets subsequent entries from "d". */
entry = readdir (d);
if (! entry) {
/* There are no more entries in this directory, so break
out of the while loop. */
break;
}
d_name = entry->d_name;
if(!strstr (d_name, ".jpg") == 0 && !strstr (d_name, ".JPG") == 0){
continue;
}
/* Print the name of the file and directory. */
printf ("%s\n", d_name);
/* If you don't want to print the directories, use the
following line: */
//if (! (entry->d_type & DT_DIR)) {
//printf ("%s/%s\n", dir_name, d_name);
//}
if (entry->d_type & DT_DIR) {
/* Check that the directory is not "d" or d's parent. */
if (strcmp (d_name, "..") != 0 && strcmp (d_name, ".") != 0) {
int path_length;
char path[PATH_MAX];
path_length = snprintf (path, PATH_MAX,
"%s/%s", dir_name, d_name);
//printf ("%s\n", path);
if (path_length >= PATH_MAX) {
fprintf (stderr, "Path length has got too long.\n");
exit (EXIT_FAILURE);
}
/* Recursively call "list_dir" with the new path. */
if(!strstr (d_name, ".jpg") == 0 && !strstr(d_name, ".JPG") == 0){
continue;
}
list_dir (path);
}
}
}
/* After going through all the entries, close the directory. */
if (closedir (d)) {
fprintf (stderr, "Could not close '%s': %s\n",
dir_name, strerror (errno));
exit (EXIT_FAILURE);
}
}
You should know that case sensitivity is not solved by just using ".jpg" and ".JPG" since there could be more like ".jPg" and so on.
You can try this
int endsWith(const char *const filename, const char *const extension)
{
size_t fileNameLength;
size_t extensionLength;
if ((filename == NULL) || (extension == NULL))
return 0;
fileNameLength = strlen(filename);
extensionLength = strlen(extension);
return (strcasecmp(extension, filename + filenameLength - extensionLength) == 0);
}
then you can do
if (endsWidth(d_name, ".jpg") != 0) /* it has jpeg extension */
Note: strcasecmp() is not standard, you can find the correct alternative for your c library googling.
And also, there are libraries that examine the file type by using the so called magic bytes, they are normally the first 4 or so bytes in the file content, there is even one called libmagic, although I have never worked with it, so I can't give you advice on how to use it.
I would replace the line
if(!strstr (d_name, ".jpg") == 0 && !strstr (d_name, ".JPG") == 0){
with more readable code:
if( fileIsNotJPGFile(d_name) ) {
And implement the function as:
int fileIsJPGFile(char const* name)
{
return (strstr(name, ".jpg") || strstr(name, ".JPG"));
}
int fileIsNotJPGFile(char const* name)
{
return !(fileIsJPGFile(name));
}
I am brand new to System Programming and am having some trouble learning how directories and files work. The program should take two arguments(directories), if both are existing directories then just copy the files from the first argument into the second. If the second is a file, return with an error, finally if the second argument doesn't exist, then create it and copy the files over.
The problem occurs when I am trying to open each file to copy over the contents to the new created copy. I can get the list of all files in the first directory. If I remove copy the data(aka. in_fd) the program copies all the files over, they just are empty files.
So far the program checks the input, makes the directory if needed. All that is left is to copy over the files.
Any help will be appreciated. I saw this on other questions but none of the answers seemed to help. Thank you in advance for all your help.
#define BUFFERSIZE 4096
#define COPYMODE 0644
void oops(char *, char *);
int main(int ac, char *av[])
{
int in_fd, out_fd, n_chars;
char buf[BUFFERSIZE];
/* check args */
if ( ac != 3 ){
fprintf( stderr, "usage: %s source destination\n", *av);
exit(1);
}
//Directory pointers
DIR *sender_dir_ptr;
DIR *receiver_dir_ptr;
struct dirent *direntp;
//Used to test second argument for new/existing directory
struct stat info;
if(lstat(av[2],&info) != 0) {
if(errno == ENOENT) {
//doesn't exist, make directory
mkdir(av[2], 0700);
if ((receiver_dir_ptr = opendir(av[2])) == NULL )
oops("cannot open %s\n", av[2]);
} else if(errno == EACCES) {
// we don't have permission to know if
// the path/file exists.. impossible to tell
oops("Permission Denied", av[2]);
}
}
//so, it exists.
if(S_ISDIR(info.st_mode)) {
//it's a directory. Assign the directory pointer
if ((receiver_dir_ptr = opendir(av[2])) == NULL )
oops("cannot open %s\n", av[2]);
} else if(S_ISREG(info.st_mode)) {
//it's a file, display error and exit
oops("File exists but looking for a directory", av[2]);
}
if ((sender_dir_ptr = opendir(av[1])) == NULL )
oops("cannot open %s\n", av[1]);
else
{
struct stat st_buf;
//Go through sender directory and copy over all files to new directory
while (( direntp = readdir(sender_dir_ptr)) != NULL )
{
lstat(direntp->d_name, &st_buf);
if (S_ISDIR (st_buf.st_mode))
{
continue;
}
else if (S_ISREG (st_buf.st_mode))
{
printf("direntp= %s\n",direntp->d_name);
char tmp_in[strlen(av[1])];
strcpy(tmp_in, av[1]);
strcat(tmp_in, "/");
strcat(tmp_in, direntp->d_name);
if ((in_fd=open(tmp_in, O_RDONLY)) == -1 )
oops("Cannot open,", direntp->d_name);
//Create pathname to the second directory
char* filename = av[2];
char tmp[strlen(av[2])];
strcpy(tmp, av[2]);
strcat(tmp, "/");
strcat(tmp, direntp->d_name);
printf("filename: %s \n", tmp);
//Create new file
if ((out_fd=creat(tmp, COPYMODE)) == -1 )
oops( "Cannot creat", tmp);
//Write old file data into the new files
while ( (n_chars = read(in_fd , buf, BUFFERSIZE)) > 0 )
if ( write(out_fd, buf, n_chars ) != n_chars )
oops("Write error to ", av[2]);
if ( n_chars == -1 )
oops("Read error from ", av[1]);
//close files
if ( close(in_fd) == -1 || close(out_fd) == -1 )
oops("Error closing files","");
}
else{
printf("File: %s \n",direntp->d_name);
}
}
//Close directories
closedir(sender_dir_ptr);
closedir(receiver_dir_ptr);
}
return 0;
}
void oops(char *s1, char *s2)
{
fprintf(stderr,"Error: %s ", s1);
perror(s2);
exit(1);
}
'direntp->d_name' is filename only, not a complete file specification as required by open() etc. You need to strcat the name to the folder path.
I have a client/ server application, and i get an error there -> perror ("[server] Can't send the message to client.\n"). So the server cant' send the msgrasp ( the buffer). If you can help, I'll be grateful.
void printdir(char *dir, int depth)
{
DIR *dp;
struct dirent *entry;
struct stat statbuf;
if((dp = opendir(dir)) == NULL) {
fprintf(stderr,"cannot open directory: %s\n", dir);
return;
}
chdir(dir);
while((entry = readdir(dp)) != NULL) {
lstat(entry->d_name,&statbuf);
if(S_ISDIR(statbuf.st_mode)) {
/* Found a directory, but ignore . and .. */
if(strcmp(".",entry->d_name) == 0 ||
strcmp("..",entry->d_name) == 0)
continue;
printf("%*s%s/\n",depth,"",entry->d_name);
/* Recurse at a new indent level */
printdir(entry->d_name,depth+4);
}
else printf("%*s%s\n",depth,"",entry->d_name);
}
chdir("..");
closedir(dp);
}
int printForClient(int fd)
{
char buffer[100];
int bytes;
char msg[100];
char *msgrasp=NULL;
bytes = read (fd, msg, sizeof (buffer));
if (bytes < 0)
{
perror ("Can't read from client.\n");
return 0;
}
printf ("[server]..%s\n", msg);
printdir(&msgrasp,msj,0);
printf("[server]%s\n",msgrasp);
if (bytes && write (fd, msgrasp, bytes) < 0)
{
perror ("[server] Can't send the message to client.\n");
return 0;
}
return bytes;
}
This is not a very good Idea, but since it's what you requested here you have a solution with dynamic memory allocation
#include <stdio.h>
#include <dirent.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
void printdir(char **output, const char *const dir, int depth)
{
DIR *dp;
struct dirent *entry;
struct stat statbuf;
if ((dp = opendir(dir)) == NULL)
{
fprintf(stderr,"cannot open directory: %s\n", dir);
return;
}
chdir(dir);
while ((entry = readdir(dp)) != NULL)
{
/* check if stat succeeded */
if (lstat(entry->d_name, &statbuf) == -1)
continue;
if (S_ISDIR(statbuf.st_mode) != 0)
{
char *buffer;
size_t length;
/* Found a directory, but ignore . and .. */
if(strcmp(".",entry->d_name) == 0 ||
strcmp("..",entry->d_name) == 0)
continue;
length = 4 + depth + strlen(entry->d_name);
if (*output != NULL)
length += strlen(*output);
buffer = realloc(*output, length);
if (buffer != NULL)
{
char current[length];
if (*output == NULL)
buffer[0] = '\0';
*output = buffer;
snprintf(current, length, "%*s%s/\n", depth, " ", entry->d_name);
strcat(*output, current);
//printf("%*s%s/\n",depth,"",entry->d_name);
/* Recurse at a new indent level */
}
else
{
fprintf(stderr, "Out of memory\n");
free(*output);
*output = NULL;
closedir(dp);
return;
}
printdir(output, entry->d_name, depth + 4);
}
else
{
char *buffer;
size_t length;
length = 4 + depth + strlen(entry->d_name);
if (*output != NULL)
length += strlen(*output);
buffer = realloc(*output, length);
if (buffer != NULL)
{
char current[length];
if (*output == NULL)
buffer[0] = '\0';
*output = buffer;
snprintf(current, length, "%*s%s/\n", depth, " ", entry->d_name);
strcat(*output, current);
}
else
{
fprintf(stderr, "Out of memory\n");
free(*output);
*output = NULL;
closedir(dp);
return;
}
}
}
chdir("..");
closedir(dp);
}
int main()
{
char *buffer = NULL; //buffer for printdir output.
printf("Directory scan of /home:\n");
printdir(&buffer, "/home", 0);
printf("done.\n");
printf("%s\n", buffer);
free(buffer);
exit(0);
}
It is not a very good Idea because you don't know if there will be enough memory to hold all the text, it could grow a lot, I added checks for that situation in this code, in the event of going out of memory, this function will abort reading, release resources and return.
I would suggest adding an argument of type char* (a pointer to a char array) and at every recursion advance the pointer. My try (supposing the buffer is long enough for the output):
void printdir(char *dir, int depth, char* output)
{
DIR *dp;
struct dirent *entry;
struct stat statbuf;
char tmp[100];
if((dp = opendir(dir)) == NULL) {
fprintf(stderr,"cannot open directory: %s\n", dir);
return;
}
chdir(dir);
while((entry = readdir(dp)) != NULL) {
lstat(entry->d_name,&statbuf);
if(S_ISDIR(statbuf.st_mode)) {
/* Found a directory, but ignore . and .. */
if(strcmp(".",entry->d_name) == 0 ||
strcmp("..",entry->d_name) == 0)
continue;
sprintf(tmp, "%*s%s/\n",depth,"",entry->d_name);
strcpy(buffer, tmp);
/* Recurse at a new indent level */
printdir(entry->d_name,depth+4, buffer+strlen(tmp));
}
else printf("%*s%s\n",depth,"",entry->d_name);
}
chdir("..");
closedir(dp);
}
int main()
{ char buffer[1000]; //buffer for printdir output.
printf("Directory scan of /home:\n");
printdir("/home",0);
printf("done.\n");
exit(0);
}
You might want to add \n between every execution, depending on what you wish to do with the output. Please note that in this program \0 at the end of each string is deleted.
I'm trying to run the following code to sign a self made certificate but the program becomes non-responsive at the following piece of code. It doesn't crash or anything but the cursor just sits there blinking.
if (sign) {
if (!(pkcs7 = PKCS7_sign (cert, pkey, chain, in, 0))) { <----Here seems to be the problem
fprintf (stderr, "Error making the PKCS#7 object\n");
goto err;
}
}
From debugging, all the variables seem to have values except chain, gdb prints out:
(gdb) p *chain
Cannot access memory at address 0x0
Here is the entire code:
#include <stdio.h>
#include <stdlib.h>
#include <openssl/crypto.h>
#include <openssl/err.h>
#include <openssl/pem.h>
#include <openssl/rand.h>
/*
* This code appearing before the main function is all for X509_STORE setup.
*/
/* these are defintions to make the example simpler */
#define CA_FILE "CAfile.pem"
#define CA_DIR "/etc/ssl"
#define CRL_FILE "CRLfile.pem"
int
verify_callback (int ok, X509_STORE_CTX * stor)
{
if (!ok)
fprintf (stderr, "Error: %s\n",
X509_verify_cert_error_string (stor->error));
return ok;
}
X509_STORE *
create_store (void)
{
X509_STORE *store;
X509_LOOKUP *lookup;
/* create the cert store and set the verify callback */
if (!(store = X509_STORE_new ())) {
fprintf (stderr, "Error creating X509_STORE_CTX object\n");
goto err;
}
X509_STORE_set_verify_cb_func (store, verify_callback);
/* load the CA certificates and CRLs */
if (X509_STORE_load_locations (store, CA_FILE, CA_DIR) != 1) {
fprintf (stderr, "Error loading the CA file or directory\n");
goto err;
}
if (X509_STORE_set_default_paths (store) != 1) {
fprintf (stderr, "Error loading the system-wide CA certificates\n");
goto err;
}
if (!(lookup = X509_STORE_add_lookup (store, X509_LOOKUP_file ()))) {
fprintf (stderr, "Error creating X509_LOOKUP object\n");
goto err;
}
if (X509_load_crl_file (lookup, CRL_FILE, X509_FILETYPE_PEM) != 1) {
fprintf (stderr, "Error reading the CRL file\n");
goto err;
}
/* set the flags of the store so that CRLs are consulted */
X509_STORE_set_flags (store, X509_V_FLAG_CRL_CHECK |
X509_V_FLAG_CRL_CHECK_ALL);
return store;
err:
return NULL;
}
int
main (int argc, char *argv[])
{
int sign;
X509 *cert;
EVP_PKEY *pkey;
STACK_OF (X509) * chain = NULL;
X509_STORE *store;
PKCS7 *pkcs7;
FILE *fp;
BIO *in, *out, *pkcs7_bio;
OpenSSL_add_all_algorithms ();
ERR_load_crypto_strings ();
/*seed_prng ();*/ /*seed_prng(1024);Borked DOONT LEAVE OUT*/
--argc, ++argv;
if (argc < 2) {
fprintf (stderr,
"Usage: sv (sign|verify) [privkey.pem] cert.pem ...\n");
goto err;
}
if (!strcmp (*argv, "sign"))
sign = 1;
else if (!strcmp (*argv, "verify"))
sign = 0;
else {
fprintf (stderr,
"Usage: sv (sign|verify) [privkey.pem] cert.pem ...\n");
goto err;
}
--argc, ++argv;
/* setup the BIO objects for stdin and stdout */
if (!(in = BIO_new_fp (stdin, BIO_NOCLOSE)) ||
!(out = BIO_new_fp (stdout, BIO_NOCLOSE))) {
fprintf (stderr, "Error creating BIO objects\n");
goto err;
}
if (sign) {
/* read the signer private key */
if (!(fp = fopen (*argv, "r")) ||
!(pkey = PEM_read_PrivateKey (fp, NULL, NULL, NULL))) {
fprintf (stderr, "Error reading signer private key in %s\n", *argv);
goto err;
}
fclose (fp);
--argc, ++argv;
} else {
/* create the cert store and set the verify callback */
if (!(store = create_store ()))
fprintf (stderr, "Error setting up X509_STORE object\n");
}
/* read the signer certificate */
if (!(fp = fopen (*argv, "r")) ||
!(cert = PEM_read_X509 (fp, NULL, NULL, NULL))) {
ERR_print_errors_fp (stderr);
fprintf (stderr, "Error reading signer certificate in %s\n", *argv);
goto err;
}
fclose (fp);
--argc, ++argv;
if (argc)
chain = sk_X509_new_null ();
while (argc) {
X509 *tmp;
if (!(fp = fopen (*argv, "r")) ||!(tmp = PEM_read_X509 (fp, NULL, NULL, NULL))) {
fprintf (stderr, "Error reading chain certificate in %s\n", *argv);
goto err;
}
sk_X509_push (chain, tmp);
fclose (fp);
--argc, ++argv;
}
if (sign) {
if (!(pkcs7 = PKCS7_sign (cert, pkey, chain, in, 0))) {
fprintf (stderr, "Error making the PKCS#7 object\n");
goto err;
}
if (SMIME_write_PKCS7 (out, pkcs7, in, 0) != 1) {
fprintf (stderr, "Error writing the S/MIME data\n");
goto err;
}
} else { /* verify */
if (!(pkcs7 = SMIME_read_PKCS7 (in, &pkcs7_bio))) {
fprintf (stderr, "Error reading PKCS#7 object\n");
goto err;
}
if (PKCS7_verify (pkcs7, chain, store, pkcs7_bio, out, 0) != 1) {
fprintf (stderr, "Error writing PKCS#7 object\n");
goto err;
} else
fprintf (stdout, "Certifiate and Signature verified!\n");
}
return 0;
err:
return -1;
}
If anybody has any ideas I would appreciate a comment!
Just got it! Read here
"In OpenSSL 1.0.0 the certs, signcert and pkey parameters can all be
NULL if the PKCS7_PARTIAL flag is set."
Changed the code to:
if (sign) {
if (!(pkcs7 = PKCS7_sign (cert, pkey, chain, in, PKCS7_PARTIAL))) {
fprintf (stderr, "Error making the PKCS#7 object\n");
goto err;
}
}
And it's all good!