OSDN Git Service

Enabled Recording the special files the same way as WSL
authorJean-Pierre André <jpandre@users.sourceforge.net>
Tue, 26 Jan 2021 09:06:18 +0000 (10:06 +0100)
committerJean-Pierre André <jpandre@users.sourceforge.net>
Tue, 26 Jan 2021 09:06:18 +0000 (10:06 +0100)
Optionally record the special files (symlinks, fifos, sockets, character
and block devices) using reparse points instead of using Interix representation.
Doing so, the special files are interoperable with Windows Subsystem for
linux (WSL).

include/ntfs-3g/ea.h
include/ntfs-3g/reparse.h
include/ntfs-3g/volume.h
libntfs-3g/dir.c
libntfs-3g/ea.c
libntfs-3g/reparse.c
src/lowntfs-3g.c
src/ntfs-3g.8.in
src/ntfs-3g.c
src/ntfs-3g_common.c
src/ntfs-3g_common.h

index b96e40b..cd61fa2 100644 (file)
@@ -26,6 +26,8 @@
 
 int ntfs_ea_check_wsldev(ntfs_inode *ni, dev_t *rdevp);
 
+int ntfs_ea_set_wsl_not_symlink(ntfs_inode *ni, mode_t mode, dev_t dev);
+
 int ntfs_get_ntfs_ea(ntfs_inode *ni, char *value, size_t size);
 
 int ntfs_set_ntfs_ea(ntfs_inode *ni, const char *value, size_t size, int flags);
index 0813ad8..c617951 100644 (file)
@@ -37,6 +37,11 @@ REPARSE_POINT *ntfs_get_reparse_point(ntfs_inode *ni);
 
 int ntfs_reparse_check_wsl(ntfs_inode *ni, const REPARSE_POINT *reparse);
 
+int ntfs_reparse_set_wsl_symlink(ntfs_inode *ni,
+                       const ntfschar *target, int target_len);
+
+int ntfs_reparse_set_wsl_not_symlink(ntfs_inode *ni, mode_t mode);
+
 int ntfs_set_ntfs_reparse_data(ntfs_inode *ni, const char *value,
                        size_t size, int flags);
 int ntfs_remove_ntfs_reparse_data(ntfs_inode *ni);
index 67fc49a..30e0790 100644 (file)
@@ -98,6 +98,11 @@ typedef enum {
        NTFS_VOLUME_INSECURE            = 22
 } ntfs_volume_status;
 
+typedef enum {
+       NTFS_FILES_INTERIX,
+       NTFS_FILES_WSL,
+} ntfs_volume_special_files;
+
 /**
  * enum ntfs_volume_state_bits -
  *
@@ -256,6 +261,7 @@ struct _ntfs_volume {
        s64 free_mft_records;   /* Same for free mft records (see above) */
        BOOL efs_raw;           /* volume is mounted for raw access to
                                   efs-encrypted files */
+       ntfs_volume_special_files special_files; /* Implementation of special files */
        const char *abs_mnt_point; /* Mount point */
 #ifdef XATTR_MAPPINGS
        struct XATTRMAPPING *xattr_mapping;
index a517ece..e85c3c5 100644 (file)
@@ -5,7 +5,7 @@
  * Copyright (c) 2004-2005 Richard Russon
  * Copyright (c) 2004-2008 Szabolcs Szakacsits
  * Copyright (c) 2005-2007 Yura Pakhuchiy
- * Copyright (c) 2008-2020 Jean-Pierre Andre
+ * Copyright (c) 2008-2021 Jean-Pierre Andre
  *
  * This program/include file is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as published
@@ -68,6 +68,7 @@
 #include "reparse.h"
 #include "object_id.h"
 #include "xattrs.h"
+#include "ea.h"
 
 /*
  * The little endian Unicode strings "$I30", "$SII", "$SDH", "$O"
@@ -1496,9 +1497,11 @@ static ntfs_inode *__ntfs_create(ntfs_inode *dir_ni, le32 securid,
 {
        ntfs_inode *ni;
        int rollback_data = 0, rollback_sd = 0;
+       int rollback_dir = 0;
        FILE_NAME_ATTR *fn = NULL;
        STANDARD_INFORMATION *si = NULL;
        int err, fn_len, si_len;
+       ntfs_volume_special_files special_files;
 
        ntfs_log_trace("Entering.\n");
        
@@ -1515,6 +1518,7 @@ static ntfs_inode *__ntfs_create(ntfs_inode *dir_ni, le32 securid,
 #if CACHE_NIDATA_SIZE
        ntfs_inode_invalidate(dir_ni->vol, ni->mft_no);
 #endif
+       special_files = dir_ni->vol->special_files;     
        /*
         * Create STANDARD_INFORMATION attribute.
         * JPA Depending on available inherited security descriptor,
@@ -1542,8 +1546,19 @@ static ntfs_inode *__ntfs_create(ntfs_inode *dir_ni, le32 securid,
        } else
                clear_nino_flag(ni, v3_Extensions);
        if (!S_ISREG(type) && !S_ISDIR(type)) {
-               si->file_attributes = FILE_ATTR_SYSTEM;
-               ni->flags = FILE_ATTR_SYSTEM;
+               switch (special_files) {
+               case NTFS_FILES_WSL :
+                       if (!S_ISLNK(type)) {
+                               si->file_attributes
+                                       = FILE_ATTRIBUTE_RECALL_ON_OPEN;
+                               ni->flags = FILE_ATTRIBUTE_RECALL_ON_OPEN;
+                       }
+                       break;
+               default :
+                       si->file_attributes = FILE_ATTR_SYSTEM;
+                       ni->flags = FILE_ATTR_SYSTEM;
+                       break;
+               }
        }
        ni->flags |= FILE_ATTR_ARCHIVE;
        if (NVolHideDotFiles(dir_ni->vol)
@@ -1576,8 +1591,8 @@ static ntfs_inode *__ntfs_create(ntfs_inode *dir_ni, le32 securid,
                        err = errno;
                        goto err_out;
                }
+               rollback_sd = 1;
        }
-       rollback_sd = 1;
 
        if (S_ISDIR(type)) {
                INDEX_ROOT *ir = NULL;
@@ -1626,34 +1641,58 @@ static ntfs_inode *__ntfs_create(ntfs_inode *dir_ni, le32 securid,
                switch (type) {
                        case S_IFBLK:
                        case S_IFCHR:
-                               data_len = offsetof(INTX_FILE, device_end);
-                               data = ntfs_malloc(data_len);
-                               if (!data) {
-                                       err = errno;
-                                       goto err_out;
+                               switch (special_files) {
+                               case NTFS_FILES_WSL :
+                                       data_len = 0;
+                                       data = (INTX_FILE*)NULL;
+                                       break;
+                               default :
+                                       data_len = offsetof(INTX_FILE,
+                                                               device_end);
+                                       data = (INTX_FILE*)ntfs_malloc(
+                                                               data_len);
+                                       if (!data) {
+                                               err = errno;
+                                               goto err_out;
+                                       }
+                                       data->major = cpu_to_le64(major(dev));
+                                       data->minor = cpu_to_le64(minor(dev));
+                                       if (type == S_IFBLK)
+                                               data->magic
+                                                       = INTX_BLOCK_DEVICE;
+                                       if (type == S_IFCHR)
+                                               data->magic
+                                                       = INTX_CHARACTER_DEVICE;
+                                       break;
                                }
-                               data->major = cpu_to_le64(major(dev));
-                               data->minor = cpu_to_le64(minor(dev));
-                               if (type == S_IFBLK)
-                                       data->magic = INTX_BLOCK_DEVICE;
-                               if (type == S_IFCHR)
-                                       data->magic = INTX_CHARACTER_DEVICE;
                                break;
                        case S_IFLNK:
-                               data_len = sizeof(INTX_FILE_TYPES) +
+                               switch (special_files) {
+                               case NTFS_FILES_WSL :
+                                       data_len = 0;
+                                       data = (INTX_FILE*)NULL;
+                                       break;
+                               default :
+                                       data_len = sizeof(INTX_FILE_TYPES) +
                                                target_len * sizeof(ntfschar);
-                               data = ntfs_malloc(data_len);
-                               if (!data) {
-                                       err = errno;
-                                       goto err_out;
-                               }
-                               data->magic = INTX_SYMBOLIC_LINK;
-                               memcpy(data->target, target,
+                                       data = (INTX_FILE*)ntfs_malloc(
+                                                               data_len);
+                                       if (!data) {
+                                               err = errno;
+                                               goto err_out;
+                                       }
+                                       data->magic = INTX_SYMBOLIC_LINK;
+                                       memcpy(data->target, target,
                                                target_len * sizeof(ntfschar));
+                                       break;
+                               }
                                break;
                        case S_IFSOCK:
                                data = NULL;
-                               data_len = 1;
+                               if (special_files == NTFS_FILES_WSL)
+                                       data_len = 0;
+                               else
+                                       data_len = 1;
                                break;
                        default: /* FIFO or regular file. */
                                data = NULL;
@@ -1684,9 +1723,10 @@ static ntfs_inode *__ntfs_create(ntfs_inode *dir_ni, le32 securid,
        fn->file_name_type = FILE_NAME_POSIX;
        if (S_ISDIR(type))
                fn->file_attributes = FILE_ATTR_I30_INDEX_PRESENT;
-       if (!S_ISREG(type) && !S_ISDIR(type))
-               fn->file_attributes = FILE_ATTR_SYSTEM;
-       else
+       if (!S_ISREG(type) && !S_ISDIR(type)) {
+               if (special_files == NTFS_FILES_INTERIX)
+                       fn->file_attributes = FILE_ATTR_SYSTEM;
+       } else
                fn->file_attributes |= ni->flags & FILE_ATTR_COMPRESSED;
        fn->file_attributes |= FILE_ATTR_ARCHIVE;
        fn->file_attributes |= ni->flags & FILE_ATTR_HIDDEN;
@@ -1714,10 +1754,40 @@ static ntfs_inode *__ntfs_create(ntfs_inode *dir_ni, le32 securid,
                ntfs_log_perror("Failed to add entry to the index");
                goto err_out;
        }
+       rollback_dir = 1;
        /* Set hard links count and directory flag. */
        ni->mrec->link_count = const_cpu_to_le16(1);
        if (S_ISDIR(type))
                ni->mrec->flags |= MFT_RECORD_IS_DIRECTORY;
+       /* Add reparse data */
+       if (special_files == NTFS_FILES_WSL) {
+               switch (type) {
+               case S_IFLNK :
+                       err = ntfs_reparse_set_wsl_symlink(ni, target,
+                                       target_len);
+                       break;
+               case S_IFIFO :
+               case S_IFSOCK :
+               case S_IFCHR :
+               case S_IFBLK :
+                       err = ntfs_reparse_set_wsl_not_symlink(ni,
+                                       type);
+                       if (!err) {
+                               err = ntfs_ea_set_wsl_not_symlink(ni,
+                                               type, dev);
+                               if (err)
+                                       ntfs_remove_ntfs_reparse_data(ni);
+                       }
+                       break;
+               default :
+                       err = 0;
+                       break;
+               }
+               if (err) {
+                       err = errno;
+                       goto err_out;
+               }
+       }
        ntfs_inode_mark_dirty(ni);
        /* Done! */
        free(fn);
@@ -1727,6 +1797,9 @@ static ntfs_inode *__ntfs_create(ntfs_inode *dir_ni, le32 securid,
 err_out:
        ntfs_log_trace("Failed.\n");
 
+       if (rollback_dir)
+               ntfs_index_remove(dir_ni, ni, fn, fn_len);
+
        if (rollback_sd)
                ntfs_attr_remove(ni, AT_SECURITY_DESCRIPTOR, AT_UNNAMED, 0);
        
index f03378b..b86930a 100644 (file)
@@ -62,6 +62,7 @@
 #include "xattrs.h"
 
 static const char lxdev[] = "$LXDEV";
+static const char lxmod[] = "$LXMOD";
 
 
 /*
@@ -466,3 +467,53 @@ int ntfs_ea_check_wsldev(ntfs_inode *ni, dev_t *rdevp)
        return (res);
 }
 
+int ntfs_ea_set_wsl_not_symlink(ntfs_inode *ni, mode_t type, dev_t dev)
+{
+       le32 mode;
+       struct {
+               le32 major;
+               le32 minor;
+       } device;
+       struct EA_WSL {
+               struct EA_LXMOD {       /* always inserted */
+                       EA_ATTR base;
+                       char name[sizeof(lxmod)];
+                       char value[sizeof(mode)];
+                       char stuff[3 & -(sizeof(lxmod) + sizeof(mode))];
+               } mod;
+               struct EA_LXDEV {       /* char or block devices only */
+                       EA_ATTR base;
+                       char name[sizeof(lxdev)];
+                       char value[sizeof(device)];
+                       char stuff[3 & -(sizeof(lxdev) + sizeof(device))];
+               } dev;
+       } attr;
+       int len;
+       int res;
+
+       memset(&attr, 0, sizeof(attr));
+       mode = cpu_to_le32((u32)(type | 0644));
+       attr.mod.base.next_entry_offset
+                       = const_cpu_to_le32(sizeof(attr.mod));
+       attr.mod.base.flags = 0;
+       attr.mod.base.name_length = sizeof(lxmod) - 1;
+       attr.mod.base.value_length = const_cpu_to_le16(sizeof(mode));
+       memcpy(attr.mod.name, lxmod, sizeof(lxmod));
+       memcpy(attr.mod.value, &mode, sizeof(mode));
+       len = sizeof(attr.mod);
+
+       if (S_ISCHR(type) || S_ISBLK(type)) {
+               device.major = cpu_to_le32(major(dev));
+               device.minor = cpu_to_le32(minor(dev));
+               attr.dev.base.next_entry_offset
+                       = const_cpu_to_le32(sizeof(attr.dev));
+               attr.dev.base.flags = 0;
+               attr.dev.base.name_length = sizeof(lxdev) - 1;
+               attr.dev.base.value_length = const_cpu_to_le16(sizeof(device));
+               memcpy(attr.dev.name, lxdev, sizeof(lxdev));
+               memcpy(attr.dev.value, &device, sizeof(device));
+               len += sizeof(attr.dev);
+               }
+       res = ntfs_set_ntfs_ea(ni, (char*)&attr, len, 0);
+       return (res);
+}
index fbdc7ca..76dbe2f 100644 (file)
@@ -1331,6 +1331,92 @@ int ntfs_remove_ntfs_reparse_data(ntfs_inode *ni)
        return (res ? -1 : 0);
 }
 
+/*
+ *             Set reparse data for a WSL type symlink
+ */
+
+int ntfs_reparse_set_wsl_symlink(ntfs_inode *ni,
+                       const ntfschar *target, int target_len)
+{
+       int res;
+       int len;
+       int reparse_len;
+       char *utarget;
+       REPARSE_POINT *reparse;
+       struct WSL_LINK_REPARSE_DATA *data;
+
+       res = -1;
+       utarget = (char*)NULL;
+       len = ntfs_ucstombs(target, target_len, &utarget, 0);
+       if (len > 0) {
+               reparse_len = sizeof(REPARSE_POINT) + sizeof(data->type) + len;
+               reparse = (REPARSE_POINT*)malloc(reparse_len);
+               if (reparse) {
+                       data = (struct WSL_LINK_REPARSE_DATA*)
+                                       reparse->reparse_data;
+                       reparse->reparse_tag = IO_REPARSE_TAG_LX_SYMLINK;
+                       reparse->reparse_data_length
+                               = cpu_to_le16(sizeof(data->type) + len);
+                       reparse->reserved = const_cpu_to_le16(0);
+                       data->type = const_cpu_to_le32(2);
+                       memcpy(data->link, utarget, len);
+                       res = ntfs_set_ntfs_reparse_data(ni,
+                               (char*)reparse, reparse_len, 0);
+                       free(reparse);
+               }
+       }
+       free(utarget);
+       return (res);
+}
+
+/*
+ *             Set reparse data for a WSL special file other than a symlink
+ *     (socket, fifo, character or block device)
+ */
+
+int ntfs_reparse_set_wsl_not_symlink(ntfs_inode *ni, mode_t mode)
+{
+       int res;
+       int len;
+       int reparse_len;
+       le32 reparse_tag;
+       REPARSE_POINT *reparse;
+
+       res = -1;
+       len = 0;
+       switch (mode) {
+       case S_IFSOCK :
+               reparse_tag = IO_REPARSE_TAG_AF_UNIX;
+               break;
+       case S_IFIFO :
+               reparse_tag = IO_REPARSE_TAG_LX_FIFO;
+               break;
+       case S_IFCHR :
+               reparse_tag = IO_REPARSE_TAG_LX_CHR;
+               break;
+       case S_IFBLK :
+               reparse_tag = IO_REPARSE_TAG_LX_BLK;
+               break;
+       default :
+               len = -1;
+               errno = EOPNOTSUPP;
+               break;
+       }
+       if (len >= 0) {
+               reparse_len = sizeof(REPARSE_POINT) + len;
+               reparse = (REPARSE_POINT*)malloc(reparse_len);
+               if (reparse) {
+                       reparse->reparse_tag = reparse_tag;
+                       reparse->reparse_data_length = cpu_to_le16(len);
+                       reparse->reserved = const_cpu_to_le16(0);
+                       res = ntfs_set_ntfs_reparse_data(ni,
+                               (char*)reparse, reparse_len, 0);
+                       free(reparse);
+               }
+       }
+       return (res);
+}
+
 
 /*
  *             Get the reparse data into a buffer
index 5cbf7f9..eea4e6d 100644 (file)
@@ -2385,7 +2385,11 @@ static int ntfs_fuse_create(fuse_req_t req, fuse_ino_t parent, const char *name,
                        perm = (typemode & ~ctx->dmask & 0777)
                                | (dsetgid & S_ISGID);
                else
-                       perm = typemode & ~ctx->fmask & 0777;
+                       if ((ctx->special_files == NTFS_FILES_WSL)
+                           && S_ISLNK(type))
+                               perm = typemode | 0777;
+                       else
+                               perm = typemode & ~ctx->fmask & 0777;
                        /*
                         * Try to get a security id available for
                         * file creation (from inheritance or argument).
@@ -4737,6 +4741,7 @@ int main(int argc, char *argv[])
                goto err_out;
 
        ctx->vol->abs_mnt_point = ctx->abs_mnt_point;
+       ctx->vol->special_files = ctx->special_files;
        ctx->security.vol = ctx->vol;
        ctx->vol->secure_flags = ctx->secure_flags;
 #ifdef HAVE_SETXATTR   /* extended attributes interface required */
index 2d18fb4..d4338a9 100644 (file)
@@ -316,6 +316,14 @@ data streams are mapped to xattrs and user can manipulate them using
 .B user_xattr
 Same as \fBstreams_interface=\fP\fIxattr\fP.
 .TP
+.BI special_files= value
+This option selects a mode for representing a special file to be created
+(symbolic link, socket, fifo, character or block device). The mode can
+be \fBinterix\fR or \fBwsl\fR, and existing files in either mode are
+recognized irrespective of the selected mode. Interix is the traditional
+mode, used by default, and wsl is interoperable with Windows WSL, but
+it is not compatible with Windows versions earlier than Windows 10.
+.TP
 .B efs_raw
 This option should only be used in backup or restore situation.
 It changes the apparent size of files and the behavior of read and
index a4c77ef..6ec2020 100644 (file)
@@ -2117,7 +2117,11 @@ static int ntfs_fuse_create(const char *org_path, mode_t typemode, dev_t dev,
                        perm = (typemode & ~ctx->dmask & 0777)
                                | (dsetgid & S_ISGID);
                else
-                       perm = typemode & ~ctx->fmask & 0777;
+                       if ((ctx->special_files == NTFS_FILES_WSL)
+                           && S_ISLNK(type))
+                               perm = typemode | 0777;
+                       else
+                               perm = typemode & ~ctx->fmask & 0777;
                        /*
                         * Try to get a security id available for
                         * file creation (from inheritance or argument).
@@ -4464,6 +4468,7 @@ int main(int argc, char *argv[])
        ctx->vol->abs_mnt_point = ctx->abs_mnt_point;
        ctx->security.vol = ctx->vol;
        ctx->vol->secure_flags = ctx->secure_flags;
+       ctx->vol->special_files = ctx->special_files;
 #ifdef HAVE_SETXATTR   /* extended attributes interface required */
        ctx->vol->efs_raw = ctx->efs_raw;
 #endif /* HAVE_SETXATTR */
index 6b24528..7e3e93d 100644 (file)
@@ -1,7 +1,7 @@
 /**
  * ntfs-3g_common.c - Common definitions for ntfs-3g and lowntfs-3g.
  *
- * Copyright (c) 2010-2020 Jean-Pierre Andre
+ * Copyright (c) 2010-2021 Jean-Pierre Andre
  * Copyright (c) 2010      Erik Larsson
  *
  * This program/include file is free software; you can redistribute it and/or
@@ -127,6 +127,7 @@ const struct DEFOPTION optionlist[] = {
        { "xattrmapping", OPT_XATTRMAPPING, FLGOPT_STRING },
        { "efs_raw", OPT_EFS_RAW, FLGOPT_BOGUS },
        { "posix_nlink", OPT_POSIX_NLINK, FLGOPT_BOGUS },
+       { "special_files", OPT_SPECIAL_FILES, FLGOPT_STRING },
        { (const char*)NULL, 0, 0 } /* end marker */
 } ;
 
@@ -503,6 +504,17 @@ char *parse_mount_options(ntfs_fuse_context_t *ctx,
                        case OPT_POSIX_NLINK :
                                ctx->posix_nlink = TRUE;
                                break;
+                       case OPT_SPECIAL_FILES :
+                               if (!strcmp(val, "interix"))
+                                       ctx->special_files = NTFS_FILES_INTERIX;
+                               else if (!strcmp(val, "wsl"))
+                                       ctx->special_files = NTFS_FILES_WSL;
+                               else {
+                                       ntfs_log_error("Invalid special_files"
+                                               " mode.\n");
+                                       goto err_exit;
+                               }
+                               break;
                        case OPT_FSNAME : /* Filesystem name. */
                        /*
                         * We need this to be able to check whether filesystem
index 8c2ecf3..4ed256a 100644 (file)
@@ -93,6 +93,7 @@ enum {
        OPT_XATTRMAPPING,
        OPT_EFS_RAW,
        OPT_POSIX_NLINK,
+       OPT_SPECIAL_FILES,
 } ;
 
                        /* Option flags */
@@ -155,6 +156,7 @@ typedef struct {
        BOOL blkdev;
        BOOL mounted;
        BOOL posix_nlink;
+       ntfs_volume_special_files special_files;
 #ifdef HAVE_SETXATTR   /* extended attributes interface required */
        BOOL efs_raw;
 #ifdef XATTR_MAPPINGS