How to open a file with append mode only if it exist - c++

The function fopen("file-name",a); will return a pointer to the end of the file. If the file exist it is opened, otherwise a new file is created.
Is it possible to use the append mode and open the file only if it already exist? (and return a NULL pointer otherwise).
Thanks in advance

To avoid race conditions, opening and checking for existence should be done in one system call. In POSIX this can be done with open as it will not create the file if the flag O_CREAT is not provided.
int fd;
FILE *fp = NULL;
fd = open ("file-name", O_APPEND);
if (fd >= 0) {
/* successfully opened the file, now get a FILE datastructure */
fp = fdopen (fd, "a")
}
open may fail for other reasons too. If you do not want to ignore all of them, you will have to check errno.
int fd;
FILE *fp = NULL;
do {
fd = open ("file-name", O_APPEND);
/* retry if open was interrupted by a signal */
} while (fd < 0 && errno == EINTR);
if (fd >= 0) {
/* successfully opened the file, now get a FILE datastructure */
fp = fdopen (fd, "a")
} else if (errno != ENOENT) { /* ignore if the file does not exist */
perror ("open file-name"); /* report any other error */
exit (EXIT_FAILURE)
}

First check if the file already exists. A simple code to do that might be like this:
int exists(const char *fname)
{
FILE *file;
if ((file = fopen(fname, "r")))
{
fclose(file);
return 1;
}
return 0;
}
It will return 0 if file doesn't exist...
and use it like this:
if(exists("somefile")){file=fopen("somefile","a");}

Related

WinPcap creating empty .pcap file

Do you know how to create empty file pcap with winpcap dll? I buffer filtered packets in program memory and want to save when user click to export to .pcap file.
But when using pcap_open_offline(const char *fname, char *errbuf) can open file only if file exists. I tried fopen and other functions to create file previously (in binary mode too) but unsucessfully.
So how to get pcap_t handle pointer for pcap_dump_open(pcap_t *p, const char *fname) this way?
UPDATED:
I try to use this code
fileHandle = pcap_open_offline(pcap_file_path.c_str(), errbuf);
if (errbuf == nullptr) {
fprintf(stderr, "\nUnable to open the file %s.\n", pcap_file_path.c_str());
return 1;
}
if (fileHandle == nullptr) {
fprintf(stderr, "\nError to open file\n");//HERE IT FAILS
return 1;
}
dumpfile = pcap_dump_open(fileHandle, pcap_file_path.c_str());
if (dumpfile == NULL)
{
fprintf(stderr, "\nError opening output file\n");
return 1;
}
SOLUTION: (Creating a pcap file)
/*create fake handle*/
fileHandle = pcap_open_dead(DLT_EN10MB, 65535);
if (fileHandle == nullptr) {
fprintf(stderr, "\nError to open file\n");
return 1;
}
/* Open the dump file */
dumpfile = pcap_dump_open(fileHandle, file_path.c_str());
if (dumpfile == NULL)
{
fprintf(stderr, "\nError opening output file\n");
return 1;
}
Do you know how to create empty file pcap with winpcap dll? I buffer filtered packets in program memory and want to save when user click to export to .pcap file.
...
So how to get pcap_t handle pointer for pcap_dump_open(pcap_t *p, const char *fname) this way?
pcap_dump_open() returns a pcap_dumper_t * handle for use when writing the file; a pcap_t * is used for capturing or reading, not writing.
What you need to do, if you want to write a pcap file, is use pcap_dump_open(). If you have a pcap_t * from which you're reading or capturing the filtered packets, you should use that pcap_t * in the call to pcap_dump_open().

Check unsupported file name for fopen

I'm trying to open a file to treat it later. My problem is that if my file name is not ANSI (Arabic, Hindi...) fopen_s and fopen refuse to open it and give me an Invalid argument error. I can't use CreateFile() to do that so I thought to check either my file name is supported by fopen or not(try to open it) and create a temporary file instead:
QString fileN=QString::fromWCharArray(fname);
QFileInfo file(DIRPath+"/"+fileN);
bool Supported=true;
if(file.exists()) {
QString temp;
char* Fname=(char*)malloc(260*sizeof(char));
strcpy(Fname,(QString(DIRPath+"/"+fileN).toStdString()).c_str());
FILE* Filedesc;
errno_t err=fopen_s(&Filedesc,Fname,"rb");
if(Filedesc!=NULL) {
qDebug()<<"\nfile opened ";
fclose(Filedesc);
} else if(err==22) {
qDebug()<<"\nfail to open file error 22: Invalid argument";
temp=QString(DIRPath+"/Temp"+QString::number(nb));
Supported=false;
} else qDebug()<<"\nfail to open file error"<<GetLastError()<<"errno"<<errno<<"strerrno"<<strerror(errno);
Fname=NULL;
free(Fname);
...
My question is: can anyone clarify for me the UNICODE/ANSI confusion? Am I safe so far or are there more precautions to consider? Is there a safer way to check if the given name is not ANSI?
Thank you in advance, any help will be appreciated.
EDIT 1
I tried this but in vain : CreateFile() return an INVALID_HANDLE_VALUE and GetLastError() return 0
//WCHAR fname[]=L"D:/أحدالأنشطة.txt";
char* name="D:/أحدالأنشطة.txt";
wchar_t* nameW=(wchar_t*)malloc(sizeof(wchar_t)*17);
qDebug()<<"s :"<<mbstowcs(nameW,name,17);
//QString path=QString::fromWCharArray(fname,17);
//QString path=QString::fromLatin1(name,17);
HANDLE fileHandle = CreateFile( nameW, // file to open
GENERIC_READ, // open for reading
FILE_SHARE_READ, // share for reading
NULL, // default security
OPEN_EXISTING, // existing file only
FILE_ATTRIBUTE_NORMAL, // normal file
NULL);
if (fileHandle == INVALID_HANDLE_VALUE)
{
qDebug()<<"CreateFile failed!\n"<<GetLastError();
nameW=NULL;
free(nameW);
return 2;
}else
qDebug()<<"CreateFile succeeded!\n";
int fd = _open_osfhandle((intptr_t) fileHandle, _O_RDONLY);
FILE* fstr = _fdopen(fd, "r");
QFile indirect;
if (!indirect.open(fstr, QIODevice::ReadOnly))
qDebug()<<"QFile open against file descriptor failed!\n";
else
{
qDebug()<<"QFile open against file descriptor succeeded!\n";
indirect.close();
}
// This will fail
QFile direct(path);
if (!direct.open(QIODevice::ReadOnly))
qDebug()<<"QFile open of filename directly failed!\n";
else
{
qDebug()<<"QFile open of filename directly succeeded!\n";
direct.close();
}
nameW=NULL;
free(nameW);
EDIT 2
QString fname(QFile::decodeName("D:/أحدالأنشطة.txt"));
QFile qFile(fname);
bool b=qFile.open(QIODevice::ReadOnly);
if(b)
{
FILE* filedesc = fdopen(qFile.handle(), "rb");
if(filedesc!=NULL)
{
char* nb=(char*)malloc(2*sizeof(char));
qDebug()<<"opened ";
size_t size=fread(nb,sizeof(char),2,filedesc);
fclose(filedesc);
qDebug()<<"filedesc closed size "<<size<<"nb "<<QString::fromAscii(nb,2);
nb=NULL;
free(nb);
}else qDebug()<<"filedesc failed error"<<strerror(errno);
}else
qDebug()<<"qFile failed error"<<strerror(errno);
You should probably use QFile to open the file, and then pass QFile::handle() to your C function. In the C code you would then use fdopen() to associate a FILE* stream to the file descriptor. Note that the mode you use in fdopen() should be compatible with the mode you used in QFile::open(). For example:
void c_func(int fd)
{
FILE* file = fdopen(fd, "rb");
// ...
}

Why does this write() operation just write a single line

I have a small problem with my code in the following. I call it in my class from within a state machine this->write_file(this->d_filename);. The case in the loop gets hit a couple of times, however I only have one line of entries in the CSV file I want to produce.
I'm not sure why this is. I open the file with this->open(filename) in my write function. It returns the file-descriptor. The file is opened with O_TRUNK, and if ((d_new_fp = fdopen(fd, d_is_binary ? "wba" : "w")) == NULL). While the aba refers to write, binary and append. Therefore I expect more than one line.
The fprintf statement writes my data. It also has a \n.
fprintf(d_new_fp, "%s, %d %d\n", this->d_packet, this->d_lqi, this->d_lqi_sample_count);
I simply can't figure out why my file doesn't grow.
Best,
Marius
inline bool
cogra_ieee_802_15_4_sink::open(const char *filename)
{
gruel::scoped_lock guard(d_mutex); // hold mutex for duration of this function
// we use the open system call to get access to the O_LARGEFILE flag.
int fd;
if ((fd = ::open(filename, O_WRONLY | O_CREAT | O_TRUNC | OUR_O_LARGEFILE,
0664)) < 0)
{
perror(filename);
return false;
}
if (d_new_fp)
{ // if we've already got a new one open, close it
fclose(d_new_fp);
d_new_fp = 0;
}
if ((d_new_fp = fdopen(fd, d_is_binary ? "wba" : "w")) == NULL)
{
perror(filename);
::close(fd);
}
d_updated = true;
return d_new_fp != 0;
}
inline void
cogra_ieee_802_15_4_sink::close()
{
gruel::scoped_lock guard(d_mutex); // hold mutex for duration of this function
if (d_new_fp)
{
fclose(d_new_fp);
d_new_fp = 0;
}
d_updated = true;
}
inline void
cogra_ieee_802_15_4_sink::write_file(const char* filename)
{
if (this->open(filename))
{
fprintf(d_new_fp, "%s, %d %d\n", this->d_packet, this->d_lqi,
this->d_lqi_sample_count);
if (true)
{
fprintf(stderr, "Writing file %x\n", this->d_packet);
}
}
}
Description for O_TRUNC from man open:
If the file already exists and is a regular file and the open mode allows writing (i.e., is O_RDWR or O_WRONLY) it will be truncated to length 0. If the file is a FIFO or terminal device file, the O_TRUNC flag is ignored. Otherwise the effect of O_TRUNC is unspecified.
The file is opened in each call to write_file(), removing anything that was previously written. Replace O_TRUNC with O_APPEND.

How to create a file only if it doesn't exist?

I wrote a UNIX daemon (targeting Debian, but it shouldn't matter) and I wanted to provide some way of creating a ".pid" file, (a file which contains the process identifier of the daemon).
I searched for a way of opening a file only if it doesn't exist, but couldn't find one.
Basically, I could do something like:
if (fileexists())
{
//fail...
}
else
{
//create it with fopen() or similar
}
But as it stands, this code does not perform the task in a atomic fashion, and doing so would be dangerous, because another process might create the file during my test, and the file creation.
Do you guys have any idea on how to do that?
Thank you.
P.S: Bonus point for a solution which only involves std::streams.
man 2 open:
O_EXCL Ensure that this call creates the file: if this flag is specified in conjunction with O_CREAT, and pathname already exists, then open()
will fail. The behavior of O_EXCL is undefined if O_CREAT is not specified.
so, you could call fd = open(name, O_CREAT | O_EXCL, 0644); /* Open() is atomic. (for a reason) */
UPDATE: and you should of course OR one of the O_RDONLY, O_WRONLY, or O_RDWR flags into the flags argument.
I learned about proper daemonizing here (back in the day):
http://www.enderunix.org/docs/eng/daemon.php
It is a good read. I have since improved the locking code to eliminate race conditions on platforms that allow advisory file locking with specific regions specified.
Here is a relevant snippet from a project that I was involved in:
static int zfsfuse_do_locking(int in_child)
{
/* Ignores errors since the directory might already exist */
mkdir(LOCKDIR, 0700);
if (!in_child)
{
ASSERT(lock_fd == -1);
/*
* before the fork, we create the file, truncating it, and locking the
* first byte
*/
lock_fd = creat(LOCKFILE, S_IRUSR | S_IWUSR);
if(lock_fd == -1)
return -1;
/*
* only if we /could/ lock all of the file,
* we shall lock just the first byte; this way
* we can let the daemon child process lock the
* remainder of the file after forking
*/
if (0==lockf(lock_fd, F_TEST, 0))
return lockf(lock_fd, F_TLOCK, 1);
else
return -1;
} else
{
ASSERT(lock_fd != -1);
/*
* after the fork, we instead try to lock only the region /after/ the
* first byte; the file /must/ already exist. Only in this way can we
* prevent races with locking before or after the daemonization
*/
lock_fd = open(LOCKFILE, O_WRONLY);
if(lock_fd == -1)
return -1;
ASSERT(-1 == lockf(lock_fd, F_TEST, 0)); /* assert that parent still has the lock on the first byte */
if (-1 == lseek(lock_fd, 1, SEEK_SET))
{
perror("lseek");
return -1;
}
return lockf(lock_fd, F_TLOCK, 0);
}
}
void do_daemon(const char *pidfile)
{
chdir("/");
if (pidfile) {
struct stat dummy;
if (0 == stat(pidfile, &dummy)) {
cmn_err(CE_WARN, "%s already exists; aborting.", pidfile);
exit(1);
}
}
/*
* info gleaned from the web, notably
* http://www.enderunix.org/docs/eng/daemon.php
*
* and
*
* http://sourceware.org/git/?p=glibc.git;a=blob;f=misc/daemon.c;h=7597ce9996d5fde1c4ba622e7881cf6e821a12b4;hb=HEAD
*/
{
int forkres, devnull;
if(getppid()==1)
return; /* already a daemon */
forkres=fork();
if (forkres<0)
{ /* fork error */
cmn_err(CE_WARN, "Cannot fork (%s)", strerror(errno));
exit(1);
}
if (forkres>0)
{
int i;
/* parent */
for (i=getdtablesize();i>=0;--i)
if ((lock_fd!=i) && (ioctl_fd!=i)) /* except for the lockfile and the comm socket */
close(i); /* close all descriptors */
/* allow for airtight lockfile semantics... */
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 200000; /* 0.2 seconds */
select(0, NULL, NULL, NULL, &tv);
VERIFY(0 == close(lock_fd));
lock_fd == -1;
exit(0);
}
/* child (daemon) continues */
setsid(); /* obtain a new process group */
VERIFY(0 == chdir("/")); /* change working directory */
umask(027); /* set newly created file permissions */
devnull=open("/dev/null",O_RDWR); /* handle standard I/O */
ASSERT(-1 != devnull);
dup2(devnull, 0); /* stdin */
dup2(devnull, 1); /* stdout */
dup2(devnull, 2); /* stderr */
if (devnull>2)
close(devnull);
/*
* contrary to recommendation, do _not_ ignore SIGCHLD:
* it will break exec-ing subprocesses, e.g. for kstat mount and
* (presumably) nfs sharing!
*
* this will lead to really bad performance too
*/
signal(SIGTSTP,SIG_IGN); /* ignore tty signals */
signal(SIGTTOU,SIG_IGN);
signal(SIGTTIN,SIG_IGN);
}
if (0 != zfsfuse_do_locking(1))
{
cmn_err(CE_WARN, "Unexpected locking conflict (%s: %s)", strerror(errno), LOCKFILE);
exit(1);
}
if (pidfile) {
FILE *f = fopen(pidfile, "w");
if (!f) {
cmn_err(CE_WARN, "Error opening %s.", pidfile);
exit(1);
}
if (fprintf(f, "%d\n", getpid()) < 0) {
unlink(pidfile);
exit(1);
}
if (fclose(f) != 0) {
unlink(pidfile);
exit(1);
}
}
}
See also http://gitweb.zfs-fuse.net/?p=sehe;a=blob;f=src/zfs-fuse/util.c;h=7c9816cc895db4f65b94592eebf96d05cd2c369a;hb=refs/heads/maint
The only way I can think of is to use system level locks. See this: C++ how to check if file is in use - multi-threaded multi-process system
One way to approach this problem is to open the file for appending. If the function succeeds and the position is at 0 then you can be fairly certain this is a new file. Could still be an empty file but that scenario may not be important.
FILE* pFile = fopen(theFilePath, "a+");
if (pFile && gfetpos(pFile) == 0) {
// Either file didn't previously exist or it did and was empty
} else if (pFile) {
fclose(pFile);
}
It would appear that there's no way to do it strictly using streams.
You can, instead, use open (as mentioned above by wildplasser) and if that succeeds, proceed to open the same file as a stream. Of course, if all you're writing to the file is a PID, it is unclear why you wouldn't just write it using C-style write().
O_EXCL only excludes other processes that are attempting to open the same file using O_EXCL. This, of course, means that you never have a perfect guarantee, but if the file name/location is somewhere nobody else is likely to be opening (other than folks you know are using O_EXCL) you should be OK.

stat not working

I am writing a file watcher and stat for some reason cant get a hold of file information, why?
struct stat info;
int fd = open(path, O_EVTONLY);
if (fd <= 0){
exit(-1);
}
int result = fstat(fd, &info);
if (!result){
exit(-1); //This happens! Errno says "No such file or directory" but that cant be because open would've failed
}
int result = fstat(fd, &info);
if (!result){
exit(-1);
}
Check fstat man page, on success 0 is returned.
stat returns zero on success, as do most standard libc functions.
This is designed as such, so you can easily check for errors in a chain of library calls:
if (stat(fd, &info)) {
perror("stat");
exit(1);
}
//stat succeeded.
if (...) {
}
From your usage, I assume you want fstat(). fstat() takes a fd as argument, stat() a string.