в WSL на SD-карте недостаточно прав git для добавления объекта

Я пытаюсь заставить Git работать в моей системе, но всегда получаю сообщение об ошибке

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

Я работаю над Surface Pro 5 в подсистеме Windows для Linux с Ubuntu. Все работает нормально, если я работаю на внутреннем диске. Проблема начинается, когда я хочу работать с моей картой micro SD. Сначала он не монтировался автоматически. Я исправил это, отредактировав файл /etc/fstab:

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

а ls -alR показывает, что разрешения должны быть rw для всех пользователей и всех файлов.

Я попробовал git add в существующем репозитории на этой SD-карте, и это не сработало. Каким-то образом он создал файл tmp в «.git/objects/54/», у которого не было прав на запись каждый раз, когда я пытался это сделать.

Затем я попытался клонировать тестовый репозиторий, но он создал папку для сплит-сека и выдал ту же ошибку. Он работает на моем обычном диске 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, я думаю.


person Nico G.    schedule 30.04.2020    source источник
comment
Можете ли вы отредактировать свой вопрос, включив в него результаты работы mount?   -  person bk2204    schedule 01.05.2020
comment
Вы можете сделать это с помощью sudo?   -  person LTPCGO    schedule 19.06.2020


Ответы (1)


У меня была точно такая же проблема.

Фон

В последних сборках Windows в WSL внесены некоторые изменения в отношении того, как он взаимодействует с вашей файловой системой. Одна из проблем заключается в том, что ранее несовместимость файловых систем Windows и Linux означала, что большинство файлов фактически имели разрешения «777» на внешнем хранилище, поэтому любой пользователь мог читать/записывать/выполнять что угодно. Это не совсем идеально для Linux, так как вы не можете хранить закрытые ключи и т. д. Теперь Microsoft изменила это поведение, поэтому файлы могут иметь разрешения как 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 с флагами равными 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);
}
person LTPCGO    schedule 20.06.2020
comment
Это проблема, с которой сталкиваются многие люди, поэтому xkcd.com/1597 так занимательный :) - person LTPCGO; 20.06.2020