Enabling NTFS file support

Use this forum to ask questions about how to do things in QCAD.

Moderator: andrew

Forum rules

Always indicate your operating system and QCAD version.

Attach drawing files and screenshots.

Post one question per topic.

Post Reply
cjh
Active Member
Posts: 31
Joined: Tue Jul 12, 2016 4:51 pm

Enabling NTFS file support

Post by cjh » Tue Aug 09, 2016 4:18 pm

Hello!

Has anyone enabled ntfs file support in qt before?
I'm currently able to open a network file from multiple computers and edit them independently with no warning.
From what I've read, the following needs to be included for Qt to handle NTFS permissions.
extern Q_CORE_EXPORT int qt_ntfs_permission_lookup;
qt_ntfs_permission_lookup++; // turn checking on
Is there a way to translate this to ECMA?
I'm having trouble tracing where Q_CORE_EXPORT is in ECMA space.

Connor

User avatar
andrew
Site Admin
Posts: 9037
Joined: Fri Mar 30, 2007 6:07 am

Re: Enabling NTFS file support

Post by andrew » Tue Aug 09, 2016 4:40 pm

qt_ntfs_permission_lookup is not mapped to the ECMAScript interface.

cjh
Active Member
Posts: 31
Joined: Tue Jul 12, 2016 4:51 pm

Re: Enabling NTFS file support

Post by cjh » Tue Aug 09, 2016 4:51 pm

OK - would a plugin that runs the two lines of code in its init function take care of this?

Thanks for your help, Andrew.

Connor

User avatar
andrew
Site Admin
Posts: 9037
Joined: Fri Mar 30, 2007 6:07 am

Re: Enabling NTFS file support

Post by andrew » Tue Aug 09, 2016 4:56 pm

Yes, you could definitely use a plugin to run this code.

I cannot tell if this will take care of your situation as I've never felt the need to enable NTFS permission checking so far, so this might or might not make a difference.

cjh
Active Member
Posts: 31
Joined: Tue Jul 12, 2016 4:51 pm

Re: Enabling NTFS file support

Post by cjh » Tue Aug 09, 2016 5:13 pm

I'm not entirely sure if this will handle it either, but it's worth a try.
AutoCAD will alert a user that they must open a file as Read-Only if another user has the file open already.
Unfortuantely, QCAD does not.

If this simple plugin doesn't work, then I'll probably have to write my own file access service to run on the server handling the networked drive.

Hopefully that won't be necessary!
I'll keep you posted.

Connor

cjh
Active Member
Posts: 31
Joined: Tue Jul 12, 2016 4:51 pm

Re: Enabling NTFS file support

Post by cjh » Wed Aug 10, 2016 9:52 pm

Unfortunately, my plugin with these two lines only succeeded in slowing down load times.
extern Q_CORE_EXPORT int qt_ntfs_permission_lookup;
qt_ntfs_permission_lookup++; // turn checking on
I feel like this is because QCAD only reads a file and imports the data into new memory to be worked on.
I'm thinking modifying FileOpen to use QFile.open(QIODevice::ReadWrite) for the duration of editing might be necessary.

Connor

***Edit: Using QFile.open does not seem like the right idea.
I could just make a lock file similar to the autosave file when a file is first opened.
Then, when opening the file, I only need to check if that lock file exists.
I'll look into QLockFile tonight or tomorrow.

cjh
Active Member
Posts: 31
Joined: Tue Jul 12, 2016 4:51 pm

Re: Enabling NTFS file support

Post by cjh » Thu Aug 18, 2016 6:26 pm

I still need to enforce only one user having a file editable at the same time.
I'm on Windows, so I need to use the WINAPI to open a windows file handle when users open a file.
Using #include <Windows.h> in a c++ file, this accomplishes registering a file as open for read/write in Windows:
HANDLE fh = CreateFile(L"B:/QCAD/multi_user_test.dxf", // file to open
                         GENERIC_WRITE|GENERIC_READ,     // open Read/Write
                         FILE_SHARE_READ,                // allow others to read
                         NULL,                           // no security attribute
                         OPEN_EXISTING,                  //opening an existing file to edit
                         FILE_ATTRIBUTE_NORMAL,          // default
                         NULL);                          // no template file
This HANDLE needs to be open throughout the duration of editing.
A second user attempting to create the same HANDLE will fail.
I need to force that user to open the file as read only.

I'm thinking of adding IoErrorReadOnly to RDocumentInterface::IoErrorCode.
When NewFile.createMdiChild is called, I can check the IoErrorCode and go into a Read-Only Mode.

Now I need to restrict the user from editing the open document, but I haven't found a Read-Only Mode for the RDocument/RDocumentInterface yet.
Does this exist?

Connor

User avatar
andrew
Site Admin
Posts: 9037
Joined: Fri Mar 30, 2007 6:07 am

Re: Enabling NTFS file support

Post by andrew » Fri Aug 19, 2016 8:45 am

cjh wrote:Now I need to restrict the user from editing the open document, but I haven't found a Read-Only Mode for the RDocument/RDocumentInterface yet.
Does this exist?
No. QCAD only treats files (not drawings) as read-only if they are read-only on the file system level. There is no read-only setting for a drawing at this point.

cjh
Active Member
Posts: 31
Joined: Tue Jul 12, 2016 4:51 pm

Re: Enabling NTFS file support

Post by cjh » Tue Aug 23, 2016 8:22 pm

If I open a file using the Windows API call below, it should be opened as GENERIC_READ|GENERIC_WRITE, while allowing others to read it (FILE_SHARE_READ).
HANDLE fh;
    fh = CreateFile(fName.toStdWString().c_str(), \
                           GENERIC_READ | GENERIC_WRITE, \
                           FILE_SHARE_READ, \
                           NULL, \
                           OPEN_EXISTING, \
                           FILE_ATTRIBUTE_NORMAL, \
                           NULL);
    if (fh != INVALID_HANDLE_VALUE) {
        qDebug() << "Success opening Read/Write: " << fName;
        return ReadWrite;
     }
If I attempt to open the file in QCAD, I would expect it to import the file successfully.
Other programs can open the file while the handle is open.
However, I receive the following error

Code: Select all

15:12:37: Debug:    Success opening Read/Write:  "B:/QCAD/multi_user_test.dxf"
Warning:  RDwgImporter::importFile: 4: OdError:
15:12:40: Debug:    "RDwgServices::printErrorStackTrace: Can't open file: \"B:\\QCAD\\multi_user_test.dxf\""
Warning:  "Import for file B:/QCAD/multi_user_test.dxf failed"
Any ideas on how to trace this further?

User avatar
andrew
Site Admin
Posts: 9037
Joined: Fri Mar 30, 2007 6:07 am

Re: Enabling NTFS file support

Post by andrew » Wed Aug 31, 2016 10:08 am

Unfortunately, this is an error coming from the underlying Teigha libraries which are used to import / export DXF and DWG files. I've had a brief look at their forum but didn't find any similar issues.

cjh
Active Member
Posts: 31
Joined: Tue Jul 12, 2016 4:51 pm

Re: Enabling NTFS file support

Post by cjh » Wed Sep 21, 2016 9:12 pm

OK - I finally got back to working on this, had some other stuff come up!

I've made a plugin that makes the interface below available to the QScriptEngine.
A map of fileNames to QLockFile is maintained.
#include <QObject>
#include <QDebug>
#include <QLockFile>

class FileLocker : public QObject
{
Q_OBJECT
public:
    FileLocker() : QObject() {}
    ~FileLocker();

    bool lock(QString fName);
    bool unlock(QString fName);
    QString toString();
    QString lockToString(QString fName);
    QString errorToString(QLockFile* lck);
    QString convertFileNameToLockName(QString fName);
private:
    QMap<QString, QLockFile*> lockFiles;
};
Q_DECLARE_METATYPE(FileLocker*)

Using this, I can create a lock file when opening a file (example shown below).
Image


A second user attempting to open the same file will throw a READ-ONLY error.
Image

I currently have Lock/Unlock set up as actions in their own script files.
I added the LockFile Action to NewFile.postOpenActions[], and the Unlock occurs under NewFile.closeRequested.
Similar action calls are my the Save.js file to account for:
- untitled drawings being saved for the first time
- a drawing being "Saved As" a different file name

I would prefer to not edit the standard scripts - is there a better way to catch the opening/closing/renaming of files?
I'm investigating the Transaction Listeners now.

Thanks -- let me know what you think!!
Connor

User avatar
andrew
Site Admin
Posts: 9037
Joined: Fri Mar 30, 2007 6:07 am

Re: Enabling NTFS file support

Post by andrew » Mon Sep 26, 2016 9:02 am

All RImportListeners are notified before and after document imports (i.e. loading a file).

All RExportListeners are notified before and document exports (i.e. saving a file).

Files cannot be renamed from within QCAD (File > Save as... creates a new file). However, the operating system file dialog might offer the user a way to rename files. This cannot be detected by QCAD.

cjh
Active Member
Posts: 31
Joined: Tue Jul 12, 2016 4:51 pm

Re: Enabling NTFS file support

Post by cjh » Tue Sep 27, 2016 9:07 pm

I was unable to use the available Listeners to handle file locking.
I have edited the scripts as follows.
The life of an existing QCAD file:
  1. 1. Open File
    1. a. results in a NewFile.createMdiChild() call
      b. I have added a FileLocker.lockFile() call after a successful import. This shows a dialog with lock info if the file is already in use. (@Line 176 of the original NewFile.js file)
    2. Perform Edits
    3. Save the file (happens one of two ways)
    1. a. Save under the same file name.
      Abort the save if the file is not locked by the current user. (before @Line 124 of original Save.js)
      b. SaveAs under a different filename effectively closes the original file and opens a new one.
      (Note: SaveAs is differentiated from a Save by having a different fileName than the current Document.getFileName().
      Abort the save if the lock cannot be acquired for the new file name. (before @Line 124 of original Save.js)
      Unlock the original file after a successful saveAs. (@Line 145 of original Save.js)
    4. Close the file
    1. a. Unlock the file after a successful close (@Line 357 and @Line 415 in original NewFile.js)
I've attached my code if anyone's curious.
Attachments
FileLocker.zip
(12.26 KiB) Downloaded 374 times

User avatar
andrew
Site Admin
Posts: 9037
Joined: Fri Mar 30, 2007 6:07 am

Re: Enabling NTFS file support

Post by andrew » Wed Sep 28, 2016 2:07 pm

Thanks for the update.

Would this be something that could be integrated into future mainstream QCAD packages under the same license as the rest of the QCAD code (see LICENSE.TXT)?

I'd probably make some minor changes and add a preference page to make file locking optional. Let me know what you think, thanks.

cjh
Active Member
Posts: 31
Joined: Tue Jul 12, 2016 4:51 pm

Re: Enabling NTFS file support

Post by cjh » Wed Sep 28, 2016 4:56 pm

Awesome - it'd be great to have everyone use it!

The preference page was in my mind this whole time but I wasn't sure how to handle it.
My first thought is adding a preference check in FileLockerPlugin.init() before registering FileLockerPlugin to the script environment.
Then, when all of the FileLocker.js functions are called, they would abort because fLocker == null.

One necessary change - if a user has a file open as Read-Only and performs edits, Autosave file names would need a rework.
Otherwise, there will be overwrites of the same autosave file between the Lock-Owner and the Read-Only users.

I temporarily have Autosave.autoSave() cancelled with the following added @Line 118 of Autosave.js:

Code: Select all

if (!FileLocker.haveLock(document.getFileName()) {
        qDebug("Autosave not allowed due to lock");
        return;
}
This produces an issue with unsaved files (where document.getFileName === "") -- no autosave is made for them.
Currently, no lock file is made for these unsaved files - any suggestions on how to handle the autosaves?

Also: the Code notation tags are missing for javascript/c++. Is that for everyone?

Post Reply

Return to “QCAD 'How Do I' Questions”