简体   繁体   中英

How to handle git under wsl2 network drive

I just configured docker to run under wsl2. That worked without any relevant problems and our projects are running fine.

I followed this article by docker on how to setup the wsl2 docker environment: https://www.docker.com/blog/docker-desktop-wsl-2-best-practices/

The article recommends to put the project files into the linux system and NOT access it by using the mounts under /mnt for performance reasons.

For accessing the files, the article suggests the following options:

  • Use Visual Studio Code (which can access wsl directly)
  • Use the network share under \\wsl$\
  • Run the IDE directly inside the linux

Some collegues use IDE's that are neither compatible with linux nor can access wsl. So I tried to let them access the project through the network share. Those collegues use the git integration in their IDE's and are not comfortable with the git cli.

Git works well, with just a little problem. We have files in the repository, that have the executable permission (+x). Thoses file have the perms 755 on linux and 644 on windows network drive.

Because the actual file perms differ from the linux environment, git detects a change for those files.

Is there a way, to expose the correct file perms to the windows environment?

Do you have any other ideas on how to solve the problem?

To sync Linux file permissions, you need to enable metadata for your Linux distro. Create /etc/wsl.conf file with this content:

[automount]
root = /
options = "metadata"

root is optional but useful, mounting your Windows drive to /c instead of /mnt/c , which saves you a few keystrokes.

To make sure this takes effect, sign out Windows and in again.

Check out the documentation for more details, as well as advanced settings like setting umask .

While at that, remember to enable Git's auto CRLF handling :

$ git config --global core.autocrlf true

Which will save you a lot of trouble when working with Git on WSL.

I had a similar problem with git where you may not be able to run a commit with various cryptic errors. Part of that is how git opens files, so hopefully this post goes some way to unpicking that.

Background

In the latest Windows builds there are some changes in WSL regarding how it interacts with your file system. One problem is the fact that previously, the incompatibility between Windows and Linux file-systems meant most files effectively had permissions '777' on external storage, so any user could read/write/execute anything. This isn't really ideal for Linux, as you can't store private keys etc. Microsoft have changed that behaviour now so files can have both Windows (NTFS) and Linux permissions, through extension attributes. On a normal drive it's fine to overcome, you can mount the drive with metadata using the following command:

umount /mnt/c;
mount -t drvfs C:\\ /mnt/c/ -o metadata

Unfortunately they seem to have rolled that change out to network and external filesystems too (like exFAT ), which doesn't have extensible attributes and gets in a bit of a mess, making external drives unusable. For example, if the file is read-only in Windows then you can't write to it in WSL; you can't override it with sudo either because Windows permissions override WSL ones regardless. The changes break a lot of programs, which I found out today trying to upload changes to git. It's one of those new problems which doesn't actually have solutions on the Internet yet, so I've attached a file will solve that issue.

To run, first compile the shared object:

cc -Wall -O3 -D_GNU_SOURCE -fPIC -c -o githack.o githack.c; gcc -o githack.so -nostartfiles -shared githack.o -ldl;

Then run the command prefixed with LD_PRELOAD :

LD_PRELOAD=./githack.so git commit -a -m "Another interesting commit"

How to investigate for other programs

For git , the issue specifically is seen:

error: insufficient permission for adding an object to repository database .git/objects

To find out why it failed, you can use strace :

strace git commit -a -m "Another interesting commit"

>

...

gettimeofday({tv_sec=1592618056, tv_usec=52991}, NULL) = 0

getpid()                               = 651

openat(AT_FDCWD, ".git/objects/78/tmp_obj_flbKNc", O_RDWR|O_CREAT|O_EXCL, 0444) = -1 EACCES (Permission denied)

write(2, "error: insufficient permission f"..., 88error: insufficient permission for adding an object to repository database .git/objects

) = 88

close(4)                               = 0

...

Immediately before the error line printed we see why it failed ( -1 ), so to fix it requires intercepting that call. You can determine that from ltrace :

ltrace git commit -a -m "Latest local copy from George"

>

...

open64(".git/objects/78/tmp_obj_zDayCc", 194, 0444)                                                                                                         = -1

__errno_location()                                                                                                                                          = 0x7f2777001000

__errno_location()                                                                                                                                          = 0x7f2777001000

__vsnprintf_chk(0x7fffd4786d00, 4096, 1, 4096)                                                                                                              = 80

__fprintf_chk(0x7f277631c680, 1, 0x7f27773eacfc, 0x7f27773c8083error: insufficient permission for adding an object to repository database .git/objects

)                                                                                            = 88

close(4)

...

And so the attached code at the bottom of this post intercepts the open64 code with flags equal 194 .

Solution code (name githack.c)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
//#define openat ignorethisopen
#define open ignorethisopen
#define open64 ignorethisopen64
#include <fcntl.h>
//#undef openat
#undef open
#undef open64
#include <dlfcn.h>


/*
    'strace git ...' will show git fail on an openat() command
    this is probably implemented as open64() on your system
    you can confirm this by use of 'ltrace git ...'
    you may also need to adjust the oflag comparison of 194
    George O'Neill 2020/06/20 (feel free to reach out if issues remain)
*/


/*static int (*___openat)(int, char *, int, mode_t);*/
static int (*___open)(const char *, int, mode_t);
static int (*___open64)(const char *, int, mode_t);


static void* dlwrap(const char *fn)
{
    const char *e;
    void *p = dlsym(RTLD_NEXT, fn);
    if ((e=dlerror())!=0)
        fprintf(stderr, "dlsym(RTLD_NEXT,'%s'): %s\r\n", fn, e);
    return p;
}


void _init(void)
{
    ___open = dlwrap("open");
    ___open64 = dlwrap("open64");
}


/*int openat(int dirfd, const char *pathname, int oflag, mode_t mode)*/
int open(const char *pathname, int oflag, mode_t mode)
{
    if (oflag && oflag == 194)
        return ___open(pathname, oflag, S_IRWXU);
    return ___open(pathname, oflag, mode);
}


int open64(const char *pathname, int oflag, mode_t mode)
{
    if (oflag && oflag == 194)
        return ___open64(pathname, oflag, S_IRWXU);
    return ___open64(pathname, oflag, mode);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM