Добавить текст в начало последней строки

Описание на справочной страницеopen(2)дает некоторые подсказки, с чего начать:

   O_PATH (since Linux 2.6.39)
          Obtain a file descriptor that can be used for two purposes:
          to  indicate  a location in the filesystem tree and to per‐
          form operations that act  purely  at  the  file  descriptor
          level.  The file itself is not opened, and other file oper‐
          ations  (e.g.,  read(2),  write(2),  fchmod(2),  fchown(2),
          fgetxattr(2), ioctl(2), mmap(2)) fail with the error EBADF.

Иногда мы не хотим открывать файл или каталог. Вместо этого нам просто нужна ссылка на этот объект файловой системы для выполнения определенных операций (, например, fchdir()на каталог, на который ссылается дескриптор файла, который мы открыли с помощьюO_PATH). Итак, банальный момент :, если это наша цель, то открытие с помощью O_PATHдолжно быть немного дешевле, так как сам файл фактически не открывается.

И менее тривиальный момент :до существования O_PATH, способ получения такой ссылки на объект файловой системы состоял в том, чтобы открыть объект с помощью O_RDONLY. Но использование O_RDONLYтребует, чтобы у нас было разрешение на чтение объекта. Однако существуют различные варианты использования, когда нам не нужно на самом деле читать объект :, например, выполнение двоичного файла или доступ к каталогу(fchdir())или обращение к каталогу, чтобы коснуться объекта внутри каталога.

Использование с системными вызовами «*at ()»

Обычный,но не единственное использование O_PATHзаключается в открытии каталога, чтобы иметь ссылку на этот каталог для использования с системными вызовами «*at», такими как openat(), fstatat(), fchownat(), и так далее. Это семейство системных вызовов, которое мы можем считать современными преемниками более старых системных вызовов с похожими именами (open(), fstat(), fchown()и т. д. ), служит двум целям: первый из которых вы затрагиваете, когда спрашиваете «почему я хочу использовать дескриптор файла вместо пути к каталогу?». Если мы посмотрим дальше на справочную страницу open(2), мы найдем этот текст (под подзаголовком с обоснованием системных вызовов «*at»):

   First,  openat()  allows  an  application to avoid race conditions
   that could occur when using open() to open  files  in  directories
   other  than  the current working directory.  These race conditions
   result from the fact that some component of the  directory  prefix
   given  to  open()  could  be  changed in parallel with the call to
   open().  Suppose, for example, that we wish  to  create  the  file
   path/to/xxx.dep  if  the  file path/to/xxx exists.  The problem is
   that between the existence check and the file creation step,  path
   or  to  (which might be symbolic links) could be modified to point
   to a different location.  Such races can be avoided by  opening  a
   file descriptor for the target directory, and then specifying that
   file descriptor as the dirfd argument of (say) fstatat(2) and ope‐
   nat().

Чтобы сделать это более конкретным... Предположим, у нас есть программа, которая хочет выполнить несколько операций в каталоге, отличном от текущего рабочего каталога, а это означает, что мы должны указать некоторый префикс каталога как часть имен файлов, которые мы используем. Предположим, например, что путь /dir1/dir2/fileи мы хотим выполнить две операции:

  1. Выполните некоторую проверку /dir1/dir2/file(, например, кому принадлежит файл или когда он последний раз модифицировался ).
  2. Если мы удовлетворены результатом этой проверки, возможно, мы захотим выполнить какую-то другую операцию с файловой системой в том же каталоге, например, создать файл с именем /dir1/dir2/file.new.

Теперь предположим, что мы сделали все, используя традиционные системные вызовы на основе пути -:

struct stat stabuf;
stat("/dir1/dir2/file", &statbuf);
if ( /* Info returned in statbuf is to our liking */ ) {
    fd = open("/dir1/dir2/file.new", O_CREAT | O_RDWR, 0600);
    /* And then populate file referred to by fd */
}

Теперь, кроме того, предположим, что в префиксе каталога /dir1/dir2один из компонентов (, скажем dir2), на самом деле был символической ссылкой (, которая ссылается на каталог ), и что между вызов stat()и вызовopen()злоумышленник смог изменить цель символической ссылки dir2, чтобы указать на другой каталог. Это классическое время -из -проверка -время -из -использование состояния гонки.Наша программа проверила файл в одном каталоге, но затем ее обманом заставили создать файл в другом каталоге --, возможно, в каталоге, уязвимом для безопасности -. Ключевым моментом здесь является то, что имя пути /dir/dir2выглядело так же, но то, на что оно указывает, полностью изменилось.

Мы можем избежать подобных проблем, используя вызовы «*at». Прежде всего, мы получаем дескриптор, ссылающийся на каталог, в котором мы будем выполнять нашу работу:

dirfd = open("/dir/dir2", O_PATH);

Важным моментом здесь является то, что dirfdявляется стабильной ссылкой на каталог, на который ссылался путь /dir1/dir2во время вызова open(). Если цель символической ссылки dir2впоследствии изменится, это не повлияет на то, на что ссылается dirfd. Теперь мы можем выполнить нашу операцию проверки +, используя вызовы «*at», которые эквивалентны вызовам stat()и open()выше :

.

fstatat(dirfd, ""file", &statbuf)
struct stat stabuf;
fstatat(dirfd, "file", &statbuf);
if ( /* Info returned in statbuf is to our liking */ ) {
    fd = openat(dirfd, "file.new", O_CREAT | O_RDWR, 0600);
    /* And then populate file referred to by fd */
}

Во время этих шагов любые манипуляции с символическими ссылками в имени пути /dir/dir2не будут иметь никакого значения. :проверка(fstatat())и операция(openat())гарантированно будут выполняться в одном и том же каталоге.

Существует еще одна цель использования вызовов " *at ()", которая связана с идеей "на -поток текущих рабочих каталогов" в многопоточных программах (и снова мы можем открывать каталоги используя O_PATH), но я думаю, что это использование, вероятно, менее актуально для вашего вопроса, и я оставляю вас читать справочную страницу open(2), если вы хотите узнать больше.

Использование файловых дескрипторов для обычных файлов

Одним из вариантов использования O_PATHс обычными файлами является открытие двоичного файла, для которого у нас есть разрешение на выполнение (, но не обязательно разрешение на чтение, поэтому мы не можем открыть файл с помощьюO_RDONLY). Затем этот файловый дескриптор можно передать вfexecve(3)для выполнения программы. Все, что fexecve(fd, argv, envp)делает со своим fdаргументом, по существу:

snprintf(buf, "/proc/self/fd/%d", fd);
execve(buf, argv, envp);

(Хотя, начиная с glibc 2.27,реализация вместо этого будет использовать системный вызовexecveat(2)для ядер, которые предоставляют этот системный вызов.)

-1
01.10.2019, 09:50
1 ответ

Попробуйте:

$ sed '$ s/^/something = /' file
AAA
BBB
CCC
something = DDD

В GNU sed (Linux )файл можно редактировать на месте с помощью:

sed -i '$ s/^/something = /' file

Чтобы отредактировать файл на месте в MacOS или BSD, используйте вместо этого:

sed -i "" -e '$ s/^/something = /' file

Как это работает:

  • s/^/something = /является замещающей командой. Он говорит sed найти начало строки, отмеченное ^, и заменить его на something =.

  • $перед командой замены указывает sed применить команду замены только к последней строке в файле.

3
28.01.2020, 05:07

Теги

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