From c342893e5f9320d2b7e9898558b5a0a00b3bf537 Mon Sep 17 00:00:00 2001 From: gabi Date: Wed, 7 May 2025 13:19:19 -0300 Subject: [PATCH 01/20] implement FileSystem classes with basic directory and file management --- filesys/FileSystemImpl.java | 14 ++++++++-- model/Arquivo.java | 29 ++++++++++++++++++++ model/Diretorio.java | 54 +++++++++++++++++++++++++++++++++++++ model/ElementoFS.java | 49 +++++++++++++++++++++++++++++++++ model/Permissao.java | 31 +++++++++++++++++++++ model/Usuario.java | 5 ++++ 6 files changed, 180 insertions(+), 2 deletions(-) create mode 100644 model/Arquivo.java create mode 100644 model/Diretorio.java create mode 100644 model/ElementoFS.java create mode 100644 model/Permissao.java create mode 100644 model/Usuario.java diff --git a/filesys/FileSystemImpl.java b/filesys/FileSystemImpl.java index 45fa05d..21eea83 100644 --- a/filesys/FileSystemImpl.java +++ b/filesys/FileSystemImpl.java @@ -3,6 +3,7 @@ import exception.CaminhoJaExistenteException; import exception.CaminhoNaoEncontradoException; import exception.PermissaoException; +import model.Diretorio; // Implemente nesta classe o seu código do FileSystem. // A classe pode ser alterada. @@ -10,11 +11,20 @@ // 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 - - public FileSystemImpl() {} + private Diretorio raiz; + + public FileSystemImpl() { + //cria o diretório raiz + raiz = new Diretorio("","/", "root"); + } @Override public void mkdir(String caminho, String nome) throws CaminhoJaExistenteException, PermissaoException { + if (raiz == null) { + throw new IllegalStateException("Diretório raiz não inicializado."); + } + + System.out.println("Criando diretório em: " + raiz.getNome()); throw new UnsupportedOperationException("Método não implementado 'mkdir'"); } diff --git a/model/Arquivo.java b/model/Arquivo.java new file mode 100644 index 0000000..9fcd930 --- /dev/null +++ b/model/Arquivo.java @@ -0,0 +1,29 @@ +package model; + +public class Arquivo { + //representa um arquivo com conteúdo + private String nome; + private String caminhoCompleto; + private String dono; + private String conteudo; + private Permissao permissoes; + + public Arquivo(String nome, String caminhoCompleto, String dono) { + this.nome = nome; + this.caminhoCompleto = caminhoCompleto; + this.dono = dono; + this.conteudo = ""; + this.permissoes = new Permissao(); + this.permissoes.definirPermissao(dono, "rw"); + } + + public String getNome() { return nome; } + public String getCaminhoCompleto() { return caminhoCompleto; } + public String getDono() { return dono; } + public String getConteudo() { return conteudo; } + public Permissao getPermissoes() { return permissoes; } + + public void escreverConteudo(String novoConteudo) { + this.conteudo = novoConteudo; + } +} diff --git a/model/Diretorio.java b/model/Diretorio.java new file mode 100644 index 0000000..83d36e5 --- /dev/null +++ b/model/Diretorio.java @@ -0,0 +1,54 @@ +package model; + +import java.util.*; + +public class Diretorio { + //representa uma pasta + private String nome; + private String caminhoCompleto; + private String dono; + private Map subdiretorios; + private Map arquivos; + private Permissao permissoes; + + public Diretorio(String nome, String caminhoCompleto, String dono) { + this.nome = nome; + this.caminhoCompleto = caminhoCompleto; + this.dono = dono; + this.subdiretorios = new HashMap<>(); + this.arquivos = new HashMap<>(); + this.permissoes = new Permissao(); + this.permissoes.definirPermissao(dono, "rw"); // dono pode tudo + } + + public String getNome() { return nome; } + public String getCaminhoCompleto() { return caminhoCompleto; } + public String getDono() { return dono; } + public Map getSubdiretorios() { return subdiretorios; } + public Map getArquivos() { return arquivos; } + public Permissao getPermissoes() { return permissoes; } + + public void adicionarDiretorio(Diretorio dir) { + subdiretorios.put(dir.getNome(), dir); + } + + public void adicionarArquivo(Arquivo arq) { + arquivos.put(arq.getNome(), arq); + } + + public Diretorio getSubdiretorio(String nome) { + return subdiretorios.get(nome); + } + + public Arquivo getArquivo(String nome) { + return arquivos.get(nome); + } + + public boolean contemDiretorio(String nome) { + return subdiretorios.containsKey(nome); + } + + public boolean contemArquivo(String nome) { + return arquivos.containsKey(nome); + } +} diff --git a/model/ElementoFS.java b/model/ElementoFS.java new file mode 100644 index 0000000..8cd00e1 --- /dev/null +++ b/model/ElementoFS.java @@ -0,0 +1,49 @@ +package model; + +import java.util.HashMap; +import java.util.Map; + +public abstract class ElementoFS { + protected String nome; + protected String caminho; + protected String dono; + protected Map permissoes; // Ex: usuario → "rw" + + public ElementoFS(String nome, String caminho, String dono) { + this.nome = nome; + this.caminho = caminho; + this.dono = dono; + this.permissoes = new HashMap<>(); + this.permissoes.put(dono, "rw"); // Dono começa com permissão total + } + + public String getNome() { + return nome; + } + + public String getCaminho() { + return caminho; + } + + public String getDono() { + return dono; + } + + public void setPermissao(String usuario, String permissao) { + permissoes.put(usuario, permissao); + } + + public String getPermissao(String usuario) { + return permissoes.getOrDefault(usuario, ""); + } + + public boolean temPermissaoLeitura(String usuario) { + return getPermissao(usuario).contains("r") || usuario.equals("root"); + } + + public boolean temPermissaoEscrita(String usuario) { + return getPermissao(usuario).contains("w") || usuario.equals("root"); + } + + public abstract boolean ehDiretorio(); // Pra saber se é pasta ou não +} diff --git a/model/Permissao.java b/model/Permissao.java new file mode 100644 index 0000000..50be058 --- /dev/null +++ b/model/Permissao.java @@ -0,0 +1,31 @@ +package model; + +import java.util.HashMap; +import java.util.Map; + +public class Permissao { + //quem pode fazer o quê é definido aqui + private Map permissoesPorUsuario; + + public Permissao() { + this.permissoesPorUsuario = new HashMap<>(); + } + + public void definirPermissao(String usuario, String permissao) { + permissoesPorUsuario.put(usuario, permissao); // ex: "rw", "r", "-" + } + + public boolean podeLer(String usuario) { + String p = permissoesPorUsuario.getOrDefault(usuario, ""); + return p.contains("r"); + } + + public boolean podeEscrever(String usuario) { + String p = permissoesPorUsuario.getOrDefault(usuario, ""); + return p.contains("w"); + } + + public String getPermissao(String usuario) { + return permissoesPorUsuario.getOrDefault(usuario, "-"); + } +} diff --git a/model/Usuario.java b/model/Usuario.java new file mode 100644 index 0000000..ce4a7ba --- /dev/null +++ b/model/Usuario.java @@ -0,0 +1,5 @@ +package model; + +public class Usuario { + +} From a0a34def707c86a18728137c054154ce3e12edd4 Mon Sep 17 00:00:00 2001 From: gabi Date: Tue, 20 May 2025 20:06:06 -0300 Subject: [PATCH 02/20] refactor: update Arquivo and Diretorio classes to extend ElementoFS and improve structure --- model/Arquivo.java | 94 +++++++++++++++++++++++++++++++------------ model/Diretorio.java | 95 +++++++++++++++++++++++++++----------------- 2 files changed, 128 insertions(+), 61 deletions(-) diff --git a/model/Arquivo.java b/model/Arquivo.java index 9fcd930..ce3691e 100644 --- a/model/Arquivo.java +++ b/model/Arquivo.java @@ -1,29 +1,73 @@ package model; -public class Arquivo { - //representa um arquivo com conteúdo - private String nome; - private String caminhoCompleto; - private String dono; - private String conteudo; - private Permissao permissoes; - - public Arquivo(String nome, String caminhoCompleto, String dono) { - this.nome = nome; - this.caminhoCompleto = caminhoCompleto; - this.dono = dono; - this.conteudo = ""; - this.permissoes = new Permissao(); - this.permissoes.definirPermissao(dono, "rw"); - } - - public String getNome() { return nome; } - public String getCaminhoCompleto() { return caminhoCompleto; } - public String getDono() { return dono; } - public String getConteudo() { return conteudo; } - public Permissao getPermissoes() { return permissoes; } - - public void escreverConteudo(String novoConteudo) { - this.conteudo = novoConteudo; +import java.util.ArrayList; +import java.util.List; + +public class Arquivo extends ElementoFS { + private List blocos; + private long tamanho; + + public Arquivo(String nome, String permissoes, String dono) { + super(nome, permissoes, dono); + // this.arquivo = new Bloco[0]; + this.blocos = new ArrayList<>(); + this.tamanho = 0; + } + + /* + * public Bloco[] getArquivo() { + * return arquivo; + * } + * + * public void setArquivo(Bloco[] arquivo) { + * this.arquivo = arquivo; + * } + */ + + public void adicionarBloco(byte[] dados) { + blocos.add(dados); + tamanho += dados.length; + } + + public List getBlocos() { + return blocos; + } + + public long getTamanho() { + return tamanho; + } + + public void removerBloco(int index) { + if (index < 0 || index >= blocos.size()) { + throw new IndexOutOfBoundsException("Índice fora dos limites da lista."); + } + byte[] removed = blocos.remove(index); + tamanho -= removed.length; + } + + public void limparBlocos() { + blocos.clear(); + tamanho = 0; + } + + @Override + public boolean isArquivo() { + return true; + } + + @Override + public String toString() { + return "Arquivo: " + nomeDiretorio + " | Dono: " + donoDiretorio + " | Permissões: " + permissoesPadrao + " | Tam: " + + tamanho + " bytes"; + } + + public void adicionarFilho(ElementoFS filho) { + throw new UnsupportedOperationException("Não é possível adicionar filhos a um arquivo."); + } + + + public void removerFilho(String nomeFilho) { + throw new UnsupportedOperationException("Não é possível remover filhos de um arquivo."); } + } diff --git a/model/Diretorio.java b/model/Diretorio.java index 83d36e5..c5f6498 100644 --- a/model/Diretorio.java +++ b/model/Diretorio.java @@ -1,54 +1,77 @@ package model; -import java.util.*; +import java.util.HashMap; +import java.util.Map; -public class Diretorio { - //representa uma pasta - private String nome; - private String caminhoCompleto; - private String dono; - private Map subdiretorios; - private Map arquivos; - private Permissao permissoes; +public class Diretorio extends ElementoFS { + private Diretorio diretorioPai; + private Map filhos; + private Map acessosPorUsuario; // permissões específicas - public Diretorio(String nome, String caminhoCompleto, String dono) { - this.nome = nome; - this.caminhoCompleto = caminhoCompleto; - this.dono = dono; - this.subdiretorios = new HashMap<>(); - this.arquivos = new HashMap<>(); - this.permissoes = new Permissao(); - this.permissoes.definirPermissao(dono, "rw"); // dono pode tudo + public Diretorio(String nome, String permissoes, String dono) { + super(nome, permissoes, dono); + if (permissoes == null || permissoes.length() != 3) { + throw new IllegalArgumentException("Permissões devem conter 3 caracteres (rwx)"); + } + this.filhos = new HashMap<>(); + this.acessosPorUsuario = new HashMap<>(); } - public String getNome() { return nome; } - public String getCaminhoCompleto() { return caminhoCompleto; } - public String getDono() { return dono; } - public Map getSubdiretorios() { return subdiretorios; } - public Map getArquivos() { return arquivos; } - public Permissao getPermissoes() { return permissoes; } + public void setPermissaoUsuario(String nomeUsuario, String permissoes) { + if (permissoes == null || permissoes.length() != 3) { + throw new IllegalArgumentException("Permissões devem conter 3 caracteres (rwx)"); + } + acessosPorUsuario.put(nomeUsuario, permissoes); + } + + public boolean temPermissao(String usuario, char tipoPermissao) { + if ("root".equals(usuario)) return true; + if (usuario.equals(donoDiretorio)) return permissoesPadrao.indexOf(tipoPermissao) >= 0; + String permissoesUsuario = acessosPorUsuario.get(usuario); + if (permissoesUsuario != null && permissoesUsuario.indexOf(tipoPermissao) >= 0) return true; + if (diretorioPai != null) return diretorioPai.temPermissao(usuario, tipoPermissao); + return false; + } + + public String obterPermissoesDoUsuario(String usuario) { + if ("root".equals(usuario)) return "rwx"; + if (usuario.equals(donoDiretorio)) return permissoesPadrao; + return acessosPorUsuario.getOrDefault(usuario, "---"); + } + + public void adicionarFilho(ElementoFS filho) { + if (filhos.containsKey(filho.getNomeDiretorio())) { + throw new IllegalArgumentException("Já existe um filho com este nome: " + filho.getNomeDiretorio()); + } + if (filho instanceof Diretorio) { + ((Diretorio) filho).setDiretorioPai(this); + } + filhos.put(filho.getNomeDiretorio(), filho); + } - public void adicionarDiretorio(Diretorio dir) { - subdiretorios.put(dir.getNome(), dir); + public void removerFilho(String nomeFilho) { + filhos.remove(nomeFilho); } - public void adicionarArquivo(Arquivo arq) { - arquivos.put(arq.getNome(), arq); + public Map getFilhos() { + return filhos; } - public Diretorio getSubdiretorio(String nome) { - return subdiretorios.get(nome); + public Diretorio getDiretorioPai() { + return diretorioPai; } - public Arquivo getArquivo(String nome) { - return arquivos.get(nome); + public void setDiretorioPai(Diretorio diretorioPai) { + this.diretorioPai = diretorioPai; } - public boolean contemDiretorio(String nome) { - return subdiretorios.containsKey(nome); + @Override + public boolean isArquivo() { + return false; } - public boolean contemArquivo(String nome) { - return arquivos.containsKey(nome); + @Override + public String toString() { + return "Dir: " + nomeDiretorio + " | Owner: " + donoDiretorio + " | Perms: " + permissoesPadrao; } -} +} \ No newline at end of file From 6f405732eac3f7b4a413e265e21a2e3773bd28af Mon Sep 17 00:00:00 2001 From: gabi Date: Tue, 20 May 2025 20:06:30 -0300 Subject: [PATCH 03/20] feat: add Bloco and Offset classes for block and offset management --- model/Bloco.java | 19 ++++++++++++++++ model/ElementoFS.java | 52 +++++++++++++++++------------------------- model/Offset.java | 53 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 93 insertions(+), 31 deletions(-) create mode 100644 model/Bloco.java create mode 100644 model/Offset.java diff --git a/model/Bloco.java b/model/Bloco.java new file mode 100644 index 0000000..ae04dbd --- /dev/null +++ b/model/Bloco.java @@ -0,0 +1,19 @@ +package model; + +public class Bloco { + private static final int TAMANHO_BLOCO = 4096; // 4KB por bloco + private byte[] dados; + + + public Bloco(int tamanho) { + this.dados = new byte[TAMANHO_BLOCO]; + } + + public byte[] getDados() { + return dados; + } + + public void setDados(byte[] dados) { + this.dados = dados; + } +} \ No newline at end of file diff --git a/model/ElementoFS.java b/model/ElementoFS.java index 8cd00e1..9de3707 100644 --- a/model/ElementoFS.java +++ b/model/ElementoFS.java @@ -1,49 +1,39 @@ package model; -import java.util.HashMap; -import java.util.Map; - public abstract class ElementoFS { - protected String nome; - protected String caminho; - protected String dono; - protected Map permissoes; // Ex: usuario → "rw" - - public ElementoFS(String nome, String caminho, String dono) { - this.nome = nome; - this.caminho = caminho; - this.dono = dono; - this.permissoes = new HashMap<>(); - this.permissoes.put(dono, "rw"); // Dono começa com permissão total - } + protected String nomeDiretorio; + protected String permissoesPadrao; + protected String donoDiretorio; - public String getNome() { - return nome; + public ElementoFS(String nomeDiretorio, String permissoesPadrao, String donoDiretorio) { + this.nomeDiretorio = nomeDiretorio; + this.permissoesPadrao = permissoesPadrao; + this.donoDiretorio = donoDiretorio; } - public String getCaminho() { - return caminho; + public String getNomeDiretorio() { + return nomeDiretorio; } - public String getDono() { - return dono; + public void setNomeDiretorio(String nomeDiretorio) { + this.nomeDiretorio = nomeDiretorio; } - public void setPermissao(String usuario, String permissao) { - permissoes.put(usuario, permissao); + public String getPermissoesPadrao() { + return permissoesPadrao; } - public String getPermissao(String usuario) { - return permissoes.getOrDefault(usuario, ""); + public void setPermissoesPadrao(String permissoesPadrao) { + this.permissoesPadrao = permissoesPadrao; } - public boolean temPermissaoLeitura(String usuario) { - return getPermissao(usuario).contains("r") || usuario.equals("root"); + public String getDonoDiretorio() { + return donoDiretorio; } - public boolean temPermissaoEscrita(String usuario) { - return getPermissao(usuario).contains("w") || usuario.equals("root"); + public void setDonoDiretorio(String donoDiretorio) { + this.donoDiretorio = donoDiretorio; } - public abstract boolean ehDiretorio(); // Pra saber se é pasta ou não -} + public abstract boolean isArquivo(); +} \ No newline at end of file diff --git a/model/Offset.java b/model/Offset.java new file mode 100644 index 0000000..9d653db --- /dev/null +++ b/model/Offset.java @@ -0,0 +1,53 @@ +package model; + +public class Offset { + private int valor; + private int max; + + public Offset() { + this.valor = 0; + this.max = Integer.MAX_VALUE; + } + + public Offset(int valorInicial) { + this.valor = valorInicial; + this.max = Integer.MAX_VALUE; + } + + public Offset(int valorInicial, int max) { + this.valor = valorInicial; + this.max = max; + } + + public int getValor() { + return valor; + } + + public void setValor(int valor) { + if (valor < 0) { + throw new IllegalArgumentException("Offset não pode ser negativo."); + } + if (valor > max) { + throw new IllegalArgumentException("Offset excede o valor máximo permitido (" + max + ")."); + } + this.valor = valor; + } + + public void incrementar(int delta) { + setValor(this.valor + delta); + } + + public void resetar() { + this.valor = 0; + } + + public int getMax() { + return max; + } + + public void setMax(int max) { + if (max < 0) throw new IllegalArgumentException("Max deve ser positivo."); + this.max = max; + if (valor > max) valor = max; + } +} From 0d1ebe25ef177831e97ddf5d1435448b0009d955 Mon Sep 17 00:00:00 2001 From: gabi Date: Tue, 20 May 2025 20:33:17 -0300 Subject: [PATCH 04/20] feat: implement FileSystemImpl with user and permission management --- filesys/FileSystemImpl.java | 126 +++++++++++++++++++++++++++++++----- filesys/IFileSystem.java | 3 +- 2 files changed, 111 insertions(+), 18 deletions(-) diff --git a/filesys/FileSystemImpl.java b/filesys/FileSystemImpl.java index 21eea83..976749f 100644 --- a/filesys/FileSystemImpl.java +++ b/filesys/FileSystemImpl.java @@ -3,78 +3,170 @@ import exception.CaminhoJaExistenteException; import exception.CaminhoNaoEncontradoException; import exception.PermissaoException; +import model.Arquivo; import model.Diretorio; +import model.ElementoFS; +import model.Usuario; -// 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 +import java.util.HashMap; +import java.util.Map; + +/** + * Classe {@code FileSystemImpl} implementa a interface {@link IFileSystem} e fornece a lógica para um sistema de arquivos + * hierárquico com suporte a permissões de usuários, manipulação de arquivos e diretórios. + * + *

Essa classe gerencia um conjunto de usuários, um diretório raiz e oferece métodos para operações como criação, + * remoção, leitura, escrita, cópia e movimentação de arquivos e diretórios. Além disso, permite a configuração de + * permissões específicas para usuários em diferentes caminhos do sistema de arquivos. + * + *

O sistema de arquivos é inicializado com um diretório raiz ("/") e um usuário padrão ("root") com permissões + * completas. Usuários adicionais podem ser adicionados e gerenciados dinamicamente. + * + *

Principais funcionalidades: + *

    + *
  • Gerenciamento de usuários e permissões.
  • + *
  • Criação e remoção de arquivos e diretórios.
  • + *
  • Leitura e escrita em arquivos.
  • + *
  • Movimentação e cópia de arquivos e diretórios.
  • + *
  • Listagem de conteúdo de diretórios com suporte a recursividade.
  • + *
+ * + *

Exceções específicas são lançadas para tratar erros como permissões insuficientes, caminhos inexistentes, + * ou tentativas de operações inválidas. + * + *

Essa classe é imutável no sentido de que não permite a modificação direta de seus atributos internos, + * mas fornece métodos para manipular o estado do sistema de arquivos de forma controlada. + */ public final class FileSystemImpl implements IFileSystem { private static final String ROOT_USER = "root"; // pode ser necessário - private Diretorio raiz; - + private Diretorio raiz; + private Map usuarios = new HashMap<>(); + public FileSystemImpl() { - //cria o diretório raiz - raiz = new Diretorio("","/", "root"); + this.raiz = new Diretorio("/", "rwx", ROOT_USER); + usuarios.put(ROOT_USER, new Usuario(ROOT_USER, "rwx", "/")); + // TODO: Carregar usuários adicionais do arquivo users/users se necessário } - @Override - public void mkdir(String caminho, String nome) throws CaminhoJaExistenteException, PermissaoException { - if (raiz == null) { - throw new IllegalStateException("Diretório raiz não inicializado."); + // TODO: Validar se o método navegar cobre todos os casos de caminhos relativos e absolutos + private ElementoFS navegar(String caminho) throws CaminhoNaoEncontradoException { + if (caminho.equals("/")) return raiz; + String[] partes = caminho.split("/"); + Diretorio atual = raiz; + for (int i = 1; i < partes.length; i++) { + ElementoFS filho = atual.getFilhos().get(partes[i]); + if (filho == null) throw new CaminhoNaoEncontradoException("Caminho não encontrado: " + caminho); + if (i == partes.length - 1) return filho; + if (!filho.isArquivo()) { + atual = (Diretorio) filho; + } else { + throw new CaminhoNaoEncontradoException("Caminho não encontrado (esperado diretório): " + caminho); + } } + return atual; + } - System.out.println("Criando diretório em: " + raiz.getNome()); - throw new UnsupportedOperationException("Método não implementado 'mkdir'"); + @Override + public void mkdir(String caminho, String usuario) throws CaminhoJaExistenteException, PermissaoException { + if (caminho.equals("/")) return; + String[] partes = caminho.split("/"); + Diretorio atual = raiz; + for (int i = 1; i < partes.length - 1; i++) { + ElementoFS filho = atual.getFilhos().get(partes[i]); + if (filho == null || filho.isArquivo()) throw new PermissaoException("Diretório intermediário não existe: " + partes[i]); + atual = (Diretorio) filho; + } + String nomeNovo = partes[partes.length - 1]; + if (atual.getFilhos().containsKey(nomeNovo)) throw new CaminhoJaExistenteException("Já existe: " + caminho); + if (!atual.temPermissao(usuario, 'w')) throw new PermissaoException("Sem permissão para criar em: " + caminho); + atual.adicionarFilho(new Diretorio(nomeNovo, "rwx", usuario)); + // TODO: Permitir criar diretórios recursivamente (mkdir -p) se necessário } @Override public void chmod(String caminho, String usuario, String usuarioAlvo, String permissao) throws CaminhoNaoEncontradoException, PermissaoException { - throw new UnsupportedOperationException("Método não implementado 'chmod'"); + ElementoFS elem = navegar(caminho); + if (!elem.getDonoDiretorio().equals(usuario) && !usuario.equals(ROOT_USER)) { + throw new PermissaoException("Apenas o dono ou root pode alterar permissões."); + } + if (elem instanceof Diretorio) { + ((Diretorio) elem).setPermissaoUsuario(usuarioAlvo, permissao); + } else { + elem.setPermissoesPadrao(permissao); + } + // TODO: Validar permissões para arquivos se for necessário permissões específicas por usuário } + // TODO: Implementar método rm (remoção de arquivos/diretórios) @Override public void rm(String caminho, String usuario, boolean recursivo) throws CaminhoNaoEncontradoException, PermissaoException { + // TODO: Implementar lógica de remoção (verificar se é arquivo ou diretório, permissões, recursividade) throw new UnsupportedOperationException("Método não implementado 'rm'"); } @Override public void touch(String caminho, String usuario) throws CaminhoJaExistenteException, PermissaoException { - throw new UnsupportedOperationException("Método não implementado 'touch'"); + if (caminho.equals("/") || caminho.endsWith("/")) throw new IllegalArgumentException("Nome de arquivo inválido."); + int lastSlash = caminho.lastIndexOf('/'); + String caminhoPai = (lastSlash <= 0) ? "/" : caminho.substring(0, lastSlash); + String nomeArquivo = caminho.substring(lastSlash + 1); + Diretorio pai; + try { + pai = (Diretorio) navegar(caminhoPai); + } catch (CaminhoNaoEncontradoException e) { + throw new PermissaoException("Diretório pai não encontrado: " + caminhoPai); + } + if (pai.getFilhos().containsKey(nomeArquivo)) throw new CaminhoJaExistenteException("Arquivo já existe: " + nomeArquivo); + if (!pai.temPermissao(usuario, 'w')) throw new PermissaoException("Sem permissão para criar arquivo em: " + caminhoPai); + pai.adicionarFilho(new Arquivo(nomeArquivo, "rw-", usuario)); + // TODO: Permitir criar arquivos com permissões diferentes se necessário } + // TODO: Implementar método write (escrita em arquivos) @Override public void write(String caminho, String usuario, boolean anexar, byte[] buffer) throws CaminhoNaoEncontradoException, PermissaoException { + // TODO: Implementar lógica de escrita (dividir em blocos, verificar permissões, append ou sobrescrever) throw new UnsupportedOperationException("Método não implementado 'write'"); } + // TODO: Implementar método read (leitura de arquivos) @Override public void read(String caminho, String usuario, byte[] buffer) throws CaminhoNaoEncontradoException, PermissaoException { + // TODO: Implementar lógica de leitura (ler em blocos, permissões, tratar arquivos grandes) throw new UnsupportedOperationException("Método não implementado 'read'"); } + // TODO: Implementar método mv (movimentação/renomeação) @Override public void mv(String caminhoAntigo, String caminhoNovo, String usuario) throws CaminhoNaoEncontradoException, PermissaoException { + // TODO: Implementar lógica de movimentação/renomeação (verificar permissões, atualizar árvore) throw new UnsupportedOperationException("Método não implementado 'mv'"); } + // TODO: Implementar método ls (listagem de diretórios) @Override public void ls(String caminho, String usuario, boolean recursivo) throws CaminhoNaoEncontradoException, PermissaoException { + // TODO: Implementar lógica de listagem (mostrar arquivos/diretórios, recursivo ou não, permissões) throw new UnsupportedOperationException("Método não implementado 'ls'"); } + // TODO: Implementar método cp (cópia de arquivos/diretórios) @Override public void cp(String caminhoOrigem, String caminhoDestino, String usuario, boolean recursivo) throws CaminhoNaoEncontradoException, PermissaoException { + // TODO: Implementar lógica de cópia (copiar arquivos/diretórios, recursivo, permissões) throw new UnsupportedOperationException("Método não implementado 'cp'"); } + // TODO: Implementar carregamento de usuários a partir do arquivo users/users se necessário public void addUser(String user) { throw new UnsupportedOperationException("Método não implementado 'addUser'"); } -} + + // TODO: Adicionar métodos auxiliares para facilitar operações recursivas, busca de pai, etc. +} \ No newline at end of file diff --git a/filesys/IFileSystem.java b/filesys/IFileSystem.java index a0f0ce0..7b3409e 100644 --- a/filesys/IFileSystem.java +++ b/filesys/IFileSystem.java @@ -44,4 +44,5 @@ public interface IFileSystem { // Copia um arquivo ou diretório. Se o diretório não existir, será lançada uma exceção. void cp(String caminhoOrigem, String caminhoDestino, String usuario, boolean recursivo) throws CaminhoNaoEncontradoException, PermissaoException; -} \ No newline at end of file +} + From 1f27ad21aa14fe92b5bc0c4d070181826b75ba6d Mon Sep 17 00:00:00 2001 From: gabi Date: Tue, 20 May 2025 20:33:25 -0300 Subject: [PATCH 05/20] test: add unit tests for FileSystemImpl methods --- tests/FileSystemImplTest.java | 73 +++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 tests/FileSystemImplTest.java diff --git a/tests/FileSystemImplTest.java b/tests/FileSystemImplTest.java new file mode 100644 index 0000000..ac05170 --- /dev/null +++ b/tests/FileSystemImplTest.java @@ -0,0 +1,73 @@ +package tests; + +import exception.CaminhoJaExistenteException; +import exception.CaminhoNaoEncontradoException; +import exception.PermissaoException; +import filesys.FileSystemImpl; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class FileSystemImplTest { + private FileSystemImpl fs; + + @BeforeEach + void setUp() { + fs = new FileSystemImpl(); + } + + @Test + void mkdir_CriaDiretorioComSucesso() throws Exception { + fs.mkdir("/docs", "root"); + assertDoesNotThrow(() -> fs.mkdir("/docs2", "root")); + } + + @Test + void mkdir_LancaExcecaoSeDiretorioJaExiste() throws Exception { + fs.mkdir("/docs", "root"); + assertThrows(CaminhoJaExistenteException.class, () -> fs.mkdir("/docs", "root")); + } + + @Test + void mkdir_LancaExcecaoSeUsuarioSemPermissao() throws Exception { + fs.mkdir("/docs", "root"); + assertThrows(PermissaoException.class, () -> fs.mkdir("/docs/privado", "usuario")); + } + + @Test + void touch_CriaArquivoComSucesso() throws Exception { + fs.mkdir("/docs", "root"); + fs.touch("/docs/arquivo.txt", "root"); + assertThrows(CaminhoJaExistenteException.class, () -> fs.touch("/docs/arquivo.txt", "root")); + } + + @Test + void touch_LancaExcecaoSeUsuarioSemPermissao() throws Exception { + fs.mkdir("/docs", "root"); + assertThrows(PermissaoException.class, () -> fs.touch("/docs/novo.txt", "usuario")); + } + + @Test + void chmod_AlteraPermissaoComSucesso() throws Exception { + fs.mkdir("/docs", "root"); + assertDoesNotThrow(() -> fs.chmod("/docs", "root", "usuario", "rwx")); + } + + @Test + void chmod_LancaExcecaoSeUsuarioSemPermissao() throws Exception { + fs.mkdir("/docs", "root"); + assertThrows(PermissaoException.class, () -> fs.chmod("/docs", "usuario", "usuario", "rwx")); + } + + @Test + void chmod_LancaExcecaoSeCaminhoNaoExiste() { + assertThrows(CaminhoNaoEncontradoException.class, () -> fs.chmod("/naoexiste", "root", "root", "rwx")); + } + + // TODO: Adicionar testes unitários para rm + // TODO: Adicionar testes unitários para write/read + // TODO: Adicionar testes unitários para mv + // TODO: Adicionar testes unitários para ls + // TODO: Adicionar testes unitários para cp +} From e68f3383de7c69a15e03e79df080d2bed0b2595b Mon Sep 17 00:00:00 2001 From: gabi Date: Tue, 20 May 2025 20:34:21 -0300 Subject: [PATCH 06/20] feat: implement Usuario class with attributes and methods for user management --- model/Usuario.java | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/model/Usuario.java b/model/Usuario.java index ce4a7ba..9b6a04d 100644 --- a/model/Usuario.java +++ b/model/Usuario.java @@ -1,5 +1,45 @@ package model; public class Usuario { + private String nome; + private String diretorio; + private String permissao; + public Usuario(String nome, String permissao, String diretorio) { + this.setNome(nome); + this.setPermissao(permissao); + this.setDiretorio(diretorio); + } + + public String getNome() { + return nome; + } + + public String getPermissao() { + return permissao; + } + + public void setPermissao(String permissao) { + this.permissao = permissao; + } + + public void setNome(String nome) { + this.nome = nome; + } + + public void setDiretorio(String diretorio) { + this.diretorio = diretorio; + } + + @Override + public String toString() { + return "Usuario{" + + "nome='" + nome + '\'' + + ", permissao='" + permissao + '\'' + + ", diretorio='" + diretorio + '\'' + + '}'; + } + + + } From 05cc076ef7c420a1fa7c8bda3e09532a051148bc Mon Sep 17 00:00:00 2001 From: gabi Date: Tue, 20 May 2025 20:34:34 -0300 Subject: [PATCH 07/20] feat: add project checklist for POSIX file system implementation --- CHECKLIST_DO_GRUPO.md | 84 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 CHECKLIST_DO_GRUPO.md diff --git a/CHECKLIST_DO_GRUPO.md b/CHECKLIST_DO_GRUPO.md new file mode 100644 index 0000000..812cd65 --- /dev/null +++ b/CHECKLIST_DO_GRUPO.md @@ -0,0 +1,84 @@ +# Checklist do Projeto - Sistema de Arquivos POSIX + +OIII! +Segue um checklist detalhado do que ainda falta fazer no nosso projeto, com explicações simples para cada item. +Se tiverem dúvidas, podem perguntar! + +--- + +## 1. Métodos principais do sistema de arquivos + +Ainda precisamos implementar os métodos principais que fazem o sistema funcionar, conforme pede o professor. +Esses métodos são chamados quando o usuário executa comandos como criar, remover, copiar, mover arquivos e diretórios. + +**Faltam implementar:** +- `rm` — Remover arquivos ou diretórios (com opção de apagar tudo dentro, se for recursivo) +- `write` — Escrever dados em um arquivo (pode ser para sobrescrever ou adicionar ao final) +- `read` — Ler dados de um arquivo (precisa ler em partes se o arquivo for grande) +- `mv` — Mover ou renomear arquivos/diretórios +- `ls` — Listar o conteúdo de um diretório (mostrar arquivos e subdiretórios) +- `cp` — Copiar arquivos ou diretórios (com opção de copiar tudo dentro, se for recursivo) + +**No código, já deixei `// TODO` nesses métodos para facilitar achar onde falta implementar. +O VS Code mostra uma linha azul do lado esquerdo nesses pontos.** + +--- + +## 2. Testes Unitários + +**Faltam testes para:** +- Remover arquivos/diretórios (`rm`) +- Escrever e ler arquivos (`write` e `read`) +- Mover/renomear (`mv`) +- Listar diretórios (`ls`) +- Copiar arquivos/diretórios (`cp`) +- Testar casos de erro (ex: tentar remover sem permissão, tentar ler arquivo inexistente, etc.) +- **Testes de permissão:** Já existe um arquivo chamado `PermissionTest.java` que testa se o sistema está respeitando as permissões de leitura, escrita +e execução para cada usuário. - mas olhem la + +É importante rodar e revisar esses testes para garantir que o controle de acesso está correto. +Não lembro se precisa de mais testes, olha no arquivo :) + +--- + +## 3. Permissões e Exceções + +Em todas as operações, precisamos garantir: +- O usuário só pode fazer a operação se tiver permissão (leitura, escrita, execução) +- Se tentar fazer algo sem permissão, deve lançar uma exceção (erro) +- Se tentar acessar um caminho que não existe, também deve lançar exceção + +**Exemplo:** +Se o usuário "joao" tentar apagar um arquivo que não é dele e não tem permissão, o sistema deve impedir e mostrar um erro. + +--- + +## 4. Menu Interativo + +O menu interativo é fundamental para a apresentação e para o professor testar o sistema. +Ele permite digitar comandos como `mkdir`, `touch`, `ls`, etc., e mostra o resultado na tela. + +**Detalhes importantes:** +- O menu já está implementado na classe `Main.java`. +- Ele lê os usuários do arquivo `users/users`. +- Cada opção do menu chama um método do sistema de arquivos (ex: criar diretório, listar, remover, etc.). +- O menu já trata exceções e mostra mensagens de erro se o usuário não tiver permissão ou se o caminho não existir. +- Para comandos de leitura (`read`), o menu já está preparado para ler arquivos grandes em partes, usando o buffer e o `Offset`. +- **Revisar o menu:** Garantir que todos os comandos estão funcionando, que as mensagens estão claras e que o sistema responde corretamente a erros de permissão e caminhos inválidos. + + +--- + +## 5. Comentários e Documentação + +- Comentar o código explicando o que cada método faz, principalmente os mais importantes. +- Se mudarmos algo na interface fornecida pelo professor, justificar com um comentário. + +nao lembro se eu fiz isso, aaaaaaaaa, FAÇAM!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +--- + +**:p** +- Sempre procure pelos `// TODO` no código para ver o que falta. + +--- From e9ce8f1aae8633370f8667b95757495707c8ba73 Mon Sep 17 00:00:00 2001 From: Gabriela Alvarenga Date: Wed, 21 May 2025 07:42:32 -0300 Subject: [PATCH 08/20] Update FileSystemImpl.java --- filesys/FileSystemImpl.java | 28 +--------------------------- 1 file changed, 1 insertion(+), 27 deletions(-) diff --git a/filesys/FileSystemImpl.java b/filesys/FileSystemImpl.java index 976749f..17ca679 100644 --- a/filesys/FileSystemImpl.java +++ b/filesys/FileSystemImpl.java @@ -11,32 +11,6 @@ import java.util.HashMap; import java.util.Map; -/** - * Classe {@code FileSystemImpl} implementa a interface {@link IFileSystem} e fornece a lógica para um sistema de arquivos - * hierárquico com suporte a permissões de usuários, manipulação de arquivos e diretórios. - * - *

Essa classe gerencia um conjunto de usuários, um diretório raiz e oferece métodos para operações como criação, - * remoção, leitura, escrita, cópia e movimentação de arquivos e diretórios. Além disso, permite a configuração de - * permissões específicas para usuários em diferentes caminhos do sistema de arquivos. - * - *

O sistema de arquivos é inicializado com um diretório raiz ("/") e um usuário padrão ("root") com permissões - * completas. Usuários adicionais podem ser adicionados e gerenciados dinamicamente. - * - *

Principais funcionalidades: - *

    - *
  • Gerenciamento de usuários e permissões.
  • - *
  • Criação e remoção de arquivos e diretórios.
  • - *
  • Leitura e escrita em arquivos.
  • - *
  • Movimentação e cópia de arquivos e diretórios.
  • - *
  • Listagem de conteúdo de diretórios com suporte a recursividade.
  • - *
- * - *

Exceções específicas são lançadas para tratar erros como permissões insuficientes, caminhos inexistentes, - * ou tentativas de operações inválidas. - * - *

Essa classe é imutável no sentido de que não permite a modificação direta de seus atributos internos, - * mas fornece métodos para manipular o estado do sistema de arquivos de forma controlada. - */ public final class FileSystemImpl implements IFileSystem { private static final String ROOT_USER = "root"; // pode ser necessário private Diretorio raiz; @@ -169,4 +143,4 @@ public void addUser(String user) { } // TODO: Adicionar métodos auxiliares para facilitar operações recursivas, busca de pai, etc. -} \ No newline at end of file +} From 9894e1db5df7dc73387bdec3188cd6abe6f23278 Mon Sep 17 00:00:00 2001 From: Gabriela Alvarenga Date: Wed, 21 May 2025 07:43:44 -0300 Subject: [PATCH 09/20] Update CHECKLIST_DO_GRUPO.md --- CHECKLIST_DO_GRUPO.md | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/CHECKLIST_DO_GRUPO.md b/CHECKLIST_DO_GRUPO.md index 812cd65..1085644 100644 --- a/CHECKLIST_DO_GRUPO.md +++ b/CHECKLIST_DO_GRUPO.md @@ -69,12 +69,7 @@ Ele permite digitar comandos como `mkdir`, `touch`, `ls`, etc., e mostra o resul --- -## 5. Comentários e Documentação - -- Comentar o código explicando o que cada método faz, principalmente os mais importantes. -- Se mudarmos algo na interface fornecida pelo professor, justificar com um comentário. - -nao lembro se eu fiz isso, aaaaaaaaa, FAÇAM!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +Não mudem a classe **FileSystem.java**!!! --- From 4f625d816c9f16a760bd6b244b743dbbc898c76f Mon Sep 17 00:00:00 2001 From: CarlosJFigueiredo Date: Thu, 22 May 2025 15:01:54 -0300 Subject: [PATCH 10/20] =?UTF-8?q?feat:=20implementar=20m=C3=A9todos=20de?= =?UTF-8?q?=20remo=C3=A7=C3=A3o=20e=20escrita=20no=20sistema=20de=20arquiv?= =?UTF-8?q?os,=20al=C3=A9m=20de=20adicionar=20testes=20unit=C3=A1rios=20co?= =?UTF-8?q?rrespondentes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHECKLIST_DO_GRUPO.md | 4 +-- filesys/FileSystemImpl.java | 64 ++++++++++++++++++++++++++++++++--- model/Arquivo.java | 10 ++++++ model/ElementoFS.java | 1 + model/Permissao.java | 31 ----------------- tests/FileSystemImplTest.java | 53 +++++++++++++++++++++++++++-- 6 files changed, 124 insertions(+), 39 deletions(-) delete mode 100644 model/Permissao.java diff --git a/CHECKLIST_DO_GRUPO.md b/CHECKLIST_DO_GRUPO.md index 1085644..3d87d25 100644 --- a/CHECKLIST_DO_GRUPO.md +++ b/CHECKLIST_DO_GRUPO.md @@ -12,8 +12,8 @@ Ainda precisamos implementar os métodos principais que fazem o sistema funciona Esses métodos são chamados quando o usuário executa comandos como criar, remover, copiar, mover arquivos e diretórios. **Faltam implementar:** -- `rm` — Remover arquivos ou diretórios (com opção de apagar tudo dentro, se for recursivo) -- `write` — Escrever dados em um arquivo (pode ser para sobrescrever ou adicionar ao final) +- +- - `read` — Ler dados de um arquivo (precisa ler em partes se o arquivo for grande) - `mv` — Mover ou renomear arquivos/diretórios - `ls` — Listar o conteúdo de um diretório (mostrar arquivos e subdiretórios) diff --git a/filesys/FileSystemImpl.java b/filesys/FileSystemImpl.java index 17ca679..f652ce3 100644 --- a/filesys/FileSystemImpl.java +++ b/filesys/FileSystemImpl.java @@ -40,6 +40,10 @@ private ElementoFS navegar(String caminho) throws CaminhoNaoEncontradoException return atual; } + public ElementoFS navegarParaTeste(String caminho) throws CaminhoNaoEncontradoException { + return navegar(caminho); + } + @Override public void mkdir(String caminho, String usuario) throws CaminhoJaExistenteException, PermissaoException { if (caminho.equals("/")) return; @@ -76,8 +80,36 @@ public void chmod(String caminho, String usuario, String usuarioAlvo, String per @Override public void rm(String caminho, String usuario, boolean recursivo) throws CaminhoNaoEncontradoException, PermissaoException { - // TODO: Implementar lógica de remoção (verificar se é arquivo ou diretório, permissões, recursividade) - throw new UnsupportedOperationException("Método não implementado 'rm'"); + if (caminho.equals("/")) { + throw new PermissaoException("Não é permitido remover o diretório raiz."); + } + // Navega até o elemento a ser removido + ElementoFS elemento = navegar(caminho); + + // Descobre o diretório pai + int lastSlash = caminho.lastIndexOf('/'); + String caminhoPai = (lastSlash <= 0) ? "/" : caminho.substring(0, lastSlash); + Diretorio pai = (Diretorio) navegar(caminhoPai); + + // Verifica permissão de escrita no pai + if (!pai.temPermissao(usuario, 'w')) { + throw new PermissaoException("Sem permissão para remover em: " + caminhoPai); + } + + if (!elemento.isArquivo()) { + Diretorio dir = (Diretorio) elemento; + if (!recursivo && !dir.getFilhos().isEmpty()) { + throw new PermissaoException("Diretório não está vazio. Use recursivo=true para remover tudo."); + } + // Remover recursivamente todos os filhos + if (recursivo) { + for (String filho : new java.util.ArrayList<>(dir.getFilhos().keySet())) { + rm(caminho + "/" + filho, usuario, true); + } + } + } + // Remove do pai + pai.removerFilho(elemento.getNomeDiretorio()); } @Override @@ -102,8 +134,32 @@ public void touch(String caminho, String usuario) throws CaminhoJaExistenteExcep @Override public void write(String caminho, String usuario, boolean anexar, byte[] buffer) throws CaminhoNaoEncontradoException, PermissaoException { - // TODO: Implementar lógica de escrita (dividir em blocos, verificar permissões, append ou sobrescrever) - throw new UnsupportedOperationException("Método não implementado 'write'"); + ElementoFS elemento = navegar(caminho); + + if (!elemento.isArquivo()) { + throw new CaminhoNaoEncontradoException("O caminho não é um arquivo."); + } + Arquivo arquivo = (Arquivo) elemento; + + if (!arquivo.temPermissao(usuario, 'w')) { + throw new PermissaoException("Sem permissão de escrita no arquivo."); + } + + final int TAMANHO_BLOCO = 4096; + + if (!anexar) { + arquivo.limparBlocos(); + } + + int pos = 0; + while (pos < buffer.length) { + int tamanhoRestante = buffer.length - pos; + int tamanhoBloco = Math.min(TAMANHO_BLOCO, tamanhoRestante); + byte[] bloco = new byte[tamanhoBloco]; + System.arraycopy(buffer, pos, bloco, 0, tamanhoBloco); + arquivo.adicionarBloco(bloco); + pos += tamanhoBloco; + } } // TODO: Implementar método read (leitura de arquivos) diff --git a/model/Arquivo.java b/model/Arquivo.java index ce3691e..1474409 100644 --- a/model/Arquivo.java +++ b/model/Arquivo.java @@ -6,6 +6,7 @@ public class Arquivo extends ElementoFS { private List blocos; private long tamanho; + public Arquivo(String nome, String permissoes, String dono) { super(nome, permissoes, dono); @@ -70,4 +71,13 @@ public void removerFilho(String nomeFilho) { throw new UnsupportedOperationException("Não é possível remover filhos de um arquivo."); } + @Override + public boolean temPermissao(String usuario, char tipoPermissao) { + if ("root".equals(usuario)) return true; + if (usuario.equals(donoDiretorio)) { + return permissoesPadrao.indexOf(tipoPermissao) >= 0; + } + // Arquivo não tem permissões específicas para outros usuários, só o dono pode acessar + return false; + } } diff --git a/model/ElementoFS.java b/model/ElementoFS.java index 9de3707..7a9045c 100644 --- a/model/ElementoFS.java +++ b/model/ElementoFS.java @@ -36,4 +36,5 @@ public void setDonoDiretorio(String donoDiretorio) { } public abstract boolean isArquivo(); + public abstract boolean temPermissao(String usuario, char tipoPermissao); } \ No newline at end of file diff --git a/model/Permissao.java b/model/Permissao.java deleted file mode 100644 index 50be058..0000000 --- a/model/Permissao.java +++ /dev/null @@ -1,31 +0,0 @@ -package model; - -import java.util.HashMap; -import java.util.Map; - -public class Permissao { - //quem pode fazer o quê é definido aqui - private Map permissoesPorUsuario; - - public Permissao() { - this.permissoesPorUsuario = new HashMap<>(); - } - - public void definirPermissao(String usuario, String permissao) { - permissoesPorUsuario.put(usuario, permissao); // ex: "rw", "r", "-" - } - - public boolean podeLer(String usuario) { - String p = permissoesPorUsuario.getOrDefault(usuario, ""); - return p.contains("r"); - } - - public boolean podeEscrever(String usuario) { - String p = permissoesPorUsuario.getOrDefault(usuario, ""); - return p.contains("w"); - } - - public String getPermissao(String usuario) { - return permissoesPorUsuario.getOrDefault(usuario, "-"); - } -} diff --git a/tests/FileSystemImplTest.java b/tests/FileSystemImplTest.java index ac05170..f49c1f9 100644 --- a/tests/FileSystemImplTest.java +++ b/tests/FileSystemImplTest.java @@ -65,8 +65,57 @@ void chmod_LancaExcecaoSeCaminhoNaoExiste() { assertThrows(CaminhoNaoEncontradoException.class, () -> fs.chmod("/naoexiste", "root", "root", "rwx")); } - // TODO: Adicionar testes unitários para rm - // TODO: Adicionar testes unitários para write/read + @Test + void rm_RemoveArquivoComSucesso() throws Exception { + fs.mkdir("/docs", "root"); + fs.touch("/docs/arquivo.txt", "root"); + assertDoesNotThrow(() -> fs.rm("/docs/arquivo.txt", "root", false)); + // Verifica se realmente foi removido + assertThrows(exception.CaminhoNaoEncontradoException.class, () -> { + fs.rm("/docs/arquivo.txt", "root", false); + }); + } + + @Test + void rm_RemoveDiretorioRecursivo() throws Exception { + fs.mkdir("/docs", "root"); + fs.mkdir("/docs/sub", "root"); + fs.touch("/docs/sub/arquivo.txt", "root"); + assertDoesNotThrow(() -> fs.rm("/docs", "root", true)); + assertThrows(exception.CaminhoNaoEncontradoException.class, () -> { + fs.rm("/docs", "root", false); + }); + } + + @Test + void rm_LancaExcecaoSeDiretorioNaoVazioSemRecursivo() throws Exception { + fs.mkdir("/docs", "root"); + fs.touch("/docs/arquivo.txt", "root"); + assertThrows(exception.PermissaoException.class, () -> fs.rm("/docs", "root", false)); + } + + @Test + void write_EscritaSimplesEmArquivo() throws Exception { + fs.mkdir("/docs", "root"); + fs.touch("/docs/arquivo.txt", "root"); + byte[] dados = "Hello, World!".getBytes(); + fs.write("/docs/arquivo.txt", "root", false, dados); + model.Arquivo arq = (model.Arquivo) fs.navegarParaTeste("/docs/arquivo.txt"); + assertEquals(dados.length, arq.getTamanho()); + } + + @Test + void write_AppendEmArquivo() throws Exception { + fs.mkdir("/docs", "root"); + fs.touch("/docs/arquivo.txt", "root"); + byte[] dados1 = "ABC".getBytes(); + byte[] dados2 = "DEF".getBytes(); + fs.write("/docs/arquivo.txt", "root", false, dados1); + fs.write("/docs/arquivo.txt", "root", true, dados2); + model.Arquivo arq = (model.Arquivo) fs.navegarParaTeste("/docs/arquivo.txt"); + assertEquals(6, arq.getTamanho()); + } + // TODO: Adicionar testes unitários para mv // TODO: Adicionar testes unitários para ls // TODO: Adicionar testes unitários para cp From 22d9f491084d9c9734b26e43901f407a8b2e7675 Mon Sep 17 00:00:00 2001 From: CarlosJFigueiredo Date: Thu, 22 May 2025 16:39:57 -0300 Subject: [PATCH 11/20] =?UTF-8?q?feat:=20implementar=20m=C3=A9todo=20de=20?= =?UTF-8?q?leitura=20de=20arquivos=20e=20adicionar=20teste=20correspondent?= =?UTF-8?q?e?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- filesys/FileSystemImpl.java | 21 +++++++++++++++++++-- tests/FileSystemImplTest.java | 12 ++++++++++++ 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/filesys/FileSystemImpl.java b/filesys/FileSystemImpl.java index f652ce3..d1d3027 100644 --- a/filesys/FileSystemImpl.java +++ b/filesys/FileSystemImpl.java @@ -166,8 +166,25 @@ public void write(String caminho, String usuario, boolean anexar, byte[] buffer) @Override public void read(String caminho, String usuario, byte[] buffer) throws CaminhoNaoEncontradoException, PermissaoException { - // TODO: Implementar lógica de leitura (ler em blocos, permissões, tratar arquivos grandes) - throw new UnsupportedOperationException("Método não implementado 'read'"); + ElementoFS elemento = navegar(caminho); + + if (!elemento.isArquivo()) { + throw new CaminhoNaoEncontradoException("O caminho não é um arquivo."); + } + Arquivo arquivo = (Arquivo) elemento; + + if (!arquivo.temPermissao(usuario, 'r')) { + throw new PermissaoException("Sem permissão de leitura no arquivo."); + } + + // Lê os blocos do arquivo e copia para o buffer até preencher ou acabar o arquivo + int posBuffer = 0; + for (byte[] bloco : arquivo.getBlocos()) { + int bytesParaCopiar = Math.min(bloco.length, buffer.length - posBuffer); + System.arraycopy(bloco, 0, buffer, posBuffer, bytesParaCopiar); + posBuffer += bytesParaCopiar; + if (posBuffer >= buffer.length) break; // buffer cheio + } } // TODO: Implementar método mv (movimentação/renomeação) diff --git a/tests/FileSystemImplTest.java b/tests/FileSystemImplTest.java index f49c1f9..775f36d 100644 --- a/tests/FileSystemImplTest.java +++ b/tests/FileSystemImplTest.java @@ -116,6 +116,18 @@ void write_AppendEmArquivo() throws Exception { assertEquals(6, arq.getTamanho()); } + @Test + void read_LeituraSimplesDeArquivo() throws Exception { + fs.mkdir("/docs", "root"); + fs.touch("/docs/arquivo.txt", "root"); + byte[] dados = "Hello, World!".getBytes(); + fs.write("/docs/arquivo.txt", "root", false, dados); + + byte[] buffer = new byte[dados.length]; + fs.read("/docs/arquivo.txt", "root", buffer); + assertArrayEquals(dados, buffer); + } + // TODO: Adicionar testes unitários para mv // TODO: Adicionar testes unitários para ls // TODO: Adicionar testes unitários para cp From 5b7b6445e037ee099248aab43501668d8e0d6b7c Mon Sep 17 00:00:00 2001 From: CarlosJFigueiredo Date: Thu, 22 May 2025 16:50:33 -0300 Subject: [PATCH 12/20] =?UTF-8?q?feat:=20implementar=20m=C3=A9todos=20mv,?= =?UTF-8?q?=20ls=20e=20cp=20no=20sistema=20de=20arquivos=20e=20adicionar?= =?UTF-8?q?=20testes=20unit=C3=A1rios=20correspondentes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHECKLIST_DO_GRUPO.md | 11 ---- filesys/FileSystemImpl.java | 106 ++++++++++++++++++++++++++++++++-- tests/FileSystemImplTest.java | 85 ++++++++++++++++++++++++++- 3 files changed, 182 insertions(+), 20 deletions(-) diff --git a/CHECKLIST_DO_GRUPO.md b/CHECKLIST_DO_GRUPO.md index 3d87d25..199180b 100644 --- a/CHECKLIST_DO_GRUPO.md +++ b/CHECKLIST_DO_GRUPO.md @@ -12,12 +12,6 @@ Ainda precisamos implementar os métodos principais que fazem o sistema funciona Esses métodos são chamados quando o usuário executa comandos como criar, remover, copiar, mover arquivos e diretórios. **Faltam implementar:** -- -- -- `read` — Ler dados de um arquivo (precisa ler em partes se o arquivo for grande) -- `mv` — Mover ou renomear arquivos/diretórios -- `ls` — Listar o conteúdo de um diretório (mostrar arquivos e subdiretórios) -- `cp` — Copiar arquivos ou diretórios (com opção de copiar tudo dentro, se for recursivo) **No código, já deixei `// TODO` nesses métodos para facilitar achar onde falta implementar. O VS Code mostra uma linha azul do lado esquerdo nesses pontos.** @@ -27,11 +21,6 @@ O VS Code mostra uma linha azul do lado esquerdo nesses pontos.** ## 2. Testes Unitários **Faltam testes para:** -- Remover arquivos/diretórios (`rm`) -- Escrever e ler arquivos (`write` e `read`) -- Mover/renomear (`mv`) -- Listar diretórios (`ls`) -- Copiar arquivos/diretórios (`cp`) - Testar casos de erro (ex: tentar remover sem permissão, tentar ler arquivo inexistente, etc.) - **Testes de permissão:** Já existe um arquivo chamado `PermissionTest.java` que testa se o sistema está respeitando as permissões de leitura, escrita e execução para cada usuário. - mas olhem la diff --git a/filesys/FileSystemImpl.java b/filesys/FileSystemImpl.java index d1d3027..95a3aed 100644 --- a/filesys/FileSystemImpl.java +++ b/filesys/FileSystemImpl.java @@ -191,23 +191,117 @@ public void read(String caminho, String usuario, byte[] buffer) @Override public void mv(String caminhoAntigo, String caminhoNovo, String usuario) throws CaminhoNaoEncontradoException, PermissaoException { - // TODO: Implementar lógica de movimentação/renomeação (verificar permissões, atualizar árvore) - throw new UnsupportedOperationException("Método não implementado 'mv'"); + if (caminhoAntigo.equals("/") || caminhoNovo.equals("/")) { + throw new PermissaoException("Não é permitido mover ou renomear o diretório raiz."); + } + + // Navega até o elemento a ser movido + ElementoFS elemento = navegar(caminhoAntigo); + + // Descobre o diretório pai do antigo e do novo caminho + int lastSlashAntigo = caminhoAntigo.lastIndexOf('/'); + String caminhoPaiAntigo = (lastSlashAntigo <= 0) ? "/" : caminhoAntigo.substring(0, lastSlashAntigo); + Diretorio paiAntigo = (Diretorio) navegar(caminhoPaiAntigo); + + int lastSlashNovo = caminhoNovo.lastIndexOf('/'); + String caminhoPaiNovo = (lastSlashNovo <= 0) ? "/" : caminhoNovo.substring(0, lastSlashNovo); + Diretorio paiNovo = (Diretorio) navegar(caminhoPaiNovo); + + String nomeNovo = caminhoNovo.substring(lastSlashNovo + 1); + + // Permissão de escrita nos dois diretórios + if (!paiAntigo.temPermissao(usuario, 'w')) { + throw new PermissaoException("Sem permissão para remover do diretório antigo: " + caminhoPaiAntigo); + } + if (!paiNovo.temPermissao(usuario, 'w')) { + throw new PermissaoException("Sem permissão para criar no diretório novo: " + caminhoPaiNovo); + } + + // Remove do diretório antigo + paiAntigo.removerFilho(elemento.getNomeDiretorio()); + + // Renomeia se necessário + elemento.setNomeDiretorio(nomeNovo); + + // Adiciona ao novo diretório + paiNovo.adicionarFilho(elemento); } // TODO: Implementar método ls (listagem de diretórios) @Override public void ls(String caminho, String usuario, boolean recursivo) throws CaminhoNaoEncontradoException, PermissaoException { - // TODO: Implementar lógica de listagem (mostrar arquivos/diretórios, recursivo ou não, permissões) - throw new UnsupportedOperationException("Método não implementado 'ls'"); + ElementoFS elemento = navegar(caminho); + + if (elemento.isArquivo()) { + if (!elemento.temPermissao(usuario, 'r')) { + throw new PermissaoException("Sem permissão de leitura no arquivo."); + } + System.out.println(elemento.getNomeDiretorio()); + return; + } + + Diretorio dir = (Diretorio) elemento; + if (!dir.temPermissao(usuario, 'r')) { + throw new PermissaoException("Sem permissão de leitura no diretório."); + } + + listarDiretorio(dir, caminho.equals("/") ? "" : caminho, usuario, recursivo, 0); + } + + private void listarDiretorio(Diretorio dir, String caminho, String usuario, boolean recursivo, int nivel) { + String prefixo = " ".repeat(nivel); + for (ElementoFS filho : dir.getFilhos().values()) { + System.out.println(prefixo + filho.getNomeDiretorio() + + (filho.isArquivo() ? "" : "/") + + " [owner=" + filho.getDonoDiretorio() + ", perms=" + filho.getPermissoesPadrao() + "]"); + if (recursivo && !filho.isArquivo()) { + listarDiretorio((Diretorio) filho, caminho + "/" + filho.getNomeDiretorio(), usuario, true, nivel + 1); + } + } } // TODO: Implementar método cp (cópia de arquivos/diretórios) @Override public void cp(String caminhoOrigem, String caminhoDestino, String usuario, boolean recursivo) throws CaminhoNaoEncontradoException, PermissaoException { - // TODO: Implementar lógica de cópia (copiar arquivos/diretórios, recursivo, permissões) - throw new UnsupportedOperationException("Método não implementado 'cp'"); + ElementoFS origem = navegar(caminhoOrigem); + + int lastSlash = caminhoDestino.lastIndexOf('/'); + String caminhoPaiDestino = (lastSlash <= 0) ? "/" : caminhoDestino.substring(0, lastSlash); + String nomeDestino = caminhoDestino.substring(lastSlash + 1); + Diretorio paiDestino = (Diretorio) navegar(caminhoPaiDestino); + + if (!origem.temPermissao(usuario, 'r')) { + throw new PermissaoException("Sem permissão de leitura na origem."); + } + if (!paiDestino.temPermissao(usuario, 'w')) { + throw new PermissaoException("Sem permissão de escrita no destino."); + } + + if (origem.isArquivo()) { + // Copia arquivo + Arquivo arqOrigem = (Arquivo) origem; + Arquivo novoArquivo = new Arquivo(nomeDestino, arqOrigem.getPermissoesPadrao(), usuario); + // Copia blocos + for (byte[] bloco : arqOrigem.getBlocos()) { + novoArquivo.adicionarBloco(bloco.clone()); + } + paiDestino.adicionarFilho(novoArquivo); + } else { + // Copia diretório + if (!recursivo) { + throw new PermissaoException("Diretório só pode ser copiado com recursivo=true."); + } + Diretorio dirOrigem = (Diretorio) origem; + Diretorio novoDir = new Diretorio(nomeDestino, dirOrigem.getPermissoesPadrao(), usuario); + paiDestino.adicionarFilho(novoDir); + // Copia recursivamente os filhos + for (ElementoFS filho : dirOrigem.getFilhos().values()) { + cp(caminhoOrigem + "/" + filho.getNomeDiretorio(), + caminhoDestino + "/" + filho.getNomeDiretorio(), + usuario, true); + } + } } // TODO: Implementar carregamento de usuários a partir do arquivo users/users se necessário diff --git a/tests/FileSystemImplTest.java b/tests/FileSystemImplTest.java index 775f36d..1c0809c 100644 --- a/tests/FileSystemImplTest.java +++ b/tests/FileSystemImplTest.java @@ -7,6 +7,9 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; + import static org.junit.jupiter.api.Assertions.*; class FileSystemImplTest { @@ -128,7 +131,83 @@ void read_LeituraSimplesDeArquivo() throws Exception { assertArrayEquals(dados, buffer); } - // TODO: Adicionar testes unitários para mv - // TODO: Adicionar testes unitários para ls - // TODO: Adicionar testes unitários para cp + @Test + void mv_MoverArquivoComSucesso() throws Exception { + fs.mkdir("/docs", "root"); + fs.touch("/docs/arquivo.txt", "root"); + fs.mkdir("/destino", "root"); + fs.mv("/docs/arquivo.txt", "/destino/novo.txt", "root"); + assertThrows(exception.CaminhoNaoEncontradoException.class, () -> fs.rm("/docs/arquivo.txt", "root", false)); + // Verifica se existe no novo local + fs.rm("/destino/novo.txt", "root", false); + } + + @Test + void ls_ListagemSimplesDeDiretorio() throws Exception { + fs.mkdir("/docs", "root"); + fs.touch("/docs/arquivo1.txt", "root"); + fs.touch("/docs/arquivo2.txt", "root"); + + // Redireciona a saída padrão para capturar o resultado do ls + ByteArrayOutputStream outContent = new ByteArrayOutputStream(); + PrintStream originalOut = System.out; + System.setOut(new PrintStream(outContent)); + + fs.ls("/docs", "root", false); + + System.setOut(originalOut); // Restaura saída padrão + + String output = outContent.toString(); + assertTrue(output.contains("arquivo1.txt")); + assertTrue(output.contains("arquivo2.txt")); + } + + @Test + void ls_ListagemRecursiva() throws Exception { + fs.mkdir("/docs", "root"); + fs.touch("/docs/arquivo1.txt", "root"); + fs.mkdir("/docs/subdir", "root"); + fs.touch("/docs/subdir/arquivo2.txt", "root"); + + ByteArrayOutputStream outContent = new ByteArrayOutputStream(); + PrintStream originalOut = System.out; + System.setOut(new PrintStream(outContent)); + + fs.ls("/docs", "root", true); + + System.setOut(originalOut); + + String output = outContent.toString(); + assertTrue(output.contains("arquivo1.txt")); + assertTrue(output.contains("subdir/")); + assertTrue(output.contains("arquivo2.txt")); + } + + @Test + void cp_CopiaArquivoComSucesso() throws Exception { + fs.mkdir("/docs", "root"); + fs.touch("/docs/arquivo.txt", "root"); + byte[] dados = "abc".getBytes(); + fs.write("/docs/arquivo.txt", "root", false, dados); + + fs.cp("/docs/arquivo.txt", "/docs/copia.txt", "root", false); + + model.Arquivo arq = (model.Arquivo) fs.navegarParaTeste("/docs/copia.txt"); + assertEquals(dados.length, arq.getTamanho()); + } + + @Test + void cp_CopiaDiretorioRecursivo() throws Exception { + fs.mkdir("/docs", "root"); + fs.touch("/docs/arquivo.txt", "root"); + fs.mkdir("/docs/subdir", "root"); + fs.touch("/docs/subdir/arquivo2.txt", "root"); + fs.cp("/docs", "/backup", "root", true); + + // Verifica se os arquivos foram copiados + model.Arquivo arq1 = (model.Arquivo) fs.navegarParaTeste("/backup/arquivo.txt"); + model.Arquivo arq2 = (model.Arquivo) fs.navegarParaTeste("/backup/subdir/arquivo2.txt"); + assertNotNull(arq1); + assertNotNull(arq2); + } } From a8a262a4a581d8d17bf2f1705110aff0f049fcf0 Mon Sep 17 00:00:00 2001 From: Arthur Date: Tue, 3 Jun 2025 10:06:03 -0300 Subject: [PATCH 13/20] =?UTF-8?q?mudan=C3=A7as=20na=20implemneta=C3=A7?= =?UTF-8?q?=C3=A3o=20e=20cria=C3=A7=C3=A3o=20dos=20testes=20de=20permiss?= =?UTF-8?q?=C3=A3o?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- filesys/FileSystemImpl.java | 4 +- tests/PermissionTest.java | 80 +++++++++++++++++++++++++++++++++---- 2 files changed, 76 insertions(+), 8 deletions(-) diff --git a/filesys/FileSystemImpl.java b/filesys/FileSystemImpl.java index 95a3aed..498e3c2 100644 --- a/filesys/FileSystemImpl.java +++ b/filesys/FileSystemImpl.java @@ -56,7 +56,9 @@ public void mkdir(String caminho, String usuario) throws CaminhoJaExistenteExcep } String nomeNovo = partes[partes.length - 1]; if (atual.getFilhos().containsKey(nomeNovo)) throw new CaminhoJaExistenteException("Já existe: " + caminho); - if (!atual.temPermissao(usuario, 'w')) throw new PermissaoException("Sem permissão para criar em: " + caminho); + // Exigir permissão de escrita E execução + if (!atual.temPermissao(usuario, 'w') || !atual.temPermissao(usuario, 'x')) + throw new PermissaoException("Sem permissão para criar em: " + caminho); atual.adicionarFilho(new Diretorio(nomeNovo, "rwx", usuario)); // TODO: Permitir criar diretórios recursivamente (mkdir -p) se necessário } diff --git a/tests/PermissionTest.java b/tests/PermissionTest.java index 6026e31..660f8fc 100644 --- a/tests/PermissionTest.java +++ b/tests/PermissionTest.java @@ -1,26 +1,92 @@ package tests; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.*; -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 exception.CaminhoJaExistenteException; +import exception.CaminhoNaoEncontradoException; +import exception.PermissaoException; import filesys.FileSystemImpl; import filesys.IFileSystem; -// Essa classe testa cenários de permissão public class PermissionTest { private static IFileSystem fileSystem; @BeforeAll public static void setUp() { - fileSystem = new FileSystemImpl(/*args...*/); + fileSystem = new FileSystemImpl(); } @Test public void testPermission() { - // Teste de permissão - assertTrue(true); + // Teste básico de permissão: root sempre pode criar diretório + assertDoesNotThrow(() -> fileSystem.mkdir("/test", "root")); + } + + @Test + public void testReadPermission() throws Exception { + fileSystem.mkdir("/docs", "root"); + fileSystem.touch("/docs/arquivo.txt", "root"); + + // root pode listar + assertDoesNotThrow(() -> fileSystem.ls("/docs", "root", false)); + + // chmod para negar leitura a outro usuário + fileSystem.chmod("/docs", "root", "joao", "---"); + assertThrows(PermissaoException.class, () -> fileSystem.ls("/docs", "joao", false)); + + // chmod para permitir leitura + fileSystem.chmod("/docs", "root", "joao", "r--"); + assertDoesNotThrow(() -> fileSystem.ls("/docs", "joao", false)); + } + + @Test + public void testWritePermission() throws Exception { + fileSystem.mkdir("/priv", "root"); + + // root pode criar arquivo + assertDoesNotThrow(() -> fileSystem.touch("/priv/novo.txt", "root")); + + // chmod para negar escrita a joao + fileSystem.chmod("/priv", "root", "joao", "r--"); + assertThrows(PermissaoException.class, () -> fileSystem.touch("/priv/joao.txt", "joao")); + + // chmod para permitir escrita + fileSystem.chmod("/priv", "root", "joao", "rw-"); + assertDoesNotThrow(() -> fileSystem.touch("/priv/joao2.txt", "joao")); + } + + @Test + public void testExecutePermission() throws Exception { + fileSystem.mkdir("/exec", "root"); + + // chmod para negar execução a joao + fileSystem.chmod("/exec", "root", "joao", "rw-"); + // Tenta criar subdiretório (precisa de x) + assertThrows(PermissaoException.class, () -> fileSystem.mkdir("/exec/sub", "joao")); + + // chmod para permitir execução + fileSystem.chmod("/exec", "root", "joao", "rwx"); + assertDoesNotThrow(() -> fileSystem.mkdir("/exec/sub", "joao")); + } + + @Test + public void testPermissionInheritance() throws Exception { + fileSystem.mkdir("/pai", "root"); + fileSystem.mkdir("/pai/filho", "root"); + + // Permissão só no pai + fileSystem.chmod("/pai", "root", "joao", "rwx"); + // Deve herdar permissão do pai + assertDoesNotThrow(() -> fileSystem.mkdir("/pai/filho/nieto", "joao")); + + // Remove permissão do pai, adiciona só no filho + fileSystem.chmod("/pai", "root", "joao", "---"); + fileSystem.chmod("/pai/filho", "root", "joao", "rwx"); + // Agora só pode criar dentro de filho, não no pai + assertThrows(PermissaoException.class, () -> fileSystem.mkdir("/pai/novo", "joao")); + assertDoesNotThrow(() -> fileSystem.mkdir("/pai/filho/novo", "joao")); } } From f80f499b35e3426d9d13237aabfdda9115cf36fa Mon Sep 17 00:00:00 2001 From: Arthur Date: Tue, 3 Jun 2025 10:37:22 -0300 Subject: [PATCH 14/20] feat: refactor FileSystem and FileSystemImpl to accept a list of users and update tests accordingly --- Main.java | 14 +++++++++----- filesys/FileSystem.java | 8 ++++++-- filesys/FileSystemImpl.java | 8 ++++++-- tests/FileSystemImplTest.java | 7 ++++++- tests/PermissionTest.java | 7 ++++++- 5 files changed, 33 insertions(+), 11 deletions(-) diff --git a/Main.java b/Main.java index 3b8673a..907b883 100644 --- a/Main.java +++ b/Main.java @@ -1,5 +1,8 @@ import filesys.IFileSystem; +import model.Usuario; +import java.util.ArrayList; +import java.util.List; import java.util.Scanner; import java.io.FileNotFoundException; @@ -40,6 +43,8 @@ public static void main(String[] args) { return; } user = args[1]; + + List usuarios = new ArrayList<>(); // Carrega a lista de usuários do sistema a partir de arquivo // Formato do arquivo users: @@ -62,12 +67,12 @@ public static void main(String[] args) { String dir = parts[1]; String dirPermission = parts[2]; - /* A FAZER: + /* FEITO: * Processar a permissão de todos os usuários existentes por diretório. * Por enquanto esse código somente imprime as permissões contidas no arquivo users. */ System.out.println(userListed + " " + dir + " " + dirPermission); // Somente imprime o usuário, diretório e permissão - + usuarios.add( new Usuario(userListed, dirPermission, dir)); } else { System.out.println("Formato ruim no arquivo de usuários. Linha: " + line); @@ -84,16 +89,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()); + // System.out.println(e.getMessage()); // } - // Menu interativo. menu(); } diff --git a/filesys/FileSystem.java b/filesys/FileSystem.java index 8d7a83b..036e9d9 100644 --- a/filesys/FileSystem.java +++ b/filesys/FileSystem.java @@ -1,16 +1,20 @@ package filesys; +import java.util.List; + import exception.CaminhoJaExistenteException; import exception.CaminhoNaoEncontradoException; import exception.PermissaoException; +import model.Usuario; // Essa classe deve servir apenas como proxy para o FileSystemImpl 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 498e3c2..5b370da 100644 --- a/filesys/FileSystemImpl.java +++ b/filesys/FileSystemImpl.java @@ -9,6 +9,7 @@ import model.Usuario; import java.util.HashMap; +import java.util.List; import java.util.Map; public final class FileSystemImpl implements IFileSystem { @@ -16,9 +17,12 @@ public final class FileSystemImpl implements IFileSystem { private Diretorio raiz; private Map usuarios = new HashMap<>(); - public FileSystemImpl() { + public FileSystemImpl(List usuarios) { this.raiz = new Diretorio("/", "rwx", ROOT_USER); - usuarios.put(ROOT_USER, new Usuario(ROOT_USER, "rwx", "/")); + this.usuarios.put(ROOT_USER, new Usuario(ROOT_USER, "rwx", "/")); + for (Usuario usuario : usuarios) { + this.usuarios.put(usuario.getNome(), usuario); + } // TODO: Carregar usuários adicionais do arquivo users/users se necessário } diff --git a/tests/FileSystemImplTest.java b/tests/FileSystemImplTest.java index 1c0809c..606ae3f 100644 --- a/tests/FileSystemImplTest.java +++ b/tests/FileSystemImplTest.java @@ -4,20 +4,25 @@ import exception.CaminhoNaoEncontradoException; import exception.PermissaoException; import filesys.FileSystemImpl; +import model.Usuario; + import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import java.io.ByteArrayOutputStream; import java.io.PrintStream; +import java.util.ArrayList; +import java.util.List; import static org.junit.jupiter.api.Assertions.*; class FileSystemImplTest { private FileSystemImpl fs; + List usuarios = new ArrayList<>(); @BeforeEach void setUp() { - fs = new FileSystemImpl(); + fs = new FileSystemImpl(usuarios); } @Test diff --git a/tests/PermissionTest.java b/tests/PermissionTest.java index 660f8fc..3493a0b 100644 --- a/tests/PermissionTest.java +++ b/tests/PermissionTest.java @@ -2,6 +2,9 @@ import static org.junit.jupiter.api.Assertions.*; +import java.util.ArrayList; +import java.util.List; + import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; @@ -10,13 +13,15 @@ import exception.PermissaoException; import filesys.FileSystemImpl; import filesys.IFileSystem; +import model.Usuario; public class PermissionTest { private static IFileSystem fileSystem; + static List usuarios = new ArrayList<>(); @BeforeAll public static void setUp() { - fileSystem = new FileSystemImpl(); + fileSystem = new FileSystemImpl(usuarios); } @Test From 3df9a6cc85b18262db25f68d199d000507d18add Mon Sep 17 00:00:00 2001 From: CarlosJFigueiredo Date: Tue, 3 Jun 2025 13:49:10 -0300 Subject: [PATCH 15/20] =?UTF-8?q?feat:=20adicionar=20suporte=20a=20permiss?= =?UTF-8?q?=C3=B5es=20globais=20de=20usu=C3=A1rios=20e=20m=C3=A9todos=20co?= =?UTF-8?q?rrespondentes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Main.java | 2 +- filesys/FileSystemImpl.java | 6 ++++++ model/Diretorio.java | 7 +++++++ model/Usuario.java | 4 ++++ 4 files changed, 18 insertions(+), 1 deletion(-) diff --git a/Main.java b/Main.java index 907b883..bc3e73d 100644 --- a/Main.java +++ b/Main.java @@ -72,7 +72,7 @@ public static void main(String[] args) { * Por enquanto esse código somente imprime as permissões contidas no arquivo users. */ System.out.println(userListed + " " + dir + " " + dirPermission); // Somente imprime o usuário, diretório e permissão - usuarios.add( new Usuario(userListed, dirPermission, dir)); + usuarios.add(new Usuario(userListed, dirPermission, dir)); } else { System.out.println("Formato ruim no arquivo de usuários. Linha: " + line); diff --git a/filesys/FileSystemImpl.java b/filesys/FileSystemImpl.java index 5b370da..262cae5 100644 --- a/filesys/FileSystemImpl.java +++ b/filesys/FileSystemImpl.java @@ -16,16 +16,22 @@ public final class FileSystemImpl implements IFileSystem { private static final String ROOT_USER = "root"; // pode ser necessário private Diretorio raiz; private Map usuarios = new HashMap<>(); + private static Map usuariosGlobais = new HashMap<>(); public FileSystemImpl(List usuarios) { this.raiz = new Diretorio("/", "rwx", ROOT_USER); this.usuarios.put(ROOT_USER, new Usuario(ROOT_USER, "rwx", "/")); for (Usuario usuario : usuarios) { this.usuarios.put(usuario.getNome(), usuario); + usuariosGlobais.put(usuario.getNome(), usuario); // Adicione aqui } // TODO: Carregar usuários adicionais do arquivo users/users se necessário } + public static Usuario getUsuarioGlobal(String nome) { + return usuariosGlobais.get(nome); + } + // TODO: Validar se o método navegar cobre todos os casos de caminhos relativos e absolutos private ElementoFS navegar(String caminho) throws CaminhoNaoEncontradoException { if (caminho.equals("/")) return raiz; diff --git a/model/Diretorio.java b/model/Diretorio.java index c5f6498..51e921b 100644 --- a/model/Diretorio.java +++ b/model/Diretorio.java @@ -3,6 +3,8 @@ import java.util.HashMap; import java.util.Map; +import filesys.FileSystemImpl; + public class Diretorio extends ElementoFS { private Diretorio diretorioPai; private Map filhos; @@ -29,6 +31,11 @@ public boolean temPermissao(String usuario, char tipoPermissao) { if (usuario.equals(donoDiretorio)) return permissoesPadrao.indexOf(tipoPermissao) >= 0; String permissoesUsuario = acessosPorUsuario.get(usuario); if (permissoesUsuario != null && permissoesUsuario.indexOf(tipoPermissao) >= 0) return true; + // Verifica permissão global do usuário (/**) + Usuario usuarioGlobal = FileSystemImpl.getUsuarioGlobal(usuario); // Implemente esse método estático + if (usuarioGlobal != null && usuarioGlobal.getDiretorio().equals("/**") && usuarioGlobal.getPermissao().indexOf(tipoPermissao) >= 0) { + return true; + } if (diretorioPai != null) return diretorioPai.temPermissao(usuario, tipoPermissao); return false; } diff --git a/model/Usuario.java b/model/Usuario.java index 9b6a04d..3f41c0d 100644 --- a/model/Usuario.java +++ b/model/Usuario.java @@ -31,6 +31,10 @@ public void setDiretorio(String diretorio) { this.diretorio = diretorio; } + public String getDiretorio() { + return diretorio; + } + @Override public String toString() { return "Usuario{" + From 57bf4e7c24ba338fe2b219f75c96fc32f8789194 Mon Sep 17 00:00:00 2001 From: CarlosJFigueiredo Date: Tue, 3 Jun 2025 14:44:36 -0300 Subject: [PATCH 16/20] =?UTF-8?q?feat:=20adicionar=20m=C3=A9todo=20para=20?= =?UTF-8?q?obter=20o=20tamanho=20de=20arquivos=20e=20ajustar=20leitura=20n?= =?UTF-8?q?o=20sistema=20de=20arquivos?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Main.java | 21 ++++++++++++++++++--- filesys/FileSystem.java | 2 +- filesys/FileSystemImpl.java | 10 ++++++++++ 3 files changed, 29 insertions(+), 4 deletions(-) diff --git a/Main.java b/Main.java index bc3e73d..b380adb 100644 --- a/Main.java +++ b/Main.java @@ -11,6 +11,7 @@ import exception.CaminhoNaoEncontradoException; import filesys.FileSystem; +import filesys.FileSystemImpl; // MENU INTERATIVO PARA O SISTEMA DE ARQUIVOS // SINTA-SE LIVRE PARA ALTERAR A CLASSE MAIN @@ -217,9 +218,23 @@ public static void write() throws CaminhoNaoEncontradoException, PermissaoExcept public static void read() throws CaminhoNaoEncontradoException, PermissaoException { System.out.println("Insira o caminho do arquivo a ser lido:"); String caminho = scanner.nextLine(); - byte[] buffer = new byte[READ_BUFFER_SIZE]; // Exemplo de tamanho de buffer por load/leitura . O que acontece se o Buffer for menor que o conteúdo a ser lido? - - fileSystem.read(caminho, user, buffer); // Lógica para ler arquivos maiores que o buffer deve ser implementada. + + // Descobre o tamanho real do arquivo usando o método auxiliar + int tamanho; + try { + // Acesso ao método auxiliar via cast para FileSystemImpl + FileSystem fsProxy = (FileSystem) fileSystem; + FileSystemImpl fsImpl = (FileSystemImpl) fsProxy.fileSystemImpl; + tamanho = fsImpl.getTamanhoArquivo(caminho); + } catch (Exception e) { + System.out.println("Erro ao obter tamanho do arquivo: " + e.getMessage()); + return; + } + + byte[] buffer = new byte[tamanho]; + fileSystem.read(caminho, user, buffer); + System.out.println("Conteúdo do arquivo:"); + System.out.println(new String(buffer)); } public static void mv() throws CaminhoNaoEncontradoException, PermissaoException { diff --git a/filesys/FileSystem.java b/filesys/FileSystem.java index 036e9d9..e622492 100644 --- a/filesys/FileSystem.java +++ b/filesys/FileSystem.java @@ -10,7 +10,7 @@ // Essa classe deve servir apenas como proxy para o FileSystemImpl final public class FileSystem implements IFileSystem { - private final IFileSystem fileSystemImpl; + public final IFileSystem fileSystemImpl; public FileSystem(List usuarios) { fileSystemImpl = new FileSystemImpl(usuarios); diff --git a/filesys/FileSystemImpl.java b/filesys/FileSystemImpl.java index 262cae5..1e4d7cd 100644 --- a/filesys/FileSystemImpl.java +++ b/filesys/FileSystemImpl.java @@ -322,4 +322,14 @@ public void addUser(String user) { } // TODO: Adicionar métodos auxiliares para facilitar operações recursivas, busca de pai, etc. + public int getTamanhoArquivo(String caminho) throws CaminhoNaoEncontradoException { + ElementoFS elemento = navegar(caminho); + if (!elemento.isArquivo()) throw new CaminhoNaoEncontradoException("O caminho não é um arquivo."); + Arquivo arquivo = (Arquivo) elemento; + int tamanho = 0; + for (byte[] bloco : arquivo.getBlocos()) { + tamanho += bloco.length; + } + return tamanho; + } } From 13732ffe494cd32f9b7286a357ef5888b51be4ed Mon Sep 17 00:00:00 2001 From: CarlosJFigueiredo Date: Tue, 3 Jun 2025 15:13:48 -0300 Subject: [PATCH 17/20] =?UTF-8?q?feat:=20implementar=20cria=C3=A7=C3=A3o?= =?UTF-8?q?=20recursiva=20de=20diret=C3=B3rios=20no=20m=C3=A9todo=20mkdir?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- filesys/FileSystemImpl.java | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/filesys/FileSystemImpl.java b/filesys/FileSystemImpl.java index 1e4d7cd..3e78a49 100644 --- a/filesys/FileSystemImpl.java +++ b/filesys/FileSystemImpl.java @@ -59,18 +59,24 @@ public void mkdir(String caminho, String usuario) throws CaminhoJaExistenteExcep if (caminho.equals("/")) return; String[] partes = caminho.split("/"); Diretorio atual = raiz; - for (int i = 1; i < partes.length - 1; i++) { - ElementoFS filho = atual.getFilhos().get(partes[i]); - if (filho == null || filho.isArquivo()) throw new PermissaoException("Diretório intermediário não existe: " + partes[i]); - atual = (Diretorio) filho; + StringBuilder caminhoAtual = new StringBuilder(); + + for (int i = 1; i < partes.length; i++) { + if (partes[i].isEmpty()) continue; + caminhoAtual.append("/").append(partes[i]); + Map filhos = atual.getFilhos(); + if (!filhos.containsKey(partes[i])) { + // Verifica permissão de escrita e execução no diretório atual + if (!atual.temPermissao(usuario, 'w') || !atual.temPermissao(usuario, 'x')) { + throw new PermissaoException("Sem permissão para criar em: " + caminhoAtual.substring(0, caminhoAtual.lastIndexOf("/"))); + } + // Cria o diretório intermediário + Diretorio novo = new Diretorio(partes[i], "rwx", usuario); + atual.adicionarFilho(novo); + } + // Avança para o próximo diretório + atual = (Diretorio) filhos.get(partes[i]); } - String nomeNovo = partes[partes.length - 1]; - if (atual.getFilhos().containsKey(nomeNovo)) throw new CaminhoJaExistenteException("Já existe: " + caminho); - // Exigir permissão de escrita E execução - if (!atual.temPermissao(usuario, 'w') || !atual.temPermissao(usuario, 'x')) - throw new PermissaoException("Sem permissão para criar em: " + caminho); - atual.adicionarFilho(new Diretorio(nomeNovo, "rwx", usuario)); - // TODO: Permitir criar diretórios recursivamente (mkdir -p) se necessário } @Override From 74f807af10c981d7da40929d8ce6ef8c1b1973bf Mon Sep 17 00:00:00 2001 From: gabi Date: Tue, 3 Jun 2025 15:22:53 -0300 Subject: [PATCH 18/20] =?UTF-8?q?feat:=20implementar=20valida=C3=A7=C3=A3o?= =?UTF-8?q?=20de=20caminhos=20relativos=20e=20absolutos=20no=20m=C3=A9todo?= =?UTF-8?q?=20navegar?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Main.java | 46 ++++++++++++++++++------------------- filesys/FileSystemImpl.java | 4 ++-- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/Main.java b/Main.java index b380adb..ffc897b 100644 --- a/Main.java +++ b/Main.java @@ -40,7 +40,7 @@ public static void main(String[] args) { // Para quaisquer operações que serão feitas por esse usuário em um caminho /path/**, // deve-se checar se o usuário tem permissão de escrita (r) neste caminho. if (args.length < 2) { - System.out.println("Usuário não fornecido"); + System.out.println("Usuario nao fornecido"); return; } user = args[1]; @@ -76,13 +76,13 @@ public static void main(String[] args) { usuarios.add(new Usuario(userListed, dirPermission, dir)); } else { - System.out.println("Formato ruim no arquivo de usuários. Linha: " + line); + System.out.println("Formato ruim no arquivo de usuarios. Linha: " + line); } } } userScanner.close(); } catch (FileNotFoundException e) { // Retorna se o arquivo de usuários não for encontrado - System.out.println("Arquivo de usuários não encontrado"); + System.out.println("Arquivo de usuarios nao encontrado"); return; } @@ -108,18 +108,18 @@ public static void main(String[] args) { // mas diretamente na interface IFileSystem public static void menu() { while (true) { - System.out.println("\nComandos disponíveis:"); - System.out.println("1. chmod - Alterar permissões"); - System.out.println("2. mkdir - Criar diretório"); - System.out.println("3. rm - Remover arquivo/diretório"); - System.out.println("4. touch - Criar arquivo"); - System.out.println("5. write - Escrever em arquivo"); - System.out.println("6. read - Ler arquivo"); - System.out.println("7. mv - Mover/renomear arquivo"); - System.out.println("8. ls - Listar diretório"); - System.out.println("9. cp - Copiar arquivo"); - System.out.println("0. exit - Sair"); - System.out.print("\nDigite o comando desejado: "); + System.out.println("\nComandos disponiveis (POSIX):"); + System.out.println("1. chmod - Alterar permissoes de arquivo ou diretorio"); + System.out.println("2. mkdir - Criar diretorio (cria diretorios intermediarios automaticamente, como 'mkdir -p')"); + System.out.println("3. rm - Remover arquivo ou diretorio (pode ser recursivo)"); + System.out.println("4. touch - Criar arquivo vazio"); + System.out.println("5. write - Escrever dados em arquivo (pode anexar ou sobrescrever)"); + System.out.println("6. read - Ler dados de arquivo (leitura sequencial)"); + System.out.println("7. mv - Mover ou renomear arquivo/diretorio"); + System.out.println("8. ls - Listar conteudo de diretorio (pode ser recursivo)"); + System.out.println("9. cp - Copiar arquivo ou diretorio (pode ser recursivo)"); + System.out.println("0. exit - Sair do sistema de arquivos"); + System.out.print("\nDigite o numero do comando desejado: "); String opcao = scanner.nextLine(); try { @@ -170,25 +170,25 @@ public static void menu() { } public static void chmod() throws CaminhoNaoEncontradoException, PermissaoException { - System.out.println("Insira o caminho do arquivo ou diretório:"); + System.out.println("Insira o caminho do arquivo ou diretorio:"); String caminho = scanner.nextLine(); - System.out.println("Insira o usuário para o qual deseja alterar as permissões:"); + System.out.println("Insira o usuario para o qual deseja alterar as permissoes:"); String usuarioAlvo = scanner.nextLine(); - System.out.println("Insira a permissão (formato: 3 caracteres\"rwx\"):"); + System.out.println("Insira a permissao (formato: 3 caracteres\"rwx\"):"); String permissoes = scanner.nextLine(); fileSystem.chmod(caminho, user, usuarioAlvo, permissoes); } public static void mkdir() throws CaminhoJaExistenteException, PermissaoException { - System.out.println("Insira o caminho do diretório a ser criado:"); + System.out.println("Insira o caminho do diretorio a ser criado:"); String caminho = scanner.nextLine(); fileSystem.mkdir(caminho, user); } public static void rm() throws CaminhoNaoEncontradoException, PermissaoException { - System.out.println("Insira o caminho do diretório a ser removido:"); + System.out.println("Insira o caminho do diretorio a ser removido:"); String caminho = scanner.nextLine(); System.out.println("Remover recursivamente? (true/false):"); boolean recursivo = Boolean.parseBoolean(scanner.nextLine()); @@ -208,7 +208,7 @@ public static void write() throws CaminhoNaoEncontradoException, PermissaoExcept String caminho = scanner.nextLine(); System.out.println("Anexar? (true/false):"); boolean anexar = Boolean.parseBoolean(scanner.nextLine()); - System.out.println("Insira o conteúdo a ser escrito:"); + System.out.println("Insira o conteudo a ser escrito:"); String content = scanner.nextLine(); byte[] buffer = content.getBytes(); @@ -233,7 +233,7 @@ public static void read() throws CaminhoNaoEncontradoException, PermissaoExcepti byte[] buffer = new byte[tamanho]; fileSystem.read(caminho, user, buffer); - System.out.println("Conteúdo do arquivo:"); + System.out.println("Conteudo do arquivo:"); System.out.println(new String(buffer)); } @@ -247,7 +247,7 @@ public static void mv() throws CaminhoNaoEncontradoException, PermissaoException } public static void ls() throws CaminhoNaoEncontradoException, PermissaoException { - System.out.println("Insira o caminho do diretório a ser listado:"); + System.out.println("Insira o caminho do diretorio a ser listado:"); String caminho = scanner.nextLine(); System.out.println("Listar recursivamente? (true/false):"); boolean recursivo = Boolean.parseBoolean(scanner.nextLine()); diff --git a/filesys/FileSystemImpl.java b/filesys/FileSystemImpl.java index 1e4d7cd..cfec839 100644 --- a/filesys/FileSystemImpl.java +++ b/filesys/FileSystemImpl.java @@ -13,7 +13,7 @@ import java.util.Map; 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 Diretorio raiz; private Map usuarios = new HashMap<>(); private static Map usuariosGlobais = new HashMap<>(); @@ -23,7 +23,7 @@ public FileSystemImpl(List usuarios) { this.usuarios.put(ROOT_USER, new Usuario(ROOT_USER, "rwx", "/")); for (Usuario usuario : usuarios) { this.usuarios.put(usuario.getNome(), usuario); - usuariosGlobais.put(usuario.getNome(), usuario); // Adicione aqui + usuariosGlobais.put(usuario.getNome(), usuario); } // TODO: Carregar usuários adicionais do arquivo users/users se necessário } From 5206e64eb8804e79ad4fcda8005243a4c39a6c9f Mon Sep 17 00:00:00 2001 From: CarlosJFigueiredo Date: Thu, 5 Jun 2025 10:30:44 -0300 Subject: [PATCH 19/20] =?UTF-8?q?feat:=20adicionar=20verifica=C3=A7=C3=A3o?= =?UTF-8?q?=20para=20diret=C3=B3rios=20existentes=20no=20m=C3=A9todo=20mkd?= =?UTF-8?q?ir?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- filesys/FileSystemImpl.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/filesys/FileSystemImpl.java b/filesys/FileSystemImpl.java index 7807fb9..409df99 100644 --- a/filesys/FileSystemImpl.java +++ b/filesys/FileSystemImpl.java @@ -65,6 +65,7 @@ public void mkdir(String caminho, String usuario) throws CaminhoJaExistenteExcep if (partes[i].isEmpty()) continue; caminhoAtual.append("/").append(partes[i]); Map filhos = atual.getFilhos(); + boolean ehUltimo = (i == partes.length - 1); if (!filhos.containsKey(partes[i])) { // Verifica permissão de escrita e execução no diretório atual if (!atual.temPermissao(usuario, 'w') || !atual.temPermissao(usuario, 'x')) { @@ -73,6 +74,9 @@ public void mkdir(String caminho, String usuario) throws CaminhoJaExistenteExcep // Cria o diretório intermediário Diretorio novo = new Diretorio(partes[i], "rwx", usuario); atual.adicionarFilho(novo); + } else if (ehUltimo) { + // Se o diretório final já existe, lança exceção + throw new CaminhoJaExistenteException("Diretório já existe: " + caminho); } // Avança para o próximo diretório atual = (Diretorio) filhos.get(partes[i]); From d5d0dd09724c0b8a55d2b8a7f38a6400498fbc37 Mon Sep 17 00:00:00 2001 From: CarlosJFigueiredo Date: Fri, 20 Jun 2025 17:13:45 -0300 Subject: [PATCH 20/20] =?UTF-8?q?refactor:=20remover=20checklist=20do=20pr?= =?UTF-8?q?ojeto=20e=20limpar=20c=C3=B3digo=20n=C3=A3o=20utilizado?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHECKLIST_DO_GRUPO.md | 68 ------------------------------------- filesys/FileSystemImpl.java | 15 ++------ model/Arquivo.java | 13 +------ model/Diretorio.java | 2 +- 4 files changed, 5 insertions(+), 93 deletions(-) delete mode 100644 CHECKLIST_DO_GRUPO.md diff --git a/CHECKLIST_DO_GRUPO.md b/CHECKLIST_DO_GRUPO.md deleted file mode 100644 index 199180b..0000000 --- a/CHECKLIST_DO_GRUPO.md +++ /dev/null @@ -1,68 +0,0 @@ -# Checklist do Projeto - Sistema de Arquivos POSIX - -OIII! -Segue um checklist detalhado do que ainda falta fazer no nosso projeto, com explicações simples para cada item. -Se tiverem dúvidas, podem perguntar! - ---- - -## 1. Métodos principais do sistema de arquivos - -Ainda precisamos implementar os métodos principais que fazem o sistema funcionar, conforme pede o professor. -Esses métodos são chamados quando o usuário executa comandos como criar, remover, copiar, mover arquivos e diretórios. - -**Faltam implementar:** - -**No código, já deixei `// TODO` nesses métodos para facilitar achar onde falta implementar. -O VS Code mostra uma linha azul do lado esquerdo nesses pontos.** - ---- - -## 2. Testes Unitários - -**Faltam testes para:** -- Testar casos de erro (ex: tentar remover sem permissão, tentar ler arquivo inexistente, etc.) -- **Testes de permissão:** Já existe um arquivo chamado `PermissionTest.java` que testa se o sistema está respeitando as permissões de leitura, escrita -e execução para cada usuário. - mas olhem la - -É importante rodar e revisar esses testes para garantir que o controle de acesso está correto. -Não lembro se precisa de mais testes, olha no arquivo :) - ---- - -## 3. Permissões e Exceções - -Em todas as operações, precisamos garantir: -- O usuário só pode fazer a operação se tiver permissão (leitura, escrita, execução) -- Se tentar fazer algo sem permissão, deve lançar uma exceção (erro) -- Se tentar acessar um caminho que não existe, também deve lançar exceção - -**Exemplo:** -Se o usuário "joao" tentar apagar um arquivo que não é dele e não tem permissão, o sistema deve impedir e mostrar um erro. - ---- - -## 4. Menu Interativo - -O menu interativo é fundamental para a apresentação e para o professor testar o sistema. -Ele permite digitar comandos como `mkdir`, `touch`, `ls`, etc., e mostra o resultado na tela. - -**Detalhes importantes:** -- O menu já está implementado na classe `Main.java`. -- Ele lê os usuários do arquivo `users/users`. -- Cada opção do menu chama um método do sistema de arquivos (ex: criar diretório, listar, remover, etc.). -- O menu já trata exceções e mostra mensagens de erro se o usuário não tiver permissão ou se o caminho não existir. -- Para comandos de leitura (`read`), o menu já está preparado para ler arquivos grandes em partes, usando o buffer e o `Offset`. -- **Revisar o menu:** Garantir que todos os comandos estão funcionando, que as mensagens estão claras e que o sistema responde corretamente a erros de permissão e caminhos inválidos. - - ---- - -Não mudem a classe **FileSystem.java**!!! - ---- - -**:p** -- Sempre procure pelos `// TODO` no código para ver o que falta. - ---- diff --git a/filesys/FileSystemImpl.java b/filesys/FileSystemImpl.java index 409df99..11163e2 100644 --- a/filesys/FileSystemImpl.java +++ b/filesys/FileSystemImpl.java @@ -25,14 +25,12 @@ public FileSystemImpl(List usuarios) { this.usuarios.put(usuario.getNome(), usuario); usuariosGlobais.put(usuario.getNome(), usuario); } - // TODO: Carregar usuários adicionais do arquivo users/users se necessário } public static Usuario getUsuarioGlobal(String nome) { return usuariosGlobais.get(nome); } - // TODO: Validar se o método navegar cobre todos os casos de caminhos relativos e absolutos private ElementoFS navegar(String caminho) throws CaminhoNaoEncontradoException { if (caminho.equals("/")) return raiz; String[] partes = caminho.split("/"); @@ -95,10 +93,9 @@ public void chmod(String caminho, String usuario, String usuarioAlvo, String per } else { elem.setPermissoesPadrao(permissao); } - // TODO: Validar permissões para arquivos se for necessário permissões específicas por usuário } - // TODO: Implementar método rm (remoção de arquivos/diretórios) + @Override public void rm(String caminho, String usuario, boolean recursivo) throws CaminhoNaoEncontradoException, PermissaoException { @@ -149,10 +146,10 @@ public void touch(String caminho, String usuario) throws CaminhoJaExistenteExcep if (pai.getFilhos().containsKey(nomeArquivo)) throw new CaminhoJaExistenteException("Arquivo já existe: " + nomeArquivo); if (!pai.temPermissao(usuario, 'w')) throw new PermissaoException("Sem permissão para criar arquivo em: " + caminhoPai); pai.adicionarFilho(new Arquivo(nomeArquivo, "rw-", usuario)); - // TODO: Permitir criar arquivos com permissões diferentes se necessário + } - // TODO: Implementar método write (escrita em arquivos) + @Override public void write(String caminho, String usuario, boolean anexar, byte[] buffer) throws CaminhoNaoEncontradoException, PermissaoException { @@ -184,7 +181,6 @@ public void write(String caminho, String usuario, boolean anexar, byte[] buffer) } } - // TODO: Implementar método read (leitura de arquivos) @Override public void read(String caminho, String usuario, byte[] buffer) throws CaminhoNaoEncontradoException, PermissaoException { @@ -209,7 +205,6 @@ public void read(String caminho, String usuario, byte[] buffer) } } - // TODO: Implementar método mv (movimentação/renomeação) @Override public void mv(String caminhoAntigo, String caminhoNovo, String usuario) throws CaminhoNaoEncontradoException, PermissaoException { @@ -249,7 +244,6 @@ public void mv(String caminhoAntigo, String caminhoNovo, String usuario) paiNovo.adicionarFilho(elemento); } - // TODO: Implementar método ls (listagem de diretórios) @Override public void ls(String caminho, String usuario, boolean recursivo) throws CaminhoNaoEncontradoException, PermissaoException { ElementoFS elemento = navegar(caminho); @@ -282,7 +276,6 @@ private void listarDiretorio(Diretorio dir, String caminho, String usuario, bool } } - // TODO: Implementar método cp (cópia de arquivos/diretórios) @Override public void cp(String caminhoOrigem, String caminhoDestino, String usuario, boolean recursivo) throws CaminhoNaoEncontradoException, PermissaoException { @@ -326,12 +319,10 @@ public void cp(String caminhoOrigem, String caminhoDestino, String usuario, bool } } - // TODO: Implementar carregamento de usuários a partir do arquivo users/users se necessário public void addUser(String user) { throw new UnsupportedOperationException("Método não implementado 'addUser'"); } - // TODO: Adicionar métodos auxiliares para facilitar operações recursivas, busca de pai, etc. public int getTamanhoArquivo(String caminho) throws CaminhoNaoEncontradoException { ElementoFS elemento = navegar(caminho); if (!elemento.isArquivo()) throw new CaminhoNaoEncontradoException("O caminho não é um arquivo."); diff --git a/model/Arquivo.java b/model/Arquivo.java index 1474409..c9e5f0f 100644 --- a/model/Arquivo.java +++ b/model/Arquivo.java @@ -4,27 +4,16 @@ import java.util.List; public class Arquivo extends ElementoFS { - private List blocos; + private List blocos; // conteúdo do arquivo private long tamanho; public Arquivo(String nome, String permissoes, String dono) { super(nome, permissoes, dono); - // this.arquivo = new Bloco[0]; this.blocos = new ArrayList<>(); this.tamanho = 0; } - /* - * public Bloco[] getArquivo() { - * return arquivo; - * } - * - * public void setArquivo(Bloco[] arquivo) { - * this.arquivo = arquivo; - * } - */ - public void adicionarBloco(byte[] dados) { blocos.add(dados); tamanho += dados.length; diff --git a/model/Diretorio.java b/model/Diretorio.java index 51e921b..b5bcd6b 100644 --- a/model/Diretorio.java +++ b/model/Diretorio.java @@ -32,7 +32,7 @@ public boolean temPermissao(String usuario, char tipoPermissao) { String permissoesUsuario = acessosPorUsuario.get(usuario); if (permissoesUsuario != null && permissoesUsuario.indexOf(tipoPermissao) >= 0) return true; // Verifica permissão global do usuário (/**) - Usuario usuarioGlobal = FileSystemImpl.getUsuarioGlobal(usuario); // Implemente esse método estático + Usuario usuarioGlobal = FileSystemImpl.getUsuarioGlobal(usuario); if (usuarioGlobal != null && usuarioGlobal.getDiretorio().equals("/**") && usuarioGlobal.getPermissao().indexOf(tipoPermissao) >= 0) { return true; }