Convertendo um arquivo para o diretório

14

Como sabemos, "Tudo no Linux" é um arquivo e, além disso, o diretório é apenas um arquivo que contém outros arquivos.

Então, eu não sei se essa "idéia maluca" é possível, mas deve estar de alguma forma de acordo com o princípio acima.

Em palavras simples, como eu poderia alterar um arquivo vazio existente em um diretório. É possível?

Como algumas tempestades cerebrais eu pensei que algumas modificações nos metadados de arquivos e torná-las como metadados de diretório deveriam fazer isso !!

Qualquer informação é apreciada.

UPDATE: Com certeza não quero excluir um arquivo e criar o diretório! Eu só estou tentando saber o quanto a filosofia acima é aplicável se você pode jogar com alguns metadados de arquivo.

    
por Maythux 21.05.2015 / 18:25

1 resposta

18

Criando um sistema de arquivos de teste Ext4:

  1. Primeiro, crie um sistema de arquivos em um arquivo para evitar corromper seu sistema de arquivos real:

    dd if=/dev/zero of=test_fs bs=10M count=1
    

    Isso criará um arquivo chamado test_fs com um tamanho de 10 megabytes.

  2. Em seguida, criaremos um sistema de arquivos Ext4:

    mkfs.ext4 test_fs
    

Colocar alguns arquivos:

  1. Temos um sistema de arquivos totalmente funcional. Vamos montá-lo:

    sudo mount test_fs /mnt
    
  2. Vamos criar uma pasta e um arquivo.

    sudo mkdir /mnt/folder
    echo "Foo" | sudo tee /mnt/file
    
  3. Agora teste se tudo correr bem:

    ls -l /mnt
    

    O resultado deve ser algo assim:

    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. Em seguida, vamos desmontar o sistema de arquivos:

    sudo umount /mnt
    

Troca do arquivo e da pasta:

  1. Execute debugfs em relação a test_fs com permissão de gravação ( -w flag):

    debugfs -w test_fs
    
  2. Converta file em uma pasta:

    • No prompt debugfs , digite:

      modify_inode file
      
    • Um aviso aparecerá perguntando a você um modo. Digite isto:

      040644
      
    • Continue pressionando Return para deixar os dados em repouso como estão, até aparecer o prompt.

  3. Converter folder em um arquivo:

    • No prompt debugfs , digite:

      modify_inode folder
      
    • Um aviso aparecerá perguntando a você um modo. Digite isto:

      0100644
      
    • Continue pressionando Return para deixar os dados em repouso como estão, até aparecer o prompt.

  4. Para sair do prompt debugfs , simplesmente pressione q e, em seguida, Retornar

Verificar se tudo corre bem:

  1. Vamos montar o sistema de arquivos de teste novamente:

    sudo mount test_fs /mnt
    
  2. Agora verifique o conteúdo do sistema de arquivos:

    ls -l /mnt
    

    Hooray! Funciona! Veja aqui:

    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
    

Script para calcular modos de inodo:

#!/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 prmissions.
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  
    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 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 when ^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 '3[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 '3[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)) '3[0;37mInode type: 3[1;37mf3[0;37mile, 3[1;37md3[0;37mirectory, 3[1;37ml3[0;37mink, named 3[1;37mp3[0;37mipe, 3[1;37ms3[0;37mocket, 3[1;37mc3[0;37mharacter device or 3[1;37mb3[0;37mlock device.'

## Print permission help:
pprint $((y-1)) $((x-40)) '3[0;36mPermission (3[1;32mu3[0;32mser3[0;36m, 3[1;33mg3[0;33mroup3[0;36m or 3[1;31mo3[0;31mther3[0;36m): 3[1;36mr3[0;36mead, 3[1;36mw3[0;36mrite, e3[1;36mx3[0;36mecute, 3[1;36mhyphen3[0;36m or 3[1;36mspace3[0;36m to skip.'
pprint $((y+0)) $((x+8)) 's3[1;36mt3[0;36micky bit and executable, '
pprint $((y+1)) $((x+8)) 's3[1;36mT3[0;36micky bit not executable, '
pprint $((y+2)) $((x+8)) '3[1;36ms3[0;36metuid/setgid and executable, '
pprint $((y+3)) $((x+8)) '3[1;36mS3[0;36metuid/setgid not executable. '

## Endless loop:
while :; do                                   # While Linux is Open Source:

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

    ## Print mask in the input area:
    printf '3[1;37m'                           # Color for the type.
    pprint $((y+2)) $((x-10)) '\u2588'            # Block for the type.
    printf '3[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='3[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='3[1;32m'                             ;;
            (group*)  color='3[1;33m'                             ;;
            (other*)  color='3[1;31m'                             ;;
        esac

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

        ## 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 a space).

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

            if [[ "${!var}"  =~ $regex ]]; then   # If there is a valid input:
                reset                                 # Clear error notification if any.
                break                                 # Exit from this loop.
            else                                  # Else:
                notify "3[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)) "3[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 is decimal).
    notify "3[1;32mOctal mode:3[1;34m $mode" # Print the octal mode.
    unset mode                                     # Reset the mode.
done

Veja o script no GitHub

A pasta não abre:

Você não pode abri-lo a menos que você coloque nele o "código da pasta bruta" que agora contém o arquivo.

Outras leituras: link

Obrigado ao @tallus . Ele me deu uma ótima dica:

  

debugfs tem um comando modify_inode que permite editar um inode   diretamente que permitiria que você defina o sinalizador de arquivo para um diretório.

    
por Helio 21.05.2015 / 22:38