Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <stdio.h>
- #include <stdlib.h>
- #include <stdbool.h>
- #include <string.h>
- #include <unistd.h>
- #include <limits.h>
- #include <fcntl.h>
- #include <dirent.h>
- #include <sys/stat.h>
- #include <sys/types.h>
- struct options {
- bool option_R;
- bool option_t;
- int numBytes;
- bool option_f;
- bool option_v;
- };
- struct list_ls {
- char *name;
- char *destiny;
- struct stat *stat;
- struct list_ls *next;
- struct list_ls *before;
- };
- struct list_ls *emptyList()
- {
- return NULL;
- }
- int info(char *s){
- struct stat b;
- //char *inf,*tmp;
- int per=0;
- int res=0;
- if(lstat(s,&b)!=0){ printf("\nError: Info: Parametros incorrectos para el lstat* en %s\n",s); exit(0);}
- else {
- if (b.st_mode & S_IRUSR) per=4; else per=0;
- if (b.st_mode & S_IWUSR) per+=2; else per+=0;
- if (b.st_mode & S_IXUSR) per+=1; else per+=0;
- res=per*64;
- if (b.st_mode & S_IRGRP) per=4; else per=0;
- if (b.st_mode & S_IWGRP) per+=2; else per+=0;
- if (b.st_mode & S_IXGRP) per+=1; else per+=0;
- res+=(per*8);
- if (b.st_mode & S_IROTH) per=4; else per=0;
- if (b.st_mode & S_IWOTH) per+=2; else per+=0;
- if (b.st_mode & S_IXOTH) per+=1; else per+=0;
- res+=per;
- return res;
- }
- }
- int isEmptyList(struct list_ls *list)
- {
- return (list==NULL)?0:1;
- }
- void deleteList(struct list_ls **list)
- {
- struct list_ls *aux;
- while (*list!=NULL){
- aux = *list;
- free(aux->name);
- free(aux->destiny);
- free(aux->stat);
- *list=aux->next;
- free(aux);
- }
- return;
- }
- struct list_ls *add(struct list_ls **list, char *d_name, char *d, struct stat *s)
- {
- struct list_ls *aux,*new;
- if((new = malloc(sizeof(struct list_ls)))==NULL){
- printf("Cannot allocate memory\n");
- exit(EXIT_FAILURE);
- }
- new->name=d_name;
- new->destiny=d;
- new->stat=s;
- new->next=NULL;
- new->before=NULL;
- if (*list==NULL) { //Caso en que la lista este vacia
- *list = new;
- return new;
- }
- aux = *list;
- while((aux->next!=NULL) && (strcmp(d_name,aux->name)<0))//Hasta que se encuentre el nombre o llegar al final de la lista
- aux = aux->next;
- if (strcmp(d_name,aux->name)>=0){
- if (aux==*list){//estamos en el principio
- new->next=*list;
- (*list)->before=new;
- *list=new;
- return *list;
- } else {//Insertar por el medio
- new->next=aux;
- new->before=aux->before;
- (new->before)->next=new;
- aux->before=new;
- return *list;
- }
- } else {//Es el mas grande de todos
- new->before=aux;
- aux->next=new;
- return *list;
- }
- return *list;
- }
- void prototype()
- {//Escribe el prototipo que tiene que tener el programa para ejecutarse
- printf("copy [-R] [-t numBytes] [-f] [-v] <sources> <dest>\n");
- exit(EXIT_FAILURE);
- }
- void init_options(struct options *options)
- {//Inicializa los valores de las opciones
- options->option_R = false;
- options->option_t = false;
- options->numBytes = -1;
- options->option_f = false;
- options->option_v = false;
- }
- void print_options(struct options option)
- {//Escribe los valores que tienen las opciones
- printf("Options:\n");
- if (option.option_R)
- printf("-R: true\n");
- else
- printf("-R: false\n");
- if (option.option_t)
- printf("-t: true, numBytes = %d\n",option.numBytes);
- else
- printf("-t: false\n");
- if (option.option_f)
- printf("-f: true\n");
- else
- printf("-f: false\n");
- if (option.option_v)
- printf("-v: true\n");
- else
- printf("-v: false\n");
- }
- void avaliable_R(struct options *options, char ** argv, int *cnt)
- {
- options->option_R = true;
- }
- void avaliable_t(struct options *options, char ** argv, int *cnt)
- {
- options->option_t = true;
- if (argv[0] != NULL)
- options->numBytes = atoi(argv[0]);
- else
- prototype();
- *cnt = *cnt + 1;//Como leo un argumento pues lo salto para no leerlo despues
- }
- void avaliable_f(struct options *options, char ** argv, int *cnt)
- {
- options->option_f = true;
- }
- void avaliable_v(struct options *options, char ** argv, int *cnt)
- {
- options->option_v = true;
- }
- void search_options(char *argv[], struct options *options)
- {//Busca las opciones en la linea de comandos
- struct activate{//para activar las opciones
- char *name;
- void (*funtion) (struct options *, char **, int *);
- };
- struct activate act_opt[] = {//Opciones disponibles
- {"-R", avaliable_R},
- {"-t", avaliable_t},
- {"-f", avaliable_f},
- {"-v", avaliable_v},
- {NULL, NULL},
- };
- int j, i;
- for (i = 0; argv[i]!=NULL; i++) {
- for (j = 0; act_opt[j].name!=NULL; j++) {//Miro por todas las opciones
- //printf("%d \t",j);
- if (!strcmp(act_opt[j].name, argv[i])) {
- (*act_opt[j].funtion)(options, argv+i+1, &i);//lanzo la funcion
- break;
- }
- }
- //printf("\nj = %d , name %s\ni = %d , name %s\n",j,act_opt[j].name,i,argv[i]);
- if ((!strncmp(argv[i],"-",1))&&(act_opt[j].name==NULL))//Opcion no valida
- prototype();
- }
- }
- char **search_sources(int argc, char **argv)
- {//Devuelve un array de 'strings' de carpetas origen
- int i, cnt = 0;
- for (i = 0; i < argc; i++) {
- if (!strncmp(argv[i],"-",1)){//opcion
- if (!strcmp(argv[i],"-t"))//pa que no mire el numBytes
- i++;
- }
- else
- cnt++;
- }
- char **aux;
- if ((aux = malloc(sizeof(char *)*(cnt+1)))==NULL) {
- printf("Cannot allocate memory\n");
- exit(EXIT_FAILURE);
- }
- aux[cnt] = NULL;
- int j = 0;
- for (i = 0; i < argc; i++) {
- if (!strncmp(argv[i],"-",1)){//opcion
- if (!strcmp(argv[i],"-t"))//pa que no mire el numBytes
- i++;
- }
- else {
- aux[j] = strdup(argv[i]);
- j++;
- }
- }
- return aux;
- }
- void delete_sources(char ***sources)
- {//Libera la memoria que se uso para la lista de directorios origen
- int i;
- char **aux = *sources;
- for (i = 0; aux[i]!=NULL; i++)
- free(aux[i]);
- free(aux);
- aux = NULL;
- }
- void print_sources(char **sources)
- {//Imprime las rutas de origen
- int i;
- printf("Source list:\n");
- for (i = 0; sources[i] != NULL; i++)
- printf("\t%s\n",sources[i]);
- return;
- }
- bool is_write_user(mode_t mode)
- {//Indica si el usuario puede escribir
- return (mode & S_IWUSR)?true: false;
- }
- bool is_read_user(mode_t mode)
- {//Indica si el usuario puede leer
- return (mode & S_IRUSR)?true: false;
- }
- bool is_link(mode_t mode)
- {//devuelve true si es un link
- return (S_ISLNK(mode))?true: false;
- }
- bool is_write_numBytes(struct options options, off_t size)
- {//Inidica si con las opciones disponibles se puede escribir un archivo con tamaño size
- if (!options.option_t)
- return true;
- return (size > options.numBytes)? false: true;
- }
- bool is_write_file(char *source, char *destiny, struct options options)
- {//Indica si el archivo source se puede copiar en destiny
- if (options.option_f)
- return true;
- struct stat buf;
- if (lstat(destiny, &buf))//Si da false es que ese será el nombre del archivo a crear
- return true;
- //printf("source: %s\n",source);
- //printf("destiny: %s\n", destiny);
- if (!S_ISDIR(buf.st_mode))//Si existe el archivo y no es un directorio
- return false;
- char *file = rindex(source, '/');
- file = (file == NULL)? source: file+1; //Nombre del archivo
- char *path;
- if ((path = malloc(sizeof(char)*(strlen(destiny)+strlen(file)+2)))==NULL){
- printf("Cannot allocate Memory\n");
- exit(EXIT_FAILURE);
- }
- strcpy(path, destiny);
- strcat(path, "/");
- strcat(path, file);
- bool exist = (!lstat(path, &buf))? true: false;
- free(path);
- return !exist;//Si existe no se podra escribir el archivo
- }
- char *file_to_creat(char *source, char *destiny)
- {//Devuelve un path del archivo que se va a crear
- struct stat stat;
- if (lstat(destiny,&stat)==0) {
- if (!S_ISDIR(stat.st_mode))//Es que existe el archivo
- return strdup(destiny);
- } else
- return strdup(destiny);
- //printf("source : %s\n", source);
- //printf("destiny: %s\n", destiny);
- char *file = rindex(source, '/');
- file = (file == NULL)? source: file+1; //Nombre del archivo
- char *path;
- if ((path = malloc(sizeof(char)*(strlen(destiny)+strlen(file)+2)))==NULL){
- printf("Cannot allocate Memory\n");
- exit(EXIT_FAILURE);
- }
- strcpy(path, destiny);
- strcat(path, "/");
- strcat(path, file);
- return path;
- }
- char *link_to_creat(char *source, char *link, char *destiny)
- {
- char *aux_source = rindex(source,'/');
- char *aux_destiny = rindex(destiny, '/');
- char *aux_link = rindex(link, '/');
- if (aux_source == NULL)
- return file_to_creat(link, destiny);
- int size_destiny = 0;
- if (aux_destiny == NULL) {
- aux_destiny = destiny;
- size_destiny = strlen(destiny);
- } else {
- size_destiny = strlen(destiny)-strlen(aux_destiny);
- }
- if (strcmp(aux_destiny, aux_source) != 0)
- return file_to_creat(link, source);
- if (aux_link == NULL)
- aux_link = link;
- else
- aux_link++;
- char *new_name = malloc(sizeof(char) * (strlen(aux_link)+size_destiny+2));
- if (new_name == NULL) {
- printf("Cannot allocate memory\n");
- exit(EXIT_FAILURE);
- }
- strncpy(new_name, destiny, size_destiny);
- new_name[size_destiny] = '\0';
- strcat(new_name, "/");
- strcat(new_name, aux_link);
- return new_name;
- }
- int file_cp(char *source, char *destiny, struct options options, char *link)
- {//Funcion para copiar un archivo
- char *aux;
- if ((link != NULL) && (!options.option_R))
- aux = link;
- else
- aux = source;
- //printf("aux: %s\n",aux);
- struct stat stat;//para coger los datos de los que se van copiar de verdad
- if (lstat(aux,&stat)) {//Si da fallo es de los extraños extraños
- perror("file_cp: lstat");
- return -1;
- }
- if (!is_write_numBytes(options, stat.st_size)) {
- printf("size of '%s': %lu\n", source, stat.st_size);
- printf("avaliable bytes to copy: %d\n", options.numBytes);
- return -1;
- }
- if (!is_write_file(source, destiny, options)) {
- printf("option -f not avaliable\nCannot rewrite the file\n");
- return -1;
- }
- char *new_file = file_to_creat(aux, destiny);
- if (link != NULL && options.option_R) {
- printf("source : %s\n",source);
- if (symlink(source, new_file)==-1) {
- perror("file_cp: symlink");
- free(new_file);
- return -1;
- }
- free(new_file);
- return 0;
- }
- //Aqui ya está todo correcto para para copiar
- int fd_source = open(aux, O_RDONLY);
- if (fd_source == -1) {
- printf("file_cp: Cannot open file: %s\n",aux);
- free(new_file);
- return -1;
- }
- remove(new_file);//si existia el archivo antes lo eliminamos
- int fd_creat = open(new_file, O_CREAT | O_WRONLY | O_EXCL, stat.st_mode);
- if (fd_creat == -1) {
- printf("file_cp: Cannot open to write: %s\n",new_file);
- free(new_file);
- return -1;
- }
- void *buffer = malloc(stat.st_size);
- if (buffer == NULL) {
- printf("Cannot allocate memory\n");
- close(fd_source);
- close(fd_creat);
- exit(EXIT_FAILURE);
- }
- if (read(fd_source, buffer, stat.st_size)==-1) {
- printf("file_cp: Cannot read file\n");
- close(fd_source);
- close(fd_creat);
- free(buffer);
- return -1;
- }
- if (write(fd_creat, buffer, stat.st_size)==-1) {
- printf("file_cp: Cannot write file\n");
- close(fd_source);
- close(fd_creat);
- free(buffer);
- return -1;
- }
- chmod(new_file,info(aux));
- if (options.option_v)
- printf("%s -> %s\n",aux,new_file);
- free(new_file);
- free(buffer);
- close(fd_source);
- close(fd_creat);
- return 0;
- }
- char *directory_and_file(char *dir, char *file)
- {
- char *new = malloc(sizeof(char)*(strlen(dir)+strlen(file)+2));
- if (new == NULL) {
- printf("Cannot allocate memory\n");
- exit(EXIT_FAILURE);
- }
- strcpy(new, dir);
- strcat(new, "/");
- strcat(new, file);
- return new;
- }
- char *cat_file(char *dir, char *name)
- {
- char *new = malloc(sizeof(char)*(strlen(dir)+strlen(name)+2));
- if (new == NULL) {
- printf("Cannot allocate memory\n");
- exit(EXIT_FAILURE);
- }
- strcpy(new, dir);
- strcat(new, "/");
- strcat(new, name);
- return new;
- }
- void main_cp(char *source, char *destiny, struct options options);
- int directory_cp(char *source, char *destiny, struct options options, const char *link)
- {//Funcion para copiar una carpeta
- DIR *dir;
- struct dirent *myDirec;
- struct list_ls *list;
- char *name;
- char *dest;
- struct stat stat, buffin, *aux_stat;
- if (lstat(source, &stat)) {
- perror("directory_cp: lstat");
- return -1;
- }
- /*if (!is_write_numBytes(options, stat.st_size)) {
- printf("size of '%s': %lu\n", source, stat.st_size);
- printf("avaliable bytes to copy: %d\n", options.numBytes);
- return -1;
- }*/
- //Introduzco todo en una lista y después se manda copiar
- list=emptyList();
- if ((dir = opendir(source))==NULL) {
- printf("directory_cp: open_dir: Cannot open directory\n");
- return -1;
- }
- while ((myDirec=readdir(dir))!=NULL) {
- name = directory_and_file(source, myDirec->d_name);
- dest = directory_and_file(destiny, myDirec->d_name);
- if (!((strcmp(myDirec->d_name,".")==0)||(strcmp(myDirec->d_name,"..")==0))) {
- if ((aux_stat = malloc(sizeof(struct stat)))==NULL) {
- printf("Cannot allocate memory\n");
- exit(EXIT_FAILURE);
- }
- if (lstat(name, aux_stat)==-1) {
- perror("directory_cp: lstat");
- exit(EXIT_FAILURE);
- }
- list = add(&list, name, dest, aux_stat);
- } else {
- free(name);
- free(dest);
- }
- }
- closedir(dir);
- char *folder = destiny;
- if (lstat(folder, &buffin)==-1)
- if (mkdir(folder, stat.st_mode)==-1) {
- printf("directory_cp: Cannot create a new folder\n");
- deleteList(&list);
- //free(folder);
- return -1;
- }
- if (chmod(folder,info(source))==-1)
- perror("directory_cp: chmod");
- if (options.option_v)
- printf("%s -> %s\n",source,folder);
- struct list_ls *aux = list;
- while (aux != NULL) {
- if (!((!options.option_R) && (S_ISDIR(aux->stat->st_mode))))
- main_cp(aux->name ,aux->destiny, options);
- //printf("aux : %s\n",aux->name);
- aux = aux->next;
- }
- deleteList(&list);
- //free(folder);
- return 0;
- }
- char *name_to_creat(char *source, char *link, char *destiny)
- {/*
- printf("source: %s\n",source);
- printf("link: %s\n",link);
- printf("destiny: %s\n",destiny);
- */
- int size_d = strlen(destiny);
- char *aux_d = rindex(destiny,'/');
- if (aux_d != NULL)
- size_d -= strlen(aux_d++);
- char *aux_s = rindex(source,'/');
- aux_s = (aux_s == NULL)? source: aux_s + 1;
- char *new = malloc(sizeof(char) * (2+size_d+strlen(aux_s)));
- if (new == NULL) {
- printf("Cannot allocate memory\n");
- exit(EXIT_FAILURE);
- }
- strncpy(new, destiny, size_d);
- new[size_d] = '\0';
- strcat(new, "/");
- strcat(new, aux_s);
- //printf("\n\tnew_file : %s\n",new);
- return new;
- }
- int link_cp(char *source, char *destiny, struct options options)
- {
- static int cnt = 0;
- cnt++;
- int parada = 92;
- char *link;
- char buffer[PATH_MAX];
- link = realpath(source, buffer);
- if (link == NULL) {
- perror("link_cp: realpath");
- return -1;
- }
- struct stat l_stat;
- if (lstat(link,&l_stat)==-1) {
- printf("link_cp: The referenced file not found\n");
- return -1;
- }
- if (cnt == parada) {
- printf("source: %s\n",source);
- printf("link: %s\n",link);
- }
- if (S_ISDIR(l_stat.st_mode) & (!options.option_R)) {
- char *new_folder = link_to_creat(source,link,destiny);
- if (cnt == parada) {
- printf("destino: %s\n",new_folder);
- exit(0);
- }
- if (mkdir(new_folder, 0755)==-1) {
- printf("link_cp: Cannot create folder\n");
- free(new_folder);
- return -1;
- }
- if (chmod(new_folder,info(link))==-1)
- perror("link_cp: chmod");
- if (options.option_v)
- printf("%s -> %s\n",link,new_folder);
- main_cp(link,new_folder,options);
- free(new_folder);
- return 0;
- }
- if (options.option_R) {//Crear el enlace
- char *new_link = name_to_creat(source,link,destiny);
- //printf("source: %s\n",source);
- //printf("new: %s\n", new_link);
- if (cnt == parada) {
- printf("destino: %s\n",new_link);
- exit(0);
- }
- if (symlink(source,new_link)==-1) {
- printf("link_cp: Fail to create link: %s\n",source);
- free(new_link);
- return -1;
- }
- if (chmod(new_link,info(link))==-1)
- perror("link_cp: chmod");
- if (options.option_v)
- printf("%s -> %s\n",link,new_link);
- free(new_link);
- return 0;
- }
- else {//Copiar el archivo al que apunta
- return file_cp(link,destiny,options,NULL);
- }
- }
- void main_cp(char *source, char *destiny, struct options options)
- {//Se tienen la lista de directorios origen, la ruta de destino y las opciones
- struct stat buf;
- if (lstat(source,&buf)) {//Si no existe
- printf("main_cp: No such file or directory: %s\n",source);
- return;
- }
- if (!is_read_user(buf.st_mode)) {
- printf("main_cp: Cannot read %s\n",source);
- return;
- }
- char *link = NULL;
- if (is_link(buf.st_mode)){//Si es un link
- int result =link_cp(source, destiny, options);
- if (result == 0)
- return;
- else {
- printf("main_cp: Fail to copy %s(it's a link) to %s\n",source, destiny);
- return;
- }
- //printf("%s -> %s\n",source, buffer);
- }
- if (S_ISDIR(buf.st_mode)) {//Si es un directorio
- if (directory_cp(source, destiny, options, link) != 0)
- printf("main_cp: Fail to copy folder '%s' into '%s'\n",source,destiny);
- } else {//Si es un archivo
- if (file_cp(source, destiny, options, link) != 0)
- printf("main_cp: Fail to copy '%s' into '%s'\n",source,destiny);
- }
- }
- void pre_cp(char **sources, char *destiny, struct options options) {
- int i;
- struct stat buf;
- if (!lstat(destiny, &buf))
- if (!is_write_user(buf.st_mode)) {
- printf("pre_cp: Cannot write into destiny\n(destiny: %s)\n",destiny);
- return;
- }
- for (i = 0; sources[i] != NULL; i++) //Lista de origenes... empezamos uno a uno
- main_cp(sources[i], destiny, options);
- }
- int main(int argc, char *argv[])
- {
- if (argc < 3)
- prototype();
- //Opciones
- struct options options_cp;
- init_options(&options_cp);//Vacia las opciones
- search_options(argv+1, &options_cp);//Activa opciones
- //print_options(options_cp);
- //rutas
- char **sources = NULL;
- char *destiny = NULL;
- sources = search_sources(argc-2, argv+1);//-2 poqe la última es el destino
- //print_sources(sources);
- if (sources[0] == NULL) {//No tiene destino para copiar
- printf("destiny not found\n");
- exit(EXIT_FAILURE);
- }
- destiny = strdup(argv[argc-1]);
- //printf("Destino:\n\t%s\n",destiny);
- //Empezar a copiar los elementos
- //printf("\n\n\n");
- pre_cp(sources, destiny, options_cp);
- delete_sources(&sources);
- if (destiny != NULL)
- free(destiny);
- exit(EXIT_SUCCESS);
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement