File: globus_ftp_client_exists.c

package info (click to toggle)
globus-ftp-client 5.3-3
  • links: PTS, VCS
  • area: main
  • in suites: squeeze
  • size: 3,492 kB
  • ctags: 1,763
  • sloc: ansic: 25,084; sh: 8,562; makefile: 340
file content (609 lines) | stat: -rw-r--r-- 16,054 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
/*
 * Copyright 1999-2006 University of Chicago
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef GLOBUS_DONT_DOCUMENT_INTERNAL
/**
 * @file
 *
 * $RCSfile: globus_ftp_client_exists.c,v $
 * $Revision: 1.10 $
 * $Date: 2006/10/14 07:21:56 $
 */
#endif

#include "globus_i_ftp_client.h"

#ifndef GLOBUS_DONT_DOCUMENT_INTERNAL

#define GLOBUS_L_FTP_CLIENT_EXIST_BUFFER_LENGTH 4096

/* Module specific data types */
/**
 * Existence check state enumeration.
 * @internal
 * 
 * Existence checking may require a few commands on the FTP control
 * channel. This enumeration shows which state we are currently processing.
 */
typedef enum
{
    GLOBUS_FTP_CLIENT_EXIST_SIZE,
    GLOBUS_FTP_CLIENT_EXIST_MLST,
    GLOBUS_FTP_CLIENT_EXIST_STAT,
    GLOBUS_FTP_CLIENT_EXIST_LIST
}
globus_l_ftp_client_existence_state_t;

/**
 * Existence check status structure.
 * @internal
 *
 * All information needed for a file or directory existence check
 * is contained here. This state is used to track the progress of
 * the existence check operation.
 *
 * @see globus_l_ftp_client_existence_info_init(),
 *      globus_l_ftp_client_existence_info_destroy()
 */
typedef struct
{
    /** The URL we are checking for existence */
    char *					url_string;

    /** Parsed representation of url_string */
    globus_url_t				parsed_url;

    /** Data channel buffer */
    globus_byte_t *				buffer;

    /** Length of our data channel buffer */
    globus_size_t				buffer_length;

    /** Copy of attributes we will use for the FTP operations needed to
     * implement the existence check.
     */
    globus_ftp_client_operationattr_t 		attr;

    /** True once we've determined that the file exists. */
    globus_bool_t				exists;

    /** Size of the file, used for one of the existence checks */
    globus_off_t				size;
    
    /** stat/mlst buffer, used for one of the existence checks */
    globus_byte_t *                             mlst_buffer;
    globus_size_t                               mlst_buffer_len;
        
    /** Error object containing the reason for why the existence check
     * failed, or GLOBUS_SUCCESS.
     */
    globus_object_t *				error;

    /** User-supplied completion callback for when we've determined
     * if the file exists or not
     */
    globus_ftp_client_complete_callback_t	callback;

    /** User-supplied callback argument */
    void *					callback_arg;

    /** Current state of the existence check machine. */
    globus_l_ftp_client_existence_state_t	state;
}
globus_l_ftp_client_existence_info_t;

/* Module specific prototypes */
static
globus_result_t
globus_l_ftp_client_existence_info_init(
    globus_l_ftp_client_existence_info_t **	existence_info,
    const char *				url,
    globus_ftp_client_operationattr_t *		attr,
    globus_bool_t				rfc1738_url,
    globus_ftp_client_complete_callback_t	complete_callback,
    void *					callback_arg);

static
globus_result_t
globus_l_ftp_client_existence_info_destroy(
    globus_l_ftp_client_existence_info_t **	existence_info);

static
void
globus_l_ftp_client_exist_callback(
    void *					user_arg,
    globus_ftp_client_handle_t *		handle,
    globus_object_t *				error);

static
void
globus_l_ftp_client_exist_data_callback(
    void *					user_arg,
    globus_ftp_client_handle_t *		handle,
    globus_object_t *				error,
    globus_byte_t *				buffer,
    globus_size_t				length,
    globus_off_t				offset,
    globus_bool_t				eof);

#endif

/**
 * @name File or Directory Existence
 */
/* @{ */
/**
 * Check for the existence of a file or directory on an FTP server.
 * @ingroup globus_ftp_client_operations
 *
 * This function attempts to determine whether the specified URL points to
 * a valid file or directory. The @a complete_callback will be invoked
 * with the result of the existence check passed as a globus error object,
 * or GLOBUS_SUCCESS.
 *
 * @param u_handle
 *        An FTP Client handle to use for the existence check operation.
 * @param url
 *        The URL of the directory or file to check. The URL may be an
 *        ftp or gsiftp URL.
 * @param attr
 *        Attributes to use for this operation.
 * @param complete_callback
 *        Callback to be invoked once the existence operation is completed.
 * @param callback_arg
 *        Argument to be passed to the complete_callback.
 * @return
 *        This function returns an error when any of these conditions are
 *        true:
 *        - u_handle is GLOBUS_NULL
 *        - url is GLOBUS_NULL
 *        - url cannot be parsed
 *        - url is not a ftp or gsiftp url
 *        - complete_callback is GLOBUS_NULL
 *        - handle already has an operation in progress
 */
globus_result_t
globus_ftp_client_exists(
    globus_ftp_client_handle_t *		u_handle,
    const char *				url,
    globus_ftp_client_operationattr_t *		attr,
    globus_ftp_client_complete_callback_t	complete_callback,
    void *					callback_arg)
{
    globus_result_t result;
    globus_l_ftp_client_existence_info_t *	existence_info;

    result = globus_l_ftp_client_existence_info_init(&existence_info,
	                                             url,
						     attr,
						     (*u_handle)->attr.rfc1738_url,
						     complete_callback,
						     callback_arg);
    if(result != GLOBUS_SUCCESS)
    {
	goto result_exit;
    }
    
    existence_info->state = GLOBUS_FTP_CLIENT_EXIST_SIZE;
    result = globus_ftp_client_size(
        u_handle,
        url,
        attr,
        &existence_info->size,
        globus_l_ftp_client_exist_callback,
        existence_info);

    if(result != GLOBUS_SUCCESS)
    {
	goto info_destroy_exit;
    }
    return GLOBUS_SUCCESS;

  info_destroy_exit:
    globus_l_ftp_client_existence_info_destroy(&existence_info);
  result_exit:
    return result;
}
/* globus_ftp_client_exists() */
/* @} */

/* Local/internal functions */
#ifndef GLOBUS_DONT_DOCUMENT_INTERNAL
/**
 * Initialize an existence info structure.
 *
 * This function allocates and initializes an existence information
 * structure.
 *
 * @param existence_info
 *        Pointer to be set to point to the address of a freshly allocated and
 *        initialized existence information structure.
 * @param url
 *        The URL which this existence info structure will be used to
 *        check the existence of.
 * @param attr
 *        FTP operation attributes which will be used to process this
 *        existence check.
 * @param complete_callback
 *        User callback to be invoked once the existence check is complete.
 * @param callback_arg
 *        User argument to above.
 *
 * @see globus_l_ftp_client_existence_info_t,
 *      globus_l_ftp_client_existence_info_destroy()
 */
static
globus_result_t
globus_l_ftp_client_existence_info_init(
    globus_l_ftp_client_existence_info_t **	existence_info,
    const char *				url,
    globus_ftp_client_operationattr_t *		attr,
    globus_bool_t				rfc1738_url,
    globus_ftp_client_complete_callback_t	complete_callback,
    void *					callback_arg)
{
    globus_object_t *				err = GLOBUS_SUCCESS;
    globus_result_t				result;
    int						rc;
    GlobusFuncName(globus_l_ftp_client_existence_info_init);

    *existence_info =
	globus_libc_calloc(1, sizeof(globus_l_ftp_client_existence_info_t));

    if(*existence_info == GLOBUS_NULL)
    {
	err = GLOBUS_I_FTP_CLIENT_ERROR_OUT_OF_MEMORY();

	goto error_exit;
    }
    
    if(rfc1738_url)
    {
        rc = globus_url_parse_rfc1738(url, &(*existence_info)->parsed_url);
    }
    else
    {   
	rc = globus_url_parse(url, &(*existence_info)->parsed_url);
    }
	    

    if(rc != GLOBUS_SUCCESS)
    {
	err = GLOBUS_I_FTP_CLIENT_ERROR_INVALID_PARAMETER("url");

	goto free_info_exit;
    }

    (*existence_info)->url_string = globus_libc_strdup(url);

    if((*existence_info)->url_string == GLOBUS_NULL)
    {
	err = GLOBUS_I_FTP_CLIENT_ERROR_OUT_OF_MEMORY();

	goto free_parsed_url_exit;
    }


    result = globus_ftp_client_operationattr_copy(
	    &(*existence_info)->attr,
	    attr);

    if(result != GLOBUS_SUCCESS)
    {
	err = globus_error_get(result);

	goto free_url_string_exit;
    }

    (*existence_info)->callback = complete_callback;
    (*existence_info)->callback_arg = callback_arg;
    (*existence_info)->buffer =
	globus_libc_malloc(GLOBUS_L_FTP_CLIENT_EXIST_BUFFER_LENGTH);

    if((*existence_info)->buffer == GLOBUS_NULL)
    {
	err = GLOBUS_I_FTP_CLIENT_ERROR_OUT_OF_MEMORY();

	goto free_attr_exit;
    }

    (*existence_info)->buffer_length = GLOBUS_L_FTP_CLIENT_EXIST_BUFFER_LENGTH;

    return GLOBUS_SUCCESS;

free_attr_exit:
    globus_ftp_client_operationattr_destroy(&(*existence_info)->attr);
free_url_string_exit:
    globus_libc_free((*existence_info)->url_string);
free_parsed_url_exit:
    globus_url_destroy(&(*existence_info)->parsed_url);
free_info_exit:
    globus_libc_free(*existence_info);
error_exit:
    return globus_error_put(err);
}
/* globus_l_ftp_client_existence_info_init() */

/**
 * Destroy an existence info structure.
 *
 * This function frees all memory allocated by
 * globus_l_ftp_client_existence_info_init().
 *
 * @param existence_info
 *        Pointer to the pointer returned from the
 *        globus_l_ftp_client_existence_info_init() function in the
 *        existence_info parameter.
 *
 * @see globus_l_ftp_client_existence_info_t,
 *      globus_l_ftp_client_existence_info_init()
 */
static
globus_result_t
globus_l_ftp_client_existence_info_destroy(
    globus_l_ftp_client_existence_info_t **	existence_info)
{
    globus_libc_free((*existence_info)->url_string);
    globus_url_destroy(&(*existence_info)->parsed_url);
    globus_libc_free((*existence_info)->buffer);
    if((*existence_info)->error)
    {
	globus_object_free((*existence_info)->error);
    }
    if((*existence_info)->mlst_buffer)
    {
	globus_free((*existence_info)->mlst_buffer);
    }

    globus_ftp_client_operationattr_destroy(&(*existence_info)->attr);

    globus_libc_free(*existence_info);

    *existence_info = GLOBUS_NULL;

    return GLOBUS_SUCCESS;
}
/* globus_l_ftp_client_existence_info_destroy() */

/**
 * Existence check state machine.
 * @internal
 *
 * This function contains the logic for proceding through the existence
 * check state machine. It is a globus_ftp_client_complete_callback_t
 * which is passed to various ftp client operations to process the 
 * existence check.
 *
 * @param user_arg
 *        A void * pointing to the globus_l_ftp_client_existence_info_t
 *        structure with the existence check state.
 * @param handle
 *        The FTP client handle that this existence check is being
 *        processed on.
 * @param error
 *        Error status from the FTP client operations.
 */
static
void
globus_l_ftp_client_exist_callback(
    void *					user_arg,
    globus_ftp_client_handle_t *		handle,
    globus_object_t *				error)
{
    globus_l_ftp_client_existence_info_t *	info;
    globus_result_t				result;
    globus_bool_t				myerr = GLOBUS_FALSE;
    globus_bool_t				try_again = GLOBUS_FALSE;
    
    info = user_arg;

    switch(info->state)
    {
	case GLOBUS_FTP_CLIENT_EXIST_SIZE:
	    if(error == GLOBUS_SUCCESS)
	    {
		info->exists = GLOBUS_TRUE;
	    }
	    else
	    {
                info->state = GLOBUS_FTP_CLIENT_EXIST_MLST;
		result = globus_ftp_client_mlst(
			handle,
			info->url_string,
			&info->attr,
			&info->mlst_buffer,
			&info->mlst_buffer_len,
			globus_l_ftp_client_exist_callback,
			info);

		if(result != GLOBUS_SUCCESS)
		{
		    error = globus_error_get(result);
		    myerr = GLOBUS_TRUE;
		}
		else
		{
		    try_again = GLOBUS_TRUE;
		}
	    }
	    break;
	case GLOBUS_FTP_CLIENT_EXIST_MLST:
	    if(error == GLOBUS_SUCCESS)
	    {
		info->exists = GLOBUS_TRUE;
	    }
	    else
	    {
                info->state = GLOBUS_FTP_CLIENT_EXIST_STAT;
		result = globus_ftp_client_stat(
			handle,
			info->url_string,
			&info->attr,
			&info->mlst_buffer,
			&info->mlst_buffer_len,
			globus_l_ftp_client_exist_callback,
			info);

		if(result != GLOBUS_SUCCESS)
		{
		    error = globus_error_get(result);
		    myerr = GLOBUS_TRUE;
		}
		else
		{
		    try_again = GLOBUS_TRUE;
		}
	    }
	    break;
	case GLOBUS_FTP_CLIENT_EXIST_STAT:
	    if(error == GLOBUS_SUCCESS)
	    {
		info->exists = GLOBUS_TRUE;
	    }
	    else
	    {                   
             /* some servers reply successfully to a LIST even if the path
             doesn't exist.  CWD to the path first will work around this 
             * -- if we got this far, we can be fairly sure it is a dir */
                info->attr->cwd_first = GLOBUS_TRUE;
                info->state = GLOBUS_FTP_CLIENT_EXIST_LIST;
		result = globus_ftp_client_verbose_list(
			handle,
			info->url_string,
			&info->attr,
			globus_l_ftp_client_exist_callback,
			info);

		if(result != GLOBUS_SUCCESS)
		{
		    error = globus_error_get(result);
		    myerr = GLOBUS_TRUE;
		}
		else
		{
		    result = globus_ftp_client_register_read(
			handle,
			info->buffer,
			info->buffer_length,
			globus_l_ftp_client_exist_data_callback,
			info);
		    if(result != GLOBUS_SUCCESS)
		    {
			error = globus_error_get(result);
			myerr = GLOBUS_TRUE;
		    }
		    else
		    {
			try_again = GLOBUS_TRUE;
		    }
		}
	    }
	    break;
	case GLOBUS_FTP_CLIENT_EXIST_LIST:
            if(error != GLOBUS_SUCCESS)
	    {
		info->exists = GLOBUS_FALSE;
	    }
	    try_again = GLOBUS_FALSE;
	    break;
    }
    if(!try_again)
    {
	if(error == GLOBUS_SUCCESS && !info->exists)
	{
	    error = GLOBUS_I_FTP_CLIENT_ERROR_NO_SUCH_FILE(info->url_string);

	    myerr = GLOBUS_TRUE;
	}
	info->callback(info->callback_arg, handle, error);

	globus_l_ftp_client_existence_info_destroy(&info);

	if(myerr)
	{
	    globus_object_free(error);
	}
    }
}
/* globus_l_ftp_client_exist_callback() */

/**
 * Existence check state machine data callback.
 * @internal
 *
 * This function handles the data which arrives as part of the LIST
 * check of the existence check state machine. It just discards the
 * data which arrives until EOF.
 *
 * @param user_arg
 *        A void * pointing to the globus_l_ftp_client_existence_info_t
 *        structure with the existence check state.
 * @param handle
 *        The FTP client handle that this existence check is being
 *        processed on.
 * @param error
 *        Error status from the FTP client operations.
 * @param buffer
 *        A pointer to the existence state structure's buffer member.
 * @param length
 *        The amount of date read on the data channel (ignored).
 * @param offset
 *        The offset of the data in the list (ignored).
 * @param eof
 *        End-of-file flag.
 */
static
void
globus_l_ftp_client_exist_data_callback(
    void *					user_arg,
    globus_ftp_client_handle_t *		handle,
    globus_object_t *				error,
    globus_byte_t *				buffer,
    globus_size_t				length,
    globus_off_t				offset,
    globus_bool_t				eof)
{
    globus_l_ftp_client_existence_info_t *	info;
    globus_result_t				result;

    info = user_arg;

    if(error != GLOBUS_SUCCESS && !info->error)
    {
	info->error = globus_object_copy(error);
    }
    if(!error)
    {
        info->exists = GLOBUS_TRUE;
    }
    if(! eof)
    {
	result =
	    globus_ftp_client_register_read(
		    handle,
		    info->buffer,
		    info->buffer_length,
		    globus_l_ftp_client_exist_data_callback,
		    info);

	if(result != GLOBUS_SUCCESS && !info->error)
	{
	    info->error = globus_error_get(result);
	}
    }
}
/* globus_l_ftp_client_exist_data_callback() */
#endif