On Jan 31 14:23, Roland Mainz via Cygwin wrote:
> On Thu, Jan 30, 2025 at 2:34 PM Cedric Blancher
> <cedric.blanc...@gmail.com> wrote:
> [snip]
> > Does the ms-nfs41-client support NFS_SPECFILE_FIFO and NFS_SPECFILE_SOCK?
> 
> No, but if Cygwin implements this for the Microsoft NFSv3 client then
> I'll add support for ms-nfs41-client and ms-nfs42-client ASAP.
> 
> But I really would prefer if Cygwin would NOT use |NFS_SPECFILE_LNK|
> (all other |NFS_SPECFILE_*| would be OK), because it seems to be
> limited to |2050| bytes, while ms-nfs41-client/ms-nfs42-client doesn't
> have such a limit (currently supported are 4096 byte long paths, which
> sites like CERN&&Pasteur really use (measured by the bug reports about
> "... paths with 3280 bytes etc don't work...") ...).
> 
> Question for Corinna:
> Why did Cygwin never use
> |NFS_SPECFILE_FIFO|/|NFS_SPECFILE_SOCK|/|NFS_SPECFILE_CHR| from
> https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/ff4df658-7f27-476a-8025-4074c0121eec
> ?

Because I didn't know about it until I read your mail.

The NFS code in Cygwin is basically from 2008.  Back in those days, I
learned how to access NFS using EAs from a nice developer at Microsoft,
who worked on SFU at the time.  There was never any communication about
an additional reparse point type, and I'm pretty sure it wasn't officially
documented at the time either.

However, testing is better than talking, so I quickly hacked up an STC:

$ cat > mk-dev-nfs.c <<EOF
#include <stdio.h>
#include <windows.h>
#include <winternl.h>

typedef struct {
    DWORD  ReparseTag;
    WORD   ReparseDataLength;
    WORD   Reserved;
    struct {
        BYTE   DataBuffer[1];
    } GenericReparseBuffer;
    struct {
        ULONGLONG       Type;
        union {
          struct {
            ULONG       Major;
            ULONG       Minor;
          } Device;
          WCHAR         LnkBuffer[1];
        };
    } NfsReparseBuffer;
} MY_REPARSE_DATA_BUFFER, *MY_PREPARSE_DATA_BUFFER;

#define NFS_SPECFILE_LNK        0x00000000014B4E4CL
#define NFS_SPECFILE_CHR        0x0000000000524843L
#define NFS_SPECFILE_BLK        0x00000000004B4C42L
#define NFS_SPECFILE_FIFO       0x000000004F464946L
#define NFS_SPECFILE_SOCK       0x000000004B434F53L

int
main (int argc, char **argv)
{
  HANDLE fh;
  char buf[65536];
  DWORD size_ret;
  MY_PREPARSE_DATA_BUFFER rp;

  if (argc < 3)
    {
      fprintf (stderr, "usage: %s <name> b|c|f|s [major] [minor]\n", argv[0]);
      return 1;
    }
  fh = CreateFile (argv[1],
                   GENERIC_WRITE,
                   0,
                   NULL,
                   CREATE_ALWAYS,
                   FILE_FLAG_BACKUP_SEMANTICS
                   | FILE_FLAG_OPEN_REPARSE_POINT,
                   NULL);
  if (fh == INVALID_HANDLE_VALUE)
    {
      fprintf (stderr, "CreateFile: %d\n", GetLastError ());
      return 1;
    }

  rp = (MY_PREPARSE_DATA_BUFFER) buf;
  rp->ReparseTag = IO_REPARSE_TAG_NFS;
  rp->ReparseDataLength = sizeof (ULONGLONG);
  switch (argv[2][0])
    {
    case 'b':
    case 'c':
      if (argc != 5)
        {
          fprintf (stderr, "usage: %s <name> b|c|f|s [major] [minor]\n",
                   argv[0]);
          return 1;
        }
      rp->ReparseDataLength += 2 * sizeof (ULONG);
      rp->NfsReparseBuffer.Type = argv[2][0] == 'b' ?
                                  NFS_SPECFILE_BLK
                                  : NFS_SPECFILE_CHR;
      rp->NfsReparseBuffer.Device.Major = strtoul (argv[3], NULL, 0);
      rp->NfsReparseBuffer.Device.Minor = strtoul (argv[4], NULL, 0);
      break;
    case 'f':
      rp->NfsReparseBuffer.Type = NFS_SPECFILE_FIFO;
      break;
    case 's':
      rp->NfsReparseBuffer.Type = NFS_SPECFILE_SOCK;
      break;
    }
  rp->ReparseDataLength = sizeof (ULONGLONG) + 2 * sizeof (ULONG);
  rp->NfsReparseBuffer.Type = NFS_SPECFILE_BLK;


  if (! DeviceIoControl (fh, FSCTL_SET_REPARSE_POINT,
                         (LPVOID) buf,
                         REPARSE_GUID_DATA_BUFFER_HEADER_SIZE
                         + rp->ReparseDataLength,
                         NULL, 0, &size_ret, NULL))
    {
      fprintf (stderr, "DeviceIoControl: %d\n", GetLastError ());
      CloseHandle (fh);
      DeleteFile (argv[1]);
      return 1;
    }
  CloseHandle (fh);
  return 0;
}
EOF
$ gcc -g ../src/mk-dev-nfs.c -o mk-dev-nfs
$ pwd
/home/corinna/tests/x86_64
$ mount | grep tests
//calimero.vinschen.de/cygwin/tests on /home/corinna/tests type nfs 
(binary,user,bind)

So we're in an NFS-mounted directory, let's try to create a FIFO:

$ ./mk-dev-nfs
usage: ./mk-dev-nfs <name> b|c|f|s [major] [minor]
$ ./mk-dev-nfs fifo f
DeviceIoControl: 50
$ ll fifo
ls: cannot access 'fifo': No such file or directory
$ ./mk-dev-nfs sock s
DeviceIoControl: 50
$ ./mk-dev-nfs blk b 0 0
DeviceIoControl: 50
$ ./mk-dev-nfs chr c 0 0
DeviceIoControl: 50

So... if you tell me what I'm doing wrong, I'm all ears.


Corinna

-- 
Problem reports:      https://cygwin.com/problems.html
FAQ:                  https://cygwin.com/faq/
Documentation:        https://cygwin.com/docs.html
Unsubscribe info:     https://cygwin.com/ml/#unsubscribe-simple

Reply via email to