/***************************************************************************** Application ASH: copy.c (c) Pierre Adriaans 1994 ------------------------------------------------------------------------------ Fonction de copie recursive. *****************************************************************************/ #include "ash.h" extern DIR *DummyDir; extern AnswerBoxItem_t *InfoMsg; extern CheckBoxItem_t *RecursiveStr; extern DirList_t *Current[NB_MAX_WINS], *List[NB_MAX_WINS], *Dummy; extern int AL,AfficheX,AfficheY,NbWins; extern char DummyStr[DUMMYSTR_SIZE],WorkingDir[NB_MAX_WINS][FILENAME_LENGTH]; extern InvZone_t InvZone[NB_MAX_WINS]; /***************************************************************************** CopyDir() ------------------------------------------------------------------------------ Fonction recursive de copie d'un ss-rep avec son contenu. La fonction suppose que le ss-rep courant est le pere du ss-rep a copier passer le nom du ss-rep a copier tel que present dans la liste DirList et la specification du ss-rep dans lequel le ss-rep a copier devra etre cree et son contenu copie. Output: 0 si ok, -1 si interrompu par l'utilisateur. *****************************************************************************/ int CopyDir(char *SourcePathF,char *DestPathF) { char CurrentPath[FILENAME_LENGTH], /* Spec complete ss-rep courant */ PathToCopy[FILENAME_LENGTH], /* Spec complete ss-rep a copier */ Path2[FILENAME_LENGTH], /* Spec complete ss-rep cible */ SourcePath[FILENAME_LENGTH], /* Copie des arguments pour eviter leur modification lors d'un appel recursif */ DestPath[FILENAME_LENGTH], /* Idem */ InFile[FILENAME_LENGTH], /* Specification complete du fichier source */ OutFile[FILENAME_LENGTH],/* Specification complete du fichier destinnation */ Line[40], /* Ligne de C_DESKTOP lors de la copie */ Line2[40]; /* Ligne d'espace rognant Line */ DirList_t *List = (DirList_t *)NULL, /* Contenu du ss-rep a effacer */ *Temp; /* Pointeur de parcours */ DIR *DummyDir; /* Teste l'accessibilite */ /* Boite de dialogue */ AnswerBoxItem_t *Msg = (AnswerBoxItem_t *)NULL, *Choices = (AnswerBoxItem_t *)NULL; int rc, /* Code de retour */ i, /* Compteurs */ Nb, BufSize, /* Taille du buffer de copie */ LeftToCopy, /* Nbre de bytes encore a copier */ All = 0, /* Temoin de reponse "All" si fichier deja existant dans le ss-rep cible */ ChWarn = 1, /* Temoin de warning si chmod == -1 */ TmWarn = 1; /* Temoin de warning si utime == -1 */ char *CopyBuf = (char *)NULL; /* Tampon de copie */ struct utimbuf tm; /* Pour rectifier les dates de la copie */ FILE *hfIn,*hfOut; /* Pointeurs de fichiers In et Out */ /* Copier les arguments dans des variables locales */ strcpy(SourcePath,SourcePathF); strcpy(DestPath,DestPathF); /* Recuperer le ss-rep courant et construire la specification complete du ss-rep a copier */ getcwd(CurrentPath,PATH_LENGTH); strcpy(PathToCopy,CurrentPath); if(strcmp(PathToCopy,PATH_SEPARATOR_STR) == 0) PathToCopy[0] = 0; strcat(PathToCopy,SourcePath); /* Tester l'accessibilite de ce ss-rep */ if((DummyDir = opendir(PathToCopy)) == (DIR *)NULL) { InitAnswerBoxItem(&InfoMsg); AddAnswerBoxItem(&InfoMsg,"ERROR: impossible to access the directory"); AddAnswerBoxItem(&InfoMsg,PathToCopy); InfoBox(ErrorNorm,ErrorInv," Copy ",InfoMsg,1,0,DOUBLE_FRAMED); InitAnswerBoxItem(&InfoMsg); return(0); } else closedir(DummyDir); /* S'y placer */ if(chdir(PathToCopy) != 0) return(0); /* Recuperer le contenu et agir en consequence */ if(Dir("*.*",&List) > 1) { /* Construire la ligne temoin de l'operation de copie */ for(i=0;i<38;i++) Line[i] = C_DESKTOP; Line[i] = 0; /* Parcourir la liste */ for(Temp = List; Temp != (DirList_t *)NULL; Temp = Temp->Suivant) { /* Interruption utilisateur ? */ if(KeyPressed()) { ReadKbd(); InitAnswerBoxItem(&Msg); InitAnswerBoxItem(&Choices); AddAnswerBoxItem(&Msg,"Operation interrupted by user."); AddAnswerBoxItem(&Msg," Do you wish to cancel the copy cycle? "); AddAnswerBoxItem(&Choices,"Cancel"); AddAnswerBoxItem(&Choices,"Resume"); rc = AnswerBox(ConfirmNorm,ConfirmInv," Copy ",Msg,Choices, 2,0,DOUBLE_FRAMED); InitAnswerBoxItem(&Msg); InitAnswerBoxItem(&Choices); if(rc == 1) { chdir(CurrentPath); FreeAllTheList(&List); return(-1); } } /* Ne pas tenter de copier les liens symboliques */ if(IS_SYMLINK(Temp->Info.s.st_mode)) continue; if(strcmp(Temp->Info.Name,"..") != 0) if(IS_DIR(Temp->Info.s.st_mode)) { /* ss-rep: creation de la copie et appel recursif */ /* Construire la spec de la copie du ss-rep */ strcpy(Path2,DestPath); if(strcmp(Path2,PATH_SEPARATOR_STR) == 0) Path2[0] = 0; if(Path2[strlen(Path2) - 1] == PATH_SEPARATOR_CHAR) Path2[strlen(Path2) - 1] = 0; strcat(Path2,Temp->Info.Name); /* Tester s'il existe deja: si non, le creer */ if(access(Path2,00) != 0) { if(mkdir(Path2,S_IREAD|S_IWRITE|S_IEXEC) == -1) { InitAnswerBoxItem(&InfoMsg); AddAnswerBoxItem(&InfoMsg, "ERROR: impossible to create the directory"); AddAnswerBoxItem(&InfoMsg,Path2); switch(errno) { case ENOTDIR: case ENOENT: case ENOLINK: AddAnswerBoxItem(&InfoMsg,"Invalid directory specification."); break; case EMULTIHOP: AddAnswerBoxItem(&InfoMsg,"Multiple remote machines link."); break; case EACCES: AddAnswerBoxItem(&InfoMsg,"Permission denied."); break; case EEXIST: AddAnswerBoxItem(&InfoMsg,"The directory already exists."); break; case EROFS: AddAnswerBoxItem(&InfoMsg,"File system is read-only."); break; case EMLINK: AddAnswerBoxItem(&InfoMsg,"Maximum number of links exceeded."); break; case EIO: AddAnswerBoxItem(&InfoMsg,"An I/O error has occured."); break; default: sprintf(DummyStr,"Unknown reason (errno %d).",errno); AddAnswerBoxItem(&InfoMsg,DummyStr); } InfoBox(ErrorNorm,ErrorInv," Create Directory ",InfoMsg,1,0, DOUBLE_FRAMED); InitAnswerBoxItem(&InfoMsg); continue; } } /* Appel recursif */ if(CopyDir(Temp->Info.Name,Path2) == -1) { chdir(CurrentPath); FreeAllTheList(&List); return(-1); } } else { /* Fichier: copie */ /* Construire les specifications completes de fichiers */ strcpy(InFile,PathToCopy); if(InFile[strlen(InFile) - 1] != PATH_SEPARATOR_CHAR) strcat(InFile,PATH_SEPARATOR_STR); strcat(InFile,Temp->Info.Name); strcpy(OutFile,DestPath); if(OutFile[strlen(OutFile) - 1] != PATH_SEPARATOR_CHAR) strcat(OutFile,PATH_SEPARATOR_STR); strcat(OutFile,Temp->Info.Name); /* Si fichier vide, on passe */ if(Temp->Info.s.st_size == 0) continue; /* Afficher source et destination */ SetCurrentAtt(FileOpNorm); SetString(8,20,42,' '); if(strlen(Temp->Info.Name) < 40) WriteString(Temp->Info.Name,FileOpNorm,8, 40 - (strlen(Temp->Info.Name) / 2)); else { strcpy(DummyStr,"/..."); strcat(DummyStr,Temp->Info.Name + (strlen(Temp->Info.Name) - 33)); WriteString(DummyStr,FileOpNorm,8, 40 - (strlen(DummyStr) / 2)); } SetString(10,20,42,' '); if(strlen(OutFile) < 40) WriteString(OutFile,FileOpNorm,10, 40 - (strlen(OutFile) / 2)); else { strcpy(DummyStr,"/..."); strcat(DummyStr,OutFile + (strlen(OutFile) - 33)); WriteString(DummyStr,FileOpNorm,10, 40 - (strlen(DummyStr) / 2)); } WriteString(Line,FileOpNorm,11,22); /* Tester la presence de ce fichier a la cible */ if(!All) { if(access(OutFile,00) == 0) { InitAnswerBoxItem(&Choices); InitAnswerBoxItem(&Msg); sprintf(DummyStr,"WARNING: the file \"%s\"",Temp->Info.Name); AddAnswerBoxItem(&Msg,DummyStr); AddAnswerBoxItem(&Msg,"already exists in the target directory"); AddAnswerBoxItem(&Msg,DestPath); AddAnswerBoxItem(&Msg," Do you wish to overwrite the old file? "); AddAnswerBoxItem(&Choices,"Overwrite"); AddAnswerBoxItem(&Choices,"All"); AddAnswerBoxItem(&Choices,"Skip"); AddAnswerBoxItem(&Choices,"Cancel"); rc = AnswerBox(ConfirmNorm,ConfirmInv," Copy ",Msg,Choices, 2,0,DOUBLE_FRAMED); InitAnswerBoxItem(&Choices); InitAnswerBoxItem(&Msg); if(rc == 2) All = 1; if(rc == 3) continue; if(rc == 4 || rc == -1) { chdir(CurrentPath); FreeAllTheList(&List); return(-1); } } } /* Calcul de la taille du buffer de copie */ LeftToCopy = BufSize = Temp->Info.s.st_size; if(BufSize > COPY_BUF_SIZE) BufSize = COPY_BUF_SIZE; /* Allocation du buffer de copie */ if((CopyBuf = (char *)malloc(BufSize)) == (char *)NULL) { InitAnswerBoxItem(&InfoMsg); AddAnswerBoxItem(&InfoMsg,"Not enough memory to copy the file"); AddAnswerBoxItem(&InfoMsg,InFile); InfoBox(ErrorNorm,ErrorInv," Copy ",InfoMsg,1,0,DOUBLE_FRAMED); continue; } /* Ouverture du fichier source */ if((hfIn = fopen(InFile,"r")) == (FILE *)NULL) { InitAnswerBoxItem(&InfoMsg); AddAnswerBoxItem(&InfoMsg,"I cannot open input file"); AddAnswerBoxItem(&InfoMsg,InFile); switch(errno) { case EACCES: AddAnswerBoxItem(&InfoMsg,"Permission denied."); break; case EAGAIN: AddAnswerBoxItem(&InfoMsg,"File is locked."); break; case EEXIST: AddAnswerBoxItem(&InfoMsg,"File exists."); break; case EIO: AddAnswerBoxItem(&InfoMsg,"I/O error."); break; case EMULTIHOP: AddAnswerBoxItem(&InfoMsg,"Multiple remote machines link."); break; case EMFILE: AddAnswerBoxItem(&InfoMsg,"No file descriptor."); break; case ENFILE: AddAnswerBoxItem(&InfoMsg,"File table is full."); break; case ENOLINK: AddAnswerBoxItem(&InfoMsg,"Remote system unavailible."); break; case ENOMEM: AddAnswerBoxItem(&InfoMsg,"Out of memory."); break; case ENOSPC: AddAnswerBoxItem(&InfoMsg,"Out of inodes."); break; case ENOENT: case ENOTDIR: AddAnswerBoxItem(&InfoMsg,"Invalid file specification."); break; case ENXIO: AddAnswerBoxItem(&InfoMsg,"Stream device failure."); break; case EROFS: AddAnswerBoxItem(&InfoMsg,"File system is read-only."); break; case ETXTBSY: AddAnswerBoxItem(&InfoMsg,"Text file busy."); break; default: sprintf(DummyStr,"Unknown reason (errno %d).",errno); AddAnswerBoxItem(&InfoMsg,DummyStr); break; } InfoBox(ErrorNorm,ErrorInv," Copy ",InfoMsg,1,0,DOUBLE_FRAMED); if(CopyBuf != (char *)NULL) free(CopyBuf); continue; } /* Ouvrir le fichier cible */ if((hfOut = fopen(OutFile,"w")) == (FILE *)NULL) { InitAnswerBoxItem(&InfoMsg); AddAnswerBoxItem(&InfoMsg,"I cannot open output file"); AddAnswerBoxItem(&InfoMsg,OutFile); switch(errno) { case EACCES: AddAnswerBoxItem(&InfoMsg,"Permission denied."); break; case EAGAIN: AddAnswerBoxItem(&InfoMsg,"File is locked."); break; case EEXIST: AddAnswerBoxItem(&InfoMsg,"File exists."); break; case EIO: AddAnswerBoxItem(&InfoMsg,"I/O error."); break; case EMULTIHOP: AddAnswerBoxItem(&InfoMsg,"Multiple remote machines link."); break; case EMFILE: AddAnswerBoxItem(&InfoMsg,"No file descriptor."); break; case ENFILE: AddAnswerBoxItem(&InfoMsg,"File table is full."); break; case ENOLINK: AddAnswerBoxItem(&InfoMsg,"Remote system unavailible."); break; case ENOMEM: AddAnswerBoxItem(&InfoMsg,"Out of memory."); break; case ENOSPC: AddAnswerBoxItem(&InfoMsg,"Out of inodes."); break; case ENOENT: case ENOTDIR: AddAnswerBoxItem(&InfoMsg,"Invalid file specification."); break; case ENXIO: AddAnswerBoxItem(&InfoMsg,"Stream device failure."); break; case EROFS: AddAnswerBoxItem(&InfoMsg,"File system is read-only."); break; case ETXTBSY: AddAnswerBoxItem(&InfoMsg,"Text file busy."); break; default: sprintf(DummyStr,"Unknown reason (errno %d).",errno); AddAnswerBoxItem(&InfoMsg,DummyStr); break; } InfoBox(ErrorNorm,ErrorInv," Copy ",InfoMsg,1,0,DOUBLE_FRAMED); if(CopyBuf != (char *)NULL) free(CopyBuf); fclose(hfIn); continue; } /* Boucle de copie d'un fichier bloc par bloc */ while(LeftToCopy > 0) { /* Lire un bloc */ if(fread(CopyBuf,1,BufSize,hfIn) != BufSize) { InitAnswerBoxItem(&InfoMsg); AddAnswerBoxItem(&InfoMsg,"ERROR reading from input file"); AddAnswerBoxItem(&InfoMsg,InFile); AddAnswerBoxItem(&InfoMsg,"Copy will be aborted"); InfoBox(ErrorNorm,ErrorInv," Copy ",InfoMsg,1,0,DOUBLE_FRAMED); free(CopyBuf); fclose(hfIn); fclose(hfOut); remove(OutFile); break; } /* Ecrire un bloc */ if(fwrite(CopyBuf,1,BufSize,hfOut) != BufSize) { InitAnswerBoxItem(&InfoMsg); AddAnswerBoxItem(&InfoMsg,"ERROR writing to output file"); AddAnswerBoxItem(&InfoMsg,InFile); AddAnswerBoxItem(&InfoMsg,"Copy will be aborted"); InfoBox(ErrorNorm,ErrorInv," Copy ",InfoMsg,1,0,DOUBLE_FRAMED); free(CopyBuf); fclose(hfIn); fclose(hfOut); remove(OutFile); break; } /* Calcul du nombre de bytes restant a copier */ LeftToCopy -= BufSize; if(LeftToCopy < BufSize) BufSize = LeftToCopy; /* Rognage de la ligne temoin proportionnellement a ce qui a ete copie */ for(i=0; (i < 38 * (Temp->Info.s.st_size - LeftToCopy) / Temp->Info.s.st_size) && i < 38; i++) Line2[i] = ' '; Line2[i] = 0; WriteString(Line2,FileOpBar,11,22); } /* Rogner completement la ligne temoin */ for(i=0;i < 38;i++) Line2[i] = ' '; Line2[i] = 0; WriteString(Line2,FileOpBar,11,22); /* Fermer les fichiers s'in ne l'ont pas deja ete */ if(hfIn != (FILE *)NULL) fclose(hfIn); if(hfIn != (FILE *)NULL) fclose(hfOut); /* Liberer le buffer de copie */ if(CopyBuf != (char *)NULL) free(CopyBuf); /* Ajuster les permissions du nouveau fichier en fonction de celles de l'original */ if(chmod(OutFile,Temp->Info.s.st_mode) == -1) { if(ChWarn) { InitAnswerBoxItem(&Msg); InitAnswerBoxItem(&Choices); AddAnswerBoxItem(&Msg, "WARNING: impossible to adjust the copie's mode"); AddAnswerBoxItem(&Msg,"according to the original file."); AddAnswerBoxItem(&Choices," OK "); if(Nb != 1) AddAnswerBoxItem(&Choices,"Disable warning"); rc = AnswerBox(ErrorNorm,ErrorInv," Copy ",Msg,Choices,1,0, DOUBLE_FRAMED); if(rc == 2) ChWarn = 0; } } /* Ajuster les dates du nouveau fichier en fonction de celles de l'original */ tm.actime = Temp->Info.s.st_atime; tm.modtime = Temp->Info.s.st_mtime; if(utime(OutFile,&tm) == -1) { if(TmWarn) { InitAnswerBoxItem(&Msg); InitAnswerBoxItem(&Choices); AddAnswerBoxItem(&Msg, "WARNING: impossible to adjust the copie's time"); AddAnswerBoxItem(&Msg, "specifications according to the original file."); AddAnswerBoxItem(&Choices," OK "); if(Nb != 1) AddAnswerBoxItem(&Choices,"Disable warning"); rc = AnswerBox(ErrorNorm,ErrorInv," Copy ",Msg,Choices,1,0, DOUBLE_FRAMED); if(rc == 2) TmWarn = 0; } } /* Reset du nom cible */ OutFile[0] = 0; } } } chdir(CurrentPath); FreeAllTheList(&List); return(0); } /***************************************************************************** Copy() ------------------------------------------------------------------------------ Fonction de copie de fichiers *****************************************************************************/ void Copy(void) { char Target[PATH_LENGTH + 1], /* Cible proposee dans l'Input Box */ CopyMsg[80], /* Message de l'Input Box */ InFile[FILENAME_LENGTH], /* Specification complete du fichier source */ OutFile[FILENAME_LENGTH], /* Specification complete du fichier destinnation */ Line[39], /* Ligne de C_DESKTOP lors de la copie */ Line2[39], /* Ligne d'espace rognant Line */ DestFile[FILENAME_LENGTH], /* Fichier destination pour la boite Warning */ TargetDir[FILENAME_LENGTH]; /* Ss-rep cible de la copie */ int Nb, /* Nbre de fichiers a copier */ NbTag, /* Nbre de fichiers marques dans le ss-rep actif */ BufSize, /* Taille du buffer de copie */ LeftToCopy, /* Nbre de bytes encore a copier */ All = 0, /* Temoin de reponse "All" si fichier deja existant dans le ss-rep cible */ rc, /* Code de retour des boites de dialogue */ i, /* Compteurs */ ChWarn = 1, /* Temoin de warning si chmod == -1 */ TmWarn = 1, /* Temoin de warning si utime == -1 */ Recursive, TWin; /* Numero de la fenetre cible de la copie */ struct stat s; /* Recupere les caracteristiques du fichier source */ char *CopyBuf = (char *)NULL; /* Tampon de copie */ struct utimbuf tm; /* Pour rectifier les dates de la copie */ /* Boites de dialogue */ AnswerBoxItem_t *Msg = (AnswerBoxItem_t *)NULL, *Choices = (AnswerBoxItem_t *)NULL; ListBoxItem_t *TargetList = (ListBoxItem_t *)NULL; FILE *hfIn,*hfOut; /* Pointeurs de fichiers In et Out */ /* Construire la ligne temoin de l'operation de copie */ for(i=0;i<38;i++) Line[i] = C_DESKTOP; Line[i] = 0; /* Recuperer le nombre de fichiers marques */ GetNbTagged(List[AL],&NbTag,&i); Nb = NbTag; if(Nb == 0 && strcmp(Current[AL]->Info.Name,"..") == 0) { InitAnswerBoxItem(&InfoMsg); AddAnswerBoxItem(&InfoMsg,"The file '..' cannot"); AddAnswerBoxItem(&InfoMsg,"be copied anywhere."); InfoBox(ErrorNorm,ErrorInv," Copy ",InfoMsg,0,0,DOUBLE_FRAMED); return; } /* Determiner la destinnation presumee de la copie: - si deux fenetres, c'est la fenetre opposee - sinon, proposer une boite de liste avec les destinations possibles */ if(NbWins == 2) { TWin = !AL; strcpy(Target,WorkingDir[TWin]); } else { for(i=0;iInfo.s.st_mode)) { if(strlen(Current[AL]->Info.Name + 1) < 50) strcpy(DummyStr,Current[AL]->Info.Name + 1); else { strcpy(DummyStr,"/..."); strcat(DummyStr,Current[AL]->Info.Name + (strlen(Current[AL]->Info.Name) - 43)); } Recursive = 1; } else { if(strlen(Current[AL]->Info.Name) < 50) strcpy(DummyStr,Current[AL]->Info.Name); else { strcpy(DummyStr,"/..."); strcat(DummyStr,Current[AL]->Info.Name + (strlen(Current[AL]->Info.Name) - 43)); } Recursive = 0; } sprintf(CopyMsg,"Copy \"%s\" to",DummyStr); } /* Saisir la cible */ if(InputBoxCB(Target,PATH_LENGTH,FileOpNorm,FileOpInv," Copy ",CopyMsg, RecursiveStr,&Recursive,0,0,DOUBLE_FRAMED) != 0) return; /* Si aucun fichier marques, on marque le fichier en inverse et on incremente le nombre de fichiers a copier */ if(Nb == 0) { Current[AL]->Info.Tagged = 1; Nb = 1; } /* Scanner la cible pour des wildcards, qui sont interdites */ if(strchr(Target,'*') != NULL || strchr(Target,'?') != NULL) { InitAnswerBoxItem(&InfoMsg); AddAnswerBoxItem(&InfoMsg,"You cannot use wildcards"); AddAnswerBoxItem(&InfoMsg,"to specify a copy target."); InfoBox(ErrorNorm,ErrorInv," Copy ",InfoMsg,0,0,DOUBLE_FRAMED); if(NbTag == 0) Current[AL]->Info.Tagged = 0; return; } /* Analyse de la cible */ if(NbTag > 0) { /* copie de plusieurs fichiers: la cible doit etre un ss-rep */ if(stat(Target,&s) != 0 || !IS_DIR(s.st_mode)) { InitAnswerBoxItem(&InfoMsg); AddAnswerBoxItem(&InfoMsg,"ERROR: Invalid target specification:"); sprintf(DummyStr,"\"%s\"",Target); AddAnswerBoxItem(&InfoMsg,DummyStr); AddAnswerBoxItem(&InfoMsg, "The target directory doesn't exist or cannot be accessed,"); AddAnswerBoxItem(&InfoMsg, "or you're trying to copy multiple files to a single one."); InfoBox(ErrorNorm,ErrorInv," Copy ",InfoMsg,0,0,DOUBLE_FRAMED); return; } else strcpy(TargetDir,Target); } else { /* Copie d'un fichier ou d'un ss-rep */ if(stat(Target,&s) == 0) { /* La cible existe: directory ou fichier ? */ if(IS_DIR(s.st_mode)) { strcpy(DestFile,Current[AL]->Info.Name); /* Chercher le ss-rep cible dans le ss-rep courant */ for(Dummy = List[AL]; Dummy != (DirList_t *)NULL && strcmp((Dummy->Info.Name) + 1,Target) != 0; Dummy = Dummy->Suivant); if(Dummy == (DirList_t *)NULL) { /* Absent: copier vers un ss-rep situe dans un autre ss-rep */ strcpy(OutFile,Target); if(OutFile[strlen(OutFile) - 1] != PATH_SEPARATOR_CHAR) strcat(OutFile,PATH_SEPARATOR_STR); if(IS_DIR(Current[AL]->Info.s.st_mode)) strcat(OutFile,(Current[AL]->Info.Name) + 1); else strcat(OutFile,Current[AL]->Info.Name); strcpy(TargetDir,Target); } else { /* Trouve: le ss-rep cible se trouve dans le ss-rep courant */ strcpy(TargetDir,WorkingDir[AL]); strcpy(OutFile,TargetDir); if(OutFile[strlen(OutFile) - 1] != PATH_SEPARATOR_CHAR) strcat(OutFile,PATH_SEPARATOR_STR); strcat(OutFile,Target); } } else { /* Simple fichier deja existant, le laisser comme tel */ Analyse(Target,TargetDir,DestFile); if(strcmp(TargetDir,".") == 0) strcpy(TargetDir,WorkingDir[AL]); strcpy(OutFile,TargetDir); if(OutFile[strlen(OutFile) - 1] != PATH_SEPARATOR_CHAR) strcat(OutFile,PATH_SEPARATOR_STR); strcat(OutFile,DestFile); } } else { /* La cible n'existe pas, c'est donc un simple fichier innexistant */ Analyse(Target,TargetDir,DestFile); if(strcmp(TargetDir,".") == 0) strcpy(TargetDir,WorkingDir[AL]); strcpy(OutFile,TargetDir); if(OutFile[strlen(OutFile) - 1] != PATH_SEPARATOR_CHAR) strcat(OutFile,PATH_SEPARATOR_STR); strcat(OutFile,DestFile); } } /* Ouvrir la fenetre temoin de copie */ OpenWin(5,16,9,50,FileOpNorm,UNFRAMED,SHADED); PaintWin(6,19,7,44,FileOpNorm,DOUBLE_FRAMED,UNSHADED); WriteString(" Copy ",FileOpNorm,6,38); WriteString("Copying the file or directory",FileOpNorm,7,26); WriteString("to",FileOpNorm,9,39); GotoXY(AfficheY,AfficheX); /* Boucle de copie parcourant la liste active */ for(Dummy = List[AL]; Dummy != (DirList_t *)NULL; Dummy = Dummy->Suivant) if(Dummy->Info.Tagged) { /* Touche clavier enregistree: interrompre la boucle ? */ if(KeyPressed()) { ReadKbd(); InitAnswerBoxItem(&Msg); InitAnswerBoxItem(&Choices); AddAnswerBoxItem(&Msg,"Copy interrupted by user."); AddAnswerBoxItem(&Msg," Do you wish to cancel the copy cycle? "); AddAnswerBoxItem(&Choices,"Cancel"); AddAnswerBoxItem(&Choices,"Resume"); rc = AnswerBox(ConfirmNorm,ConfirmInv," Copy ",Msg,Choices, 2,0,DOUBLE_FRAMED); InitAnswerBoxItem(&Msg); InitAnswerBoxItem(&Choices); if(rc == 1) break; } /* Ne pas copier les liens symboliques */ if(IS_SYMLINK(Dummy->Info.s.st_mode)) { Dummy->Info.Tagged = 0; continue; } /* Construire les specifications completes de fichiers */ strcpy(InFile,WorkingDir[AL]); if(InFile[strlen(InFile) - 1] != PATH_SEPARATOR_CHAR) strcat(InFile,PATH_SEPARATOR_STR); if(IS_DIR(Dummy->Info.s.st_mode)) strcat(InFile,(Dummy->Info.Name) + 1); else strcat(InFile,Dummy->Info.Name); if(NbTag > 0) { strcpy(OutFile,TargetDir); if(OutFile[strlen(OutFile) - 1] != PATH_SEPARATOR_CHAR) strcat(OutFile,PATH_SEPARATOR_STR); if(IS_DIR(Dummy->Info.s.st_mode)) strcat(OutFile,(Dummy->Info.Name) + 1); else strcat(OutFile,Dummy->Info.Name); } /* Recuperer les caracteristiques du fichier source */ stat(InFile,&s); /* Si fichier vide, on passe */ if(s.st_size == 0) { Dummy->Info.Tagged = 0; continue; } /* Afficher source et destination */ SetCurrentAtt(FileOpNorm); SetString(8,20,42,' '); if(strlen(Dummy->Info.Name) < 40) WriteString(Dummy->Info.Name,FileOpNorm,8, 40 - (strlen(Dummy->Info.Name) / 2)); else { strcpy(DummyStr,"/..."); strcat(DummyStr,Dummy->Info.Name + (strlen(Dummy->Info.Name) - 33)); WriteString(DummyStr,FileOpNorm,8, 40 - (strlen(DummyStr) / 2)); } SetString(10,20,42,' '); if(strlen(OutFile) < 40) WriteString(OutFile,FileOpNorm,10, 40 - (strlen(OutFile) / 2)); else { strcpy(DummyStr,"/..."); strcat(DummyStr,OutFile + (strlen(OutFile) - 33)); WriteString(DummyStr,FileOpNorm,10, 40 - (strlen(DummyStr) / 2)); } WriteString(Line,FileOpNorm,11,22); /* Copie cyclique ? */ if(strcmp(InFile,OutFile) == 0) { InitAnswerBoxItem(&InfoMsg); AddAnswerBoxItem(&InfoMsg,"ERROR: a file cannot be copied to itself."); strcpy(DummyStr,"From: "); strcat(DummyStr,InFile); AddAnswerBoxItem(&InfoMsg,DummyStr); strcpy(DummyStr,"To: "); strcat(DummyStr,OutFile); AddAnswerBoxItem(&InfoMsg,DummyStr); AddAnswerBoxItem(&InfoMsg,"Copy cycle will be aborted."); InfoBox(ErrorNorm,ErrorInv," Copy ",InfoMsg,1,0,DOUBLE_FRAMED); break; } if(IS_DIR(s.st_mode)) { if(!Recursive) { Dummy->Info.Tagged = 0; continue; } if(NbTag > 0) { strcpy(DummyStr,TargetDir); if(strcmp(DummyStr,PATH_SEPARATOR_STR) == 0) DummyStr[0] = 0; strcat(DummyStr,Dummy->Info.Name); } else { strcpy(DummyStr,OutFile); } if(access(DummyStr,00) != 0) if(mkdir(DummyStr,S_IREAD|S_IWRITE|S_IEXEC) == -1) { InitAnswerBoxItem(&InfoMsg); AddAnswerBoxItem(&InfoMsg, "ERROR: impossible to create the directory"); AddAnswerBoxItem(&InfoMsg,DummyStr); switch(errno) { case ENOTDIR: case ENOENT: case ENOLINK: AddAnswerBoxItem(&InfoMsg,"Invalid directory specification."); break; case EMULTIHOP: AddAnswerBoxItem(&InfoMsg,"Multiple remote machines link."); break; case EACCES: AddAnswerBoxItem(&InfoMsg,"Permission denied."); break; case EEXIST: AddAnswerBoxItem(&InfoMsg,"The directory already exists."); break; case EROFS: AddAnswerBoxItem(&InfoMsg,"File system is read-only."); break; case EMLINK: AddAnswerBoxItem(&InfoMsg,"Maximum number of links exceeded."); break; case EIO: AddAnswerBoxItem(&InfoMsg,"An I/O error has occured."); break; default: sprintf(DummyStr,"Unknown reason (errno %d).",errno); AddAnswerBoxItem(&InfoMsg,DummyStr); } InfoBox(ErrorNorm,ErrorInv," Create Directory ",InfoMsg,1,0, DOUBLE_FRAMED); InitAnswerBoxItem(&InfoMsg); continue; } Dummy->Info.Tagged = 0; if(CopyDir(Dummy->Info.Name,DummyStr) == -1) break; } else { /* Tester la presence de ce fichier a la cible */ if(!All) { if(access(OutFile,00) == 0) { InitAnswerBoxItem(&Choices); InitAnswerBoxItem(&Msg); if(NbTag > 0) strcpy(DestFile,Dummy->Info.Name); sprintf(DummyStr,"WARNING: the file \"%s\"",DestFile); AddAnswerBoxItem(&Msg,DummyStr); AddAnswerBoxItem(&Msg,"already exists in the target directory"); AddAnswerBoxItem(&Msg,TargetDir); AddAnswerBoxItem(&Msg," Do you wish to overwrite the old file? "); AddAnswerBoxItem(&Choices,"Overwrite"); AddAnswerBoxItem(&Choices,"All"); AddAnswerBoxItem(&Choices,"Skip"); AddAnswerBoxItem(&Choices,"Cancel"); rc = AnswerBox(ConfirmNorm,ConfirmInv," Copy ",Msg,Choices, 2,0,DOUBLE_FRAMED); InitAnswerBoxItem(&Choices); InitAnswerBoxItem(&Msg); if(rc == 2) All = 1; if(rc == 3) continue; if(rc == 4 || rc == -1) break; } } /* Calcul de la taille du buffer de copie */ LeftToCopy = BufSize = s.st_size; if(BufSize > COPY_BUF_SIZE) BufSize = COPY_BUF_SIZE; /* Allocation du buffer de copie */ if(BufSize > 0) if((CopyBuf = (char *)malloc(BufSize)) == (char *)NULL) { InitAnswerBoxItem(&InfoMsg); AddAnswerBoxItem(&InfoMsg,"Not enough memory to copy the file"); AddAnswerBoxItem(&InfoMsg,InFile); InfoBox(ErrorNorm,ErrorInv," Copy ",InfoMsg,1,0,DOUBLE_FRAMED); continue; } /* Ouverture du fichier source */ if((hfIn = fopen(InFile,"r")) == (FILE *)NULL) { InitAnswerBoxItem(&InfoMsg); AddAnswerBoxItem(&InfoMsg,"I cannot open input file"); AddAnswerBoxItem(&InfoMsg,InFile); switch(errno) { case EACCES: AddAnswerBoxItem(&InfoMsg,"Permission denied."); break; case EAGAIN: AddAnswerBoxItem(&InfoMsg,"File is locked."); break; case EEXIST: AddAnswerBoxItem(&InfoMsg,"File exists."); break; case EIO: AddAnswerBoxItem(&InfoMsg,"I/O error."); break; case EMULTIHOP: AddAnswerBoxItem(&InfoMsg,"Multiple remote machines link."); break; case EMFILE: AddAnswerBoxItem(&InfoMsg,"No file descriptor."); break; case ENFILE: AddAnswerBoxItem(&InfoMsg,"File table is full."); break; case ENOLINK: AddAnswerBoxItem(&InfoMsg,"Remote system unavailible."); break; case ENOMEM: AddAnswerBoxItem(&InfoMsg,"Out of memory."); break; case ENOSPC: AddAnswerBoxItem(&InfoMsg,"Out of inodes."); break; case ENOENT: case ENOTDIR: AddAnswerBoxItem(&InfoMsg,"Invalid file specification."); break; case ENXIO: AddAnswerBoxItem(&InfoMsg,"Stream device failure."); break; case EROFS: AddAnswerBoxItem(&InfoMsg,"File system is read-only."); break; case ETXTBSY: AddAnswerBoxItem(&InfoMsg,"Text file busy."); break; default: sprintf(DummyStr,"Unknown reason (errno %d).",errno); AddAnswerBoxItem(&InfoMsg,DummyStr); break; } InfoBox(ErrorNorm,ErrorInv," Copy ",InfoMsg,1,0,DOUBLE_FRAMED); if(CopyBuf != (char *)NULL) free(CopyBuf); continue; } /* Ouvrir le fichier cible */ if((hfOut = fopen(OutFile,"w")) == (FILE *)NULL) { InitAnswerBoxItem(&InfoMsg); AddAnswerBoxItem(&InfoMsg,"I cannot open output file"); AddAnswerBoxItem(&InfoMsg,OutFile); switch(errno) { case EACCES: AddAnswerBoxItem(&InfoMsg,"Permission denied."); break; case EAGAIN: AddAnswerBoxItem(&InfoMsg,"File is locked."); break; case EEXIST: AddAnswerBoxItem(&InfoMsg,"File exists."); break; case EIO: AddAnswerBoxItem(&InfoMsg,"I/O error."); break; case EMULTIHOP: AddAnswerBoxItem(&InfoMsg,"Multiple remote machines link."); break; case EMFILE: AddAnswerBoxItem(&InfoMsg,"No file descriptor."); break; case ENFILE: AddAnswerBoxItem(&InfoMsg,"File table is full."); break; case ENOLINK: AddAnswerBoxItem(&InfoMsg,"Remote system unavailible."); break; case ENOMEM: AddAnswerBoxItem(&InfoMsg,"Out of memory."); break; case ENOSPC: AddAnswerBoxItem(&InfoMsg,"Out of inodes."); break; case ENOENT: case ENOTDIR: AddAnswerBoxItem(&InfoMsg,"Invalid file specification."); break; case ENXIO: AddAnswerBoxItem(&InfoMsg,"Stream device failure."); break; case EROFS: AddAnswerBoxItem(&InfoMsg,"File system is read-only."); break; case ETXTBSY: AddAnswerBoxItem(&InfoMsg,"Text file busy."); break; default: sprintf(DummyStr,"Unknown reason (errno %d).",errno); AddAnswerBoxItem(&InfoMsg,DummyStr); break; } InfoBox(ErrorNorm,ErrorInv," Copy ",InfoMsg,1,0,DOUBLE_FRAMED); if(CopyBuf != (char *)NULL) free(CopyBuf); fclose(hfIn); continue; } /* Boucle de copie d'un fichier bloc par bloc */ while(LeftToCopy > 0) { /* Lire un bloc */ if(fread(CopyBuf,1,BufSize,hfIn) != BufSize) { InitAnswerBoxItem(&InfoMsg); AddAnswerBoxItem(&InfoMsg,"ERROR reading from input file"); AddAnswerBoxItem(&InfoMsg,InFile); AddAnswerBoxItem(&InfoMsg,"Copy will be aborted"); InfoBox(ErrorNorm,ErrorInv," Copy ",InfoMsg,1,0,DOUBLE_FRAMED); free(CopyBuf); fclose(hfIn); fclose(hfOut); remove(OutFile); break; } /* Ecrire un bloc */ if(fwrite(CopyBuf,1,BufSize,hfOut) != BufSize) { InitAnswerBoxItem(&InfoMsg); AddAnswerBoxItem(&InfoMsg,"ERROR writing to output file"); AddAnswerBoxItem(&InfoMsg,InFile); AddAnswerBoxItem(&InfoMsg,"Copy will be aborted"); InfoBox(ErrorNorm,ErrorInv," Copy ",InfoMsg,1,0,DOUBLE_FRAMED); free(CopyBuf); fclose(hfIn); fclose(hfOut); remove(OutFile); break; } /* Calcul du nombre de bytes restant a copier */ LeftToCopy -= BufSize; if(LeftToCopy < BufSize) BufSize = LeftToCopy; /* Rognage de la ligne temoin proportionnellement a ce qui a ete copie */ for(i=0; (i < 38 * (s.st_size - LeftToCopy) / s.st_size) && i < 38; i++) Line2[i] = ' '; Line2[i] = 0; WriteString(Line2,FileOpBar,11,22); } /* Rogner completement la ligne temoin */ for(i=0;i < 38;i++) Line2[i] = ' '; Line2[i] = 0; WriteString(Line2,FileOpBar,11,22); /* Fermer les fichiers s'in ne l'ont pas deja ete */ if(hfIn != (FILE *)NULL) fclose(hfIn); if(hfIn != (FILE *)NULL) fclose(hfOut); /* Liberer le buffer de copie */ if(CopyBuf != (char *)NULL) free(CopyBuf); /* Deselectionner le fichier venant d'etre copie */ Dummy->Info.Tagged = 0; /* Ajuster les permissions du nouveau fichier en fonction de celles de l'original */ if(chmod(OutFile,Dummy->Info.s.st_mode) == -1) { if(ChWarn) { InitAnswerBoxItem(&Msg); InitAnswerBoxItem(&Choices); AddAnswerBoxItem(&Msg, "WARNING: impossible to adjust the copie's mode"); AddAnswerBoxItem(&Msg,"according to the original file."); AddAnswerBoxItem(&Choices," OK "); if(Nb != 1) AddAnswerBoxItem(&Choices,"Disable warning"); rc = AnswerBox(ErrorNorm,ErrorInv," Copy ",Msg,Choices,1,0, DOUBLE_FRAMED); if(rc == 2) ChWarn = 0; } } /* Ajuster les dates du nouveau fichier en fonction de celles de l'original */ tm.actime = Dummy->Info.s.st_atime; tm.modtime = Dummy->Info.s.st_mtime; if(utime(OutFile,&tm) == -1) { if(TmWarn) { InitAnswerBoxItem(&Msg); InitAnswerBoxItem(&Choices); AddAnswerBoxItem(&Msg, "WARNING: impossible to adjust the copie's time"); AddAnswerBoxItem(&Msg, "specifications according to the original file."); AddAnswerBoxItem(&Choices," OK "); if(Nb != 1) AddAnswerBoxItem(&Choices,"Disable warning"); rc = AnswerBox(ErrorNorm,ErrorInv," Copy ",Msg,Choices,1,0, DOUBLE_FRAMED); if(rc == 2) TmWarn = 0; } } /* Reset du nom cible */ OutFile[0] = 0; } } /* Fermeture de la fenetre temoin */ CloseWin(); /* Supprimer le faux marquage */ if(NbTag == 0) Current[AL]->Info.Tagged = 0; /* Reset affichage */ for(i=0;i