Как изменить значение по адресу из mmap без mallo c? - PullRequest
0 голосов
/ 27 мая 2020

Имея это:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/mman.h>

int main (void) {

    int fd = open("./sometext.txt", O_RDONLY);
    struct stat sb;

    if(fstat(fd,&sb)) perror("in function fstat"); 

    printf("file size is %ld bytes\n\n",sb.st_size);
    char* file_p = mmap(0, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);

    printf("printing file as an array of chars \n\n");
    for(int i =0; i<sb.st_size ; i++){
        if(file_p[i]=='a') //cannot do this
            file_p[i]='5'; //string/char is read-only, but then how?
        printf("%c",file_p[i]);
    }

    munmap(file_p, sb.st_size);
    close(fd);

    return 0;
}

Как я обнаружил из других вопросов, чтобы изменить строковый литерал, который по умолчанию доступен только для чтения, мне нужно либо иметь хранилище массива (char arr[] = "sometext_to_change_in_loop"), либо сделать другое Указатель, malloc требуется пробел, а затем скопируйте первый адрес строки, которая указатель из mallo c. Но как изменить строку «in-line», не выполняя ни одного из этих действий?

EDIT: Да, основная проблема заключалась в том, что я не выполнял побитовое ИЛИ для аргумента int prot в вызове mmap. Однако, как это возможно, что только этого достаточно?

1) - Я делаю не изменяю int flags в open вызове, так почему это работает, когда open ed с O_RDONLY, а не O_RDWD, что делает тот же файл доступным для записи (что я делаю с помощью file_p[i] = '5': Writting).

2) Как на самом деле могут быть сохранены изменения, когда в mmap I в аргументе есть int flags MAP_PRIVATE, но я хочу сохранить изменения, поэтому у меня должно быть MAP_SHARED? в соответствии с этим руководством: введите здесь описание ссылки где оба - флаг открытия и флаг mmap были изменены, когда я пишу. Мне тоже нужно объяснить это.

EDIT2: из учебника. Это действительно необходимо в случае другой записи в файл:

for(int i =0; i<sb.st_size ; i++){
        file_p[i] = toupper(file_p[i]);
        printf("%c",file_p[i]);
    }

Это будет ТРЕБУЕТСЯ , чтобы установить флаг open на O_RDWR и mmap на MAP_SHARED. Но почему? Почему одно изменение файла file_p[i]='5' отличается от другого изменения file_p[i]=toupper(file_p[i])? Почему не одно изменение требует установки двух флагов (первый случай), а другое требует (второй случай)? Меня сейчас это сбивает с толку.

Ответы [ 2 ]

1 голос
/ 27 мая 2020

Попробуйте заменить

char* file_p = mmap(0, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);

на

char* file_p = mmap(0, sb.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
0 голосов
/ 28 мая 2020

Кажется, вы задаете два совершенно разных вопроса: один о mmap() и один о строковых литералах. Принимая последнее:

, чтобы изменить строковый литерал, который по умолчанию доступен только для чтения, мне нужно либо иметь хранилище массива (char arr [] = "sometext_to_change_in_l oop"), либо сделать другое Указатель, mallo c требуется пробел, а затем скопируйте первый адрес строки, которая указатель из mallo c. Но как изменить строку «в строке», не выполняя ни одного из этих действий?

Повторяю мои комментарии по вопросу, не существует определенного способа изменить строковый литерал. Любая попытка сделать это приведет к неопределенному поведению. Однако многие строки не являются литералами, и если они имеют элементы изменяемого типа и хранятся в доступном для записи хранилище, они могут быть изменены с помощью различных функций строк и ввода-вывода, а также путем обычного доступа к массивам, в которых они находятся. В частности, содержимое строкового литерала можно скопировать в такое пространство, а затем изменить полученную отдельную строку.


Что касается вопроса (ов) mmap(), то общий вопрос кажется быть, как сопоставить файл, чтобы его содержимое можно было изменить с помощью сопоставления. Это уже рассмотрено в вашем другом ответе, в котором отмечается, что разрешенный доступ к отображению контролируется битовой маской, переданной как третий аргумент mmap(), как описано в POSIX . Существуют отдельные биты для чтения, записи и выполнения доступа к содержимому сопоставления.

Вы go просите разъяснений:

1) - Да не изменить int flags в вызове open, так почему это работает, когда open редактируется с O_RDONLY, а не с O_RDWD [sic], что делает тот же файл доступным для записи

Я понимаю, почему это наблюдение может стать неожиданностью. Отображение, установленное mmap(), не обращается к базовому объекту через предоставленный файловый дескриптор , поэтому режим дескриптора не имеет значения. Дескриптор файла служит только (частичной) идентификацией данных, которые необходимо сопоставить. Разрешения для доступа через сопоставление определяются аргументами только для mmap(), и вызов mmap() завершится ошибкой, если процесс не имеет достаточных привилегий для сопоставленного объекта для доступа к нему в запрошенных режимах.

Как на самом деле могут быть сохранены изменения, если в mmap у меня есть аргумент int flags MAP_PRIVATE, но я хочу сохранить изменения, поэтому у меня должно быть MAP_SHARED?

Вы объединяете две разные вещи. Уже обсужденные режимы доступа определяют, можете ли вы писать в отображение. MAP_PRIVATE против . MAP_SHARED определяет, могут ли другие процессы видеть такие записи, либо в их собственной копии сопоставления, либо в базовом файле. POSIX выражает это как расположение записей в отображение. С помощью MAP_SHARED они изменяют базовый объект. В MAP_PRIVATE они не изменяют базовый объект и видны только процессу, выполнившему запись.

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

Как сказано в POSIX: «Не указано, были ли модификации базового объекта выполнены после Отображение MAP_PRIVATE установлено, видны через отображение MAP_PRIVATE ". Это в значительной степени оборотная сторона уже обсуждаемой семантики MAP_PRIVATE: не только записи в сопоставление не отражаются в базовом объекте, но и модификации базового объекта также могут быть не видны через сопоставление. Напомним, что отображение, установленное mmap(), не обращается к базовому объекту через предоставленный файловый дескриптор.

...