Преобразование файла в каталог

14

Как мы знаем, «Все в Linux» - это файл, и, кроме того, каталог - это просто файл, содержащий другие файлы.

Итак, я не знаю, возможна ли эта «сумасшедшая идея», но она должна быть в некотором роде согласно вышеуказанному принципу.

Проще говоря, как я могу изменить существующий пустой файл в каталог. Является ли это возможным?

Как мозговой штурм, я подумал о некоторой модификации метаданных файла и сделал это метаданными каталога, которые должны были это сделать !!

Любая информация приветствуется.


ОБНОВЛЕНИЕ: Конечно, я не хочу удалять файл и создавать каталог вместо! Я просто пытаюсь узнать, насколько философия выше применима, если вы можете играть с некоторыми метаданными файла.

Maythux
источник
1
Что может быть причиной для этого?
Pilot6
1
Единственный правильный способ - удалить файл и создать каталог. В противном случае файловая система может быть повреждена. Вы можете сделать это на низком уровне, но это зависит от файловой системы. В ext4 индекс должен быть отредактирован, я думаю.
Pilot6
2
Концепция «файла» не об этом. Устройства также рассматриваются как файлы, но это не означает, что вы можете преобразовать файл в устройство. :))
Pilot6
5
У debugfs есть команда modify_inode, которая позволяет вам редактировать inode напрямую, что позволит вам установить флаг файла в dir. Он также имеет команду mkdir <inode>. Я ничего не сделал и не собираюсь пробовать.
Таллус
4
Это предположение «Как мы знаем,« Все в Linux »- это файл», неверно, поэтому весь ваш вопрос разваливается. Как мы знаем, «Все в Linux - это файл DESCRIPTOR». Делает мир разницы.
Rinzwind

Ответы:

21

Достижение конверсии

Создание тестовой файловой системы

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

  1. Создайте заполненный нулями файл testразмером 10 мегабайт:

    dd if=/dev/zero of=~/test bs=10M count=1
    
  2. Создайте файловую систему Ext4 внутри файла, как если бы это был раздел:

    mkfs.ext4 ~/test
    

Создание некоторых файлов и каталогов

Теперь у нас есть полностью функциональная файловая система внутри testфайла, поэтому мы собираемся создать в ней несколько файлов и каталогов.

  1. Смонтируйте вновь созданную файловую систему внутри /mnt:

    sudo mount ~/test /mnt
    
  2. Создайте файл и каталог:

    sudo mkdir /mnt/folder
    echo "contents" | sudo tee /mnt/file
    
  3. Проверьте содержимое файловой системы:

    ls -l /mnt
    

    Вывод должен быть примерно таким:

    total 2
    -rw-r--r-- 1 root root     0 may 21 18:53 file
    drw-r--r-- 2 root root  1024 may 21 18:55 folder
    
  4. Размонтируйте тестовую файловую систему:

    sudo umount /mnt
    

Обмен файла и папки

  1. Запуск debugfsпротив testфайла с разрешением записи ( -wфлаг):

    debugfs -w ~/test
    
  2. Конвертировать fileв папку:

    • В debugfsкомандной строке введите это:

      modify_inode file
      
    • Появится подсказка с вопросом о режиме; введите это:

      040644
      
    • Продолжайте нажимать, returnчтобы оставить оставшиеся данные как есть, пока приглашение не появится снова.

  3. Конвертировать folderв файл:

    • В debugfsкомандной строке введите это:

      modify_inode folder
      
    • Появится подсказка с вопросом о режиме; введите это:

      0100644
      
    • Продолжайте нажимать, returnчтобы оставить оставшиеся данные как есть, пока приглашение не появится снова.

  4. Для выхода из debugfsкомандной строки просто нажмите, qа затемreturn

Проверка успешности операции

  1. Смонтируйте тестовую файловую систему снова:

    sudo mount ~/test /mnt
    
  2. Проверьте содержимое файловой системы:

    ls -l /mnt
    

    Теперь он должен показывать файл, как если бы он был каталогом, и наоборот :

    total 2
    drw-r--r-- 1 root root     0 may 21 18:53 file
    -rw-r--r-- 2 root root  1024 may 21 18:55 folder
    

Скрипт для расчета режимов inode

#!/bin/bash

#### See https://ext4.wiki.kernel.org/index.php/Ext4_Disk_Layout#Inode_Table

## Terminal measures:
x="$(( $(tput cols) / 2 ))"   # Width of the terminal
y="$(( $(tput lines) /  2 ))" # Height of the terminal

## File descriptors:
declare -A types       # Declare an associative array with file descriptors
types[f]='0x8000'      # File
types[l]='0xA000'      # Link
types[s]='0xC000'      # Socket
types[d]='0x4000'      # Directory
types[p]='0x1000'      # Named pipe
types[b]='0x6000'      # Block device
types[c]='0x2000'      # Character device

## Permissions:
declare -A permission  # Declare an associative array with permissions
permission[user_S]='0x800'  # UID
permission[user_s]='0x840'  # UID and user can execute
permission[user_r]='0x100'  # User can read
permission[user_w]='0x80'   # User can write
permission[user_x]='0x40'   # User can execute
permission[group_S]='0x400' # GID
permission[group_s]='0x408' # GID and group can execute
permission[group_r]='0x20'  # Group can read
permission[group_w]='0x10'  # Group can write
permission[group_x]='0x8'   # Group can execute
permission[other_T]='0x200' # Sticky bit
permission[other_t]='0x201' # Sticky bit and other can execute
permission[other_r]='0x4'   # Other can read
permission[other_w]='0x2'   # Other can write
permission[other_x]='0x1'   # Other can execute

## Cleanup function:
function cleanup() {
    tput cvvis        # Make the cursor visible
    tput rmcup        # Restore saved terminal contents
    stty sane         # Fix problems caused by read -s
    exit 0            # Exit gracefully
}

## Function to print at a specified position:
function pprint() {
    tput cup $1 $2
    printf "${@:3}"
}

## Function to clear the notification area:
function reset() {
    pprint $((y+2)) $((x-40)) ' %.0s' {1..25} # Print 25 spaces
}

## Function to notify something to the user:
function notify() {
    reset                          # Clear the notification area
    pprint $((y+2)) $((x-40)) "$@" # Print the notification text
}

## If the terminal is smaller than 100x8, exit gracefully (self-explainatory):
if [ $x -lt 50 ] || [ $y -lt 5 ]; then
    echo 'Error, I need a minimum of 100x10 lines to run'
    exit 0
fi

## Initialize the terminal:
trap cleanup EXIT SIGHUP SIGINT SIGTERM # Call cleanup function after receiving ^C
stty -echo  cbreak                      # Put terminal in silent mode
tput smcup                              # Save terminal contents
tput civis                              # Make the cursor inisible

## Draw the big box:
printf '\033[1;37m'                            # Color
pprint $((y-3)) $((x-48)) '\u2500%.0s' {1..97} # Upper line
pprint $((y+4)) $((x-48)) '\u2500%.0s' {1..97} # Lower line
for ((i=4;i>-4;i--)); do                       # Sides:
    pprint $((y+i)) $((x-49)) '\u2502'             # Left line
    pprint $((y+i)) $((x+49)) '\u2502'             # Right line
done                                           # End sides
pprint $((y-3)) $((x-49)) '\u256D'             # Upper-left corner
pprint $((y+4)) $((x-49)) '\u2570'             # Lower-left corner
pprint $((y-3)) $((x+49)) '\u256E'             # Upper-right corner
pprint $((y+4)) $((x+49)) '\u256F'             # Lower-right corner

## Draw the small box:
printf '\033[1;35m'                             # Color
pprint $((y+1)) $((x-10)) '\u2501%.0s' {1..10}  # Upper line
pprint $((y+3)) $((x-10)) '\u2501%.0s' {1..10}  # Lower line
pprint $((y+2)) $((x-11)) '\u2503'              # Left line
pprint $((y+2)) $((x+00)) '\u2503'              # Right line
pprint $((y+1)) $((x-11)) '\u250F'              # Upper-left corner
pprint $((y+3)) $((x-11)) '\u2517'              # Lower-left corner
pprint $((y+1)) $((x+00)) '\u2513'              # Upper-right corner
pprint $((y+3)) $((x+00)) '\u251B'              # Lower-right corner

## Print type help:
pprint $((y-2)) $((x-44)) '\033[0;37mInode type: \033[1;37mf\033[0;37mile, \033[1;37md\033[0;37mirectory, \033[1;37ml\033[0;37mink, named \033[1;37mp\033[0;37mipe, \033[1;37ms\033[0;37mocket, \033[1;37mc\033[0;37mharacter device or \033[1;37mb\033[0;37mlock device.'

## Print permission help:
pprint $((y-1)) $((x-40)) '\033[0;36mPermission (\033[1;32mu\033[0;32mser\033[0;36m, \033[1;33mg\033[0;33mroup\033[0;36m or \033[1;31mo\033[0;31mther\033[0;36m): \033[1;36mr\033[0;36mead, \033[1;36mw\033[0;36mrite, e\033[1;36mx\033[0;36mecute, \033[1;36mhyphen\033[0;36m or \033[1;36mspace\033[0;36m to skip.'
pprint $((y+0)) $((x+8)) 's\033[1;36mt\033[0;36micky bit and executable, '
pprint $((y+1)) $((x+8)) 's\033[1;36mT\033[0;36micky bit not executable, '
pprint $((y+2)) $((x+8)) '\033[1;36ms\033[0;36metuid/setgid and executable, '
pprint $((y+3)) $((x+8)) '\033[1;36mS\033[0;36metuid/setgid not executable. '

## Endless loop:
while :; do

    ## Clear the input area:
    pprint $((y+2)) $((x-10)) '% *s\n' 10         # Print 16 spaces

    ## Print mask in the input area:
    printf '\033[1;37m'                           # Color for the type
    pprint $((y+2)) $((x-10)) '\u2588'            # Block for the type
    printf '\033[1;36m'                           # Color for the permision
    pprint $((y+2)) $((x- 9)) '\u2588%.0s' {1..9} # Blocks for the permission

    ## Loop through all variables to make a proper input:
    for var in type {user,group,other}_{r,w,x}; do

        ## Assign colors and regex to fields:
        case "$var" in
            (type)    color='\033[1;37m';     regex='^[fdlpscb]$'    ;;

            (other_x)                         regex='^[-xtT]$'       ;;&
            (user_x|group_x)                  regex='^[-xsS]$'       ;;&
            (user_[rw]|group_[rw]|other_[rw]) regex="^[-${var: -1}]$";;&

            (user*)   color='\033[1;32m'                             ;;
            (group*)  color='\033[1;33m'                             ;;
            (other*)  color='\033[1;31m'                             ;;
        esac

        ## Change the pointer position:
        pprint $((y+3)) $(((x-10)+pointer)) "${color}\u2501"           # Print the pointer on its new position
        if (( pointer > 0 )); then                                     # If the pointer is not in the first position:
            pprint $((y+3)) $(((x-10)+(pointer-1))) '\033[1;35m\u2501'     # Clear the old pointer         
        fi

        ## Infinite loop until there is a valid input for the current character:
        while :; do
            printf "$color"                       # Set the character color
            IFS= read -rn 1 $var                  # Read a character (even if it's a space)

            declare $var="${!var// /-}"           # Convert spaces to hyphens.
            if [[ "$var" == "type" ]]; then       # If the current variable is type:
                declare $var="${!var//-/f}"           # Convert "-" to "f"
            fi

            if [[ "${!var}"  =~ $regex ]]; then   # If there is a valid input:
                reset                                 # Clear error notification if any
                break                                 # Exit from this loop
            else                                  # Else:
                notify "\033[1;31mWrong input!"       # Print the error message
            fi
        done

        ## Print the entered value:
        pprint $((y+2)) $(((x-10)+pointer)) "${!var}"

        ## Sum the current permission:
        ((mode+=permission[${var%_*}_${!var}]))

        ## Increment the pointer:
        ((pointer++))
    done

    ## Post-read:
    unset pointer                                 # Reset the pointer
    pprint $((y+3)) $((x-1)) "\033[1;35m\u2501"   # Clear the pointer
    read -n 1                                     # Wait for Return or another character

    ## Sum file descriptor type:
    ((mode+=${types[$type]}))

    ## Final commands:
    mode=$(printf "%o" $mode)                      # Convert mode to octal (before this was decimal)
    notify "\033[1;32mOctal mode:\033[1;34m $mode" # Print the octal mode
    unset mode                                     # Reset the mode
done

Посмотреть скрипт на GitHub

Форы

  • Папка не открывается. Вы не сможете открыть его, если не добавите в него «необработанные данные папки», которые изначально содержали его.

дальнейшее чтение

https://ext4.wiki.kernel.org/index.php/Ext4_Disk_Layout#Inode_Table


Спасибо @tallus . Он дал мне отличный намек:

У debugfs есть команда modify_inode, которая позволяет вам редактировать inode напрямую, что позволит вам установить флаг файла в dir.

гелиограф
источник
2
+1 Хороший ответ, но только примечания 0100755должны быть 0100644для того, чтобы не изменять права доступа к файлу, так как 755 даст исполнение для преобразованного файла ...
Maythux
Кроме того, недавно преобразованный каталог не будет открыт. Это показывает, что файл становится папкой, но папка не может быть открыта. У вас есть какое-то решение для этого?
Maythux
Я буду держать это открытым какое-то время, иначе, если нет другого отличного ответа, я
отмечу
3
Черт, это здорово @helio: D
Rinzwind
1
Какой блестящий ответ! Хорошо, это в конечном счете бесполезно, но все же очень впечатляет, так что +1 от меня.
Карл Х