Prova Pratica 2014.06.17

From Sistemi Operativi
Jump to navigation Jump to search

Link al testo

Esercizio 1

Occorre scrivere due programmi: mytar myuntar.
Mytar prende come parametro il nome di una directory e il nome di un file:
mytar ddd ddd.mytar
mytar crea il file indicato come secondo parametro e registra in esso tutti i file regolari presenti nella directory (ddd
nell'esempio). Ogni file e' registrato nel secondo il seguente formato:
nome del file (stringa ASCII terminata da un byte 0)
lunghezza del file (stringa ASCII terminata da 0, la lunghezza e' registrata come stringa in rappresentazione in base 10
per non avere problemi di endianess e di ampiezza dei campi)
contenuto del file (un numero di byte corrispondente alla lunghezza indicata sopra).
Myuntar fa l'operazione inversa:
myuntar ddd.mytar newddd
crea la directory indicata come secondo parametro e, in essa, tutti i file registrati in ddd.mytar.
Per provare i due programmi, al termine dell'esecuzione di due comandi simili a quelli degli esempi mostrati qui sopra per
mytar e myuntar, tutti i file regolari presenti in ddd devono esistere in newddd e devono avere tutti lo stesso contenuto.
Se create una directory ddd contenente solo file regolare l'output di “diff -R ddd newddd” deve essere vuoto.

Soluzione di Dado

mytar e myuntar entrambi funzionanti


mytar.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <dirent.h>
#include <sys/stat.h>

#define MAX 20
#define MAXI 1024

/*codice copiato da internet che ipotizzo funzioni :) */

 void reverse(char s[])
 {
     int i, j;
     char c;
 
     for (i = 0, j = strlen(s)-1; i<j; i++, j--) {
         c = s[i];
         s[i] = s[j];
         s[j] = c;
     }
 }

void itoa(int n, char s[])
 {
     int i, sign;
 
     if ((sign = n) < 0)  /* record sign */
         n = -n;          /* make n positive */
     i = 0;
     do {       /* generate digits in reverse order */
         s[i++] = n % 10 + '0';   /* get next digit */
     } while ((n /= 10) > 0);     /* delete it */
     if (sign < 0)
         s[i++] = '-';
     s[i] = '\0';
     reverse(s);
 }


/*mytar*/
int main(int argc, char * argv[]){
	if(argc!=3){
		fprintf(stderr, "Wrong arguments number\n");
		return -1;
	}
	else{
		FILE *dest;
		FILE *temp;
		DIR *dir;
		char length[MAX];
		char *buf_read;
		char zero='\0';
		size_t n_readed;
		struct stat buf;
		struct dirent *entry;
		if((dir=opendir(argv[1]))==NULL){
			fprintf(stderr, "Error opendir\n");
			exit(-1);
		}
		if((dest=fopen(argv[2],"w"))==NULL){
			fprintf(stderr, "Error fopen\n");
			exit(-1);
		}
		while((entry=readdir(dir))!=NULL){
			buf_read=NULL;
			chdir(argv[1]);
			if(entry->d_type==DT_REG){
				if(stat(entry->d_name,&buf)==-1){
					fprintf(stderr, "Error stat\n");
					exit(-1);
				}
				if((temp=fopen(entry->d_name,"r"))==NULL){
					fprintf(stderr, "Error fopen_temp\n");
					exit(-1);
				}
				write(fileno(dest),entry->d_name,strlen(entry->d_name)+1);
				itoa(buf.st_size-1,length);
				write(fileno(dest),length,strlen(length)+1);
				/*scrivere dati*/
				while(getdelim(&buf_read,&n_readed,EOF,temp)>0){
					write(fileno(dest),buf_read,strlen(buf_read)-1);
				}
				free(buf_read);
			}
		}
		printf("File mytar creato con successo!\n");
		return 0;
	}
}


myuntar.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <dirent.h>
#include <sys/stat.h>


int main(int argc, char * argv[]){
	if(argc!=3){
		fprintf(stderr, "Wrong arguments number\n");
		exit(-1);
	}else{
		FILE *mytar;
		FILE *tmp;
		char nome[256];
		int dim, i;
		char readed[2],length[20];
		nome[0]=length[0]=0;
		readed[1]=0;
		if(mkdir(argv[2],(mode_t)0777)==-1){
			fprintf(stderr, "Error mkdir\n");
			exit(-1);
		}
		if((mytar=fopen(argv[1],"r"))==NULL){
			fprintf(stderr, "Error fopen\n");
			exit(-1);
		}
		if(chdir(argv[2])==-1){
			fprintf(stderr, "Errore chdir\n");
			exit(-1);
		}
		while((fread(&readed,1,1,mytar))){
			strcat(nome,readed);
			while((fread(&readed,1,1,mytar))){
				if(readed[0]=='\0') break;
				strcat(nome,readed);
			}
			printf("Nome trovato: %s\n",nome);
			if((tmp=fopen(nome,"w"))==NULL){
				fprintf(stderr, "Error fopen files\n");
				exit(-1);
			}
			while((fread(&readed,1,1,mytar))){
				if(readed[0]=='\0') break;
				strcat(length,readed);
			}
			dim=atoi(length);
			printf("Lunghezza trovata: %s\n",length);
			for(i=0; i<dim; i++){
				fread(&readed,1,1,mytar);
				write(fileno(tmp),&readed,1);
			}
		fclose(tmp);
		nome[0]=0;
		length[0]=0;
		}
	fclose(mytar);
	printf("File myuntar scompattato correttamente, credo\n");
	return 0;
	}
}


Soluzione di MV

Per ora ho fatto solo la prima parte, cioè mytar.
L'unico problema che non riesco a capire è che entra in un loop infinito (scrivendo all'infinito sul file che crea!) se viene usato nella cartella dell'eseguibile stesso...
/*-------------------------------------MYTAR.C--------------------------------------------*/

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <fcntl.h>
#include <unistd.h>

#define BUF_DIM 512

/* scrive nome, dimensione e contenuto del file indicato da src nel file dest (già aperto in scrittura) */
int filecpy(const char *src, const int dest, off_t size);

/* ---------------------------------- MAIN ------------------------------- */
int main(int argc, char* argv[])
{	
	DIR *ddd;
	int f;
	struct dirent *entry;
	struct stat dest_st;
	int e,i,len;
	char buf[BUF_DIM];
	
	if(argc != 3)
	{
		printf("Error: needed 2 parameters\n");
		return 1;
	}
	
	umask(0001);
	/* Creo il file passato come secondo parametro */
	if((f = open(argv[2], O_WRONLY|O_CREAT|O_TRUNC, 0666)) == -1)
	{
		printf("Error in open(): %s (%i)\n",strerror(errno),errno);
		return errno;
	}
	
	/* Apro la directory passata come primo parametro, se c'è */
	if((ddd = opendir(argv[1])) == NULL)
	{
		printf("Error in opendir(%s): %s (%i)\n",argv[1],strerror(errno),errno);
		return errno;
	}
	/* mi sposto in quella directory */
	if(chdir(argv[1]) == -1)
	{
		printf("Error in chdir(%s): %s (%i)\n",argv[1],strerror(errno),errno);
		return errno;
	}
	
	e = errno;
	i = 0;	/* in i mantengo il numero totale di file copiati */
	/* leggo lo stat del file che ho creato */
	if(fstat(f, &dest_st) == -1)
	{
		printf("Error in stat(%s): %s (%i)\n",buf,strerror(errno),errno);
		return errno;
	}
	
	/* leggo le entry della directory finchè ce ne sono */
	while((entry = readdir(ddd)) != NULL)
	{
		struct stat st;
		
		strcpy(buf, entry->d_name);
		
		if(stat(buf, &st) == -1)
		{
			printf("Error in stat(%s): %s (%i)\n",buf,strerror(errno),errno);
			return errno;
		}
		else if(st.st_mode & S_IFREG)	/* è un file */
		{	
			/* verifico che il file in questione sia diverso da quello aperto in scrittura, per evitare che scriva su se stesso all'infinito */
			if((st.st_ino == dest_st.st_ino) && (st.st_rdev == dest_st.st_rdev))
				continue;
			
			if(filecpy(buf, f, st.st_size) == -1)
			{
				printf("Error in filecpy(%s, %i)\n",buf,f);
				return -1;
			}
			printf("%s inserito.\n", buf);
			i++;
		}
	}
	
	if(e != errno)	/* sono uscito dal ciclo a causa di un errore */
	{
		printf("Error in readdir(): %s (%i)\n",strerror(errno),errno);
		return errno;			
	}
	else	/* perchè ho visitato tutte le entrate della directory */
		printf("end of directory, %i entry found.\n", i);
	
	return 0;
}

int filecpy(const char *src, const int dest, off_t size)
{
	/* NB: dest è già aperto in scrittura */
	int s, len, tot;
	char buf[BUF_DIM];
	
	if((s = open(src,O_RDONLY,0)) == -1)	/* apro src in lettura */
		return -1;
	
	tot = write(dest, src, strlen(src)+1);	/* per prima cosa copio il titolo del file src */
							/* NB: faccio tot+1 per copiare anche lo 0 terminatore */
	sprintf(buf, "%i", (int)size);	/* poi copio la dimensione */
	tot += write(dest, buf, strlen(buf)+1);
	
	/* infine copio tutto il contenuto */
	while( (len = read(s,buf,BUF_DIM)) != 0)
	{
		if(len == -1)
		{
			printf("Error in read(): %s (%i)\n",strerror(errno),errno);
			return -1;
		}
		/*else printf("%i\n",len);*/
		tot += write(dest, buf, len);
	}
	
	return tot;	/* restituisce il numero totale di byte scritti */
}


Esercizio 3

Il comando che dovrete implementare come script shell o programma python e' maxfreq.
Maxfreq ha come parametro un carattere alfanumerico e una directory.
Es:
maxfreq q mydir
Cerca in tutto il sottoalbero del file system originato da mydir il file che ha la maggior frequenza della lettera indicata (in
questo caso la maggior frequenza di 'q'). Fornisce in output il nome del file e la frequenza in percentuale.

Bash

Soluzione di Davide Quadrelli

#! /bin/bash
if [[ -z $1 ]] ; then
	echo "maxfreq [char da contare] [directory]"
	exit
fi
if [[ -n $2 ]] ; then
	files=`find -L $2`
else
	echo if2
	echo "maxfreq [char da contare] [directory]"
	exit
fi
max=0
file=""
for var in $files; do
	tmp=`cat $var 2> /dev/null | grep -c $1 2> /dev/null`
	if [[ max -le tmp ]]; then
		max=$tmp
		file=$var
	fi
done
dim=`ls -l $file | cut -d " " -f 5`
echo "( ${max} * 100 ) / ${dim}" > tmp
echo "quit" >> tmp
perc=`bc -q tmp`
rm tmp
echo "Il file $file contiene ${perc}% di $1 ($max su $dim caratteri)"

Ho sfruttato il comando bc per calcolare la percentuale. Utilizzo il parametro -q per impedire che stampi il "saluto" del programma e metto tutto il codice da eseguire nel file tmp. Oltre al comando, inserisco un "quit" per terminare il comando bc, che avrà restituito alla variabile soltanto il risultato del calcolo. Elimino poi ovviamente il file tmp.

Nota di Maldus

grep -c $1 conta il numero di righe in cui si trovano le occorrenze; questo significa che se in una riga abbiamo 2 ( o più ) occorrenze viene comunque contata come 1. Per contare tutte le occorrenze ( anche nella stessa riga ) si potrebbe sostituire la riga

tmp=`cat $var 2> /dev/null | grep -c $1 2> /dev/null`

con

tmp=`cat $var 2> /dev/null | grep -o $1 2> /dev/null | wc -l`

Soluzione di G.C.

#!/bin/bash

#input check 

if [ $# -lt 2 ] ; then
	echo "Arguments Error. Usage ./maxfreq character directory"
	exit
fi
if [[ "$1" =~ [^a-zA-Z0-9] ]]; then
	echo "invalid character"
	exit
fi
if ! [ -d $2 ] ; then
	echo "invalid directory as second argument"
	exit
fi 

tmp_file=/tmp/maxfreq$$

#recursively find of $2 directory
find $2 -type f | while read line
do
	num=$(cat $line | grep -o $1 | wc -l)
	echo "$num:$line" >> $tmp_file
done

#file of "numOccurency:FileName"

ord_tmp_file=/tmp/ord_tmp_file$$

#reverse ordering of the file and rewriting
cat $tmp_file | sort -r > $ord_tmp_file
rm $tmp_file

#take first line (major file occurency of char $1)
num=$(head -1 $ord_tmp_file | awk -F: '{print $1}')
file=$(head -1 $ord_tmp_file | awk -F: '{print $2}')

#count all char in $file of the first line
max=$(cat $file | wc -c)

#basename of file name (this is not mandatory)
base=$(basename $file)

#math to calculate % num/max
tmp_math_file=/tmp/math$$
echo "( ${num} *100) / ${max}" > $tmp_math_file
echo "quit" >> $tmp_math_file
freq=$(bc -q $tmp_math_file)
rm $tmp_math_file


echo "File: $base Freq '$1' of $freq %"

rm $ord_tmp_file

Python3

Soluzione di G.C.

import sys
import os

def checkFile(char, d):
	e = []
	for x in os.listdir(d):
		if os.path.isdir(os.path.join(d,x)):
			e.append(checkFile(char,os.path.join(d,x)))
		else:
			f = open(os.path.join(d,x),"r")
			e.append((os.path.join(d,x),f.read().count(char)))
			f.close()
	return e

def sortAndPrint(d):
	d.sort(key=lambda tup: tup[1], reverse=True)
	fileName= d[0][0]
	num = d[0][1]
	f = open(fileName,"r")
	max_c = len(f.read())
	f.close()
	return fileName, num/max_c*100

if __name__=='__main__':
	try:
		if len(sys.argv) < 3:
			raise Exception("Too few arguments. Usage ./maxfreq char dir")
		if not sys.argv[1].isalnum():
			raise Exception("Char not alphanumeric passed")
		if not os.path.isdir(sys.argv[2]):
			raise Exception("%s is not a directory" % (sys.argv[2]))
		d = checkFile(sys.argv[1],sys.argv[2])
		f,p = sortAndPrint(d)
		print("Maxfreq occurency of %s was in %s with a percentage of %f %%" % (sys.argv[1],f,p))
	except Exception as inst:
		print(inst.args)