From 49a4839ea8e127244350c0c5129ed8c5ef068ab1 Mon Sep 17 00:00:00 2001 From: GiulianoLBP <112990487+GiulianoLBP@users.noreply.github.com> Date: Mon, 23 Jun 2025 19:07:45 -0300 Subject: [PATCH 1/2] MyFileSys --- Main.java | 18 ++- core/Arquivo.java | 58 ++++++++ core/Bloco.java | 22 +++ core/Diretorio.java | 74 ++++++++++ core/ElementoFS.java | 39 ++++++ core/Offset.java | 53 ++++++++ core/Permissao.java | 31 +++++ core/Usuario.java | 42 ++++++ filesys/FileSystem.java | 7 +- filesys/FileSystemImpl.java | 245 ++++++++++++++++++++++++++++++---- tests/FileSystemImplTest.java | 210 +++++++++++++++++++++++++++++ tests/PermissionTest.java | 91 +++++++++++-- 12 files changed, 847 insertions(+), 43 deletions(-) create mode 100644 core/Arquivo.java create mode 100644 core/Bloco.java create mode 100644 core/Diretorio.java create mode 100644 core/ElementoFS.java create mode 100644 core/Offset.java create mode 100644 core/Permissao.java create mode 100644 core/Usuario.java create mode 100644 tests/FileSystemImplTest.java diff --git a/Main.java b/Main.java index 3b8673a..34b209b 100644 --- a/Main.java +++ b/Main.java @@ -1,6 +1,7 @@ import filesys.IFileSystem; +import core.Usuario; -import java.util.Scanner; +import java.util.*; import java.io.FileNotFoundException; import exception.PermissaoException; @@ -51,6 +52,7 @@ public static void main(String[] args) { // A partir do momento que um usuário cria outro diretório ou arquivo, // a permissão desse usuário é de leitura, escrita e execução nesse novo diretório/arquivo, // e sempre será rwx para o usuário root. + List usuarios = new ArrayList<>(); try { Scanner userScanner = new Scanner(new java.io.File("users/users")); while (userScanner.hasNextLine()) { @@ -68,6 +70,8 @@ public static void main(String[] args) { */ System.out.println(userListed + " " + dir + " " + dirPermission); // Somente imprime o usuário, diretório e permissão + usuarios.add(new Usuario(userListed, dirPermission, dir));//Adicionar usuario + } else { System.out.println("Formato ruim no arquivo de usuários. Linha: " + line); @@ -84,15 +88,15 @@ public static void main(String[] args) { // Finalmente cria o Sistema de Arquivos // Lista de usuários é imutável durante a execução do programa // Obs: Como passar a lista de usuários para o FileSystem? - fileSystem = new FileSystem(/*usuários?*/); + fileSystem = new FileSystem(usuarios); // // DESCOMENTE O BLOCO ABAIXO PARA CRIAR O DIRETÓRIO RAIZ ANTES DE RODAR O MENU // // Cria o diretório raiz do sistema. Root sempre tem permissão total "rwx" - // try { - // fileSystem.mkdir(ROOT_DIR, ROOT_USER); - // } catch (CaminhoJaExistenteException | PermissaoException e) { - // System.out.println(e.getMessage()); - // } + try { + fileSystem.mkdir(ROOT_DIR, ROOT_USER); + } catch (CaminhoJaExistenteException | PermissaoException e) { + System.out.println(e.getMessage()); + } // Menu interativo. menu(); diff --git a/core/Arquivo.java b/core/Arquivo.java new file mode 100644 index 0000000..3372d54 --- /dev/null +++ b/core/Arquivo.java @@ -0,0 +1,58 @@ +package core; + +import java.util.ArrayList; +import java.util.List; + +public class Arquivo extends ElementoFS { + private final List blocos; + private long bytesTotais; + + public Arquivo(String nome, String permissoes, String dono) { + super(nome, permissoes, dono); + this.blocos = new ArrayList<>(); + this.bytesTotais = 0; + } + + public void adicionarBloco(byte[] dados) { + blocos.add(dados); + bytesTotais += dados.length; + } + + public List getBlocos() { + return blocos; + } + + public long getBytesTotais() { + return bytesTotais; + } + + public void removerBloco(int idx) { + if (idx < 0 || idx >= blocos.size()) + throw new IndexOutOfBoundsException("Índice inválido para remoção de bloco."); + byte[] removido = blocos.remove(idx); + bytesTotais -= removido.length; + } + + public void limpar() { + blocos.clear(); + bytesTotais = 0; + } + + @Override + public boolean isArquivo() { + return true; + } + + @Override + public String toString() { + return "[ARQ] " + nomeDiretorio + " | Dono: " + donoDiretorio + " | Perm: " + permissoesPadrao + " | Tam: " + bytesTotais + " bytes"; + } + + public void inserirElemento(ElementoFS filho) { + throw new UnsupportedOperationException("Arquivo não pode conter elementos."); + } + + public void excluirElemento(String nome) { + throw new UnsupportedOperationException("Arquivo não possui elementos para remover."); + } +} \ No newline at end of file diff --git a/core/Bloco.java b/core/Bloco.java new file mode 100644 index 0000000..a88323c --- /dev/null +++ b/core/Bloco.java @@ -0,0 +1,22 @@ +package core; + +public class Bloco { + public static final int TAMANHO_PADRAO = 4096; // 4KB + private byte[] dados; + + public Bloco() { + this.dados = new byte[TAMANHO_PADRAO]; + } + + public Bloco(byte[] dados) { + this.dados = dados; + } + + public byte[] getDados() { + return dados; + } + + public void setDados(byte[] dados) { + this.dados = dados; + } +} \ No newline at end of file diff --git a/core/Diretorio.java b/core/Diretorio.java new file mode 100644 index 0000000..fc10734 --- /dev/null +++ b/core/Diretorio.java @@ -0,0 +1,74 @@ +package core; + +import java.util.HashMap; +import java.util.Map; + +public class Diretorio extends ElementoFS { + private Diretorio pai; + private final Map conteudo; + private final Map permissoesUsuario; + + public Diretorio(String nome, String permissoes, String dono) { + super(nome, permissoes, dono); + if (permissoes == null || permissoes.length() != 3) + throw new IllegalArgumentException("Permissões devem ter 3 caracteres (rwx)"); + this.conteudo = new HashMap<>(); + this.permissoesUsuario = new HashMap<>(); + } + + public void definirPermissao(String usuario, String permissoes) { + if (permissoes == null || permissoes.length() != 3) + throw new IllegalArgumentException("Permissões devem ter 3 caracteres (rwx)"); + permissoesUsuario.put(usuario, permissoes); + } + + public boolean possuiPermissao(String usuario, char tipo) { + if ("root".equals(usuario)) return true; + if (usuario.equals(donoDiretorio)) return permissoesPadrao.indexOf(tipo) >= 0; + String perm = permissoesUsuario.get(usuario); + if (perm != null && perm.indexOf(tipo) >= 0) return true; + if (pai != null) return pai.possuiPermissao(usuario, tipo); + return false; + } + + public String permissoesDoUsuario(String usuario) { + if ("root".equals(usuario)) return "rwx"; + if (usuario.equals(donoDiretorio)) return permissoesPadrao; + return permissoesUsuario.getOrDefault(usuario, "---"); + } + + public void inserirElemento(ElementoFS elemento) {//adiciona FILHO + if (conteudo.containsKey(elemento.getNomeDiretorio())) + throw new IllegalArgumentException("Elemento já existe: " + elemento.getNomeDiretorio()); + if (elemento instanceof Diretorio) { + ((Diretorio) elemento).setPai(this); + } + conteudo.put(elemento.getNomeDiretorio(), elemento); + } + + public void excluirElemento(String nome) {//exclui FILHO + conteudo.remove(nome); + } + + public Map getConteudo() { + return conteudo; + } + + public Diretorio getPai() { + return pai; + } + + public void setPai(Diretorio pai) { + this.pai = pai; + } + + @Override + public boolean isArquivo() { + return false; + } + + @Override + public String toString() { + return "[DIR] " + nomeDiretorio + " | Dono: " + donoDiretorio + " | Perm: " + permissoesPadrao; + } +} \ No newline at end of file diff --git a/core/ElementoFS.java b/core/ElementoFS.java new file mode 100644 index 0000000..11b2e9c --- /dev/null +++ b/core/ElementoFS.java @@ -0,0 +1,39 @@ +package core; + +public abstract class ElementoFS { + protected String nomeDiretorio; + protected String permissoesPadrao; + protected String donoDiretorio; + + public ElementoFS(String nomeDiretorio, String permissoesPadrao, String donoDiretorio) { + this.nomeDiretorio = nomeDiretorio; + this.permissoesPadrao = permissoesPadrao; + this.donoDiretorio = donoDiretorio; + } + + public String getNomeDiretorio() { + return nomeDiretorio; + } + + public void setNomeDiretorio(String nomeDiretorio) { + this.nomeDiretorio = nomeDiretorio; + } + + public String getPermissoesPadrao() { + return permissoesPadrao; + } + + public void setPermissoesPadrao(String permissoesPadrao) { + this.permissoesPadrao = permissoesPadrao; + } + + public String getDonoDiretorio() { + return donoDiretorio; + } + + public void setDonoDiretorio(String donoDiretorio) { + this.donoDiretorio = donoDiretorio; + } + + public abstract boolean isArquivo(); +} diff --git a/core/Offset.java b/core/Offset.java new file mode 100644 index 0000000..d247c12 --- /dev/null +++ b/core/Offset.java @@ -0,0 +1,53 @@ +package core; + +public class Offset { + private int posicao; + private int limite; + + public Offset() { + this.posicao = 0; + this.limite = Integer.MAX_VALUE; + } + + public Offset(int inicial) { + this.posicao = inicial; + this.limite = Integer.MAX_VALUE; + } + + public Offset(int inicial, int limite) { + this.posicao = inicial; + this.limite = limite; + } + + public int getPosicao() { + return posicao; + } + + public void setPosicao(int posicao) { + if (posicao < 0) { + throw new IllegalArgumentException("Offset não pode ser negativo."); + } + if (posicao > limite) { + throw new IllegalArgumentException("Offset excede o limite permitido (" + limite + ")."); + } + this.posicao = posicao; + } + + public void avancar(int quantidade) { + setPosicao(this.posicao + quantidade); + } + + public void zerar() { + this.posicao = 0; + } + + public int getLimite() { + return limite; + } + + public void setLimite(int limite) { + if (limite < 0) throw new IllegalArgumentException("Limite deve ser positivo."); + this.limite = limite; + if (posicao > limite) posicao = limite; + } +} \ No newline at end of file diff --git a/core/Permissao.java b/core/Permissao.java new file mode 100644 index 0000000..ec5423c --- /dev/null +++ b/core/Permissao.java @@ -0,0 +1,31 @@ +package core; + +import java.util.HashMap; +import java.util.Map; + +public class Permissao { + // Mapeia usuários para suas permissões + private Map mapaPermissoes; + + public Permissao() { + this.mapaPermissoes = new HashMap<>(); + } + + public void atribuirPermissao(String usuario, String permissao) { + mapaPermissoes.put(usuario, permissao); // exemplos: "rw", "r", "-" + } + + public boolean leituraPermitida(String usuario) { + String p = mapaPermissoes.getOrDefault(usuario, ""); + return p.contains("r"); + } + + public boolean escritaPermitida(String usuario) { + String p = mapaPermissoes.getOrDefault(usuario, ""); + return p.contains("w"); + } + + public String consultarPermissao(String usuario) { + return mapaPermissoes.getOrDefault(usuario, "-"); + } +} \ No newline at end of file diff --git a/core/Usuario.java b/core/Usuario.java new file mode 100644 index 0000000..501aff6 --- /dev/null +++ b/core/Usuario.java @@ -0,0 +1,42 @@ +package core; + +public class Usuario { + private String identificador; + private String pastaBase; + private String nivelAcesso; + + public Usuario(String identificador, String nivelAcesso, String pastaBase) { + this.setIdentificador(identificador); + this.setNivelAcesso(nivelAcesso); + this.setPastaBase(pastaBase); + } + + public String getIdentificador() { + return identificador; + } + + public String getNivelAcesso() { + return nivelAcesso; + } + + public void setNivelAcesso(String nivelAcesso) { + this.nivelAcesso = nivelAcesso; + } + + public void setIdentificador(String identificador) { + this.identificador = identificador; + } + + public void setPastaBase(String pastaBase) { + this.pastaBase = pastaBase; + } + + @Override + public String toString() { + return "Usuario{" + + "identificador='" + identificador + '\'' + + ", nivelAcesso='" + nivelAcesso + '\'' + + ", pastaBase='" + pastaBase + '\'' + + '}'; + } +} \ No newline at end of file diff --git a/filesys/FileSystem.java b/filesys/FileSystem.java index 8d7a83b..462a4ea 100644 --- a/filesys/FileSystem.java +++ b/filesys/FileSystem.java @@ -1,5 +1,8 @@ package filesys; +import java.util.List; + +import core.Usuario; import exception.CaminhoJaExistenteException; import exception.CaminhoNaoEncontradoException; import exception.PermissaoException; @@ -9,8 +12,8 @@ final public class FileSystem implements IFileSystem { private final IFileSystem fileSystemImpl; - public FileSystem() { - fileSystemImpl = new FileSystemImpl(); + public FileSystem(List usuarios) { + fileSystemImpl = new FileSystemImpl(usuarios); } @Override diff --git a/filesys/FileSystemImpl.java b/filesys/FileSystemImpl.java index 45fa05d..6ed6f28 100644 --- a/filesys/FileSystemImpl.java +++ b/filesys/FileSystemImpl.java @@ -1,70 +1,269 @@ package filesys; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import core.Arquivo; +import core.Diretorio; +import core.ElementoFS; +import core.Usuario; import exception.CaminhoJaExistenteException; import exception.CaminhoNaoEncontradoException; import exception.PermissaoException; -// Implemente nesta classe o seu código do FileSystem. -// A classe pode ser alterada. -// O construtor, argumentos do construtor podem ser modificados -// e atributos & métodos privados podem ser adicionados public final class FileSystemImpl implements IFileSystem { - private static final String ROOT_USER = "root"; // pode ser necessário + private static final String ROOT_USER = "root"; + private final Diretorio raiz; + private final Map usuarios; + + public FileSystemImpl(List listaUsuarios) { + this.raiz = new Diretorio("/", "rwx", ROOT_USER); + this.usuarios = new HashMap<>(); + usuarios.put(ROOT_USER, new Usuario(ROOT_USER, "rwx", "/")); + for (Usuario u : listaUsuarios) { + if (!u.getIdentificador().equalsIgnoreCase(ROOT_USER)) { + usuarios.put(u.getIdentificador(), u); + } + } + // Aqui você pode carregar os usuários do arquivo users, se desejar + // Exemplo: usuarios.put("root", new Usuario("root", "rwx", "/")); + } - public FileSystemImpl() {} + private Diretorio navegarParaDiretorioPai(String caminho) throws CaminhoNaoEncontradoException { + String[] partes = caminho.split("/"); + Diretorio atual = raiz; + for (int i = 1; i < partes.length - 1; i++) { + ElementoFS filho = atual.getConteudo().get(partes[i]); + if (filho == null || filho.isArquivo()) { + throw new CaminhoNaoEncontradoException("Diretório não encontrado: " + partes[i]); + } + atual = (Diretorio) filho; + } + return atual; + } + + private ElementoFS buscarElemento(String caminho) throws CaminhoNaoEncontradoException { + if ("/".equals(caminho)) + return raiz; + String[] partes = caminho.split("/"); + Diretorio atual = raiz; + for (int i = 1; i < partes.length - 1; i++) { + ElementoFS filho = atual.getConteudo().get(partes[i]); + if (filho == null || filho.isArquivo()) { + throw new CaminhoNaoEncontradoException("Diretório não encontrado: " + partes[i]); + } + atual = (Diretorio) filho; + } + ElementoFS alvo = atual.getConteudo().get(partes[partes.length - 1]); + if (alvo == null) + throw new CaminhoNaoEncontradoException("Elemento não encontrado: " + caminho); + return alvo; + } + + public ElementoFS buscarElementoTeste(String caminho) throws CaminhoNaoEncontradoException { + return buscarElemento(caminho); + } @Override - public void mkdir(String caminho, String nome) throws CaminhoJaExistenteException, PermissaoException { - throw new UnsupportedOperationException("Método não implementado 'mkdir'"); + public void mkdir(String caminho, String usuario) throws CaminhoJaExistenteException, PermissaoException { + Diretorio pai; + try { + pai = navegarParaDiretorioPai(caminho); + } catch (CaminhoNaoEncontradoException e) { + throw new PermissaoException("Diretório pai não encontrado: " + caminho); + } + String nomeNovo = caminho.substring(caminho.lastIndexOf('/') + 1); + if (pai.getConteudo().containsKey(nomeNovo)) { + throw new CaminhoJaExistenteException("Já existe um arquivo ou diretório com esse nome."); + } + if (!pai.possuiPermissao(usuario, 'w') || !pai.possuiPermissao(usuario, 'x')) { + throw new PermissaoException("Usuário sem permissão de escrita no diretório."); + } + Diretorio novoDir = new Diretorio(nomeNovo, "rwx", usuario); + pai.inserirElemento(novoDir); } @Override - public void chmod(String caminho, String usuario, String usuarioAlvo, String permissao) - throws CaminhoNaoEncontradoException, PermissaoException { - throw new UnsupportedOperationException("Método não implementado 'chmod'"); + public void touch(String caminho, String usuario) throws CaminhoJaExistenteException, PermissaoException { + Diretorio pai; + try { + pai = navegarParaDiretorioPai(caminho); + } catch (CaminhoNaoEncontradoException e) { + throw new PermissaoException("Diretório pai não encontrado: " + caminho); + } + String nomeArquivo = caminho.substring(caminho.lastIndexOf('/') + 1); + if (pai.getConteudo().containsKey(nomeArquivo)) { + throw new CaminhoJaExistenteException("Já existe um arquivo ou diretório com esse nome."); + } + if (!pai.possuiPermissao(usuario, 'w')) { + throw new PermissaoException("Usuário sem permissão de escrita no diretório."); + } + Arquivo novoArq = new Arquivo(nomeArquivo, "rw-", usuario); + pai.inserirElemento(novoArq); } @Override - public void rm(String caminho, String usuario, boolean recursivo) + public void chmod(String caminho, String usuario, String usuarioAlvo, String permissao) throws CaminhoNaoEncontradoException, PermissaoException { - throw new UnsupportedOperationException("Método não implementado 'rm'"); + ElementoFS elemento = buscarElemento(caminho); + if (!elemento.getDonoDiretorio().equals(usuario) && !"root".equals(usuario)) { + throw new PermissaoException("Apenas o dono ou root pode alterar permissões."); + } + if (elemento instanceof Diretorio) { + ((Diretorio) elemento).definirPermissao(usuarioAlvo, permissao); + } else { + elemento.setPermissoesPadrao(permissao); // Para arquivos, pode ser diferente + } } @Override - public void touch(String caminho, String usuario) throws CaminhoJaExistenteException, PermissaoException { - throw new UnsupportedOperationException("Método não implementado 'touch'"); + public void rm(String caminho, String usuario, boolean recursivo) + throws CaminhoNaoEncontradoException, PermissaoException { + Diretorio pai = navegarParaDiretorioPai(caminho); + String nome = caminho.substring(caminho.lastIndexOf('/') + 1); + ElementoFS alvo = pai.getConteudo().get(nome); + if (alvo == null) + throw new CaminhoNaoEncontradoException("Elemento não encontrado."); + if (!pai.possuiPermissao(usuario, 'w')) { + throw new PermissaoException("Sem permissão para remover."); + } + if (alvo instanceof Diretorio && !recursivo && !((Diretorio) alvo).getConteudo().isEmpty()) { + throw new PermissaoException("Diretório não vazio. Use recursivo."); + } + pai.excluirElemento(nome); } @Override public void write(String caminho, String usuario, boolean anexar, byte[] buffer) throws CaminhoNaoEncontradoException, PermissaoException { - throw new UnsupportedOperationException("Método não implementado 'write'"); + ElementoFS elemento = buscarElemento(caminho); + if (!elemento.isArquivo()) + throw new CaminhoNaoEncontradoException("Não é um arquivo."); + if (!elemento.getDonoDiretorio().equals(usuario) && !"root".equals(usuario)) { + throw new PermissaoException("Sem permissão para escrever."); + } + Arquivo arquivo = (Arquivo) elemento; + if (!anexar) + arquivo.limpar(); + arquivo.adicionarBloco(buffer); } @Override public void read(String caminho, String usuario, byte[] buffer) throws CaminhoNaoEncontradoException, PermissaoException { - throw new UnsupportedOperationException("Método não implementado 'read'"); + ElementoFS elemento = buscarElemento(caminho); + if (!elemento.isArquivo()) + throw new CaminhoNaoEncontradoException("Não é um arquivo."); + if (!elemento.getDonoDiretorio().equals(usuario) && !"root".equals(usuario)) { + throw new PermissaoException("Sem permissão para leitura."); + } + Arquivo arquivo = (Arquivo) elemento; + List blocos = arquivo.getBlocos(); + int offset = 0; + for (byte[] bloco : blocos) { + int len = Math.min(bloco.length, buffer.length - offset); + System.arraycopy(bloco, 0, buffer, offset, len); + offset += len; + if (offset >= buffer.length) + break; + } } @Override public void mv(String caminhoAntigo, String caminhoNovo, String usuario) throws CaminhoNaoEncontradoException, PermissaoException { - throw new UnsupportedOperationException("Método não implementado 'mv'"); + Diretorio paiAntigo, paiNovo; + try { + paiAntigo = navegarParaDiretorioPai(caminhoAntigo); + paiNovo = navegarParaDiretorioPai(caminhoNovo); + } catch (CaminhoNaoEncontradoException e) { + throw new PermissaoException("Diretório pai não encontrado."); + } + String nomeAntigo = caminhoAntigo.substring(caminhoAntigo.lastIndexOf('/') + 1); + String nomeNovo = caminhoNovo.substring(caminhoNovo.lastIndexOf('/') + 1); + ElementoFS elemento = paiAntigo.getConteudo().get(nomeAntigo); + if (elemento == null) + throw new CaminhoNaoEncontradoException("Elemento não encontrado."); + if (!paiAntigo.possuiPermissao(usuario, 'w')) { + throw new PermissaoException("Sem permissão para mover."); + } + if (paiNovo.getConteudo().containsKey(nomeNovo)) { + throw new PermissaoException("Já existe um elemento com esse nome no destino."); + } + paiAntigo.excluirElemento(nomeAntigo); + elemento.setNomeDiretorio(nomeNovo); + paiNovo.inserirElemento(elemento); } @Override - public void ls(String caminho, String usuario, boolean recursivo) throws CaminhoNaoEncontradoException, PermissaoException { - throw new UnsupportedOperationException("Método não implementado 'ls'"); + public void ls(String caminho, String usuario, boolean recursivo) + throws CaminhoNaoEncontradoException, PermissaoException { + ElementoFS elemento = buscarElemento(caminho); + if (!(elemento instanceof Diretorio)) + throw new CaminhoNaoEncontradoException("Não é um diretório."); + Diretorio dir = (Diretorio) elemento; + if (!dir.possuiPermissao(usuario, 'r')) { + throw new PermissaoException("Sem permissão para leitura."); + } + listarConteudo(dir, recursivo, ""); + } + + private void listarConteudo(Diretorio dir, boolean recursivo, String prefixo) { + for (ElementoFS filho : dir.getConteudo().values()) { + System.out.println(prefixo + filho.getNomeDiretorio()); + if (recursivo && filho instanceof Diretorio) { + listarConteudo((Diretorio) filho, true, prefixo + " "); + } + } } @Override public void cp(String caminhoOrigem, String caminhoDestino, String usuario, boolean recursivo) throws CaminhoNaoEncontradoException, PermissaoException { - throw new UnsupportedOperationException("Método não implementado 'cp'"); + ElementoFS origem = buscarElemento(caminhoOrigem); + Diretorio destinoPai; + try { + destinoPai = navegarParaDiretorioPai(caminhoDestino); + } catch (CaminhoNaoEncontradoException e) { + throw new PermissaoException("Diretório pai não encontrado: " + caminhoDestino); + } + String nomeDestino = caminhoDestino.substring(caminhoDestino.lastIndexOf('/') + 1); + if (destinoPai.getConteudo().containsKey(nomeDestino)) { + throw new PermissaoException("Já existe um elemento com esse nome no destino."); + } + if (!destinoPai.possuiPermissao(usuario, 'w')) { + throw new PermissaoException("Sem permissão para copiar."); + } + ElementoFS copia = copiarElemento(origem, recursivo); + copia.setNomeDiretorio(nomeDestino); + destinoPai.inserirElemento(copia); + } + + private ElementoFS copiarElemento(ElementoFS elemento, boolean recursivo) { + if (elemento instanceof Arquivo) { + Arquivo arq = (Arquivo) elemento; + Arquivo novo = new Arquivo(arq.getNomeDiretorio(), arq.getPermissoesPadrao(), arq.getDonoDiretorio()); + for (byte[] bloco : arq.getBlocos()) { + novo.adicionarBloco(Arrays.copyOf(bloco, bloco.length)); + } + return novo; + } else if (elemento instanceof Diretorio) { + Diretorio dir = (Diretorio) elemento; + Diretorio novoDir = new Diretorio(dir.getNomeDiretorio(), dir.getPermissoesPadrao(), + dir.getDonoDiretorio()); + if (recursivo) { + for (ElementoFS filho : dir.getConteudo().values()) { + novoDir.inserirElemento(copiarElemento(filho, true)); + } + } + return novoDir; + } + throw new IllegalArgumentException("Tipo desconhecido."); } public void addUser(String user) { - throw new UnsupportedOperationException("Método não implementado 'addUser'"); + // Implemente se desejar gerenciar usuários dinamicamente } -} +} \ No newline at end of file diff --git a/tests/FileSystemImplTest.java b/tests/FileSystemImplTest.java new file mode 100644 index 0000000..65efc41 --- /dev/null +++ b/tests/FileSystemImplTest.java @@ -0,0 +1,210 @@ +package tests; + +import static org.junit.jupiter.api.Assertions.*; + +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.List; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import core.Usuario; +import exception.CaminhoJaExistenteException; +import exception.CaminhoNaoEncontradoException; +import exception.PermissaoException; +import filesys.FileSystemImpl; + +class FileSystemImplTest { + private FileSystemImpl sistema; + List listaUsuarios = new ArrayList<>(); + + @BeforeEach + void inicializar() { + sistema = new FileSystemImpl(listaUsuarios); + } + + @Test + void criaDiretorio_RetornaSucesso() throws Exception { + sistema.mkdir("/pasta", "root"); + assertDoesNotThrow(() -> sistema.mkdir("/outra", "root")); + } + + @Test + void criaDiretorio_JaExiste_LancaErro() throws Exception { + sistema.mkdir("/pasta", "root"); + assertThrows(CaminhoJaExistenteException.class, () -> sistema.mkdir("/pasta", "root")); + } + + @Test + void criaDiretorio_SemPermissao_LancaErro() throws Exception { + sistema.mkdir("/pasta", "root"); + assertThrows(PermissaoException.class, () -> sistema.mkdir("/pasta/priv", "usuario")); + } + + @Test + void criaArquivo_Sucesso() throws Exception { + sistema.mkdir("/pasta", "root"); + sistema.touch("/pasta/novo.txt", "root"); + assertThrows(CaminhoJaExistenteException.class, () -> sistema.touch("/pasta/novo.txt", "root")); + } + + @Test + void criaArquivo_SemPermissao_LancaErro() throws Exception { + sistema.mkdir("/pasta", "root"); + assertThrows(PermissaoException.class, () -> sistema.touch("/pasta/sempermissao.txt", "usuario")); + } + + @Test + void alteraPermissao_Sucesso() throws Exception { + sistema.mkdir("/pasta", "root"); + assertDoesNotThrow(() -> sistema.chmod("/pasta", "root", "usuario", "rwx")); + } + + @Test + void alteraPermissao_SemPermissao_LancaErro() throws Exception { + sistema.mkdir("/pasta", "root"); + assertThrows(PermissaoException.class, () -> sistema.chmod("/pasta", "usuario", "usuario", "rwx")); + } + + @Test + void alteraPermissao_CaminhoInexistente_LancaErro() { + assertThrows(CaminhoNaoEncontradoException.class, () -> sistema.chmod("/inexistente", "root", "root", "rwx")); + } + + @Test + void removeArquivo_Sucesso() throws Exception { + sistema.mkdir("/pasta", "root"); + sistema.touch("/pasta/arquivo.txt", "root"); + assertDoesNotThrow(() -> sistema.rm("/pasta/arquivo.txt", "root", false)); + assertThrows(CaminhoNaoEncontradoException.class, () -> sistema.rm("/pasta/arquivo.txt", "root", false)); + } + + @Test + void removeDiretorio_Recursivo_Sucesso() throws Exception { + sistema.mkdir("/pasta", "root"); + sistema.mkdir("/pasta/sub", "root"); + sistema.touch("/pasta/sub/arquivo.txt", "root"); + assertDoesNotThrow(() -> sistema.rm("/pasta", "root", true)); + assertThrows(CaminhoNaoEncontradoException.class, () -> sistema.rm("/pasta", "root", false)); + } + + @Test + void removeDiretorio_NaoVazio_SemRecursivo_LancaErro() throws Exception { + sistema.mkdir("/pasta", "root"); + sistema.touch("/pasta/arquivo.txt", "root"); + assertThrows(PermissaoException.class, () -> sistema.rm("/pasta", "root", false)); + } + + @Test + void escritaArquivo_Simples() throws Exception { + sistema.mkdir("/pasta", "root"); + sistema.touch("/pasta/arquivo.txt", "root"); + byte[] conteudo = "Teste123".getBytes(); + sistema.write("/pasta/arquivo.txt", "root", false, conteudo); + core.Arquivo arquivo = (core.Arquivo) sistema.buscarElementoTeste("/pasta/arquivo.txt"); + assertEquals(conteudo.length, arquivo.getBytesTotais()); + } + + @Test + void escritaArquivo_Append() throws Exception { + sistema.mkdir("/pasta", "root"); + sistema.touch("/pasta/arquivo.txt", "root"); + byte[] parte1 = "ABC".getBytes(); + byte[] parte2 = "DEF".getBytes(); + sistema.write("/pasta/arquivo.txt", "root", false, parte1); + sistema.write("/pasta/arquivo.txt", "root", true, parte2); + core.Arquivo arquivo = (core.Arquivo) sistema.buscarElementoTeste("/pasta/arquivo.txt"); + assertEquals(6, arquivo.getBytesTotais()); + } + + @Test + void leituraArquivo_Simples() throws Exception { + sistema.mkdir("/pasta", "root"); + sistema.touch("/pasta/arquivo.txt", "root"); + byte[] conteudo = "Leitura".getBytes(); + sistema.write("/pasta/arquivo.txt", "root", false, conteudo); + + byte[] buffer = new byte[conteudo.length]; + sistema.read("/pasta/arquivo.txt", "root", buffer); + assertArrayEquals(conteudo, buffer); + } + + @Test + void moverArquivo_Sucesso() throws Exception { + sistema.mkdir("/origem", "root"); + sistema.touch("/origem/arquivo.txt", "root"); + sistema.mkdir("/destino", "root"); + sistema.mv("/origem/arquivo.txt", "/destino/novo.txt", "root"); + assertThrows(CaminhoNaoEncontradoException.class, () -> sistema.rm("/origem/arquivo.txt", "root", false)); + sistema.rm("/destino/novo.txt", "root", false); + } + + @Test + void listarDiretorio_Simples() throws Exception { + sistema.mkdir("/pasta", "root"); + sistema.touch("/pasta/arq1.txt", "root"); + sistema.touch("/pasta/arq2.txt", "root"); + + ByteArrayOutputStream saida = new ByteArrayOutputStream(); + PrintStream saidaOriginal = System.out; + System.setOut(new PrintStream(saida)); + + sistema.ls("/pasta", "root", false); + + System.setOut(saidaOriginal); + + String resultado = saida.toString(); + assertTrue(resultado.contains("arq1.txt")); + assertTrue(resultado.contains("arq2.txt")); + } + + @Test + void listarDiretorio_Recursivo() throws Exception { + sistema.mkdir("/pasta", "root"); + sistema.touch("/pasta/arq1.txt", "root"); + sistema.mkdir("/pasta/subpasta", "root"); + sistema.touch("/pasta/subpasta/arq2.txt", "root"); + + ByteArrayOutputStream saida = new ByteArrayOutputStream(); + PrintStream saidaOriginal = System.out; + System.setOut(new PrintStream(saida)); + + sistema.ls("/pasta", "root", true); + + System.setOut(saidaOriginal); + + String resultado = saida.toString(); + assertTrue(resultado.contains("arq1.txt")); + assertTrue(resultado.contains("subpasta")); + assertTrue(resultado.contains("arq2.txt")); + } + + @Test + void copiaArquivo_Sucesso() throws Exception { + sistema.mkdir("/pasta", "root"); + sistema.touch("/pasta/original.txt", "root"); + byte[] dados = "xyz".getBytes(); + sistema.write("/pasta/original.txt", "root", false, dados); + + sistema.cp("/pasta/original.txt", "/pasta/copia.txt", "root", false); + + core.Arquivo arquivo = (core.Arquivo) sistema.buscarElementoTeste("/pasta/copia.txt"); + assertEquals(dados.length, arquivo.getBytesTotais()); + } + + @Test + void copiaDiretorio_Recursivo() throws Exception { + sistema.mkdir("/pasta", "root"); + sistema.touch("/pasta/original.txt", "root"); + sistema.mkdir("/pasta/subpasta", "root"); + sistema.touch("/pasta/subpasta/arq2.txt", "root"); + sistema.cp("/pasta", "/backup", "root", true); + + core.Arquivo arq1 = (core.Arquivo) sistema.buscarElementoTeste("/backup/original.txt"); + core.Arquivo arq2 = (core.Arquivo) sistema.buscarElementoTeste("/backup/subpasta/arq2.txt"); + assertNotNull(arq1); + assertNotNull(arq2); + } +} \ No newline at end of file diff --git a/tests/PermissionTest.java b/tests/PermissionTest.java index 6026e31..2e86876 100644 --- a/tests/PermissionTest.java +++ b/tests/PermissionTest.java @@ -1,26 +1,95 @@ package tests; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.*; + +import java.util.ArrayList; +import java.util.List; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.Assertions.*; import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; import filesys.FileSystemImpl; import filesys.IFileSystem; +import core.Usuario; +import exception.PermissaoException; -// Essa classe testa cenários de permissão public class PermissionTest { - private static IFileSystem fileSystem; + private static IFileSystem sistema; + static List usuarios = new ArrayList<>(); @BeforeAll - public static void setUp() { - fileSystem = new FileSystemImpl(/*args...*/); + public static void preparar() { + sistema = new FileSystemImpl(usuarios); } @Test - public void testPermission() { - // Teste de permissão - assertTrue(true); + public void rootSemprePodeCriarDiretorio() { + // O usuário root deve conseguir criar qualquer diretório + assertDoesNotThrow(() -> sistema.mkdir("/diretorio", "root")); + } + + @Test + public void leituraDiretorio_RespeitaPermissao() throws Exception { + sistema.mkdir("/area", "root"); + sistema.touch("/area/doc.txt", "root"); + + // root tem leitura garantida + assertDoesNotThrow(() -> sistema.ls("/area", "root", false)); + + // Retira permissão de leitura do usuário joao + sistema.chmod("/area", "root", "joao", "---"); + assertThrows(PermissaoException.class, () -> sistema.ls("/area", "joao", false)); + + // Concede permissão de leitura novamente + sistema.chmod("/area", "root", "joao", "r--"); + assertDoesNotThrow(() -> sistema.ls("/area", "joao", false)); + } + + @Test + public void escritaArquivo_RespeitaPermissao() throws Exception { + sistema.mkdir("/privado", "root"); + + // root pode criar normalmente + assertDoesNotThrow(() -> sistema.touch("/privado/novo.txt", "root")); + + // Bloqueia escrita para joao + sistema.chmod("/privado", "root", "joao", "r--"); + assertThrows(PermissaoException.class, () -> sistema.touch("/privado/joao.txt", "joao")); + + // Libera escrita para joao + sistema.chmod("/privado", "root", "joao", "rw-"); + assertDoesNotThrow(() -> sistema.touch("/privado/joao2.txt", "joao")); + } + + @Test + public void execucaoDiretorio_RespeitaPermissao() throws Exception { + sistema.mkdir("/execs", "root"); + + // Remove permissão de execução de joao + sistema.chmod("/execs", "root", "joao", "rw-"); + // Não deve conseguir criar subdiretório sem 'x' + assertThrows(PermissaoException.class, () -> sistema.mkdir("/execs/sub", "joao")); + + // Permite execução para joao + sistema.chmod("/execs", "root", "joao", "rwx"); + assertDoesNotThrow(() -> sistema.mkdir("/execs/sub", "joao")); + } + + @Test + public void herancaPermissaoDiretorio() throws Exception { + sistema.mkdir("/topo", "root"); + sistema.mkdir("/topo/ramo", "root"); + + // Permissão concedida apenas no topo + sistema.chmod("/topo", "root", "joao", "rwx"); + // Deve herdar permissão do topo + assertDoesNotThrow(() -> sistema.mkdir("/topo/ramo/folha", "joao")); + + // Remove permissão do topo, concede só no ramo + sistema.chmod("/topo", "root", "joao", "---"); + sistema.chmod("/topo/ramo", "root", "joao", "rwx"); + // Agora só pode criar em ramo, não em topo + assertThrows(PermissaoException.class, () -> sistema.mkdir("/topo/novo", "joao")); + assertDoesNotThrow(() -> sistema.mkdir("/topo/ramo/novo", "joao")); } -} +} \ No newline at end of file From a2526fcbbe04e831f06bd46b0658640324c8b564 Mon Sep 17 00:00:00 2001 From: GiulianoLBP <112990487+GiulianoLBP@users.noreply.github.com> Date: Mon, 23 Jun 2025 19:10:07 -0300 Subject: [PATCH 2/2] . --- filesys/FileSystemImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/filesys/FileSystemImpl.java b/filesys/FileSystemImpl.java index 6ed6f28..e9af4d1 100644 --- a/filesys/FileSystemImpl.java +++ b/filesys/FileSystemImpl.java @@ -264,6 +264,6 @@ private ElementoFS copiarElemento(ElementoFS elemento, boolean recursivo) { } public void addUser(String user) { - // Implemente se desejar gerenciar usuários dinamicamente + throw new UnsupportedOperationException("Esse metodo não foi implementado 'addUser'"); } } \ No newline at end of file