Prova Pratica 2014.06.17
Jump to navigation
Jump to search
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.
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`