Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/cmd/cs/vcs_src/ifs_ftp.c
1810 views
1
/***********************************************************************
2
* *
3
* This software is part of the ast package *
4
* Copyright (c) 1990-2011 AT&T Intellectual Property *
5
* and is licensed under the *
6
* Eclipse Public License, Version 1.0 *
7
* by AT&T Intellectual Property *
8
* *
9
* A copy of the License is available at *
10
* http://www.eclipse.org/org/documents/epl-v10.html *
11
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
12
* *
13
* Information and Software Systems Research *
14
* AT&T Research *
15
* Florham Park NJ *
16
* *
17
* Glenn Fowler <[email protected]> *
18
* *
19
***********************************************************************/
20
/*
21
* File: ifs_ftp.c
22
*/
23
24
#include "ifs_agent.h"
25
#include <stdio.h>
26
27
struct {
28
int version;
29
} ftp_data;
30
31
struct fileinfo {
32
char *fname;
33
char *info;
34
int ftype;
35
off_t fsize;
36
};
37
38
/*
39
* name: ftp_addentry
40
* Add a time entry of filename into timestamp
41
*/
42
int
43
ftp_addentry( fname, ftime )
44
char *fname;
45
time_t ftime;
46
{
47
FILE *flog, *fent;
48
char flogname[ STRLEN ];
49
char buf[ STRLEN ];
50
int len;
51
52
len = strlen( fname );
53
sfsprintf( flogname, sizeof(flogname), "._log.%d", ftime );
54
if( (flog = fopen( flogname, "w" )) == NULL ) {
55
return -1;
56
}
57
fprintf( flog, "%s %d\n", fname, ftime );
58
if( (fent = fopen( "._log", "r" )) != NULL ) {
59
while( fgets( buf, sizeof(buf), fent ) != NULL ) {
60
if( strncmp( buf, fname, len ) != 0 || buf[len] != ' ' ) {
61
fprintf( flog, "%s", buf );
62
}
63
}
64
fclose( fent );
65
}
66
fclose( flog );
67
rename( flogname, "._log" );
68
return 0;
69
}
70
71
/*
72
* name: ftp_doentry
73
* add a full-path file to timestamp
74
*/
75
int
76
ftp_doentry( filepath )
77
char *filepath;
78
{
79
struct stat st;
80
char *ptr;
81
82
if( (ptr = strrchr( filepath, '/' )) == NULL )
83
return -1;
84
*ptr = '\0';
85
chdir( filepath );
86
*ptr++ = '/';
87
if( stat( ptr, &st ) == -1 )
88
return -1;
89
ftp_addentry( ptr, st.st_mtime );
90
return 0;
91
}
92
93
/*
94
* name: ftp_log2hash
95
* read log timestamp into an new allocated hash table
96
*/
97
/*
98
HASHTABLE *
99
ftp_log2hash( logfile )
100
char *logfile;
101
{
102
HASHTABLE *htab;
103
FILE *fent;
104
char buf[ STRLEN ], *ptr;
105
106
htab = hashalloc( NULL, HASH_set, HASH_ALLOCATE, 0 );
107
if( (fent = fopen( logfile, "r" )) != NULL ) {
108
while( fgets( buf, sizeof(buf), fent ) != NULL ) {
109
if( (ptr = strchr( buf, ' ' )) != NULL ) {
110
*ptr++ = '\0';
111
hashput( htab, buf, ptr );
112
}
113
}
114
fclose( fent );
115
}
116
return htab;
117
}
118
*/
119
120
/*
121
* name: ftp_parselist
122
* parse the directory entry and check the file type.
123
* PS: support UNIX and NT ftp directory styles.
124
*/
125
int
126
ftp_parselist( fi, buf )
127
struct fileinfo *fi;
128
char *buf;
129
{
130
char *ptr;
131
132
strtok( buf, "\n\r" );
133
if( (ptr = strrchr( buf, ' ' )) == NULL )
134
return 0;
135
*ptr++ = '\0';
136
fi->fname = ptr;
137
fi->ftype = 0;
138
fi->fsize = 0;
139
switch( buf[0] ) {
140
/* -rw-rw-r-- 1 CSIE ftp 1509 Sep 14 08:31 README */
141
/* lrwxrwxrwx 1 CSIE ftp 8 Nov 14 1993 dir -> pub/dir */
142
/* drwxrwxr-x 25 CSIE ftp 1024 Jan 31 04:56 pub */
143
case 'd': fi->ftype = 1; /* unix directory */
144
case '-': /* unix regular file */
145
if( *(ptr - 14) == ' ' ) {
146
ptr -= 15;
147
while( *ptr != ' ' ) ptr--;
148
fi->fsize = (int)strtol( ptr+1, (char**)0, 0 );
149
}
150
break;
151
152
case 'l': fi->ftype = 2; /* unix link file */
153
fi->info = ptr;
154
if( (ptr = strrchr( buf, ' ' )) == NULL ||
155
strcmp( ptr, " ->" ) != 0 )
156
return 0;
157
*ptr = '\0';
158
fi->fname = strrchr( buf, ' ' ) + 1;
159
break;
160
161
/* 08-01-95 02:55PM 13280 ROCNTS1.DOC */
162
/* 08-01-95 02:55PM <DIR> DIR */
163
case '0': /* NT 3.0 file system */
164
case '1':
165
fi->ftype = (buf[25] == 'D' ? 1 : 0);
166
if( *(ptr - 2) != ' ' ) {
167
ptr -= 2;
168
while( *ptr != ' ' ) ptr--;
169
fi->fsize = (int)strtol( ptr+1, (char**)0, 0 );
170
}
171
break;
172
173
default: return 0;
174
}
175
return 1;
176
}
177
178
/*
179
* name: ftp_makedents
180
* make virtual name space from the directory list.
181
* PS: the mtime of invalid file is set to 4 years ago.
182
*/
183
int
184
ftp_makedents( tmpfile )
185
char *tmpfile;
186
{
187
struct fileinfo finfo;
188
time_t modtime;
189
char buf[ STRLEN ];
190
FILE *fdir, *fent;
191
192
modtime = cs.time - 86400 * (365 * 4 + 1);
193
if( (fdir = fopen( tmpfile, "r" )) == NULL )
194
return -1;
195
fent = fopen( "._log", "w" );
196
while( fgets( buf, sizeof( buf ), fdir ) != NULL ) {
197
if( ftp_parselist( &finfo, buf ) ) {
198
if( finfo.ftype == 1 ) { /* directory file */
199
mkdir( finfo.fname, 0755 );
200
} else if( finfo.ftype == 2 ) { /* link file */
201
symlink( finfo.info, finfo.fname );
202
} else { /* regular */
203
MakeImageFile( finfo.fname, finfo.fsize );
204
fprintf( fent, "%s %d\n", finfo.fname, modtime );
205
}
206
}
207
}
208
fclose( fent );
209
fclose( fdir );
210
return 0;
211
}
212
213
/*
214
* ========================= ftp cs =========================
215
*/
216
217
/*
218
*name: FtpCommand
219
*/
220
int
221
FtpCommand( nFile, cmd, arg )
222
NetFile *nFile;
223
char *cmd, *arg;
224
{
225
char buf[ STRLEN ];
226
227
if( cmd == NULL )
228
return -1;
229
sfsprintf( buf, sizeof(buf), arg ? "%s %s\r\n" : "%s\r\n", cmd, arg );
230
NetWrite( nFile, buf, strlen(buf) );
231
#ifdef DEBUG
232
if( strcmp( cmd, "PASS" ) == 0 )
233
debug_logit( "PASS *\r\n" );
234
else
235
debug_logit( buf );
236
#endif
237
return 0;
238
}
239
240
241
/*
242
*name: FtpReply
243
*/
244
int
245
FtpReply( nFile, buf, bsize )
246
NetFile *nFile;
247
char *buf;
248
int bsize;
249
{
250
char tmpbuf[ STRLEN ];
251
char token[4], *ptr;
252
253
if( buf == NULL ) {
254
buf = tmpbuf;
255
bsize = sizeof(tmpbuf);
256
}
257
if( NetGets( nFile, buf, bsize ) == NULL ) {
258
debug_logit( "FtpReply: NetGets return NULL\n" );
259
return -1;
260
}
261
262
/* parsing multi-line response */
263
if( buf[3] == '-' ) {
264
strncpy( token, buf, 3 );
265
token[3] = ' ';
266
while( strncmp( buf, token, 4 ) != 0 ) {
267
if( NetGets( nFile, buf, bsize ) == NULL ) {
268
debug_logit( "Multi-line parse error\n" );
269
return -1;
270
}
271
}
272
}
273
274
/* trim "...\r\n" to "...\n" */
275
if( (ptr = strchr( buf, '\r' )) != NULL && ptr[1] == '\n' ) {
276
*ptr++ = '\n';
277
*ptr = '\0';
278
}
279
debug_logit( buf );
280
return( (buf[0]-'0') * 100 + (buf[1]-'0') * 10 );
281
}
282
283
/*
284
*name: FtpTalk
285
*/
286
int
287
FtpTalk( nFile, cmd, arg )
288
NetFile *nFile;
289
char *cmd, *arg;
290
{
291
FtpCommand( nFile, cmd, arg );
292
return FtpReply( nFile, NULL, 0 );
293
}
294
295
/*
296
*name: FtpDataConnect
297
*/
298
NetFile *
299
FtpDataConnect( srv, nFile )
300
struct server_info *srv;
301
NetFile *nFile;
302
{
303
char reply[ STRLEN ];
304
char host[ STRLEN ];
305
char *arg[6], *ptr;
306
int port;
307
308
FtpCommand( nFile, "PASV", NULL );
309
if( FtpReply( nFile, reply, sizeof(reply) ) != 220 ||
310
(ptr = strchr( reply, '(' )) == NULL ) {
311
cserrno = E_CONNECT;
312
return NULL;
313
}
314
if( SplitFields( arg, 6, ptr+1, ',' ) < 6 ) {
315
cserrno = E_CONNECT;
316
return NULL;
317
}
318
sfsprintf( host, sizeof(host), "%s.%s.%s.%s", arg[0], arg[1], arg[2], arg[3] );
319
port = (int)strtol( arg[4], (char**)0, 0 ) * 256 + (int)strtol( arg[5], (char**)0, 0 );
320
return NetConnect( srv, host, port );
321
}
322
323
/*
324
*name: FtpXfer
325
*/
326
int
327
FtpXfer( srv, cmd, rpath, tmpfile )
328
struct server_info *srv;
329
char *cmd;
330
char *rpath;
331
char *tmpfile;
332
{
333
NetFile *nFile, *nData;
334
char buf[ STRLEN ];
335
int fd, len;
336
337
nFile = srv->mitem->nFile;
338
if( (nData = FtpDataConnect( srv, nFile )) == NULL ) {
339
if( IfsAbortFlag ) FtpDisconnect( srv );
340
cserrno = E_CONNECT;
341
return -1;
342
}
343
if( FtpTalk( nFile, cmd, rpath ) >= 200 ) {
344
if( IfsAbortFlag ) FtpDisconnect( srv );
345
NetClose( nData );
346
cserrno = E_DATAXFER;
347
return -1;
348
}
349
cserrno = E_NIL;
350
if( (fd = open( tmpfile, O_WRONLY|O_CREAT|O_TRUNC, 0644 )) < 0 ) {
351
cserrno = E_DATAXFER;
352
} else {
353
while( (len = NetRead( nData, buf, sizeof(buf) )) > 0 )
354
write( fd, buf, len );
355
close( fd );
356
}
357
NetClose( nData );
358
if( FtpReply( nFile, NULL, 0 ) != 220 ) { /* xfer result */
359
cserrno = E_DATAXFER;
360
}
361
if( IfsAbortFlag ) FtpDisconnect( srv );
362
return (cserrno == E_NIL ? 0 : -1);
363
}
364
365
/*
366
*name: FtpXferFile
367
*/
368
int
369
FtpXferFile( srv, tmpfile )
370
struct server_info *srv;
371
char *tmpfile;
372
{
373
char *lpath = srv->lpath;
374
char *rpath = srv->rpath;
375
376
if( *rpath == '/' && rpath[1] == '~' ) /* home directory mount */
377
rpath++;
378
if( FtpXfer( srv, "RETR", rpath, tmpfile ) == -1 ) {
379
return -1;
380
}
381
MakePath( lpath );
382
rename( tmpfile, lpath );
383
ftp_doentry( lpath );
384
return 0;
385
}
386
387
/*
388
*name: FtpXferDir
389
*/
390
int
391
FtpXferDir( srv, tmpfile )
392
struct server_info *srv;
393
char *tmpfile;
394
{
395
NetFile *nFile = srv->mitem->nFile;
396
char buf[ STRLEN ];
397
char *lpath = srv->lpath;
398
char *rpath = srv->rpath;
399
400
if( *rpath == '\0' ) rpath = "/";
401
if( *rpath == '/' && rpath[1] == '~' ) /* home directory mount */
402
rpath++;
403
FtpCommand( nFile, "CWD", rpath );
404
if( FtpReply( nFile, buf, sizeof(buf) ) != 250 ||
405
strncmp( buf, "250 Unable to locate", 20 ) == 0 ) {
406
/* typo of SMART_CD patch (of [email protected]) */
407
logit( "<ftp>: cwd error\n" );
408
cserrno = E_DATAXFER;
409
return -1;
410
}
411
logit( "<ftp>: xfer directory\n" );
412
if( FtpXfer( srv, "LIST", NULL, tmpfile ) == -1 )
413
return -1;
414
if( chdir( lpath ) == -1 ) {
415
sfsprintf( buf, sizeof(buf), "%s/._dir", lpath );
416
MakePath( buf );
417
chdir( lpath );
418
}
419
rename( tmpfile, "._dir" );
420
ftp_makedents( "._dir" );
421
symlink( srv->mitem->timeout, "._cache_time" );
422
return 0;
423
}
424
425
/*
426
*name: FtpConnect
427
* create a connection to remote host,
428
* save socket handler in the 'mode' field of mount_item.
429
*/
430
int
431
FtpConnect( srv )
432
struct server_info *srv;
433
{
434
struct mount_item *mitem = srv->mitem;
435
NetFile *nFile = mitem->nFile;
436
char pass[ 80 ], *user;
437
int port;
438
439
if( nFile != NULL ) {
440
if( FtpTalk( nFile, "NOOP", NULL ) == 200 ) {
441
sfsprintf( csusrmsg, sizeof(csusrmsg), "use fd:%d", nFile->socket );
442
return 0;
443
}
444
}
445
logit( "<ftp>: connect\n" );
446
port = (mitem->port ? mitem->port : 21);
447
if( (nFile = NetConnect( srv, mitem->host, port )) == NULL ) {
448
logit( "<ftp>: connect failed!\n" );
449
return -1;
450
}
451
if( FtpReply( nFile, NULL, 0 ) != 220 ) { /* initial message */
452
cserrno = E_CONNECT;
453
NetClose( nFile );
454
return -1;
455
}
456
logit( "<ftp>: login\n" );
457
user = mitem->user ? mitem->user : "anonymous";
458
if( mitem->passlen > 0 ) {
459
SecurityDataAccess( mitem->pass, pass, mitem->passlen );
460
} else {
461
strcpy( pass, "ftpcs@" );
462
}
463
if( FtpTalk( nFile, "USER", user ) != 330 ||
464
FtpTalk( nFile, "PASS", pass ) != 230 ) {
465
cserrno = E_USERAUTH;
466
NetClose( nFile );
467
return -1;
468
}
469
if( FtpTalk( nFile, "TYPE", "I" ) != 200 ) {
470
cserrno = E_CONNECT;
471
NetClose( nFile );
472
return -1;
473
}
474
mitem->nFile = nFile;
475
sfsprintf( csusrmsg, sizeof(csusrmsg), "use fd: %d", nFile->socket );
476
return 0;
477
}
478
479
/*
480
*name: FtpDisconnect
481
* close the socket handler which stored in mount_item->mode
482
*/
483
int
484
FtpDisconnect( srv )
485
struct server_info *srv;
486
{
487
struct mount_item *mitem = srv->mitem;
488
NetFile *nFile = mitem->nFile;
489
490
if( nFile != NULL ) {
491
logit( "<ftp>: disconnect\n" );
492
NetClose( nFile );
493
mitem->nFile = NULL;
494
sfsprintf( csusrmsg, sizeof(csusrmsg), "closefd= %d", nFile->socket );
495
}
496
return 0;
497
}
498
499
/*
500
*name: FtpGetFile
501
* get a file/directory from remote host
502
*/
503
int
504
FtpGetFile( srv )
505
struct server_info *srv;
506
{
507
struct mount_item *mitem = srv->mitem;
508
char tmpfile[ STRLEN ];
509
char *lpath = srv->lpath;
510
char *rpath = srv->rpath;
511
int ans;
512
513
MakeTmpFile( lpath, tmpfile, sizeof(tmpfile) );
514
if( mitem->nFile == NULL )
515
if( FtpConnect( srv ) == -1 )
516
return -1;
517
if( NetDataReady( mitem->nFile ) ) { /* maybe connection timeout */
518
FtpDisconnect( srv );
519
if( FtpConnect( srv ) == -1 ) /* make a new connection */
520
return -1;
521
}
522
if( *rpath == '\0' || DashD( lpath ) ) {
523
ans = FtpXferDir( srv, tmpfile );
524
} else if( DashF( lpath ) ) {
525
ans = FtpXferFile( srv, tmpfile );
526
} else {
527
if( (ans = FtpXferDir( srv, tmpfile )) == -1 )
528
ans = FtpXferFile( srv, tmpfile );
529
}
530
unlink( tmpfile );
531
return ans;
532
}
533
534
/*
535
* name: FtpPutFile
536
* put a file from local file system to remote host
537
*/
538
int
539
FtpPutFile( srv )
540
struct server_info *srv;
541
{
542
struct mount_item *mitem = srv->mitem;
543
NetFile *nFile, *nData;
544
char buf[ STRLEN ];
545
char *rpath;
546
int fd, len;
547
548
cserrno = E_NIL;
549
if( FtpConnect( srv ) == -1 )
550
return -1;
551
nFile = mitem->nFile;
552
logit( "<ftp>: store file\n" );
553
if( (fd = open( srv->lpath, O_RDONLY, 0 )) < 0 ) {
554
cserrno = E_DATAXFER;
555
return -1;
556
}
557
if( (nData = FtpDataConnect( srv, nFile )) == NULL ) {
558
close( fd );
559
return -1;
560
}
561
rpath = srv->rpath;
562
if( *rpath == '/' && rpath[1] == '~' ) /* home directory mount */
563
rpath++;
564
if( FtpTalk( nFile, "STOR", rpath ) >= 200 ) {
565
logit( "<ftp>: stor error\n" );
566
cserrno = E_DATAXFER;
567
NetClose( nData );
568
close( fd );
569
return -1;
570
}
571
while( (len = read( fd, buf, sizeof(buf) )) > 0 ) {
572
NetWrite( nData, buf, len );
573
}
574
NetClose( nData );
575
close( fd );
576
if( FtpReply( nFile, NULL, 0 ) != 220 ) { /* transfer result */
577
cserrno = E_DATAXFER;
578
return -1;
579
}
580
return 0;
581
}
582
583
/*
584
* name: FtpNop
585
* unimplement command
586
*/
587
int
588
FtpNop()
589
{
590
return 0;
591
}
592
593
/*
594
* name: FtpInit
595
* Initial the data and functions in agent_item
596
*/
597
int
598
FtpInit( tbl )
599
struct agent_item *tbl;
600
{
601
tbl->localdata = (char *) &ftp_data;
602
tbl->connect = FtpConnect;
603
tbl->disconnect = FtpDisconnect;
604
tbl->listdents = FtpGetFile;
605
tbl->getfile = FtpGetFile;
606
tbl->putfile = FtpPutFile;
607
tbl->userdef = FtpNop;
608
return 0;
609
}
610
611
612