команда find & copy не копирует одинаковое количество файлов

Этот ответ Тома Хейла продолжает уточнять:

...it appears that the filesystem has been unmounted, but in reality it has only been hidden from the file namespace / heirarchy.

  • Processes can still write via open file descriptors
  • New or existing files can be opened for writing by processes with a working directory inside the mountpoint via relative pathnames

Ответ Тома действительно попал в самую точку, но повторюсь:

  • «Недоступно для нового доступа» просто означает, что вы не можете разрешать имена путей, которые включают точку монтирования.

  • Вы можете делать что угодно с точкой монтирования, кроме открытия новых файлов/каталогов по абсолютному пути .

  • Единственное, что вы можете быть уверены в том, что происходит после вызова umount(MNT_DETACH), это то, что точки ниже точки монтирования недоступны по имени.

Название параметра MNT_DETACHдаже объясняет такое поведение. :Точка монтирования отсоединена от иерархии каталогов, но ничто в фактической смонтированной файловой системе не гарантируется.


Это несколько очевидно, если подумать, но текущий рабочий каталог, по существу, является открытой файловой ссылкой на этот каталог, но поддерживается ядром.Таким образом:

chdir("/foo");
open("./bar.txt", O_RDONLY);

эквивалентно

chdir("/foo");
openat(AT_FDCWD, "bar.txt", O_RDONLY);

что эквивалентно

int dirfd = open("/foo", O_RDONLY | O_DIRECTORY);
openat(dirfd, "bar.txt", O_RDONLY);

Я провел несколько тестов относительно ленивой развязки и открытых каталогов:

  • Если у вас есть дескриптор открытого файла, ссылающийся на каталог в точке монтирования :
    • Вы по-прежнему можете позвонить getdents(2), чтобы прочитать содержимое каталога
    • Вы по-прежнему можете использовать openat(2)для открытия файлов в этом каталоге, используя их пути относительно него!

Эта программа демонстрирует:

#define _GNU_SOURCE
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

static void 
show_dir_listing(DIR *dir)
{
    printf("Listing directory (by handle):\n");
    rewinddir(dir);

    for (;;) {
        struct dirent *d;

        errno = 0;
        d = readdir(dir);
        if (d == NULL) {
            if (errno)
                error(2, errno, "readdir failed");
            break;
        }

        printf("    %s%s\n",
                d->d_name,
                (d->d_type == DT_DIR) ? "/" : "");
    }
}

int main(int argc, char **argv)
{
    const char *dirpath;
    const char *filename;
    DIR *dir;
    int fd, rc;

    if (argc < 3) {
        fprintf(stderr, "Usage: %s DIR FILE\n",
                program_invocation_short_name);
        return 1;
    }
    dirpath = argv[1];
    filename = argv[2];

    printf("PID: %u\n", (unsigned int)getpid());

    printf("Opening handle to %s\n", dirpath);
    dir = opendir(dirpath);
    if (dir == NULL)
        error(2, errno, "opendir failed: %s", dirpath);

    show_dir_listing(dir);

    printf("\nLazy-unmounting %s\n\n", dirpath);
    rc = umount2(dirpath, MNT_DETACH);
    if (rc < 0)
        error(2, errno, "umount2 failed");

    show_dir_listing(dir);


    /* Try to open by full path name */
    {
        char path[PATH_MAX];
        path[0] = '\0';
        strcat(path, dirpath);
        strcat(path, "/");
        strcat(path, filename);

        printf("Trying to open(\"%s\")... ", path);
        fd = open(path, O_RDONLY);
        if (fd < 0) {
            printf("Failed!\n");
        }
        else {
            printf("Success: fd=%d\n", fd);
            close(fd);
        }
    }

    /* Try to openat relative to dir */
    {
        int dfd = dirfd(dir);
        printf("Trying to openat(%d, \"%s\")... ", dfd, filename);
        fd = openat(dfd, filename, O_RDONLY);
        if (fd < 0) {
            printf("Failed!\n");
        }
        else {
            printf("Success: fd=%d\n", fd);
            close(fd);
        }
    }

    return 0;
}

Тестирование:

$ ls /tmp/to-be-bound/
bar.txt  crackle.txt  foo.txt  pop.txt  snap.txt
$ mkdir /tmp/readonly-bind
$ mount -o bind,ro /tmp/to-be-bound /tmp/readonly-bind
$ ls /tmp/readonly-bind/
bar.txt  crackle.txt  foo.txt  pop.txt  snap.txt
$ echo 'should fail' >> /tmp/readonly-bind/foo.txt 
-bash: /tmp/readonly-bind/foo.txt: Read-only file system

$ sudo./lazytest /tmp/readonly-bind foo.txt
PID: 21160
Opening handle to /tmp/readonly-bind
Listing directory (by handle):
   ./
   ../
    pop.txt
    crackle.txt
    snap.txt
    bar.txt
    foo.txt

Lazy-unmounting /tmp/readonly-bind

Listing directory (by handle):
   ./
   ../
    pop.txt
    crackle.txt
    snap.txt
    bar.txt
    foo.txt
Trying to open("/tmp/readonly-bind/foo.txt")... Failed!
Trying to openat(3, "foo.txt")... Success: fd=4

0
04.02.2021, 13:12
1 ответ

Возможно, у вас есть повторяющиеся имена файлов? Если это так, они будут перезаписывать существующие и уменьшать общее количество файлов, попадающих в пункт назначения.

Вы можете попробовать это и посмотреть, что это вам даст, оно должно учитывать только количество уникальных базовых имен ваших найденных файлов:

find /tmp/files/test/ -type f -size -1000c -print0 | xargs -n1 -0 basename | sort | uniq | wc -l
0
18.03.2021, 22:32

Теги

Похожие вопросы