<file_sep>#include "threads.h"

/*Inicializes a specific lock*/
void lock_init(){
  #ifdef MUTEX
    pthread_mutex_init(&lock,NULL);
    pthread_mutex_init(&lock_commands,NULL);    
  #elif RWLOCK
    pthread_rwlock_init(&rwlock,NULL);
    pthread_rwlock_init(&rwlock_commands,NULL);
  #endif
}

/*Destroys a specific lock*/
void lock_destroy(){
  #ifdef MUTEX
    pthread_mutex_destroy(&lock);
    pthread_mutex_destroy(&lock_commands);
  #elif RWLOCK
    pthread_rwlock_destroy(&rwlock);
    pthread_rwlock_destroy(&rwlock_commands);
  #endif
}

/* Lock_function chooses between using Mutex_lock
or Rw/Wrlock depending on the executable */
void lock_function(int i, pthread_mutex_t mutex, pthread_rwlock_t rw){
	#ifdef MUTEX
		pthread_mutex_lock(&mutex);
	#elif RWLOCK
		if (i)	/*If it's !=0, than it locks for write*/
			pthread_rwlock_wrlock(&rw);
		else 	/*else, it locks for reading*/
			pthread_rwlock_rdlock(&rw);
	#endif
}

/* unlock_function chooses between using Mutex_unlock
or Rwlock_unlock depending on the executable */
void unlock_function(pthread_mutex_t mutex, pthread_rwlock_t rw){
	#ifdef MUTEX
		pthread_mutex_unlock(&mutex);
	#elif RWLOCK
		pthread_rwlock_unlock(&rw);
	#endif
}
<file_sep># Makefile, versao 1
# Sistemas Operativos, DEI/IST/ULisboa 2019-20

SOURCES = main.c fs.c sync.c
SOURCES+= lib/bst.c
OBJS_NOSYNC = $(SOURCES:%.c=%.o)
OBJS_MUTEX  = $(SOURCES:%.c=%-mutex.o)
OBJS_RWLOCK = $(SOURCES:%.c=%-rwlock.o)
OBJS = $(OBJS_NOSYNC) $(OBJS_MUTEX) $(OBJS_RWLOCK)
CC   = gcc
LD   = gcc
CFLAGS =-Wall -std=gnu99 -I../ -g
LDFLAGS=-lm -pthread
TARGETS = tecnicofs-nosync tecnicofs-mutex tecnicofs-rwlock

.PHONY: all clean

all: $(TARGETS)

$(TARGETS):
	$(LD) $(CFLAGS) $^ -o $@ $(LDFLAGS)


### no sync ###
lib/bst.o: lib/bst.c lib/bst.h
fs.o: fs.c fs.h lib/bst.h
the.o: threads.c threads.h
main.o: main.c fs.h lib/bst.h threads.h
tecnicofs-nosync: lib/bst.o fs.o the.o main.o

### MUTEX ###
lib/bst-mutex.o: CFLAGS+=-DMUTEX
lib/bst-mutex.o: lib/bst.c lib/bst.h

fs-mutex.o: CFLAGS+=-DMUTEX
fs-mutex.o: fs.c fs.h lib/bst.h

the-mutex.o: CFLAGS+=-DMUTEX
the-mutex.o: threads.c threads.h

main-mutex.o: CFLAGS+=-DMUTEX
main-mutex.o: main.c fs.h lib/bst.h threads.h
tecnicofs-mutex: lib/bst-mutex.o fs-mutex.o the-mutex.o main-mutex.o

### RWLOCK ###
lib/bst-rwlock.o: CFLAGS+=-DRWLOCK
lib/bst-rwlock.o: lib/bst.c lib/bst.h

fs-rwlock.o: CFLAGS+=-DRWLOCK
fs-rwlock.o: fs.c fs.h lib/bst.h

the-rwlock.o: CFLAGS+=-DRWLOCK
the-rwlock.o: threads.c threads.h

main-rwlock.o: CFLAGS+=-DRWLOCK
main-rwlock.o: main.c fs.h lib/bst.h threads.h
tecnicofs-rwlock: lib/bst-rwlock.o fs-rwlock.o the-rwlock.o main-rwlock.o


%.o:
	$(CC) $(CFLAGS) -c -o $@ $<

clean:
	@echo Cleaning...
	rm -f $(OBJS) $(TARGETS)
<file_sep>﻿# Projeto SO
>VERIFICAR SE FICHEIRO ESTA ABERTO PARA QUE

## Open
```
Lista para cada sessao de inodes (Max:5)
```
Erros:
+ Verificar se existe o ficheiro (lockup)
+ Verificar se há posições na qual conseguimos escrever
+ ...

## Write
```
Escrever no inode o conteudo do buffer
```
Erros:
+ Verificar se existe o ficheiro (lockup)
+ Verificar se o ficheiro tá aberto na tabela ou se está na Tabela
+ ...

## Read
```
Ler no inode o conteudo do buffer
```
Erros:
+ Verificar se existe o ficheiro (lockup)
+ Verificar se o ficheiro tá aberto na tabela ou se está na Tabela
+ ...

## Close
```
Retirar elemento da lista
```
Erros:
+ Verificar se existe o ficheiro (lockup)
+ Verificar se o ficheiro tá aberto na tabela ou se está na Tabela
+ ...


# Perguntas
+ No servidor utilizar mutexes ou rwlocks?
+ 


----
# O que falta
+ Meter locks em tudo o que falta

+ Ver qual o free que me falta


+ pthread_signal

+ Ver multiplos clientes, clientes iguais da erro de sessao repetida...

<file_sep>#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>

#define UNIXSTR_PATH "/tmp/s.unixstr"
#define UNIXDG_PATH "/tmp/s.unixdgx"
#define UNIXDG_TMP "/tmp/dgXXXXXXX"



int mount(int argc , char *argv[]){
  struct sockaddr_un serv_addr, cli_addr;
	int sockfd;

  if ((sockfd = socket(AF_UNIX,SOCK_STREAM,0) ) < 0)
    puts("server: can't open stream socket");

  bzero((char *) &serv_addr, sizeof(serv_addr));

  serv_addr.sun_family = AF_UNIX;
  strcpy(serv_addr.sun_path, argv[1]);

  int servlen = strlen(serv_addr.sun_path) + sizeof(serv_addr.sun_family);

	if(connect(sockfd, (struct sockaddr *) &serv_addr, servlen) < 0)
		puts("client: can't connect to server");
		
	char buf[10];
	
	read(STDIN_FILENO, buf, sizeof(buf));
  write(sockfd, buf, sizeof(buf));
  return 0;
}



int main(int argc , char *argv[]){
	mount(argc,argv);
	return 0;
}
<file_sep>/**
 * Sistemas Operativos, DEI/IST/ULisboa 2019-20
 * Modified by <NAME> Nelson, group 22
 */
#include "fs.h"
#include "lib/bst.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "sync.h"


tecnicofs* new_tecnicofs(int max){
	tecnicofs*fs = malloc(sizeof(tecnicofs));
	if (!fs) {
		perror("failed to allocate tecnicofs");
		exit(EXIT_FAILURE);
	}
	fs->hashMax=max;
	fs->nextINumber = 0;
	fs->bstRoot = (node **) malloc(sizeof(node)*max);
	fs->bstLock = (syncMech *) malloc(sizeof(syncMech)*max);
	for (int i=0;i < max;i++){
		fs->bstRoot[i] = NULL;
		sync_init(&(fs->bstLock[i]));
	}
	return fs;
}

void free_tecnicofs(tecnicofs* fs){
	for (int i=0;i < fs->hashMax;i++){
		free_tree(fs->bstRoot[i]);
		sync_destroy(&(fs->bstLock[i]));
	}
	free(fs->bstRoot);
	free(fs->bstLock);
	free(fs);
}

void create(tecnicofs* fs, char *name, int inumber, int flag){	/* if flag==0 then it locks*/
	int hashcode=hash(name,fs->hashMax);
	if (!flag) sync_wrlock(&(fs->bstLock[hashcode]));
	fs->bstRoot[hashcode] = insert(fs->bstRoot[hashcode], name, inumber);
	if (!flag) sync_unlock(&(fs->bstLock[hashcode]));
}

void delete(tecnicofs* fs, char *name, int flag){ /* if flag==0 then it locks*/
	int hashcode=hash(name,fs->hashMax);
	if (!flag) sync_wrlock(&(fs->bstLock[hashcode]));
	fs->bstRoot[hashcode] = remove_item(fs->bstRoot[hashcode], name);
	if (!flag) sync_unlock(&(fs->bstLock[hashcode]));
}

int lookup(tecnicofs* fs, char *name){
	int hashcode=hash(name,fs->hashMax);
	sync_rdlock(&(fs->bstLock[hashcode]));
	int inumber = -1;
	node* searchNode = search(fs->bstRoot[hashcode], name);
	if ( searchNode ) {
		inumber = searchNode->inumber;
	}
	sync_unlock(&(fs->bstLock[hashcode]));
	return inumber;
}

void renameFile(char* oldName,char* newName,tecnicofs *fs) {
	int locknew = hash(newName,fs->hashMax);
	int lockold = hash(oldName, fs->hashMax);

	int	iNumberOld = lookup(fs,oldName);
	int iNumberNew = lookup(fs,newName);

	if (iNumberNew==-1){
		if(iNumberOld!=-1){
			if (locknew==lockold){
				sync_wrlock(&(fs->bstLock[locknew]));
				delete(fs,oldName,1);
				create(fs,newName,iNumberOld,1);
				sync_unlock(&(fs->bstLock[locknew]));
				return;
			}	
			else
				while(1){
					sync_wrlock(&(fs->bstLock[lockold]));
					int err = syncMech_try_lock(&(fs->bstLock[locknew]));
					if (!err){
						delete(fs,oldName,1);
						create(fs,newName,iNumberOld,1);
						sync_unlock(&(fs->bstLock[locknew]));
						sync_unlock(&(fs->bstLock[lockold]));
						return;
					}
					sync_unlock(&(fs->bstLock[lockold]));
				}
			}
		else {printf("%s doesn't existes!\n",oldName);return;} //Erro de nao existir
		}
	else {printf("%s already existes!\n",newName);return;} //Erro de ja existir			
}

void print_tecnicofs_tree(FILE * fp, tecnicofs *fs){
	for (int i=0; i < fs->hashMax ;i++)
		if (fs->bstRoot[i]!=NULL)
			print_tree(fp, fs->bstRoot[i]);
}
<file_sep>#!/bin/bash
#Modified by <NAME> Nelson, group 22

#Checks if there are 4 elements after the executable
if [ ! $# -eq 4 ];then
	echo "Wrong format!"
	echo "Correct form: ./runTests.sh inputFolder outputFolder numThreads numHash"
	exit 1
fi

#Inputs
inputdir=$1
outputdir=$2
maxthreads=$3
numbuckets=$4

#Scrpit
if [ ! -d "tecnicofs-*" ]; then
	make all | grep !""
fi

mkdir -p $2


for inputFile in "$inputdir"/*
do
	echo "InputFile = ​${inputFile/"$inputdir/"/""}" "NumThreads = 1"
	auxFile=${inputFile/"$inputdir"/$outputdir}
	auxFile=${auxFile%.*}
	outFile="$auxFile-1.txt"
	./tecnicofs-nosync $inputFile $outFile 1 1 | grep "TecnicoFS completed in"

	for thread in $(seq 2 $maxthreads)
	do
		echo "InputFile =​ ${inputFile/"$inputdir/"/""}" "NumThreads = $thread"
		auxFile=${inputFile/"$inputdir"/$outputdir}
		auxFile=${auxFile%.*}
		outFile="$auxFile-$thread.txt"
		./tecnicofs-mutex $inputFile $outFile $thread $numbuckets | grep "TecnicoFS completed in"
	done

done

#make clean | grep !""
exit 0
<file_sep>/*
  First Project for Operating systems.
  Modified by <NAME> and <NAME>,
  ist191593 and ist193743, Group 22.
*/ 
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <string.h>
#include <ctype.h>
#include <sys/time.h>
#include "threads.h"

#define MAX_COMMANDS 150000
#define MAX_INPUT_SIZE 100

int numberThreads = 0;
tecnicofs* fs;

char inputCommands[MAX_COMMANDS][MAX_INPUT_SIZE];
int numberCommands = 0;
int headQueue = 0;

static void displayUsage (const char* appName){
  printf("Usage: %s\n", appName);
  exit(EXIT_FAILURE);
}

static void parseArgs (long argc, char* const argv[]){
  if (argc != 4) {
    fprintf(stderr, "Invalid format:\n");
    displayUsage(argv[0]);
  }
  if (argv[3] <= 0){
    fprintf(stderr, "Invalid number of threats:\n");
    exit(EXIT_FAILURE);
  }
}

int insertCommand(char* data) {
  if(numberCommands != MAX_COMMANDS) {
    strcpy(inputCommands[numberCommands++], data);
    return 1;
  }
  return 0;
}

char* removeCommand() {
  lock_function(1,lock_commands, rwlock_commands);
  if(numberCommands > 0){
    numberCommands--;
    unlock_function(lock_commands, rwlock_commands);
    return inputCommands[headQueue++];
  }
  unlock_function(lock_commands, rwlock_commands);
  return NULL;
}

void errorParse(){
  fprintf(stderr, "Error: command invalid\n");
  //exit(EXIT_FAILURE);
}

void processInput(char* f_in){
  FILE *fin = fopen(f_in, "r");
  if (fin==NULL){
    fprintf(stderr, "Error: Not existing input file\n");
    exit(EXIT_FAILURE);
  }
  char line[MAX_INPUT_SIZE];

  while (fgets(line, sizeof(line)/sizeof(char), fin)) {
    char token;
    char name[MAX_INPUT_SIZE];

    int numTokens = sscanf(line, "%c %s", &token, name);

    /* perform minimal validation */
    if (numTokens < 1) {
      continue;
    }
    switch (token) {
      case 'c':
      case 'l':
      case 'd':
        if(numTokens != 2)
          errorParse();
        if(insertCommand(line))
          break;
        return;
      case '#':
        break;
      default: { /* error */
        errorParse();
      }
    }
  }
  fclose(fin);
}

void* applyCommands(void *args){
  while(numberCommands > 0){
    const char* command = removeCommand();
    if (command == NULL){
      continue;
    }
    
    char token;
    char name[MAX_INPUT_SIZE];
    int numTokens = sscanf(command, "%c %s", &token, name);
    if (numTokens != 2) {
      fprintf(stderr, "Error: invalid command in Queue\n");
      exit(EXIT_FAILURE);
    }

    int searchResult;
    int iNumber;
    switch (token) {
      case 'c':
        iNumber = obtainNewInumber(fs);
        create(fs, name, iNumber);
        break;
      case 'l':
        searchResult = lookup(fs, name);
        if(!searchResult)
          printf("%s not found\n", name);
        else
          printf("%s found with inumber %d\n", name, searchResult);
        break;
      case 'd':
        delete(fs, name);
        break;
      default: { /* error */
        fprintf(stderr, "Error: command to apply\n");
        exit(EXIT_FAILURE);
      }
    }
  }
  return NULL;
}

void apply_command_main(int maxThreads){
    #if defined(MUTEX) || defined(RWLOCK)
      for (int i=0;i<maxThreads;i++)
        if (!pthread_create(&tid[i],NULL,applyCommands,NULL))
          fprintf(stderr, "Error: pthread_create failed to execute\n");
      for (int i=0;i<maxThreads;i++)
        if (!pthread_join(tid[i],NULL))
          fprintf(stderr, "Error: pthread_join failed to execute\n");
    #else
      applyCommands(NULL);
    #endif
}

int main(int argc, char* argv[]) {
  parseArgs(argc, argv);
  FILE *fout;
  double time_taken=0;
  struct timeval start, end;
  
  lock_init();
  fs = new_tecnicofs();
  processInput(argv[1]);

  gettimeofday(&start, NULL); /*Start clock*/
  apply_command_main(atoi(argv[3]));
  gettimeofday(&end, NULL);   /*Ends clock*/
  fout = fopen(argv[2],"w");
  print_tecnicofs_tree(fout, fs);

  fclose(fout);
  lock_destroy();
  free_tecnicofs(fs);

  /*Execution Time*/
  time_taken = (end.tv_sec - start.tv_sec) * 1e6; /*Seconds*/
  time_taken += (end.tv_usec - start.tv_usec) * 1e-6; /*Micro-Seconds*/
  printf("TecnicoFS completed in %.04f seconds.\n", time_taken);
  exit(EXIT_SUCCESS);
}
<file_sep>#!/bin/bash
echo Nesta aula vamos aprender a
echo desenvolver os nossos primeiros scripts em bash!
<file_sep>#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>

#define UNIXSTR_PATH "/tmp/s.unixstr"
#define UNIXDG_PATH "/tmp/s.unixdgx"
#define UNIXDG_TMP "/tmp/dgXXXXXXX"



int main(int argc , char *argv[]){
  struct sockaddr_un serv_addr, cli_addr;
	int sockfd;
	FILE* fout=fopen(argv[2],"w");
	sockfd = socket(AF_UNIX,SOCK_STREAM,0);
  if (sockfd < 0)
    puts("server: can't open stream socket");
    
	unlink(argv[1]);
  bzero((char *)&serv_addr, sizeof(serv_addr));

  serv_addr.sun_family = AF_UNIX;
  strcpy(serv_addr.sun_path, argv[1]);
  int servlen = strlen(serv_addr.sun_path) + sizeof(serv_addr.sun_family);
  
  if (bind(sockfd, (struct sockaddr *) &serv_addr, servlen) < 0)
    puts("server, can't bind local address");
  listen(sockfd, 5);
  int len=sizeof(cli_addr);
		puts("Waiting..");
  int newsockfd = accept(sockfd,(struct sockaddr *) &serv_addr, &len);
    if (newsockfd < 0) puts("server: accept error");
  
  char recvline[10];
  int n = read(newsockfd, recvline, 10);
  recvline[n]=0;
  
  fputs(recvline, fout);
  fclose(fout);
  
}
<file_sep>if [ $1 -eq 1 ];then 
	echo nosync;
	for i in $(seq 1 $2)
	do
		./tecnicofs-nosync inputs/test1.txt outF 1 1;
		cat outF
		echo ---
	done

elif [ $1 -eq 2 ];then
	echo mutex;
	for i in $(seq 1 $2)
	do
		./tecnicofs-mutex inputs/test1.txt outF 4 4;
		cat outF;
		echo ---
	done
fi

<file_sep>/*
  First Project for Operating systems.
  Modified by <NAME> and <NAME>,
  ist191593 and ist193743, Group 22.
*/ 
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "fs.h"

int obtainNewInumber(tecnicofs* fs) {
	lock_function(1, lock, rwlock);
	int newInumber = ++(fs->nextINumber);
	unlock_function(lock,rwlock);
	return newInumber;
}

tecnicofs* new_tecnicofs(){
	tecnicofs*fs = malloc(sizeof(tecnicofs));
	if (!fs) {
		perror("failed to allocate tecnicofs");
		exit(EXIT_FAILURE);
	}
	fs->bstRoot = NULL;
	fs->nextINumber = 0;
	return fs;
}

void free_tecnicofs(tecnicofs* fs){
	free_tree(fs->bstRoot);
	free(fs);
}

void create(tecnicofs* fs, char *name, int inumber){
	lock_function(1, lock, rwlock);
	fs->bstRoot = insert(fs->bstRoot, name, inumber);
	unlock_function(lock,rwlock);
}

void delete(tecnicofs* fs, char *name){
	lock_function(1, lock, rwlock);
	fs->bstRoot = remove_item(fs->bstRoot, name);
	unlock_function(lock,rwlock);
}

int lookup(tecnicofs* fs, char *name){
	lock_function(0, lock, rwlock);
	node* searchNode = search(fs->bstRoot, name);
	unlock_function(lock,rwlock);
	if ( searchNode ) return searchNode->inumber;
	return 0;
}

void print_tecnicofs_tree(FILE * fp, tecnicofs *fs){
	print_tree(fp, fs->bstRoot);
}
<file_sep>/**
 * Sistemas Operativos, DEI/IST/ULisboa 2019-20
 * Created by <NAME> Nelson, group 22
 */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include "tecnicofs-client-api.h"

int sockfd;

int tfsCreate(char *filename, permission ownerPermissions, permission othersPermissions) {
  char buff[MAX_INPUT]="";
  dprintf(sockfd, "c %s %d", filename, (ownerPermissions*10+othersPermissions));
  read(sockfd,&buff,sizeof(buff));
  return atoi(buff);
}

int tfsDelete(char *filename){
  char buff[MAX_INPUT]="";
  dprintf(sockfd, "d %s", filename);
  read(sockfd,&buff,sizeof(buff));
  return atoi(buff);
}

int tfsRename(char *filenameOld, char *filenameNew){
  char buff[MAX_INPUT]="";
  dprintf(sockfd, "r %s %s", filenameOld, filenameNew);
  read(sockfd,&buff,sizeof(buff));
  return atoi(buff);
}

int tfsOpen(char *filename, permission mode){
  char buff[MAX_INPUT]="";
  dprintf(sockfd, "o %s %d", filename, mode);
  read(sockfd,&buff,sizeof(buff));
  return atoi(buff);
}

int tfsClose(int fd){
  char buff[MAX_INPUT]="";
  dprintf(sockfd, "x %d", fd);
  read(sockfd,&buff,sizeof(buff));
  return atoi(buff);
}

int tfsRead(int fd, char *buffer, int len){
  char buff[MAX_INPUT]="";
  dprintf(sockfd, "l %d %d", fd,len);
  read(sockfd,&buff,sizeof(buff));
  buff[MAX_INPUT]=0;
  sscanf(buff, "%s %d", buffer, &len);
  return len;
}

int tfsWrite(int fd, char *buffer, int len){
  char buff[MAX_INPUT]="";
  dprintf(sockfd, "w %d %s", fd,buffer);
  read(sockfd,&buff,sizeof(buff));
  return atoi(buff);
}

int tfsMount(char * address){
	struct sockaddr_un serv_addr;
	
	sockfd = socket(AF_UNIX,SOCK_STREAM,0);
  if (sockfd < 0)
    puts("server: can't open stream socket");

  bzero((char *) &serv_addr, sizeof(serv_addr));

  serv_addr.sun_family = AF_UNIX;
  strcpy(serv_addr.sun_path, address);
  int servlen = strlen(serv_addr.sun_path) + sizeof(serv_addr.sun_family);

	if(connect(sockfd, (struct sockaddr *) &serv_addr, servlen) < 0){
    puts("client: can't connect to server");
    exit(TECNICOFS_ERROR_CONNECTION_ERROR);
  }
}

int tfsUnmount(){
  dprintf(sockfd, "e");
	close(sockfd);
}
<file_sep># Makefile, versao 1
# Sistemas Operativos, DEI/IST/ULisboa 2019-20

SOURCES = main.c fs.c sync.c
SOURCES+= lib/bst.c lib/hash.c
OBJS_NOSYNC = $(SOURCES:%.c=%.o)
OBJS_MUTEX  = $(SOURCES:%.c=%-mutex.o)
OBJS_RWLOCK = $(SOURCES:%.c=%-rwlock.o)
OBJS = $(OBJS_NOSYNC) $(OBJS_MUTEX) $(OBJS_RWLOCK)
CC   = gcc
LD   = gcc
CFLAGS =-Wall -std=gnu99 -I../ -g
LDFLAGS=-lm -pthread
TARGETS = tecnicofs-nosync tecnicofs-mutex tecnicofs-rwlock

.PHONY: all clean

all: $(TARGETS)

$(TARGETS):
	$(LD) $(CFLAGS) $^ -o $@ $(LDFLAGS)


### no sync ###
lib/bst.o: lib/bst.c lib/bst.h
lib/hash.o: lib/hash.c lib/hash.h
fs.o: fs.c fs.h lib/bst.h
sync.o: sync.c sync.h constants.h
main.o: main.c fs.h lib/bst.h constants.h lib/timer.h sync.h lib/hash.h
tecnicofs-nosync: lib/bst.o fs.o sync.o main.o lib/hash.o

### MUTEX ###
lib/bst-mutex.o: CFLAGS+=-DMUTEX
lib/bst-mutex.o: lib/bst.c lib/bst.h

lib/hash-mutex.o: CFLAGS+=-DMUTEX
lib/hash-mutex.o: lib/hash.c lib/hash.h

fs-mutex.o: CFLAGS+=-DMUTEX
fs-mutex.o: fs.c fs.h lib/bst.h

sync-mutex.o: CFLAGS+=-DMUTEX
sync-mutex.o: sync.c sync.h constants.h

main-mutex.o: CFLAGS+=-DMUTEX
main-mutex.o: main.c fs.h lib/bst.h constants.h lib/timer.h sync.h lib/hash.h
tecnicofs-mutex: lib/bst-mutex.o lib/hash-mutex.o fs-mutex.o sync-mutex.o main-mutex.o 

### RWLOCK ###
lib/bst-rwlock.o: CFLAGS+=-DRWLOCK
lib/bst-rwlock.o: lib/bst.c lib/bst.h

lib/hash-rwlock.o: CFLAGS+=-DRWLOCK
lib/hash-rwlock.o: lib/hash.c lib/hash.h

fs-rwlock.o: CFLAGS+=-DRWLOCK
fs-rwlock.o: fs.c fs.h lib/bst.h

sync-rwlock.o: CFLAGS+=-DRWLOCK
sync-rwlock.o: sync.c sync.h constants.h

main-rwlock.o: CFLAGS+=-DRWLOCK
main-rwlock.o: main.c fs.h lib/bst.h constants.h lib/timer.h sync.h lib/hash.h
tecnicofs-rwlock: lib/bst-rwlock.o lib/hash-rwlock.o fs-rwlock.o sync-rwlock.o main-rwlock.o


%.o:
	$(CC) $(CFLAGS) -c -o $@ $<

clean:
	@echo Cleaning...
	rm -f $(OBJS) $(TARGETS)
<file_sep>void renameFile(char* oldName,char* newName,tecnicofs *fs) {
	int hashNew = hash(newName,fs->hashMax);
	int hashOld = hash(oldName, fs->hashMax);
	while (!lookup(fs,newName)) {
		int iNumber = lookup(fs,oldName);
		if (lookup(fs,oldName)) {
			if (!lookup(fs,newName)) {
				if (hashNew == hashOld) {
					if (!syncMech_try_lock(&(fs->bstLock[hashNew]))) {
						delete(fs,oldName,1);
						create(fs,newName,iNumber,1);
						sync_unlock(&(fs->bstLock[hashNew]));
						return;
					} else {
						sync_unlock(&(fs->bstLock[hashNew]));
					}
				} else {
					if (!syncMech_try_lock(&(fs->bstLock[hashOld]))) {
						delete(fs,oldName,1);
						sync_unlock(&(fs->bstLock[hashOld]));
					}
					if (!syncMech_try_lock(&(fs->bstLock[hashNew]))) {
						create(fs,newName,iNumber,1);
						sync_unlock(&(fs->bstLock[hashNew]));
					}
				}
			}
		}
	}	
	return;
}<file_sep>#!/bin/bash

outdir=out/;

for outFile in "$outdir"/*
do
    echo »» $outFile:
    cat $outFile
    echo
done<file_sep>#include "../tecnicofs-api-constants.h"
#include "../tecnicofs-client-api.h"
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>

int main(int argc, char* argv[]) {
    assert(tfsMount(argv[1]) == 0);
    printf("Test: create file sucess\n");
    assert(tfsCreate("abc", RW, READ) == 0);
    sleep(25);
    assert(tfsUnmount() == 0);
    exit( 0);
}<file_sep>/* Sistemas Operativos, DEI/IST/ULisboa 2019-20 */
/* Modified by <NAME> Nelson, group 22 */
#define _GNU_SOURCE 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/un.h>
#include <pthread.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <signal.h>

#include "fs.h"
#include "sync.h"
#include "constants.h"
#include "lib/timer.h"
#include "lib/inodes.h"



int numBuckets;
char *nomeSocket, *global_outputFile;
int sockfd, newsockfd;

sigset_t set;
tecnicofs *fs;
pthread_t vector_threads[MAX_CLIENTS];


int flag_end=0;
struct ucred ucred;
TIMER_T startTime, stopTime;

struct file {
  int iNumber;
  enum permission mode;
};


static void displayUsage (const char* appName){
    printf("Usage: %s input_filepath output_filepath threads_number\n", appName);
    exit(EXIT_FAILURE);
}

static void parseArgs (long argc, char* const argv[]){
  if (argc != 4) {
      fprintf(stderr, "Invalid format:\n");
      displayUsage(argv[0]);
  }
  nomeSocket = argv[1];
  global_outputFile = argv[2];
  numBuckets = atoi(argv[3]);
  if (!numBuckets) {
      fprintf(stderr, "Invalid number of buckets\n");
      displayUsage(argv[0]);
  }  
}

/**
 *                           
 * * Checks if the permission passed as argument is sufficient
 *                           
 * */
int isPermitted(permission othersPermission, enum permission perm) {
  int ret;
  switch (othersPermission) {
		case 1:
		  if (perm == WRITE || perm == RW) ret = 0;
		  else ret = -1;
		  break;
		case 2:
		  if (perm == READ || perm == RW) ret = 0;
		  else ret = -1;
		  break;
		case 3:
		  ret = 0;
		  break;
		case 0:
		default:
		  ret = -1;
		  break;
  }
  return ret;
}

/*
* Verifies if the user can do the operation desired
*/
int user_allowed(int userid, int fd, struct file *files, enum permission perm) {
  permission ownerPermission;
  permission othersPermission;
  uid_t creatorId;
  
  inode_get(files[fd].iNumber,&creatorId,&ownerPermission,&othersPermission,NULL,0);
  if (isPermitted(perm,files[fd].mode) == 0) {
    if (userid != creatorId) {
      if (isPermitted(othersPermission,perm) == 0) return 0;
    } 
    else if (isPermitted(ownerPermission,files[fd].mode) == 0) return 0;
    return TECNICOFS_ERROR_PERMISSION_DENIED;
  }
  return TECNICOFS_ERROR_INVALID_MODE;
}

int apply_create(uid_t userid, char *buff){
  int iNumber=0;
  int permissions;
  char token,name[MAX_INPUT_SIZE];
  permission ownerPermissions,otherPermissions;

  sscanf(buff, "%s %s %d", &token, name, &permissions);
  if (lookup(fs,name)==-1){
    otherPermissions = permissions%10;
    ownerPermissions = permissions/10;
    iNumber = inode_create(userid,ownerPermissions,otherPermissions);
    
    create(fs, name, iNumber,1);
    return 0;
  }
  return TECNICOFS_ERROR_FILE_ALREADY_EXISTS;
}

int apply_delete(uid_t userid, char *buff){
  uid_t owner;
  int iNumber=0;
  char token,name[MAX_INPUT_SIZE];

  sscanf(buff, "%s %s", &token, name);
  iNumber=lookup(fs,name);

  if (iNumber==-1) return TECNICOFS_ERROR_FILE_NOT_FOUND;

  inode_get(iNumber,&owner,NULL,NULL,NULL,0);
  if(userid==owner){
    inode_delete(iNumber);
    delete(fs, name,0);
    return 0;
  }
  return TECNICOFS_ERROR_PERMISSION_DENIED;
}

int apply_rename(uid_t userid, char *buff){
  uid_t ownerold;
  int iNumberold=0, iNumbernew=0;
  char token,nameold[MAX_INPUT_SIZE], namenew[MAX_INPUT_SIZE];
  permission ownerPermissions,otherPermissions;

  sscanf(buff, "%s %s %s", &token, nameold, namenew);

  iNumberold=lookup(fs,nameold);
  iNumbernew=lookup(fs,namenew);
  if (iNumberold==-1) return TECNICOFS_ERROR_FILE_NOT_FOUND;
  if (iNumbernew!=-1) return TECNICOFS_ERROR_FILE_ALREADY_EXISTS;

  inode_get(iNumberold,&ownerold,&ownerPermissions,&otherPermissions,NULL,0);
  
  if (ownerold==userid){
    renameFile(nameold, namenew, fs);
    return 0;
  } 
  return TECNICOFS_ERROR_PERMISSION_DENIED;
}

int apply_open(uid_t userid, char* buff,struct file *files){
  int iNumber=0;
  uid_t owner;
  char token,name[MAX_INPUT_SIZE];
  enum permission mode, ownerperm,otherperm;

  sscanf(buff, "%s %s %u", &token, name, &mode);
  iNumber = lookup(fs,name);
  if (iNumber == -1) return TECNICOFS_ERROR_FILE_NOT_FOUND;
  
  inode_get(iNumber,&owner,&ownerperm,&otherperm,NULL,0);
  
  for(int i=0; i<5; i++)
    if (files[i].iNumber==iNumber) return TECNICOFS_ERROR_FILE_IS_OPEN;
  
  for(int i=0; i<5; i++)
    if (files[i].iNumber==-1){
      files[i].iNumber=iNumber;
      files[i].mode=mode;
      return i;
    }
  return TECNICOFS_ERROR_MAXED_OPEN_FILES;
}

int apply_close(uid_t userid, char* buff,struct file *files){
  int fileDescriptor=-1;
  char token;
  sscanf(buff, "%s %d",&token, &fileDescriptor);
  
  if (fileDescriptor>5 || fileDescriptor<0) return TECNICOFS_ERROR_OTHER;

  files[fileDescriptor].iNumber=-1;
  files[fileDescriptor].mode=0;
  return 0;
}

int apply_write(uid_t userid, char* buff,struct file *files){
  int len, fd=-1;
  char token,name[MAX_INPUT_SIZE];

  sscanf(buff, "%s %d %s", &token, &fd, name);
  
  if (fd>5 || fd<0) return TECNICOFS_ERROR_FILE_ALREADY_EXISTS;
  if (files[fd].iNumber == -1) return TECNICOFS_ERROR_FILE_NOT_OPEN;

  int rc = user_allowed(userid,fd,files,WRITE);
  if (!rc) {
    len = inode_set(files[fd].iNumber, name, strlen(name));
    return len;
  }
  return rc;
}

int apply_read(int socket, uid_t userid, char* buff,struct file *files){
  char token;
  int len=0, fd=-1;

  sscanf(buff, "%s %d %d", &token, &fd, &len);
  char content[len];
  memset(content, '\0', len);

  if (fd>5 || fd<0){
    dprintf(socket, "%s %d", "e", TECNICOFS_ERROR_FILE_ALREADY_EXISTS);
    return TECNICOFS_ERROR_FILE_ALREADY_EXISTS;
  }
  
  if (files[fd].iNumber == -1) {
    dprintf(socket, "%s %d", "e", TECNICOFS_ERROR_FILE_NOT_OPEN);
    return TECNICOFS_ERROR_FILE_NOT_OPEN;
  }

  int rc=user_allowed(userid,fd,files,READ);
  if (!rc) {
    inode_get(files[fd].iNumber,NULL,NULL,NULL,content,len-1);
    dprintf(socket, "%s %ld", content, strlen(content));
    return len; 
  }
  dprintf(socket, "%s %d", "e", rc);
  return rc;
}

void* applyComands(void *args){
  int userid = *(int*) args;
  struct ucred owner;
  socklen_t len = sizeof(struct ucred);
  getsockopt(userid, SOL_SOCKET, SO_PEERCRED, &owner, &len);

  pthread_sigmask(SIG_BLOCK, &set, NULL);

  char buff[MAX_INPUT_SIZE];
  struct file files[MAX_TABLE_SIZE];
  for (int i=0;i<MAX_TABLE_SIZE;i++){
    files[i].iNumber = -1;
    files[i].mode = 0;
  }

  while(1){
    bzero(buff, MAX_INPUT_SIZE); 
    read(userid, buff, sizeof(buff));
    int n=sizeof(buff);
    buff[n]=0;

    int rc=0;
    
    char token = buff[0];
    switch (token){
      case 'c':
        rc = apply_create(owner.uid, buff);
        dprintf(userid,"%d",rc);
        break;
      case 'd':
        rc = apply_delete(owner.uid, buff);
        dprintf(userid,"%d",rc);
        break;
      case 'r':
        rc = apply_rename(owner.uid, buff);
        dprintf(userid,"%d",rc);
        break;
      case 'o':
        rc = apply_open(owner.uid, buff,files);
        dprintf(userid,"%d",rc);
        break;
      case 'x':
        rc = apply_close(owner.uid, buff, files);
        dprintf(userid,"%d",rc);
        break;
      case 'l':
        rc = apply_read(userid, owner.uid, buff, files);
        break;
      case 'w':
        rc = apply_write(owner.uid, buff, files);
        dprintf(userid,"%d",rc);
        break;
      case 'e':
        return NULL;
    }
  }
  return NULL;
}


int socket_create(){
  int i=0;
  struct sockaddr_un serv_addr, cli_addr;
  
	sockfd = socket(AF_UNIX,SOCK_STREAM,0);
  if (sockfd < 0){
    puts("server: can't open stream socket");
    return TECNICOFS_ERROR_CONNECTION_ERROR;
  }
    
	unlink(nomeSocket);
  bzero((char *)&serv_addr, sizeof(serv_addr));

  serv_addr.sun_family = AF_UNIX;
  strcpy(serv_addr.sun_path, nomeSocket);
  int servlen = strlen(serv_addr.sun_path) + sizeof(serv_addr.sun_family);
  
  if (bind(sockfd, (struct sockaddr *) &serv_addr, servlen) < 0){
    puts("server, can't bind local address");
    return TECNICOFS_ERROR_CONNECTION_ERROR;
  }
  listen(sockfd, 5);
  
  TIMER_READ(startTime);
  for (;;){
    socklen_t len = sizeof(cli_addr);
    if (!flag_end) {
      newsockfd = accept(sockfd,(struct sockaddr *) &cli_addr, &len);
        if (newsockfd < 0) { 
          puts("server: accept error"); 
          return TECNICOFS_ERROR_CONNECTION_ERROR;
        }
      
      if (pthread_create(&vector_threads[i++], NULL, applyComands, &newsockfd) != 0){
        puts("Erro");
        return TECNICOFS_ERROR_CONNECTION_ERROR;
      }
    }
    else return TECNICOFS_ERROR_OTHER;
  }
}


void end_server(){
  FILE*out = fopen(global_outputFile, "w");
  flag_end=-1;
  for(int i=0;i<MAX_CLIENTS;i++)
    pthread_join(vector_threads[i],NULL);

  TIMER_READ(stopTime);
  fprintf(out, "TecnicoFS completed in %.4f seconds.\n", TIMER_DIFF_SECONDS(startTime, stopTime));
  print_tecnicofs_tree(out,fs);

  fflush(out);
  fclose(out);
	unlink(nomeSocket);
  inode_table_destroy();
  free_tecnicofs(fs);
  exit(EXIT_SUCCESS);
}



int main(int argc, char* argv[]) {
  parseArgs(argc,argv);
  signal(SIGINT, end_server);
  sigemptyset(&set);
  sigaddset(&set, SIGINT);
  for(int i=0;i<MAX_CLIENTS;i++) vector_threads[i]=0;

  fs = new_tecnicofs(numBuckets);
  inode_table_init();
  socket_create();
}
<file_sep>#ifndef THREADS_H
#define THREADS_H
#include "fs.h"
#include <pthread.h>    /*For creating threats*/


#define MAX_THREADS 100
/*Global Variables (locks)*/
pthread_t tid[MAX_THREADS];
pthread_mutex_t lock_commands,lock;
pthread_rwlock_t rwlock_commands,rwlock;

void lock_init();
void lock_destroy();
void lock_function(int i, pthread_mutex_t mutex, pthread_rwlock_t rw);
void unlock_function(pthread_mutex_t mutex, pthread_rwlock_t rw);


#endif<file_sep>//Example code: A simple server side code, which echos back the received message.
//Handle multiple socket connections with select and fd_set on Linux
#include <stdio.h>
#include <string.h> //strlen
#include <stdlib.h>
#include <errno.h>
#include <unistd.h> //close
#include <arpa/inet.h> //close
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/time.h> //FD_SET, FD_ISSET, FD_ZERO macros
#define PORT 8080

int main(int argc , char *argv[]){
	int master_socket , addrlen , new_socket , client_socket[30] ,
		max_clients = 30 , activity, i , valread , sd;
	int max_sd;

	fd_set readfds;
	char buffer[1025]; //data buffer of 1K
	struct sockaddr_in address;

	//create a master socket
	master_socket = socket(AF_UNIX, SOCK_STREAM , 0);
	if( master_socket == 0){
		perror("socket failed");
		exit(EXIT_FAILURE);
	}

	//type of socket created
	address.sin_family = AF_INET;
	strcpy(address.sin_addr.s_addr, argv[1]);
	address.sin_port = htons( PORT );

	//bind the socket to localhost port 8888
	if (bind(master_socket, (struct sockaddr *)&address, sizeof(address))<0) {
		perror("bind failed");
		exit(EXIT_FAILURE);
	}

	//try to specify maximum of 5 pending connections for the master socket
	if (listen(master_socket, 5) < 0){
		perror("listen");
		exit(EXIT_FAILURE);
	}

	//accept the incoming connection
	addrlen = sizeof(address);
	puts("Waiting for connections ...");






	while(1){

    FD_ZERO(&readfds);
    FD_SET(master_socket, &readfds);
		max_sd = master_socket;

    for ( i = 0 ; i < max_clients ; i++){
			sd = client_socket[i];
      if(sd > 0) FD_SET( sd , &readfds);
			if(sd > max_sd) max_sd = sd;
		}

		activity = select( max_sd + 1 , &readfds , NULL , NULL , NULL);

		if (FD_ISSET(master_socket, &readfds)){
			if ((new_socket = accept(master_socket,(struct sockaddr *)&address,
        (socklen_t*)&addrlen))<0){
				perror("accept");
				exit(EXIT_FAILURE);
			}

			for (i = 0; i < max_clients; i++)
				if( client_socket[i] == 0 ){
					client_socket[i] = new_socket;
					printf("Adding to list of sockets as %d\n" , i);
					break;
			  }
    }

		for (i = 0; i < max_clients; i++){
			sd = client_socket[i];
			if (FD_ISSET( sd , &readfds)){
				if ((valread = read( sd , buffer, 1024)) == 0){
          buffer[valread] = '\0';
					send(sd , buffer , strlen(buffer) , 0 );
					close( sd );
					client_socket[i] = 0;
				}
		  }
	  }
  }

	return 0;
}
<file_sep>#!/bin/bash
#Criado por <NAME> Matheus

#Checks if there are 4 elements after the executable
if [ ! $# -eq 3 ];then
	echo "Wrong format!";
	echo "Curret: ./runTests.sh inputFolder outputFolder numThreads numHash";
	exit 1;
fi

#Inputs
inputFolder=$1;
outputFolder=$2;
numThreads=$3;

#Scrpit
if [ ! -d "tecnicofs-*" ]; then
	make all | grep !"";
fi

if [ ! -d "$outputFolder" ]; then
	mkdir $2;
fi

for inputFile in "$1"/*
do
	echo "InputFile=​ $inputFile NumThreads= 1"
	./tecnicofs-nosync $inputFile ${inputFile/"inputs"/$2} 1 | grep "TecnicoFS completed in";

	for i in $(seq 2 $numThreads)
	do
		echo "InputFile=​ $inputFile NumThreads= $i"
		auxFile=${inputFile/"inputs"/$2}
		outFile=${auxFile/".txt"/"-$i.txt"}
		./tecnicofs-mutex $inputFile $outFile $i | grep "TecnicoFS completed in";
	done

done

make clean | grep !"";
exit 0;<file_sep>// In main.c

  // In processInput
    case 'r';

  // In applyCommands
    case 'r':
      renameFile(name,hashcode,fs,hashMax);
      break;

// In fs.c
  #include "lib/hash.h"

  void renameFile(char* names,int hashCode,tecnicofs *fs,int hashMax) {
    char *oldName,*newName;
    oldName = malloc(sizeof(char));
    newName = malloc(sizeof(char));
    int iNumber,newHash;
    sscanf(names,"%s %s",oldName,newName);
    iNumber = lookup(fs,oldName,hashCode);
    delete(fs,oldName,hashCode);
    newHash = hash(newName,hashMax);
    create(fs,newName,iNumber,newHash);
    free(oldName);
    free(newName);
}

// In fs.h

  void renameFile(char* names,int hashCode,tecnicofs *fs,int hashMax);
<file_sep># SO_2019-2020
Operating Systems 2019/2020

## Project 1

* [Project](Project_1/docs/projeto-ex1-SO-19-20.pdf)
* [Files](Project_1/)

**Grade:** *13.40* / 20.0

## Project 2

* [Project](Project_2/docs/projeto-ex2-SO-19-20.pdf)
* [Files](Project_2/)

**Grade:** *15.40* / 20.0

## Project 3

* [Project](Project_3/docs/projeto-ex3-SO-19-20.pdf)
* [Files](Project_3/)

**Grade:** *10.35* / 20.0
<file_sep>/* Sistemas Operativos, DEI/IST/ULisboa 2019-20 */
/* Modified by <NAME> Nelson, group 22 */

#ifndef FS_H
#define FS_H
#include "lib/bst.h"
#include "lib/hash.h"
#include "sync.h"

typedef struct tecnicofs {
    node** bstRoot;
    int nextINumber;
    int hashMax;
    syncMech* bstLock;
} tecnicofs;

int obtainNewInumber(tecnicofs* fs);
tecnicofs* new_tecnicofs(int max);
void free_tecnicofs(tecnicofs* fs);
void create(tecnicofs* fs, char *name, int inumber, int flag);
void delete(tecnicofs* fs, char *name, int flag);
int lookup(tecnicofs* fs, char *name);
void renameFile(char* oldName,char* newName,tecnicofs *fs);
void print_tecnicofs_tree(FILE * fp, tecnicofs *fs);

#endif /* FS_H */
<file_sep>#ifndef HASH_H
#define HASH_H

int hash(char* name, int n);

#endif

<file_sep>#include "../tecnicofs-api-constants.h"
#include "../tecnicofs-client-api.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
#include <string.h>

int main(int argc, char* argv[]) {
   int fd = -1;
    char readBuffer[4] = {0};
   assert(tfsMount(argv[1]) == 0);
   assert((fd = tfsOpen("abc", WRITE)) == 0);
   assert(tfsRead(fd,readBuffer,5) == TECNICOFS_ERROR_INVALID_MODE);
   assert(tfsRename("abc","bc") == TECNICOFS_ERROR_PERMISSION_DENIED);
   assert(tfsClose(fd) == 0);
   assert(tfsUnmount()==0);
   exit(0);
}<file_sep>/* Sistemas Operativos, DEI/IST/ULisboa 2019-20 */
/* Modified by <NAME> Nelson, group 22 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include "fs.h"
#include "constants.h"
#include "lib/timer.h"
#include "sync.h"

/*GLOBAL VARIABLES*/
char* global_inputFile = NULL;
char* global_outputFile = NULL;
int hashMax = 0;
int numberThreads = 0;

pthread_mutex_t commandsLock;
tecnicofs* fs;
sem_t sem_prod, sem_cons;

char inputCommands[MAX_COMMANDS][MAX_INPUT_SIZE];
int numberCommands = 0;
int headQueue = 0;
int sleepTime=0;

static void displayUsage (const char* appName){
    printf("Usage: %s input_filepath output_filepath threads_number\n", appName);
    exit(EXIT_FAILURE);
}

static void parseArgs (long argc, char* const argv[]){
    if (argc != 5 && argc!=6) {
        fprintf(stderr, "Invalid format:\n");
        displayUsage(argv[0]);
    }

    global_inputFile = argv[1];
    global_outputFile = argv[2];
    numberThreads = atoi(argv[3]);
    if (!numberThreads) {
        fprintf(stderr, "Invalid number of threads\n");
        displayUsage(argv[0]);
    }
    hashMax=atoi(argv[4]);
    if(!hashMax){
        fprintf(stderr, "Invalid number of Hash Size\n");
        displayUsage(argv[0]);
    }
    
    sleepTime = (argc==6)? atoi(argv[5]): 0;
    
}

int insertCommand(char* data) {
    sem_wait_err(&sem_prod, "Producer");
    mutex_lock(&commandsLock);
    strcpy(inputCommands[(numberCommands++)%MAX_COMMANDS], data);
    mutex_unlock(&commandsLock);
    sem_post_err(&sem_cons, "Consumer");
    return 1;
}

char* removeCommand() {
    return inputCommands[(headQueue++)%MAX_COMMANDS];
}

void errorParse(int lineNumber){
    fprintf(stderr, "Error: line %d invalid\n", lineNumber);
    exit(EXIT_FAILURE);
}

void* processInput(void*agrs){
    FILE* inputFile;
    inputFile = fopen(global_inputFile, "r");
    if(!inputFile){
        fprintf(stderr, "Error: Could not read %s\n", global_inputFile);
        exit(EXIT_FAILURE);
    }
    int lineNumber = 0;
    char line[MAX_INPUT_SIZE];

    while (fgets(line, sizeof(line)/sizeof(char), inputFile)) {
        char token;
        char name[MAX_INPUT_SIZE];
        char name2[MAX_INPUT_SIZE];
        lineNumber++;
        int numTokens = sscanf(line, "%c %s %s", &token, name, name2);

        /* perform minimal validation */
        if (numTokens < 1) { continue; }
        switch (token){
            case 'r':
                if (numTokens != 3) errorParse(lineNumber);
                if(insertCommand(line))
                    break;
            case 'c':
            case 'l':
            case 'd':
                if(numTokens != 2) errorParse(lineNumber);
                if(insertCommand(line))
                    break;
            case '#':
                break;
            default: { /* error */
                errorParse(lineNumber);
            }
        }
    }
    for (int i=0;i<numberThreads;i++)
      insertCommand("e"); //Command e: end a Consumer thread
    fclose(inputFile);
    return NULL;
}

FILE * openOutputFile() {
    FILE *fp;
    fp = fopen(global_outputFile, "w");
    if (fp == NULL) {
        perror("Error opening output file");
        exit(EXIT_FAILURE);
    }
    return fp;
}

void* applyCommands(){
   while(1){
        sem_wait_err(&sem_cons, "Consumer");
        mutex_lock(&commandsLock);
        const char* command = removeCommand();
        char token;
        char name[MAX_INPUT_SIZE],name2[MAX_INPUT_SIZE];
        sscanf(command, "%c %s", &token, name);
        int iNumber;
        switch (token) {
            case 'c':
                iNumber = obtainNewInumber(fs);
                mutex_unlock(&commandsLock);
                sem_post_err(&sem_prod,"Producer");		        
                create(fs, name, iNumber,0);
                break;
            case 'l':
                mutex_unlock(&commandsLock);
                sem_post_err(&sem_prod,"Producer");		        
                int searchResult = lookup(fs, name);
                if(!searchResult)
                    printf("%s not found\n", name);
                else
                    printf("%s found with inumber %d\n", name, searchResult);
                break;
            case 'd':
                mutex_unlock(&commandsLock);
                sem_post_err(&sem_prod,"Producer");		        
                delete(fs, name,0);
                break;
            case 'r':
                sscanf(command, "%c %s %s", &token, name, name2);
                mutex_unlock(&commandsLock);
                sem_post_err(&sem_prod,"Producer");		        
                renameFile(name,name2,fs);
                break;
            case 'e':
                mutex_unlock(&commandsLock);
                //sem_post_err(&sem_prod,"Producer");		        
                return NULL;
                break;
            default: { /* error */
                mutex_unlock(&commandsLock);
                fprintf(stderr, "Error: commands to apply\n");
                exit(EXIT_FAILURE);
            }
        }
    }
    return NULL;
}

void runThreads(FILE* timeFp){
    TIMER_T startTime, stopTime;
    pthread_t producer_th;
    pthread_t* workers = (pthread_t*) malloc((numberThreads) * sizeof(pthread_t));

    TIMER_READ(startTime);

    if (pthread_create(&producer_th, NULL, processInput, NULL)!= 0){
        perror("Can't create thread: Producer");
        exit(EXIT_FAILURE);
    }

    for(int i = 0; i < numberThreads; i++){
        if (pthread_create(&workers[i], NULL, applyCommands, NULL)!= 0){
            perror("Can't create thread: Consumers");
            exit(EXIT_FAILURE);
        }
    }

    for(int i = 0; i < numberThreads; i++)
        if(pthread_join(workers[i], NULL))
            perror("Can't join thread: Consumers");

    if(pthread_join(producer_th, NULL))
        perror("Can't join thread: Producer");

    TIMER_READ(stopTime);
    fprintf(timeFp, "TecnicoFS completed in %.4f seconds.\n", TIMER_DIFF_SECONDS(startTime, stopTime));
    free(workers);
}

void init_variables(){
    mutex_init(&commandsLock);
    sem_init(&sem_prod,0,MAX_COMMANDS);
    sem_init(&sem_cons,0,0);
}

void destroy_variables(){
  mutex_destroy(&commandsLock);
  sem_destroy(&sem_cons);
  sem_destroy(&sem_prod);
}

int main(int argc, char* argv[]) {
    parseArgs(argc, argv);
    FILE * outputFp = openOutputFile();
    init_variables();
    fs = new_tecnicofs(hashMax);
    printf("Sleeping..\n");
    sleep(sleepTime);
    printf("Awake..\n");
    runThreads(stdout);
    print_tecnicofs_tree(outputFp, fs);
    fflush(outputFp);
    fclose(outputFp);

    destroy_variables();
    free_tecnicofs(fs);
    exit(EXIT_SUCCESS);
}
