1 /***************************************************************************/
2 /* */
3 /* Fast Webpage Exchanger - an FTP client for updating webpages */
4 /* Copyright (C) 1999-2000 Yuuki NINOMIYA <gm@debian.or.jp> */
5 /* */
6 /* This program is free software; you can redistribute it and/or modify */
7 /* it under the terms of the GNU General Public License as published by */
8 /* the Free Software Foundation; either version 2, or (at your option) */
9 /* any later version. */
10 /* */
11 /* This program is distributed in the hope that it will be useful, */
12 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
13 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
14 /* GNU General Public License for more details. */
15 /* */
16 /* You should have received a copy of the GNU General Public License */
17 /* along with this program; if not, write to the */
18 /* Free Software Foundation, Inc., 59 Temple Place - Suite 330, */
19 /* Boston, MA 02111-1307, USA. */
20 /* */
21 /***************************************************************************/
22
23 #ifdef HAVE_CONFIG_H
24 # include "config.h"
25 #endif
26
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <dirent.h>
30 #include <string.h>
31 #include <time.h>
32 #include <ctype.h>
33 #include <sys/stat.h>
34 #include "intl.h"
35 #include "strlib.h"
36 #include "variable.h"
37 #include "proto.h"
38
39 #ifndef PATH_MAX
40 # define PATH_MAX 512
41 #endif /* PATH_MAX */
42
43
44 /* --------------------------------------------------
45 NAME get_local_file_data
46 FUNCTION get the data of local files
47 INPUT local_data ... pointer to stored date
48 OUTPUT the maximum number of local files
49 -------------------------------------------------- */
get_local_file_data(FileData ** local_data)50 int get_local_file_data(FileData **local_data)
51 {
52 DIR *dir;
53 struct dirent *ent;
54 struct stat file_stat;
55 struct tm *ftime;
56 char time_temp[10];
57 char date_temp[10];
58 int isdir;
59 int file_num=0;
60 int i;
61
62 dir=opendir(".");
63 while((ent=readdir(dir))!=NULL){
64 if(strcmp(ent->d_name,".")==0 || strcmp(ent->d_name,"..")==0){
65 continue;
66 }
67 lstat(ent->d_name,&file_stat);
68
69 /* follow symlinks */
70 if (follow_symlinks[host_number] && (file_stat.st_mode & S_IFLNK)==S_IFLNK){
71 char realfname[PATH_MAX];
72
73 DebugPrint((stderr,"Local symlink is detected: %s\n",ent->d_name));
74 if(realpath(ent->d_name,realfname)==NULL){
75 char *temp;
76
77 fprintf(stderr,_("Cannot expand symbolic link `%s'. Ignore this file.\n"),ent->d_name);
78 temp=str_dup_printf(_("Expanding symbolic link failed: %s"),ent->d_name);
79 log_write(temp);
80 free(temp);
81 continue;
82 }
83 stat(realfname,&file_stat);
84 DebugPrint((stderr,"Realfname is %s\n",realfname));
85 }
86 isdir = ((file_stat.st_mode & S_IFDIR) == S_IFDIR);
87 ftime=gmtime(&file_stat.st_mtime);
88
89 if(isdir){
90 if(is_ignore_dir(ent->d_name,LOCAL)){
91 DebugPrint((stderr,"Ignore local dir: %s\n",ent->d_name));
92 continue;
93 }
94 }else{
95 if(is_ignore_file(ent->d_name,LOCAL)){
96 DebugPrint((stderr,"Ignore local file: %s\n",ent->d_name));
97 continue;
98 }
99 }
100
101 sprintf(date_temp,"%04d%02d%02d",1900+ftime->tm_year,ftime->tm_mon+1,ftime->tm_mday);
102 sprintf(time_temp,"%02d%02d%02d",ftime->tm_hour,ftime->tm_min,ftime->tm_sec);
103
104 *local_data=str_realloc(*local_data,sizeof(**local_data)*(file_num+1));
105 (*local_data)[file_num].date=atol(date_temp);
106 (*local_data)[file_num].time=atol(time_temp);
107 (*local_data)[file_num].isdir=isdir;
108 (*local_data)[file_num].name=str_dup(ent->d_name);
109
110 DebugPrint((stderr,"Local: [%08ld] [%06ld] [%08o] [%d] [%s]\n",(*local_data)[file_num].date,(*local_data)[file_num].time,file_stat.st_mode,(*local_data)[file_num].isdir,(*local_data)[file_num].name));
111
112 if(conv_to_lower[host_number]){
113 for(i=0;i<file_num;i++){
114 if(strcasecmp((*local_data)[file_num].name,(*local_data)[i].name)==0){
115 char *temp;
116
117 fprintf(stderr,_("ConvToLower causes a conflict between `%s' and `%s'. Proceed anyway.\n"),(*local_data)[i].name,(*local_data)[file_num].name);
118
119 temp=str_dup_printf(_("Confliction by ConvToLower: %s"),(*local_data)[i].name);
120 log_write(temp);
121 free(temp);
122 }
123 }
124 }
125
126 file_num++;
127 }
128 closedir(dir);
129 return(file_num);
130 }
131
132
133 /* --------------------------------------------------
134 NAME get_remote_file_data
135 FUNCTION get the data of remote files
136 INPUT remote_data ... pointer to stored date
137 OUTPUT the maximum number of remote files
138 -------------------------------------------------- */
get_remote_file_data(FileData ** remote_data)139 int get_remote_file_data(FileData **remote_data)
140 {
141 char list_temp[32];
142 int fd;
143 FILE *fp;
144 char *fgets_temp;
145 char *file_name;
146 long date,mtime;
147 char mod_temp[20];
148 char dir_flag;
149 char *temp;
150 int *add_cache_num=NULL;
151 int add_cache_files=0;
152 int file_num=0;
153 int i;
154
155 if(strcmp(current_dir[REMOTE],dest_dir[host_number])!=0){
156 change_dir_actually(REMOTE);
157 }
158 strcpy(list_temp, "/tmp/weexXXXXXX");
159 fd=mkstemp(list_temp);
160 if(fd==-1){
161 fprintf(stderr,_("Cannot create a unique file name.\n"));
162 ftp_disconnect();
163 exit(1);
164 }
165
166 if((show_hidden_file[host_number] && FtpDir(list_temp,"-a",ftp_buf)==0) ||
167 (!show_hidden_file[host_number] && FtpDir(list_temp,NULL,ftp_buf)==0)){
168 fprintf(stderr,_("Cannot get remote directory list.\n"));
169 log_write(_("Getting remote directory list failed"));
170 ftp_disconnect();
171 exit(1);
172 }
173 fp=fdopen(fd,"r");
174 if(fp==NULL){
175 fprintf(stderr,_("Cannot open `%s'.\n"),list_temp);
176 ftp_disconnect();
177 exit(1);
178 }
179
180 while((fgets_temp=str_fgets(fp))!=NULL){
181 if(strncmp(fgets_temp,"total",5)==0){
182 free(fgets_temp);
183 continue;
184 }
185
186 DebugPrint((stderr,"Remote: %s\n",fgets_temp));
187
188 dir_flag=parse_file_and_filetype(fgets_temp,&file_name);
189
190 free(fgets_temp);
191
192 /*
193 Test to which this entry is directory or file.
194 This way is very dirty and slow.
195 */
196 if(dir_flag=='l'){
197 DebugPrint((stderr,"Remote symlink is detected: %s\n",file_name));
198 dir_flag=FtpChdir(file_name,ftp_buf) ? 'd' : '-';
199 FtpChdir(current_dir[REMOTE], ftp_buf);
200 DebugPrint((stderr,"Symlink type is '%c'\n",dir_flag));
201 }
202
203 if(strcmp(file_name,".")==0 ||
204 strcmp(file_name,"..")==0 ||
205 (dir_flag=='d' && is_ignore_dir(file_name,REMOTE)) ||
206 (dir_flag!='d' && is_ignore_file(file_name,REMOTE)) ){
207 DebugPrint((stderr,"[%c] Ignore remote `%s'\n",dir_flag,file_name));
208 free(file_name);
209 continue;
210 }
211
212 date=mtime=0;
213 if(dir_flag!='d'){
214 if(conv_to_lower[host_number]){
215 temp=str_tolower(file_name);
216 DebugPrint((stderr,"conv_to_lower from `%s' to `%s'\n",file_name,temp));
217 free(file_name);
218 file_name=temp;
219 }
220 if(get_cache(file_name,&date,&mtime)==-1){
221 DebugPrint((stderr,"No cache: %s\n",file_name));
222 if(FtpModDate(file_name,mod_temp,20,ftp_buf)==1){
223 date=n_atol(mod_temp,8);
224 mtime=n_atol(mod_temp+8,6);
225 add_cache_num=str_realloc(add_cache_num,sizeof(*add_cache_num)*(add_cache_files+1));
226 add_cache_num[add_cache_files++]=file_num;
227 } else {
228 /* Ignore the MDTM failure and store the current date */
229 /* it would be better to use the LIST date ... */
230 time_t curtime = time(NULL);
231 struct tm *tmcur = gmtime(&curtime);
232
233 date=(1900+tmcur->tm_year)*10000 + (tmcur->tm_mon+1)*100 + (tmcur->tm_mday);
234 mtime=tmcur->tm_hour*10000 + tmcur->tm_min*100 + tmcur->tm_sec;
235 add_cache_num=str_realloc(add_cache_num,sizeof(*add_cache_num)*(add_cache_files+1));
236 add_cache_num[add_cache_files++]=file_num;
237 }
238 }
239
240 }
241
242 *remote_data=str_realloc(*remote_data,sizeof(**remote_data)*(file_num+1));
243 (*remote_data)[file_num].date=date;
244 (*remote_data)[file_num].time=mtime;
245 (*remote_data)[file_num].isdir=(dir_flag=='d');
246 (*remote_data)[file_num].name=file_name;
247
248 DebugPrint((stderr,"Remote: [%08ld] [%06ld] [%c] [%d] [%s]\n",(*remote_data)[file_num].date,(*remote_data)[file_num].time,dir_flag,(*remote_data)[file_num].isdir,(*remote_data)[file_num].name));
249
250 file_num++;
251 }
252
253 for(i=0;i<add_cache_files;i++){
254 update_cache((*remote_data)[add_cache_num[i]].name,(*remote_data)[add_cache_num[i]].date,(*remote_data)[add_cache_num[i]].time);
255 DebugPrint((stderr,"Update cache `%s' : %ld %ld\n",(*remote_data)[add_cache_num[i]].name,(*remote_data)[add_cache_num[i]].date,(*remote_data)[add_cache_num[i]].time));
256 }
257
258 fclose(fp);
259 if(remove(list_temp)==-1){
260 fprintf(stderr,_("Cannot remove `%s'.\n"),list_temp);
261 ftp_disconnect();
262 exit(1);
263 }
264 free(add_cache_num);
265 /* free(list_temp); */
266 return(file_num);
267 }
268
269
270 /* --------------------------------------------------
271 NAME free_file_data
272 FUNCTION release memory stored file data
273 INPUT file_data ... file data
274 max_file_data ... the maximum number of file data
275 OUTPUT none
276 -------------------------------------------------- */
free_file_data(FileData * file_data,int max_file_data)277 void free_file_data(FileData *file_data,int max_file_data)
278 {
279 int i;
280
281 for(i=0;i<max_file_data;i++){
282 free(file_data[i].name);
283 }
284 free(file_data);
285 }
286
287
288 /* --------------------------------------------------
289 NAME parse_file_and_filetype
290 FUNCTION parse file and filetype (whether dir) from file list
291 INPUT str .... file list (a single line)
292 file ... pointer to stored file name
293 OUTPUT dir_flag ... directory is 'd'
294 symlink is 'l'
295 others are '-'
296 return -1 if error
297 -------------------------------------------------- */
parse_file_and_filetype(char * str,char ** file)298 int parse_file_and_filetype(char *str,char **file)
299 {
300 char dir_flag;
301 int i;
302 char *ptr;
303 char *lnktmp;
304
305 ptr=strtok(str," ");
306 if(ptr==NULL){
307 fprintf(stderr,_("Cannot get the remote directory list correctly.\n"));
308 ftp_disconnect();
309 exit(1);
310 }
311 if(isdigit(*ptr) && isdigit(*(ptr+1)) && *(ptr+2)=='-'){ /* Remote system type is Windows_NT */
312 for(i=0;i<2;i++){
313 if((ptr=strtok(NULL," "))==NULL){
314 fprintf(stderr,_("Cannot get the remote directory list correctly.\n"));
315 ftp_disconnect();
316 exit(1);
317 }
318 }
319 dir_flag=(strcmp(ptr,"<DIR>")==0) ? 'd' : '-';
320 }else{ /* Remote system type is UNIX or MACOS */
321 dir_flag=str[0];
322
323 for(i=0;i<7;i++){
324 if((ptr=strtok(NULL," "))==NULL){
325 fprintf(stderr,_("Cannot get the remote directory list correctly.\n"));
326 ftp_disconnect();
327 exit(1);
328 }
329 if((i==0 && strcmp(ptr,"folder")==0) ||
330 (i==1 && strcmp(ptr,"0000/0000")==0) ||
331 (i==3 && isupper(*ptr) && islower(*(ptr+1)) && islower(*(ptr+2)) && *(ptr+3)=='\0')){
332 i++;
333 }
334 }
335 }
336 ptr=ptr+strlen(ptr)+1;
337 if((lnktmp=strstr(ptr," -> "))!=NULL){ /* This file is a symbolic link. */
338 *lnktmp='\0';
339 }
340
341 /* Strip leading spaces from the filename which can occur
342 with an FTP server based on Windows NT */
343 while (*ptr == ' '){
344 ptr++;
345 }
346
347 *file=str_dup(ptr);
348
349 return(dir_flag);
350 }
351
352
353 /* --------------------------------------------------
354 NAME is_ignore_dir
355 FUNCTION whether ???IgnoreDir or not
356 INPUT dir_name ... name of the directory
357 side ....... LOCAL or REMOTE
358 OUTPUT return 1 if match ???IgnoreDir otherwise return 0
359 -------------------------------------------------- */
is_ignore_dir(char * dir_name,LocalOrRemote side)360 int is_ignore_dir(char *dir_name,LocalOrRemote side)
361 {
362 cfgList *l;
363 char *temp;
364
365 if((side==LOCAL && ignore_local_dir[host_number]==NULL) || (side==REMOTE && ignore_remote_dir[host_number]==NULL)){
366 return(0);
367 }
368 temp=str_concat(current_dir[side],dir_name,"/",NULL);
369 if(side==LOCAL){
370 for(l=ignore_local_dir[host_number];l!=NULL;l=l->next){
371 if(cmp_file_with_wildcard(temp,l->str)==0){
372 free(temp);
373 return(1);
374 }
375 }
376 }else if(side==REMOTE){
377 for(l=ignore_remote_dir[host_number];l!=NULL;l=l->next){
378 if(cmp_file_with_wildcard(temp,l->str)==0){
379 free(temp);
380 return(1);
381 }
382 }
383 }
384 free(temp);
385 return(0);
386 }
387
388
389 /* --------------------------------------------------
390 NAME is_ignore_file
391 FUNCTION whether ???IgnoreFile or not
392 INPUT file_name ... file name
393 side ........ LOCAL or REMOTE
394 OUTPUT return 1 if match ???IgnoreFile otherwise return 0
395 -------------------------------------------------- */
is_ignore_file(char * file_name,LocalOrRemote side)396 int is_ignore_file(char *file_name,LocalOrRemote side)
397 {
398 cfgList *l;
399 char *temp;
400
401 if((side==LOCAL && ignore_local_file[host_number]==NULL) || (side==REMOTE && ignore_remote_file[host_number]==NULL)){
402 return(0);
403 }
404 temp=str_concat(current_dir[side],file_name,NULL);
405 if(side==LOCAL){
406 for(l=ignore_local_file[host_number];l!=NULL;l=l->next){
407 if(strchr(l->str,'/')==NULL){
408 if(cmp_file_with_wildcard(file_name,l->str)==0){
409 free(temp);
410 return(1);
411 }
412 }else{
413 if(cmp_file_with_wildcard(temp,l->str)==0){
414 free(temp);
415 return(1);
416 }
417 }
418 }
419 }else if(side==REMOTE){
420 for(l=ignore_remote_file[host_number];l!=NULL;l=l->next){
421 if(strchr(l->str,'/')==NULL){
422 if(cmp_file_with_wildcard(file_name,l->str)==0){
423 free(temp);
424 return(1);
425 }
426 }else{
427 if(cmp_file_with_wildcard(temp,l->str)==0){
428 free(temp);
429 return(1);
430 }
431 }
432 }
433 }
434 free(temp);
435 return(0);
436 }
437
438
439 /* --------------------------------------------------
440 NAME is_ascii_file
441 FUNCTION whether AsciiFile or not
442 INPUT file_name ... file name
443 OUTPUT return 1 if match AsciiFile otherwise return 0
444 -------------------------------------------------- */
is_ascii_file(char * file_name)445 int is_ascii_file(char *file_name)
446 {
447 cfgList *l;
448 char *temp;
449
450 if(ascii_file[host_number]==NULL){
451 return(0);
452 }
453 temp=str_concat(current_dir[LOCAL],file_name,NULL);
454 for(l=ascii_file[host_number];l!=NULL;l=l->next){
455 if(strchr(l->str,'/')==NULL){
456 if(cmp_file_with_wildcard(file_name,l->str)==0){
457 free(temp);
458 return(1);
459 }
460 }else{
461 if(cmp_file_with_wildcard(temp,l->str)==0){
462 free(temp);
463 return(1);
464 }
465 }
466 }
467 free(temp);
468 return(0);
469 }
470
471
472 /* --------------------------------------------------
473 NAME is_change_permission_dir
474 FUNCTION whether ChangePermissionDir or not
475 OUTPUT return 1 if match ChangePermissionDir otherwise return 0
476 -------------------------------------------------- */
is_change_permission_dir(void)477 int is_change_permission_dir(void)
478 {
479 cfgList *l;
480
481 if(change_permission_dir[host_number]==NULL){
482 return(0);
483 }
484 for(l=change_permission_dir[host_number];l!=NULL;l=l->next){
485 if(cmp_file_with_wildcard(current_dir[LOCAL],l->str)==0){
486 return(1);
487 }
488 }
489 return(0);
490 }
491
492
493 /* --------------------------------------------------
494 NAME is_preserve_permission_dir
495 FUNCTION whether PreservePermissionDir or not
496 OUTPUT return 1 if match PreservePermissionDir otherwise return 0
497 -------------------------------------------------- */
is_preserve_permission_dir(void)498 int is_preserve_permission_dir(void)
499 {
500 cfgList *l;
501
502 if(preserve_permission_dir[host_number]==NULL){
503 return(0);
504 }
505 for(l=preserve_permission_dir[host_number];l!=NULL;l=l->next){
506 if(cmp_file_with_wildcard(current_dir[LOCAL],l->str)==0){
507 return(1);
508 }
509 }
510 return(0);
511 }
512
513
514 /* --------------------------------------------------
515 NAME is_keep_remote_dir
516 FUNCTION whether KeepRemoteDir or not
517 OUTPUT return 1 if match KeepRemoteDir otherwise return 0
518 -------------------------------------------------- */
is_keep_remote_dir(void)519 int is_keep_remote_dir(void)
520 {
521 cfgList *l;
522
523 if(keep_remote_dir[host_number]==NULL){
524 return(0);
525 }
526 for(l=keep_remote_dir[host_number];l!=NULL;l=l->next){
527 if(cmp_file_with_wildcard(current_dir[REMOTE],l->str)==0){
528 return(1);
529 }
530 }
531 return(0);
532 }
533