How to open file using fstream constructor in shared mode

I have a code ( a logger) which open file (and keeps it open). The file is supposed to be shared with other application - for read and write permission.

Here is a constructor :

fstream( filename, (std::fstream::in | std::fstream::out | std::fstream::app), ios_base::_Openprot)

File is correctly opened; the program keeps it open and add message, all okay up to this point.

Problem is that the file is not fully shared with other applications. Other application can read it but cannot write to file, while the file is opened by the first application.

The sh_read, sh_write ...  are not members of filebuf anymore so it cannot be used. The only protection parameter which I was able to find is the   ios_base::_Openprot, but it does not work, too.
matoustAsked:
Who is Participating?

[Webinar] Streamline your web hosting managementRegister Today

x
 
evilrixConnect With a Mentor Senior Software Engineer (Avast)Commented:
There is no reason why you can't open the same file from two different processes from two different streams. It works just fine, although (as jkr points out) you'll need to synchronize access to the file using a cross process synchronization object (such as a mutex as pointed out by DeepuAbrahamK). Try the code below, build it and run it twice. Then try pressing enter in each process and you should find both will update the file.

Maybe you could clarify a bit more about what you are trying to achieve here as it may help us guide you to a more appropriate solution.

-Rx.
#include <cstdlib>
#include <fstream>
 
int main()
{
	std::fstream fs("c:\\temp\\test.txt", std::ios::out | std::ios::in | std::ios::app);
 
	for(;;)
	{
		system("pause");
		fs << "Hello" << std::endl;
	}
}

Open in new window

0
 
jkrConnect With a Mentor Commented:
'ios_base::_Openprot' is simply set to '_SH_DENYNO' (see xiosbase) which is used when opening the file internally. If that does not work, chance are that something more low-level is going wrong. In general, for shared access to a file I'd rather go for OS-specific methods, since STL's streams are nice, yet do not offer any atomic access to the file or any othre synchrinization, you might just mess up the logfile that way. OK, the Windows API might be less convenient to use, on the other hand ypu have control over what you are doing (http://msdn2.microsoft.com/en-us/library/aa363858.aspx - "CreateFile")
0
 
oleberConnect With a Mentor Commented:
something like
    try {
        // Get a file channel for the file
        File file = new File("filename");
        FileChannel channel = new RandomAccessFile(file, "rw").getChannel();
    
        // Use the file channel to create a lock on the file.
        // This method blocks until it can retrieve the lock.
        FileLock lock = channel.lock();
    
        // Try acquiring the lock without blocking. This method returns
        // null or throws an exception if the file is already locked.
        try {
            lock = channel.tryLock();
        } catch (OverlappingFileLockException e) {
            // File is already locked in this thread or virtual machine
        }
    
        // Release the lock
        lock.release();
    
        // Close the file
        channel.close();
    } catch (Exception e) {
    }

Open in new window

0
The new generation of project management tools

With monday.com’s project management tool, you can see what everyone on your team is working in a single glance. Its intuitive dashboards are customizable, so you can create systems that work for you.

 
Deepu AbrahamConnect With a Mentor R & D Engineering ManagerCommented:
You can use cross process syncronisation mutex which is known to all of your application which is aware of this file or writing into it:
Something very similar:
http://sendhil.spaces.live.com/blog/cns!30862CF919BD131A!375.entry

Best Regards,
DeepuAbrahamK
0
 
matoustAuthor Commented:
Thank you all, I just start to understand it. The logger daemon, which I am working on accepts messages on a UDP port and writhe them to file(s) or forward it to other servers on the network. The files are open in the same way as envilrix shows in the code example and then I use fs.write() to add the messages.

So far it works okay. But the log files are growing and there is a requirement once per a while to copy the log file to backup and empty it. This I want to do using a script (in similar way as unix systems do). Problem is that the log file is held by the logger daemon, so the script cannot do anything with it.

As the logger daemon is idle most of the time and reach the log file only if there is a message to write, I have to fine a way how to release the log file for other processes when the logger is idle  (but do not close it, as i am afraid that closing and opening the file would slow it down).
Does fstream class enable something like that?

thanks matoust
0
 
evilrixConnect With a Mentor Senior Software Engineer (Avast)Commented:
>> So far it works okay. But the log files are growing and there is a requirement once per a while to copy the log file to backup and empty it. This I want to do using a script (in similar way as unix systems do). Problem is that the log file is held by the logger daemon, so the script cannot do anything with it.

Get you code to do this, it'll be simpler! Code to copy a file can be found here.
http://www.experts-exchange.com/Programming/Languages/CPP/Q_23114203.html

Just close the file, copy it then reopen with ios::trunc to set it to 0 bytes in length.

File locking is handled by the OS, fstream doesn't really give you much control over this.
0
 
jkrConnect With a Mentor Commented:
>>As the logger daemon is idle most of the time and reach the log file only if
>>there is a message to write, I have to fine a way how to release the log file
>>for other processes when the logger is idle

Close the file then - if the daemon is only writing at sparse intervals anyway, the slowdown won't matter at all. Or even better, consider sending a message to the daemon for that purpose, indicating that you want to copy the file and it should close it for that purpuse.
0
 
matoustAuthor Commented:
I really don't want to open and close the file for each message entry. I like the example with the system("pause"). What the pause actually does? Can I get the main thread of the logger to the same status as the pause does programatically?  My logger has main thread and a "port listener" thread which runs independently on main. The listener just watch the port and pass incomming messages to memory queue.
The main thread watch the queue, fetch the message from it and process it.  I think I need to suspend the main thread in the way which release the file (as the pause does). Do you know how to do it.
0
 
jkrConnect With a Mentor Commented:
The problem is not to pause the thread, but to release the file, the 1st issue is simple. As the docs state, the file *should* be shared. If it isn't, Houston is having a problem which youn't do much about except

- closing the file explicitly
- share using the Win32 API
0
 
evilrixConnect With a Mentor Senior Software Engineer (Avast)Commented:
>> What the pause actually does?
C:\>pause
Press any key to continue . . .

>> I really don't want to open and close the file for each message entry
Just chose it when you want to copy it and then reopen it with ios::trunc to zero size it (http:#20760982)

>> Can I get the main thread of the logger to the same status as the pause does programatically?
I think you misunderstand what pause doe :)

>> I think I need to suspend the main thread in the way which release the file (as the pause does).
Pause is a DOS command, it does nothing other than wait for a key to be pressed (see above)
0
 
matoustAuthor Commented:
Share using the Win32 API sounds good to me, but I am not sure if it works. I have tried :

  HANDLE fileHandle = CreateFile(
                                fileName.c_str( ),
                                (FILE_READ_DATA | FILE_WRITE_DATA | FILE_APPEND_DATA),
                                (FILE_SHARE_READ | FILE_SHARE_WRITE),
                                NULL,
                                OPEN_ALWAYS,
                                FILE_ATTRIBUTE_NORMAL,
                                NULL);

and then write to file using

      WriteFile(   fileHandle,
                        buf,
                        sizeof(buf),
                        &len,
                        NULL);

It did not help; other application are able to read the file, but not to write (clean, copy) the file. Is there any Win32 API trick that I am missing?
0
 
jkrConnect With a Mentor Commented:
Stupid question (since the above should work): Is the script that copies the file running under a different account? This would explain the effect...
0
 
jkrConnect With a Mentor Commented:
BTW, if the latter applies, the solution would be to set a "World" security descriptor (use the SECURITY_ATTRIBUTES' struct in the following code with 'CreateFile()' on that file, e.g.


PSID                        psidWorldSid    =   NULL;
SECURITY_DESCRIPTOR         sd;
SECURITY_ATTRIBUTES         sa;
 
 
    //  Create a security descriptor for the log file that allows
    //  access from both the privileged service and the non-privileged
    //  user mode programs
 
    psidWorldSid    =   ( PSID) LocalAlloc  (   LPTR,
                                                GetSidLengthRequired    (   1)
                                            );
 
    InitializeSid   (   psidWorldSid,   &siaWorldSidAuthority,  1);
 
    *(  GetSidSubAuthority  (   psidWorldSid,   0)) =   SECURITY_WORLD_RID;
 
    InitializeSecurityDescriptor    (   &sd,    SECURITY_DESCRIPTOR_REVISION);
 
    SetSecurityDescriptorGroup      (   &sd,    psidWorldSid,   TRUE);
 
    ZeroMemory  (   &sa,    sizeof  (   SECURITY_ATTRIBUTES));
 
    sa.nLength              =   sizeof  (   SECURITY_ATTRIBUTES);
    sa.lpSecurityDescriptor =   &sd;
    sa.bInheritHandle           =   FALSE;

Open in new window

0
 
matoustAuthor Commented:
Sorry for delay. I was distracted by some other commitments.
Finay have solve it using the Win32 calls as CreatFile, WriteFile and so on. The reason why I wrongly stated that it does not work in my previous respond was that I tried the to open and modify the file using Windows notepad, whichprobably does not open the file in the share mode.
When I create file in share mode and by one application and then open it in share mode by the other, both application can read write, move pointer , delete and so on.
0
All Courses

From novice to tech pro — start learning today.