1

I thought converting a mapped drive letter to a UNC path would be enough to be able to open a .GDB file, but alas:

function ConvertToUNCPath(AMappedDrive: string) : string;
var
   lRemoteString : array[0..255] of char;
   lpRemote      : PChar;
   lStringLen    : Cardinal;
begin
   lpRemote := @lRemoteString;
   lStringLen := 255;
   If WNetGetConnection(Pchar(ExtractFileDrive(AMappedDrive)) ,
                        lpRemote,
                        lStringLen) = NO_ERROR Then
      Result := lRemoteString
   else
      Result := ''; // No mapping found
end;

function TDataModuleData.OpenGDBDatabase(AGDBName: string) : Boolean;
var
   lDlgLogin: TFrmLogin;
   p        : Integer;
   lUNC,
   lErrMsg  : String;
begin
   Result := False;

   with FDConnection do   // TFDConnection
   begin
      Close;
      TxOptions.Isolation := xiDirtyRead;

      p := Pos(':',AGDBName);
      if p = 2 then
      begin
         lUNC := ConvertToUNCPath(Copy(AGDBName,1,2));
         if lUNC <> '' then
         begin
            lUNC := Copy(lUNC,3);
            p := pos('\',lUNC);
            AGDBName := Copy(lUNC,p) + Copy(AGDBName,3);
            lUNC := copy(lUNC,1,p-1);
         end;
      end;

      DriverName := S_FD_IBId;
      Params.Database := AGDBName;
      if lUNC <> '' then
         Params.Add('Server=' + lUNC)
      else   
         Params.Add('Server=localhost');  // Not strictly necessary

      Params.UserName := 'SYSDBA';
      Params.Password := 'masterkey';

      try
         Open;
         Result := Connected;
      except
         on E:Exception do
         begin
            lErrMsg := LowerCase(E.Message);
         end;
      end;
   end;
end;

Depending on how I parse the ConvertToUNCPath result I get different error messages:

[firedac][phys][ib]unavailable database
[firedac][phys][ib]i/o error during "createfile (open)" operation for file "persoonlijk\jan\klanten.gdb"'#$D#$A'error while trying to open file'#$D#$A'the system cannot find the path specified.

The part of the code using ConvertToUNCPath succesfully converts e.g. P:\Jan\KLANTEN.GDB to \\tt2012server\persoonlijk\Jan\KLANTEN.GDB.

How can I open a GDB file when the path points to a mapped drive letter?

Added: I tried these hardcoded variations, they all fail:

// lUNC := '\\2012server';  // Unable to complete network request to host
lUNC := 'tt2012server';
//AGDBName := '\\tt2012server\persoonlijk\jan\klanten.gdb';
//AGDBName := 'tt2012server\persoonlijk\jan\klanten.gdb';
//AGDBName := '\persoonlijk\jan\klanten.gdb';
//AGDBName := 'persoonlijk\jan\klanten.gdb';
//AGDBName := '\jan\klanten.gdb';
//AGDBName := 'jan\klanten.gdb';
//AGDBName := 'p:\jan\klanten.gdb'; (original input)

(P: maps to \\tt2012server\persoonlijk)

Added:

Sorry, I was not clear in my initial text: this is not about connecting to a database on a remote server per se. I just want my local 'DB inspection' tool to be able to open a GDB file if someone places it in my network share for inspection (instead of having to copy it to local disk first).
To only intention of using WNetGetConnection was to resolve drive letter to UNC path (some I code I found on the web).

Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
Jan Doggen
  • 8,799
  • 13
  • 70
  • 144
  • 1
    Contrary to what you think, you're not actually using a network share (which wouldn't work anyway with default config). You are using a WNET connection string with an invalid path. See [Connection strings](https://www.firebirdsql.org/file/documentation/reference_manuals/user_manuals/html/qsg3-databases.html#qsg3-databases-connstrings) in the Firebird 3 quickstart guide (under _NetBEUI connection strings_). – Mark Rotteveel Mar 02 '18 at 14:41

1 Answers1

3

1. Firebird explicitly denies attempts to open database files on non-local disks

Firebird is database server, and as such it focuses on performance and reliability.

http://www.firebirdfaq.org/faq46/

Performance means lots of data is cached, both cached for reading and cached for writing.

Reliability means Firebird has to gain worthy warrants from OS that:

a. no other process would tinker with the database file while the server has some data from it cached for reading.

b. at any moment in time the server might wish to write any data to the file from its cache and it is warranted that that data - at any moment in time - ends persistently written to the persistent media.

Network-connected disks nullify both warranties and consequently Firebird Server refuses to trust them.

You may hack Firebird configuration or source files on your own discretion to remove this safety check and open network-shared files, if you really need this more than safety and speed.

But proper solution would be installing Firebird server on the machine whose disks do carry the database file.

2. Connection String is not a database file name

AGDBName := '\\tt2012server\persoonlijk\jan\klanten.gdb'

This does NOT mean "local Firebird server should connect to tt2012server server using LOCAL_SYSTEM credentials and read the database file from persoonlijk shared resource", as you probably intended it to mean.

http://www.firebirdfaq.org/faq260/

If anything, Windows LOCAL_SYSTEM user is explicitly barred from most network operations to contain intruders and viruses. Even if you hack Firebird into opening network files, most probably Windows would prohibit this access anyway, unless you would setup your Windows to run Firebird Server service with some user account other than the default LOCAL_SYSTEM.

Anyway, what \\tt2012server\persoonlijk\jan\klanten.gdb Connection String actually means is that you request your application to connect to tt2012server using WNET (aka Microsoft Named Pipes) protocol and find Firebird server running on that server and communicating by WNET protocol, as opposed to TCP/IP protocol.

Judging by the error you quote - lUNC := '\\2012server'; // Unable to complete network request to host - the said tt2012server computer perhaps does not have a Firebird Server running and accepting Named Pipes connections.

The WNET protocol is considered obsoleted and would most probably be removed from the future Firebird Server versions. As of now it is working, but few people use it, thus little up to date experience exists in that area. It is suggested you would use TCP/IP protocol by default to connect your application to the Firebird Server running on the tt2012server machine, not WNET protocol.

PS. This question has duplicates:

PPS. Firebird is a multi-generation database engine.

Consequently, there is no "dirty read" transactions possible in Interbase/Yaffil/Firebird family.

TxOptions.Isolation := xiDirtyRead; - this line would not work. Most probably it would silently change the transaction class to "READ COMMITTED", less probably it would give an explicit error.

Arioch 'The
  • 15,799
  • 35
  • 62
  • Thanks. You are correct about tt2012server not running FireBird, that was not the intention at all (and as such the questions you point to are not duplicates). The only thing I wanted is that my local 'Database browser' tool was able to (also) open a .GDB file that was on a share instead of local disk. We share a file that way if e.g. a helpdesk employee wants a developer to look at a client DB: *I placed the file on your share* – Jan Doggen Mar 02 '18 at 15:37
  • 1
    @JanDoggen And that is not possible with the default config: it is a great way to corrupt databases if accessed concurrently from multiple machines. You can enable it (setting `RemoteFileOpenAbility = 1`), you will need a Firebird server (or Firebird embedded) on your local machine to be able to do this. And of course you need to use a connection string that is not interpreted as a WNET connection string. – Mark Rotteveel Mar 03 '18 at 09:18
  • @MarkRotteveel I am not sure, but I think i heard only embedded would appreciate this parameter. But anyway, it is emergency mode and not to be used in normal workflow. – Arioch 'The Mar 05 '18 at 07:46
  • @JanDoggen they are duplicates as they both are about opening database file from remote folder, they use different tools (not Delphi but Python and C), but the essence of the problem is the same: opening non-local database file. Granted, they do not throw the primary problem into your face, that is why you did not found them. And that is why I made this answer as explicit as possible. So, hopefully no 4th duplicate would be created in the future. – Arioch 'The Mar 05 '18 at 07:53
  • "my local 'Database browser' tool" - make share on your local machine for them, or copy the file. Also, you probably can use emergency generic tools like DBExplorer module from IBExpert, or some of IB-Aid suite. Those would be just generic tools of course without knowledge of your business project specifics. Last thing, I understand that WinXP is but dead, still using GDB file extensions... Mmmeh... – Arioch 'The Mar 05 '18 at 07:54