What is the easiest way to create a temporary file from C program in Linux?
We can either call system function and use mktemp
system("TMPFILENAME=$(mktemp tmp.XXXXXXXX)");
or we can use function
mkstemp function or we can use tmpfile of tmpnam functions.
Don't do this. You should be using the mkstemp function. Here's an example that prints the name of the file like you want along with other information:
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
int main(void)
{
// buffer to hold the temporary file name
char nameBuff[32];
// buffer to hold data to be written/read to/from temporary file
char buffer[24];
int filedes = -1,count=0;
// memset the buffers to 0
memset(nameBuff,0,sizeof(nameBuff));
memset(buffer,0,sizeof(buffer));
// Copy the relevant information in the buffers
strncpy(nameBuff,"/tmp/myTmpFile-XXXXXX",21);
strncpy(buffer,"Hello World",11);
errno = 0;
// Create the temporary file, this function will replace the 'X's
filedes = mkstemp(nameBuff);
// Call unlink so that whenever the file is closed or the program exits
// the temporary file is deleted
unlink(nameBuff);
if(filedes<1)
{
printf("\n Creation of temp file failed with error [%s]\n",strerror(errno));
return 1;
}
else
{
printf("\n Temporary file [%s] created\n", nameBuff);
}
}
For a reference of the function look here.
Related
I am trying to delete a file in c program. Assume that the file is located in current directory of source file. I have searched a lot but didn't get any solution. Everyone is suggesting to use remove() function.
Here is my source code:
#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE *fp;
int delete_status;
char del[50];
printf("Enter a file name to delete it: ");
gets(del);
delete_status = remove(del);
if(delete_status!=0) {
printf("File can not be deleted!\nFile does not exist in current directory\n");
}
else printf("File %s has been deleted successfully!\n", del);
return 0;
}
Is there any way to remove file without using remove() function. I want to code manually without using any other stl built in function.
You can replace remove() with unlink() (for files) and rmdir() (for directories).
You can check this answer. You should try to read a system programming book where you can learn about uses like INTERNAL_SYSCALL.
You can skim through the functions referred in the posts like unlink() etc.
EDIT: actually somehow you will end up using a system-call at some level. You probably trying to achieve the operation of deleting a file from different abstraction level.(remove() system call will also use INTERNAL_SYSCALL which nothing but a system call).
Now from low level deleting a file doesn't mean we are erasing something. We are just considering the space as free space(free pool of memory) and then any metadata related to that file is also freed. To achieve that you need to implement a filesystem that allocates memory,deletes it..using device level instructions.
Call unlink for files, rmdir for directories. You could easily check which a file is using stat and then call the correct function.
struct stat sb;
if (!stat(filename, &sb))
{
if (S_ISDIR(sb.st_mode))
rmdir(filename);
else
unlink(filename);
}
Include <sys/stat.h> for stat and S_ISDIR, <unistd.h> for rmdir and unlink.
Oh, and per your comment:
All of you didn't understand my needs and requirement. I know that it is posible to delete a file using standard library function like remove(), unlink(), rm() etc. But I want to code manually without using any built in function.
Have fun reproducing unlink's source code.
I think what you need to know is unlink() function. For deleting files, remove() internally calls unlink() itself. Check the man page for details.
However, first I suggest you to change the gets() with fgets(). Also, int main() should be int main(void).
One can use fork and exec to run the rm command over shell.
sample code:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(){
int status;
pid_t pid = fork();
if(-1 == pid){
printf("fork() failed");
exit(EXIT_FAILURE);
}else if(pid == 0){
execl("/bin/sh", "sh", "-c", "rm /tmp/sandeep_reve.txt", (char *) NULL);
}else{
printf("Fork with id %ld\n",(long)pid);
waitpid(pid,&status,0);
}
return 0;
}
Use system():
PART I:(Delete file)
#include <stdio.h>
#include <string.h>
int main()
{
FILE *fp;
int delete_status;
char path[100],order[]="del ";//del for delete file, if change del to rd is delete folder(**Code at part 2)
printf("Enter a path of file to delete it: ");
gets(path);
strcat(order,path);//Order
fp = fopen(path,"r");
if(fp != NULL){//Check file whether or not exist
fclose(fp);
system(order);//Del file
printf("Delete successfully");
}else{
perror("ERROR");
fclose(fp);
}
return 0;
}
For example, you want to delete 1.txt.Then, you may put the c program in the same file and then intput 1.txt or enter whole path of the file.(e.g C:\User\desktop\1.txt)
PART II :(Delete folder)
#include <stdio.h>
#include <string.h>
int main()
{
FILE *fp;
int delete_status,i = 1;
char path[100],order[] = "rd ";//del -> rd
printf("Enter a path of file to delete it: ");
gets(path);
strcat(order,path);
system(order);
return 0;
}
Im trying to use the md5sum command in a C program, right now im using dirent.h to get all the files in a folder, now, I want to get all the md5 of all those files, I am doing this:
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <syslog.h>
#include <string.h>
#include <dirent.h>
int main(void){
char *word = ".gz";
int i=0;
char *word2 = ".";
char *word3 = "..";
unsigned int md5;
DIR *d;
struct dirent *dir;
d = opendir(".");
if (d) {
while ((dir = readdir(d)) != NULL)
{
if((strstr(dir->d_name, word) == NULL) && (strcmp(dir->d_name, word2) != 0) && (strcmp(dir->d_name, word3)!= 0)) {
md5 = system("md5sum dir->d_name");
printf("The md5 of %s is %d\n", dir->d_name, md5);
}
}
}
return(0);
}
but when I run it, it says, for example:
md5sum: dir-: No such file or directory
The md5 of ej1_signal.c is 256
md5sum: dir-: No such file or directory
The md5 of pipeL.c is 256
Could you please explain me why is this happening? Thanks !
The system function doesn't returns you what you think. system is used to launch a command and when that command finished, it (generally) exits with an exit code. This is the value you catched.
What you need is the output of the command not its return value. So what you need is popen which lets you launch some external command and read/write to it through a pipe. See http://pubs.opengroup.org/onlinepubs/009695399/functions/popen.html for example.
system does not return the output of a command. To get the output of a command, you need to create a process and tie the standard output stream to a file descriptor you can read data off in the other process. For an example on how to do that, you can refer to the pipe man page (section 2).
Another option is to use a library that provides an MD5 implementation (eg. OpenSSL). The man page of EVP_DigestInit (section 3) provides an example for that.
Another problem is that your code tries to calculate the digest of d->d_name, not the file which name is in d->d_name. You could use sprintf or strncat with a suitably sized buffer (ie. the length of the static string part md5sum plus the maximum size of the file name (usually 256 bytes, may vary between library implementations and file systems) plus another byte for safely terminating the string (as some implementations may report an unterminated string in d->d_name)). Please note that this does not apply if you use a library for digest calculation, as the library uses either the file name or you need to pass the file contents to a library function (eg. EVP_DigestUpdate).
The first problem is that you launch a new shell process executing "md5sum dir->d_name", meaning it does a md5 on the "file" named dir->d_name, instead of using the value you get from readdir.
So you could add a temp variable, and prepare the command in it prior to running system.
limits.h is for Linux, adjust it if necessary to get the max length of a path
...
#include <linux/limits.h>
char temp[PATH_MAX];
then instead of
md5 = system("md5sum dir->d_name");
add
strcpy(temp, "md5sum ");
strcat(temp, dir->d_name);
system(temp);
as for the other problem (system will not return the md5 string), this will display the md5 of the file in the directory. And you can just remove the printf ...
There is no command in C to return the output of an external command, but there exists popen you can just open a command as a FILE * and read the output from it. This is how you can do it, and it's all explained within the code
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
int main(void)
{
DIR *d;
struct dirent *dir;
d = opendir(".");
if (d == NULL)
return -1;
while ((dir = readdir(d)) != NULL)
{
char command[sizeof dir->d_name + 10];
struct stat st;
FILE *pipe;
if (stat(dir->d_name, &st) == -1)
continue;
/* check if the entry is a directory, md5sum does not work with them */
if (S_ISDIR(st.st_mode) != 0)
continue;
/*
* md5sum dir->d_name will pass `dir->d_name` as the argument to the md5sum command,
* we need to build the command string, I like snprintf in this case
*/
snprintf(command, sizeof command, "md5sum \"%s\"", dir->d_name);
/*
* Open the pipe, it will execute the new command in a new process (fork)
* and create a pipe for communication with the current porcess
*/
pipe = popen(command, "r");
if (pipe != NULL)
{
char md5[33];
/* read the md5 digest string from the command output */
fread(md5, 1, sizeof md5 - 1, pipe);
/* append a null terminator */
md5[sizeof md5 - 1] = '\0';
printf("The md5 of %s is %s\n", dir->d_name, md5);
}
/* close the pipe */
pclose(pipe);
}
/* you should always call closedir() if opendir() succeded */
closedir(d);
return 0;
}
I am trying to open the utmp file in Linux and read the contents into an array of utmp structures. After that I display the ut_user and ut_type from each structure in the array. I have this working when I open the file with File *file and use the fopen() and fread() functions but when I try to do the same task with just a file descriptor int file and the open() and read() functions I get address locations when trying to access members of the utmp structure.
So in the below program you can see I commented out three lines of code which together I could use to successfully perform the task of reading the utmp file into an array of utmp structures and print out two of their members values. But when I try doing the exact same thing with the three lines of code (denoted "new way") in place of the old way that worked I get a bunch of address locations rather than the values of ut_user and ut_id.
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <utmp.h>
void utmpprint(struct utmp *log) {
printf("\n ut_user: %s \n ut_type: %ld \n", log->ut_user, log->ut_type);
}
int main() {
int logsize = 10;
//FILE *file; //Working way
int file; //New way
struct utmp log[logsize];
int i = 0;
//file = fopen("/var/run/utmp", "rb"); //Working way
file = open("/var/run/utmp", O_RDONLY); //New way
if( file < 0 ) { //New way
printf("Failed to open");
return(0);
}
if (file) {
//fread(&log, sizeof(struct utmp), logsize, file); //Working way
read(file, &log, logsize); //New way
for(i = 0; i < logsize; i++) {
utmpprint(&log[i]);
}
close(file); //New way
} else {
return(0);
}
return(0);
}
Here is some of the output for the working way:
And here is the output for the new way that is not working:
I have tried looking online for more information on this matter but I can't seem to find anything that uses the file descriptor and not File. I also tried changing around some of the pointers and references but that did not improve any of the results.
I am very new to C and I think I am probably using the read() function incorrectly in this case because I am passing a simple buffer into the read function when I think I should be somehow passing it the utmp structure array.
You are not reading enough data from the file.
read(file, &log, logsize);
should be:
read(file, &log, sizeof(log));
// or
read(file, &log, logsize * sizeof (struct utmp));
Also, in both cases, you should check the return value to see how many bytes were actually read.
Even though you could manipulate data from the utmp file by using the open() system call or functions derived from open(), it is impractical.
You could include the "utmp.h" header in your project and use predefined functions and data structures.
Here you can find the utmp.h file documentation.
Below is some code to print the ut_user and ut_type using the utmp.h data structures and functions.
#include <utmp.h>
#include <stdio.h>
#include <string.h>
int main()
{
struct utmp* data;
char aux[50];
data = getutent();
//getutent() populates the data structure with information
while(data != NULL )
{
/*make sure to use strncpy
*because most data fiels in the utmp struct
*have ___nonstring___ atribute */
strncpy(aux, data->ut_user, 32);
aux[32] = '\0';
printf("ut_user: %s\n", aux);
printf("ut_type: %hi\n\n", data->ut_type);
data = getutent();
}
return 0;
}
The output of the code is:
ut_user: reboot
ut_type: 2
ut_user: alc
ut_type: 7
ut_user: runlevel
ut_type: 1
I am writing a program which should do multiple things including prompting the user for the name of the input file which I have done, but I am having troubling implementing a process where the program processes each line from a file, storing it as a struct data structure, finally using the malloc, calloc commands it will store all the valid records in memory to be validated. So any help on how to do this would be helpful.
#include <stdio.h> //library including standard input and output functions
#include <stdlib.h> //library including exit and system functions used below
#include <string.h> //library including string functions used
struct packet{
int source;
int destination;
int type; // Varibles for the structure
int port;
char data[50];
char * filename;
};
int main ()
{
printf("**************Details*******************************\n");
printf("*****Student name: ***********************\n");
printf("*****Course name: *******\n");
printf("*****Student ID: ************************ \n");
printf("\n");
// The program must prompt for the name of the input file. If it doesn't exist the program should stop with an error message
FILE *DataFile;
char filename[10] = { '\0' } ;
char DataLine[70];
printf("Enter the filename you wish to open\n");
scanf("%s", &filename);
if (( DataFile = fopen(filename, "r")) == NULL)
{
printf ("*****file could not be opened. : %s\n", filename);
exit(1);
}
// Read the data from this file
char *fgets(DataLine, 70, (FILE) *DataFile);
system("pause");
return 0;
}
Here is the text file the program should take the data from
0001:0002:0003:0021:CLS
0001:0010:0003:0021:CLS
0001:0002:0002:0080:<HTML>
0005:0002:0002:8080:<BR>
0005:0012:0002:8080:<BR>
0001:0002:0002:0080:<BODY>
0005:0002:0002:8080:<B>HELLO</B><BR>
0002:0004:0002:0090:100000000000000000022
0001:0002:0003:0021:DEL
0002:0004:0002:0010:100000000000000000023
Each colon from the file shows what part of the packet structure it should be a part of, i.e. the first set of 4 numbers is the "source" then "destination and so forth.
One way to do this is :
Use fgets to read the file line by line.
For each line, use strtok to tokenize the string.
For each of the first four tokens, use strtol to convert it to an integer.
A. The line char *fgets(DataLine, 70, (FILE) *DataFile); should probably just read fgets(DataLine, 70, DataFile);
B. If you create a single variable you don't really need malloc since the compiler will allocate it, but if you are planning on creating an array of Data you will only need to call malloc once to create the whole array, something like:
struct packet* packetarr = malloc(sizeof packetarr * DESIRED_ARRAY_SIZE);
C. As downHillFromHere suggested, use strtok to get each part of the string and strtol to convert the read strings to numbers when appropriate.
I'm trying to check a directory for a file. I've done that properly. But I'm having trouble for exceptions--> when the file is not there. Here's what I am wanting to do: I 'd like to check for the file, if it exists, then exit the loop. If the file does not exist, then sleep. After sleeping for 3 seconds, check for the file again. Repeat until the file is found then return to main() and print "Hello everyone".
Currently, if the file is missing and i put the file into this directory while the program is running, it never recognizes the new file until i stop the program then start it back up. I want the program to check for the file again after sleep.
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <curl/curl.h>
#include <unistd.h>
#define MYFILE "/Users/stackoverflow/Documents/fileabc123"
int checkfile() {
FILE *pFile;
pFile = fopen(MYFILE,"r");
char file_string[40];
int repeat = 0;
while( repeat < 1) {
if (pFile!=NULL) {
fgets (file_string,36,pFile);
fclose (pFile);
printf("%s\n", file_string);
repeat = 1 ;
}
if (pFile ==NULL) {
printf("Machine cannot read system file. \n");
sleep(3);
}
}
}
int main (int argc, char ** argv) {
checkfile();
printf("Hello everyone\n");
return 0;
}
You need to put the fopen in the loop.
if ((pFile = fopen(MYFILE, "r")) != NULL) {
// read it
}
else {
printf("Failed opening");
}
The error is in the loop.
you simply aren't trying to open the file again :)
this give you 2 error:
1. if you put the file it is not seen, as the program does not try to open it
2. if the file is present, you read it, then you close it, leaving an INVALID file descriptr but that is NOT null
this mean next loop you will try to read an invalid file descriptor. It is like reading/writing value with a overflow index from an array, or from a free() pointer.
You will almost always have the right value.. until that ram is reallocated.
so:
1. you have to try to open a file, until you get a valid file descriptor.
2. close will not change pointer value. It simply can't, think about it.
if you whant to change the value of somthing, you have to give it's address. A pointer is the adress of somthing. So File* is pointing to a File, but if you want to change the address pointed by File*, you need it's address (&pFile), just like a scanf :)