open file folder in the directory - c++

I want my C++ application to implement "open File Folder" functionality like in that firefox and download manager. This is the code that I've come up with.
int File::openTempFile(std::string temp_file_dir)
{
std::string file_path = temp_file_dir + "/" ;
file_path = file_path + this->additional_info ;
// if there is already an temporary file then delete it//
if( temporary_file != "" )
{
// :TODO: open temporary file stack //
// so when the application dinit we could remove those //
// remove(temporary_file.c_str() );
}
/* write temporary file */
FILE* fp = fopen (file_path.c_str(), "w");
if( fp== NULL)
return FALSE;
fwrite( m_data, 1, m_size, fp);
fclose(fp);
// now open it using natulus //
char * parmList[] = {strdup("nautilus"),strdup(file_path.c_str() )} ;
int pid;
if(( pid= fork() ) == -1)
perror("fork failed");
if( pid ==0 ){
int a = execvp("nautilus" , parmList);
printf("exevp failed to load the temporary file");
}
temporary_file = file_path ;
return TRUE;
}
But Instead of a one nautilus window , it open 3 windows.Any idea what is the reason for that ?And how could I get nautilus "open with" dialog just instead of showing it on the directory ?

When opening a folder, I use the xdg-open command which opens the specified folder with the preferred file manager for a given desktop environment.
On my system when I'm running KDE, it calls dolphin to display the folder, and xfce4, it invokes thunar, as these are the preferred file managers as per my settings. I often don't want nautilus to be used, as the interface differs from my preferred apps, doesn't look consistent with the other applications - in terms of widgets, style, etc. - and won't group the same in my taskbar.
It also uses separate preferences for my default open-with settings, and conflicts with my workflow.
Additionally, nautilus isn't necessarily guaranteed to be on my system.
For example, on some of my older systems, where I've emerged a custom gentoo system where I'm either constrained by RAM or HDD space, I've only emerged say twm and xfce4, so nautilus doesn't exist.
As far as the nautilus-specific behaviour is concerned, I have had similar problems with nautilus creates a desktop on initial invokation (as is the case when I am running twm).
Invoking nautilus --help shows the following options:
Application Options:
-c, --check Perform a quick set of self-check tests.
--version Show the version of the program.
-g, --geometry=GEOMETRY Create the initial window with the given geometry.
-w, --new-window Always open a new window for browsing specified URIs
-n, --no-default-window Only create windows for explicitly specified URIs.
--no-desktop Never manage the desktop (ignore the GSettings preference).
--force-desktop Always manage the desktop (ignore the GSettings preference).
-q, --quit Quit Nautilus.
-s, --select Select specified URI in parent folder.
--display=DISPLAY X display to use
Unfortunately, I can't help you specifically invoke the nautilus "open with..." dialog, although xdg-open will use the default application when a file is specified. Perhaps polling configurations within the mimeapps.list file (which can be in one of several cascading override locations: including, but not limited to, user-desktop, user, sysadmin-desktop, sysadmin, default-desktop, and default).

Related

Only if VisualStudio made folder is used, log file remains empty. Low level io used

This is the situation ... Simple util class for assuring the log file presence. A constructor does _sopen_s and stores the file descriptor obtained. Here is the relevant line:
...
// inside a constructor receiving a file_name
errno_t rez = _sopen_s(&file_descriptor, file_name, O_WRONLY | O_APPEND | O_CREAT, _SH_DENYNO, _S_IREAD | _S_IWRITE);
// using `fstat()` for checks here
// all is fine, exit the constructor
...
Obviously this is WINLAND and _sopen_s() is what is required. And admittedly, that "never" fails. Now there is this single method, in the same class:
FILE* file_ptr(const char* options_ = "w") const noexcept
{
_ASSERTE(file_descriptor_ > -1);
static FILE* file_ = _fdopen(file_descriptor_, options_);
_ASSERTE(file_ != nullptr);
_ASSERTE(0 == ferror( file_));
return file_;
}
That also, I have never seen fail. Calers uses that file pointer wherever else, as the first argument to fprintf. For log file writing and such. All of which blissfully and peacefully "just works".
Until. You are using as the log file name the application base name with ".log" suffix added.
Example: ".\myprog.exe.log" . You hit F5, VS churns out all the output required for debugging in the 'Debug' folder and you focus on whatever you need to debug.
But that log file, ~\Debug\myprog.exe.log remains empty after myprog.exe has finished. No exceptions and no errors being caught...
And ... if you decide your log file should be e.g. "d:/whatever.log", it remains nicely packed with the fprintf() output using the mechanism, as described above.
I assume there are some "special" permissions required to write into that file located inside those visual studio made build folders.
But no error is made and the whole mechanism works if file pointer is for the file located anywhere outside of those folders ...
Why is fprintf quietly not producing any output into these local log files, located in visual studio generated folders? Any idea anyone?
ps: yes all four x86 debug/release and x64 debug/release folders I have checked.
if the log files are in there, they are created and no errors are reported but they remain empty.
The machine is WIN10 PRO fully updated. Visual Studio 2019 and CL are also fully updated. SDK is the latest.

Correctly creating and running a win32 service with file I/O

I've written a very simple service application based on this code example.
The application as part of its normal running assumes there exists a file in the directory it is found, or in its execution path.
When I 'install' the service and then subsequently 'start' the service from the service manager in control panel. The application fails because it can't find the file to open and read from (even though the file is in the same directory as the installed executable).
My question is when a windows service is run, which is the expected running path supposed to be?
When calling 'CreateService' there only seems to be a path parameter for the binary, not for execution. Is there someway to indicate where the binary should be executed from?
I've tried this on windows vista and windows 7. Getting the same issues.
Since Windows services are run from a different context than normal user-mode applications, it's best if you don't make any assumptions about working directories or relative paths. Aside from differences in working directories, a service could run using a completely different set of permissions, etc.
Using an absolute path to the file that your service needs should avoid this problem entirely. Absolute paths will be interpreted the same regardless of the working directory, so this should make the working directory of your service irrelevant. There are several ways to go about this:
Hard-code the absolute path - This is perhaps the easiest way to avoid the problem, however it's also the least flexible. This method is probably fine for basic development and testing work, but you probably want something a bit more sophisticated before other people start using your program.
Store the absolute path in an environment variable - This gives you an extra layer of flexibility since the path can now be set to any arbitrary value and changed as needed. Since a service can run as a different user with a different set of environment variables, there are still some gotchas with this approach.
Store an absolute path in the registry - This is probably the most fool-proof method. Retrieving the path from the registry will give you the same result for all user accounts, plus this is relatively easy to set up at install time.
By default, the current directory for your Windows service is the System32 folder.
A promising solution is creating an environment variable that keeps the full path of your input location and retrieving the path from this variable at runtime.
If you use the same path as binary, you could just read binary path and modify it accordingly. But this is rather quick-fix rather than designed-solution. If I were you, I would either create system-wide environment variable and store value there, or (even better) use windows registry to store service configuration.
Note:
You will need to add Yourself some privileges using AdjustTokenPrivileges function, you can see an example here in ModifyPrivilege function.
Also be sure to use HKEY_LOCAL_MACHINE and not HKEY_CURRENT_USER. Services ar running under different user account so it's HKCU's will be different than what you can see in your registry editor.
Today I solved this problem as it was needed for some software I was developing.
As people above have said; you can hardcode the directory to a specific file - but that would mean whatever config files are needed to load would have to be placed there.
For me, this service was being installed on > 50,000 computers.
We designed it to load from directory in which the service executable is running from.
Now, this is easy enough to set up and achieve as a non-system process (I did most of my testing as a non-system process). But the thing is that the system wrapper that you used (and I used as well) uses Unicode formatting (and depends on it) so traditional ways of doing it doesn't work as well.
Commented parts of the code should explain this. There are some redundancies, I know, but I just wanted a working version when I wrote this.
Fortunately, you can just use GetModuleFileNameA to process it in ASCII format
The code I used is:
char buffer[MAX_PATH]; // create buffer
DWORD size = GetModuleFileNameA(NULL, buffer, MAX_PATH); // Get file path in ASCII
std::string configLoc; // make string
for (int i = 0; i < strlen(buffer); i++) // iterate through characters of buffer
{
if (buffer[i] == '\\') // if buffer has a '\' in it, replace with doubles
{
configLoc = configLoc + "\\\\"; // doubles needed for parsing. 4 = 2(str)
}
else
{
configLoc = configLoc + buffer[i]; // else just add char as normal
}
}
// Complete location
configLoc = configLoc.substr(0, configLoc.length() - 17); //cut the .exe off the end
//(change this to fit needs)
configLoc += "\\\\login.cfg"; // add config file to end of string
From here on, you can simple parse configLoc into a new ifsteam - and then process the contents.
Use this function to adjust the working directory of the service to be the same as the working directory of the exe it's running.
void AdjustCurrentWorkingDir() {
TCHAR szBuff[1024];
DWORD dwRet = 0;
dwRet = GetModuleFileName(NULL, szBuff, 1024); //gets path of exe
if (dwRet != 0 && GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
*(_tcsrchr(szBuff, '\\') + 1) = 0; //get parent directory of exe
if (SetCurrentDirectory(szBuff) == 0) {
//Error
}
}
}

change linux socket file permissions

First, yes this is related to this stack overflow question, but I'm having a slightly different set of circumstances and my post there is not getting an answer.
So, on my Dell desktop workstation, Ubuntu 10.04 32 bit, I have developed a server program that is designed to offer a Unix-Domain socket to a PHP "program" run by Apache. (note: umask = 0022) I named the socket file /home/wmiller/ACT/web_socket_file. (ACT is a reference to the product name). /home/wmiller/ACT has permissions of 777. /home/wmiller/ACT/web_socket_file gets created with permissions of 777.
Now, I copy the program to my test platform, a Q7 format Intel processor board, which also has Ubuntu 10.04 32 bit and umask = 0022. Same directories, same 777 permission on the dir. However, now when i run the code /home/wmiller/ACT/web_socket_file comes up with 755 permissions and Apache/PHP can't open the Unix Domain socket because it gets r-x permissions instead of rw- or rwx. Apache is running in uid = www-data.
sockaddr_un webServAddr;
remove( g_webSocketFileName.c_str() ); // to erase any lingering file from last time
memset(&webServAddr, 0, sizeof(webServAddr));
webServAddr.sun_family = AF_UNIX;
snprintf( webServAddr.sun_path, UNIX_PATH_MAX, "%s", g_webSocketFileName.c_str() );
if (( g_webServerSock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0 )
{
PLOG( ERROR ) << "Failed to acquire the web Server socket: "; // uses google glog tool
return -1;
}
So I tried both of these and neither worked.
chmod( g_webSocketFileName.c_str(), S_IRWXU | S_IRWXG | S_IRWXO );
and
char temp[100];
sprintf( temp , "chmod o+w %s\n", g_webSocketFileName.c_str() );
system( temp );
Tried permissions of 777 and o+w.
I even tried adding a
unlink( g_webSocketFileName.c_str() );
But no help there.
Anyone have suggestions on why ir works on one machine and not on another almost identical machine?
Would I be better off to put the socket file elsewhere? Is there a standard place-where-socket-files-go?
On Linux, you need to call fchmod() on the Unix domain socket file descriptor before bind(). In this way the bind() call will create the filesystem object with the specified permissions. Calling fchmod() on an already bound socket is not effective.
Using chmod() could lead to TOCTTOU race condition. If possible, use fchmod() instead.
This is a Linux-specific hack. On most BSD systems, fchmod() will fail on a socket fd and set EINVAL.
Edit. I found this system-dependent behavior difference by tinkering. Perhaps the best "source" for this should be the kernel source code itself.
On FreeBSD, it appears that fchmod() on a Unix domain socket is defined as a no-op that sets EINVAL (Ref1)
On Linux, it appears that a Unix domain socket fd is created just like an inode, along with file modes (but with S_IFSOCK bitwise-or'ed in). (Ref2) Linux's fchmod() implementation will then happily apply changes to such an object. When binding a Unix domain socket to an address, the file modes are used in creating the filesystem-object. (Ref3) According to man 2 stat, S_IFSOCK is present in POSIX.1-2001.
If I read the sources wrong, please feel free to correct me.
As Cong Ma said, under Linux you should look at using fchmod() before the bind(). However, the umask() is still going to be applied. So the correct sequence goes like this:
// create the socket
int s = socket();
// restrict permissions
#ifdef __linux__
fchmod(s, S_IRUSR | S_IWUSR);
#endif
// bind the socket now
bind(s, &u, sizeof(u));
// finally, fix the permissions to your liking
chmod(u.sun_path, 0666); // <- change 0666 to what your permissions
Important Note: the code here does not show the error handling which is required to make sure things work as expected. See complete example here.
What is the problem with fchmod()?
If you try to set the exact mode that you need in fchmod(), the file gets created by bind() and at that point the umask gets applied. That means with a umask such as 022, you still do not get the write permissions for the group and other users (i.e. you would get 0644 instead of 0666).
One way to use fchmod() and skip on the chmod() after the bind() is to change umask with:
umask(0);
bind(...);
However, if like many of us you are running in a multithreaded application, changing the umask is probably not an option. The solution above works without having to use umask(0) which long term is a better way of doing things.

How to remove the file which has opened handles?

PROBLEM HISTORY:
Now I use Windows Media Player SDK 9 to play AVI files in my desktop application. It works well on Windows XP but when I try to run it on Windows 7 I caught an error - I can not remove AVI file immediately after playback. The problem is that there are opened file handles exist. On Windows XP I have 2 opened file handles during the playing file and they are closed after closing of playback window but on Windows 7 I have already 4 opened handles during the playing file and 2 of them remain after the closing of playback window. They are become free only after closing the application.
QUESTION:
How can I solve this problem? How to remove the file which has opened handles? May be exists something like "force deletion"?
The problem is that you're not the only one getting handles to your file. Other processes and services are also able to open the file. So deleting it isn't possible until they release their handles. You can rename the file while those handles are open. You can copy the file while those handles are open. Not sure if you can move the file to another container, however?
Other processes & services esp. including antivirus, indexing, etc.
Here's a function I wrote to accomplish "Immediate Delete" under Windows:
bool DeleteFileNow(const wchar_t * filename)
{
// don't do anything if the file doesn't exist!
if (!PathFileExistsW(filename))
return false;
// determine the path in which to store the temp filename
wchar_t path[MAX_PATH];
wcscpy_s(path, filename);
PathRemoveFileSpecW(path);
// generate a guaranteed to be unique temporary filename to house the pending delete
wchar_t tempname[MAX_PATH];
if (!GetTempFileNameW(path, L".xX", 0, tempname))
return false;
// move the real file to the dummy filename
if (!MoveFileExW(filename, tempname, MOVEFILE_REPLACE_EXISTING))
{
// clean up the temp file
DeleteFileW(tempname);
return false;
}
// queue the deletion (the OS will delete it when all handles (ours or other processes) close)
return DeleteFileW(tempname) != FALSE;
}
Technically you can delete a locked file by using MoveFileEx and passing in MOVEFILE_DELAY_UNTIL_REBOOT. When the lpNewFileName parameter is NULL, the Move turns into a delete and can delete a locked file. However, this is intended for installers and, among other issues, requires administrator privileges.
Have you checked which application is still using the avi file?
you can do this by using handle.exe. You can try deleting/moving the file after closing the process(es) that is/are using that file.
The alternative solution would be to use unlocker appliation (its free).
One of the above two method should fix your problem.
Have you already tried to ask WMP to release the handles instead? (IWMPCore::close seems to do that)

How to find if an document can be OPENed via ShellExecute?

I want to check if a particular file can be successfully "OPEN"ed via ShellExecute, so I'm attempting to use AssocQueryString to discover this.
Example:
DWORD size = 1024;
TCHAR buff[1024]; // fixed size as dirty hack for testing
int err = AssocQueryString(0, ASSOCSTR_EXECUTABLE, ".mxf", NULL ,buff , &size);
openAction->Enabled = ((err == S_OK) || (err == S_FALSE)) && (size > 0);
Now, this almost works. If there's a registered application, I get the string.
But, there's a catch: On Vista, even if there is no registered application, It returns that the app c:\Windows\System32\shell32.dll is associated, which is the thing that brings up the 100% useless "Windows cannot open this file: Use the Web service to find the correct program?" dialog.
Obviously I want to hide that peice of cr*p from end users, but simply comparing the returned string to a constant seems like an ugly, brute-force and fragile way of doing it.
Also, hacking the registry to totally disable this dialog isn't a great idea.
What's a better option?
I always use FindExecutable() to get the registered application for a given document.
There is another way to do this, using the ASSOCF_INIT_IGNOREUNKNOWN option flag with AssocQueryString().
int err = AssocQueryString(ASSOCF_INIT_IGNOREUNKNOWN, ASSOCSTR_EXECUTABLE, ".mxf", NULL ,buff , &size);
This has a couple of important advantages over using FindExecutable()
It can work with just the file extension, while FindExecutable needs a full path to an existing file of the specified type.
Because it's not accessing the file, it's much faster with Samba and other network storage. Calling FindExecutable() on one file in a directory containing ~3000 files via Samba took > 1 second in my tests.