Writing rapidjson document to a file using PrettyWriter - rapidjson

I have been unable to find a direct answer to this question. After searching for some time, I've written the following code but I'm sure that there exists a simpler way of doing the same task.
int persistJSONChanges(rapidjson::Document& fa_cloneDoc, string jsonFilePath)
{
FILE* lp_file = fopen(jsonFilePath.c_str(), "w");
rapidjson::StringBuffer buffer;
rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(buffer);
fa_cloneDoc.Accept(writer);
string temp=buffer.GetString();
unique_ptr<char[]>l_writeBuffer(new char[temp.size()]);
rapidjson::FileWriteStream l_writeStream(lp_file, l_writeBuffer.get(), temp.size());
rapidjson::PrettyWriter<rapidjson::FileWriteStream> l_writer(l_writeStream);
bool l_returnStatus=fa_cloneDoc.Accept(l_writer);
if(l_returnStatus==false)
{
cout<<endl<<"file update failed"<<endl;
return -1;
}
fclose(lp_file);
return 0;
}

I think you misused the FileWriteStream. It just needs a buffer of arbitrary size.
You simply needs:
FILE* fp = fopen(...);
char buffer[1024];
FileWriteStream fs(fp, buffer, sizeof(buffer));
PrettyWriter<FileWriteStream> writer(fs);
document.Accept(writer);
fclose(fp);

I have tried the following which worked for me:
int persistJSONChanges(rapidjson::Document& fa_cloneDoc, string jsonFilePath)
{
rapidjson::StringBuffer buffer;
rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(buffer);
bool l_returnStatus=fa_cloneDoc.Accept(writer);
if(l_returnStatus==false)
{
fprintf(stdout,"\n[%s::%d] JSON File update failed\n",__FILE__,__LINE__);
return -1;
}
string temp=buffer.GetString();
ofstream out(jsonFilePath.c_str(),std::ofstream::trunc);
out<<temp;
return 0;
}

I don't use
rapidjson::Document
This is work for me:
namespace rpj = rapidjson;
FILE* fp_r = fopen("json.json", "w" );
char buf[BUF_SIZE];
rpj::FileWriteStream os(fp_r, buf, sizeof (buf));
rpj::PrettyWriter<rpj::FileWriteStream> writer(os);
writer.StartObject();
writer.String("hello");
writer.String("world");
writer.String("arr");
writer.StartArray();
writer.Int(33);
writer.Int(34);
writer.Int(36);
writer.EndArray();
writer.EndObject();
fclose(fp_r);

Related

Why Input/Output Error occurs when use ls command in my fuse filesystem?

Why I/O Error causes when I tried ls . command in my fuse filesystem?
My filesystem has a limitation that it only allows mail address type as individual filename and it does not allows sub directory.
Now I want to display a list of file name when use ls . but it does not work.
I understood that it must implement a callback function. (Correspond function is ll_readdir in mycode)
but I have no idea what points are causes the errors.
Update:
Now I use strace command to investigate what system call raise a this error.
According to result of strace, this error caused in getdents64 syscall.
getdents64(3, 0x5611ed000540, 32768) = -1 EIO (Input/output error)
Code1 (implementation of mm:
struct mutex_map {
int counter = 2;
std::mutex _mtx;
std::unordered_map<int, std::string> _data;
std::unordered_map<std::string, int> _rev_data;
public:
int set_value(const char* value) {
std::string s = std::string(value);
std::lock_guard<std::mutex> lock(_mtx);
counter++;
_data[counter] = s;
_rev_data[s] = counter;
return counter;
}
const char* get_value(int key) { return _data[key].c_str(); }
int get_ino(const char* name) { return _rev_data[std::string(name)]; }
};
static mutex_map mm;
Code2: (sendmailfs_stat)
static int sendmailfs_stat(fuse_ino_t ino, struct stat* stbuf,
size_t name_length) {
uid_t uid = getuid();
gid_t gid = getgid();
stbuf->st_ino = ino;
if (ino == 1) {
stbuf->st_mode = S_IFDIR | 0755;
stbuf->st_nlink = 2;
stbuf->st_uid = uid;
stbuf->st_mode = S_IFDIR;
} else {
stbuf->st_mode = S_IFCHR | 0666;
stbuf->st_nlink = 1;
stbuf->st_size = name_length;
stbuf->st_uid = uid;
stbuf->st_gid = gid;
}
return 0;
}
Code 3: (implementation of readdir callback)
static void ll_readdir(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off,
struct fuse_file_info* fi) {
// printf("size_t=%ld, fh=%ld, ino=%ld\n", size, fi->fh, ino);
if (ino == 1) {
off_t o = 0;
size_t rest = size;
size_t res;
char* buf = (char*)calloc(1, size);
struct stat dotst;
sendmailfs_stat(ino, &dotst, strlen("."));
res = fuse_add_direntry(req, buf, rest, ".", &dotst, o);
rest -= res;
o++;
printf("%s\n", "start of loop");
uint64_t num_contain = 0;
for (auto& c : mm._data) {
const char* t = c.second.c_str();
int ino2 = mm.get_ino(t);
struct stat st;
sendmailfs_stat(ino2, &st, strlen(t));
fuse_entry_param e;
e.ino = ino2;
e.attr_timeout = 0;
sendmailfs_stat(ino2, &e.attr, strlen(t));
res = fuse_add_direntry_plus(req, buf, rest, t, &e, o);
o += 1;
rest -= res;
}
fuse_reply_buf(req, buf, size);
}
}
A bit late, but if anyone having this error stumbles upon this thread, they might want to check first whether the filesystem is mounted properly. The Input/output error from getdents64 is symptomatic of a filesystem that was unmounted, but failed for some reason (like a file was still in use when user tried the umount command), so still looks mounted, but no data can be fetched from it.
So in this case, some process could be calling umount (and failing) before you run ls, or the filesystem failed to correctly mount in the first place for some reason.

can we perform the operation using functions like fgets(), fputs(), feof(),etc. for the fifo file like we use for the normal file?

I have an assignment where I have to transfer the file from a client process to server process using fifo.I have tried to deal with fifo file as the other files we create in the system. It compiled without any error but it didn't execute properly.Can someone please give me an idea about the fifo file structure inside the computer system? What processes and functions are present for it ?Till now, I know how to use create(),read(),write(), open() function for fifo file.Also, I would be grateful if someone could help me to correct my program?
My client and server program are as follows:-
Client Program:-
#include<stdio.h>
#include<string.h>
#include<fcntl.h>
#include<sys/stat.h>
#include<sys/types.h>
#include<unistd.h>
int main()
{
int fd;
char *myfifo ="/tmp/myfifo";
char str[80];
FILE *fp;
char filename[20];
printf("\nEnter filename: ");
gets(filename);
mkfifo(myfifo,0666);
fp = fopen(filename,"r");
if(fp == NULL)
{
printf("\nError opening the file");
exit(1);
}
fd = open(myfifo, O_WRONLY);
while(fgets(str,80,fp)!=NULL)
{
write(fd,str,strlen(str)+1);
}
close(fd);
fclose(fp);
return 0;
}
Client Program:-
#include<stdio.h>
#include<string.h>
#include<fcntl.h>
#include<sys/stat.h>
#include<sys/types.h>
#include<unistd.h>
int main()
{
int fd1;
char *myfifo ="/tmp/myfifo";
char str1[80], filename[20];
FILE *fp1, *fp2;
fd1= open(myfifo, O_RDONLY);
fp1 = fopen(filename,"r");
fp2 = fopen(filename,"w");
while(!feof(fp1))
{
read(fd1,str1,strlen(str1)+1);
fputs(str1,fp2);
}
return 0;
}
Yes, but you have a few small problems in your programs. in the first:
write(fd, str, strlen(str)+1);
is a bit unconventional. This sends the string plus its end-of-string delimiter (\0) into the fd. One doesn't normally do this with strings, strlen(str) is probably what you want.
in the second:
fp1 = fopen(filename,"r");
fp2 = fopen(filename,"w");
filename has not been assigned a value, so both of these opens will almost certainly fail. When they do, they return a NULL pointer, so the first attempt to use them:
while(!feof(fp1))
will likely cause a segment violation. Also, you don't use fp1 anyways, so if feof(fp1) returned 1, it would always return 1. You want to base this loop on when the fifo is exhausted, which means there is no data in it, and nobody has it open for write. So changing this program around a bit yields:
#include<stdio.h>
#include<string.h>
#include<fcntl.h>
#include<sys/stat.h>
#include<sys/types.h>
#include<unistd.h>
int main()
{
int fd1;
char *myfifo ="/tmp/myfifo";
char str1[80];
ssize_t n;
fd1= open(myfifo, O_RDONLY);
while ((n=read(fd1,str1,sizeof str1)) > 0)
{
fwrite(str1, 1, n, stdout);
}
return 0;
}
While this set of changes works, it doesn't address your other question, about using stdio functions with pipes. The answer is yes, and here is another functional rewrite of your second program:
#include<stdio.h>
int main()
{
char *myfifo ="/tmp/myfifo";
FILE *fp;
int c;
if ((fp = fopen(myfifo, "r")) != NULL) {
while ((c = getc(fp)) != EOF) {
putchar(c);
}
fclose(fp);
}
return 0;
}
Also, in the first, the critical bit with stdio:
...
FILE *fi = fopen(myfifo, "a");
while(fgets(str,80,fp)!=NULL)
{
fputs(str, fi);
}
fclose(fi);
...
as in the second, the loop could have been implemented with getc, putc.
A general refinement might be functions like these:
ssize_t FCopy(FILE *in, FILE *out) {
int c;
ssize_t len = 0;
while ((c = getc(in)) != EOF) {
len++;
if (putc(c, out) != c) {
return -len;
}
}
return len;
}
ssize_t FileAppend(char *from, char *to) {
FILE *in, *out;
ssize_t n = 0;
if ((in = fopen(from, "rb")) != NULL) {
if ((out = fopen(to, "ab")) != NULL) {
n = FCopy(in, out);
fclose(out);
} else {
n = -1;
}
fclose(in);
} else {
n = -1;
}
return n;
}
so your main would look more like:
...
char filename[80];
printf("Enter a file to store the data in: ");
if (fgets(filename, sizeof filename, stdin)) {
filename[strlen(filename)-1] = '\0';
if (FileAppend(myfifo, filename) < 0) {
printf("Error: could not save data to %s\n", filename);
}
}
....

TOCTTOU code vulnerability

I have a piece of code in C, and I need to know where I have the TOCTTOU vulnerability and why. Does somebody know where it is and how I can correct it?
int process(char *filename)
{
struct stat aux;
char buffer[1024];
printf("Input to be appended: ");
fgets(buffer, sizeof(buffer), stdin);
if((lstat(filename, &aux) == 0) && !S_ISLNK(aux.st_mode))
{
printf("[+] Opening\n", filename);
int fd = open(filename, O_RDWR | O_APPEND), nb;
nb = write(fd, buffer, strlen(buffer));
printf("[+] Done!\n");
return 0;
}else
printf("[-] ERROR\n", filename);
return 1;
}
int main(int argc, char * argv[])
{
if(argc != 2){
fprintf(stderr, "usage: %s filename\n", argv[0]);
exit(1);
}
return process(argv[1]);
}
Thanks!!
The use of lstat() provides a TOCTOU vulnerability because the file may be deleted after the lstat() and before the open(). Use open() instead and test the return value is a simple solution for this.

How do I convert from wstring (that's subst'ed) to TCHAR?

I have a wstring that I assign in the following function. I pull out of the string with the .substr method with the start and length parameters. But once I do a substr, how do I get the result ultimately into a TCHAR that the function can return (and assign as one of its parameters):
TCHAR *Mid(TCHAR *dest, TCHAR *source, size_t start, size_t num)
{
wstring sSource(s);
// this line won't compile, unable to fix. How to get from subst to TCHAR?
dest = sSource.substr(start, num);
return dest;
}
Thanks!
EDIT: Perhaps this?
{
wstring wSource(source);
wstring wTemp;
wTemp = wSource.substr(start, num);
_tcscpy(dest,wTemp.c_str());
return dest;
}

Initial assignment a Char Array using a Function in C

as we know it in C, a string defining is,
char string[] = "Hello World";
That is OK,
But I want to use a function and at initial same up,
I tried those, For example;
char * to_string()
{
return "Hello World";
}
Or;
char * to_String(void) // Function
{
char buff[16];
sprintf(buff, "%s", "Hello World");
return buff;
}
main() // main function
{
char Initial_String[] = to_String();
}
How to make this or any idea same another way.
I find what I dont send address of char Initial_String[] to fill into. No. is there Another method.
Thanks.
When you compile this, atleast in GCC, it will give you the following warning:
b.c:9: warning: function returns address of local variable
Why? Because buff[] is a local variable of function to_string(). Its scope is only inside the function to_string(). main() does not have any access to this variable. Try making buff[] a global variable instead.
Second problem: char Initial_String[] = to_String(); cannot be assigned value in this way. to_string() returns a char pointer, hence assign the value thus:
char *Initial_String = to_String();
The code below will work:
char buff[16];
char* to_String(void) // Function
{
//char buff[16]; /*this is a local variable*/
sprintf(buff, "%s", "Hello World");
return buff;
}
int main(void) // main function
{
char *Initial_String = to_String();
printf("%s", Initial_String);
return 0;
}
Yes You are right about local buffer mismake,
But This is not my wanting,
if I edit some differently,
char buff[16];
char* to_String(void) // Function
{
//char buff[16]; /*this is a local variable*/
sprintf(buff, "%s", "Hello World");
return buff;
}
int main(void) // main function
{
char *Initial_String_1 = to_String();
char *Initial_String_2 = to_String();
char *Initial_String_3 = to_String();
printf("%s", Initial_String_1 );
printf("%s", Initial_String_2 );
printf("%s", Initial_String_3 );
in this case, all strings will be same, because They have same buffer address,
I want to open the topic little more.
struct
{
long aaa;
short bbb;
int ccc;
char ddd;
.
.
. // the list goes on
}elements;
typedef struct
{
int lengt;
int *adress;
char name[10];
}_list;
char* to_String(long variable) // Function
{
sprintf(buff, "%ld", variable);
return buff;
}
int main (void)
{
_list My_List[] = {
{ sizeof(elements.aaa), &elements.aaa , to_string( elements.aaa) },
{ sizeof(elements.bbb), &elements.bbb , to_string( elements.bbb) },
{ sizeof(elements.ccc), &elements.ccc , to_string( elements.ddd) },
.
.
. //// the list goes on
};
I do not know, Do I make myself clear.
Here, string must be filled into name array, without assigning it the address.
I may have syntax mistake. the code is not tested with compiler. the idea is for illustrative purposes only.
I am trying to find a method for The purpose.
Thanks.

Resources