Is it possible to find out if a drive path (e.g. P:/temp/foo) is local or remote?
Here ( CMD line to tell if a file/path is local or remote? ) it's shown for a cmd evaluation, but I am looking for a C++/Qt way.
Related to:
QDir::exists with mapped remote directory
How to perform Cross-Platform Asynchronous File I/O in C++
There's no way in Qt, at least up to Qt 5.5. QStorageInfo would be the closest fit, but there is no agreement about how such an API should look like (see the gigantic discussion that started in this thread; basically one risks to have Qt reporting misleading information).
So, for now, you're up to using native APIs. The aforementioned GetDriveType would be fine for Windows, but you're pretty much on your own on Linux and Mac.
you could use the GetDriveType function:
https://msdn.microsoft.com/en-us/library/windows/desktop/aa364939(v=vs.85).aspx
I recently filed a feature request about this exact question: https://bugreports.qt.io/browse/QTBUG-83321
A possible workaround emerged there. Using the following enum:
enum DeviceType {
Physical,
Other,
Unknown
};
I could reliably check a mount to be a local device or something else (possibly a net mount) using the following function on Linux, Windows and macOS:
DeviceType deviceType(const QStorageInfo &volume) const
{
#ifdef Q_OS_LINUX
if (QString::fromLatin1(volume.device()).startsWith(QLatin1String("/"))) {
return DeviceType::Physical;
} else {
return DeviceType::Other;
}
#endif
#ifdef Q_OS_WIN
if (QString::fromLatin1(volume.device()).startsWith(QLatin1String("\\\\?\\Volume"))) {
return DeviceType::Physical;
} else {
return DeviceType::Other;
}
#endif
#ifdef Q_OS_MACOS
if (! QString::fromLatin1(volume.device()).startsWith(QLatin1String("//"))) {
return DeviceType::Physical;
} else {
return DeviceType::Other;
}
#endif
return DeviceType::Unknown;
}
Related
I have loaded NTFS-3G from here: https://github.com/vitalif/ntfs-3g into a VS2017 project, wanting to read NTFS USB stick drive. And when I debugging reading process, I saw that is not reading USB drive due to:
// bootsect.c
BOOL ntfs_boot_sector_is_ntfs(NTFS_BOOT_SECTOR* b)
{
u32 i;
BOOL ret = FALSE;
ntfs_log_debug("Beginning bootsector check.\n");
ntfs_log_debug("Checking OEMid, NTFS signature.\n");
if (b->oem_id != const_cpu_to_le64(0x202020205346544eULL)) // "NTFS "
{
ntfs_log_error("NTFS signature is missing.\n"); // <-- my code is running here ...
goto not_ntfs;
}
...
...
I run it this code on Win10 64bit/VS2017. And my USB stick are valid, I have tried several USB stick (all of them NTFS).
I read that vitalif/ntfs-3g has a OS limitation: Windows XP, ... and Windows 7 file systems ... that is why I suspect the cause of my failing reading process ...
I have seek it on github for another NTFS-3G project that support Win10, I didn't found it ... is there anywhere another version of NTFS-3G library that work on Win10 ? Or, could another cause for my failing ?
Any support will be wellcome, I am struggle for this issue for days and days ...
In some rare cases (in fact on a single client's computer) code below throws an exception "library_error":
namespace ipc = boost::interprocess;
ipc::shared_memory_object m_shm;
...
bool initAsServer(size_t sharedMemSize)
{
ipc::permissions perm;
perm.set_unrestricted();
try
{
m_shm = ipc::shared_memory_object(
ipc::create_only,
CNameGenHelper::genUniqueNameUtf8().c_str(), // static std::string genUniqueNameUtf8()
ipc::read_write, perm);
}
catch(const ipc::interprocess_exception& ex)
{
logError("failed with exception \"%s\"", ex.what());
return false;
}
...
}
In log file:
[ERR] failed with exception "boost::interprocess_exception::library_error"
Boost v1.58, platform win32, vs13.
I'll be very grateful if you help me in solving this problem. Thank you in advance!
Reason of problem is events with Event ID = "6005" and source name is "EventLog" in "System" Windows log.
Event Viewer - Windows Logs - System.
If the system log does not contain at least one such event, then method boost::interprocess::winapi::get_last_bootup_time() returns false and boost::interprocess::ipcdetail::windows_bootstamp constructor throws exception.
(define BOOST_INTERPROCESS_HAS_KERNEL_BOOTTIME is used).
So it seems that it is enough to clear the "System" windows event log and any application that uses the Boost shared memory will stop working.
What a terrible logic: use the contents of the windows event log.
It seems this boost ipc implementation bug that has not yet been fixed (boost_1_61_0).
My temporary workaround for this case (w/o reboot of computer):
bool fixBoostIpcSharedMem6005issue() const
{
bool result = false;
HANDLE hEventLog = ::RegisterEventSourceA(NULL, "EventLog");
if(hEventLog)
{
const char* msg = "simple boost shared memory fix for 6005";
if(::ReportEventA(hEventLog, EVENTLOG_INFORMATION_TYPE, 0, 6005, NULL, 1, 0, &msg, NULL))
result = true;
::DeregisterEventSource(hEventLog);
}
return result;
}
Use it and try to use ipc::shared_memory_object again :)
Many detailed explanations about by the problem, by one of the authors of the library: Boost interprocess: Getting boot-up time is unreliable on Windows and here: Interprocess get_last_bootup_time use of Event Log on Windows is completely unreliable
Apparently, a reliable solution is to define the preprocessor constant BOOST_INTERPROCESS_SHARED_DIR_PATH to a function call, which always returns the same directory path as a string, once the machine is booted. For example by formatting the update time-stamp of a file, written to at start-up.
You can #define BOOST_INTERPROCESS_BOOTSTAMP_IS_SESSION_MANAGER_BASED or BOOST_INTERPROCESS_BOOTSTAMP_IS_LASTBOOTUPTIME to switch to either registry or WMI based boot time detection.
Alternatively, you can use BOOST_INTERPROCESS_SHARED_DIR_PATH, but it's kind of useless on Windows since it uses hardcoded path. BOOST_INTERPROCESS_SHARED_DIR_FUNC is much better option since it lets you define a function that returns path to the shared directory.
I am writing a small class which can create/remove/rename/search for files and directories on the PC.
I successfully wrote the class and run on Linux.
When I was trying to run the same Class Code in MinGW, it was giving an error.
I could narrow down to:
mkdir function in Linux, Cygwin has 2 Arguments (directory name , mode permissions)
but in MinGW has only one argument(directory name).
My query is : a) What is the best way to make the code work on both OSs. b) Though I never used, I heard Preprocessor directives can be put like #ifdefined .....#endif ..or some thing of that sort c) Is using Preprocessor directives a good programming practice. As I learnt, preprocessor directives should be used minimally.
Could some one help me in this:
Here is my Code which works on Linux and Cygwin:
#include "BioDatabase.h"
#include <dirent.h>
#include <sys/stat.h>
#include <stdio.h>
#include <unistd.h>
BioDatabase::BioDatabase() {
string s = getcwd(NULL,0);
changeDirectory(s,"*");
}
BioDatabase::BioDatabase(string directoryName, string extension)
{
changeDirectory(directoryName, extension);
}
bool BioDatabase::createDirectory(string st)
{
if( mkdir(st.c_str(),0755) == -1)
{
cerr <<endl<<"BOSERR-BioDatabase, createDirectory: Path or file function not found or Permission denied\n\n";
return false;
}
flag =1;
return true;
}
You could code something like
#if _POSIX_C_SOURCE
if( mkdir(st.c_str()) == -1)
#else
if ((mkdir(st.c_str(),0755) == -1)
#endif
See also feature_test_macros(7) man page.
1) you can use pre-processors to do one thing on one platform, and something different on another. EG:
#ifdef mingw32
/* windows specific code, like mkdir()... */
#else
/* other platform code, like a different way to call mkdir() */
#endif
2) Yes, you're absolutely right: limit using them as much as you can. but you'll quickly find out you can't avoid them entirely.
3) The best thing to do is to use a script that checks for
functionality rather than do it on a per-operating system basis.
Typically this involves writing a configure script (or
similar), which is a whole other learning curve. Still, it lets
you port to new platforms by checking for functionality rather than
adding the platform to a long list.
I want to implement faster directory search.
Is there any algorithm in c/c++ is available for that ?
Check boost::filesystem library on http://www.boost.org/doc/libs/1_47_0/libs/filesystem/v3/doc/index.htm, there you have a recursive_directory_iterator class.
There isn't a C++ thing per se, but usually directory search is slow because of IO, and because you must stat each file (or whatever the OS equivalent is non-unix systems) to find out anything besides its name. One way to make this faster would be to keep write a server that keeps the inodes and filenames in memory. Of course the difficulty is that the inode information is not static. You would need to listen to file system changes to keep your cache up to date. That is definitely possible in linux, but I have no experience with it on other systems. As you can see, another theme of this problem is that it is very system and possibly filesystem dependent. Maybe a system-independent library like Boost::Filesystem can help, but I doubt it implements directory update callbacks.
Maybe just install Google Desktop?
Here's a windows solution (http://ideone.com/5dFVf)
class file_iterator : std::iterator<std::output_iterator_tag, const WIN32_FIND_DATA> {
HANDLE handle;
WIN32_FIND_DATA fdata;
public:
file_iterator() :handle(NULL) {
#ifdef _DEBUG
memset(&fdata, 0, sizeof(fdata);
#endif //_DEBUG
}
file_iterator(const std::wstring& path) :handle(FindFirstFile(path.c_str(), &fdata)) {}
file_iterator(file_iterator&& b) :handle(b.handle) {b.handle = NULL;}
file_iterator& operator=(file_iterator&& b) {close(); handle = b.handle; b.handle = NULL;}
void close() {
if (handle)
FindClose(handle);
#ifdef _DEBUG
memset(&fdata, 0, sizeof(fdata);
#endif //_DEBUG
}
const WIN32_FIND_DATA& operator*() {return fdata;}
file_iterator& operator++() {if (FindNextFile(handle , &fdata)==false) close(); return *this;}
bool operator==(const file_iterator& b) {return handle == b.handle;}
bool operator!=(const file_iterator& b) {return handle != b.handle;}
};
std::vector<std::wstring>
find_files_with_extension(
const std::wstring& folder,
const std::wstring& extension,
std::vector<std::wstring>* result=NULL)
{
std::wstring filepath = folder + L"/*";
std::vector<std::wstring> local_result;
std::deque<std::wstring> todo;
if (result == NULL)
result = &local_result;
file_iterator iter(filepath);
while(iter != file_iterator()) {
std::wstring folder_file((*iter).cFileName);
if ((*iter).dwFileAttributes | FILE_ATTRIBUTE_DIRECTORY)
todo.push_back(folder_file);
else if (folder_file.size() > extension.size() && folder_file.substr(folder_file.size()-extension.size())==extension)
result->push_back(folder_file);
++iter;
}
for(int i=0; i<todo.size(); ++i)
find_files_with_extension(todo[i], extension, result);
return *result;
}
This uses a breadth-first search, which takes a little more RAM and is slightly more complicated, but faster due to caching.
Searching is an OS feature these days, and those who are trying to implement third party indexing are giving up. Even Google Desktop is not being updated and most consider it dead:
https://superuser.com/questions/194082/is-google-desktop-search-a-dead-project
If you install a search server on someone's computer and get caught hogging disk and CPU--and you do not have a very, VERY good reason for doing so--you will not only waste a lot of time writing code and patching bugs but you will also alienate your users.
For most cross-platform apps, letting the users find the files in the Explorer/Finder/Nautilus and then making your app accept multi-file drag and drops is a better answer. Also, most "common dialogs" for opening files provide built in search functionality now.
If you're trying to write a search-accelerated tool for a specific platform, hook into that platform's API, which may even permit you to supplement its index. Here's Microsoft's Programmatic Search API:
http://msdn.microsoft.com/en-us/library/windows/desktop/bb266517(v=vs.85).aspx
OS/X has the spotlight API:
http://developer.apple.com/library/mac/#documentation/Carbon/Conceptual/SpotlightQuery/SpotlightQuery.html
I'm not quite sure if there's "canon" for search in the Linux world, but most all of the relevant versions of Ubuntu now ship with Tracker:
http://live.gnome.org/Tracker/Documentation
Using C++ on the Linux desktop, what is the best way to get the icon, the document description and the application "associated" with an arbitrary file/file path?
I'd like to use the most "canonical" way to find icons, mime-type/file type descriptions and associated applications on both KDE and gnome and I'd like to avoid any "shelling out" to the command line and "low-level" routines as well as avoiding re-inventing the wheel myself (no parsing the mime-types file and such).
Edits and Notes:
Hey, I originally asked this question about the QT file info object and the answer that "there is no clear answer" seems to be correct as far as it goes. BUT this is such a screwed-up situation that I am opening the question looking for more information.
I don't care about QT in particular any more, I'm just looking for the most cannonical way to find the mime type via C++/c function calls on both KDE and gnome (especially Gnome, since that's where things confuse me most). I want to be able show icons and descriptions matching Nautilus in Gnome and Konquerer/whatever on KDE as well as opening files appropriately, etc.
I suppose it's OK that I get this separately for KDE and Gnome. The big question is what's the most common/best/cannonical way to get all this information for the Linux desktop? Gnome documentation is especially opaque. gnome-vsf has mime routines but it's deprecated and I can't find a mime routine for GIO/GFS, gnome-vsf's replacement. There's a vague implication that one should use the open desktop applications but which one to use is obscure. And where does libmagic and xdg fit in?
Pointers to an essay summarizing the issues gladly accepted. Again, I know the three line answer is "no such animal" but I'm looking for the long answer.
Here is an example of using GLib/GIO to get the information you want.
#include <gio/gio.h>
#include <stdio.h>
int
main (int argc, char **argv)
{
g_thread_init (NULL);
g_type_init ();
if (argc < 2)
return -1;
GError *error;
GFile *file = g_file_new_for_path (argv[1]);
GFileInfo *file_info = g_file_query_info (file,
"standard::*",
0,
NULL,
&error);
const char *content_type = g_file_info_get_content_type (file_info);
char *desc = g_content_type_get_description (content_type);
GAppInfo *app_info = g_app_info_get_default_for_type (
content_type,
FALSE);
/* you'd have to use g_loadable_icon_load to get the actual icon */
GIcon *icon = g_file_info_get_icon (file_info);
printf ("File: %s\nDescription: %s\nDefault Application: %s\n",
argv[1],
desc,
g_app_info_get_executable (app_info));
return 0;
}
You can use the tools available from xdg for that, in particular xdg-mime query.
To find out the filetype of e.g. a file index.html you would
$ xdg-mime query filetype index.html
This will return the mimetype. To query what application is associated with that mimetye use e.g.
$ xdg-mime query default text/html
This returns epiphany.desktop here, i.e. $APPNAME.desktop, so it is easy to get the application name from it. If you would just want to open the file in the default app you could of course just run
$ xdg-open index.html
which would fire up epiphany.
Query functions for icon resources do not seem to be available in xdg-utils, but you could write a small python script using pyxdg that offers tons of additional functionality, too.
For C bindings you will probably need to have a look into the portland code linked on the xdg page.
EDIT:
Concerning libmagic and friends, you will need to decide on your preferences: While libmagic seems to be more complete (and accurate) in terms of coverage for filetypes, it does not care at all about default applications or icons. It also does not provide you with tools to install extra mimetypes.
In Qt >= 4.6, there is a new function for X11 systems
QIcon QIcon::fromTheme ( const QString & name, const QIcon & fallback = QIcon() ) [static]
You can use this function. Documentation here / (Qt 5)
Neither QFileIconProvider nor QFileInfo will do anything with the OS mime database. To access icons associated with different mime types, you will have to use functions of the underlying desktop environment. In Qt there is (yet) no canonical way.
Consider you can have a different icon in Gnome, in KDE and in Windows. So for instance, in KDE you would use KMimeType.
I just found KFileItem. This class gives you everything you for icons, mime types and related things in KDE. I'm sure that there's an equivalent in gnome but this gives access at the same level as a QT application works.
You may want to use the system's "/etc/mime.types" file. It is also a good idea to maintain your program's copy of a MIME type file. That way, you are not dependent on the system, but at the same time you need to keep it fairly exhaustive. Not sure about Icons.
Maybe take a look at this code:
http://ftp.devil-linux.org/pub/devel/sources/1.2/file-4.23.tar.gz
This is the standard file util found on most Linux/Unix distributions. You will get the MIME-type and some more information.
I think both Gnome and KDE have their own ways to determine this and also to set the icon and the standard application for it.
Anyway, that file-tool is probably the best way to get the mime type and the document description. And in some cases even some details about the content.
This will get you the mime-type. That is what you need anyway to know how you can open the file. These are seperated steps. file doesn't say you about the icon nor the application to open the file with.
About 8 years late, but still useful.
To get the associated applications in KDE you can do what Joe suggested (using KFileItem). However, that requires inclusion of a lot of libraries.
The code below requires less.
#include <QCoreApplication>
#include <QMimeDatabase>
#include <QDebug>
#include <KMimeTypeTrader>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
if (argc < 2)
{
qDebug() << "missing argument <filename>";
return 1;
}
QMimeDatabase mimeDb;
QMimeType mimeType = mimeDb.mimeTypeForFile(QString::fromLocal8Bit(argv[1]));
KService::List services = KMimeTypeTrader::self()->query(
mimeType.name(),QStringLiteral("Application"));
foreach(const QExplicitlySharedDataPointer<KService>& svc, services)
{
qDebug() << "service: " << svc->name();
qDebug() << "exec: " << svc->exec();
}
}
To compile the code add QT += KService KCoreAddons to your qmake .pro file.
Links to KMimeTypeTrader & KService documentation:
https://api.kde.org/frameworks/kservice/html/classKService.html
https://api.kde.org/frameworks/kservice/html/classKMimeTypeTrader.html
Copy/Paste of the nice example above (using GLib/Gio) just added proper release of allocated memory as per documentation. I tried to just edit the existing answer but it kept saying the edit queue was full :(
#include <gio/gio.h>
#include <stdio.h>
int
main (int argc, char **argv)
{
g_thread_init (NULL);
g_type_init ();
if (argc < 2)
return -1;
g_autoptr(GError) error;
GFile* file = g_file_new_for_path (argv[1]);
GFileInfo* file_info = g_file_query_info (file,
"standard::*",
G_FILE_QUERY_INFO_NONE,
NULL,
&error);
const char* content_type = g_file_info_get_content_type (file_info);
g_autofree gchar* desc = g_content_type_get_description (content_type);
GAppInfo* app_info = g_app_info_get_default_for_type (
content_type,
FALSE);
/* you'd have to use g_loadable_icon_load to get the actual icon */
GIcon* icon = g_file_info_get_icon (file_info);
printf ("File: %s\nDescription: %s\nDefault Application: %s\n",
argv[1],
desc,
g_app_info_get_executable (app_info));
g_object_unref(file_info);
g_object_unref(file);
return 0;
}