Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 4 years ago.
Improve this question
I just saw a file about copying a file online but I dont know how to run it, I tried "gcc -o a a.c" to create a program, then when I typed "./a" it says "usage: ./a source destination" as error. What should I do?
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <string.h>
#define BUFFERSIZE 4096
#define COPYMODE 0644
void oops(char *, char *);
void copy_file(char *, char *);
void copy(char *, char *);
int main(int ac, char *av[]) {
if (ac != 3) {
fprintf(stderr, "usage: %s source destination\n", *av);
exit(1);
}
copy(av[1], av[2]);
return 0;
}
void oops(char *s1, char *s2) {
fprintf(stderr, "Error: %s ", s1);
perror(s2);
exit(1);
}
void copy_file(char *file1, char *file2)
{
int in_fd, out_fd, n_chars;
char buf[BUFFERSIZE];
struct stat in_stat, out_stat;
Check if two files are existed
if (stat(file1, &in_stat) == 0 && stat(file2, &out_stat) == 0)
{
//Check if two files are same
if (in_stat.st_ino == out_stat.st_ino)
{
//if same, do nothing
return;
}
}
if ( (in_fd=open(file1, O_RDONLY)) == -1 )
oops("Cannot open ", file1);
if ( (out_fd=creat( file2, COPYMODE)) == -1 )
oops( "Cannot creat", file2);
while ( (n_chars = read(in_fd , buf, BUFFERSIZE)) > 0 )
if ( write( out_fd, buf, n_chars ) != n_chars )
oops("Write error to ", file2);
if ( n_chars == -1 )
oops("Read error from ", file1);
if ( close(in_fd) == -1 || close(out_fd) == -1 )
oops("Error closing files","");
if (chmod(file2, in_stat.st_mode) != 0) {
oops("Error change file mode", "");
}
}
void copy(char *file1, char *file2)
{
struct stat in_stat, out_stat;
struct dirent *direntp;
DIR *dir_ptr;
if (stat(file1, &in_stat) != 0)
{
oops("File not exist", "");
}
if (S_ISDIR(in_stat.st_mode))
{
if (stat(file2, &out_stat) != 0)
{
if (mkdir(file2, in_stat.st_mode) != 0)
{
oops("Failed to create directory", "");
}
}
if ((dir_ptr = opendir(file1)) == NULL)
{
oops("Failed to open directory", "");
} else {
while ((direntp = readdir(dir_ptr)) != NULL)
{
if (strcmp(direntp->d_name, ".") && strcmp(direntp->d_name, ".."))
{
char *new_file1 = (char *)malloc(strlen(file1)+strlen(direntp->d_name)+2);
strcpy(new_file1, file1);
strcat(new_file1, "/");
strcat(new_file1, direntp->d_name);
char *new_file2 = (char *)malloc(strlen(file2)+strlen(direntp->d_name)+2);
strcpy(new_file2, file2);
strcat(new_file2, "/");
strcat(new_file2, direntp->d_name);
copy(new_file1, new_file2);
free(new_file1);
free(new_file2);
}
}
closedir(dir_ptr);
}
}else {
copy_file(file1, file2);
}
}
I also tried to add pathname after "./a" but still not working
Sorry that I am pretty new to c language
Take a look at the first few lines of main.
int main(int ac, char *av[]) {
if (ac != 3) {
fprintf(stderr, "usage: %s source destination\n", *av);
exit(1);
}
The first argument to main, ac, is the number of arguments. You have code that prints an error message when ac is not equal to exactly three, and then it exits.
When you use
./a
The number of arguments to the program is 1, just the program itself.
It appears that your program expects a source file and a destination file to work correctly. You need to provide them in the command line.
./a file-1 file-2
where file-1 is the source file and file-2 is the destination file.
Your code wants to take 2 arguments after the “.\a” which are 2 textfile path. After adding this arguments, you can run your code without error messages.
Usage:
“.\a -filepath1 -filepath2”
Related
WHAT I HAVE TO DO
I have to find, starting from a directory, a file located in one of all directories that have as root the directory passed in input.
Something as shell command find.
INPUT/OUTPUT
Having this in input:
./myfind /home/claudio/Scrivania file.txt
I need something as this in output, absolute path and last modify date ecc:
/home/claudio/Scrivania/SistemiOperativi/file.txt Tue Mar 30 19:51:54 2021
MY CODE
It doesn't print anything.
#include <stdio.h>
#include <sys/types.h>
#include <dirent.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <time.h>
#include <stdlib.h>
#include <errno.h>
#if !defined(NAME_MAX)
#define NAME_MAX 256
#endif
void find(const char* passed_dir_name, const char* passed_file_name) {
if (chdir(passed_dir_name) == -1) {
perror("FATAL ERROR CHANGING DIRECTORY");
exit(EXIT_FAILURE);
}
DIR* current_directory;
if ((current_directory = opendir(".")) == NULL) {
perror("FATAL ERROR OPENING CURRENT WORKING DIRECTORY");
exit(EXIT_FAILURE);
}
char* buf;
if ((buf = calloc(NAME_MAX, sizeof(char))) == NULL) {
perror("FATAL ERROR ALLOCATING MEMORY");
exit(EXIT_FAILURE);
}
struct dirent* dir;
while ((dir = readdir(current_directory)) != NULL) {
struct stat statbuf;
stat(dir->d_name, &statbuf);
if (S_ISDIR(statbuf.st_mode)) {
if (strncmp(dir->d_name, ".", 1) != 0 && strncmp(dir->d_name, "..", 2) != 0) {
find(dir->d_name, passed_file_name);
}
} else {
if (strncmp(dir->d_name, passed_file_name, strlen(passed_file_name) == 0)) {
if (getcwd(buf, NAME_MAX) == NULL) {
perror("FATAL ERROR");
exit(EXIT_FAILURE);
}
fprintf(stdout, "%s/%s %s", buf, dir->d_name, ctime(&statbuf.st_mtime));
}
}
}
if (closedir(current_directory) == -1) {
perror("FATAL ERROR CLOSING CURRENT WORKING DIRECTORY");
exit(EXIT_FAILURE);
}
chdir("..");
free(buf);
}
int main(int argc, char** argv) {
if (argc != 3) {
fprintf(stderr, "ERROR: RUn as ./myfind directory\n");
exit(EXIT_FAILURE);
}
const char* dir = argv[1];
const char* file = argv[2];
struct stat statbuf;
stat(dir, &statbuf);
if(!S_ISDIR(statbuf.st_mode)) {
fprintf(stderr, "FATAL ERROR: %s IS NOT A DIRECTORY\n", dir);
exit(EXIT_FAILURE);
}
find(dir, file);
exit(EXIT_SUCCESS);
}
Your parentheses are wrong in:
if (strncmp(dir->d_name, passed_file_name, strlen(passed_file_name) == 0))
You need to write:
if (strncmp(dir->d_name, passed_file_name, strlen(passed_file_name)) == 0)
Since strncmp(x, y, 0) will always return 0, the condition is never being met.
But note that there's no point in using strncmp here at all. strncmp is only needed if you don't know that one of your entries is a null terminated string. You have a guarante that d_name is null-terminated, and if passed_file_name is not, then strlen is going to be problematic. You might as well just write strcmp(dir->d_name, passed_file_name).
I'm currently learning systems programming and came across an implementation of the Linux cp command in C. This implementation though from my understanding allows for copying the contents of one file to another file in the same directory and also copying a file into a Directory in the current directory.
How could you change this code to allow for multiple files to be copied to a directory at once (i.e "copy f1.txt f2.txt f3.txt /dirInCurrentDir")
or even ("copy d1/d2/d3/f1 d4/d5/d6/f2 d ") which would copy the 2 files to directory d. I know that the changes would have to occur in main() but how could you add to the if-else statement?
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#define BUFFERSIZE 1024
#define COPYMORE 0644
void oops(char *, char *);
int copyFiles(char *src, char *dest);
int dostat(char *filename);
int mode_isReg(struct stat info);
int main(int ac, char *av[])
{
/* checks args */
if(ac != 3)
{
fprintf(stderr, "usage: %s source destination\n", *av);
exit(1);
}
char *src = av[1];
char *dest = av[2];
if( src[0] != '/' && dest[0] != '/' )//cp1 file1.txt file2.txt
{
copyFiles(src, dest);
}
else if( src[0] != '/' && dest[0] == '/' )//cp1 file1.txt /dir
{
int i;
for(i=1; i<=strlen(dest); i++)
{
dest[(i-1)] = dest[i];
}
strcat(dest, "/");
strcat(dest, src);
copyFiles(src, dest);
}
else
{
fprintf(stderr, "usage: cp1 source destination\n");
exit(1);
}
}
int dostat(char *filename)
{
struct stat fileInfo;
//printf("Next File %s\n", filename);
if(stat(filename, &fileInfo) >=0)
if(S_ISREG(fileInfo.st_mode))
return 1;
else return 0;
return;
}
int copyFiles(char *source, char *destination)
{
int in_fd, out_fd, n_chars;
char buf[BUFFERSIZE];
/* open files */
if( (in_fd=open(source, O_RDONLY)) == -1 )
{
oops("Cannot open ", source);
}
if( (out_fd=creat(destination, COPYMORE)) == -1 )
{
oops("Cannot create ", destination);
}
/* copy files */
while( (n_chars = read(in_fd, buf, BUFFERSIZE)) > 0 )
{
if( write(out_fd, buf, n_chars) != n_chars )
{
oops("Write error to ", destination);
}
if( n_chars == -1 )
{
oops("Read error from ", source);
}
}
/* close files */
if( close(in_fd) == -1 || close(out_fd) == -1 )
{
oops("Error closing files", "");
}
return 1;
}
void oops(char *s1, char *s2)
{
fprintf(stderr, "Error: %s ", s1);
perror(s2);
exit(1);
}
You would loop through all the argument values (from av[1] to av[ac - 2]) and copy it to the destination argument, which would be av[ac - 1].
In your case, you would pass av[i] and av[ac - 1] to the copyFiles function, where i would be your loop index.
I created two programs, which will communicate via named pipe, one will be reading from it and another one will be writing to it. It works pretty fine now, except for the fact, that it opens and writes to the same fifo exactly 3 times. It's my first time with C and pipes, and I don't understand why is this writing three times. Can you see why is this writing three times?
writing.c
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <dirent.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#define BUFFSIZE 512
#define err(mess) { fprintf(stderr,"Error: %s.", mess); exit(1); }
void writing(char *s)
{
int fd;
ssize_t n;
char buf[BUFFSIZE];
printf("writing to %s\n",s);
if ( (fd = open(s, O_WRONLY)) < 0)
err("open")
while( (n = read(STDIN_FILENO, buf, sizeof buf -1) ) > 0) {
buf[n-1] = '\0';
printf("Received: %s\n", buf);
if ( write(fd, buf, n) != n) {
err("write");
}
if(strcmp(buf,"END")==0){
printf("%s","exit");
break;
}
}
close(fd);
}
char* concat(const char *s1, const char *s2)
{
char *result = malloc(strlen(s1)+strlen(s2)+1);//+1 for the zero-terminator
strcpy(result, s1);
strcat(result, s2);
return result;
}
int file_stat(char *argv){
int isfifo = 0;
struct stat sb;
printf("%s",argv);
if (stat(argv, &sb) == -1) {
perror("stat");
exit(EXIT_FAILURE);
}
printf("File type: ");
if (sb.st_mode & S_IFMT == S_IFIFO) {
printf("FIFO/pipe\n");
isfifo = 1;
}
printf("Ownership: UID=%ld GID=%ld\n",
(long) sb.st_uid, (long) sb.st_gid);
//exit(EXIT_SUCCESS);
return isfifo;
}
int main(int argc, char *argv[])
{
// READ ALL FILES IN DIRECTORY
if (argc != 2) {
fprintf(stderr, "Usage: %s /<pathname>/\n", argv[0]);
exit(EXIT_FAILURE);
}
DIR *d;
struct dirent *dir;
if ((d = opendir (argv[1])) != NULL) {
/* print all the files and directories within directory */
while ((dir = readdir (d)) != NULL) {
printf ("%s\n", dir->d_name);
char* s = concat(argv[1], dir->d_name);
if (file_stat(s) == 1) {
writing(s);
}
else {
mkfifo("fifo_x", 0666);
writing("fifo_x");
}
free(s);
}
closedir (d);
}
else {
/* could not open directory */
perror ("error: ");
return EXIT_FAILURE;
}
}
reading file is the same except for "reading" function and call to reading()
reading
void reading(char *s)
{
int fd;
ssize_t n;
char buf[BUFFSIZE];
printf("%s",s);
if ( (fd = open(s, O_RDONLY)) < 0)
err("open");
while( (n = read(fd, buf, sizeof buf - 1) ) > 0) {
buf[n-1] = '\0';
if(strcmp(buf,"END")==0){
printf("%s\n", "exit");
break;
}
buf[n-1] = '\n';
if ( write(STDOUT_FILENO, buf, n) != n) {
exit(1);
}
}
close(fd);
}
the output
/home/..File type: Ownership: UID=0 GID=0
writing to fifo_x
END
Received: END
exitola
/home/olaFile type: Ownership: UID=1001 GID=1001
writing to fifo_x
END
Received: END
exit.
/home/.File type: Ownership: UID=0 GID=0
writing to fifo_x
END
Received: END
exit
You have three files in the directory with whose pathname you called your program. All three files are not fifo's so for each you write to fifo_x.
The file names are
.
..
olaFile
Maybe you should explicitly exclude the files
.
..
which happen to be in every directory in linux and represent the current directory . and the parent directory ...
I am having a problem with the below code validating a file using regex. My file must only contain letters or numbers. My regular expression is:
#define to_find "^[a-zA-Z0-9]+$"
which is located in my main.h file. The below code is in my main.c
#include <ctype.h>
#include <errno.h>
#include <regex.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include "main.h"
int main(int argc, char * argv[])
{
int ret_val;
regex_t regex;
FILE *fp;
char line[1024];
if (regcomp(®ex, to_find, REG_EXTENDED) != 0)
{
fprintf(stderr, "Failed to compile regex '%s'\n", to_find);
return EXIT_FAILURE;
}
if (argc > 2)
{
printf("Usage: tree OR tree [filename]\n");
return EXIT_FAILURE;
}
else if (argc == 2)
{
fp = fopen(strcat(argv[1],".dat"), "r");
printf("file opened\n");
while ((fgets(line, 1024, fp)) != NULL)
{
line[strlen(line) - 1] = '\0';
if ((ret_val = regexec(®ex, line, 0, NULL, 0)) != 0);
{
printf("Error: %s\n", line);
return EXIT_FAILURE;
}
}
fclose(fp);
printf("File closed\n");
}
return 0;
}
My file I am reading is called names.dat and contains:
int
char
[
double
What is happening is it is kicking out at the very first line which it should kick out at the 3rd line. I am sure this is pretty simple to solve but it seems I have not figured it out. I would appreciate any help. Also, how do I deal with the
\n
character in the file? this file will have several lines. Thanks in advance.
You have some small errors but the one that cause the error is:
// Do you see this sweet little semicolon :P ----------------+
if ((ret_val = regexec(®ex, line, 0, NULL, 0)) != 0); // <+
{
printf("Error: %s\n", line);
return EXIT_FAILURE;
}
beside this line:
fp = fopen(strcat(argv[1],".dat"), "r");
You cannot add to argv, you need to create a new buffer to hold the data, create a buffer with PATH_MAX size add append the path to it. Here an improved version:
#include <ctype.h>
#include <errno.h>
#include <regex.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <limits.h>
#define to_find "^[a-zA-Z0-9]+$"
int main(int argc, char * argv[])
{
int ret_val;
regex_t regex;
FILE *fp;
char file[PATH_MAX];
char line[1024];
if (regcomp(®ex, to_find, REG_EXTENDED) != 0)
{
fprintf(stderr, "Failed to compile regex '%s'\n", to_find);
return EXIT_FAILURE;
}
if (argc > 2)
{
printf("Usage: tree OR tree [filename]\n");
return EXIT_FAILURE;
}
else if (argc == 2)
{
sprintf(file, "%s.dat", argv[1]);
fp = fopen(file, "r");
if( fp == NULL ) {
perror("Error");
return -1;
}
printf("file opened\n");
while (fscanf(fp, "%1023s", line) > 0)
{
if ((ret_val = regexec(®ex, line, 0, NULL, 0)) != 0)
{
printf("Not match: %s\n", line);
//return EXIT_FAILURE;
} else {
printf("Match: %s\n", line);
}
}
regfree(®ex);
fclose(fp);
printf("File closed\n");
}
return 0;
}
See the diff: http://www.diffchecker.com/8itbz5dy
test:
$ gcc -Wall sample.c
$
$ cat name.dat
int
char
[
double
$ ./a.out name
file opened
Match: int
Match: char
Not match: [
Match: double
File closed
$
I am trying to simulate linux command ls using linux api from c. Looking at the code it does make sense, but when I run it I get "stat error: No such file or directory". I have checked that opendir is working ok. I think the problem is in stat, which is returning -1 even though I think it should return 0.
What am I missing?
Thanks for your help.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <sys/stat.h>
#include <errno.h>
int main(int argc, char *argv[])
{
DIR *dirp;
struct dirent *direntp;
struct stat stat_buf;
char *str;
if (argc != 2)
{
fprintf( stderr, "Usage: %s dir_name\n", argv[0]);
exit(1);
}
if ((dirp = opendir( argv[1])) == NULL)
{
perror(argv[1]);
exit(2);
}
while ((direntp = readdir( dirp)) != NULL)
{
if (stat(direntp->d_name, &stat_buf)==-1)
{
perror("stat ERROR");
exit(3);
}
if (S_ISREG(stat_buf.st_mode)) str = "regular";
else if (S_ISDIR(stat_buf.st_mode)) str = "directory";
else str = "other";
printf("%-25s - %s\n", direntp->d_name, str);
}
closedir(dirp);
exit(0);
}
It's because you aren't stating the actual file. It's in a different directory. If you want the real filename, combine argv[1] and direntp->d_name with a '/' between them.
Also, hungarian naming is icky, even the minor bit like 'p' on the end. If you have so many variables you need to keep track of their types in their names you're doing something wrong.
Here is a revised version of your program:
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <dirent.h>
#include <sys/stat.h>
#include <errno.h>
#include <limits.h>
#include <sys/param.h>
int main(int argc, char *argv[])
{
DIR *dirp;
struct dirent *direntp;
struct stat stat_buf;
char *str;
char fullpath[MAXPATHLEN + 1];
size_t dirnamelen;
if (argc != 2)
{
fprintf( stderr, "Usage: %s dir_name\n", argv[0]);
exit(1);
}
strncpy(fullpath, argv[1], MAXPATHLEN - 1); /* account for trailing '/' */
fullpath[MAXPATHLEN - 1] = '\0';
dirnamelen = strlen(fullpath);
if (strlen(argv[1]) > dirnamelen) {
fprintf( stderr, "Directory name is too long: %s", argv[1] );
exit(2);
}
fullpath[dirnamelen++] = '/';
fullpath[dirnamelen] = '\0';
if ((dirp = opendir( argv[1])) == NULL)
{
perror(argv[1]);
exit(2);
}
while ((direntp = readdir( dirp)) != NULL)
{
fullpath[dirnamelen] = '\0';
if ((dirnamelen + strlen(direntp->d_name)) > MAXPATHLEN) {
fprintf(stderr, "File %s + directory %s is too long.", direntp->d_name, fullpath);
continue;
} else {
/* strncpy is mild overkill because the if statement has verified that
there's enough space. */
strncpy(fullpath + dirnamelen, direntp->d_name, MAXPATHLEN - dirnamelen);
fullpath[MAXPATHLEN] = '\0';
}
if (stat(fullpath, &stat_buf)==-1)
{
perror("stat ERROR");
exit(3);
}
if (S_ISREG(stat_buf.st_mode)) str = "regular";
else if (S_ISDIR(stat_buf.st_mode)) str = "directory";
else str = "other";
printf("%-25s - %s\n", direntp->d_name, str);
}
closedir(dirp);
exit(0);
}
Note that I use MAXPATHLEN (from <limits.h>) and carefully check to make sure there aren't any buffer overflows. You should do the same in your code.
Edit: Changed code to use strn family functions for added safety.
Add
#include <unistd.h>
...
chdir(argv[1]);
or call stat with the full pathname like this
...
char fullpath[MAXPATHLEN];
snprintf(fullpath, sizeof(fullpath), "%s/%s", argv[1], direntp->d_name);
if (stat(fullpath, &stat_buf) == -1)
...
Others have suggested building a full path for stat(), or using chdir(). Both those will work (although they are subject to a race condition, if the directory is renamed while you are in the middle of reading it).
An alternative, which is not subject to the race condition, and is therefore arguably more "correct", is to use fstatat(). Just replace your existing stat() call with:
fstatat(dirfd(dirp), direntp->d_name, &stat_buf, 0)
(The chdir() method can be made race-condition-free too: either by using fchdir(dirfd(dirp)) instead of chdir(), or by changing directory to argv[1] and then opening "." with opendir(). The pathname construction method can't be made race-condition-free).
Why dont you try this? Just give the path to argv[1] like this /home/sabri/Desktop/Test
int main(int argc, char *argv[])
{
struct dirent *direntp;
DIR *dirp;
if (argc != 2)
{
fprintf(stderr, "Usage: %s directory_name\n", argv[0]);
return 1;
}
if ((dirp = opendir(argv[1])) == NULL)
{
perror ("Failed to open directory");
return 1;
}
while ((direntp = readdir(dirp)) != NULL)
printf("%s\n", direntp->d_name);
while ((closedir(dirp) == -1) && (errno == EINTR)) ;
return 0;
}
If you are using on unix, then you may use the system command.
system("ls -ltr | grep -d");