diff --git a/Main.java b/Main.java index 3b8673a..fd95f7d 100644 --- a/Main.java +++ b/Main.java @@ -1,5 +1,7 @@ -import filesys.IFileSystem; +import filesys.*; +import java.util.HashMap; +import java.util.Map; import java.util.Scanner; import java.io.FileNotFoundException; @@ -7,15 +9,15 @@ import exception.CaminhoJaExistenteException; import exception.CaminhoNaoEncontradoException; -import filesys.FileSystem; - // MENU INTERATIVO PARA O SISTEMA DE ARQUIVOS // SINTA-SE LIVRE PARA ALTERAR A CLASSE MAIN + public class Main { // Constantes úteis para a versão interativa. // 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; @@ -31,15 +33,16 @@ public class Main { // 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. + public static void main(String[] args) { // Usuário que está executando o programa. // Para quaisquer operações que serão feitas por esse usuário em um caminho /path/**, // deve-se checar se o usuário tem permissão de escrita (r) neste caminho. - if (args.length < 2) { + if (args.length < 1) { System.out.println("Usuário não fornecido"); return; } - user = args[1]; + user = args[0]; // Carrega a lista de usuários do sistema a partir de arquivo // Formato do arquivo users: @@ -51,6 +54,9 @@ public static void main(String[] args) { // A partir do momento que um usuário cria outro diretório ou arquivo, // a permissão desse usuário é de leitura, escrita e execução nesse novo diretório/arquivo, // e sempre será rwx para o usuário root. + + Map> permissoes = new HashMap<>(); + try { Scanner userScanner = new Scanner(new java.io.File("users/users")); while (userScanner.hasNextLine()) { @@ -61,11 +67,20 @@ public static void main(String[] args) { String userListed = parts[0]; String dir = parts[1]; String dirPermission = parts[2]; + + // Ajuste aqui: + if (dir.equals("/**")) { + dir = "/"; + } /* 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. */ + + permissoes.putIfAbsent(dir, new HashMap<>()); + permissoes.get(dir).put(userListed, dirPermission); + System.out.println(userListed + " " + dir + " " + dirPermission); // Somente imprime o usuário, diretório e permissão @@ -80,19 +95,30 @@ public static void main(String[] args) { return; } + + // Verifica se o usuário existe em alguma permissão, exceto root + boolean usuarioExiste = user.equals(ROOT_USER) || permissoes.values().stream() + .anyMatch(mapUserPerm -> mapUserPerm.containsKey(user)); + + if (!usuarioExiste) { + System.out.println("Usuário não fornecido ou inexistente."); + return; + } + // Usuário Importante // Finalmente cria o Sistema de Arquivos // Lista de usuários é imutável durante a execução do programa // Obs: Como passar a lista de usuários para o FileSystem? - fileSystem = new FileSystem(/*usuários?*/); + fileSystem = new FileSystem(permissoes); // passar o mapa de permissoes ao criar 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()); - // } + try { + // Cria diretório raiz com permissão total para root + fileSystem.mkdir(ROOT_DIR, ROOT_USER); + } catch (CaminhoJaExistenteException | PermissaoException e) { + System.out.println(e.getMessage()); + } // Menu interativo. menu(); @@ -101,6 +127,7 @@ public static void main(String[] args) { // Menu interativo para fins de teste. // Os testes junit não são feitos com esse menu, // mas diretamente na interface IFileSystem + public static void menu() { while (true) { System.out.println("\nComandos disponíveis:"); @@ -246,4 +273,5 @@ public static void cp() throws CaminhoNaoEncontradoException, PermissaoException fileSystem.cp(caminhoOrigem, caminhoDestino, user, recursivo); } + } diff --git a/Makefile b/Makefile index fb358c4..52b1d2d 100644 --- a/Makefile +++ b/Makefile @@ -28,7 +28,7 @@ clean: # Run the application with a username run: compile - $(JAVA) -cp $(BIN_DIR) $(MAIN_CLASS) -u $(USERNAME) + $(JAVA) -cp $(BIN_DIR) $(MAIN_CLASS) $(USERNAME) # Help target help: diff --git a/bin/Main.class b/bin/Main.class new file mode 100644 index 0000000..c169e70 Binary files /dev/null and b/bin/Main.class differ diff --git a/bin/exception/CaminhoJaExistenteException.class b/bin/exception/CaminhoJaExistenteException.class new file mode 100644 index 0000000..b6074d1 Binary files /dev/null and b/bin/exception/CaminhoJaExistenteException.class differ diff --git a/bin/exception/CaminhoNaoEncontradoException.class b/bin/exception/CaminhoNaoEncontradoException.class new file mode 100644 index 0000000..e8bda4e Binary files /dev/null and b/bin/exception/CaminhoNaoEncontradoException.class differ diff --git a/bin/exception/PermissaoException.class b/bin/exception/PermissaoException.class new file mode 100644 index 0000000..fbdeaf1 Binary files /dev/null and b/bin/exception/PermissaoException.class differ diff --git a/bin/filesys/FileSystem.class b/bin/filesys/FileSystem.class new file mode 100644 index 0000000..06ef633 Binary files /dev/null and b/bin/filesys/FileSystem.class differ diff --git a/bin/filesys/FileSystemImpl.class b/bin/filesys/FileSystemImpl.class new file mode 100644 index 0000000..c0f2d61 Binary files /dev/null and b/bin/filesys/FileSystemImpl.class differ diff --git a/bin/filesys/IFileSystem.class b/bin/filesys/IFileSystem.class new file mode 100644 index 0000000..fe05c0b Binary files /dev/null and b/bin/filesys/IFileSystem.class differ diff --git a/exception/CaminhoJaExistenteException.java b/exception/CaminhoJaExistenteException.java index dd96126..5e593ce 100644 --- a/exception/CaminhoJaExistenteException.java +++ b/exception/CaminhoJaExistenteException.java @@ -3,7 +3,9 @@ import java.io.IOException; public class CaminhoJaExistenteException extends IOException { + public CaminhoJaExistenteException(String message) { super(message); } + } diff --git a/exception/CaminhoNaoEncontradoException.java b/exception/CaminhoNaoEncontradoException.java index 28b60a3..8da8917 100644 --- a/exception/CaminhoNaoEncontradoException.java +++ b/exception/CaminhoNaoEncontradoException.java @@ -1,7 +1,9 @@ package exception; public class CaminhoNaoEncontradoException extends Exception { + public CaminhoNaoEncontradoException(String message) { super(message); } + } diff --git a/exception/PermissaoException.java b/exception/PermissaoException.java index f8800c1..3f09317 100644 --- a/exception/PermissaoException.java +++ b/exception/PermissaoException.java @@ -1,7 +1,9 @@ package exception; public class PermissaoException extends Exception { + public PermissaoException(String message) { super(message); } + } \ No newline at end of file diff --git a/filesys/FileSystem.java b/filesys/FileSystem.java index 8d7a83b..1c1f769 100644 --- a/filesys/FileSystem.java +++ b/filesys/FileSystem.java @@ -1,16 +1,32 @@ package filesys; +import java.util.Map; + import exception.CaminhoJaExistenteException; import exception.CaminhoNaoEncontradoException; import exception.PermissaoException; // Essa classe deve servir apenas como proxy para o FileSystemImpl + final public class FileSystem implements IFileSystem { private final IFileSystem fileSystemImpl; + // Implementação + + public FileSystem(Map> permissoes) { + this.fileSystemImpl = new FileSystemImpl(permissoes); + } + public FileSystem() { - fileSystemImpl = new FileSystemImpl(); + this.fileSystemImpl = new FileSystemImpl(); + } + + // Função de add Usuário + public void addUser(String usuario) { + if (fileSystemImpl instanceof FileSystemImpl fsImpl) { + fsImpl.addUser(usuario); + } } @Override @@ -64,4 +80,5 @@ public void cp(String caminhoOrigem, String caminhoDestino, String usuario, bool throws CaminhoNaoEncontradoException, PermissaoException { fileSystemImpl.cp(caminhoOrigem, caminhoDestino, usuario, recursivo); } + } \ No newline at end of file diff --git a/filesys/FileSystemImpl.java b/filesys/FileSystemImpl.java index 45fa05d..62066e7 100644 --- a/filesys/FileSystemImpl.java +++ b/filesys/FileSystemImpl.java @@ -1,5 +1,13 @@ package filesys; +import java.util.Set; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; + import exception.CaminhoJaExistenteException; import exception.CaminhoNaoEncontradoException; import exception.PermissaoException; @@ -8,63 +16,520 @@ // 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_DIR = "/"; // diretório raiz - public FileSystemImpl() {} + public Map> permissoes; - @Override - public void mkdir(String caminho, String nome) throws CaminhoJaExistenteException, PermissaoException { - throw new UnsupportedOperationException("Método não implementado 'mkdir'"); + // Função para adicionar meu usuário + private final Set usuarios = new HashSet<>(); + + // Guarda se é arquivo ou diretório + private Map isArquivo; + + // Guarda conteúdo dos arquivos + private Map conteudoArquivos; + + //public FileSystemImpl(Map> permissoes) { + //this.permissoes = permissoes; + // Inicialização dos diretórios, arquivos, etc. + //} + + public FileSystemImpl(Map> permissoes) { + this.permissoes = permissoes; + this.isArquivo = new HashMap<>(); + this.conteudoArquivos = new HashMap<>(); + + // Preenche usuários a partir das chaves do mapa permissoes + if (permissoes != null) { + for (Map usuariosPerms : permissoes.values()) { + for (String usuario : usuariosPerms.keySet()) { + if (usuario != null && !usuario.trim().isEmpty()) { + this.usuarios.add(usuario); + } + } + } + } + + // Garante que root existe e tem permissão total para raiz + if (!usuarios.contains(ROOT_USER)) { + usuarios.add(ROOT_USER); + } + + permissoes.putIfAbsent(ROOT_DIR, new HashMap<>()); + permissoes.get(ROOT_DIR).put(ROOT_USER, "rwx"); + isArquivo.put(ROOT_DIR, false); // raiz é diretório +} + + public FileSystemImpl() { + + this.permissoes = new HashMap<>(); + this.isArquivo = new HashMap<>(); + this.conteudoArquivos = new HashMap<>(); + + // Inicialização de diretórios, etc. + + // Adicionador root como usuário + addUser(ROOT_USER); + + // Inicializar raiz com permissão total para root + Map rootPerms = new HashMap<>(); + rootPerms.put(ROOT_USER, "rwx"); + permissoes.put("/", rootPerms); + isArquivo.put("/", false); // raiz é diretório + + } + + // Função para adicionar meu usuário + + public void addUser(String usuario) { + if (usuario != null && !usuario.trim().isEmpty()) { + usuarios.add(usuario); + } + } + + + private boolean usuarioExiste(String usuario) { + return usuarios.contains(usuario); + } + + // Getter às permissões + public Map> getPermissoes() { + return permissoes; + } + + // Listar os usuários + public Set getUsuarios() { + return Collections.unmodifiableSet(usuarios); } + private boolean temPermissao(String caminho, String usuario, char tipoPermissao) { + if (ROOT_USER.equals(usuario)) return true; + + // Caminho atual (parte mais específica) + String caminhoAtual = caminho; + + while (caminhoAtual != null && !caminhoAtual.isEmpty()) { + Map mapUsuarioPerm = permissoes.get(caminhoAtual); + if (mapUsuarioPerm != null && mapUsuarioPerm.containsKey(usuario)) { + String perm = mapUsuarioPerm.get(usuario); + return perm.indexOf(tipoPermissao) != -1; + } + + // Se chegou na raiz, para + if (caminhoAtual.equals("/")) break; + + // Sobe um nível no caminho + int lastSlash = caminhoAtual.lastIndexOf('/'); + caminhoAtual = lastSlash > 0 ? caminhoAtual.substring(0, lastSlash) : "/"; + } + + // Se não encontrou permissão exata, procura se tem permissão de /** no "/" + Map raizPerms = permissoes.get("/"); + if (raizPerms != null && raizPerms.containsKey(usuario)) { + String perm = raizPerms.get(usuario); + return perm.indexOf(tipoPermissao) != -1; + } + + return false; + } + + @Override + public void mkdir(String caminho, String usuario) throws CaminhoJaExistenteException, PermissaoException { + + if (!usuarioExiste(usuario)) { + throw new PermissaoException("Usuário não fornecido ou inexistente."); + } + + if (caminho == null || caminho.isEmpty() || !caminho.startsWith("/")) { + throw new IllegalArgumentException("Caminho inválido."); + } + + if (permissoes.containsKey(caminho)) { + throw new CaminhoJaExistenteException("O diretório já existe: " + caminho); + } + + int lastSlashIndex = caminho.lastIndexOf('/'); + String caminhoPai = (lastSlashIndex == 0) ? "/" : caminho.substring(0, lastSlashIndex); + + if (!permissoes.containsKey(caminhoPai)) { + throw new PermissaoException("Diretório pai inexistente: " + caminhoPai); + } + + Map permsPai = permissoes.get(caminhoPai); + String permUsuario = ROOT_USER.equals(usuario) ? "rwx" : permsPai.get(usuario); + if (permUsuario == null || !permUsuario.contains("w")) { + throw new PermissaoException("Usuário não tem permissão de escrita no diretório pai."); + } + + Map novasPerms = new HashMap<>(); + novasPerms.put(usuario, "rwx"); + novasPerms.put(ROOT_USER, "rwx"); + + permissoes.put(caminho, novasPerms); + isArquivo.put(caminho, false); // <-- ESSENCIAL PARA O MÉTODO rm FUNCIONAR + + System.out.println("Diretório criado com sucesso: " + caminho); +} + @Override public void chmod(String caminho, String usuario, String usuarioAlvo, String permissao) throws CaminhoNaoEncontradoException, PermissaoException { - throw new UnsupportedOperationException("Método não implementado 'chmod'"); + // throw new UnsupportedOperationException("Método não implementado 'chmod'"); + + // Verifica se o caminho existe (permissoes contem o caminho) + if (!permissoes.containsKey(caminho)) { + throw new CaminhoNaoEncontradoException("Caminho não encontrado: " + caminho); + } + + // Verfica se o usuário que está tentando alterar é root ou tem permissão rwx + if (!ROOT_USER.equals(usuario)) { + + Map permissoesDoCaminho = permissoes.get(caminho); + String permUsuario = permissoesDoCaminho.get(usuario); + + if (permUsuario == null || ! permUsuario.startsWith("rw")) { + throw new PermissaoException("Usuário " + usuario + " não tem permissão para alterar permissões em " + caminho); + } + } + + // Verificar se o usuarioAlvo existe + if (!usuarioExiste(usuarioAlvo)) { + throw new PermissaoException("Usuário alvo não existe: " + usuarioAlvo); + } + + // Atualiza a permissão para o usuarioAlvo no caminho + Map permissoesDoCaminho = permissoes.get(caminho); + permissoesDoCaminho.put(usuarioAlvo, permissao); + + // imprimir a mudança de permissão + System.out.println("Permissão para " + usuarioAlvo + " no caminho " + caminho + " alterada para " + permissao); + } @Override - public void rm(String caminho, String usuario, boolean recursivo) - throws CaminhoNaoEncontradoException, PermissaoException { - throw new UnsupportedOperationException("Método não implementado 'rm'"); + public void rm(String caminho, String usuario, boolean recursivo) throws CaminhoNaoEncontradoException, PermissaoException { + if (!usuarioExiste(usuario)) { + throw new PermissaoException("Usuário não fornecido ou inexistente."); + } + + if (!permissoes.containsKey(caminho)) { + throw new CaminhoNaoEncontradoException("Caminho não encontrado: " + caminho); + } + + Map perms = permissoes.get(caminho); + String permUsuario = ROOT_USER.equals(usuario) ? "rwx" : perms.get(usuario); + if (permUsuario == null || !permUsuario.contains("w")) { + throw new PermissaoException("Usuário não tem permissão de escrita para remover: " + caminho); + } + + // Se for diretório e não recursivo, deve falhar se tiver conteúdo + if (!isArquivo.get(caminho) && !recursivo) { + // Verifica se existe algum caminho que começa com esse caminho + "/" + for (String c : permissoes.keySet()) { + if (!c.equals(caminho) && c.startsWith(caminho.endsWith("/") ? caminho : caminho + "/")) { + throw new PermissaoException("Diretório não está vazio e recursivo não foi especificado."); + } + } + } + + // Remove recursivamente todos os caminhos filhos + permissoes.keySet().removeIf(c -> c.equals(caminho) || c.startsWith(caminho.endsWith("/") ? caminho : caminho + "/")); + isArquivo.keySet().removeIf(c -> c.equals(caminho) || c.startsWith(caminho.endsWith("/") ? caminho : caminho + "/")); + conteudoArquivos.keySet().removeIf(c -> c.equals(caminho) || c.startsWith(caminho.endsWith("/") ? caminho : caminho + "/")); + + System.out.println("Removido: " + caminho); } @Override public void touch(String caminho, String usuario) throws CaminhoJaExistenteException, PermissaoException { - throw new UnsupportedOperationException("Método não implementado 'touch'"); + if (!usuarioExiste(usuario)) { + throw new PermissaoException("Usuário não fornecido ou inexistente."); + } + + if (caminho == null || caminho.isEmpty() || !caminho.startsWith("/")) { + throw new IllegalArgumentException("Caminho inválido."); + } + + if (permissoes.containsKey(caminho)) { + throw new CaminhoJaExistenteException("O arquivo já existe: " + caminho); + } + + int lastSlashIndex = caminho.lastIndexOf('/'); + String caminhoPai = (lastSlashIndex == 0) ? "/" : caminho.substring(0, lastSlashIndex); + + if (!permissoes.containsKey(caminhoPai)) { + throw new PermissaoException("Diretório pai inexistente: " + caminhoPai); + } + + Map permsPai = permissoes.get(caminhoPai); + String permUsuario = ROOT_USER.equals(usuario) ? "rwx" : permsPai.get(usuario); + if (permUsuario == null || !permUsuario.contains("w")) { + throw new PermissaoException("Usuário não tem permissão de escrita no diretório pai."); + } + + Map novasPerms = new HashMap<>(); + novasPerms.put(usuario, "rw"); // Para arquivos, geralmente "rw" + novasPerms.put(ROOT_USER, "rw"); + + permissoes.put(caminho, novasPerms); + isArquivo.put(caminho, true); + conteudoArquivos.put(caminho, new byte[0]); // Arquivo vazio + + System.out.println("Arquivo criado com sucesso: " + caminho); } + @Override public void write(String caminho, String usuario, boolean anexar, byte[] buffer) throws CaminhoNaoEncontradoException, PermissaoException { - throw new UnsupportedOperationException("Método não implementado 'write'"); + if (!usuarioExiste(usuario)) { + throw new PermissaoException("Usuário não fornecido ou inexistente."); + } + if (!permissoes.containsKey(caminho)) { + throw new CaminhoNaoEncontradoException("Caminho não encontrado: " + caminho); + } + if (!Boolean.TRUE.equals(isArquivo.get(caminho))) { + throw new PermissaoException("O caminho não é um arquivo: " + caminho); + } + Map perms = permissoes.get(caminho); + String permUsuario = ROOT_USER.equals(usuario) ? "rw" : perms.get(usuario); + if (permUsuario == null || !permUsuario.contains("w")) { + throw new PermissaoException("Usuário não tem permissão para escrever no arquivo: " + caminho); + } + + // Bloco de escrita + final int BLOCK_SIZE = 256; + byte[] conteudoAtual = conteudoArquivos.get(caminho); + ByteArrayOutputStream output = new ByteArrayOutputStream(); + + try { + if (anexar) { + output.write(conteudoAtual); + } + + int offset = 0; + while (offset < buffer.length) { + int blockLen = Math.min(BLOCK_SIZE, buffer.length - offset); + output.write(buffer, offset, blockLen); + offset += blockLen; + } + + conteudoArquivos.put(caminho, output.toByteArray()); + System.out.println("Escrita por blocos concluída: " + caminho); + } catch (IOException e) { + e.printStackTrace(); // Não deve ocorrer em ByteArrayOutputStream + } } @Override public void read(String caminho, String usuario, byte[] buffer) throws CaminhoNaoEncontradoException, PermissaoException { - throw new UnsupportedOperationException("Método não implementado 'read'"); + if (!usuarioExiste(usuario)) { + throw new PermissaoException("Usuário não fornecido ou inexistente."); + } + if (!permissoes.containsKey(caminho)) { + throw new CaminhoNaoEncontradoException("Caminho não encontrado: " + caminho); + } + if (!Boolean.TRUE.equals(isArquivo.get(caminho))) { + throw new PermissaoException("O caminho não é um arquivo: " + caminho); + } + + Map perms = permissoes.get(caminho); + String permUsuario = ROOT_USER.equals(usuario) ? "rw" : perms.get(usuario); + if (permUsuario == null || !permUsuario.contains("r")) { + throw new PermissaoException("Usuário não tem permissão de leitura no arquivo: " + caminho); + } + + byte[] conteudo = conteudoArquivos.get(caminho); + + // Leitura em blocos + final int BLOCK_SIZE = 256; + int offset = 0; + while (offset < conteudo.length && offset < buffer.length) { + int blockLen = Math.min(BLOCK_SIZE, conteudo.length - offset); + System.arraycopy(conteudo, offset, buffer, offset, blockLen); + offset += blockLen; + } + + String conteudoStr = new String(buffer).trim(); + System.out.println("Conteúdo lido por blocos:"); + System.out.println(conteudoStr); } @Override public void mv(String caminhoAntigo, String caminhoNovo, String usuario) throws CaminhoNaoEncontradoException, PermissaoException { - throw new UnsupportedOperationException("Método não implementado 'mv'"); + + if (!usuarioExiste(usuario)) { + throw new PermissaoException("Usuário não fornecido ou inexistente."); + } + if (!permissoes.containsKey(caminhoAntigo)) { + throw new CaminhoNaoEncontradoException("Caminho antigo não encontrado: " + caminhoAntigo); + } + + // Verificar permissão de escrita no diretório pai do caminhoAntigo + int lastSlashOld = caminhoAntigo.lastIndexOf('/'); + String paiAntigo = (lastSlashOld == 0) ? "/" : caminhoAntigo.substring(0, lastSlashOld); + Map permsPaiAntigo = permissoes.get(paiAntigo); + String permUsuarioAntigo = ROOT_USER.equals(usuario) ? "rwx" : permsPaiAntigo.get(usuario); + if (permUsuarioAntigo == null || !permUsuarioAntigo.contains("w")) { + throw new PermissaoException("Usuário não tem permissão de escrita no diretório pai do caminho antigo."); + } + + // Se já existe como destino, não precisa verificar o pai + if (!permissoes.containsKey(caminhoNovo)) { + // Se não existe, verificar o pai + int lastSlashNew = caminhoNovo.lastIndexOf('/'); + String paiNovo = (lastSlashNew == 0) ? "/" : caminhoNovo.substring(0, lastSlashNew); + if (!permissoes.containsKey(paiNovo)) { + throw new PermissaoException("Diretório pai do caminho novo não existe: " + paiNovo); + } + Map permsPaiNovo = permissoes.get(paiNovo); + String permUsuarioNovo = ROOT_USER.equals(usuario) ? "rwx" : permsPaiNovo.get(usuario); + if (permUsuarioNovo == null || !permUsuarioNovo.contains("w")) { + throw new PermissaoException("Usuário não tem permissão de escrita no diretório pai do caminho novo."); + } + } + + // Lista de caminhos que serão movidos (inclui caminhoAntigo e seus filhos) + Set caminhosAMover = new HashSet<>(); + String prefixoAntigo = caminhoAntigo.endsWith("/") ? caminhoAntigo : caminhoAntigo + "/"; + for (String c : permissoes.keySet()) { + if (c.equals(caminhoAntigo) || c.startsWith(prefixoAntigo)) { + caminhosAMover.add(c); + } + } + + // Mover: remover entradas antigas e criar novas com o prefixo atualizado + for (String c : caminhosAMover) { + String novoCaminho = caminhoNovo + c.substring(caminhoAntigo.length()); + + // Permissões + Map p = permissoes.remove(c); + permissoes.put(novoCaminho, p); + + // isArquivo + Boolean isA = isArquivo.remove(c); + isArquivo.put(novoCaminho, isA); + + // Conteúdo arquivos + if (isA) { + byte[] conteudo = conteudoArquivos.remove(c); + conteudoArquivos.put(novoCaminho, conteudo); + } + } } @Override public void ls(String caminho, String usuario, boolean recursivo) throws CaminhoNaoEncontradoException, PermissaoException { - throw new UnsupportedOperationException("Método não implementado 'ls'"); + if (!usuarioExiste(usuario)) { + throw new PermissaoException("Usuário não fornecido ou inexistente."); + } + if (!permissoes.containsKey(caminho)) { + throw new CaminhoNaoEncontradoException("Caminho não encontrado: " + caminho); + } + + // Verifica permissão de leitura + Map perms = permissoes.get(caminho); + String permUsuario = ROOT_USER.equals(usuario) ? "r" : perms.get(usuario); + if (permUsuario == null || !permUsuario.contains("r")) { + throw new PermissaoException("Usuário não tem permissão para listar: " + caminho); + } + + for (String c : permissoes.keySet()) { + if (c.equals(caminho)) continue; + if (c.startsWith(caminho.endsWith("/") ? caminho : caminho + "/")) { + if (!recursivo) { + // Lista só filhos diretos + String restante = c.substring(caminho.length()); + if (restante.startsWith("/")) { + restante = restante.substring(1); + } + if (!restante.contains("/")) { + System.out.println(c); + } + } else { + System.out.println(c); + } + } + } } + @Override public void cp(String caminhoOrigem, String caminhoDestino, String usuario, boolean recursivo) throws CaminhoNaoEncontradoException, PermissaoException { - throw new UnsupportedOperationException("Método não implementado 'cp'"); - } - public void addUser(String user) { - throw new UnsupportedOperationException("Método não implementado 'addUser'"); + if (!usuarioExiste(usuario)) { + throw new PermissaoException("Usuário não fornecido ou inexistente."); + } + if (!permissoes.containsKey(caminhoOrigem)) { + throw new CaminhoNaoEncontradoException("Caminho origem não encontrado: " + caminhoOrigem); + } + + // Verifica permissão leitura no caminhoOrigem + Map permsOrigem = permissoes.get(caminhoOrigem); + String permUsuarioOrigem = ROOT_USER.equals(usuario) ? "rwx" : permsOrigem.get(usuario); + if (permUsuarioOrigem == null || !permUsuarioOrigem.contains("r")) { + throw new PermissaoException("Usuário não tem permissão para ler o caminho origem."); + } + + // Verifica permissão escrita no diretório pai do destino + if (!permissoes.containsKey(caminhoDestino)) { + throw new PermissaoException("Diretório de destino não existe: " + caminhoDestino); + } + Map permsDestino = permissoes.get(caminhoDestino); + String permUsuarioDestino = ROOT_USER.equals(usuario) ? "rwx" : permsDestino.get(usuario); + if (permUsuarioDestino == null || !permUsuarioDestino.contains("w")) { + throw new PermissaoException("Usuário não tem permissão para escrever no destino."); + } + if (permUsuarioDestino == null || !permUsuarioDestino.contains("w")) { + throw new PermissaoException("Usuário não tem permissão para escrever no diretório pai do destino."); + } + + boolean origemArquivo = Boolean.TRUE.equals(isArquivo.get(caminhoOrigem)); + + if (!origemArquivo && !recursivo) { + throw new PermissaoException("Caminho origem e diretório recursivo não foi especificado."); + } + + // Caminhos a copiar (origem + filhos se diretório) + Set caminhosACopiar = new HashSet<>(); + if (origemArquivo) { + caminhosACopiar.add(caminhoOrigem); + } else { + String prefixoOrigem = caminhoOrigem.endsWith("/") ? caminhoOrigem : caminhoOrigem + "/"; + for (String c : permissoes.keySet()) { + if (c.equals(caminhoOrigem) || c.startsWith(prefixoOrigem)) { + caminhosACopiar.add(c); + } + } + } + + for (String c : caminhosACopiar) { + String novoCaminho = caminhoDestino + c.substring(caminhoOrigem.length()); + + // Clonar permissões + Map permsOrig = permissoes.get(c); + Map novaPerms = new HashMap<>(permsOrig); + permissoes.put(novoCaminho, novaPerms); + + // Clonar isArquivo + Boolean isA = isArquivo.get(c); + isArquivo.put(novoCaminho, isA); + + // Clonar conteúdo se arquivo + if (isA) { + byte[] conteudo = conteudoArquivos.get(c); + conteudoArquivos.put(novoCaminho, conteudo.clone()); + } + } } + } + + diff --git a/filesys/IFileSystem.java b/filesys/IFileSystem.java index a0f0ce0..317323f 100644 --- a/filesys/IFileSystem.java +++ b/filesys/IFileSystem.java @@ -44,4 +44,5 @@ public interface IFileSystem { // Copia um arquivo ou diretório. Se o diretório não existir, será lançada uma exceção. void cp(String caminhoOrigem, String caminhoDestino, String usuario, boolean recursivo) throws CaminhoNaoEncontradoException, PermissaoException; + } \ No newline at end of file diff --git a/tests/PermissionTest.java b/tests/PermissionTest.java index 6026e31..2ea0ec3 100644 --- a/tests/PermissionTest.java +++ b/tests/PermissionTest.java @@ -1,26 +1,286 @@ package tests; import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.fail; + +import java.util.HashMap; +import java.util.Map; import org.junit.jupiter.api.Test; + +import exception.CaminhoJaExistenteException; +import exception.CaminhoNaoEncontradoException; +import exception.PermissaoException; + import org.junit.jupiter.api.Assertions.*; import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; import filesys.FileSystemImpl; import filesys.IFileSystem; +import filesys.FileSystem; // Essa classe testa cenários de permissão + public class PermissionTest { - private static IFileSystem fileSystem; - @BeforeAll - public static void setUp() { - fileSystem = new FileSystemImpl(/*args...*/); + private FileSystemImpl fs; + + @BeforeEach + public void setup() { + fs = new FileSystemImpl(); + fs.addUser("alice"); + fs.addUser("bob"); + // Cria estrutura básica para testes + try { + fs.mkdir("/dir", "root"); + fs.touch("/dir/file.txt", "root"); + fs.mkdir("/dir/subdir", "root"); + // Define permissões para os usuários + fs.permissoes.get("/dir").put("alice", "rwx"); + fs.permissoes.get("/dir/file.txt").put("alice", "rw"); + fs.permissoes.get("/dir/subdir").put("alice", "rwx"); + fs.permissoes.get("/dir").put("bob", "r"); + fs.permissoes.get("/dir/file.txt").put("bob", "r"); + } catch (Exception e) { + fail("Setup falhou: " + e.getMessage()); + } + } + + @Test + public void testAddUser_andUsuarioExiste() { + assertTrue(fs.getPermissoes().containsKey("/")); + // Usuário root já existe por padrão + fs.addUser("charlie"); + // Não há método direto para checar usuário, mas mkdir lança PermissaoException para usuário inválido + assertThrows(PermissaoException.class, () -> fs.mkdir("/dirInvalidUser", "invalidUser")); + } + + @Test + public void testMkdirDiretorioPaiNaoExiste() { + Exception ex = assertThrows(PermissaoException.class, () -> fs.mkdir("/noParent/dir", "root")); + assertTrue(ex.getMessage().contains("Diretório pai inexistente")); + } + + @Test + public void testMkdirCaminhoJaExistente() throws Exception { + fs.mkdir("/dirExistente", "root"); + assertThrows(CaminhoJaExistenteException.class, () -> fs.mkdir("/dirExistente", "root")); + } + + @Test + public void testMkdirSemPermissao() { + fs.addUser("carol"); + Exception ex = assertThrows(PermissaoException.class, () -> fs.mkdir("/dir2", "carol")); + assertTrue(ex.getMessage().contains("Usuário não tem permissão de escrita")); + } + + @Test + public void testChmodSucesso() throws Exception { + fs.mkdir("/dirChmod", "root"); + fs.addUser("user1"); + fs.getPermissoes().get("/dirChmod").put("root", "rwx"); + fs.getPermissoes().get("/dirChmod").put("user2", "rw"); + fs.addUser("user2"); + // root pode alterar + fs.chmod("/dirChmod", "root", "user1", "rwx"); + assertEquals("rwx", fs.getPermissoes().get("/dirChmod").get("user1")); + } + + @Test + public void testChmodUsuarioNaoTemPermissao() throws Exception { + fs.mkdir("/dirChmod2", "root"); + fs.addUser("user3"); + fs.getPermissoes().get("/dirChmod2").put("user3", "r"); + fs.addUser("user4"); + Exception ex = assertThrows(PermissaoException.class, () -> fs.chmod("/dirChmod2", "user3", "user4", "rw")); + assertTrue(ex.getMessage().contains("não tem permissão")); + } + + @Test + public void testChmodCaminhoNaoEncontrado() { + assertThrows(CaminhoNaoEncontradoException.class, + () -> fs.chmod("/noExist", "root", "user1", "rw")); + } + + @Test + public void testTouchSucesso() throws Exception { + fs.mkdir("/dirTouch", "root"); + fs.touch("/dirTouch/fileTouch", "root"); + assertTrue(fs.getPermissoes().containsKey("/dirTouch/fileTouch")); + } + + @Test + public void testTouchCaminhoJaExistente() throws Exception { + fs.mkdir("/dirTouch2", "root"); + fs.touch("/dirTouch2/fileTouch2", "root"); + assertThrows(CaminhoJaExistenteException.class, + () -> fs.touch("/dirTouch2/fileTouch2", "root")); + } + + @Test + public void testWriteReadSucesso() throws Exception { + fs.mkdir("/dirWriteRead", "root"); + fs.touch("/dirWriteRead/fileWriteRead", "root"); + byte[] data = "hello".getBytes(); + fs.write("/dirWriteRead/fileWriteRead", "root", false, data); + byte[] buffer = new byte[10]; + fs.read("/dirWriteRead/fileWriteRead", "root", buffer); + String result = new String(buffer, 0, data.length); + assertEquals("hello", result); + } + + @Test + public void testWritePermissaoNegada() throws Exception { + fs.mkdir("/dirWrite2", "root"); + fs.touch("/dirWrite2/fileWrite2", "root"); + fs.addUser("dave"); + Exception ex = assertThrows(PermissaoException.class, () -> fs.write("/dirWrite2/fileWrite2", "dave", false, "data".getBytes())); + assertTrue(ex.getMessage().contains("não tem permissão")); + } + + @Test + public void testReadPermissaoNegada() throws Exception { + fs.mkdir("/dirRead2", "root"); + fs.touch("/dirRead2/fileRead2", "root"); + fs.addUser("eve"); + Exception ex = assertThrows(PermissaoException.class, () -> fs.read("/dirRead2/fileRead2", "eve", new byte[10])); + assertTrue(ex.getMessage().contains("não tem permissão")); + } + + @Test + public void testMvSucesso() throws Exception { + fs.mkdir("/dirMv", "root"); + fs.touch("/dirMv/fileMv", "root"); + fs.mkdir("/dirDest", "root"); + fs.mv("/dirMv/fileMv", "/dirDest/fileMvNew", "root"); + assertFalse(fs.getPermissoes().containsKey("/dirMv/fileMv")); + assertTrue(fs.getPermissoes().containsKey("/dirDest/fileMvNew")); + } + + @Test + public void testMvPermissaoNegada() throws Exception { + fs.mkdir("/dirMv2", "root"); + fs.touch("/dirMv2/fileMv2", "root"); + fs.mkdir("/dirDest2", "root"); + fs.addUser("frank"); + Exception ex = assertThrows(PermissaoException.class, () -> fs.mv("/dirMv2/fileMv2", "/dirDest2/fileMv2New", "frank")); + assertTrue(ex.getMessage().contains("não tem permissão")); + } + + @Test + public void testMvCaminhoAntigoNaoExiste() { + assertThrows(CaminhoNaoEncontradoException.class, + () -> fs.mv("/noOldPath/file", "/someNewPath/file", "root")); + } + + @Test + public void testMvDiretorioPaiNovoNaoExiste() throws Exception { + fs.mkdir("/dirMv3", "root"); + fs.touch("/dirMv3/fileMv3", "root"); + Exception ex = assertThrows(PermissaoException.class, + () -> fs.mv("/dirMv3/fileMv3", "/noParentDir/fileNew", "root")); + assertTrue(ex.getMessage().contains("Diretório pai do caminho novo não existe")); + } + + @Test + public void testLs_SucessoNaoRecursivo() throws Exception { + assertDoesNotThrow(() -> fs.ls("/dir", "alice", false)); + } + + @Test + public void testLs_SucessoRecursivo() throws Exception { + assertDoesNotThrow(() -> fs.ls("/dir", "alice", true)); + } + + @Test + public void testLs_CaminhoNaoEncontrado() { + Exception ex = assertThrows(CaminhoNaoEncontradoException.class, () -> fs.ls("/inexistente", "alice", false)); + assertTrue(ex.getMessage().contains("Caminho não encontrado")); + } + + // ------------------- TESTES CP ------------------- + + @Test + public void testCp_ArquivoSucesso() throws Exception { + fs.cp("/dir/file.txt", "/dir/file_copia.txt", "alice", false); + assertTrue(fs.permissoes.containsKey("/dir/file_copia.txt")); + } + + @Test + public void testCp_CaminhoOrigemNaoEncontrado() { + Exception ex = assertThrows(CaminhoNaoEncontradoException.class, + () -> fs.cp("/dir/inexistente.txt", "/dir/file_copia.txt", "alice", false)); + assertTrue(ex.getMessage().contains("origem não encontrado")); } @Test - public void testPermission() { - // Teste de permissão - assertTrue(true); + public void testCp_SemPermissaoLeituraOrigem() { + fs.permissoes.get("/dir/file.txt").put("bob", ""); // sem permissão leitura + Exception ex = assertThrows(PermissaoException.class, + () -> fs.cp("/dir/file.txt", "/dir/file_copia.txt", "bob", false)); + assertTrue(ex.getMessage().contains("não tem permissão para ler")); } + + @Test + public void testCp_SemPermissaoEscritaDestino() { + fs.permissoes.get("/dir").put("bob", "r"); // só leitura, sem escrita + Exception ex = assertThrows(PermissaoException.class, + () -> fs.cp("/dir/file.txt", "/dir/file_copia.txt", "bob", false)); + assertTrue(ex.getMessage().contains("não tem permissão para escrever")); + } + + @Test + public void testRead_ArquivoSucesso() throws Exception { + byte[] buffer = new byte[10]; + fs.read("/dir/file.txt", "alice", buffer); + // Se não lançar exceção, sucesso + } + + @Test + public void testRead_CaminhoNaoEncontrado() { + byte[] buffer = new byte[10]; + Exception ex = assertThrows(CaminhoNaoEncontradoException.class, + () -> fs.read("/dir/inexistente.txt", "alice", buffer)); + assertTrue(ex.getMessage().contains("não encontrado")); + } + + @Test + public void testRead_CaminhoNaoArquivo() throws Exception { + fs.mkdir("/dir/subdir2", "alice"); + byte[] buffer = new byte[10]; + Exception ex = assertThrows(PermissaoException.class, + () -> fs.read("/dir/subdir2", "alice", buffer)); + assertTrue(ex.getMessage().contains("não é um arquivo")); + } + + @Test + public void testRm_ArquivoSucesso() throws Exception { + fs.touch("/dir/file_para_remover.txt", "alice"); + fs.rm("/dir/file_para_remover.txt", "alice", false); + assertFalse(fs.permissoes.containsKey("/dir/file_para_remover.txt")); + } + + @Test + public void testRm_SemPermissao() throws Exception { + fs.touch("/dir/file_para_remover.txt", "alice"); + fs.permissoes.get("/dir/file_para_remover.txt").put("bob", "r"); // só leitura + Exception ex = assertThrows(PermissaoException.class, + () -> fs.rm("/dir/file_para_remover.txt", "bob", false)); + assertTrue(ex.getMessage().contains("não tem permissão de escrita")); + } + + @Test + public void testRm_CaminhoNaoEncontrado() { + Exception ex = assertThrows(CaminhoNaoEncontradoException.class, + () -> fs.rm("/inexistente", "alice", false)); + assertTrue(ex.getMessage().contains("não encontrado")); + } + } + + diff --git a/users/users b/users/users index 58c2992..d86e641 100644 --- a/users/users +++ b/users/users @@ -4,4 +4,12 @@ joao /** rw- pedro /** rw- tiago /** rw- luzia /** rwx -carla /** r-- \ No newline at end of file +carla /** r-- +diogo /usr/bin/diogo rw- +frieren /usr/bin/frieren rw- +bocchi /home rw- +peep /usr/include/benztruck rwx +platao /boot r-- +gawrgura /usr/bin/gooba rwx +pikachu /tmp rw- +flamengo /usr/bin/arrasca rwx