I want to create file test in this path /tmp/a1/a2/a3/a4/test
But all the directories (a1..a4) doesn't exist, How can I create this file in C at Linux OS?
You can use the mkdir function from sys/stat.h to create the directories as you need them. E.g.,
mkdir("/tmp/a1",0766);
However, you should check, via stat, whether or not the directories exist already.
Once you've created the directory structure, your file can be created with
open("/tmp/a1/a2/a3/a4/test",O_WRONLY|O_CREAT);
Obviously, you need to check the return values of all of these function calls.
Below is a complete function in C that achieves what you want.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/stat.h>
#include <fcntl.h>
int create_file_with_parent_dirs (char pathname[])
{
for (char *p = pathname; (p = strchr(p ,'/')) != NULL; ++p) {
char c = p[1];
p[1] = '\0';
errno = 0;
if (mkdir(pathname, 0700) != 0 && errno != EEXIST) {
perror("mkdir");
return -1;
}
p[1] = c;
}
int fd = creat(pathname, 0600);
if (fd < 0)
perror("creat");
return fd;
}
int main (void)
{
char pathname[] = "/tmp/a1/a2/a3/a4/test";
create_file_with_parent_dirs(pathname);
}
Note that the array pointed to by pathname must be modifiable. Do not call the function with a string literal. Also beware that the file will be truncated to zero length if it already exists.
You can use this code. This program split the path and check whether the path exist or not if not create the path and create the final path as file.
#include <dirent.h>
#include <errno.h>
#include <bits/stdc++.h>
#include <iostream>
#include <sys/stat.h>
#include <sys/types.h>
#include <vector>
#include <fstream>
using namespace std;
int checkDir(char * path)
{
DIR* dir = opendir(path);
if (dir) {
/* Directory exists. */
closedir(dir);
return 0;
} else if (ENOENT == errno) {
/* Directory does not exist. */
return -1;
} else {
/* opendir() failed for some other reason. */
return -2;
}
}
int make_dir(char *path)
{
int ret = checkDir(path);
if( ret == -1)
{
if (mkdir(path, 0777) == -1)
{
cerr << "Error : " << strerror(errno) << endl;
return -1;
}
else
{
cout << "Directory created";
return 0;
}
}
return ret;
}
int main(int args, char **argv)
{
std::string strpath(argv[1]);
std::string delimeter = "/";
std::string substr1 = "";
int cnt = 0;
std::vector<string> strPaths;
std::string strbck = strpath;
for( int i = strpath.find(delimeter); i != std::string::npos; i = strpath.find(delimeter))
{
if(cnt > 0)
{
substr1 = strbck.substr(0, substr1.length() + i + 1);
strPaths.push_back(substr1);
}
strpath = strpath.substr(i +1,strpath.length());
cnt++;
}
strPaths.push_back(strbck);
std::string str;
for_each( strPaths.begin() ,strPaths.end() -1 , [](std::string str) {make_dir((char*)str.c_str());});
ofstream outfile;
std::ofstream file {strPaths[strPaths.size() -1].c_str() };
file << "hello"<< std::endl;
file.close();
return 0;
}
Related
The following is always meeting the ENOENT condition at the end. I would like to print ENODATA. What do I need to change in setxattr?
#include <sys/xattr.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
int main() {
int ret;
const char * file = "non_existent_file.txt";
const char * name = "user.test";
const char * value = "value";
ssize_t size = strlen(value);
printf("Setting Xattr\n");
ret = setxattr(file, name, value, size, XATTR_REPLACE);
if (ret == -1) {
printf("Xattr set failed: %s\n", strerror(errno));
perror("");
}
if (errno == ENODATA) {
printf("ENODATA\n");
}
if (errno == ENOENT) {
printf("ENOENT\n");
}
return 0;
}
I get “ENOENT” printed from last condition end statements
I tried adding the XATTR_REPLACE flag.
I’ve removed valid paths for the file path
Edit:
Target OS: Ubuntu/ Linux
I've been working on code that:
1. checks if "sample.txt" exist, if not ,generate a new file,
2. if file already exist, check if first line has single '0'. if not, truncate and write '0'
Below is what i've written so far. however the iszeroOrnewfile always turns into 0 so don't go into different case. Am i approaching this correctly?
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#define buf 128
int main (int argc, char** argv)
{
int fd;
char buff[buf]={0} ;
int iszeroOrnewfile=1;
int iszero=0;
if(!(argv[0]>0))
printf("insert positive integer");
fd = open("./sample.txt",O_RDWR|O_CREAT);
pread ( fd,buff,buf,0);
for (int i=0;i<buf;i++)
{
if((0 != buff[i]) || ('0' != buff[i]) )
{ iszeroOrnewfile = 0;}
if('0' == buff [i]);
{ iszero = 1;}
}
if (iszeroOrnewfile == 1 )
{
if (iszero !=1)
write(fd, "0",strlen("0"));
}
else if(iszeroOrnewfile ==0)
{
truncate ("./sample.txt" , 0);
write(fd, "0",strlen("0"));
}
}
Following code may be useful:
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#define buf 128
int main (int argc, char** argv)
{
int fd;
char buff[buf]={0} ;
int iszeroOrnewfile=1;
int iszero=0;
int isFileCreated = 0;
int len = 0;
int i;
if(!(argv[0]>0))
printf("insert positive integer");
fd = open("./sample.txt",O_RDWR);
if(fd==-1 && errno==ENOENT)
{
//File dosen't exists
isFileCreated = 1;
fd = open("./sample.txt",O_RDWR|O_CREAT);
write(fd, "0",strlen("0"));
}
else
{
len = pread ( fd,buff,buf,0);
for (i=0;i<len;i++)
{
if((0 == buff[i]) || ('0' == buff[i]) )
{
iszero = 1;
break;
}
}
if(len==-1 || iszero)
{
truncate ("./sample.txt" , 0);
write(fd, "0",strlen("0"));
}
}
return 0;
}
I'm new to stack overflow so bear with me :)
I am trying to create a custom linux shell as a project.
Right now I want to make the default output going to a file instead of console when the user uses > symbol for example ls > filename.txt
But , the program crashes and a Bad address error pops yet it writes the command output to the file.
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
typedef char* string;
int main (int argc,char** argv) {
int error = 0;
int posIn=0; int posOut=0; int appendMark=0;
string Output,Input;
while (1) {
error=0;
char progName[255];
printf("\nmysh3 > ");
if(fgets(progName,500,stdin)==NULL){return 0 ;}
char dir[1024];
string params[40];
string pch=progName;
int i=0;
while ((pch = strtok (pch," \n")) != NULL){
params[i]=pch;
if (strcmp(pch,"<")==0) { posIn = i;params[i]=NULL;i--;} // < is skipped and we put only the name of the command on the params array
if (strcmp(pch,">")==0) { posOut = i;params[i]=NULL;i--;} //output
if (strcmp(pch,">>")==0) {appendMark=1;params[i]=NULL;i--;}
i++;
pch = NULL;
}
params[i]=NULL;
if(strlen(progName)>255){
printf("The commands can't be over 255 characters\n");
return 0;
}
if (posOut) {
int out = open(params[posOut], O_CREAT|O_TRUNC|O_WRONLY, 0777);
params[posOut]=NULL;
if (out < 0) {
error = 1;
fprintf(stderr,"open error: %d [%s]\n",errno,strerror(errno));
exit(1); }
int k = dup2(out,1);
if (k<0) {
error = 1;
perror("Cannot redirect output");
}
close(out);
}
pid_t proccess1,waitpid;
int status;
proccess1 = fork();
if (proccess1<0) {perror("Out of memory"); } //Monos tropos na apotyxei h fork einai na mhn yparxei mnhmh
else if (proccess1==0) {
execvp(params[0],params);
if (!error) {perror("Unknown command");}
}
else {
waitpid=wait(&status);
if (waitpid==-1) {perror("ERROR: A NEW ZOMBIE IS BORN 3:)");return 0;}
}
}
return 0; }
I'm trying to get the size of a directory recursively but I only get segfaults. I really can't see where I'm wrong, could someone help me?
P.S. I don't need to verify if the file exist or not, this is only a try for another function I have to write.
Here's the code:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>
#include <stdlib.h>
#include <limits.h>
int main(int argc, char * argv[])
{
printf("%d\n", size(argv[1]));
return 0;
}
int is_folder(char * path)
{
struct stat path_stat;
stat(path, &path_stat);
return !(S_ISREG(path_stat.st_mode));
}
int size(char * name)
{
int dir_size = 0;
struct dirent * pDirent;
DIR * pDir = opendir(name);
while ((pDirent = readdir(pDir)) != NULL)
{
char buf[PATH_MAX + 1];
realpath(pDirent->d_name, buf);
if (is_folder(buf))
{
size(buf);
}
else
{
struct stat st;
stat(buf, &st);
int sz = st.st_size;
dir_size += sz;
}
}
return dir_size;
}
Building on your code, below is the closest I was able to reproduce what du -sk returns:
#include <stdio.h>
#include <sys/stat.h>
#include <dirent.h>
#include <limits.h>
#include <string.h>
off_t directorySize(char *directory_name)
{
off_t directory_size = 0;
DIR *pDir;
if ((pDir = opendir(directory_name)) != NULL)
{
struct dirent *pDirent;
while ((pDirent = readdir(pDir)) != NULL)
{
char buffer[PATH_MAX + 1];
strcat(strcat(strcpy(buffer, directory_name), "/"), pDirent->d_name);
struct stat file_stat;
if (stat(buffer, &file_stat) == 0)
{
directory_size += file_stat.st_blocks * S_BLKSIZE;
}
if (pDirent->d_type == DT_DIR)
{
if (strcmp(pDirent->d_name, ".") != 0 && strcmp(pDirent->d_name, "..") != 0)
{
directory_size += directorySize(buffer);
}
}
}
(void) closedir(pDir);
}
return directory_size;
}
int main(int argc, char *argv[])
{
printf("%lldKiB\n", directorySize(argv[1]) / 1024);
return 0;
}
I'm guessing the difference you're seeing is due to directories consuming a small amount of space which you need to include in your total and that file space usage is chunked so you need to count blocks, not bytes.
After one night spent on trying how to find a size that is quiet the same of the one reported by du -sh: I wrote this and it seems to work also on large directories (like the linux source that is 750MB or more).
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <dirent.h>
#include <stdlib.h>
#include <limits.h>
long folder_size(char *);
int main(int argc, char * argv[])
{
if (argc < 2)
{
exit(1);
}
printf("%ld\n", mysize(argv[1]));
return 0;
}
int not_folder(char * path)
{
struct stat path_stat;
stat(path, &path_stat);
return (S_ISREG(path_stat.st_mode));
}
long folder_size(char * name)
{
long dir_size = 0L;
struct dirent * pDirent;
DIR * pDir = opendir(name);
while ((pDirent = readdir(pDir)))
{
if (strcmp (pDirent->d_name, "..") != 0 && strcmp (pDirent->d_name, ".") != 0)
{
char buf[PATH_MAX];
strcpy(buf, name);
strcat(buf, "/");
strcat(buf, pDirent->d_name);
if (not_folder(buf))
{
struct stat st;
stat(buf, &st);
dir_size += st.st_blocks * S_BLKSIZE;
printf("%s %ld\n", buf, (long)st.st_size);
}
else
{
dir_size += folder_size(buf);
}
}
}
(void) closedir(pDir);
return dir_size;
}
I am writing small C program which will act like daemon and do something every second. I managed it to run only single instance using filelock and last thing I need to know is if it is possible to send commandline arguments to running program, something like that:
first program start:
./sampleprogram
then decide to take some action/update setting
./sampleprogram -r
it will be another rotation script for my thinkpad X41 convertible:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
/*#include <stdbool.h>*/
#define TRUE 1
#define FALSE 0
#define NIL -1
int fdlock;
int get_lock(void)
{
struct flock fl;
fl.l_type = F_WRLCK;
fl.l_whence = SEEK_SET;
fl.l_start = 0;
fl.l_len = 1;
if((fdlock = open("oneproc.lock", O_WRONLY|O_CREAT, 0666)) == -1) { return 0; }
if(fcntl(fdlock, F_SETLK, &fl) == -1) { return 0; }
return 1;
}
int main() {
if(!get_lock()) {
fputs("Process already running!\n", stderr);
return 1;
}
int tabletmode;
int autorotate = TRUE;
int prevmode = NIL;
FILE *fstate;
char state[1];
FILE *fgyrovals;
char gyroval_a[1];
while (TRUE) {
fstate = fopen("/sys/devices/platform/thinkpad_acpi/hotkey_tablet_mode", "r");
fread(state, sizeof(state[0]), 1, fstate);
/*
printf("picaa");
fflush(stdout);
*/
/*tabletmode = atoi(state[0]);*/
tabletmode = state[0] - '0';
printf("koko: %d", tabletmode);
fflush(stdout);
fclose(fstate);
if (prevmode != tabletmode) {
if (tabletmode) {
system("notify-send 'Notebook v tablet móde'");
} else {
system("notify-send 'Notebook v štandartnom režime'");
}
}
if (tabletmode) {
if (autorotate) {
fgyrovals = fopen("/sys/devices/platform/hdaps/position", "r");
fclose(fgyrovals);
}
}
prevmode = tabletmode;
sleep(1);
}
return 0;
}