4

我正在尝试让 Git 在我的系统上运行,但我总是收到错误消息

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

我正在使用 Ubuntu 开发适用于 Linux 的 Windows 子系统中的 Surface Pro 5。如果我在内部驱动器上工作,一切正常。当我想在我的微型 SD 卡上工作时,问题就开始了。首先它不是自动挂载的。我通过编辑/etc/fstab文件解决了这个问题:

E: /mnt/e drvfs defaults,metadata,rw,exec,uid=nico,gid=nico 0 0

ls -alR显示所有用户和所有文件的权限都应为 rw。

我尝试git add了此 SD 卡上的现有存储库,但它不起作用。不知何故,它在 '.git/objects/54/' 中创建了一个 tmp 文件,每次我尝试它时都没有写权限。

然后我尝试克隆一个测试存储库,但它为 splitsec 创建了文件夹并给了我同样的错误。它可以在我的普通驱动器 C: 上工作,但不能在我的 SD 卡上工作。

nico@DESKTOP-639MEJ9:/mnt/e$ git clone https://github.com/NicoJG/TestGit.git
Cloning into 'TestGit'...
remote: Enumerating objects: 3, done.
remote: Counting objects: 100% (3/3), done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
error: insufficient permission for adding an object to repository database /mnt/e/TestGit/.git/objects
fatal: failed to write object
fatal: unpack-objects failed
nico@DESKTOP-639MEJ9:/mnt/e$ sudo git clone https://github.com/NicoJG/TestGit.git
[sudo] password for nico:
Cloning into 'TestGit'...
remote: Enumerating objects: 3, done.
remote: Counting objects: 100% (3/3), done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
error: insufficient permission for adding an object to repository database /mnt/e/TestGit/.git/objects
fatal: failed to write object
fatal: unpack-objects failed
nico@DESKTOP-639MEJ9:/mnt/e$

不知何故,git 无法使用 WSL 中的权限正常工作。我已经尝试过:

sudo chmod -R ug+rw *
sudo chwn -R nico:nico *

有谁知道如何解决它?

编辑:根据 bk2204 的要求,这里是输出mount

nico@DESKTOP-639MEJ9:/mnt/e$ mount
rootfs on / type lxfs (rw,noatime)
none on /dev type tmpfs (rw,noatime,mode=755)
sysfs on /sys type sysfs (rw,nosuid,nodev,noexec,noatime)
proc on /proc type proc (rw,nosuid,nodev,noexec,noatime)
devpts on /dev/pts type devpts (rw,nosuid,noexec,noatime,gid=5,mode=620)
none on /run type tmpfs (rw,nosuid,noexec,noatime,mode=755)
none on /run/lock type tmpfs (rw,nosuid,nodev,noexec,noatime)
none on /run/shm type tmpfs (rw,nosuid,nodev,noatime)
none on /run/user type tmpfs (rw,nosuid,nodev,noexec,noatime,mode=755)
binfmt_misc on /proc/sys/fs/binfmt_misc type binfmt_misc (rw,relatime)
cgroup on /sys/fs/cgroup type tmpfs (rw,relatime,mode=755)
cgroup on /sys/fs/cgroup/devices type cgroup (rw,relatime,devices)
E: on /mnt/e type drvfs (rw,relatime,uid=1000,gid=1000,case=off)
C:\ on /windir/c type drvfs (rw,noatime,uid=1000,gid=1000,umask=22,fmask=11,metadata,case=off)

我只知道 C:(我的主驱动器)和 E:(我的 SD 卡)是什么。我认为其余的似乎是特定于 WSL 的。

4

1 回答 1

2

我有同样的问题。

背景

在最新的 Windows 版本中,WSL 与文件系统交互的方式发生了一些变化。一个问题是,以前,Windows 和 Linux 文件系统之间的不兼容意味着大多数文件实际上在外部存储上具有“777”权限,因此任何用户都可以读/写/执行任何内容。这对于 Linux 来说并不理想,因为您不能存储私钥等。微软现在已经改变了这种行为,因此文件可以通过扩展属性同时具有 Windows (NTFS) 和 Linux 权限。在普通驱动器上可以克服,您可以使用以下命令安装带有元数据的驱动器:

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

不幸的是,他们似乎也将这种更改推广到了网络和外部文件系统(如exFAT),它们没有可扩展的属性并且有点混乱,使得外部驱动器无法使用。例如,如果文件在 Windows 中是只读的,那么您不能在 WSL 中写入;您不能用sudo任何一种方法覆盖它,因为无论如何 Windows 权限都会覆盖 WSL 权限。这些更改破坏了很多程序,我今天发现它们试图将更改上传到 git。这是互联网上实际上还没有解决方案的新问题之一,所以我附上了一个文件来解决这个问题。

要运行,首先编译共享对象:

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

然后运行带有前缀的命令LD_PRELOAD

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

如何调查其他程序

对于git,该问题具体可见:

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

要找出失败的原因,您可以使用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

...

在打印错误行之前,我们立即看到它失败的原因(-1),因此要修复它需要拦截该调用。您可以从以下方面确定ltrace

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

>

...

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)

...

因此,这篇文章底部的附加代码会拦截open64带有 equal 标志的代码194

解决方案代码(名称 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
*/


/*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);
}
于 2020-06-20T04:25:42.940 回答