From 397098abc4beadb394342dfe6a8d52a67eab1740 Mon Sep 17 00:00:00 2001 From: alvimdev Date: Sun, 13 Apr 2025 13:30:25 -0300 Subject: [PATCH 01/22] fea: implement file and directory management with error handling --- Main.java | 18 ++++++------- filesys/Arquivo.java | 34 +++++++++++++++++++++++ filesys/Diretorio.java | 54 +++++++++++++++++++++++++++++++++++++ filesys/FileSystem.java | 4 +-- filesys/FileSystemImpl.java | 50 +++++++++++++++++++++++++++++++--- filesys/IFileSystem.java | 4 +-- 6 files changed, 147 insertions(+), 17 deletions(-) create mode 100644 filesys/Arquivo.java create mode 100644 filesys/Diretorio.java diff --git a/Main.java b/Main.java index 3b8673a..c8b3010 100644 --- a/Main.java +++ b/Main.java @@ -86,13 +86,13 @@ public static void main(String[] args) { // Obs: Como passar a lista de usuários para o FileSystem? fileSystem = new FileSystem(/*usuários?*/); - // // 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()); - // } + // 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 | CaminhoNaoEncontradoException e) { + System.out.println(e.getMessage()); + } // Menu interativo. menu(); @@ -175,7 +175,7 @@ public static void chmod() throws CaminhoNaoEncontradoException, PermissaoExcept fileSystem.chmod(caminho, user, usuarioAlvo, permissoes); } - public static void mkdir() throws CaminhoJaExistenteException, PermissaoException { + public static void mkdir() throws CaminhoJaExistenteException, PermissaoException, CaminhoNaoEncontradoException { System.out.println("Insira o caminho do diretório a ser criado:"); String caminho = scanner.nextLine(); @@ -191,7 +191,7 @@ public static void rm() throws CaminhoNaoEncontradoException, PermissaoException fileSystem.rm(caminho, user, recursivo); } - public static void touch() throws CaminhoJaExistenteException, PermissaoException { + public static void touch() throws CaminhoJaExistenteException, PermissaoException, CaminhoNaoEncontradoException { System.out.println("Insira o caminho do arquivo a ser criado:"); String caminho = scanner.nextLine(); diff --git a/filesys/Arquivo.java b/filesys/Arquivo.java new file mode 100644 index 0000000..5b6c64b --- /dev/null +++ b/filesys/Arquivo.java @@ -0,0 +1,34 @@ +package filesys; + +public class Arquivo extends Diretorio { + private byte[] conteudo; + + public Arquivo(String nome, String permissoes, String dono) { + super(nome, permissoes, dono); + this.conteudo = new byte[0]; + this.filhos = null; // Arquivos não podem ter filhos + } + + public byte[] getConteudo() { + return conteudo; + } + + public void setConteudo(byte[] conteudo) { + this.conteudo = conteudo; + } + + @Override + public boolean isArquivo() { + return true; // Um `File` é um arquivo + } + + @Override + public void adicionarFilho(Diretorio filho) { + throw new UnsupportedOperationException("Arquivos não podem conter filhos."); + } + + @Override + public void removerFilho(String nome) { + throw new UnsupportedOperationException("Arquivos não podem conter filhos."); + } +} \ No newline at end of file diff --git a/filesys/Diretorio.java b/filesys/Diretorio.java new file mode 100644 index 0000000..d74baec --- /dev/null +++ b/filesys/Diretorio.java @@ -0,0 +1,54 @@ +package filesys; + +import java.util.HashMap; +import java.util.Map; + +public class Diretorio { + protected String nome; + protected String permissoes; + protected String dono; + protected Map filhos; + + public Diretorio(String nome, String permissoes, String dono) { + this.nome = nome; + this.permissoes = permissoes; + this.dono = dono; + this.filhos = new HashMap<>(); + } + + public String getNome() { + return nome; + } + + public String getPermissoes() { + return permissoes; + } + + public void setPermissoes(String permissoes) { + this.permissoes = permissoes; + } + + public String getDono() { + return dono; + } + + public void setDono(String dono) { + this.dono = dono; + } + + public Map getFilhos() { + return filhos; + } + + public void adicionarFilho(Diretorio filho) { + filhos.put(filho.getNome(), filho); + } + + public void removerFilho(String nome) { + filhos.remove(nome); + } + + public boolean isArquivo() { + return false; // Por padrão, um `Diretorio` não é um arquivo + } +} \ No newline at end of file diff --git a/filesys/FileSystem.java b/filesys/FileSystem.java index 8d7a83b..ff0e70f 100644 --- a/filesys/FileSystem.java +++ b/filesys/FileSystem.java @@ -20,7 +20,7 @@ public void chmod(String caminho, String usuario, String usuarioAlvo, String per } @Override - public void mkdir(String caminho, String usuario) throws CaminhoJaExistenteException, PermissaoException { + public void mkdir(String caminho, String usuario) throws CaminhoJaExistenteException, PermissaoException, CaminhoNaoEncontradoException { fileSystemImpl.mkdir(caminho, usuario); } @@ -31,7 +31,7 @@ public void rm(String caminho, String usuario, boolean recursivo) } @Override - public void touch(String caminho, String usuario) throws CaminhoJaExistenteException, PermissaoException { + public void touch(String caminho, String usuario) throws CaminhoJaExistenteException, PermissaoException, CaminhoNaoEncontradoException { fileSystemImpl.touch(caminho, usuario); } diff --git a/filesys/FileSystemImpl.java b/filesys/FileSystemImpl.java index 45fa05d..98ad55a 100644 --- a/filesys/FileSystemImpl.java +++ b/filesys/FileSystemImpl.java @@ -10,12 +10,43 @@ // e atributos & métodos privados podem ser adicionados public final class FileSystemImpl implements IFileSystem { private static final String ROOT_USER = "root"; // pode ser necessário + private Diretorio root; public FileSystemImpl() {} + private Diretorio navegar(String caminho) throws CaminhoNaoEncontradoException { + if (caminho.equals("/")) { + return root; + } + + String[] partes = caminho.split("/"); + Diretorio atual = root; + + for (String parte : partes) { + if (parte.isEmpty()) continue; + if (!atual.getFilhos().containsKey(parte)) { + throw new CaminhoNaoEncontradoException("Caminho não encontrado: " + caminho); + } + atual = atual.getFilhos().get(parte); + } + + return atual; + } + @Override - public void mkdir(String caminho, String nome) throws CaminhoJaExistenteException, PermissaoException { - throw new UnsupportedOperationException("Método não implementado 'mkdir'"); + public void mkdir(String caminho, String usuario) throws CaminhoJaExistenteException, PermissaoException, CaminhoNaoEncontradoException { + Diretorio parent = navegar(caminho.substring(0, caminho.lastIndexOf('/'))); + String nomeDiretorio = caminho.substring(caminho.lastIndexOf('/') + 1); + + if (parent.isArquivo()) { + throw new UnsupportedOperationException("Não é possível criar um diretório dentro de um arquivo."); + } + + if (parent.getFilhos().containsKey(nomeDiretorio)) { + throw new CaminhoJaExistenteException("Diretório já existe: " + nomeDiretorio); + } + + parent.adicionarFilho(new Diretorio(nomeDiretorio, "rwx", usuario)); } @Override @@ -31,8 +62,19 @@ public void rm(String caminho, String usuario, boolean recursivo) } @Override - public void touch(String caminho, String usuario) throws CaminhoJaExistenteException, PermissaoException { - throw new UnsupportedOperationException("Método não implementado 'touch'"); + public void touch(String caminho, String usuario) throws CaminhoJaExistenteException, PermissaoException, CaminhoNaoEncontradoException { + Diretorio parent = navegar(caminho.substring(0, caminho.lastIndexOf('/'))); + String nomeArquivo = caminho.substring(caminho.lastIndexOf('/') + 1); + + if (parent.isArquivo()) { + throw new PermissaoException("Não é possível criar um arquivo dentro de um arquivo."); + } + + if (parent.getFilhos().containsKey(nomeArquivo)) { + throw new CaminhoJaExistenteException("Arquivo já existe: " + nomeArquivo); + } + + parent.adicionarFilho(new Arquivo(nomeArquivo, "rw-", usuario)); } @Override diff --git a/filesys/IFileSystem.java b/filesys/IFileSystem.java index a0f0ce0..5d0326b 100644 --- a/filesys/IFileSystem.java +++ b/filesys/IFileSystem.java @@ -14,14 +14,14 @@ public interface IFileSystem { // Cria um novo diretório. Se o diretório já existir, será lançada uma exceção. // Se o usuario não tiver permissão para criar o diretório, será lançada uma exceção. - void mkdir(String caminho, String usuario) throws CaminhoJaExistenteException, PermissaoException; + void mkdir(String caminho, String usuario) throws CaminhoJaExistenteException, PermissaoException, CaminhoNaoEncontradoException; // Remove um arquivo ou diretório. Se o diretório não existir, será lançada uma exceção. // Caso recursivo seja true, o diretório será removido recursivamente. void rm(String caminho, String usuario, boolean recursivo) throws CaminhoNaoEncontradoException, PermissaoException; // Cria um novo arquivo. Atenção: Se o arquivo já existir, será lançada uma exceção. - void touch(String caminho, String usuario) throws CaminhoJaExistenteException, PermissaoException; + void touch(String caminho, String usuario) throws CaminhoJaExistenteException, PermissaoException, CaminhoNaoEncontradoException; // Escreve dados em um arquivo. Se o diretório não existir, será lançada uma exceção. // Caso o diretório exista, o arquivo será criado ou sobrescrito. From b8d7c9d90470b6bc37adc350613c19fac0515765 Mon Sep 17 00:00:00 2001 From: alvimdev Date: Wed, 16 Apr 2025 16:09:33 -0300 Subject: [PATCH 02/22] fea: enhance file system implementation with user management and permission handling and implementing FileSystemInterface --- filesys/Arquivo.java | 46 ++++++- filesys/Diretorio.java | 109 ++++++++++------ filesys/FileSystemImpl.java | 248 ++++++++++++++++++++++++++++++++---- filesys/Usuario.java | 46 +++++++ 4 files changed, 380 insertions(+), 69 deletions(-) create mode 100644 filesys/Usuario.java diff --git a/filesys/Arquivo.java b/filesys/Arquivo.java index 5b6c64b..15633bd 100644 --- a/filesys/Arquivo.java +++ b/filesys/Arquivo.java @@ -1,25 +1,57 @@ package filesys; +import java.util.ArrayList; +import java.util.List; + public class Arquivo extends Diretorio { - private byte[] conteudo; + private static final int TAMANHO_BLOCO = 4096; // 4KB por bloco (ajuste conforme necessário) + private List blocos; + private long tamanho; public Arquivo(String nome, String permissoes, String dono) { super(nome, permissoes, dono); - this.conteudo = new byte[0]; + this.blocos = new ArrayList<>(); + this.tamanho = 0; this.filhos = null; // Arquivos não podem ter filhos } - public byte[] getConteudo() { - return conteudo; + // Classe interna para representar blocos + public static class Bloco { + byte[] dados; + + Bloco() { + this.dados = new byte[TAMANHO_BLOCO]; + } + } + + public void addBloco(Bloco bloco) { + this.blocos.add(bloco); + } + + public void clearBlocos() { + this.blocos.clear(); + this.tamanho = 0; + } + + public List getBlocos() { + return blocos; + } + + public void setBlocos(List blocos) { + this.blocos = blocos; + } + + public void incrementTamnho(long tamanho) { + this.tamanho += tamanho; } - public void setConteudo(byte[] conteudo) { - this.conteudo = conteudo; + public long getTamanho() { + return tamanho; } @Override public boolean isArquivo() { - return true; // Um `File` é um arquivo + return true; } @Override diff --git a/filesys/Diretorio.java b/filesys/Diretorio.java index d74baec..9ec7789 100644 --- a/filesys/Diretorio.java +++ b/filesys/Diretorio.java @@ -4,51 +4,86 @@ import java.util.Map; public class Diretorio { - protected String nome; - protected String permissoes; - protected String dono; - protected Map filhos; - - public Diretorio(String nome, String permissoes, String dono) { - this.nome = nome; - this.permissoes = permissoes; - this.dono = dono; - this.filhos = new HashMap<>(); - } + protected String nome; + protected String permissoes; + protected String dono; + protected Map filhos; + protected Map permissoesEspecificas = new HashMap<>(); - public String getNome() { - return nome; - } + public Diretorio(String nome, String permissoes, String dono) { + this.nome = nome; + this.permissoes = permissoes; + this.dono = dono; + this.filhos = new HashMap<>(); + } - public String getPermissoes() { - return permissoes; + public void setPermissaoUsuario(String usuario, String permissao) { + // Valida o formato da permissão (rwx com 3 caracteres) + if (permissao == null || permissao.length() != 3) { + throw new IllegalArgumentException("Permissão deve ter 3 caracteres (rwx)"); } + permissoesEspecificas.put(usuario, permissao); + } - public void setPermissoes(String permissoes) { - this.permissoes = permissoes; - } + public boolean temPermissao(String usuario, char permissaoNecessaria) { + // Root tem todas as permissões + if ("root".equals(usuario)) return true; - public String getDono() { - return dono; - } + // Dono tem todas as permissões + if (usuario.equals(dono)) return true; - public void setDono(String dono) { - this.dono = dono; + // Verifica permissões específicas do usuário + String permissoesUsuario = permissoesEspecificas.get(usuario); + if (permissoesUsuario != null && permissoesUsuario.indexOf(permissaoNecessaria) != -1) { + return true; } - public Map getFilhos() { - return filhos; - } + return false; + } - public void adicionarFilho(Diretorio filho) { - filhos.put(filho.getNome(), filho); - } + public String getPermissoesUsuario(String usuario) { + if ("root".equals(usuario)) return "rwx"; + if (usuario.equals(dono)) return permissoes; + return permissoesEspecificas.getOrDefault(usuario, "---"); + } - public void removerFilho(String nome) { - filhos.remove(nome); - } + public String getNome() { + return nome; + } - public boolean isArquivo() { - return false; // Por padrão, um `Diretorio` não é um arquivo - } -} \ No newline at end of file + public String getPermissoes() { + return permissoes; + } + + public void setPermissoes(String permissoes) { + this.permissoes = permissoes; + } + + public String getDono() { + return dono; + } + + public void setNome(String nome) { + this.nome = nome; + } + + public void setDono(String dono) { + this.dono = dono; + } + + public Map getFilhos() { + return filhos; + } + + public void adicionarFilho(Diretorio filho) { + filhos.put(filho.getNome(), filho); + } + + public void removerFilho(String nome) { + filhos.remove(nome); + } + + public boolean isArquivo() { + return false; // Por padrão, um `Diretorio` não é um arquivo + } +} diff --git a/filesys/FileSystemImpl.java b/filesys/FileSystemImpl.java index 98ad55a..7d3b27c 100644 --- a/filesys/FileSystemImpl.java +++ b/filesys/FileSystemImpl.java @@ -3,27 +3,42 @@ import exception.CaminhoJaExistenteException; import exception.CaminhoNaoEncontradoException; import exception.PermissaoException; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.StringTokenizer; -// Implemente nesta classe o seu código do FileSystem. -// A classe pode ser alterada. -// O construtor, argumentos do construtor podem ser modificados -// e atributos & métodos privados podem ser adicionados public final class FileSystemImpl implements IFileSystem { - private static final String ROOT_USER = "root"; // pode ser necessário + private static final String ROOT_USER = "root"; + private Set users = new HashSet<>(); private Diretorio root; - public FileSystemImpl() {} + public FileSystemImpl() { + root = new Diretorio("/", "rwx", ROOT_USER); + users.add(new Usuario(ROOT_USER, "rwx", "/**")); + } + + public void addUser(Usuario user) { + if (users.stream().anyMatch(u -> u.getNome().equals(user.getNome()))) { + throw new IllegalArgumentException("Usuário com o mesmo nome já existe: " + user.getNome()); + } + users.add(user); + } + + public void removeUser(Usuario user) { + users.remove(user); + } private Diretorio navegar(String caminho) throws CaminhoNaoEncontradoException { if (caminho.equals("/")) { return root; } - String[] partes = caminho.split("/"); Diretorio atual = root; + StringTokenizer tokenizer = new StringTokenizer(caminho, "/"); - for (String parte : partes) { - if (parte.isEmpty()) continue; + while (tokenizer.hasMoreTokens()) { + String parte = tokenizer.nextToken(); if (!atual.getFilhos().containsKey(parte)) { throw new CaminhoNaoEncontradoException("Caminho não encontrado: " + caminho); } @@ -34,10 +49,15 @@ private Diretorio navegar(String caminho) throws CaminhoNaoEncontradoException { } @Override - public void mkdir(String caminho, String usuario) throws CaminhoJaExistenteException, PermissaoException, CaminhoNaoEncontradoException { + public void mkdir(String caminho, String usuario) + throws CaminhoJaExistenteException, PermissaoException, CaminhoNaoEncontradoException { Diretorio parent = navegar(caminho.substring(0, caminho.lastIndexOf('/'))); String nomeDiretorio = caminho.substring(caminho.lastIndexOf('/') + 1); + if (!parent.temPermissao(usuario, 'w')) { + throw new PermissaoException("Sem permissão para criar diretório em: " + caminho); + } + if (parent.isArquivo()) { throw new UnsupportedOperationException("Não é possível criar um diretório dentro de um arquivo."); } @@ -46,67 +66,245 @@ public void mkdir(String caminho, String usuario) throws CaminhoJaExistenteExcep throw new CaminhoJaExistenteException("Diretório já existe: " + nomeDiretorio); } - parent.adicionarFilho(new Diretorio(nomeDiretorio, "rwx", usuario)); + Usuario user = users.stream() + .filter(u -> u.getNome().equals(usuario)) + .findFirst() + .orElseThrow(() -> new PermissaoException("Usuário não encontrado: " + usuario)); + + parent.adicionarFilho(new Diretorio(nomeDiretorio, user.getPermissao(), user.getNome())); } @Override public void chmod(String caminho, String usuario, String usuarioAlvo, String permissao) throws CaminhoNaoEncontradoException, PermissaoException { - throw new UnsupportedOperationException("Método não implementado 'chmod'"); + Diretorio dir = navegar(caminho); + + if (!dir.temPermissao(usuario, 'w')) { + throw new PermissaoException("Usuário sem permissão para alterar permissões em: " + caminho); + } + + dir.setPermissaoUsuario(usuarioAlvo, permissao); } @Override public void rm(String caminho, String usuario, boolean recursivo) throws CaminhoNaoEncontradoException, PermissaoException { - throw new UnsupportedOperationException("Método não implementado 'rm'"); + if (caminho.equals("/")) { + throw new PermissaoException("Não é possível remover o diretório raiz."); + } + + Diretorio pai = navegar(caminho.substring(0, caminho.lastIndexOf('/'))); + String nomeAlvo = caminho.substring(caminho.lastIndexOf('/') + 1); + + Diretorio alvo = pai.getFilhos().get(nomeAlvo); + if (alvo == null) throw new CaminhoNaoEncontradoException("Caminho não encontrado: " + caminho); + + if (!alvo.temPermissao(usuario, 'w')) + throw new PermissaoException("Sem permissão para remover: " + caminho); + + if (!alvo.isArquivo()) { + if (!recursivo && !alvo.getFilhos().isEmpty()) { + throw new PermissaoException("Diretório não está vazio. Use recursivo=true."); + } + + if (recursivo) { + removerRecursivo(alvo, usuario); + } + } + + pai.removerFilho(nomeAlvo); + } + + private void removerRecursivo(Diretorio dir, String usuario) throws PermissaoException { + for (Diretorio filho : dir.getFilhos().values()) { + if (!filho.temPermissao(usuario, 'w')) { + throw new PermissaoException("Sem permissão para remover: " + filho.getNome()); + } + + if (!filho.isArquivo()) { + removerRecursivo(filho, usuario); + } + } + dir.getFilhos().clear(); } @Override - public void touch(String caminho, String usuario) throws CaminhoJaExistenteException, PermissaoException, CaminhoNaoEncontradoException { + public void touch(String caminho, String usuario) + throws CaminhoJaExistenteException, PermissaoException, CaminhoNaoEncontradoException { Diretorio parent = navegar(caminho.substring(0, caminho.lastIndexOf('/'))); String nomeArquivo = caminho.substring(caminho.lastIndexOf('/') + 1); + if (!parent.temPermissao(usuario, 'w')) { + throw new PermissaoException("Sem permissão para criar arquivo em: " + caminho); + } + if (parent.isArquivo()) { - throw new PermissaoException("Não é possível criar um arquivo dentro de um arquivo."); + throw new UnsupportedOperationException("Não é possível criar um arquivo dentro de um arquivo."); } if (parent.getFilhos().containsKey(nomeArquivo)) { throw new CaminhoJaExistenteException("Arquivo já existe: " + nomeArquivo); } - parent.adicionarFilho(new Arquivo(nomeArquivo, "rw-", usuario)); + Usuario user = users.stream() + .filter(u -> u.getNome().equals(usuario)) + .findFirst() + .orElseThrow(() -> new PermissaoException("Usuário não encontrado: " + usuario)); + + parent.adicionarFilho(new Arquivo(nomeArquivo, user.getPermissao(), user.getNome())); } @Override public void write(String caminho, String usuario, boolean anexar, byte[] buffer) throws CaminhoNaoEncontradoException, PermissaoException { - throw new UnsupportedOperationException("Método não implementado 'write'"); + Diretorio dir = navegar(caminho); + + if (!dir.isArquivo()) + throw new UnsupportedOperationException("Não é possível escrever em um diretório."); + if (!dir.temPermissao(usuario, 'w')) throw new PermissaoException("Sem permissão de escrita."); + + Arquivo arquivo = (Arquivo) dir; + + if (!anexar) arquivo.clearBlocos(); + + int offset = 0; + while (offset < buffer.length) { + Arquivo.Bloco bloco = new Arquivo.Bloco(); + int length = Math.min(buffer.length - offset, bloco.dados.length); + + if (length <= 0) { + throw new IllegalArgumentException("O tamanho do bloco não pode ser zero ou negativo."); + } + + System.arraycopy(buffer, offset, bloco.dados, 0, length); + offset += length; + } } - @Override public void read(String caminho, String usuario, byte[] buffer) throws CaminhoNaoEncontradoException, PermissaoException { - throw new UnsupportedOperationException("Método não implementado 'read'"); + Diretorio dir = navegar(caminho); + + if (!dir.isArquivo()) throw new PermissaoException("Não é possível ler de um diretório."); + if (!dir.temPermissao(usuario, 'r')) throw new PermissaoException("Sem permissão de leitura."); + + Arquivo arquivo = (Arquivo) dir; + + long fileSize = arquivo.getTamanho(); + if (buffer.length < fileSize) { + throw new IllegalArgumentException("Buffer é menor que o tamanho do arquivo."); + } + + int offset = 0; + for (Arquivo.Bloco bloco : arquivo.getBlocos()) { + int length = Math.min(buffer.length - offset, bloco.dados.length); + System.arraycopy(bloco.dados, 0, buffer, offset, length); + offset += length; + } } @Override public void mv(String caminhoAntigo, String caminhoNovo, String usuario) throws CaminhoNaoEncontradoException, PermissaoException { - throw new UnsupportedOperationException("Método não implementado 'mv'"); + if (caminhoAntigo.equals("/") || caminhoNovo.equals("/")) { + throw new PermissaoException("Não é possível mover o diretório raiz."); + } + + Diretorio paiAntigo = navegar(caminhoAntigo.substring(0, caminhoAntigo.lastIndexOf('/'))); + String nomeAntigo = caminhoAntigo.substring(caminhoAntigo.lastIndexOf('/') + 1); + Diretorio alvo = paiAntigo.getFilhos().get(nomeAntigo); + + if (alvo == null) throw new CaminhoNaoEncontradoException("Origem não encontrada."); + if (!alvo.temPermissao(usuario, 'w')) + throw new PermissaoException("Sem permissão de escrita no item de origem."); + + Diretorio paiNovo = navegar(caminhoNovo.substring(0, caminhoNovo.lastIndexOf('/'))); + String nomeNovo = caminhoNovo.substring(caminhoNovo.lastIndexOf('/') + 1); + + if (paiNovo.getFilhos().containsKey(nomeNovo)) { + throw new PermissaoException("Já existe um item no destino com esse nome."); + } + + paiAntigo.removerFilho(nomeAntigo); + alvo.setNome(nomeNovo); + paiNovo.adicionarFilho(alvo); } @Override - public void ls(String caminho, String usuario, boolean recursivo) throws CaminhoNaoEncontradoException, PermissaoException { - throw new UnsupportedOperationException("Método não implementado 'ls'"); + public void ls(String caminho, String usuario, boolean recursivo) + throws CaminhoNaoEncontradoException, PermissaoException { + Diretorio dir = navegar(caminho); + + if (!dir.temPermissao(usuario, 'r')) { + throw new PermissaoException("Sem permissão de leitura para listar o diretório."); + } + + String output = listar(dir, caminho, recursivo, usuario); + System.out.print(output); + } + + private String listar(Diretorio dir, String caminho, boolean recursivo, String usuario) { + StringBuilder output = new StringBuilder(); + output.append(caminho).append(":\n"); + for (Map.Entry entry : dir.getFilhos().entrySet()) { + Diretorio filho = entry.getValue(); + output + .append(" ") + .append(filho.isArquivo() ? "A" : "D") + .append(" ") + .append(filho.getPermissoesUsuario(usuario)) + .append(" ") + .append(filho.getDono()) + .append(" ") + .append(filho.getNome()) + .append("\n"); + if (recursivo && !filho.isArquivo()) { + output.append(listar(filho, caminho + "/" + filho.getNome(), true, usuario)); + } + } + return output.toString(); } @Override public void cp(String caminhoOrigem, String caminhoDestino, String usuario, boolean recursivo) throws CaminhoNaoEncontradoException, PermissaoException { - throw new UnsupportedOperationException("Método não implementado 'cp'"); + Diretorio origem = navegar(caminhoOrigem); + Diretorio destino = navegar(caminhoDestino); + + if (!origem.temPermissao(usuario, 'r')) { + throw new PermissaoException("Sem permissão de leitura na origem."); + } + if (!destino.temPermissao(usuario, 'w')) { + throw new PermissaoException("Sem permissão de escrita no destino."); + } + + if (origem.isArquivo()) { + copiarArquivo((Arquivo) origem, destino); + } else { + if (!recursivo) { + throw new PermissaoException("Diretório precisa de recursividade para cópia."); + } + copiarDiretorio((Diretorio) origem, destino, usuario); + } } - public void addUser(String user) { - throw new UnsupportedOperationException("Método não implementado 'addUser'"); + private void copiarArquivo(Arquivo origem, Diretorio destino) { + Arquivo copia = new Arquivo(origem.getNome(), origem.getPermissoes(), origem.getDono()); + for (Arquivo.Bloco bloco : origem.getBlocos()) { + copia.addBloco(bloco); + } + destino.adicionarFilho(copia); + } + + private void copiarDiretorio(Diretorio origem, Diretorio destino, String usuario) throws PermissaoException { + Diretorio copia = new Diretorio(origem.getNome(), origem.getPermissoes(), origem.getDono()); + destino.adicionarFilho(copia); + for (Diretorio filho : origem.getFilhos().values()) { + if (filho.isArquivo()) { + copiarArquivo((Arquivo) filho, copia); + } else { + copiarDiretorio(filho, copia, usuario); + } + } } } diff --git a/filesys/Usuario.java b/filesys/Usuario.java new file mode 100644 index 0000000..ea93b5d --- /dev/null +++ b/filesys/Usuario.java @@ -0,0 +1,46 @@ +package filesys; + +public class Usuario { + private String nome; + private String permissao; + private String dir; + + public Usuario(String nome, String permissao, String dir) { + this.setNome(nome); + this.setPermissao(permissao); + this.setDir(dir); + } + + public String getNome() { + return nome; + } + + public void setNome(String nome) { + this.nome = nome; + } + + public String getPermissao() { + return permissao; + } + + public void setPermissao(String permissao) { + this.permissao = permissao; + } + + public String getDir() { + return dir; + } + + public void setDir(String dir) { + this.dir = dir; + } + + @Override + public String toString() { + return "Usuario{" + + "nome='" + nome + '\'' + + ", permissao='" + permissao + '\'' + + ", dir='" + dir + '\'' + + '}'; + } +} From cbd635039764c1ff6ee25832e1c1988e02b36342 Mon Sep 17 00:00:00 2001 From: alvimdev Date: Wed, 16 Apr 2025 16:56:01 -0300 Subject: [PATCH 03/22] fea: implement user management with addUser and removeUser methods in FileSystem and FileSystemImpl --- Main.java | 32 +++++++++++++++++++------------- filesys/FileSystem.java | 10 ++++++++++ filesys/FileSystemImpl.java | 4 ++++ filesys/IFileSystem.java | 7 +++++++ 4 files changed, 40 insertions(+), 13 deletions(-) diff --git a/Main.java b/Main.java index c8b3010..c1f3d4c 100644 --- a/Main.java +++ b/Main.java @@ -1,4 +1,5 @@ import filesys.IFileSystem; +import filesys.Usuario; import java.util.Scanner; import java.io.FileNotFoundException; @@ -27,7 +28,7 @@ public class Main { private static Scanner scanner = new Scanner(System.in); // Usuário que está executando o programa - private static String user; + private static String username; // O sistema de arquivos é inteiramente virtual, ou seja, será reiniciado a cada execução do programa. // Logo, não é necessário salvar os arquivos em disco. O sistema será uma simulação em memória. @@ -39,7 +40,7 @@ public static void main(String[] args) { System.out.println("Usuário não fornecido"); return; } - user = args[1]; + username = args[1]; // Carrega a lista de usuários do sistema a partir de arquivo // Formato do arquivo users: @@ -62,12 +63,17 @@ public static void main(String[] args) { String dir = parts[1]; String dirPermission = parts[2]; - /* A FAZER: + /* + A FAZER: * 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 + */ + + Usuario user = new Usuario(userListed, dirPermission, dir); + fileSystem.addUser(user); } else { System.out.println("Formato ruim no arquivo de usuários. Linha: " + line); @@ -172,14 +178,14 @@ public static void chmod() throws CaminhoNaoEncontradoException, PermissaoExcept System.out.println("Insira a permissão (formato: 3 caracteres\"rwx\"):"); String permissoes = scanner.nextLine(); - fileSystem.chmod(caminho, user, usuarioAlvo, permissoes); + fileSystem.chmod(caminho, username, usuarioAlvo, permissoes); } public static void mkdir() throws CaminhoJaExistenteException, PermissaoException, CaminhoNaoEncontradoException { System.out.println("Insira o caminho do diretório a ser criado:"); String caminho = scanner.nextLine(); - fileSystem.mkdir(caminho, user); + fileSystem.mkdir(caminho, username); } public static void rm() throws CaminhoNaoEncontradoException, PermissaoException { @@ -188,14 +194,14 @@ public static void rm() throws CaminhoNaoEncontradoException, PermissaoException System.out.println("Remover recursivamente? (true/false):"); boolean recursivo = Boolean.parseBoolean(scanner.nextLine()); - fileSystem.rm(caminho, user, recursivo); + fileSystem.rm(caminho, username, recursivo); } public static void touch() throws CaminhoJaExistenteException, PermissaoException, CaminhoNaoEncontradoException { System.out.println("Insira o caminho do arquivo a ser criado:"); String caminho = scanner.nextLine(); - fileSystem.touch(caminho, user); + fileSystem.touch(caminho, username); } public static void write() throws CaminhoNaoEncontradoException, PermissaoException { @@ -207,7 +213,7 @@ public static void write() throws CaminhoNaoEncontradoException, PermissaoExcept String content = scanner.nextLine(); byte[] buffer = content.getBytes(); - fileSystem.write(caminho, user, anexar, buffer); + fileSystem.write(caminho, username, anexar, buffer); } public static void read() throws CaminhoNaoEncontradoException, PermissaoException { @@ -215,7 +221,7 @@ public static void read() throws CaminhoNaoEncontradoException, PermissaoExcepti 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. + fileSystem.read(caminho, username, buffer); // Lógica para ler arquivos maiores que o buffer deve ser implementada. } public static void mv() throws CaminhoNaoEncontradoException, PermissaoException { @@ -224,7 +230,7 @@ public static void mv() throws CaminhoNaoEncontradoException, PermissaoException System.out.println("Insira o novo caminho do arquivo:"); String caminhoNovo = scanner.nextLine(); - fileSystem.mv(caminhoAntigo, caminhoNovo, user); + fileSystem.mv(caminhoAntigo, caminhoNovo, username); } public static void ls() throws CaminhoNaoEncontradoException, PermissaoException { @@ -233,7 +239,7 @@ public static void ls() throws CaminhoNaoEncontradoException, PermissaoException System.out.println("Listar recursivamente? (true/false):"); boolean recursivo = Boolean.parseBoolean(scanner.nextLine()); - fileSystem.ls(caminho, user, recursivo); + fileSystem.ls(caminho, username, recursivo); } public static void cp() throws CaminhoNaoEncontradoException, PermissaoException { @@ -244,6 +250,6 @@ public static void cp() throws CaminhoNaoEncontradoException, PermissaoException System.out.println("Copiar recursivamente? (true/false):"); boolean recursivo = Boolean.parseBoolean(scanner.nextLine()); - fileSystem.cp(caminhoOrigem, caminhoDestino, user, recursivo); + fileSystem.cp(caminhoOrigem, caminhoDestino, username, recursivo); } } diff --git a/filesys/FileSystem.java b/filesys/FileSystem.java index ff0e70f..6345943 100644 --- a/filesys/FileSystem.java +++ b/filesys/FileSystem.java @@ -64,4 +64,14 @@ public void cp(String caminhoOrigem, String caminhoDestino, String usuario, bool throws CaminhoNaoEncontradoException, PermissaoException { fileSystemImpl.cp(caminhoOrigem, caminhoDestino, usuario, recursivo); } + + @Override + public void addUser(Usuario user) { + fileSystemImpl.addUser(user); + } + + @Override + public void removeUser(Usuario user) { + fileSystemImpl.removeUser(user); + } } \ No newline at end of file diff --git a/filesys/FileSystemImpl.java b/filesys/FileSystemImpl.java index 7d3b27c..5ace21c 100644 --- a/filesys/FileSystemImpl.java +++ b/filesys/FileSystemImpl.java @@ -18,6 +18,7 @@ public FileSystemImpl() { users.add(new Usuario(ROOT_USER, "rwx", "/**")); } + @Override public void addUser(Usuario user) { if (users.stream().anyMatch(u -> u.getNome().equals(user.getNome()))) { throw new IllegalArgumentException("Usuário com o mesmo nome já existe: " + user.getNome()); @@ -25,7 +26,10 @@ public void addUser(Usuario user) { users.add(user); } + @Override public void removeUser(Usuario user) { + if (user.getNome().equals(ROOT_USER)) + throw new IllegalArgumentException("Não é possível remover o usuário root."); users.remove(user); } diff --git a/filesys/IFileSystem.java b/filesys/IFileSystem.java index 5d0326b..46c849e 100644 --- a/filesys/IFileSystem.java +++ b/filesys/IFileSystem.java @@ -7,6 +7,13 @@ // Apenas modifique essa interface caso seja EXTREMAMENTE necessário. // Documente & Justifique TODAS asalterações feitas. public interface IFileSystem { + // Adiciona um usuário ao sistema. Se o usuário já existir, será lançada uma exceção. + void addUser(Usuario user); + + // Remove um usuário do sistema. + // O usuário root não pode ser removido. + void removeUser(Usuario user); + // Altera as permissões de um arquivo ou diretório. // Configura a permissao do caminho para o usuarioAlvo. // Apenas o usuario root ou que tenha permissão de rw do caminho podem alterar as permissões. From f86942b346d7286a69658cd965ed645ef32f9432 Mon Sep 17 00:00:00 2001 From: alvimdev Date: Fri, 2 May 2025 14:57:23 -0300 Subject: [PATCH 04/22] fea: enhance file reading functionality with offset management and implement Offset class --- Main.java | 30 ++++++++++++++------- filesys/FileSystem.java | 4 +-- filesys/FileSystemImpl.java | 34 +++++++++++++++++------- filesys/IFileSystem.java | 2 +- filesys/Offset.java | 53 +++++++++++++++++++++++++++++++++++++ 5 files changed, 101 insertions(+), 22 deletions(-) create mode 100644 filesys/Offset.java diff --git a/Main.java b/Main.java index c1f3d4c..29b7ee8 100644 --- a/Main.java +++ b/Main.java @@ -1,4 +1,5 @@ import filesys.IFileSystem; +import filesys.Offset; import filesys.Usuario; import java.util.Scanner; @@ -41,6 +42,10 @@ public static void main(String[] args) { return; } username = args[1]; + + // Cria o sistema de arquivos + // O sistema de arquivos é inteiramente virtual, ou seja, será reiniciado a cada execução do programa. + fileSystem = new FileSystem(); // Carrega a lista de usuários do sistema a partir de arquivo // Formato do arquivo users: @@ -86,11 +91,6 @@ public static void main(String[] args) { return; } - - // 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?*/); // 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" @@ -219,11 +219,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, username, buffer); // Lógica para ler arquivos maiores que o buffer deve ser implementada. - } + byte[] buffer = new byte[READ_BUFFER_SIZE]; + + Offset offset = new Offset(0); + int offsetAnterior; + int bytesLidos; + + do { + offsetAnterior = offset.getValue(); + fileSystem.read(caminho, username, buffer, offset); + bytesLidos = offset.getValue() - offsetAnterior; + + if (bytesLidos > 0) System.out.write(buffer, 0, bytesLidos); + } while (bytesLidos > 0); + System.out.flush(); + } + public static void mv() throws CaminhoNaoEncontradoException, PermissaoException { System.out.println("Insira o caminho do arquivo a ser movido:"); String caminhoAntigo = scanner.nextLine(); diff --git a/filesys/FileSystem.java b/filesys/FileSystem.java index 6345943..9e85dd8 100644 --- a/filesys/FileSystem.java +++ b/filesys/FileSystem.java @@ -42,9 +42,9 @@ public void write(String caminho, String usuario, boolean anexar, byte[] buffer) } @Override - public void read(String caminho, String usuario, byte[] buffer) + public void read(String caminho, String usuario, byte[] buffer, Offset offset) throws CaminhoNaoEncontradoException, PermissaoException { - fileSystemImpl.read(caminho, usuario, buffer); + fileSystemImpl.read(caminho, usuario, buffer, offset); } @Override diff --git a/filesys/FileSystemImpl.java b/filesys/FileSystemImpl.java index 5ace21c..8494ec0 100644 --- a/filesys/FileSystemImpl.java +++ b/filesys/FileSystemImpl.java @@ -181,30 +181,44 @@ public void write(String caminho, String usuario, boolean anexar, byte[] buffer) } System.arraycopy(buffer, offset, bloco.dados, 0, length); + arquivo.addBloco(bloco); offset += length; } } - public void read(String caminho, String usuario, byte[] buffer) + public void read(String caminho, String usuario, byte[] buffer, Offset offset) throws CaminhoNaoEncontradoException, PermissaoException { Diretorio dir = navegar(caminho); - if (!dir.isArquivo()) throw new PermissaoException("Não é possível ler de um diretório."); + if (!dir.isArquivo()) throw new UnsupportedOperationException("Não é possível ler de um diretório."); if (!dir.temPermissao(usuario, 'r')) throw new PermissaoException("Sem permissão de leitura."); Arquivo arquivo = (Arquivo) dir; - long fileSize = arquivo.getTamanho(); - if (buffer.length < fileSize) { - throw new IllegalArgumentException("Buffer é menor que o tamanho do arquivo."); - } + offset.setMax((int) fileSize); // garante limite do offset + + if (offset.getValue() >= fileSize) return; + + int arquivoOffset = offset.getValue(); + int bufferOffset = 0; - int offset = 0; for (Arquivo.Bloco bloco : arquivo.getBlocos()) { - int length = Math.min(buffer.length - offset, bloco.dados.length); - System.arraycopy(bloco.dados, 0, buffer, offset, length); - offset += length; + if (arquivoOffset >= bloco.dados.length) { + arquivoOffset -= bloco.dados.length; + continue; + } + + int bytesDisponiveis = bloco.dados.length - arquivoOffset; + int bytesParaLer = Math.min(buffer.length - bufferOffset, bytesDisponiveis); + System.arraycopy(bloco.dados, arquivoOffset, buffer, bufferOffset, bytesParaLer); + + bufferOffset += bytesParaLer; + arquivoOffset = 0; + + if (bufferOffset >= buffer.length) break; } + + offset.add(bufferOffset); // avança o offset } @Override diff --git a/filesys/IFileSystem.java b/filesys/IFileSystem.java index 46c849e..e77a608 100644 --- a/filesys/IFileSystem.java +++ b/filesys/IFileSystem.java @@ -38,7 +38,7 @@ public interface IFileSystem { // Lê dados de um arquivo. Se o arquivo não existir, será lançada uma exceção. // Leitura sequencial - todo o conteudo do arquivo sera lido e armazenado no buffer. - void read(String caminho, String usuario, byte[] buffer) throws CaminhoNaoEncontradoException, PermissaoException; + void read(String caminho, String usuario, byte[] buffer, Offset offset) throws CaminhoNaoEncontradoException, PermissaoException; // Move ou renomeia um arquivo ou diretório. Se o diretório não existir, será lançada uma exceção. // Se o diretório já existir, será sobrescrito. diff --git a/filesys/Offset.java b/filesys/Offset.java new file mode 100644 index 0000000..56430a8 --- /dev/null +++ b/filesys/Offset.java @@ -0,0 +1,53 @@ +package filesys; + +public class Offset { + private int value; + private int max; + + public Offset() { + this.setValue(0); + this.setMax(Integer.MAX_VALUE); + } + + public Offset(int initialValue) { + this.setValue(initialValue); + this.setMax(Integer.MAX_VALUE); + } + + public Offset(int initialValue, int max) { + this.setValue(initialValue); + this.setMax(max); + } + + public int getValue() { + return value; + } + + public void setValue(int value) { + if (value < 0) { + throw new IllegalArgumentException("Offset não pode ser negativo."); + } + if (value > max) { + throw new IllegalArgumentException("Offset excede o valor máximo permitido (" + max + ")."); + } + this.value = value; + } + + public void add(int delta) { + setValue(this.value + delta); + } + + public void reset() { + this.value = 0; + } + + public void setMax(int max) { + if (max < 0) throw new IllegalArgumentException("Max deve ser positivo."); + this.max = max; + if (value > max) value = max; // ajusta valor atual se necessário + } + + public int getMax() { + return max; + } +} From 71c8bc1fc5c54bd09751504850f799d465694b43 Mon Sep 17 00:00:00 2001 From: alvimdev Date: Sat, 3 May 2025 13:46:50 -0300 Subject: [PATCH 05/22] fea: enhance user management by adding exception handling for addUser method and updating directory structure --- Main.java | 19 ++++++++----------- filesys/Arquivo.java | 5 +++++ filesys/Diretorio.java | 28 +++++++++++++++++++++++++--- filesys/FileSystem.java | 2 +- filesys/FileSystemImpl.java | 27 +++++++++++---------------- filesys/IFileSystem.java | 2 +- 6 files changed, 51 insertions(+), 32 deletions(-) diff --git a/Main.java b/Main.java index 29b7ee8..8a65b77 100644 --- a/Main.java +++ b/Main.java @@ -19,7 +19,6 @@ public class Main { // Para esse tipo de execução, o tamanho max do buffer de // leitura pode ser menor. private static final String ROOT_USER = "root"; - private static final String ROOT_DIR = "/"; private static final int READ_BUFFER_SIZE = 256; // Sistema de arquivos @@ -65,7 +64,7 @@ public static void main(String[] args) { String[] parts = line.split(" "); if (parts.length == 3) { String userListed = parts[0]; - String dir = parts[1]; + String dir = parts[1].substring(0, 1); // O primeiro caractere é o diretório String dirPermission = parts[2]; /* @@ -76,6 +75,11 @@ public static void main(String[] args) { System.out.println(userListed + " " + dir + " " + dirPermission); // Somente imprime o usuário, diretório e permissão */ + if (userListed.equals(ROOT_USER)) { + System.out.println("O usuário root já está adicionado."); + continue; + } + Usuario user = new Usuario(userListed, dirPermission, dir); fileSystem.addUser(user); @@ -88,16 +92,9 @@ public static void main(String[] args) { 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"); - return; - } - - // 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 | CaminhoNaoEncontradoException e) { - System.out.println(e.getMessage()); + } catch (CaminhoNaoEncontradoException e) { + System.out.println("Erro ao adicionar usuário: " + e.getMessage()); } // Menu interativo. diff --git a/filesys/Arquivo.java b/filesys/Arquivo.java index 15633bd..fd49dcb 100644 --- a/filesys/Arquivo.java +++ b/filesys/Arquivo.java @@ -63,4 +63,9 @@ public void adicionarFilho(Diretorio filho) { public void removerFilho(String nome) { throw new UnsupportedOperationException("Arquivos não podem conter filhos."); } + + @Override + public String toString() { + return "A " + permissoes + " " + dono + " " + nome + " " + tamanho + " bytes"; + } } \ No newline at end of file diff --git a/filesys/Diretorio.java b/filesys/Diretorio.java index 9ec7789..b03b8be 100644 --- a/filesys/Diretorio.java +++ b/filesys/Diretorio.java @@ -7,14 +7,16 @@ public class Diretorio { protected String nome; protected String permissoes; protected String dono; + protected Diretorio pai; protected Map filhos; - protected Map permissoesEspecificas = new HashMap<>(); + protected Map permissoesEspecificas; public Diretorio(String nome, String permissoes, String dono) { this.nome = nome; this.permissoes = permissoes; this.dono = dono; this.filhos = new HashMap<>(); + this.permissoesEspecificas = new HashMap<>(); } public void setPermissaoUsuario(String usuario, String permissao) { @@ -32,13 +34,19 @@ public boolean temPermissao(String usuario, char permissaoNecessaria) { // Dono tem todas as permissões if (usuario.equals(dono)) return true; - // Verifica permissões específicas do usuário + // Verifica permissões específicas do usuário no diretório atual String permissoesUsuario = permissoesEspecificas.get(usuario); if (permissoesUsuario != null && permissoesUsuario.indexOf(permissaoNecessaria) != -1) { return true; } - return false; + // Se não houver permissões específicas, verifica permissões herdadas do pai + Diretorio pai = getPai(); // Método para obter o diretório pai + if (pai != null) { + return pai.temPermissao(usuario, permissaoNecessaria); + } + + return false; // Sem permissões } public String getPermissoesUsuario(String usuario) { @@ -75,7 +83,16 @@ public Map getFilhos() { return filhos; } + public Diretorio getPai() { + return pai; + } + + protected void setPai(Diretorio pai) { + this.pai = pai; + } + public void adicionarFilho(Diretorio filho) { + filho.setPai(this); filhos.put(filho.getNome(), filho); } @@ -86,4 +103,9 @@ public void removerFilho(String nome) { public boolean isArquivo() { return false; // Por padrão, um `Diretorio` não é um arquivo } + + @Override + public String toString() { + return "D " + permissoes + " " + dono + " " + nome; + } } diff --git a/filesys/FileSystem.java b/filesys/FileSystem.java index 9e85dd8..b75dce9 100644 --- a/filesys/FileSystem.java +++ b/filesys/FileSystem.java @@ -66,7 +66,7 @@ public void cp(String caminhoOrigem, String caminhoDestino, String usuario, bool } @Override - public void addUser(Usuario user) { + public void addUser(Usuario user) throws CaminhoNaoEncontradoException { fileSystemImpl.addUser(user); } diff --git a/filesys/FileSystemImpl.java b/filesys/FileSystemImpl.java index 8494ec0..708cb6c 100644 --- a/filesys/FileSystemImpl.java +++ b/filesys/FileSystemImpl.java @@ -14,16 +14,17 @@ public final class FileSystemImpl implements IFileSystem { private Diretorio root; public FileSystemImpl() { - root = new Diretorio("/", "rwx", ROOT_USER); users.add(new Usuario(ROOT_USER, "rwx", "/**")); + root = new Diretorio("/", "rwx", ROOT_USER); } @Override - public void addUser(Usuario user) { + public void addUser(Usuario user) throws CaminhoNaoEncontradoException { if (users.stream().anyMatch(u -> u.getNome().equals(user.getNome()))) { throw new IllegalArgumentException("Usuário com o mesmo nome já existe: " + user.getNome()); } users.add(user); + navegar(user.getDir()).setPermissaoUsuario(user.getNome(), user.getPermissao()); } @Override @@ -34,7 +35,7 @@ public void removeUser(Usuario user) { } private Diretorio navegar(String caminho) throws CaminhoNaoEncontradoException { - if (caminho.equals("/")) { + if (caminho.equals("/") || caminho.isEmpty()) { return root; } @@ -75,7 +76,7 @@ public void mkdir(String caminho, String usuario) .findFirst() .orElseThrow(() -> new PermissaoException("Usuário não encontrado: " + usuario)); - parent.adicionarFilho(new Diretorio(nomeDiretorio, user.getPermissao(), user.getNome())); + parent.adicionarFilho(new Diretorio(nomeDiretorio, parent.getPermissoes(), user.getNome())); } @Override @@ -264,24 +265,18 @@ public void ls(String caminho, String usuario, boolean recursivo) private String listar(Diretorio dir, String caminho, boolean recursivo, String usuario) { StringBuilder output = new StringBuilder(); output.append(caminho).append(":\n"); + for (Map.Entry entry : dir.getFilhos().entrySet()) { Diretorio filho = entry.getValue(); - output - .append(" ") - .append(filho.isArquivo() ? "A" : "D") - .append(" ") - .append(filho.getPermissoesUsuario(usuario)) - .append(" ") - .append(filho.getDono()) - .append(" ") - .append(filho.getNome()) - .append("\n"); + + output.append(" ").append(filho.toString()).append("\n"); + if (recursivo && !filho.isArquivo()) { - output.append(listar(filho, caminho + "/" + filho.getNome(), true, usuario)); + output.append(listar(filho, caminho + filho.getNome(), recursivo, usuario)); } } return output.toString(); - } + } @Override public void cp(String caminhoOrigem, String caminhoDestino, String usuario, boolean recursivo) diff --git a/filesys/IFileSystem.java b/filesys/IFileSystem.java index e77a608..5b9fe02 100644 --- a/filesys/IFileSystem.java +++ b/filesys/IFileSystem.java @@ -8,7 +8,7 @@ // Documente & Justifique TODAS asalterações feitas. public interface IFileSystem { // Adiciona um usuário ao sistema. Se o usuário já existir, será lançada uma exceção. - void addUser(Usuario user); + void addUser(Usuario user) throws CaminhoNaoEncontradoException; // Remove um usuário do sistema. // O usuário root não pode ser removido. From cb6e24a037e5fa025e2e4a9a05d425b74666e7cf Mon Sep 17 00:00:00 2001 From: alvimdev Date: Sat, 3 May 2025 14:13:53 -0300 Subject: [PATCH 06/22] fea: refactor user removal method to accept username and enhance Arquivo class with block data handling --- filesys/Arquivo.java | 9 +++++++++ filesys/FileSystem.java | 4 ++-- filesys/FileSystemImpl.java | 22 ++++++++++++---------- filesys/IFileSystem.java | 2 +- 4 files changed, 24 insertions(+), 13 deletions(-) diff --git a/filesys/Arquivo.java b/filesys/Arquivo.java index fd49dcb..23d75ff 100644 --- a/filesys/Arquivo.java +++ b/filesys/Arquivo.java @@ -22,6 +22,11 @@ public static class Bloco { Bloco() { this.dados = new byte[TAMANHO_BLOCO]; } + + public Bloco(byte[] dados2) { + this.dados = new byte[dados2.length]; + System.arraycopy(dados2, 0, this.dados, 0, Math.min(dados2.length, TAMANHO_BLOCO)); + } } public void addBloco(Bloco bloco) { @@ -33,6 +38,10 @@ public void clearBlocos() { this.tamanho = 0; } + public int getTamMaxBloco() { + return TAMANHO_BLOCO; + } + public List getBlocos() { return blocos; } diff --git a/filesys/FileSystem.java b/filesys/FileSystem.java index b75dce9..b1e5de2 100644 --- a/filesys/FileSystem.java +++ b/filesys/FileSystem.java @@ -71,7 +71,7 @@ public void addUser(Usuario user) throws CaminhoNaoEncontradoException { } @Override - public void removeUser(Usuario user) { - fileSystemImpl.removeUser(user); + public void removeUser(String username) { + fileSystemImpl.removeUser(username); } } \ No newline at end of file diff --git a/filesys/FileSystemImpl.java b/filesys/FileSystemImpl.java index 708cb6c..3535812 100644 --- a/filesys/FileSystemImpl.java +++ b/filesys/FileSystemImpl.java @@ -28,7 +28,11 @@ public void addUser(Usuario user) throws CaminhoNaoEncontradoException { } @Override - public void removeUser(Usuario user) { + public void removeUser(String username) { + Usuario user = users.stream() + .filter(u -> u.getNome().equals(username)) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException("Usuário não encontrado: " + username)); if (user.getNome().equals(ROOT_USER)) throw new IllegalArgumentException("Não é possível remover o usuário root."); users.remove(user); @@ -174,17 +178,15 @@ public void write(String caminho, String usuario, boolean anexar, byte[] buffer) int offset = 0; while (offset < buffer.length) { - Arquivo.Bloco bloco = new Arquivo.Bloco(); - int length = Math.min(buffer.length - offset, bloco.dados.length); - - if (length <= 0) { - throw new IllegalArgumentException("O tamanho do bloco não pode ser zero ou negativo."); - } - - System.arraycopy(buffer, offset, bloco.dados, 0, length); + int length = Math.min(buffer.length - offset, arquivo.getTamMaxBloco()); // supondo um tamanho fixo + byte[] dados = new byte[length]; + System.arraycopy(buffer, offset, dados, 0, length); + + Arquivo.Bloco bloco = new Arquivo.Bloco(dados); // criar com dados já definidos arquivo.addBloco(bloco); + arquivo.incrementTamnho(length); // incrementa o tamanho do arquivo offset += length; - } + } } public void read(String caminho, String usuario, byte[] buffer, Offset offset) diff --git a/filesys/IFileSystem.java b/filesys/IFileSystem.java index 5b9fe02..bbf97c4 100644 --- a/filesys/IFileSystem.java +++ b/filesys/IFileSystem.java @@ -12,7 +12,7 @@ public interface IFileSystem { // Remove um usuário do sistema. // O usuário root não pode ser removido. - void removeUser(Usuario user); + void removeUser(String username); // Altera as permissões de um arquivo ou diretório. // Configura a permissao do caminho para o usuarioAlvo. From 4a3818118706ec27656106709fb795a4af41f805 Mon Sep 17 00:00:00 2001 From: alvimdev Date: Sat, 3 May 2025 14:14:12 -0300 Subject: [PATCH 07/22] fea: add comprehensive unit tests for FileSystem class methods including chmod, mkdir, rm, touch, write, read, mv, ls, cp, addUser, and removeUser --- tests/FileSystemTest.java | 92 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 tests/FileSystemTest.java diff --git a/tests/FileSystemTest.java b/tests/FileSystemTest.java new file mode 100644 index 0000000..f539272 --- /dev/null +++ b/tests/FileSystemTest.java @@ -0,0 +1,92 @@ +package tests; + +import exception.CaminhoJaExistenteException; +import exception.CaminhoNaoEncontradoException; +import exception.PermissaoException; +import filesys.*; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class FileSystemTest { + + private static IFileSystem fileSystem; + private static Usuario user; + + @BeforeAll + static void setUp() { + fileSystem = new FileSystem(); + } + + @Test + void testChmod() throws CaminhoNaoEncontradoException, PermissaoException, CaminhoJaExistenteException { + fileSystem.mkdir("/chmodTest", "root"); + fileSystem.addUser(new Usuario("alvim", "r--", "/chmodTest")); + assertDoesNotThrow(() -> fileSystem.chmod("/chmodTest", "root", "alvim", "rw-")); + } + + @Test + void testMkdir() throws CaminhoJaExistenteException, PermissaoException, CaminhoNaoEncontradoException { + assertDoesNotThrow(() -> fileSystem.mkdir("/mkdirTest", "root")); + } + + @Test + void testRm() throws CaminhoNaoEncontradoException, PermissaoException, CaminhoJaExistenteException { + fileSystem.mkdir("/rmTest", "root"); + assertDoesNotThrow(() -> fileSystem.rm("/rmTest", "root", true)); + } + + @Test + void testTouch() throws CaminhoJaExistenteException, PermissaoException, CaminhoNaoEncontradoException { + fileSystem.mkdir("/touchDir", "root"); + assertDoesNotThrow(() -> fileSystem.touch("/touchDir/file.txt", "root")); + } + + @Test + void testWriteAndRead() throws CaminhoNaoEncontradoException, PermissaoException, CaminhoJaExistenteException { + fileSystem.mkdir("/rwDir", "root"); + fileSystem.touch("/rwDir/file", "root"); + byte[] buffer = new byte[]{1, 2, 3}; + fileSystem.write("/rwDir/file", "root", true, buffer); + + byte[] readBuffer = new byte[3]; + Offset offset = new Offset(0); + fileSystem.read("/rwDir/file", "root", readBuffer, offset); + assertArrayEquals(buffer, readBuffer); + } + + @Test + void testMv() throws CaminhoNaoEncontradoException, PermissaoException, CaminhoJaExistenteException { + fileSystem.mkdir("/mvDir", "root"); + fileSystem.mv("/mvDir", "/mvDirRenamed", "root"); + } + + @Test + void testLs() throws CaminhoNaoEncontradoException, PermissaoException, CaminhoJaExistenteException { + fileSystem.mkdir("/lsTest", "root"); + assertDoesNotThrow(() -> fileSystem.ls("/lsTest", "root", true)); + } + + @Test + void testCp() throws CaminhoNaoEncontradoException, PermissaoException, CaminhoJaExistenteException { + fileSystem.mkdir("/cpSrc", "root"); + fileSystem.touch("/cpSrc/file.txt", "root"); + fileSystem.mkdir("/cpDest", "root"); + fileSystem.cp("/cpSrc", "/cpDest", "root", true); + // poderia testar se "/cpDest" existe se houvesse método acessor + } + + @Test + void testAddUser() throws CaminhoNaoEncontradoException { + assertDoesNotThrow(() -> fileSystem.addUser(new Usuario("markids", "rwx", "/"))); + } + + @Test + void testRemoveUser() throws CaminhoNaoEncontradoException {; + user = new Usuario("marceneiro", "---", "/"); + fileSystem.addUser(user); + assertDoesNotThrow(() -> fileSystem.removeUser(user.getNome())); + } +} From bc10d4ad7cec0a44e6455f032729fd106d8e2329 Mon Sep 17 00:00:00 2001 From: alvimdev Date: Sat, 3 May 2025 15:11:11 -0300 Subject: [PATCH 08/22] fea: update FileSystem and IFileSystem classes to improve user management and enhance documentation --- Main.java | 2 - filesys/FileSystem.java | 11 ++- filesys/FileSystemImpl.java | 41 +++++++- filesys/IFileSystem.java | 181 +++++++++++++++++++++++++++++------- tests/FileSystemTest.java | 4 +- 5 files changed, 194 insertions(+), 45 deletions(-) diff --git a/Main.java b/Main.java index 8a65b77..dcf303f 100644 --- a/Main.java +++ b/Main.java @@ -93,8 +93,6 @@ public static void main(String[] args) { } catch (FileNotFoundException e) { // Retorna se o arquivo de usuários não for encontrado System.out.println("Arquivo de usuários não encontrado"); return; - } catch (CaminhoNaoEncontradoException e) { - System.out.println("Erro ao adicionar usuário: " + e.getMessage()); } // Menu interativo. diff --git a/filesys/FileSystem.java b/filesys/FileSystem.java index b1e5de2..e1d3d20 100644 --- a/filesys/FileSystem.java +++ b/filesys/FileSystem.java @@ -4,7 +4,14 @@ import exception.CaminhoNaoEncontradoException; import exception.PermissaoException; -// Essa classe deve servir apenas como proxy para o FileSystemImpl +/** + * Classe {@code FileSystem} atua como um proxy para a implementação real do sistema de arquivos {@link FileSystemImpl}. + * + *

Essa classe encapsula a lógica interna e fornece uma interface padronizada para operações em sistemas de arquivos, + * delegando todas as chamadas de método à instância de {@code FileSystemImpl}. + * + *

Inicializa com um diretório raiz padrão ("/") e um usuário padrão ("root") com permissões completas. + */ final public class FileSystem implements IFileSystem { private final IFileSystem fileSystemImpl; @@ -66,7 +73,7 @@ public void cp(String caminhoOrigem, String caminhoDestino, String usuario, bool } @Override - public void addUser(Usuario user) throws CaminhoNaoEncontradoException { + public void addUser(Usuario user) { fileSystemImpl.addUser(user); } diff --git a/filesys/FileSystemImpl.java b/filesys/FileSystemImpl.java index 3535812..1c7eae6 100644 --- a/filesys/FileSystemImpl.java +++ b/filesys/FileSystemImpl.java @@ -8,23 +8,58 @@ import java.util.Set; import java.util.StringTokenizer; +/** + * 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"; private Set users = new HashSet<>(); private Diretorio root; public FileSystemImpl() { - users.add(new Usuario(ROOT_USER, "rwx", "/**")); + users.add(new Usuario(ROOT_USER, "rwx", "/")); root = new Diretorio("/", "rwx", ROOT_USER); } @Override - public void addUser(Usuario user) throws CaminhoNaoEncontradoException { + public void addUser(Usuario user) { if (users.stream().anyMatch(u -> u.getNome().equals(user.getNome()))) { throw new IllegalArgumentException("Usuário com o mesmo nome já existe: " + user.getNome()); } users.add(user); - navegar(user.getDir()).setPermissaoUsuario(user.getNome(), user.getPermissao()); + try { + navegar(user.getDir()).setPermissaoUsuario(user.getNome(), user.getPermissao()); + } catch (CaminhoNaoEncontradoException e) { + try { + mkdir(user.getDir(), ROOT_USER); + navegar(user.getDir()).setPermissaoUsuario(user.getNome(), user.getPermissao()); + } catch (CaminhoJaExistenteException | PermissaoException | CaminhoNaoEncontradoException ex) { + throw new RuntimeException("Erro ao criar diretório para o usuário: " + user.getNome(), ex); + } + } } @Override diff --git a/filesys/IFileSystem.java b/filesys/IFileSystem.java index bbf97c4..e76271d 100644 --- a/filesys/IFileSystem.java +++ b/filesys/IFileSystem.java @@ -4,51 +4,160 @@ import exception.CaminhoNaoEncontradoException; import exception.PermissaoException; -// Apenas modifique essa interface caso seja EXTREMAMENTE necessário. -// Documente & Justifique TODAS asalterações feitas. +/** + * Interface para as operações de um sistema de arquivos virtual. + * + *

IFyleSystem é implementada por FileSystemImpl, que contém a lógica de manipulação de arquivos e diretórios e FyleSystem atua como um proxy que delega as chamadas para a implementação real. + *

Essa interface define os métodos necessários para gerenciar usuários, permissões e operações de arquivos. + *

O sistema de arquivos é inicializado com um diretório raiz padrão ("/") e um usuário padrão ("root") + *

Não é necessário passar parâmetros para o construtor e nem adicionar o diretório e o usuário root + *

Importante: O usuário root não pode ser removido. + */ public interface IFileSystem { - // Adiciona um usuário ao sistema. Se o usuário já existir, será lançada uma exceção. - void addUser(Usuario user) throws CaminhoNaoEncontradoException; - // Remove um usuário do sistema. - // O usuário root não pode ser removido. + /** + * Adiciona um novo usuário ao sistema. + * + * @param user Usuário a ser adicionado. + */ + void addUser(Usuario user); + + /** + * Remove um usuário do sistema. + * + * Importante: O usuário root não pode ser removido. + * + * @param username Nome do usuário a ser removido. + */ void removeUser(String username); - // Altera as permissões de um arquivo ou diretório. - // Configura a permissao do caminho para o usuarioAlvo. - // Apenas o usuario root ou que tenha permissão de rw do caminho podem alterar as permissões. - void chmod(String caminho, String usuario, String usuarioAlvo, String permissao) throws CaminhoNaoEncontradoException, PermissaoException; + /** + * Altera as permissões de um caminho para um usuário específico. + * + *

+ * Apenas o usuário root ou aquele com permissão rw no caminho pode alterar permissões. + *

+ * + * @param caminho Caminho do arquivo ou diretório. + * @param usuario Usuário que está realizando a operação. + * @param usuarioAlvo Usuário cujas permissões serão alteradas. + * @param permissao Novas permissões (ex: "rwx"). + * @throws CaminhoNaoEncontradoException Se o caminho não existir. + * @throws PermissaoException Se o usuário não tiver permissão para modificar. + */ + void chmod(String caminho, String usuario, String usuarioAlvo, String permissao) + throws CaminhoNaoEncontradoException, PermissaoException; - // Cria um novo diretório. Se o diretório já existir, será lançada uma exceção. - // Se o usuario não tiver permissão para criar o diretório, será lançada uma exceção. - void mkdir(String caminho, String usuario) throws CaminhoJaExistenteException, PermissaoException, CaminhoNaoEncontradoException; + /** + * Cria um novo diretório. + * + * @param caminho Caminho completo do diretório a ser criado. + * @param usuario Usuário que está criando o diretório. + * @throws CaminhoJaExistenteException Se o diretório já existir. + * @throws PermissaoException Se o usuário não tiver permissão para criar o diretório. + * @throws CaminhoNaoEncontradoException Se o caminho pai não existir. + */ + void mkdir(String caminho, String usuario) + throws CaminhoJaExistenteException, PermissaoException, CaminhoNaoEncontradoException; - // Remove um arquivo ou diretório. Se o diretório não existir, será lançada uma exceção. - // Caso recursivo seja true, o diretório será removido recursivamente. - void rm(String caminho, String usuario, boolean recursivo) throws CaminhoNaoEncontradoException, PermissaoException; + /** + * Remove um arquivo ou diretório. + * + * @param caminho Caminho do arquivo ou diretório a ser removido. + * @param usuario Usuário que realiza a remoção. + * @param recursivo Se true, remove diretórios recursivamente. + * @throws CaminhoNaoEncontradoException Se o caminho não existir. + * @throws PermissaoException Se o usuário não tiver permissão de remoção. + */ + void rm(String caminho, String usuario, boolean recursivo) + throws CaminhoNaoEncontradoException, PermissaoException; - // Cria um novo arquivo. Atenção: Se o arquivo já existir, será lançada uma exceção. - void touch(String caminho, String usuario) throws CaminhoJaExistenteException, PermissaoException, CaminhoNaoEncontradoException; + /** + * Cria um novo arquivo vazio. + * + * Atenção: Se o arquivo já existir, será lançada uma exceção. + * + * @param caminho Caminho do arquivo. + * @param usuario Usuário que está criando o arquivo. + * @throws CaminhoJaExistenteException Se o arquivo já existir. + * @throws PermissaoException Se o usuário não tiver permissão de criação. + * @throws CaminhoNaoEncontradoException Se o caminho pai não existir. + */ + void touch(String caminho, String usuario) + throws CaminhoJaExistenteException, PermissaoException, CaminhoNaoEncontradoException; - // Escreve dados em um arquivo. Se o diretório não existir, será lançada uma exceção. - // Caso o diretório exista, o arquivo será criado ou sobrescrito. - // Caso anexar (append) seja true, os dados serão adicionados ao final do arquivo. - // Escrita sequencial. - void write(String caminho, String usuario, boolean anexar, byte[] buffer) throws CaminhoNaoEncontradoException, PermissaoException; + /** + * Escreve dados em um arquivo. + * + *

+ * Caso o arquivo não exista, será lançado um erro. + * Se anexar for true, os dados serão adicionados ao final do arquivo. + *

+ * + * @param caminho Caminho do arquivo. + * @param usuario Usuário que está escrevendo. + * @param anexar Se true, realiza operação de append. + * @param buffer Dados a serem escritos. + * @throws CaminhoNaoEncontradoException Se o arquivo não existir. + * @throws PermissaoException Se o usuário não tiver permissão de escrita. + */ + void write(String caminho, String usuario, boolean anexar, byte[] buffer) + throws CaminhoNaoEncontradoException, PermissaoException; - // Lê dados de um arquivo. Se o arquivo não existir, será lançada uma exceção. - // Leitura sequencial - todo o conteudo do arquivo sera lido e armazenado no buffer. - void read(String caminho, String usuario, byte[] buffer, Offset offset) throws CaminhoNaoEncontradoException, PermissaoException; + /** + * Lê dados de um arquivo sequencialmente. + * + *

Todo o conteúdo do arquivo será lido a partir de um Offset e armazenado no buffer. + *

+ * + * @param caminho Caminho do arquivo. + * @param usuario Usuário que está lendo. + * @param buffer Buffer onde os dados serão armazenados. + * @param offset Objeto que representa o deslocamento atual da leitura. + * @throws CaminhoNaoEncontradoException Se o arquivo não existir. + * @throws PermissaoException Se o usuário não tiver permissão de leitura. + */ + void read(String caminho, String usuario, byte[] buffer, Offset offset) + throws CaminhoNaoEncontradoException, PermissaoException; - // Move ou renomeia um arquivo ou diretório. Se o diretório não existir, será lançada uma exceção. - // Se o diretório já existir, será sobrescrito. - // mv é naturalmente recursivo. - void mv(String caminhoAntigo, String caminhoNovo, String usuario) throws CaminhoNaoEncontradoException, PermissaoException; + /** + * Move ou renomeia um arquivo ou diretório. + * + *

+ * A operação é recursiva. Se o destino já existir, será sobrescrito. + *

+ * + * @param caminhoAntigo Caminho original. + * @param caminhoNovo Novo caminho. + * @param usuario Usuário que está realizando a operação. + * @throws CaminhoNaoEncontradoException Se o caminho antigo não existir. + * @throws PermissaoException Se o usuário não tiver permissão. + */ + void mv(String caminhoAntigo, String caminhoNovo, String usuario) + throws CaminhoNaoEncontradoException, PermissaoException; - // Lista o conteúdo de um diretório. Se o diretório não existir, será lançada uma exceção. - // Caso recursivo seja true, todo o conteúdo do diretório será listado recursivamente. - void ls(String caminho, String usuario, boolean recursivo) throws CaminhoNaoEncontradoException, PermissaoException; + /** + * Lista o conteúdo de um diretório. + * + * @param caminho Caminho do diretório. + * @param usuario Usuário que está acessando. + * @param recursivo Se true, lista recursivamente os subdiretórios. + * @throws CaminhoNaoEncontradoException Se o diretório não existir. + * @throws PermissaoException Se o usuário não tiver permissão de leitura. + */ + void ls(String caminho, String usuario, boolean recursivo) + throws CaminhoNaoEncontradoException, PermissaoException; - // 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 + /** + * Copia um arquivo ou diretório. + * + * @param caminhoOrigem Caminho de origem. + * @param caminhoDestino Caminho de destino. + * @param usuario Usuário que está realizando a operação. + * @param recursivo Se true, copia diretórios recursivamente. + * @throws CaminhoNaoEncontradoException Se a origem não existir. + * @throws PermissaoException Se o usuário não tiver permissão. + */ + void cp(String caminhoOrigem, String caminhoDestino, String usuario, boolean recursivo) + throws CaminhoNaoEncontradoException, PermissaoException; +} \ No newline at end of file diff --git a/tests/FileSystemTest.java b/tests/FileSystemTest.java index f539272..61458d8 100644 --- a/tests/FileSystemTest.java +++ b/tests/FileSystemTest.java @@ -79,12 +79,12 @@ void testCp() throws CaminhoNaoEncontradoException, PermissaoException, CaminhoJ } @Test - void testAddUser() throws CaminhoNaoEncontradoException { + void testAddUser() { assertDoesNotThrow(() -> fileSystem.addUser(new Usuario("markids", "rwx", "/"))); } @Test - void testRemoveUser() throws CaminhoNaoEncontradoException {; + void testRemoveUser() {; user = new Usuario("marceneiro", "---", "/"); fileSystem.addUser(user); assertDoesNotThrow(() -> fileSystem.removeUser(user.getNome())); From 6515946b68671a22bc2987a87cb42034bb8fd03c Mon Sep 17 00:00:00 2001 From: alvimdev Date: Sat, 3 May 2025 15:11:33 -0300 Subject: [PATCH 09/22] fea: enhance PermissionTest class with comprehensive permission tests for read, write and inheritance scenarios --- tests/PermissionTest.java | 129 ++++++++++++++++++++++++++++++++------ 1 file changed, 111 insertions(+), 18 deletions(-) diff --git a/tests/PermissionTest.java b/tests/PermissionTest.java index 6026e31..a06e196 100644 --- a/tests/PermissionTest.java +++ b/tests/PermissionTest.java @@ -1,26 +1,119 @@ package tests; -import static org.junit.Assert.assertTrue; - -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.Assertions.*; -import org.junit.jupiter.api.BeforeAll; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import exception.CaminhoJaExistenteException; +import exception.CaminhoNaoEncontradoException; +import exception.PermissaoException; import filesys.FileSystemImpl; import filesys.IFileSystem; +import filesys.Usuario; +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; -// Essa classe testa cenários de permissão public class PermissionTest { - private static IFileSystem fileSystem; - - @BeforeAll - public static void setUp() { - fileSystem = new FileSystemImpl(/*args...*/); - } - - @Test - public void testPermission() { - // Teste de permissão - assertTrue(true); - } + private static IFileSystem fileSystem; + + @BeforeAll + public static void setUp() throws CaminhoJaExistenteException, PermissaoException, CaminhoNaoEncontradoException { + fileSystem = new FileSystemImpl(); + fileSystem.addUser(new Usuario("maria", "rw-", "/")); + fileSystem.addUser(new Usuario("joao", "rwx", "/docs")); + + fileSystem.mkdir("/bin", "maria"); + fileSystem.mkdir("/bin/subdir", "maria"); + } + + @Test + public void testReadPermission() throws CaminhoNaoEncontradoException, PermissaoException, CaminhoJaExistenteException { + // Captura a saída do console + ByteArrayOutputStream outContent = new ByteArrayOutputStream(); + System.setOut(new PrintStream(outContent)); + + // Maria tem permissão de leitura no diretório raiz e em todos os subdiretórios + fileSystem.ls("/", "maria", false); + assertTrue(outContent.toString().contains("/:\n")); + + // Limpa a saída capturada + outContent.reset(); + + // Maria também pode listar subdiretórios como /bin + fileSystem.ls("/bin", "maria", false); + assertTrue(outContent.toString().contains("/bin:\n")); + + // Limpa a saída capturada + outContent.reset(); + + // João não tem permissão de leitura no diretório raiz + assertThrows(PermissaoException.class, () -> fileSystem.ls("/", "joao", false)); + + // Restaura a saída padrão + System.setOut(System.out); + } + + @Test + public void testWritePermission() throws CaminhoNaoEncontradoException, PermissaoException, CaminhoJaExistenteException { + // Captura a saída do console + ByteArrayOutputStream outContent = new ByteArrayOutputStream(); + System.setOut(new PrintStream(outContent)); + + fileSystem.ls("/bin", "maria", false); + assertTrue(outContent.toString().contains("subdir")); + + // Limpa a saída capturada + outContent.reset(); + + // João não pode criar um diretório no diretório raiz + assertThrows(PermissaoException.class, () -> fileSystem.mkdir("/bin2", "joao")); + + // Restaura a saída padrão + System.setOut(System.out); + } + + @Test + public void testExecutePermission() throws CaminhoNaoEncontradoException, PermissaoException, CaminhoJaExistenteException { + // João pode criar um arquivo em /docs porque tem permissão rwx; + fileSystem.touch("/docs/file.txt", "joao"); + + // Captura a saída do console + ByteArrayOutputStream outContent = new ByteArrayOutputStream(); + System.setOut(new PrintStream(outContent)); + + fileSystem.ls("/docs", "joao", false); + assertTrue(outContent.toString().contains("file.txt")); + + // Limpa a saída capturada + outContent.reset(); + + // Maria pode criar um arquivo em qualquer lugar porque tem permissões herdadas de / + fileSystem.touch("/docs/file2.txt", "maria"); + fileSystem.ls("/docs", "maria", false); + assertTrue(outContent.toString().contains("file2.txt")); + + // Restaura a saída padrão + System.setOut(System.out); + } + + @Test + public void testPermissionInheritance() throws CaminhoNaoEncontradoException, PermissaoException, CaminhoJaExistenteException { + + // Captura a saída do console + ByteArrayOutputStream outContent = new ByteArrayOutputStream(); + System.setOut(new PrintStream(outContent)); + + fileSystem.ls("/bin", "maria", false); + assertTrue(outContent.toString().contains("subdir")); + + // Limpa a saída capturada + outContent.reset(); + + // João não pode criar um subdiretório em /bin porque não tem permissão em / + assertThrows(PermissaoException.class, () -> fileSystem.mkdir("/bin/subdir2", "joao")); + + // Restaura a saída padrão + System.setOut(System.out); + } } From 51c4c3ab6915a996284eb0e3dc5b336f339ed177 Mon Sep 17 00:00:00 2001 From: alvimdev Date: Sun, 4 May 2025 16:00:50 -0300 Subject: [PATCH 10/22] fea: add OperacaoInvalidaException and update methods across the file system to handle invalid operations --- Main.java | 13 +++++---- exception/OperacaoInvalidaException.java | 7 +++++ filesys/FileSystem.java | 9 +++--- filesys/FileSystemImpl.java | 36 +++++++++++++++--------- filesys/IFileSystem.java | 13 ++++++--- tests/FileSystemTest.java | 15 +++++----- tests/PermissionTest.java | 5 ++-- 7 files changed, 62 insertions(+), 36 deletions(-) create mode 100644 exception/OperacaoInvalidaException.java diff --git a/Main.java b/Main.java index dcf303f..dc8da7f 100644 --- a/Main.java +++ b/Main.java @@ -8,7 +8,7 @@ import exception.PermissaoException; import exception.CaminhoJaExistenteException; import exception.CaminhoNaoEncontradoException; - +import exception.OperacaoInvalidaException; import filesys.FileSystem; // MENU INTERATIVO PARA O SISTEMA DE ARQUIVOS @@ -154,7 +154,7 @@ public static void menu() { default: System.out.println("Comando inválido!"); } - } catch (CaminhoNaoEncontradoException | CaminhoJaExistenteException | PermissaoException e) { + } catch (CaminhoNaoEncontradoException | CaminhoJaExistenteException | PermissaoException | OperacaoInvalidaException e) { System.out.println("Erro: " + e.getMessage()); } @@ -176,7 +176,7 @@ public static void chmod() throws CaminhoNaoEncontradoException, PermissaoExcept fileSystem.chmod(caminho, username, usuarioAlvo, permissoes); } - public static void mkdir() throws CaminhoJaExistenteException, PermissaoException, CaminhoNaoEncontradoException { + public static void mkdir() throws CaminhoJaExistenteException, PermissaoException, CaminhoNaoEncontradoException, OperacaoInvalidaException { System.out.println("Insira o caminho do diretório a ser criado:"); String caminho = scanner.nextLine(); @@ -192,14 +192,14 @@ public static void rm() throws CaminhoNaoEncontradoException, PermissaoException fileSystem.rm(caminho, username, recursivo); } - public static void touch() throws CaminhoJaExistenteException, PermissaoException, CaminhoNaoEncontradoException { + public static void touch() throws CaminhoJaExistenteException, PermissaoException, CaminhoNaoEncontradoException, OperacaoInvalidaException { System.out.println("Insira o caminho do arquivo a ser criado:"); String caminho = scanner.nextLine(); fileSystem.touch(caminho, username); } - public static void write() throws CaminhoNaoEncontradoException, PermissaoException { + public static void write() throws CaminhoNaoEncontradoException, PermissaoException, OperacaoInvalidaException { System.out.println("Insira o caminho do arquivo a ser escrito:"); String caminho = scanner.nextLine(); System.out.println("Anexar? (true/false):"); @@ -211,7 +211,7 @@ public static void write() throws CaminhoNaoEncontradoException, PermissaoExcept fileSystem.write(caminho, username, anexar, buffer); } - public static void read() throws CaminhoNaoEncontradoException, PermissaoException { + public static void read() throws CaminhoNaoEncontradoException, PermissaoException, OperacaoInvalidaException { System.out.println("Insira o caminho do arquivo a ser lido:"); String caminho = scanner.nextLine(); byte[] buffer = new byte[READ_BUFFER_SIZE]; @@ -229,6 +229,7 @@ public static void read() throws CaminhoNaoEncontradoException, PermissaoExcepti } while (bytesLidos > 0); System.out.flush(); + System.out.println(); } public static void mv() throws CaminhoNaoEncontradoException, PermissaoException { diff --git a/exception/OperacaoInvalidaException.java b/exception/OperacaoInvalidaException.java new file mode 100644 index 0000000..9f446af --- /dev/null +++ b/exception/OperacaoInvalidaException.java @@ -0,0 +1,7 @@ +package exception; + +public class OperacaoInvalidaException extends Exception { + public OperacaoInvalidaException(String message) { + super(message); + } +} diff --git a/filesys/FileSystem.java b/filesys/FileSystem.java index e1d3d20..5b50062 100644 --- a/filesys/FileSystem.java +++ b/filesys/FileSystem.java @@ -2,6 +2,7 @@ import exception.CaminhoJaExistenteException; import exception.CaminhoNaoEncontradoException; +import exception.OperacaoInvalidaException; import exception.PermissaoException; /** @@ -27,7 +28,7 @@ public void chmod(String caminho, String usuario, String usuarioAlvo, String per } @Override - public void mkdir(String caminho, String usuario) throws CaminhoJaExistenteException, PermissaoException, CaminhoNaoEncontradoException { + public void mkdir(String caminho, String usuario) throws CaminhoJaExistenteException, PermissaoException, CaminhoNaoEncontradoException, OperacaoInvalidaException { fileSystemImpl.mkdir(caminho, usuario); } @@ -38,19 +39,19 @@ public void rm(String caminho, String usuario, boolean recursivo) } @Override - public void touch(String caminho, String usuario) throws CaminhoJaExistenteException, PermissaoException, CaminhoNaoEncontradoException { + public void touch(String caminho, String usuario) throws CaminhoJaExistenteException, PermissaoException, CaminhoNaoEncontradoException, OperacaoInvalidaException { fileSystemImpl.touch(caminho, usuario); } @Override public void write(String caminho, String usuario, boolean anexar, byte[] buffer) - throws CaminhoNaoEncontradoException, PermissaoException { + throws CaminhoNaoEncontradoException, PermissaoException, OperacaoInvalidaException { fileSystemImpl.write(caminho, usuario, anexar, buffer); } @Override public void read(String caminho, String usuario, byte[] buffer, Offset offset) - throws CaminhoNaoEncontradoException, PermissaoException { + throws CaminhoNaoEncontradoException, PermissaoException, OperacaoInvalidaException { fileSystemImpl.read(caminho, usuario, buffer, offset); } diff --git a/filesys/FileSystemImpl.java b/filesys/FileSystemImpl.java index 1c7eae6..d8907da 100644 --- a/filesys/FileSystemImpl.java +++ b/filesys/FileSystemImpl.java @@ -2,6 +2,7 @@ import exception.CaminhoJaExistenteException; import exception.CaminhoNaoEncontradoException; +import exception.OperacaoInvalidaException; import exception.PermissaoException; import java.util.HashSet; import java.util.Map; @@ -56,7 +57,7 @@ public void addUser(Usuario user) { try { mkdir(user.getDir(), ROOT_USER); navegar(user.getDir()).setPermissaoUsuario(user.getNome(), user.getPermissao()); - } catch (CaminhoJaExistenteException | PermissaoException | CaminhoNaoEncontradoException ex) { + } catch (CaminhoJaExistenteException | PermissaoException | CaminhoNaoEncontradoException | OperacaoInvalidaException ex) { throw new RuntimeException("Erro ao criar diretório para o usuário: " + user.getNome(), ex); } } @@ -94,7 +95,7 @@ private Diretorio navegar(String caminho) throws CaminhoNaoEncontradoException { @Override public void mkdir(String caminho, String usuario) - throws CaminhoJaExistenteException, PermissaoException, CaminhoNaoEncontradoException { + throws CaminhoJaExistenteException, PermissaoException, CaminhoNaoEncontradoException, OperacaoInvalidaException { Diretorio parent = navegar(caminho.substring(0, caminho.lastIndexOf('/'))); String nomeDiretorio = caminho.substring(caminho.lastIndexOf('/') + 1); @@ -103,7 +104,7 @@ public void mkdir(String caminho, String usuario) } if (parent.isArquivo()) { - throw new UnsupportedOperationException("Não é possível criar um diretório dentro de um arquivo."); + throw new OperacaoInvalidaException("Não é possível criar um diretório dentro de um arquivo."); } if (parent.getFilhos().containsKey(nomeDiretorio)) { @@ -174,7 +175,7 @@ private void removerRecursivo(Diretorio dir, String usuario) throws PermissaoExc @Override public void touch(String caminho, String usuario) - throws CaminhoJaExistenteException, PermissaoException, CaminhoNaoEncontradoException { + throws CaminhoJaExistenteException, PermissaoException, CaminhoNaoEncontradoException, OperacaoInvalidaException { Diretorio parent = navegar(caminho.substring(0, caminho.lastIndexOf('/'))); String nomeArquivo = caminho.substring(caminho.lastIndexOf('/') + 1); @@ -183,7 +184,7 @@ public void touch(String caminho, String usuario) } if (parent.isArquivo()) { - throw new UnsupportedOperationException("Não é possível criar um arquivo dentro de um arquivo."); + throw new OperacaoInvalidaException("Não é possível criar um arquivo dentro de um arquivo."); } if (parent.getFilhos().containsKey(nomeArquivo)) { @@ -200,11 +201,11 @@ public void touch(String caminho, String usuario) @Override public void write(String caminho, String usuario, boolean anexar, byte[] buffer) - throws CaminhoNaoEncontradoException, PermissaoException { + throws CaminhoNaoEncontradoException, PermissaoException, OperacaoInvalidaException { Diretorio dir = navegar(caminho); if (!dir.isArquivo()) - throw new UnsupportedOperationException("Não é possível escrever em um diretório."); + throw new OperacaoInvalidaException("Não é possível escrever em um diretório."); if (!dir.temPermissao(usuario, 'w')) throw new PermissaoException("Sem permissão de escrita."); Arquivo arquivo = (Arquivo) dir; @@ -225,10 +226,10 @@ public void write(String caminho, String usuario, boolean anexar, byte[] buffer) } public void read(String caminho, String usuario, byte[] buffer, Offset offset) - throws CaminhoNaoEncontradoException, PermissaoException { + throws CaminhoNaoEncontradoException, PermissaoException, OperacaoInvalidaException { Diretorio dir = navegar(caminho); - if (!dir.isArquivo()) throw new UnsupportedOperationException("Não é possível ler de um diretório."); + if (!dir.isArquivo()) throw new OperacaoInvalidaException("Não é possível ler de um diretório."); if (!dir.temPermissao(usuario, 'r')) throw new PermissaoException("Sem permissão de leitura."); Arquivo arquivo = (Arquivo) dir; @@ -303,17 +304,25 @@ private String listar(Diretorio dir, String caminho, boolean recursivo, String u StringBuilder output = new StringBuilder(); output.append(caminho).append(":\n"); + // Listar arquivos e diretórios filhos for (Map.Entry entry : dir.getFilhos().entrySet()) { Diretorio filho = entry.getValue(); - output.append(" ").append(filho.toString()).append("\n"); + } - if (recursivo && !filho.isArquivo()) { - output.append(listar(filho, caminho + filho.getNome(), recursivo, usuario)); + // Recursão: somente depois de listar os filhos diretos + if (recursivo) { + for (Map.Entry entry : dir.getFilhos().entrySet()) { + Diretorio filho = entry.getValue(); + if (!filho.isArquivo()) { + String novoCaminho = caminho.equals("/") ? "/" + filho.getNome() : caminho + "/" + filho.getNome(); + output.append(listar(filho, novoCaminho, true, usuario)); + } } } + return output.toString(); - } + } @Override public void cp(String caminhoOrigem, String caminhoDestino, String usuario, boolean recursivo) @@ -342,6 +351,7 @@ private void copiarArquivo(Arquivo origem, Diretorio destino) { Arquivo copia = new Arquivo(origem.getNome(), origem.getPermissoes(), origem.getDono()); for (Arquivo.Bloco bloco : origem.getBlocos()) { copia.addBloco(bloco); + copia.incrementTamnho(bloco.dados.length); } destino.adicionarFilho(copia); } diff --git a/filesys/IFileSystem.java b/filesys/IFileSystem.java index e76271d..cf0c9cb 100644 --- a/filesys/IFileSystem.java +++ b/filesys/IFileSystem.java @@ -2,6 +2,7 @@ import exception.CaminhoJaExistenteException; import exception.CaminhoNaoEncontradoException; +import exception.OperacaoInvalidaException; import exception.PermissaoException; /** @@ -56,9 +57,10 @@ void chmod(String caminho, String usuario, String usuarioAlvo, String permissao) * @throws CaminhoJaExistenteException Se o diretório já existir. * @throws PermissaoException Se o usuário não tiver permissão para criar o diretório. * @throws CaminhoNaoEncontradoException Se o caminho pai não existir. + * @throws OperacaoInvalidaException */ void mkdir(String caminho, String usuario) - throws CaminhoJaExistenteException, PermissaoException, CaminhoNaoEncontradoException; + throws CaminhoJaExistenteException, PermissaoException, CaminhoNaoEncontradoException, OperacaoInvalidaException; /** * Remove um arquivo ou diretório. @@ -82,9 +84,10 @@ void rm(String caminho, String usuario, boolean recursivo) * @throws CaminhoJaExistenteException Se o arquivo já existir. * @throws PermissaoException Se o usuário não tiver permissão de criação. * @throws CaminhoNaoEncontradoException Se o caminho pai não existir. + * @throws OperacaoInvalidaException */ void touch(String caminho, String usuario) - throws CaminhoJaExistenteException, PermissaoException, CaminhoNaoEncontradoException; + throws CaminhoJaExistenteException, PermissaoException, CaminhoNaoEncontradoException, OperacaoInvalidaException; /** * Escreve dados em um arquivo. @@ -100,9 +103,10 @@ void touch(String caminho, String usuario) * @param buffer Dados a serem escritos. * @throws CaminhoNaoEncontradoException Se o arquivo não existir. * @throws PermissaoException Se o usuário não tiver permissão de escrita. + * @throws OperacaoInvalidaException */ void write(String caminho, String usuario, boolean anexar, byte[] buffer) - throws CaminhoNaoEncontradoException, PermissaoException; + throws CaminhoNaoEncontradoException, PermissaoException, OperacaoInvalidaException; /** * Lê dados de um arquivo sequencialmente. @@ -116,9 +120,10 @@ void write(String caminho, String usuario, boolean anexar, byte[] buffer) * @param offset Objeto que representa o deslocamento atual da leitura. * @throws CaminhoNaoEncontradoException Se o arquivo não existir. * @throws PermissaoException Se o usuário não tiver permissão de leitura. + * @throws OperacaoInvalidaException */ void read(String caminho, String usuario, byte[] buffer, Offset offset) - throws CaminhoNaoEncontradoException, PermissaoException; + throws CaminhoNaoEncontradoException, PermissaoException, OperacaoInvalidaException; /** * Move ou renomeia um arquivo ou diretório. diff --git a/tests/FileSystemTest.java b/tests/FileSystemTest.java index 61458d8..782906d 100644 --- a/tests/FileSystemTest.java +++ b/tests/FileSystemTest.java @@ -2,6 +2,7 @@ import exception.CaminhoJaExistenteException; import exception.CaminhoNaoEncontradoException; +import exception.OperacaoInvalidaException; import exception.PermissaoException; import filesys.*; @@ -21,7 +22,7 @@ static void setUp() { } @Test - void testChmod() throws CaminhoNaoEncontradoException, PermissaoException, CaminhoJaExistenteException { + void testChmod() throws CaminhoNaoEncontradoException, PermissaoException, CaminhoJaExistenteException, OperacaoInvalidaException { fileSystem.mkdir("/chmodTest", "root"); fileSystem.addUser(new Usuario("alvim", "r--", "/chmodTest")); assertDoesNotThrow(() -> fileSystem.chmod("/chmodTest", "root", "alvim", "rw-")); @@ -33,19 +34,19 @@ void testMkdir() throws CaminhoJaExistenteException, PermissaoException, Caminho } @Test - void testRm() throws CaminhoNaoEncontradoException, PermissaoException, CaminhoJaExistenteException { + void testRm() throws CaminhoNaoEncontradoException, PermissaoException, CaminhoJaExistenteException, OperacaoInvalidaException { fileSystem.mkdir("/rmTest", "root"); assertDoesNotThrow(() -> fileSystem.rm("/rmTest", "root", true)); } @Test - void testTouch() throws CaminhoJaExistenteException, PermissaoException, CaminhoNaoEncontradoException { + void testTouch() throws CaminhoJaExistenteException, PermissaoException, CaminhoNaoEncontradoException, OperacaoInvalidaException { fileSystem.mkdir("/touchDir", "root"); assertDoesNotThrow(() -> fileSystem.touch("/touchDir/file.txt", "root")); } @Test - void testWriteAndRead() throws CaminhoNaoEncontradoException, PermissaoException, CaminhoJaExistenteException { + void testWriteAndRead() throws CaminhoNaoEncontradoException, PermissaoException, CaminhoJaExistenteException, OperacaoInvalidaException { fileSystem.mkdir("/rwDir", "root"); fileSystem.touch("/rwDir/file", "root"); byte[] buffer = new byte[]{1, 2, 3}; @@ -58,19 +59,19 @@ void testWriteAndRead() throws CaminhoNaoEncontradoException, PermissaoException } @Test - void testMv() throws CaminhoNaoEncontradoException, PermissaoException, CaminhoJaExistenteException { + void testMv() throws CaminhoNaoEncontradoException, PermissaoException, CaminhoJaExistenteException, OperacaoInvalidaException { fileSystem.mkdir("/mvDir", "root"); fileSystem.mv("/mvDir", "/mvDirRenamed", "root"); } @Test - void testLs() throws CaminhoNaoEncontradoException, PermissaoException, CaminhoJaExistenteException { + void testLs() throws CaminhoNaoEncontradoException, PermissaoException, CaminhoJaExistenteException, OperacaoInvalidaException { fileSystem.mkdir("/lsTest", "root"); assertDoesNotThrow(() -> fileSystem.ls("/lsTest", "root", true)); } @Test - void testCp() throws CaminhoNaoEncontradoException, PermissaoException, CaminhoJaExistenteException { + void testCp() throws CaminhoNaoEncontradoException, PermissaoException, CaminhoJaExistenteException, OperacaoInvalidaException { fileSystem.mkdir("/cpSrc", "root"); fileSystem.touch("/cpSrc/file.txt", "root"); fileSystem.mkdir("/cpDest", "root"); diff --git a/tests/PermissionTest.java b/tests/PermissionTest.java index a06e196..a6c03b9 100644 --- a/tests/PermissionTest.java +++ b/tests/PermissionTest.java @@ -5,6 +5,7 @@ import exception.CaminhoJaExistenteException; import exception.CaminhoNaoEncontradoException; +import exception.OperacaoInvalidaException; import exception.PermissaoException; import filesys.FileSystemImpl; import filesys.IFileSystem; @@ -18,7 +19,7 @@ public class PermissionTest { private static IFileSystem fileSystem; @BeforeAll - public static void setUp() throws CaminhoJaExistenteException, PermissaoException, CaminhoNaoEncontradoException { + public static void setUp() throws CaminhoJaExistenteException, PermissaoException, CaminhoNaoEncontradoException, OperacaoInvalidaException { fileSystem = new FileSystemImpl(); fileSystem.addUser(new Usuario("maria", "rw-", "/")); fileSystem.addUser(new Usuario("joao", "rwx", "/docs")); @@ -74,7 +75,7 @@ public void testWritePermission() throws CaminhoNaoEncontradoException, Permissa } @Test - public void testExecutePermission() throws CaminhoNaoEncontradoException, PermissaoException, CaminhoJaExistenteException { + public void testExecutePermission() throws CaminhoNaoEncontradoException, PermissaoException, CaminhoJaExistenteException, OperacaoInvalidaException { // João pode criar um arquivo em /docs porque tem permissão rwx; fileSystem.touch("/docs/file.txt", "joao"); From 4da642ab564e222078669ff06d2ccff9fa7fe737 Mon Sep 17 00:00:00 2001 From: alvimdev Date: Tue, 6 May 2025 16:58:34 -0300 Subject: [PATCH 11/22] fea: update mkdir method to streamline directory creation and enhance unit tests for mkdir and touch methods --- filesys/FileSystem.java | 2 +- filesys/FileSystemImpl.java | 71 ++++++++++++++++++++++++------------- filesys/IFileSystem.java | 2 +- tests/FileSystemTest.java | 2 ++ 4 files changed, 50 insertions(+), 27 deletions(-) diff --git a/filesys/FileSystem.java b/filesys/FileSystem.java index 5b50062..7c33c76 100644 --- a/filesys/FileSystem.java +++ b/filesys/FileSystem.java @@ -28,7 +28,7 @@ public void chmod(String caminho, String usuario, String usuarioAlvo, String per } @Override - public void mkdir(String caminho, String usuario) throws CaminhoJaExistenteException, PermissaoException, CaminhoNaoEncontradoException, OperacaoInvalidaException { + public void mkdir(String caminho, String usuario) throws CaminhoJaExistenteException, PermissaoException, OperacaoInvalidaException { fileSystemImpl.mkdir(caminho, usuario); } diff --git a/filesys/FileSystemImpl.java b/filesys/FileSystemImpl.java index d8907da..c42ec09 100644 --- a/filesys/FileSystemImpl.java +++ b/filesys/FileSystemImpl.java @@ -95,29 +95,40 @@ private Diretorio navegar(String caminho) throws CaminhoNaoEncontradoException { @Override public void mkdir(String caminho, String usuario) - throws CaminhoJaExistenteException, PermissaoException, CaminhoNaoEncontradoException, OperacaoInvalidaException { - Diretorio parent = navegar(caminho.substring(0, caminho.lastIndexOf('/'))); - String nomeDiretorio = caminho.substring(caminho.lastIndexOf('/') + 1); - - if (!parent.temPermissao(usuario, 'w')) { - throw new PermissaoException("Sem permissão para criar diretório em: " + caminho); - } - - if (parent.isArquivo()) { - throw new OperacaoInvalidaException("Não é possível criar um diretório dentro de um arquivo."); - } - - if (parent.getFilhos().containsKey(nomeDiretorio)) { - throw new CaminhoJaExistenteException("Diretório já existe: " + nomeDiretorio); + throws CaminhoJaExistenteException, PermissaoException, OperacaoInvalidaException { + if (caminho.equals("/")) return; + + StringTokenizer tokenizer = new StringTokenizer(caminho, "/"); + Diretorio atual = root; + StringBuilder caminhoAtual = new StringBuilder(); + + while (tokenizer.hasMoreTokens()) { + String parte = tokenizer.nextToken(); + caminhoAtual.append("/").append(parte); + + Map filhos = atual.getFilhos(); + + if (!filhos.containsKey(parte)) { + if (!atual.temPermissao(usuario, 'w')) { + throw new PermissaoException("Sem permissão para criar em: " + caminhoAtual); + } + + Usuario user = users.stream() + .filter(u -> u.getNome().equals(usuario)) + .findFirst() + .orElseThrow(() -> new PermissaoException("Usuário não encontrado: " + usuario)); + + Diretorio novo = new Diretorio(parte, atual.getPermissoes(), user.getNome()); + atual.adicionarFilho(novo); + atual = novo; + } else { + if (filhos.get(parte).isArquivo()) { + throw new OperacaoInvalidaException("Não é possível criar um diretório dentro de um arquivo."); + } + atual = filhos.get(parte); + } } - - Usuario user = users.stream() - .filter(u -> u.getNome().equals(usuario)) - .findFirst() - .orElseThrow(() -> new PermissaoException("Usuário não encontrado: " + usuario)); - - parent.adicionarFilho(new Diretorio(nomeDiretorio, parent.getPermissoes(), user.getNome())); - } + } @Override public void chmod(String caminho, String usuario, String usuarioAlvo, String permissao) @@ -176,11 +187,21 @@ private void removerRecursivo(Diretorio dir, String usuario) throws PermissaoExc @Override public void touch(String caminho, String usuario) throws CaminhoJaExistenteException, PermissaoException, CaminhoNaoEncontradoException, OperacaoInvalidaException { - Diretorio parent = navegar(caminho.substring(0, caminho.lastIndexOf('/'))); - String nomeArquivo = caminho.substring(caminho.lastIndexOf('/') + 1); + if (caminho.equals("/") || caminho.endsWith("/")) { + throw new OperacaoInvalidaException("Nome de arquivo inválido."); + } + + int lastSlash = caminho.lastIndexOf('/'); + String caminhoPai = (lastSlash <= 0) ? "/" : caminho.substring(0, lastSlash); + String nomeArquivo = caminho.substring(lastSlash + 1); + + // Cria os diretórios intermediários (como mkdir -p) + mkdir(caminhoPai, usuario); + + Diretorio parent = navegar(caminhoPai); if (!parent.temPermissao(usuario, 'w')) { - throw new PermissaoException("Sem permissão para criar arquivo em: " + caminho); + throw new PermissaoException("Sem permissão para criar arquivo em: " + caminhoPai); } if (parent.isArquivo()) { diff --git a/filesys/IFileSystem.java b/filesys/IFileSystem.java index cf0c9cb..a31e31f 100644 --- a/filesys/IFileSystem.java +++ b/filesys/IFileSystem.java @@ -60,7 +60,7 @@ void chmod(String caminho, String usuario, String usuarioAlvo, String permissao) * @throws OperacaoInvalidaException */ void mkdir(String caminho, String usuario) - throws CaminhoJaExistenteException, PermissaoException, CaminhoNaoEncontradoException, OperacaoInvalidaException; + throws CaminhoJaExistenteException, PermissaoException, OperacaoInvalidaException; /** * Remove um arquivo ou diretório. diff --git a/tests/FileSystemTest.java b/tests/FileSystemTest.java index 782906d..b613057 100644 --- a/tests/FileSystemTest.java +++ b/tests/FileSystemTest.java @@ -31,6 +31,7 @@ void testChmod() throws CaminhoNaoEncontradoException, PermissaoException, Camin @Test void testMkdir() throws CaminhoJaExistenteException, PermissaoException, CaminhoNaoEncontradoException { assertDoesNotThrow(() -> fileSystem.mkdir("/mkdirTest", "root")); + assertDoesNotThrow(() -> fileSystem.mkdir("/mkdirTest2/subdir", "root")); } @Test @@ -43,6 +44,7 @@ void testRm() throws CaminhoNaoEncontradoException, PermissaoException, CaminhoJ void testTouch() throws CaminhoJaExistenteException, PermissaoException, CaminhoNaoEncontradoException, OperacaoInvalidaException { fileSystem.mkdir("/touchDir", "root"); assertDoesNotThrow(() -> fileSystem.touch("/touchDir/file.txt", "root")); + assertDoesNotThrow(() -> fileSystem.touch("/touchDir2/file2.txt", "root")); } @Test From b77969e091261c7122c61d52bff7e51a5f2abd87 Mon Sep 17 00:00:00 2001 From: marcosffp Date: Mon, 16 Jun 2025 16:47:49 -0300 Subject: [PATCH 12/22] =?UTF-8?q?modulariza=C3=A7=C3=A3o?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- filesys/Arquivo.java | 7 + filesys/FileSystemImpl.java | 345 +++++++++--------------------- filesys/util/ArquivoUtil.java | 94 ++++++++ filesys/util/DiretorioUtil.java | 117 ++++++++++ filesys/util/UsuarioUtil.java | 19 ++ filesys/util/VerificacaoUtil.java | 93 ++++++++ 6 files changed, 431 insertions(+), 244 deletions(-) create mode 100644 filesys/util/ArquivoUtil.java create mode 100644 filesys/util/DiretorioUtil.java create mode 100644 filesys/util/UsuarioUtil.java create mode 100644 filesys/util/VerificacaoUtil.java diff --git a/filesys/Arquivo.java b/filesys/Arquivo.java index 23d75ff..dd59ac1 100644 --- a/filesys/Arquivo.java +++ b/filesys/Arquivo.java @@ -27,6 +27,11 @@ public Bloco(byte[] dados2) { this.dados = new byte[dados2.length]; System.arraycopy(dados2, 0, this.dados, 0, Math.min(dados2.length, TAMANHO_BLOCO)); } + + public byte[] getDados() { + return dados; + } + } public void addBloco(Bloco bloco) { @@ -46,6 +51,8 @@ public List getBlocos() { return blocos; } + + public void setBlocos(List blocos) { this.blocos = blocos; } diff --git a/filesys/FileSystemImpl.java b/filesys/FileSystemImpl.java index c42ec09..55732e9 100644 --- a/filesys/FileSystemImpl.java +++ b/filesys/FileSystemImpl.java @@ -4,36 +4,55 @@ import exception.CaminhoNaoEncontradoException; import exception.OperacaoInvalidaException; import exception.PermissaoException; +import filesys.util.ArquivoUtil; +import filesys.util.DiretorioUtil; +import filesys.util.UsuarioUtil; +import filesys.util.VerificacaoUtil; + import java.util.HashSet; -import java.util.Map; import java.util.Set; import java.util.StringTokenizer; /** - * 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. + * 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. + *

+ * 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. + *

+ * 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: + *

+ * 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.
  • + *
  • 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, + *

+ * 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. + *

+ * 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"; @@ -52,12 +71,13 @@ public void addUser(Usuario user) { } users.add(user); try { - navegar(user.getDir()).setPermissaoUsuario(user.getNome(), user.getPermissao()); + DiretorioUtil.navegar(user.getDir(), root).setPermissaoUsuario(user.getNome(), user.getPermissao()); } catch (CaminhoNaoEncontradoException e) { try { mkdir(user.getDir(), ROOT_USER); - navegar(user.getDir()).setPermissaoUsuario(user.getNome(), user.getPermissao()); - } catch (CaminhoJaExistenteException | PermissaoException | CaminhoNaoEncontradoException | OperacaoInvalidaException ex) { + DiretorioUtil.navegar(user.getDir(), root).setPermissaoUsuario(user.getNome(), user.getPermissao()); + } catch (CaminhoJaExistenteException | PermissaoException | CaminhoNaoEncontradoException + | OperacaoInvalidaException ex) { throw new RuntimeException("Erro ao criar diretório para o usuário: " + user.getNome(), ex); } } @@ -74,66 +94,36 @@ public void removeUser(String username) { users.remove(user); } - private Diretorio navegar(String caminho) throws CaminhoNaoEncontradoException { - if (caminho.equals("/") || caminho.isEmpty()) { - return root; - } - - Diretorio atual = root; - StringTokenizer tokenizer = new StringTokenizer(caminho, "/"); - - while (tokenizer.hasMoreTokens()) { - String parte = tokenizer.nextToken(); - if (!atual.getFilhos().containsKey(parte)) { - throw new CaminhoNaoEncontradoException("Caminho não encontrado: " + caminho); - } - atual = atual.getFilhos().get(parte); - } - - return atual; - } - @Override public void mkdir(String caminho, String usuario) throws CaminhoJaExistenteException, PermissaoException, OperacaoInvalidaException { - if (caminho.equals("/")) return; - + if (caminho.equals("/")) + return; + StringTokenizer tokenizer = new StringTokenizer(caminho, "/"); Diretorio atual = root; StringBuilder caminhoAtual = new StringBuilder(); - + while (tokenizer.hasMoreTokens()) { String parte = tokenizer.nextToken(); caminhoAtual.append("/").append(parte); - - Map filhos = atual.getFilhos(); - - if (!filhos.containsKey(parte)) { - if (!atual.temPermissao(usuario, 'w')) { - throw new PermissaoException("Sem permissão para criar em: " + caminhoAtual); - } - - Usuario user = users.stream() - .filter(u -> u.getNome().equals(usuario)) - .findFirst() - .orElseThrow(() -> new PermissaoException("Usuário não encontrado: " + usuario)); - - Diretorio novo = new Diretorio(parte, atual.getPermissoes(), user.getNome()); - atual.adicionarFilho(novo); - atual = novo; + + if (!existeFilho(atual, parte)) { + atual = DiretorioUtil.criarDiretorioFilho(atual, parte, caminhoAtual.toString(), usuario, users); } else { - if (filhos.get(parte).isArquivo()) { - throw new OperacaoInvalidaException("Não é possível criar um diretório dentro de um arquivo."); - } - atual = filhos.get(parte); + atual = DiretorioUtil.avancarParaDiretorioFilho(atual, parte); } } - } + } + + public boolean existeFilho(Diretorio atual, String nome) { + return atual.getFilhos().containsKey(nome); + } @Override public void chmod(String caminho, String usuario, String usuarioAlvo, String permissao) throws CaminhoNaoEncontradoException, PermissaoException { - Diretorio dir = navegar(caminho); + Diretorio dir = DiretorioUtil.navegar(caminho, root); if (!dir.temPermissao(usuario, 'w')) { throw new PermissaoException("Usuário sem permissão para alterar permissões em: " + caminho); @@ -149,243 +139,110 @@ public void rm(String caminho, String usuario, boolean recursivo) throw new PermissaoException("Não é possível remover o diretório raiz."); } - Diretorio pai = navegar(caminho.substring(0, caminho.lastIndexOf('/'))); - String nomeAlvo = caminho.substring(caminho.lastIndexOf('/') + 1); - - Diretorio alvo = pai.getFilhos().get(nomeAlvo); - if (alvo == null) throw new CaminhoNaoEncontradoException("Caminho não encontrado: " + caminho); + Diretorio pai = DiretorioUtil.obterDiretorioPai(caminho, root); + String nomeAlvo = obterNomeAlvo(caminho); + Diretorio alvo = DiretorioUtil.obterAlvo(pai, nomeAlvo, caminho); - if (!alvo.temPermissao(usuario, 'w')) - throw new PermissaoException("Sem permissão para remover: " + caminho); + VerificacaoUtil.verificarPermissaoEscrita(alvo, usuario, caminho); if (!alvo.isArquivo()) { - if (!recursivo && !alvo.getFilhos().isEmpty()) { - throw new PermissaoException("Diretório não está vazio. Use recursivo=true."); - } - + VerificacaoUtil.verificarRemocaoDiretorio(alvo, recursivo); if (recursivo) { - removerRecursivo(alvo, usuario); + DiretorioUtil.removerRecursivo(alvo, usuario); } } pai.removerFilho(nomeAlvo); } - private void removerRecursivo(Diretorio dir, String usuario) throws PermissaoException { - for (Diretorio filho : dir.getFilhos().values()) { - if (!filho.temPermissao(usuario, 'w')) { - throw new PermissaoException("Sem permissão para remover: " + filho.getNome()); - } - - if (!filho.isArquivo()) { - removerRecursivo(filho, usuario); - } - } - dir.getFilhos().clear(); + private String obterNomeAlvo(String caminho) { + return caminho.substring(caminho.lastIndexOf('/') + 1); } @Override public void touch(String caminho, String usuario) - throws CaminhoJaExistenteException, PermissaoException, CaminhoNaoEncontradoException, OperacaoInvalidaException { - if (caminho.equals("/") || caminho.endsWith("/")) { - throw new OperacaoInvalidaException("Nome de arquivo inválido."); - } + throws CaminhoJaExistenteException, PermissaoException, + CaminhoNaoEncontradoException, OperacaoInvalidaException { - int lastSlash = caminho.lastIndexOf('/'); - String caminhoPai = (lastSlash <= 0) ? "/" : caminho.substring(0, lastSlash); - String nomeArquivo = caminho.substring(lastSlash + 1); + VerificacaoUtil.verificarCaminhoArquivo(caminho); + String caminhoPai = DiretorioUtil.extrairCaminhoPai(caminho); + String nomeArquivo = DiretorioUtil.extrairNomeArquivo(caminho); - // Cria os diretórios intermediários (como mkdir -p) mkdir(caminhoPai, usuario); + Diretorio parent = DiretorioUtil.navegar(caminhoPai, root); + VerificacaoUtil.verificarPermissaoEscrita(parent, usuario, caminhoPai); + VerificacaoUtil.verificarSeEhArquivo(parent); - Diretorio parent = navegar(caminhoPai); - - if (!parent.temPermissao(usuario, 'w')) { - throw new PermissaoException("Sem permissão para criar arquivo em: " + caminhoPai); - } - - if (parent.isArquivo()) { - throw new OperacaoInvalidaException("Não é possível criar um arquivo dentro de um arquivo."); - } - - if (parent.getFilhos().containsKey(nomeArquivo)) { - throw new CaminhoJaExistenteException("Arquivo já existe: " + nomeArquivo); - } - - Usuario user = users.stream() - .filter(u -> u.getNome().equals(usuario)) - .findFirst() - .orElseThrow(() -> new PermissaoException("Usuário não encontrado: " + usuario)); + VerificacaoUtil.verificarSeArquivoExiste(parent, nomeArquivo); + Usuario user = UsuarioUtil.buscarUsuario(usuario, users); + Arquivo novoArquivo = ArquivoUtil.criarNovoArquivo(nomeArquivo, user); - parent.adicionarFilho(new Arquivo(nomeArquivo, user.getPermissao(), user.getNome())); + parent.adicionarFilho(novoArquivo); } @Override public void write(String caminho, String usuario, boolean anexar, byte[] buffer) throws CaminhoNaoEncontradoException, PermissaoException, OperacaoInvalidaException { - Diretorio dir = navegar(caminho); - - if (!dir.isArquivo()) - throw new OperacaoInvalidaException("Não é possível escrever em um diretório."); - if (!dir.temPermissao(usuario, 'w')) throw new PermissaoException("Sem permissão de escrita."); - - Arquivo arquivo = (Arquivo) dir; - - if (!anexar) arquivo.clearBlocos(); - - int offset = 0; - while (offset < buffer.length) { - int length = Math.min(buffer.length - offset, arquivo.getTamMaxBloco()); // supondo um tamanho fixo - byte[] dados = new byte[length]; - System.arraycopy(buffer, offset, dados, 0, length); - - Arquivo.Bloco bloco = new Arquivo.Bloco(dados); // criar com dados já definidos - arquivo.addBloco(bloco); - arquivo.incrementTamnho(length); // incrementa o tamanho do arquivo - offset += length; - } + Diretorio dir = DiretorioUtil.navegar(caminho, root); + VerificacaoUtil.verificarEscritaArquivo(dir, usuario); + ArquivoUtil.escreverBufferNoArquivo((Arquivo) dir, buffer, anexar); } + @Override public void read(String caminho, String usuario, byte[] buffer, Offset offset) throws CaminhoNaoEncontradoException, PermissaoException, OperacaoInvalidaException { - Diretorio dir = navegar(caminho); - - if (!dir.isArquivo()) throw new OperacaoInvalidaException("Não é possível ler de um diretório."); - if (!dir.temPermissao(usuario, 'r')) throw new PermissaoException("Sem permissão de leitura."); - + Diretorio dir = DiretorioUtil.navegar(caminho, root); + VerificacaoUtil.verificarLeituraArquivo(dir, usuario); Arquivo arquivo = (Arquivo) dir; - long fileSize = arquivo.getTamanho(); - offset.setMax((int) fileSize); // garante limite do offset - - if (offset.getValue() >= fileSize) return; - - int arquivoOffset = offset.getValue(); - int bufferOffset = 0; - - for (Arquivo.Bloco bloco : arquivo.getBlocos()) { - if (arquivoOffset >= bloco.dados.length) { - arquivoOffset -= bloco.dados.length; - continue; - } - - int bytesDisponiveis = bloco.dados.length - arquivoOffset; - int bytesParaLer = Math.min(buffer.length - bufferOffset, bytesDisponiveis); - System.arraycopy(bloco.dados, arquivoOffset, buffer, bufferOffset, bytesParaLer); - - bufferOffset += bytesParaLer; - arquivoOffset = 0; - - if (bufferOffset >= buffer.length) break; - } - - offset.add(bufferOffset); // avança o offset + ArquivoUtil.atualizarOffsetLimite(offset, arquivo.getTamanho()); + if (offset.getValue() >= arquivo.getTamanho()) + return; + ArquivoUtil.lerDadosDoArquivo(arquivo, buffer, offset); } @Override public void mv(String caminhoAntigo, String caminhoNovo, String usuario) throws CaminhoNaoEncontradoException, PermissaoException { - if (caminhoAntigo.equals("/") || caminhoNovo.equals("/")) { - throw new PermissaoException("Não é possível mover o diretório raiz."); - } + VerificacaoUtil.verificarMovimentacaoPermitida(caminhoAntigo, caminhoNovo); - Diretorio paiAntigo = navegar(caminhoAntigo.substring(0, caminhoAntigo.lastIndexOf('/'))); - String nomeAntigo = caminhoAntigo.substring(caminhoAntigo.lastIndexOf('/') + 1); - Diretorio alvo = paiAntigo.getFilhos().get(nomeAntigo); + Diretorio paiAntigo = DiretorioUtil.obterDiretorioPai(caminhoAntigo, root); + String nomeAntigo = DiretorioUtil.extrairNomeArquivo(caminhoAntigo); + Diretorio alvo = DiretorioUtil.obterAlvo(paiAntigo, nomeAntigo, caminhoAntigo); - if (alvo == null) throw new CaminhoNaoEncontradoException("Origem não encontrada."); - if (!alvo.temPermissao(usuario, 'w')) - throw new PermissaoException("Sem permissão de escrita no item de origem."); + VerificacaoUtil.verificarPermissaoEscrita(alvo, usuario, caminhoAntigo); - Diretorio paiNovo = navegar(caminhoNovo.substring(0, caminhoNovo.lastIndexOf('/'))); - String nomeNovo = caminhoNovo.substring(caminhoNovo.lastIndexOf('/') + 1); + Diretorio paiNovo = DiretorioUtil.obterDiretorioPai(caminhoNovo, root); + String nomeNovo = DiretorioUtil.extrairNomeArquivo(caminhoNovo); - if (paiNovo.getFilhos().containsKey(nomeNovo)) { - throw new PermissaoException("Já existe um item no destino com esse nome."); - } + VerificacaoUtil.verificarDestinoDisponivel(paiNovo, nomeNovo); - paiAntigo.removerFilho(nomeAntigo); - alvo.setNome(nomeNovo); - paiNovo.adicionarFilho(alvo); + ArquivoUtil.executarMovimentacao(paiAntigo, paiNovo, nomeAntigo, nomeNovo, alvo); } @Override public void ls(String caminho, String usuario, boolean recursivo) throws CaminhoNaoEncontradoException, PermissaoException { - Diretorio dir = navegar(caminho); - - if (!dir.temPermissao(usuario, 'r')) { - throw new PermissaoException("Sem permissão de leitura para listar o diretório."); - } - - String output = listar(dir, caminho, recursivo, usuario); + Diretorio dir = DiretorioUtil.navegar(caminho, root); + VerificacaoUtil.verificarLeituraDiretorio(dir, usuario, caminho); + String output = DiretorioUtil.listar(dir, caminho, recursivo, usuario); System.out.print(output); } - private String listar(Diretorio dir, String caminho, boolean recursivo, String usuario) { - StringBuilder output = new StringBuilder(); - output.append(caminho).append(":\n"); - - // Listar arquivos e diretórios filhos - for (Map.Entry entry : dir.getFilhos().entrySet()) { - Diretorio filho = entry.getValue(); - output.append(" ").append(filho.toString()).append("\n"); - } - - // Recursão: somente depois de listar os filhos diretos - if (recursivo) { - for (Map.Entry entry : dir.getFilhos().entrySet()) { - Diretorio filho = entry.getValue(); - if (!filho.isArquivo()) { - String novoCaminho = caminho.equals("/") ? "/" + filho.getNome() : caminho + "/" + filho.getNome(); - output.append(listar(filho, novoCaminho, true, usuario)); - } - } - } - - return output.toString(); - } - @Override public void cp(String caminhoOrigem, String caminhoDestino, String usuario, boolean recursivo) throws CaminhoNaoEncontradoException, PermissaoException { - Diretorio origem = navegar(caminhoOrigem); - Diretorio destino = navegar(caminhoDestino); + Diretorio origem = DiretorioUtil.navegar(caminhoOrigem, root); + Diretorio destino = DiretorioUtil.navegar(caminhoDestino, root); - if (!origem.temPermissao(usuario, 'r')) { - throw new PermissaoException("Sem permissão de leitura na origem."); - } - if (!destino.temPermissao(usuario, 'w')) { - throw new PermissaoException("Sem permissão de escrita no destino."); - } + VerificacaoUtil.verificarPermissoesParaCopia(origem, destino, usuario); if (origem.isArquivo()) { - copiarArquivo((Arquivo) origem, destino); + ArquivoUtil.copiarArquivo((Arquivo) origem, destino); } else { if (!recursivo) { throw new PermissaoException("Diretório precisa de recursividade para cópia."); } - copiarDiretorio((Diretorio) origem, destino, usuario); - } - } - - private void copiarArquivo(Arquivo origem, Diretorio destino) { - Arquivo copia = new Arquivo(origem.getNome(), origem.getPermissoes(), origem.getDono()); - for (Arquivo.Bloco bloco : origem.getBlocos()) { - copia.addBloco(bloco); - copia.incrementTamnho(bloco.dados.length); - } - destino.adicionarFilho(copia); - } - - private void copiarDiretorio(Diretorio origem, Diretorio destino, String usuario) throws PermissaoException { - Diretorio copia = new Diretorio(origem.getNome(), origem.getPermissoes(), origem.getDono()); - destino.adicionarFilho(copia); - for (Diretorio filho : origem.getFilhos().values()) { - if (filho.isArquivo()) { - copiarArquivo((Arquivo) filho, copia); - } else { - copiarDiretorio(filho, copia, usuario); - } + ArquivoUtil.copiarDiretorio((Diretorio) origem, destino, usuario); } } } diff --git a/filesys/util/ArquivoUtil.java b/filesys/util/ArquivoUtil.java new file mode 100644 index 0000000..833b96e --- /dev/null +++ b/filesys/util/ArquivoUtil.java @@ -0,0 +1,94 @@ +package filesys.util; + +import exception.PermissaoException; +import filesys.Arquivo; +import filesys.Diretorio; +import filesys.Offset; +import filesys.Usuario; + +public class ArquivoUtil { + + private ArquivoUtil() { + } + + public static Arquivo criarNovoArquivo(String nomeArquivo, Usuario user) { + return new Arquivo(nomeArquivo, user.getPermissao(), user.getNome()); + } + + public static void escreverBufferNoArquivo(Arquivo arquivo, byte[] buffer, boolean anexar) { + if (!anexar) { + arquivo.clearBlocos(); + } + + int offset = 0; + int tamMax = arquivo.getTamMaxBloco(); + + while (offset < buffer.length) { + int length = Math.min(buffer.length - offset, tamMax); + byte[] dados = new byte[length]; + System.arraycopy(buffer, offset, dados, 0, length); + + arquivo.addBloco(new Arquivo.Bloco(dados)); + arquivo.incrementTamnho(length); + offset += length; + } + } + + public static void atualizarOffsetLimite(Offset offset, long fileSize) { + offset.setMax((int) fileSize); + } + + public static void lerDadosDoArquivo(Arquivo arquivo, byte[] buffer, Offset offset) { + int arquivoOffset = offset.getValue(); + int bufferOffset = 0; + + for (Arquivo.Bloco bloco : arquivo.getBlocos()) { + if (arquivoOffset >= bloco.getDados().length) { + arquivoOffset -= bloco.getDados().length; + continue; + } + + int bytesDisponiveis = bloco.getDados().length - arquivoOffset; + int bytesParaLer = Math.min(buffer.length - bufferOffset, bytesDisponiveis); + System.arraycopy(bloco.getDados(), arquivoOffset, buffer, bufferOffset, bytesParaLer); + + bufferOffset += bytesParaLer; + arquivoOffset = 0; + + if (bufferOffset >= buffer.length) + break; + } + + offset.add(bufferOffset); + } + + public static void executarMovimentacao(Diretorio paiAntigo, Diretorio paiNovo, String nomeAntigo, String nomeNovo, + Diretorio alvo) { + paiAntigo.removerFilho(nomeAntigo); + alvo.setNome(nomeNovo); + paiNovo.adicionarFilho(alvo); + } + + + public static void copiarArquivo(Arquivo origem, Diretorio destino) { + Arquivo copia = new Arquivo(origem.getNome(), origem.getPermissoes(), origem.getDono()); + for (Arquivo.Bloco bloco : origem.getBlocos()) { + copia.addBloco(bloco); + copia.incrementTamnho(bloco.getDados().length); + } + destino.adicionarFilho(copia); + } + + public static void copiarDiretorio(Diretorio origem, Diretorio destino, String usuario) throws PermissaoException { + Diretorio copia = new Diretorio(origem.getNome(), origem.getPermissoes(), origem.getDono()); + destino.adicionarFilho(copia); + for (Diretorio filho : origem.getFilhos().values()) { + if (filho.isArquivo()) { + copiarArquivo((Arquivo) filho, copia); + } else { + copiarDiretorio(filho, copia, usuario); + } + } + } + +} diff --git a/filesys/util/DiretorioUtil.java b/filesys/util/DiretorioUtil.java new file mode 100644 index 0000000..6bd07fc --- /dev/null +++ b/filesys/util/DiretorioUtil.java @@ -0,0 +1,117 @@ +package filesys.util; + +import java.util.Map; +import java.util.Set; +import java.util.StringTokenizer; + +import exception.CaminhoNaoEncontradoException; +import exception.OperacaoInvalidaException; +import exception.PermissaoException; +import filesys.Diretorio; +import filesys.Usuario; + +public class DiretorioUtil { + + private DiretorioUtil() { + } + + public static Diretorio obterDiretorioPai(String caminho, Diretorio root) throws CaminhoNaoEncontradoException { + String caminhoPai = caminho.substring(0, caminho.lastIndexOf('/')); + return navegar(caminhoPai.isEmpty() ? "/" : caminhoPai, root); + } + + public static Diretorio navegar(String caminho, Diretorio root) throws CaminhoNaoEncontradoException { + if (caminho.equals("/") || caminho.isEmpty()) { + return root; + } + Diretorio atual = root; + StringTokenizer tokenizer = new StringTokenizer(caminho, "/"); + while (tokenizer.hasMoreTokens()) { + String parte = tokenizer.nextToken(); + if (!atual.getFilhos().containsKey(parte)) { + throw new CaminhoNaoEncontradoException("Caminho não encontrado: " + caminho); + } + atual = atual.getFilhos().get(parte); + } + return atual; + } + + public static Diretorio obterAlvo(Diretorio pai, String nomeAlvo, String caminho) + throws CaminhoNaoEncontradoException { + Diretorio alvo = pai.getFilhos().get(nomeAlvo); + if (alvo == null) { + throw new CaminhoNaoEncontradoException("Caminho não encontrado: " + caminho); + } + return alvo; + } + + public static Diretorio criarDiretorioFilho(Diretorio atual, String nome, String caminhoAtual, String usuario, + Set users) + throws PermissaoException { + VerificacaoUtil.verificarPermissaoEscrita(atual, usuario, caminhoAtual); + Usuario user = UsuarioUtil.buscarUsuario(usuario, users); + Diretorio novo = new Diretorio(nome, atual.getPermissoes(), user.getNome()); + atual.adicionarFilho(novo); + return novo; + } + + public static Diretorio avancarParaDiretorioFilho(Diretorio atual, String nome) throws OperacaoInvalidaException { + Diretorio filho = atual.getFilhos().get(nome); + if (filho.isArquivo()) { + throw new OperacaoInvalidaException("Não é possível criar um diretório dentro de um arquivo."); + } + return filho; + } + + public static void removerRecursivo(Diretorio dir, String usuario) throws PermissaoException { + for (Diretorio filho : dir.getFilhos().values()) { + if (!filho.temPermissao(usuario, 'w')) { + throw new PermissaoException("Sem permissão para remover: " + filho.getNome()); + } + + if (!filho.isArquivo()) { + removerRecursivo(filho, usuario); + } + } + dir.getFilhos().clear(); + } + + public static String extrairCaminhoPai(String caminho) { + int lastSlash = caminho.lastIndexOf('/'); + return (lastSlash <= 0) ? "/" : caminho.substring(0, lastSlash); + } + + public static String extrairNomeArquivo(String caminho) { + return caminho.substring(caminho.lastIndexOf('/') + 1); + } + + private static void listarDiretorioAtual(Diretorio dir, String caminho, StringBuilder output) { + output.append(caminho).append(":\n"); + for (Map.Entry entry : dir.getFilhos().entrySet()) { + Diretorio filho = entry.getValue(); + output.append(" ").append(filho.toString()).append("\n"); + } + } + + private static void listarRecursivamente(Diretorio dir, String caminho, StringBuilder output, String usuario) { + for (Map.Entry entry : dir.getFilhos().entrySet()) { + Diretorio filho = entry.getValue(); + if (!filho.isArquivo()) { + String novoCaminho = caminho.equals("/") ? "/" + filho.getNome() : caminho + "/" + filho.getNome(); + listarDiretorioAtual(filho, novoCaminho, output); + listarRecursivamente(filho, novoCaminho, output, usuario); + } + } + } + + public static String listar(Diretorio dir, String caminho, boolean recursivo, String usuario) { + StringBuilder output = new StringBuilder(); + listarDiretorioAtual(dir, caminho, output); + + if (recursivo) { + listarRecursivamente(dir, caminho, output, usuario); + } + + return output.toString(); + } +} diff --git a/filesys/util/UsuarioUtil.java b/filesys/util/UsuarioUtil.java new file mode 100644 index 0000000..9be4897 --- /dev/null +++ b/filesys/util/UsuarioUtil.java @@ -0,0 +1,19 @@ +package filesys.util; + +import java.util.Set; + +import exception.PermissaoException; +import filesys.Usuario; + +public class UsuarioUtil { + + private UsuarioUtil() { + } + + public static Usuario buscarUsuario(String nome, Set users) throws PermissaoException { + return users.stream() + .filter(u -> u.getNome().equals(nome)) + .findFirst() + .orElseThrow(() -> new PermissaoException("Usuário não encontrado: " + nome)); + } +} diff --git a/filesys/util/VerificacaoUtil.java b/filesys/util/VerificacaoUtil.java new file mode 100644 index 0000000..01844d8 --- /dev/null +++ b/filesys/util/VerificacaoUtil.java @@ -0,0 +1,93 @@ +package filesys.util; + +import exception.CaminhoJaExistenteException; +import exception.OperacaoInvalidaException; +import exception.PermissaoException; +import filesys.Diretorio; + +public class VerificacaoUtil { + + private VerificacaoUtil() { + } + + public static void verificarPermissaoEscrita(Diretorio diretorio, String usuario, String caminhoAtual) + throws PermissaoException { + if (!diretorio.temPermissao(usuario, 'w')) { + throw new PermissaoException("Sem permissão para criar em: " + caminhoAtual); + } + } + + public static void verificarLeituraDiretorio(Diretorio dir, String usuario, String caminho) + throws PermissaoException { + if (!dir.temPermissao(usuario, 'r')) { + throw new PermissaoException("Sem permissão de leitura para listar o diretório: " + caminho); + } + } + + public static void verificarRemocaoDiretorio(Diretorio alvo, boolean recursivo) throws PermissaoException { + if (!recursivo && !alvo.getFilhos().isEmpty()) { + throw new PermissaoException("Diretório não está vazio. Use recursivo=true."); + } + } + + public static void verificarCaminhoArquivo(String caminho) throws OperacaoInvalidaException { + if (caminho.equals("/") || caminho.endsWith("/")) { + throw new OperacaoInvalidaException("Nome de arquivo inválido."); + } + } + + public static void verificarSeEhArquivo(Diretorio parent) throws OperacaoInvalidaException { + if (parent.isArquivo()) { + throw new OperacaoInvalidaException("Não é possível criar um arquivo dentro de um arquivo."); + } + } + + public static void verificarSeArquivoExiste(Diretorio parent, String nomeArquivo) + throws CaminhoJaExistenteException { + if (parent.getFilhos().containsKey(nomeArquivo)) { + throw new CaminhoJaExistenteException("Arquivo já existe: " + nomeArquivo); + } + } + + public static void verificarEscritaArquivo(Diretorio dir, String usuario) + throws OperacaoInvalidaException, PermissaoException { + if (!dir.isArquivo()) { + throw new OperacaoInvalidaException("Não é possível escrever em um diretório."); + } + if (!dir.temPermissao(usuario, 'w')) { + throw new PermissaoException("Sem permissão de escrita."); + } + } + + public static void verificarLeituraArquivo(Diretorio dir, String usuario) + throws OperacaoInvalidaException, PermissaoException { + if (!dir.isArquivo()) + throw new OperacaoInvalidaException("Não é possível ler de um diretório."); + if (!dir.temPermissao(usuario, 'r')) + throw new PermissaoException("Sem permissão de leitura."); + } + + public static void verificarMovimentacaoPermitida(String origem, String destino) throws PermissaoException { + if (origem.equals("/") || destino.equals("/")) { + throw new PermissaoException("Não é possível mover o diretório raiz."); + } + } + + public static void verificarDestinoDisponivel(Diretorio paiDestino, String nomeDestino) + throws PermissaoException { + if (paiDestino.getFilhos().containsKey(nomeDestino)) { + throw new PermissaoException("Já existe um item no destino com esse nome."); + } + } + + public static void verificarPermissoesParaCopia(Diretorio origem, Diretorio destino, String usuario) + throws PermissaoException { + if (!origem.temPermissao(usuario, 'r')) { + throw new PermissaoException("Sem permissão de leitura na origem."); + } + if (!destino.temPermissao(usuario, 'w')) { + throw new PermissaoException("Sem permissão de escrita no destino."); + } + } + +} From 9ef47736f4ae930d86d57332d986fb1760380fbe Mon Sep 17 00:00:00 2001 From: marcosffp Date: Mon, 16 Jun 2025 16:53:22 -0300 Subject: [PATCH 13/22] =?UTF-8?q?formata=C3=A7=C3=A3o?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- filesys/Diretorio.java | 12 +++++++---- filesys/FileSystem.java | 17 ++++++++++----- filesys/util/ArquivoUtil.java | 39 +++++++++++++++++------------------ filesys/util/UsuarioUtil.java | 14 ++++++------- 4 files changed, 46 insertions(+), 36 deletions(-) diff --git a/filesys/Diretorio.java b/filesys/Diretorio.java index b03b8be..18d4529 100644 --- a/filesys/Diretorio.java +++ b/filesys/Diretorio.java @@ -29,10 +29,12 @@ public void setPermissaoUsuario(String usuario, String permissao) { public boolean temPermissao(String usuario, char permissaoNecessaria) { // Root tem todas as permissões - if ("root".equals(usuario)) return true; + if ("root".equals(usuario)) + return true; // Dono tem todas as permissões - if (usuario.equals(dono)) return true; + if (usuario.equals(dono)) + return true; // Verifica permissões específicas do usuário no diretório atual String permissoesUsuario = permissoesEspecificas.get(usuario); @@ -50,8 +52,10 @@ public boolean temPermissao(String usuario, char permissaoNecessaria) { } public String getPermissoesUsuario(String usuario) { - if ("root".equals(usuario)) return "rwx"; - if (usuario.equals(dono)) return permissoes; + if ("root".equals(usuario)) + return "rwx"; + if (usuario.equals(dono)) + return permissoes; return permissoesEspecificas.getOrDefault(usuario, "---"); } diff --git a/filesys/FileSystem.java b/filesys/FileSystem.java index 7c33c76..8e2b5ba 100644 --- a/filesys/FileSystem.java +++ b/filesys/FileSystem.java @@ -6,12 +6,17 @@ import exception.PermissaoException; /** - * Classe {@code FileSystem} atua como um proxy para a implementação real do sistema de arquivos {@link FileSystemImpl}. + * Classe {@code FileSystem} atua como um proxy para a implementação real do + * sistema de arquivos {@link FileSystemImpl}. * - *

Essa classe encapsula a lógica interna e fornece uma interface padronizada para operações em sistemas de arquivos, + *

+ * Essa classe encapsula a lógica interna e fornece uma interface padronizada + * para operações em sistemas de arquivos, * delegando todas as chamadas de método à instância de {@code FileSystemImpl}. * - *

Inicializa com um diretório raiz padrão ("/") e um usuário padrão ("root") com permissões completas. + *

+ * Inicializa com um diretório raiz padrão ("/") e um usuário padrão ("root") + * com permissões completas. */ final public class FileSystem implements IFileSystem { @@ -28,7 +33,8 @@ public void chmod(String caminho, String usuario, String usuarioAlvo, String per } @Override - public void mkdir(String caminho, String usuario) throws CaminhoJaExistenteException, PermissaoException, OperacaoInvalidaException { + public void mkdir(String caminho, String usuario) + throws CaminhoJaExistenteException, PermissaoException, OperacaoInvalidaException { fileSystemImpl.mkdir(caminho, usuario); } @@ -39,7 +45,8 @@ public void rm(String caminho, String usuario, boolean recursivo) } @Override - public void touch(String caminho, String usuario) throws CaminhoJaExistenteException, PermissaoException, CaminhoNaoEncontradoException, OperacaoInvalidaException { + public void touch(String caminho, String usuario) throws CaminhoJaExistenteException, PermissaoException, + CaminhoNaoEncontradoException, OperacaoInvalidaException { fileSystemImpl.touch(caminho, usuario); } diff --git a/filesys/util/ArquivoUtil.java b/filesys/util/ArquivoUtil.java index 833b96e..2c1f9fd 100644 --- a/filesys/util/ArquivoUtil.java +++ b/filesys/util/ArquivoUtil.java @@ -7,14 +7,14 @@ import filesys.Usuario; public class ArquivoUtil { - + private ArquivoUtil() { } public static Arquivo criarNovoArquivo(String nomeArquivo, Usuario user) { return new Arquivo(nomeArquivo, user.getPermissao(), user.getNome()); } - + public static void escreverBufferNoArquivo(Arquivo arquivo, byte[] buffer, boolean anexar) { if (!anexar) { arquivo.clearBlocos(); @@ -69,26 +69,25 @@ public static void executarMovimentacao(Diretorio paiAntigo, Diretorio paiNovo, paiNovo.adicionarFilho(alvo); } - - public static void copiarArquivo(Arquivo origem, Diretorio destino) { - Arquivo copia = new Arquivo(origem.getNome(), origem.getPermissoes(), origem.getDono()); - for (Arquivo.Bloco bloco : origem.getBlocos()) { - copia.addBloco(bloco); - copia.incrementTamnho(bloco.getDados().length); - } - destino.adicionarFilho(copia); + public static void copiarArquivo(Arquivo origem, Diretorio destino) { + Arquivo copia = new Arquivo(origem.getNome(), origem.getPermissoes(), origem.getDono()); + for (Arquivo.Bloco bloco : origem.getBlocos()) { + copia.addBloco(bloco); + copia.incrementTamnho(bloco.getDados().length); } + destino.adicionarFilho(copia); + } - public static void copiarDiretorio(Diretorio origem, Diretorio destino, String usuario) throws PermissaoException { - Diretorio copia = new Diretorio(origem.getNome(), origem.getPermissoes(), origem.getDono()); - destino.adicionarFilho(copia); - for (Diretorio filho : origem.getFilhos().values()) { - if (filho.isArquivo()) { - copiarArquivo((Arquivo) filho, copia); - } else { - copiarDiretorio(filho, copia, usuario); - } - } + public static void copiarDiretorio(Diretorio origem, Diretorio destino, String usuario) throws PermissaoException { + Diretorio copia = new Diretorio(origem.getNome(), origem.getPermissoes(), origem.getDono()); + destino.adicionarFilho(copia); + for (Diretorio filho : origem.getFilhos().values()) { + if (filho.isArquivo()) { + copiarArquivo((Arquivo) filho, copia); + } else { + copiarDiretorio(filho, copia, usuario); + } } + } } diff --git a/filesys/util/UsuarioUtil.java b/filesys/util/UsuarioUtil.java index 9be4897..accba65 100644 --- a/filesys/util/UsuarioUtil.java +++ b/filesys/util/UsuarioUtil.java @@ -6,14 +6,14 @@ import filesys.Usuario; public class UsuarioUtil { - + private UsuarioUtil() { } - public static Usuario buscarUsuario(String nome, Set users) throws PermissaoException { - return users.stream() - .filter(u -> u.getNome().equals(nome)) - .findFirst() - .orElseThrow(() -> new PermissaoException("Usuário não encontrado: " + nome)); - } + public static Usuario buscarUsuario(String nome, Set users) throws PermissaoException { + return users.stream() + .filter(u -> u.getNome().equals(nome)) + .findFirst() + .orElseThrow(() -> new PermissaoException("Usuário não encontrado: " + nome)); + } } From b9ea6b68221c2b9458e6142f357744dfb8758a91 Mon Sep 17 00:00:00 2001 From: marcosffp Date: Mon, 16 Jun 2025 21:09:46 -0300 Subject: [PATCH 14/22] =?UTF-8?q?atualiza=C3=A7=C3=A3o?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- filesys/FileSystemImpl.java | 49 +++++++++++++------------------ filesys/util/DiretorioUtil.java | 29 +++++++++++++----- filesys/util/VerificacaoUtil.java | 7 +++++ 3 files changed, 49 insertions(+), 36 deletions(-) diff --git a/filesys/FileSystemImpl.java b/filesys/FileSystemImpl.java index 55732e9..d24c8c1 100644 --- a/filesys/FileSystemImpl.java +++ b/filesys/FileSystemImpl.java @@ -71,16 +71,19 @@ public void addUser(Usuario user) { } users.add(user); try { - DiretorioUtil.navegar(user.getDir(), root).setPermissaoUsuario(user.getNome(), user.getPermissao()); - } catch (CaminhoNaoEncontradoException e) { + DiretorioUtil.navegar(user.getDir(), root, user.getNome()) + .setPermissaoUsuario(user.getNome(), user.getPermissao()); + } catch (CaminhoNaoEncontradoException | PermissaoException e) { try { mkdir(user.getDir(), ROOT_USER); - DiretorioUtil.navegar(user.getDir(), root).setPermissaoUsuario(user.getNome(), user.getPermissao()); + DiretorioUtil.navegar(user.getDir(), root, user.getNome()) + .setPermissaoUsuario(user.getNome(), user.getPermissao()); } catch (CaminhoJaExistenteException | PermissaoException | CaminhoNaoEncontradoException | OperacaoInvalidaException ex) { throw new RuntimeException("Erro ao criar diretório para o usuário: " + user.getNome(), ex); } } + } @Override @@ -99,15 +102,13 @@ public void mkdir(String caminho, String usuario) throws CaminhoJaExistenteException, PermissaoException, OperacaoInvalidaException { if (caminho.equals("/")) return; - StringTokenizer tokenizer = new StringTokenizer(caminho, "/"); Diretorio atual = root; StringBuilder caminhoAtual = new StringBuilder(); - while (tokenizer.hasMoreTokens()) { String parte = tokenizer.nextToken(); caminhoAtual.append("/").append(parte); - + VerificacaoUtil.verificarPermissaoExecucao(atual, usuario, caminhoAtual.toString()); if (!existeFilho(atual, parte)) { atual = DiretorioUtil.criarDiretorioFilho(atual, parte, caminhoAtual.toString(), usuario, users); } else { @@ -116,19 +117,15 @@ public void mkdir(String caminho, String usuario) } } - public boolean existeFilho(Diretorio atual, String nome) { + private boolean existeFilho(Diretorio atual, String nome) { return atual.getFilhos().containsKey(nome); } @Override public void chmod(String caminho, String usuario, String usuarioAlvo, String permissao) throws CaminhoNaoEncontradoException, PermissaoException { - Diretorio dir = DiretorioUtil.navegar(caminho, root); - - if (!dir.temPermissao(usuario, 'w')) { - throw new PermissaoException("Usuário sem permissão para alterar permissões em: " + caminho); - } - + Diretorio dir = DiretorioUtil.navegar(caminho, root, usuario); + VerificacaoUtil.verificarPermissaoEscrita(dir, usuarioAlvo, caminho); dir.setPermissaoUsuario(usuarioAlvo, permissao); } @@ -139,25 +136,19 @@ public void rm(String caminho, String usuario, boolean recursivo) throw new PermissaoException("Não é possível remover o diretório raiz."); } - Diretorio pai = DiretorioUtil.obterDiretorioPai(caminho, root); - String nomeAlvo = obterNomeAlvo(caminho); + Diretorio pai = DiretorioUtil.obterDiretorioPai(caminho, root, usuario); + String nomeAlvo = DiretorioUtil.obterNomeAlvo(caminho); Diretorio alvo = DiretorioUtil.obterAlvo(pai, nomeAlvo, caminho); - VerificacaoUtil.verificarPermissaoEscrita(alvo, usuario, caminho); - if (!alvo.isArquivo()) { VerificacaoUtil.verificarRemocaoDiretorio(alvo, recursivo); if (recursivo) { DiretorioUtil.removerRecursivo(alvo, usuario); } } - pai.removerFilho(nomeAlvo); } - private String obterNomeAlvo(String caminho) { - return caminho.substring(caminho.lastIndexOf('/') + 1); - } @Override public void touch(String caminho, String usuario) @@ -169,7 +160,7 @@ public void touch(String caminho, String usuario) String nomeArquivo = DiretorioUtil.extrairNomeArquivo(caminho); mkdir(caminhoPai, usuario); - Diretorio parent = DiretorioUtil.navegar(caminhoPai, root); + Diretorio parent = DiretorioUtil.navegar(caminhoPai, root, usuario); VerificacaoUtil.verificarPermissaoEscrita(parent, usuario, caminhoPai); VerificacaoUtil.verificarSeEhArquivo(parent); @@ -183,7 +174,7 @@ public void touch(String caminho, String usuario) @Override public void write(String caminho, String usuario, boolean anexar, byte[] buffer) throws CaminhoNaoEncontradoException, PermissaoException, OperacaoInvalidaException { - Diretorio dir = DiretorioUtil.navegar(caminho, root); + Diretorio dir = DiretorioUtil.navegar(caminho, root,usuario); VerificacaoUtil.verificarEscritaArquivo(dir, usuario); ArquivoUtil.escreverBufferNoArquivo((Arquivo) dir, buffer, anexar); } @@ -191,7 +182,7 @@ public void write(String caminho, String usuario, boolean anexar, byte[] buffer) @Override public void read(String caminho, String usuario, byte[] buffer, Offset offset) throws CaminhoNaoEncontradoException, PermissaoException, OperacaoInvalidaException { - Diretorio dir = DiretorioUtil.navegar(caminho, root); + Diretorio dir = DiretorioUtil.navegar(caminho, root,usuario); VerificacaoUtil.verificarLeituraArquivo(dir, usuario); Arquivo arquivo = (Arquivo) dir; ArquivoUtil.atualizarOffsetLimite(offset, arquivo.getTamanho()); @@ -205,13 +196,13 @@ public void mv(String caminhoAntigo, String caminhoNovo, String usuario) throws CaminhoNaoEncontradoException, PermissaoException { VerificacaoUtil.verificarMovimentacaoPermitida(caminhoAntigo, caminhoNovo); - Diretorio paiAntigo = DiretorioUtil.obterDiretorioPai(caminhoAntigo, root); + Diretorio paiAntigo = DiretorioUtil.obterDiretorioPai(caminhoAntigo, root, usuario); String nomeAntigo = DiretorioUtil.extrairNomeArquivo(caminhoAntigo); Diretorio alvo = DiretorioUtil.obterAlvo(paiAntigo, nomeAntigo, caminhoAntigo); VerificacaoUtil.verificarPermissaoEscrita(alvo, usuario, caminhoAntigo); - Diretorio paiNovo = DiretorioUtil.obterDiretorioPai(caminhoNovo, root); + Diretorio paiNovo = DiretorioUtil.obterDiretorioPai(caminhoNovo, root, usuario); String nomeNovo = DiretorioUtil.extrairNomeArquivo(caminhoNovo); VerificacaoUtil.verificarDestinoDisponivel(paiNovo, nomeNovo); @@ -222,7 +213,7 @@ public void mv(String caminhoAntigo, String caminhoNovo, String usuario) @Override public void ls(String caminho, String usuario, boolean recursivo) throws CaminhoNaoEncontradoException, PermissaoException { - Diretorio dir = DiretorioUtil.navegar(caminho, root); + Diretorio dir = DiretorioUtil.navegar(caminho, root, usuario); VerificacaoUtil.verificarLeituraDiretorio(dir, usuario, caminho); String output = DiretorioUtil.listar(dir, caminho, recursivo, usuario); System.out.print(output); @@ -231,8 +222,8 @@ public void ls(String caminho, String usuario, boolean recursivo) @Override public void cp(String caminhoOrigem, String caminhoDestino, String usuario, boolean recursivo) throws CaminhoNaoEncontradoException, PermissaoException { - Diretorio origem = DiretorioUtil.navegar(caminhoOrigem, root); - Diretorio destino = DiretorioUtil.navegar(caminhoDestino, root); + Diretorio origem = DiretorioUtil.navegar(caminhoOrigem, root, usuario); + Diretorio destino = DiretorioUtil.navegar(caminhoDestino, root, usuario); VerificacaoUtil.verificarPermissoesParaCopia(origem, destino, usuario); diff --git a/filesys/util/DiretorioUtil.java b/filesys/util/DiretorioUtil.java index 6bd07fc..8d61439 100644 --- a/filesys/util/DiretorioUtil.java +++ b/filesys/util/DiretorioUtil.java @@ -15,24 +15,38 @@ public class DiretorioUtil { private DiretorioUtil() { } - public static Diretorio obterDiretorioPai(String caminho, Diretorio root) throws CaminhoNaoEncontradoException { + public static Diretorio obterDiretorioPai(String caminho, Diretorio root, String usuario) + throws CaminhoNaoEncontradoException, PermissaoException { String caminhoPai = caminho.substring(0, caminho.lastIndexOf('/')); - return navegar(caminhoPai.isEmpty() ? "/" : caminhoPai, root); + return navegar(caminhoPai.isEmpty() ? "/" : caminhoPai, root, usuario); } - public static Diretorio navegar(String caminho, Diretorio root) throws CaminhoNaoEncontradoException { + + + public static Diretorio navegar(String caminho, Diretorio root, String usuario) + throws CaminhoNaoEncontradoException, PermissaoException { + if (caminho.equals("/") || caminho.isEmpty()) { + VerificacaoUtil.verificarPermissaoExecucao(root, usuario, "/"); return root; } + Diretorio atual = root; StringTokenizer tokenizer = new StringTokenizer(caminho, "/"); + StringBuilder caminhoAtual = new StringBuilder("/"); + while (tokenizer.hasMoreTokens()) { String parte = tokenizer.nextToken(); + if (!atual.getFilhos().containsKey(parte)) { throw new CaminhoNaoEncontradoException("Caminho não encontrado: " + caminho); } + atual = atual.getFilhos().get(parte); + caminhoAtual.append(parte).append("/"); + VerificacaoUtil.verificarPermissaoExecucao(atual, usuario, caminhoAtual.toString()); } + return atual; } @@ -65,10 +79,7 @@ public static Diretorio avancarParaDiretorioFilho(Diretorio atual, String nome) public static void removerRecursivo(Diretorio dir, String usuario) throws PermissaoException { for (Diretorio filho : dir.getFilhos().values()) { - if (!filho.temPermissao(usuario, 'w')) { - throw new PermissaoException("Sem permissão para remover: " + filho.getNome()); - } - + VerificacaoUtil.verificarPermissaoEscrita(filho, usuario, dir.getNome()); if (!filho.isArquivo()) { removerRecursivo(filho, usuario); } @@ -114,4 +125,8 @@ public static String listar(Diretorio dir, String caminho, boolean recursivo, St return output.toString(); } + + public static String obterNomeAlvo(String caminho) { + return caminho.substring(caminho.lastIndexOf('/') + 1); + } } diff --git a/filesys/util/VerificacaoUtil.java b/filesys/util/VerificacaoUtil.java index 01844d8..5ebdf14 100644 --- a/filesys/util/VerificacaoUtil.java +++ b/filesys/util/VerificacaoUtil.java @@ -17,6 +17,13 @@ public static void verificarPermissaoEscrita(Diretorio diretorio, String usuario } } + public static void verificarPermissaoExecucao(Diretorio diretorio, String usuario, String caminhoAtual) + throws PermissaoException { + if (!diretorio.temPermissao(usuario, 'x')) { + throw new PermissaoException("Sem permissão de navegação em: " + caminhoAtual); + } + } + public static void verificarLeituraDiretorio(Diretorio dir, String usuario, String caminho) throws PermissaoException { if (!dir.temPermissao(usuario, 'r')) { From efbbd0d9df92be31961859eb929b833bfcf897db Mon Sep 17 00:00:00 2001 From: marcosffp Date: Tue, 17 Jun 2025 09:07:23 -0300 Subject: [PATCH 15/22] ref: remove redundant permission checks and enhance directory navigation logic --- filesys/FileSystemImpl.java | 30 +++++++++++++++++++++++++----- filesys/util/DiretorioUtil.java | 2 -- filesys/util/VerificacaoUtil.java | 6 ------ 3 files changed, 25 insertions(+), 13 deletions(-) diff --git a/filesys/FileSystemImpl.java b/filesys/FileSystemImpl.java index d24c8c1..d87750b 100644 --- a/filesys/FileSystemImpl.java +++ b/filesys/FileSystemImpl.java @@ -108,7 +108,6 @@ public void mkdir(String caminho, String usuario) while (tokenizer.hasMoreTokens()) { String parte = tokenizer.nextToken(); caminhoAtual.append("/").append(parte); - VerificacaoUtil.verificarPermissaoExecucao(atual, usuario, caminhoAtual.toString()); if (!existeFilho(atual, parte)) { atual = DiretorioUtil.criarDiretorioFilho(atual, parte, caminhoAtual.toString(), usuario, users); } else { @@ -202,12 +201,33 @@ public void mv(String caminhoAntigo, String caminhoNovo, String usuario) VerificacaoUtil.verificarPermissaoEscrita(alvo, usuario, caminhoAntigo); - Diretorio paiNovo = DiretorioUtil.obterDiretorioPai(caminhoNovo, root, usuario); - String nomeNovo = DiretorioUtil.extrairNomeArquivo(caminhoNovo); + boolean destinoExiste = false; + Diretorio destino; + try { + destino = DiretorioUtil.navegar(caminhoNovo, root, usuario); + destinoExiste = true; + } catch (CaminhoNaoEncontradoException e) { + destinoExiste = false; + destino = null; + } + + if (destinoExiste && !destino.isArquivo()) { + // Se destino é um diretório existente, mova para dentro dele + VerificacaoUtil.verificarPermissaoEscrita(destino, usuario, caminhoNovo); + if (destino.getFilhos().containsKey(nomeAntigo)) { + throw new PermissaoException("Já existe um item com o mesmo nome no diretório de destino."); + } + ArquivoUtil.executarMovimentacao(paiAntigo, destino, nomeAntigo, nomeAntigo, alvo); + } else { + // Caso seja renomeação ou mudança para novo caminho + Diretorio paiNovo = DiretorioUtil.obterDiretorioPai(caminhoNovo, root, usuario); + String nomeNovo = DiretorioUtil.extrairNomeArquivo(caminhoNovo); - VerificacaoUtil.verificarDestinoDisponivel(paiNovo, nomeNovo); + VerificacaoUtil.verificarPermissaoEscrita(paiNovo, usuario, caminhoNovo); + VerificacaoUtil.verificarDestinoDisponivel(paiNovo, nomeNovo); - ArquivoUtil.executarMovimentacao(paiAntigo, paiNovo, nomeAntigo, nomeNovo, alvo); + ArquivoUtil.executarMovimentacao(paiAntigo, paiNovo, nomeAntigo, nomeNovo, alvo); + } } @Override diff --git a/filesys/util/DiretorioUtil.java b/filesys/util/DiretorioUtil.java index 8d61439..d37d8dd 100644 --- a/filesys/util/DiretorioUtil.java +++ b/filesys/util/DiretorioUtil.java @@ -27,7 +27,6 @@ public static Diretorio navegar(String caminho, Diretorio root, String usuario) throws CaminhoNaoEncontradoException, PermissaoException { if (caminho.equals("/") || caminho.isEmpty()) { - VerificacaoUtil.verificarPermissaoExecucao(root, usuario, "/"); return root; } @@ -44,7 +43,6 @@ public static Diretorio navegar(String caminho, Diretorio root, String usuario) atual = atual.getFilhos().get(parte); caminhoAtual.append(parte).append("/"); - VerificacaoUtil.verificarPermissaoExecucao(atual, usuario, caminhoAtual.toString()); } return atual; diff --git a/filesys/util/VerificacaoUtil.java b/filesys/util/VerificacaoUtil.java index 5ebdf14..bb685fd 100644 --- a/filesys/util/VerificacaoUtil.java +++ b/filesys/util/VerificacaoUtil.java @@ -17,12 +17,6 @@ public static void verificarPermissaoEscrita(Diretorio diretorio, String usuario } } - public static void verificarPermissaoExecucao(Diretorio diretorio, String usuario, String caminhoAtual) - throws PermissaoException { - if (!diretorio.temPermissao(usuario, 'x')) { - throw new PermissaoException("Sem permissão de navegação em: " + caminhoAtual); - } - } public static void verificarLeituraDiretorio(Diretorio dir, String usuario, String caminho) throws PermissaoException { From 3973d09b6c5398c4a8aa7b4b8fba0747ba2bc1bc Mon Sep 17 00:00:00 2001 From: marcosffp Date: Tue, 17 Jun 2025 09:15:15 -0300 Subject: [PATCH 16/22] =?UTF-8?q?corre=C3=A7=C3=A3o?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- filesys/FileSystemImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/filesys/FileSystemImpl.java b/filesys/FileSystemImpl.java index d87750b..b164e9b 100644 --- a/filesys/FileSystemImpl.java +++ b/filesys/FileSystemImpl.java @@ -124,7 +124,7 @@ private boolean existeFilho(Diretorio atual, String nome) { public void chmod(String caminho, String usuario, String usuarioAlvo, String permissao) throws CaminhoNaoEncontradoException, PermissaoException { Diretorio dir = DiretorioUtil.navegar(caminho, root, usuario); - VerificacaoUtil.verificarPermissaoEscrita(dir, usuarioAlvo, caminho); + VerificacaoUtil.verificarPermissaoEscrita(dir, usuario, caminho); dir.setPermissaoUsuario(usuarioAlvo, permissao); } From 682f5efb36d26794738e0cb527d2b772dbc0d340 Mon Sep 17 00:00:00 2001 From: marcosffp Date: Tue, 17 Jun 2025 12:12:13 -0300 Subject: [PATCH 17/22] =?UTF-8?q?corre=C3=A7oes=20dnv?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- filesys/FileSystemImpl.java | 3 +++ filesys/util/DiretorioUtil.java | 12 +++++++++++- filesys/util/VerificacaoUtil.java | 7 +++++++ 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/filesys/FileSystemImpl.java b/filesys/FileSystemImpl.java index b164e9b..9a98532 100644 --- a/filesys/FileSystemImpl.java +++ b/filesys/FileSystemImpl.java @@ -107,6 +107,8 @@ public void mkdir(String caminho, String usuario) StringBuilder caminhoAtual = new StringBuilder(); while (tokenizer.hasMoreTokens()) { String parte = tokenizer.nextToken(); + VerificacaoUtil.verificarPermissaoExecucao(atual, usuario, + caminhoAtual.length() == 0 ? "/" : caminhoAtual.toString()); caminhoAtual.append("/").append(parte); if (!existeFilho(atual, parte)) { atual = DiretorioUtil.criarDiretorioFilho(atual, parte, caminhoAtual.toString(), usuario, users); @@ -114,6 +116,7 @@ public void mkdir(String caminho, String usuario) atual = DiretorioUtil.avancarParaDiretorioFilho(atual, parte); } } + } private boolean existeFilho(Diretorio atual, String nome) { diff --git a/filesys/util/DiretorioUtil.java b/filesys/util/DiretorioUtil.java index d37d8dd..7e23f6d 100644 --- a/filesys/util/DiretorioUtil.java +++ b/filesys/util/DiretorioUtil.java @@ -27,6 +27,7 @@ public static Diretorio navegar(String caminho, Diretorio root, String usuario) throws CaminhoNaoEncontradoException, PermissaoException { if (caminho.equals("/") || caminho.isEmpty()) { + VerificacaoUtil.verificarPermissaoExecucao(root, usuario, caminho); return root; } @@ -43,6 +44,7 @@ public static Diretorio navegar(String caminho, Diretorio root, String usuario) atual = atual.getFilhos().get(parte); caminhoAtual.append(parte).append("/"); + VerificacaoUtil.verificarPermissaoExecucao(atual, usuario, caminhoAtual.toString()); } return atual; @@ -67,11 +69,19 @@ public static Diretorio criarDiretorioFilho(Diretorio atual, String nome, String return novo; } - public static Diretorio avancarParaDiretorioFilho(Diretorio atual, String nome) throws OperacaoInvalidaException { + public static Diretorio avancarParaDiretorioFilho(Diretorio atual, String nome) + throws OperacaoInvalidaException, PermissaoException { Diretorio filho = atual.getFilhos().get(nome); + + if (filho == null) { + throw new OperacaoInvalidaException("Diretório não encontrado: " + nome); + } + if (filho.isArquivo()) { throw new OperacaoInvalidaException("Não é possível criar um diretório dentro de um arquivo."); } + VerificacaoUtil.verificarPermissaoExecucao(filho, filho.getDono(), nome); + return filho; } diff --git a/filesys/util/VerificacaoUtil.java b/filesys/util/VerificacaoUtil.java index bb685fd..c8cf116 100644 --- a/filesys/util/VerificacaoUtil.java +++ b/filesys/util/VerificacaoUtil.java @@ -17,6 +17,13 @@ public static void verificarPermissaoEscrita(Diretorio diretorio, String usuario } } + public static void verificarPermissaoExecucao(Diretorio diretorio, String usuario, String caminhoAtual) + throws PermissaoException { + if (!diretorio.temPermissao(usuario, 'x')) { + throw new PermissaoException("Sem permissão de execução para acessar: " + caminhoAtual); + } + } + public static void verificarLeituraDiretorio(Diretorio dir, String usuario, String caminho) throws PermissaoException { From 04aeee2e9f80dcdc2f8caf51022bec0dddc07a2a Mon Sep 17 00:00:00 2001 From: marcosffp Date: Tue, 17 Jun 2025 12:27:03 -0300 Subject: [PATCH 18/22] =?UTF-8?q?corre=C3=A7=C3=B5es?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- filesys/FileSystemImpl.java | 23 +++++++++++++---------- tests/FileSystemTest.java | 2 +- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/filesys/FileSystemImpl.java b/filesys/FileSystemImpl.java index 9a98532..39d934a 100644 --- a/filesys/FileSystemImpl.java +++ b/filesys/FileSystemImpl.java @@ -71,20 +71,23 @@ public void addUser(Usuario user) { } users.add(user); try { - DiretorioUtil.navegar(user.getDir(), root, user.getNome()) + // Navegar usando root para setar permissão do novo usuário + DiretorioUtil.navegar(user.getDir(), root, ROOT_USER) .setPermissaoUsuario(user.getNome(), user.getPermissao()); - } catch (CaminhoNaoEncontradoException | PermissaoException e) { + } catch (CaminhoNaoEncontradoException e) { try { + // Criar o diretório usando root mkdir(user.getDir(), ROOT_USER); - DiretorioUtil.navegar(user.getDir(), root, user.getNome()) + // Navegar usando root para setar permissão do novo usuário + DiretorioUtil.navegar(user.getDir(), root, ROOT_USER) .setPermissaoUsuario(user.getNome(), user.getPermissao()); - } catch (CaminhoJaExistenteException | PermissaoException | CaminhoNaoEncontradoException - | OperacaoInvalidaException ex) { + } catch (Exception ex) { throw new RuntimeException("Erro ao criar diretório para o usuário: " + user.getNome(), ex); } + } catch (PermissaoException e) { + throw new RuntimeException("Erro de permissão inesperado ao adicionar usuário: " + user.getNome(), e); } - - } + } @Override public void removeUser(String username) { @@ -107,16 +110,16 @@ public void mkdir(String caminho, String usuario) StringBuilder caminhoAtual = new StringBuilder(); while (tokenizer.hasMoreTokens()) { String parte = tokenizer.nextToken(); - VerificacaoUtil.verificarPermissaoExecucao(atual, usuario, - caminhoAtual.length() == 0 ? "/" : caminhoAtual.toString()); caminhoAtual.append("/").append(parte); + VerificacaoUtil.verificarPermissaoExecucao(atual, usuario, caminhoAtual.toString()); + if (!existeFilho(atual, parte)) { atual = DiretorioUtil.criarDiretorioFilho(atual, parte, caminhoAtual.toString(), usuario, users); } else { atual = DiretorioUtil.avancarParaDiretorioFilho(atual, parte); } } - + } private boolean existeFilho(Diretorio atual, String nome) { diff --git a/tests/FileSystemTest.java b/tests/FileSystemTest.java index b613057..58c53e7 100644 --- a/tests/FileSystemTest.java +++ b/tests/FileSystemTest.java @@ -24,7 +24,7 @@ static void setUp() { @Test void testChmod() throws CaminhoNaoEncontradoException, PermissaoException, CaminhoJaExistenteException, OperacaoInvalidaException { fileSystem.mkdir("/chmodTest", "root"); - fileSystem.addUser(new Usuario("alvim", "r--", "/chmodTest")); + fileSystem.addUser(new Usuario("alvim", "r-x", "/chmodTest")); assertDoesNotThrow(() -> fileSystem.chmod("/chmodTest", "root", "alvim", "rw-")); } From a4ceba99f6b141f77b78a76fe9b9b4869282d5f2 Mon Sep 17 00:00:00 2001 From: marcosffp Date: Tue, 17 Jun 2025 16:18:16 -0300 Subject: [PATCH 19/22] =?UTF-8?q?anexo=20da=20nova=20verifica=C3=A7=C3=A3o?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- filesys/FileSystemImpl.java | 2 +- filesys/util/VerificacaoUtil.java | 15 +++++++++++---- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/filesys/FileSystemImpl.java b/filesys/FileSystemImpl.java index 39d934a..15b607d 100644 --- a/filesys/FileSystemImpl.java +++ b/filesys/FileSystemImpl.java @@ -169,7 +169,7 @@ public void touch(String caminho, String usuario) VerificacaoUtil.verificarPermissaoEscrita(parent, usuario, caminhoPai); VerificacaoUtil.verificarSeEhArquivo(parent); - VerificacaoUtil.verificarSeArquivoExiste(parent, nomeArquivo); + VerificacaoUtil.verificarSeArquivoOuDiretorioExiste(parent, nomeArquivo); Usuario user = UsuarioUtil.buscarUsuario(usuario, users); Arquivo novoArquivo = ArquivoUtil.criarNovoArquivo(nomeArquivo, user); diff --git a/filesys/util/VerificacaoUtil.java b/filesys/util/VerificacaoUtil.java index c8cf116..f5ff168 100644 --- a/filesys/util/VerificacaoUtil.java +++ b/filesys/util/VerificacaoUtil.java @@ -50,10 +50,17 @@ public static void verificarSeEhArquivo(Diretorio parent) throws OperacaoInvalid } } - public static void verificarSeArquivoExiste(Diretorio parent, String nomeArquivo) - throws CaminhoJaExistenteException { - if (parent.getFilhos().containsKey(nomeArquivo)) { - throw new CaminhoJaExistenteException("Arquivo já existe: " + nomeArquivo); + public static void verificarSeArquivoOuDiretorioExiste(Diretorio parent, String nomeArquivo) + throws CaminhoJaExistenteException, OperacaoInvalidaException { + + Diretorio existente = parent.getFilhos().get(nomeArquivo); + if (existente != null) { + if (existente.isArquivo()) { + throw new CaminhoJaExistenteException("Arquivo já existe: " + nomeArquivo); + } else { + throw new OperacaoInvalidaException( + "Não é possível criar um arquivo: já existe um diretório com o nome '" + nomeArquivo + "'"); + } } } From af008a334ce3ab8df26f6ab2804f849addd55a9a Mon Sep 17 00:00:00 2001 From: marcosffp Date: Tue, 17 Jun 2025 16:45:41 -0300 Subject: [PATCH 20/22] =?UTF-8?q?modulariza=C3=A7=C3=A3o?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- filesys/FileSystemImpl.java | 37 +++++++++--------- filesys/util/ArquivoUtil.java | 3 ++ filesys/util/DiretorioUtil.java | 57 +--------------------------- filesys/util/NavegacaoUtil.java | 63 +++++++++++++++++++++++++++++++ filesys/util/VerificacaoUtil.java | 22 +++++------ 5 files changed, 97 insertions(+), 85 deletions(-) create mode 100644 filesys/util/NavegacaoUtil.java diff --git a/filesys/FileSystemImpl.java b/filesys/FileSystemImpl.java index 15b607d..80eeac5 100644 --- a/filesys/FileSystemImpl.java +++ b/filesys/FileSystemImpl.java @@ -6,6 +6,7 @@ import exception.PermissaoException; import filesys.util.ArquivoUtil; import filesys.util.DiretorioUtil; +import filesys.util.NavegacaoUtil; import filesys.util.UsuarioUtil; import filesys.util.VerificacaoUtil; @@ -72,14 +73,14 @@ public void addUser(Usuario user) { users.add(user); try { // Navegar usando root para setar permissão do novo usuário - DiretorioUtil.navegar(user.getDir(), root, ROOT_USER) + NavegacaoUtil.navegar(user.getDir(), root, ROOT_USER) .setPermissaoUsuario(user.getNome(), user.getPermissao()); } catch (CaminhoNaoEncontradoException e) { try { // Criar o diretório usando root mkdir(user.getDir(), ROOT_USER); // Navegar usando root para setar permissão do novo usuário - DiretorioUtil.navegar(user.getDir(), root, ROOT_USER) + NavegacaoUtil.navegar(user.getDir(), root, ROOT_USER) .setPermissaoUsuario(user.getNome(), user.getPermissao()); } catch (Exception ex) { throw new RuntimeException("Erro ao criar diretório para o usuário: " + user.getNome(), ex); @@ -129,7 +130,7 @@ private boolean existeFilho(Diretorio atual, String nome) { @Override public void chmod(String caminho, String usuario, String usuarioAlvo, String permissao) throws CaminhoNaoEncontradoException, PermissaoException { - Diretorio dir = DiretorioUtil.navegar(caminho, root, usuario); + Diretorio dir = NavegacaoUtil.navegar(caminho, root, usuario); VerificacaoUtil.verificarPermissaoEscrita(dir, usuario, caminho); dir.setPermissaoUsuario(usuarioAlvo, permissao); } @@ -141,9 +142,9 @@ public void rm(String caminho, String usuario, boolean recursivo) throw new PermissaoException("Não é possível remover o diretório raiz."); } - Diretorio pai = DiretorioUtil.obterDiretorioPai(caminho, root, usuario); - String nomeAlvo = DiretorioUtil.obterNomeAlvo(caminho); - Diretorio alvo = DiretorioUtil.obterAlvo(pai, nomeAlvo, caminho); + Diretorio pai = NavegacaoUtil.obterDiretorioPai(caminho, root, usuario); + String nomeAlvo = NavegacaoUtil.obterNomeAlvo(caminho); + Diretorio alvo = NavegacaoUtil.obterAlvo(pai, nomeAlvo, caminho); VerificacaoUtil.verificarPermissaoEscrita(alvo, usuario, caminho); if (!alvo.isArquivo()) { VerificacaoUtil.verificarRemocaoDiretorio(alvo, recursivo); @@ -161,11 +162,11 @@ public void touch(String caminho, String usuario) CaminhoNaoEncontradoException, OperacaoInvalidaException { VerificacaoUtil.verificarCaminhoArquivo(caminho); - String caminhoPai = DiretorioUtil.extrairCaminhoPai(caminho); + String caminhoPai = NavegacaoUtil.extrairCaminhoPai(caminho); String nomeArquivo = DiretorioUtil.extrairNomeArquivo(caminho); mkdir(caminhoPai, usuario); - Diretorio parent = DiretorioUtil.navegar(caminhoPai, root, usuario); + Diretorio parent = NavegacaoUtil.navegar(caminhoPai, root, usuario); VerificacaoUtil.verificarPermissaoEscrita(parent, usuario, caminhoPai); VerificacaoUtil.verificarSeEhArquivo(parent); @@ -179,7 +180,7 @@ public void touch(String caminho, String usuario) @Override public void write(String caminho, String usuario, boolean anexar, byte[] buffer) throws CaminhoNaoEncontradoException, PermissaoException, OperacaoInvalidaException { - Diretorio dir = DiretorioUtil.navegar(caminho, root,usuario); + Diretorio dir = NavegacaoUtil.navegar(caminho, root,usuario); VerificacaoUtil.verificarEscritaArquivo(dir, usuario); ArquivoUtil.escreverBufferNoArquivo((Arquivo) dir, buffer, anexar); } @@ -187,7 +188,7 @@ public void write(String caminho, String usuario, boolean anexar, byte[] buffer) @Override public void read(String caminho, String usuario, byte[] buffer, Offset offset) throws CaminhoNaoEncontradoException, PermissaoException, OperacaoInvalidaException { - Diretorio dir = DiretorioUtil.navegar(caminho, root,usuario); + Diretorio dir = NavegacaoUtil.navegar(caminho, root,usuario); VerificacaoUtil.verificarLeituraArquivo(dir, usuario); Arquivo arquivo = (Arquivo) dir; ArquivoUtil.atualizarOffsetLimite(offset, arquivo.getTamanho()); @@ -201,16 +202,16 @@ public void mv(String caminhoAntigo, String caminhoNovo, String usuario) throws CaminhoNaoEncontradoException, PermissaoException { VerificacaoUtil.verificarMovimentacaoPermitida(caminhoAntigo, caminhoNovo); - Diretorio paiAntigo = DiretorioUtil.obterDiretorioPai(caminhoAntigo, root, usuario); + Diretorio paiAntigo = NavegacaoUtil.obterDiretorioPai(caminhoAntigo, root, usuario); String nomeAntigo = DiretorioUtil.extrairNomeArquivo(caminhoAntigo); - Diretorio alvo = DiretorioUtil.obterAlvo(paiAntigo, nomeAntigo, caminhoAntigo); + Diretorio alvo = NavegacaoUtil.obterAlvo(paiAntigo, nomeAntigo, caminhoAntigo); VerificacaoUtil.verificarPermissaoEscrita(alvo, usuario, caminhoAntigo); boolean destinoExiste = false; Diretorio destino; try { - destino = DiretorioUtil.navegar(caminhoNovo, root, usuario); + destino = NavegacaoUtil.navegar(caminhoNovo, root, usuario); destinoExiste = true; } catch (CaminhoNaoEncontradoException e) { destinoExiste = false; @@ -226,7 +227,7 @@ public void mv(String caminhoAntigo, String caminhoNovo, String usuario) ArquivoUtil.executarMovimentacao(paiAntigo, destino, nomeAntigo, nomeAntigo, alvo); } else { // Caso seja renomeação ou mudança para novo caminho - Diretorio paiNovo = DiretorioUtil.obterDiretorioPai(caminhoNovo, root, usuario); + Diretorio paiNovo = NavegacaoUtil.obterDiretorioPai(caminhoNovo, root, usuario); String nomeNovo = DiretorioUtil.extrairNomeArquivo(caminhoNovo); VerificacaoUtil.verificarPermissaoEscrita(paiNovo, usuario, caminhoNovo); @@ -239,8 +240,8 @@ public void mv(String caminhoAntigo, String caminhoNovo, String usuario) @Override public void ls(String caminho, String usuario, boolean recursivo) throws CaminhoNaoEncontradoException, PermissaoException { - Diretorio dir = DiretorioUtil.navegar(caminho, root, usuario); - VerificacaoUtil.verificarLeituraDiretorio(dir, usuario, caminho); + Diretorio dir = NavegacaoUtil.navegar(caminho, root, usuario); + VerificacaoUtil.verificarPermissaoLeitura(dir, usuario, caminho); String output = DiretorioUtil.listar(dir, caminho, recursivo, usuario); System.out.print(output); } @@ -248,8 +249,8 @@ public void ls(String caminho, String usuario, boolean recursivo) @Override public void cp(String caminhoOrigem, String caminhoDestino, String usuario, boolean recursivo) throws CaminhoNaoEncontradoException, PermissaoException { - Diretorio origem = DiretorioUtil.navegar(caminhoOrigem, root, usuario); - Diretorio destino = DiretorioUtil.navegar(caminhoDestino, root, usuario); + Diretorio origem = NavegacaoUtil.navegar(caminhoOrigem, root, usuario); + Diretorio destino = NavegacaoUtil.navegar(caminhoDestino, root, usuario); VerificacaoUtil.verificarPermissoesParaCopia(origem, destino, usuario); diff --git a/filesys/util/ArquivoUtil.java b/filesys/util/ArquivoUtil.java index 2c1f9fd..7379674 100644 --- a/filesys/util/ArquivoUtil.java +++ b/filesys/util/ArquivoUtil.java @@ -90,4 +90,7 @@ public static void copiarDiretorio(Diretorio origem, Diretorio destino, String u } } + + + } diff --git a/filesys/util/DiretorioUtil.java b/filesys/util/DiretorioUtil.java index 7e23f6d..a7f9dfe 100644 --- a/filesys/util/DiretorioUtil.java +++ b/filesys/util/DiretorioUtil.java @@ -2,9 +2,6 @@ import java.util.Map; import java.util.Set; -import java.util.StringTokenizer; - -import exception.CaminhoNaoEncontradoException; import exception.OperacaoInvalidaException; import exception.PermissaoException; import filesys.Diretorio; @@ -15,50 +12,6 @@ public class DiretorioUtil { private DiretorioUtil() { } - public static Diretorio obterDiretorioPai(String caminho, Diretorio root, String usuario) - throws CaminhoNaoEncontradoException, PermissaoException { - String caminhoPai = caminho.substring(0, caminho.lastIndexOf('/')); - return navegar(caminhoPai.isEmpty() ? "/" : caminhoPai, root, usuario); - } - - - - public static Diretorio navegar(String caminho, Diretorio root, String usuario) - throws CaminhoNaoEncontradoException, PermissaoException { - - if (caminho.equals("/") || caminho.isEmpty()) { - VerificacaoUtil.verificarPermissaoExecucao(root, usuario, caminho); - return root; - } - - Diretorio atual = root; - StringTokenizer tokenizer = new StringTokenizer(caminho, "/"); - StringBuilder caminhoAtual = new StringBuilder("/"); - - while (tokenizer.hasMoreTokens()) { - String parte = tokenizer.nextToken(); - - if (!atual.getFilhos().containsKey(parte)) { - throw new CaminhoNaoEncontradoException("Caminho não encontrado: " + caminho); - } - - atual = atual.getFilhos().get(parte); - caminhoAtual.append(parte).append("/"); - VerificacaoUtil.verificarPermissaoExecucao(atual, usuario, caminhoAtual.toString()); - } - - return atual; - } - - public static Diretorio obterAlvo(Diretorio pai, String nomeAlvo, String caminho) - throws CaminhoNaoEncontradoException { - Diretorio alvo = pai.getFilhos().get(nomeAlvo); - if (alvo == null) { - throw new CaminhoNaoEncontradoException("Caminho não encontrado: " + caminho); - } - return alvo; - } - public static Diretorio criarDiretorioFilho(Diretorio atual, String nome, String caminhoAtual, String usuario, Set users) throws PermissaoException { @@ -80,7 +33,7 @@ public static Diretorio avancarParaDiretorioFilho(Diretorio atual, String nome) if (filho.isArquivo()) { throw new OperacaoInvalidaException("Não é possível criar um diretório dentro de um arquivo."); } - VerificacaoUtil.verificarPermissaoExecucao(filho, filho.getDono(), nome); + VerificacaoUtil.verificarPermissaoExecucao(filho, filho.getDono(), nome); return filho; } @@ -95,11 +48,6 @@ public static void removerRecursivo(Diretorio dir, String usuario) throws Permis dir.getFilhos().clear(); } - public static String extrairCaminhoPai(String caminho) { - int lastSlash = caminho.lastIndexOf('/'); - return (lastSlash <= 0) ? "/" : caminho.substring(0, lastSlash); - } - public static String extrairNomeArquivo(String caminho) { return caminho.substring(caminho.lastIndexOf('/') + 1); } @@ -134,7 +82,4 @@ public static String listar(Diretorio dir, String caminho, boolean recursivo, St return output.toString(); } - public static String obterNomeAlvo(String caminho) { - return caminho.substring(caminho.lastIndexOf('/') + 1); - } } diff --git a/filesys/util/NavegacaoUtil.java b/filesys/util/NavegacaoUtil.java new file mode 100644 index 0000000..f9d1481 --- /dev/null +++ b/filesys/util/NavegacaoUtil.java @@ -0,0 +1,63 @@ +package filesys.util; + +import java.util.StringTokenizer; + +import exception.CaminhoNaoEncontradoException; +import exception.PermissaoException; +import filesys.Diretorio; + +public class NavegacaoUtil { + private NavegacaoUtil() { + } + + public static Diretorio navegar(String caminho, Diretorio root, String usuario) + throws CaminhoNaoEncontradoException, PermissaoException { + + if (caminho.equals("/") || caminho.isEmpty()) { + VerificacaoUtil.verificarPermissaoExecucao(root, usuario, caminho); + return root; + } + + Diretorio atual = root; + StringTokenizer tokenizer = new StringTokenizer(caminho, "/"); + StringBuilder caminhoAtual = new StringBuilder("/"); + + while (tokenizer.hasMoreTokens()) { + String parte = tokenizer.nextToken(); + + if (!atual.getFilhos().containsKey(parte)) { + throw new CaminhoNaoEncontradoException("Caminho não encontrado: " + caminho); + } + + atual = atual.getFilhos().get(parte); + caminhoAtual.append(parte).append("/"); + VerificacaoUtil.verificarPermissaoExecucao(atual, usuario, caminhoAtual.toString()); + } + + return atual; + } + + public static Diretorio obterDiretorioPai(String caminho, Diretorio root, String usuario) + throws CaminhoNaoEncontradoException, PermissaoException { + String caminhoPai = caminho.substring(0, caminho.lastIndexOf('/')); + return navegar(caminhoPai.isEmpty() ? "/" : caminhoPai, root, usuario); + } + + public static Diretorio obterAlvo(Diretorio pai, String nomeAlvo, String caminho) + throws CaminhoNaoEncontradoException { + Diretorio alvo = pai.getFilhos().get(nomeAlvo); + if (alvo == null) { + throw new CaminhoNaoEncontradoException("Caminho não encontrado: " + caminho); + } + return alvo; + } + + public static String extrairCaminhoPai(String caminho) { + int lastSlash = caminho.lastIndexOf('/'); + return (lastSlash <= 0) ? "/" : caminho.substring(0, lastSlash); + } + + public static String obterNomeAlvo(String caminho) { + return caminho.substring(caminho.lastIndexOf('/') + 1); + } +} diff --git a/filesys/util/VerificacaoUtil.java b/filesys/util/VerificacaoUtil.java index f5ff168..fabbe75 100644 --- a/filesys/util/VerificacaoUtil.java +++ b/filesys/util/VerificacaoUtil.java @@ -10,26 +10,26 @@ public class VerificacaoUtil { private VerificacaoUtil() { } - public static void verificarPermissaoEscrita(Diretorio diretorio, String usuario, String caminhoAtual) + private static void verificarPermissao(Diretorio dir, String usuario, char tipoPermissao, String mensagemErro) throws PermissaoException { - if (!diretorio.temPermissao(usuario, 'w')) { - throw new PermissaoException("Sem permissão para criar em: " + caminhoAtual); + if (!dir.temPermissao(usuario, tipoPermissao)) { + throw new PermissaoException(mensagemErro); } } - public static void verificarPermissaoExecucao(Diretorio diretorio, String usuario, String caminhoAtual) + public static void verificarPermissaoEscrita(Diretorio diretorio, String usuario, String caminhoAtual) throws PermissaoException { - if (!diretorio.temPermissao(usuario, 'x')) { - throw new PermissaoException("Sem permissão de execução para acessar: " + caminhoAtual); - } + verificarPermissao(diretorio, usuario, 'w', "Sem permissão de escrita para acessar: " + caminhoAtual); } + public static void verificarPermissaoExecucao(Diretorio diretorio, String usuario, String caminhoAtual) + throws PermissaoException { + verificarPermissao(diretorio, usuario, 'x', "Sem permissão de execução para acessar: " + caminhoAtual); + } - public static void verificarLeituraDiretorio(Diretorio dir, String usuario, String caminho) + public static void verificarPermissaoLeitura(Diretorio dir, String usuario, String caminho) throws PermissaoException { - if (!dir.temPermissao(usuario, 'r')) { - throw new PermissaoException("Sem permissão de leitura para listar o diretório: " + caminho); - } + verificarPermissao(dir, usuario, 'r', "Sem permissão de leitura para acessar: " + caminho); } public static void verificarRemocaoDiretorio(Diretorio alvo, boolean recursivo) throws PermissaoException { From be5a6eb57eed85af6d675b4e1c19c686d13e8315 Mon Sep 17 00:00:00 2001 From: alvimdev Date: Thu, 19 Jun 2025 14:41:34 -0300 Subject: [PATCH 21/22] enh: add new users and update pedro's permissions --- users/users | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/users/users b/users/users index 58c2992..1d72a42 100644 --- a/users/users +++ b/users/users @@ -1,7 +1,9 @@ root /** rwx maria /** rw- joao /** rw- -pedro /** rw- +pedro /** rwx tiago /** rw- -luzia /** rwx -carla /** r-- \ No newline at end of file +carla /** r-- +alvim /** rwx +marcos /** r-x +luisa /** -wx \ No newline at end of file From 485386c99fbad85f2783546d2aac1494e06127f0 Mon Sep 17 00:00:00 2001 From: luisajardim Date: Thu, 19 Jun 2025 15:40:02 -0300 Subject: [PATCH 22/22] =?UTF-8?q?corre=C3=A7=C3=A3o=20nos=20testes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/PermissionTest.java | 139 +++++++++++++++++--------------------- 1 file changed, 62 insertions(+), 77 deletions(-) diff --git a/tests/PermissionTest.java b/tests/PermissionTest.java index a6c03b9..1adee1f 100644 --- a/tests/PermissionTest.java +++ b/tests/PermissionTest.java @@ -19,102 +19,87 @@ public class PermissionTest { private static IFileSystem fileSystem; @BeforeAll - public static void setUp() throws CaminhoJaExistenteException, PermissaoException, CaminhoNaoEncontradoException, OperacaoInvalidaException { + public static void setUp() + throws CaminhoJaExistenteException, + PermissaoException, + CaminhoNaoEncontradoException, + OperacaoInvalidaException { fileSystem = new FileSystemImpl(); - fileSystem.addUser(new Usuario("maria", "rw-", "/")); - fileSystem.addUser(new Usuario("joao", "rwx", "/docs")); - - fileSystem.mkdir("/bin", "maria"); - fileSystem.mkdir("/bin/subdir", "maria"); + fileSystem.addUser(new Usuario("completo", "rwx", "/")); + fileSystem.addUser(new Usuario("leitura_execucao", "r-x", "/")); + fileSystem.addUser(new Usuario("so_leitura", "r--", "/")); + fileSystem.addUser(new Usuario("so_escrita", "-w-", "/")); + fileSystem.addUser(new Usuario("so_execucao", "--x", "/")); + fileSystem.addUser(new Usuario("nenhuma", "---", "/")); + + fileSystem.mkdir("/bin", "completo"); + fileSystem.touch("/bin/arquivo.txt", "completo"); } @Test - public void testReadPermission() throws CaminhoNaoEncontradoException, PermissaoException, CaminhoJaExistenteException { - // Captura a saída do console + public void testPermissaoLeitura() throws Exception { + // Usuário com r pode ler ByteArrayOutputStream outContent = new ByteArrayOutputStream(); System.setOut(new PrintStream(outContent)); - - // Maria tem permissão de leitura no diretório raiz e em todos os subdiretórios - fileSystem.ls("/", "maria", false); - assertTrue(outContent.toString().contains("/:\n")); - - // Limpa a saída capturada + fileSystem.ls("/bin", "leitura_execucao", false); + assertTrue(outContent.toString().contains("arquivo.txt")); outContent.reset(); - // Maria também pode listar subdiretórios como /bin - fileSystem.ls("/bin", "maria", false); - assertTrue(outContent.toString().contains("/bin:\n")); - - // Limpa a saída capturada - outContent.reset(); + // Usuário só com r NÃO pode ler porque não tem x para navegar + assertThrows(PermissaoException.class, () -> fileSystem.ls("/bin", "so_leitura", false)); - // João não tem permissão de leitura no diretório raiz - assertThrows(PermissaoException.class, () -> fileSystem.ls("/", "joao", false)); + // Usuário só com x NÃO pode ler porque não tem r + assertThrows(PermissaoException.class, () -> fileSystem.ls("/bin", "so_execucao", false)); - // Restaura a saída padrão + // Usuário sem r nem x não pode ler + assertThrows(PermissaoException.class, () -> fileSystem.ls("/bin", "so_escrita", false)); + assertThrows(PermissaoException.class, () -> fileSystem.ls("/bin", "nenhuma", false)); System.setOut(System.out); } @Test - public void testWritePermission() throws CaminhoNaoEncontradoException, PermissaoException, CaminhoJaExistenteException { - // Captura a saída do console - ByteArrayOutputStream outContent = new ByteArrayOutputStream(); - System.setOut(new PrintStream(outContent)); - - fileSystem.ls("/bin", "maria", false); - assertTrue(outContent.toString().contains("subdir")); - - // Limpa a saída capturada - outContent.reset(); - - // João não pode criar um diretório no diretório raiz - assertThrows(PermissaoException.class, () -> fileSystem.mkdir("/bin2", "joao")); - - // Restaura a saída padrão - System.setOut(System.out); + public void testPermissaoEscrita() throws Exception { + // Usuário com w pode criar arquivos/diretórios + fileSystem.touch("/bin/novo.txt", "completo"); + + // Usuário sem w não pode criar arquivos/diretórios + assertThrows(PermissaoException.class, () -> fileSystem.touch("/bin/somenter.txt", "so_escrita")); + assertThrows(PermissaoException.class, () -> fileSystem.touch("/bin/semw.txt", "so_leitura")); + assertThrows(PermissaoException.class, () -> fileSystem.touch("/bin/semw2.txt", "so_execucao")); + assertThrows(PermissaoException.class, () -> fileSystem.touch("/bin/semw3.txt", "nenhuma")); } @Test - public void testExecutePermission() throws CaminhoNaoEncontradoException, PermissaoException, CaminhoJaExistenteException, OperacaoInvalidaException { - // João pode criar um arquivo em /docs porque tem permissão rwx; - fileSystem.touch("/docs/file.txt", "joao"); - - // Captura a saída do console - ByteArrayOutputStream outContent = new ByteArrayOutputStream(); - System.setOut(new PrintStream(outContent)); - - fileSystem.ls("/docs", "joao", false); - assertTrue(outContent.toString().contains("file.txt")); - - // Limpa a saída capturada - outContent.reset(); - - // Maria pode criar um arquivo em qualquer lugar porque tem permissões herdadas de / - fileSystem.touch("/docs/file2.txt", "maria"); - fileSystem.ls("/docs", "maria", false); - assertTrue(outContent.toString().contains("file2.txt")); - - // Restaura a saída padrão - System.setOut(System.out); + public void testPermissaoExecucaoNavegacao() throws Exception { + // Usuário com x pode navegar/criar subdiretórios + fileSystem.mkdir("/bin/subx", "completo"); + + // Usuário sem x não pode navegar/criar subdiretórios + assertThrows(PermissaoException.class, () -> fileSystem.mkdir("/bin/somentex", "so_execucao")); + assertThrows(PermissaoException.class, () -> fileSystem.mkdir("/bin/semx", "so_leitura")); + assertThrows(PermissaoException.class, () -> fileSystem.mkdir("/bin/semx2", "so_escrita")); + assertThrows(PermissaoException.class, () -> fileSystem.mkdir("/bin/semx3", "nenhuma")); } @Test - public void testPermissionInheritance() throws CaminhoNaoEncontradoException, PermissaoException, CaminhoJaExistenteException { - - // Captura a saída do console - ByteArrayOutputStream outContent = new ByteArrayOutputStream(); - System.setOut(new PrintStream(outContent)); - - fileSystem.ls("/bin", "maria", false); - assertTrue(outContent.toString().contains("subdir")); - - // Limpa a saída capturada - outContent.reset(); - - // João não pode criar um subdiretório em /bin porque não tem permissão em / - assertThrows(PermissaoException.class, () -> fileSystem.mkdir("/bin/subdir2", "joao")); + public void testPermissaoExecucaoLeituraArquivo() throws Exception { + // Usuário sem x não pode nem ler arquivos em subdiretórios + assertThrows( + PermissaoException.class, () -> fileSystem.ls("/bin", "so_leitura", false)); // sem x + assertThrows( + PermissaoException.class, () -> fileSystem.ls("/bin", "so_escrita", false)); // sem x + assertThrows(PermissaoException.class, () -> fileSystem.ls("/bin", "nenhuma", false)); // sem x + + // Usuário com x mas sem r NÃO pode ler (deve lançar exceção) + assertThrows(PermissaoException.class, () -> fileSystem.ls("/bin", "so_execucao", false)); + } - // Restaura a saída padrão - System.setOut(System.out); + @Test + public void testNenhumaPermissao() { + // Usuário sem nenhuma permissão não pode fazer nada + assertThrows(PermissaoException.class, () -> fileSystem.ls("/", "nenhuma", false)); + assertThrows( + PermissaoException.class, () -> fileSystem.touch("/bin/arquivo_novo.txt", "nenhuma")); + assertThrows(PermissaoException.class, () -> fileSystem.mkdir("/bin/dir_novo", "nenhuma")); } -} +} \ No newline at end of file