GridLab
Grid Application Toolkit

A simple API for Grid Applications
GAT

Menu



Main Page   Alphabetical List   Compound List   File List   Compound Members   File Members  

adaptor.c

Go to the documentation of this file.
00001 /** @file adaptor.c
00002  * Main file for the fileops adaptor.
00003  * 
00004  * Test adaptor to check the GATFile API. Provides a simple
00005  * file GATFileCPI implementation.
00006  * 
00007  * @date Sun Oct 5 2003
00008  * 
00009  * @version $Header: /export/cvs-gridlab/wp-1/Codes/GATEngine/C-reference/adaptors/fileops/adaptor.c,v 1.25 2004/04/22 10:25:05 hartmutkaiser Exp $
00010  *
00011  *  Copyright (C) Tom Goodale
00012  *  Copyright (C) Hartmut Kaiser
00013  *  This file is part of the GAT Engine.
00014  *  Contributed by 
00015  *    Tom Goodale <goodale@aei.mpg.de>
00016  *    Hartmut Kaiser <hartmutkaiser [at] t-online [dot] de>.
00017  *
00018  *  Use, modification and distribution is subject to the Gridlab Software
00019  *  License. (See accompanying file GLlicense.txt or copy at
00020  *  http://www.gridlab.org/GLlicense.txt)
00021  */
00022 
00023 #if defined(sccs)
00024 static const char *rcsid = "$Header: /export/cvs-gridlab/wp-1/Codes/GATEngine/C-reference/adaptors/fileops/adaptor.c,v 1.25 2004/04/22 10:25:05 hartmutkaiser Exp $";
00025 #endif
00026 
00027 /* System Header Files */
00028 #include <stdio.h>
00029 #include <stdlib.h>
00030 #include <string.h>
00031 
00032 #include <sys/wait.h>
00033 #include <sys/stat.h>
00034 
00035 /* GAT Header Files */
00036 #include <GATCPI.h>
00037 
00038 /* Macros */
00039 
00040 /* Should copy this from a config table if available, and
00041  * use the below as a default.
00042  */
00043 #define COPY_COMMAND    "/bin/cp"
00044 #define MOVE_COMMAND    "/bin/mv"
00045 #define REMOVE_COMMAND  "/bin/rm -f"
00046 
00047 #define __countof(x) (sizeof(x)/sizeof(x[0]))
00048 
00049 /* Structures, unions and enums */
00050 
00051 /* Adaptor data */
00052 typedef struct GATFileOpsAdaptor_Data {
00053   GATTable config_data;
00054 } GATFileOpsAdaptor_Data;
00055 
00056 /* Instance data */
00057 typedef struct GATFileOpsInstance_Data {
00058   GATContext context;
00059   GATLocation location;
00060 } GATFileOpsInstance_Data;
00061 
00062 
00063 /* Static function prototypes */
00064 static void 
00065 fileops_adaptor_FileCPI_Destroy(void *data);
00066 
00067 /* instance specific functions */
00068 static GATResult
00069 fileops_adaptor_FileCPI_ServiceActions(void *data, 
00070   GATFileCPI_Instance *instance_data, GATTimePeriod_const timeout /* = 0 */);
00071   
00072 static GATResult 
00073 fileops_adaptor_FileCPI_CreateInstance(void *data, 
00074   GATFileCPI_Instance *instance_data);
00075 
00076 static void 
00077 fileops_adaptor_FileCPI_DestroyInstance(void *data, 
00078   GATFileCPI_Instance *instance_data);
00079 
00080 static GATResult 
00081 fileops_adaptor_FileCPI_CloneInstance(void *data, 
00082   GATFileCPI_Instance const *instance_data, 
00083   GATFileCPI_Instance *new_instance_data);
00084 
00085 static GATResult 
00086 fileops_adaptor_FileCPI_EqualsInstance(void *data, 
00087   GATFileCPI_Instance const *lhs, GATFileCPI_Instance const *rhs, 
00088   GATBool *isequal);
00089 
00090 /* Serialisation functions */
00091 static GATResult 
00092 fileops_adaptor_FileCPI_Serialise(GATFileCPI cpi, 
00093   GATFileCPI_Instance const *instance_data, GATObject stream,
00094   GATBool clear_dirty);
00095   
00096 static GATResult 
00097 fileops_adaptor_FileCPI_DeSerialise(GATFileCPI cpi, 
00098   GATObject stream, GATFileCPI_Instance *instance_data);
00099   
00100 /* Execute a GATFile copy operation */
00101 static GATResult 
00102 fileops_adaptor_FileCPI_Copy(void *data, 
00103   GATFileCPI_Instance const *instance_data, GATLocation_const targetLocation,
00104   GATFileMode mode);
00105 
00106 /* Execute a GATFile move operation */
00107 static GATResult 
00108 fileops_adaptor_FileCPI_Move(void *data, 
00109   GATFileCPI_Instance const *instance_data, GATLocation_const targetLocation,
00110   GATFileMode mode);
00111 
00112 /* Execute a GATFile delete operation */
00113 static GATResult 
00114 fileops_adaptor_FileCPI_Delete(void *data, 
00115   GATFileCPI_Instance const *instance_data);
00116   
00117 /* Execute a GATFile test for is_readable */
00118 static GATResult 
00119 fileops_adaptor_FileCPI_IsReadable(void *data, 
00120   GATFileCPI_Instance const *instance_data);
00121 
00122 /* Execute a GATFile test for is_writable */
00123 static GATResult 
00124 fileops_adaptor_FileCPI_IsWritable(void *data, 
00125   GATFileCPI_Instance const *instance_data);
00126 
00127 /* Execute a GATFile get_length operation */
00128 static GATResult 
00129 fileops_adaptor_FileCPI_GetLength(void *data, 
00130   GATFileCPI_Instance const *instance_data, unsigned long *length);
00131   
00132 /* Execute a GATFile get_lastwritetime operation */
00133 static GATResult 
00134 fileops_adaptor_FileCPI_LastWriteTime(void *data, 
00135   GATFileCPI_Instance const *instance_data, GATTime *lw_time);
00136 
00137 /* Execute a GATFile get_metrics operation */
00138 static GATResult 
00139 fileops_adaptor_FileCPI_GetMetrics(void *data, 
00140   GATFileCPI_Instance const *instance_data, GATList_GATMetric *metrics);
00141 
00142 /* Execute a GATFile get_metric_event operation */
00143 static GATResult 
00144 fileops_adaptor_FileCPI_GetMetricEvent(void *data, 
00145   GATFileCPI_Instance const *instance_data, GATMetric metric, 
00146     GATMetricEvent *event);
00147 static GATResult 
00148   fileops_adaptor_get_file_size(void *data, GATType type, 
00149     void *buffer, GATuint32 size);
00150 
00151 /* local helper functions */
00152 static char *
00153 fileops_get_table_entry(GATTable_const table, char const *key);
00154 
00155 static GATResult
00156 fileops_copy_config(GATTable internal_data, GATTable_const system_config, 
00157   GATTable_const instance_config, char const *key, char const *default_value);
00158 
00159 /* monitoring support (event firing) */
00160 static GATResult 
00161 fileops_adaptor_FireCopiedEvent(GATContext context, 
00162   GATMonitorable_Impl monitorable, GATObject_const source, char const *name);
00163 
00164 static GATResult 
00165 fileops_adaptor_FireMovedEvent(GATContext context, 
00166   GATMonitorable_Impl monitorable, GATObject_const source, char const *name);
00167 
00168 static GATResult 
00169 fileops_adaptor_FireDeletedEvent(GATContext context, 
00170   GATMonitorable_Impl monitorable, GATObject_const source, char const *name);
00171 
00172 /* Adaptor data */
00173 static GATFileOpsAdaptor_Data *
00174   GATFileOpsAdaptor_Data_Create();
00175 static void 
00176   GATFileOpsAdaptor_Data_Destroy(GATFileOpsAdaptor_Data *);
00177 
00178 /* File scope variables */
00179 
00180 /* supported metrics */
00181 static GATStaticMetric metric_data[] = {
00182   /* fileops.file_copied event */
00183   { 
00184     "fileops.file_copied",          /* name */
00185     GATMeasurementType_EventLike,   /* type */
00186     GATType_String,                 /* data type */
00187     "",                             /* unit */
00188     0,                              /* parameter count */
00189     0                               /* parameters */
00190   },
00191   /* fileops.file_moved event */
00192   { 
00193     "fileops.file_moved",           /* name */
00194     GATMeasurementType_EventLike,   /* type */
00195     GATType_String,                 /* data type */
00196     "",                             /* unit */
00197     0,                              /* parameter count */
00198     0                               /* parameters */
00199   },
00200   /* fileops.file_deleted event */
00201   { 
00202     "fileops.file_deleted",         /* name */
00203     GATMeasurementType_EventLike,   /* type */
00204     GATType_String,                 /* data type */
00205     "",                             /* unit */
00206     0,                              /* parameter count */
00207     0                               /* parameters */
00208   },
00209   /* fileops.file_size metric */
00210   { 
00211     "fileops.file_size",            /* name */
00212     GATMeasurementType_Continuous,  /* type */
00213     GATType_GATuint32,              /* data type */
00214     "Bytes",                        /* unit */
00215     0,                              /* parameter count */
00216     0                               /* parameters */
00217   },
00218 };
00219 
00220 /* symbolic constants for the metric positions inside the metric_data array */
00221 #define METRIC_FILE_COPIED  0
00222 #define METRIC_FILE_MOVED   1
00223 #define METRIC_FILE_DELETED 2
00224 #define METRIC_FILE_SIZE    3
00225 
00226 /* External functions */
00227 GATResult 
00228 fileops_adaptor_register(GATContext error_context, GATRegistry registry, 
00229   GATTable_const system_config, GATTable_const instance_config, void *token);
00230 
00231 /** fileops_adaptor_register
00232  *  Registers all CPIs this adaptor provides.
00233  *
00234  *  This function is invoked by the loader in the GATEngine when
00235  *  an instance of this adaptor is loaded.  Each instance has its
00236  *  own private configuration table. 
00237  *
00238  *  For every CPI provided the adapter has to hand all the corresponding 
00239  *  function pointers to the engine to allow to be called back under certain
00240  *  circumstances. Additionally the adaptor may allocate some private data for
00241  *  every loaded instance. This data is handed back to the adaptor as the first
00242  *  parameter to each of the subsequently called functions.
00243  *
00244  *  @param registry The registry the adaptor should register its CPIs with.
00245  *  @param system_config The system configuration table.
00246  *  @param instance_config The configuration table for this instance.
00247  *  @param token An arbitrary token used by the loader to identify this adaptor 
00248  *        instance
00249  *
00250  *  @return An error code.
00251  */
00252 GATResult 
00253 fileops_adaptor_register(GATContext error_context, GATRegistry registry, 
00254   GATTable_const system_config, GATTable_const instance_config, void *token)
00255 {
00256   GATResult retcode = GAT_MEMORYFAILURE;
00257   GATFileCPI cpi = NULL;
00258   GATPreferences preferences = NULL;
00259 
00260   if (!GATVERSION_ISCOMPATIBLE())
00261   {
00262     retcode = GAT_UNKNOWN_VERSION;
00263   }
00264   else
00265   {
00266     GATFileOpsAdaptor_Data *internal_data = GATFileOpsAdaptor_Data_Create();
00267     GATFileCPI_Data cpidata;
00268     
00269     memset(&cpidata, 0, sizeof(GATFileCPI_Data));
00270     if (NULL != internal_data) 
00271     {
00272       /* Create a GATFileCPI object.
00273       * This adaptor stores the internal data in an own GATTable object.
00274       */
00275       fileops_copy_config(internal_data->config_data, system_config, 
00276         instance_config, "copycmd", COPY_COMMAND);
00277       fileops_copy_config(internal_data->config_data, system_config, 
00278         instance_config, "movecmd", MOVE_COMMAND);
00279       fileops_copy_config(internal_data->config_data, system_config, 
00280         instance_config, "deletecmd", REMOVE_COMMAND);
00281       
00282       /*
00283       *  provide the appropriate callback functions
00284       */
00285        
00286       /* adaptor instance data */
00287       cpidata.data = internal_data;
00288       cpidata.destroy = fileops_adaptor_FileCPI_Destroy;
00289       
00290       /*  Lifetime control and basic GATObject functionality support for every
00291       *  object instance created by the client.
00292       */
00293       cpidata.service_actions = fileops_adaptor_FileCPI_ServiceActions;
00294       cpidata.create_instance = fileops_adaptor_FileCPI_CreateInstance;
00295       cpidata.destroy_instance = fileops_adaptor_FileCPI_DestroyInstance;
00296       cpidata.clone_instance = fileops_adaptor_FileCPI_CloneInstance;
00297       cpidata.equals_instance = fileops_adaptor_FileCPI_EqualsInstance;
00298       
00299       /* serialisation support for the provided instance data */
00300       cpidata.serialise = fileops_adaptor_FileCPI_Serialise;
00301       cpidata.deserialise = fileops_adaptor_FileCPI_DeSerialise;
00302 
00303       /* the CPI specific functionality */
00304       cpidata.copy = fileops_adaptor_FileCPI_Copy;
00305       cpidata.move = fileops_adaptor_FileCPI_Move;
00306       cpidata.remove = fileops_adaptor_FileCPI_Delete;
00307       cpidata.isreadable = fileops_adaptor_FileCPI_IsReadable;
00308       cpidata.iswritable = fileops_adaptor_FileCPI_IsWritable;
00309       cpidata.length = fileops_adaptor_FileCPI_GetLength;
00310       cpidata.lastwritetime = fileops_adaptor_FileCPI_LastWriteTime;
00311       
00312       /* monitoring support */
00313       cpidata.get_metrics = fileops_adaptor_FileCPI_GetMetrics;
00314       cpidata.get_metric_event = fileops_adaptor_FileCPI_GetMetricEvent;
00315 
00316       /* register this new CPI provider with the engine */
00317       cpi = GATFileCPI_Create(GATFILECPI_VERSION, &cpidata);
00318       if(NULL != cpi)
00319       {
00320         /* Need to pass preferences to allow matching
00321         * of a user's preferences with what this adaptor does.
00322         */
00323         preferences = GATPreferences_Create();
00324         if(NULL != preferences)
00325         {
00326           /* at least the Name preference should be defined */
00327           GATPreferences_Add(preferences, "Name", "fileops_adaptor");
00328           GATPreferences_Add(preferences, "Security", "none");
00329           GATPreferences_Add(preferences, "Local", "true");
00330           
00331           retcode = GATRegistry_AddGATFileCPI(registry, cpi, token, preferences);
00332           
00333           GATPreferences_Destroy(&preferences);
00334         }
00335       }
00336     }
00337     
00338     if (GAT_SUCCESS != retcode)
00339     {
00340       GATFileCPI_Destroy(&cpi);
00341       GATFileOpsAdaptor_Data_Destroy(internal_data);
00342     }
00343   }
00344   return retcode;
00345 }
00346 
00347 /* Local functions */
00348 
00349 /** fileops_adaptor_FileCPI_Destroy
00350  *  Destroy the adaptor-provided data object on GATFileCPI destruction.
00351  *  When the GATFileCPI object created in this adaptor's _register
00352  *  function is destroyed, this function is invoked to allow the
00353  *  adaptor to cleanup.
00354  *
00355  *  @param data Adaptor-provided data object.
00356  */
00357 static void 
00358 fileops_adaptor_FileCPI_Destroy(void *data)
00359 {
00360   GATFileOpsAdaptor_Data_Destroy((GATFileOpsAdaptor_Data *) data);
00361 }
00362 
00363 /* instance specific functions */
00364 
00365 /** fileops_adaptor_FileCPI_ServiceActions
00366  *  
00367  *  The function fileops_adaptor_FileCPI_ServiceActions is called, whenever
00368  *  the client calls GATContext_ServiceActions. This function is called for 
00369  *  every created object.
00370  *  This function should be used to update all instance specific data, which 
00371  *  may have been changed asynchronously or to fire pending events.
00372  *
00373  *  @param data Adaptor-provided data object.
00374  *  @param instance_data The instance data of this CPI object
00375  *  @param timeout This may be a 0 timeout to indicate no timeout at all, or
00376  *        a specific time length.
00377  *
00378  *  @return An error code.
00379  */
00380 static GATResult
00381 fileops_adaptor_FileCPI_ServiceActions(void *data, 
00382   GATFileCPI_Instance *instance_data, GATTimePeriod_const timeout)
00383 {
00384   return GAT_NOTIMPL;
00385 }
00386 
00387 /** fileops_adaptor_FileCPI_CreateInstance
00388  *  Create a new CPI object instance.
00389  *  Adaptor implementation of create instance capability.
00390  *
00391  *  This function gets called for every created object instance. The adaptor
00392  *  may provide some arbitrary instance data, which is to be stored inside the
00393  *  provided data structure (there is an instance_data member, which hold this
00394  *  adaptor provided object instance data). This overall data structure 
00395  *  is handed back to the adaptor on every function call always as the second 
00396  *  parameter.
00397  *
00398  *  @param adaptor_data Adaptor-provided data object.
00399  *  @param data The pointer to the data structure containing at least 
00400  *        the constructor provided data items and a member instance_data, which 
00401  *        may be used by the adaptor to store CPI instance specific data.
00402  * 
00403  * @return An error code.
00404  */
00405 static GATResult 
00406 fileops_adaptor_FileCPI_CreateInstance(void *adaptor_data, 
00407   GATFileCPI_Instance *data)
00408 {
00409   GATResult retval = GAT_INVALID_PARAMETER;
00410   if (NULL != data)
00411   {
00412     /* this adaptor does not maintain instance data */
00413     data->instance_data = NULL;
00414     retval = GAT_SUCCESS;
00415   }
00416   return retval;
00417 }
00418 
00419 /** fileops_adaptor_FileCPI_DestroyInstance
00420  *  Destroy a CPI object instance.
00421  *  Adaptor implementation of destroy instance capability.
00422  *
00423  * @param data Adaptor-provided data object.
00424  * @param instance_data The instance data of the CPI object to destroy.
00425  */
00426 static void
00427 fileops_adaptor_FileCPI_DestroyInstance(void *adaptor_data, 
00428   GATFileCPI_Instance *data)
00429 {
00430   /* this adaptor does not maintain instance data */
00431   assert(NULL == data || NULL == data->instance_data);
00432 }
00433 
00434 /** fileops_adaptor_FileCPI_CloneInstance
00435  *  Clone a CPI object instance.
00436  *  Adaptor implementation of the clone instance capability.
00437  *
00438  * @param data Adaptor-provided data object.
00439  * @param instance_data The instance data of this CPI object
00440  * @param new_instance_data The pointer to the variable, where the instance 
00441  *      data of the cloned CPI object is to be returned to.
00442  * 
00443  * @return An error code.
00444  */
00445 static GATResult 
00446 fileops_adaptor_FileCPI_CloneInstance(void *adaptor_data, 
00447   GATFileCPI_Instance const *data, 
00448   GATFileCPI_Instance *new_data)
00449 {
00450   GATResult retval = GAT_INVALID_PARAMETER;
00451   if (NULL != new_data)
00452   {
00453     /* this adaptor does not maintain instance data */
00454     new_data->instance_data = NULL;
00455     retval = GAT_SUCCESS;
00456   }
00457   return retval;
00458 }
00459 
00460 /** fileops_adaptor_FileCPI_EqualsInstance
00461  *  Clone a CPI object instance.
00462  *  Adaptor implementation of the clone instance capability.
00463  *
00464  * @param data Adaptor-provided data object.
00465  * @param lhs The instance data of the left CPI object.
00466  * @param rhs The instance data of the right CPI object.
00467  * @param isequal The pointer to the variable, where the result is to be 
00468  *        returned to.
00469  *
00470  * @return An error code.
00471  */
00472 static GATResult 
00473 fileops_adaptor_FileCPI_EqualsInstance(void *adaptor_data, 
00474   GATFileCPI_Instance const *lhs, GATFileCPI_Instance const *rhs, 
00475   GATBool *isequal)
00476 {
00477   /* this adaptor does not maintain instance data */
00478   GATResult retval = GAT_INVALID_PARAMETER;
00479   if (NULL != isequal)
00480   {
00481     /* has to compare the instance specific data only */
00482     *isequal = GATTrue;
00483     retval = GAT_SUCCESS;
00484   }
00485   return retval;
00486 }
00487 
00488 
00489 /* Serialisation support */
00490 
00491 /** fileops_adaptor_FileCPI_Serialise
00492  *
00493  *  The function fileops_adaptor_FileCPI_Serialise is called by the 
00494  *  GAT engine, whenever the client requested a Serialise operation on the 
00495  *  corresponding GATFile object. The function should serialise into the 
00496  *  given stream all the instance specific data of the object.
00497  *
00498  *  @param data Adaptor-provided data object.
00499  *  @param instance_data The instance data of this CPI object.
00500  *  @param stream The GATSTream object to use for serialisation of the instance 
00501  *        data.
00502  *  @param clear_dirty This flag defines, whether the dirty flag of saved 
00503  *        dependent objects is to be cleared.
00504  *
00505  *  @return An error code
00506  */
00507 static GATResult 
00508 fileops_adaptor_FileCPI_Serialise(GATFileCPI cpi, 
00509   GATFileCPI_Instance const *instance_data, GATObject stream,
00510   GATBool clear_dirty)
00511 {
00512   /* this adaptor does not maintain instance data, so there is nothing to 
00513      do here */
00514   GATResult retval = GAT_SUCCESS;
00515   return retval;
00516 }
00517 
00518 /** fileops_adaptor_FileCPI_DeSerialise
00519  *
00520  *  The function fileops_adaptor_FileCPI_DeSerialise is called by 
00521  *  the GATEngine, whenever the client requested a DeSerialise operation for
00522  *  a GATFile object. The function should deserialise all the instance 
00523  *  specific data of the object from the given stream.
00524  *
00525  *  @param data Adaptor-provided data object.
00526  *  @param stream The GATSTream object to use for de-serialisation of the 
00527  *        instance data.
00528  *  @param instance_data The instance data of this CPI object.
00529  *
00530  *  @return An error code
00531  */
00532 static GATResult 
00533 fileops_adaptor_FileCPI_DeSerialise(GATFileCPI cpi, 
00534   GATObject stream, GATFileCPI_Instance *instance_data)
00535 {
00536   /* this adaptor does not maintain instance data, so there is nothing to 
00537      do here */
00538   GATResult retval = GAT_INVALID_PARAMETER;
00539   if (NULL != instance_data)
00540   {
00541     instance_data->instance_data = NULL;
00542     retval = GAT_SUCCESS;
00543   }
00544   return retval;
00545 }
00546   
00547 
00548 /* CPI specific functionality */
00549 
00550 /** fileops_adaptor_FileCPI_Copy  
00551  *  Copy a file from one location to another.
00552  *  Adaptor implementation of file copy capability.
00553  *
00554  * @param data Adaptor-provided data object.
00555  * @param instance_data The instance data of this CPI object
00556  * @param targetLocation Location to copy file to.
00557  * 
00558  * @return An error code.
00559  */
00560 static GATResult 
00561 fileops_adaptor_FileCPI_Copy(void *adaptor_data, 
00562   GATFileCPI_Instance const *data, GATLocation_const targetLocation,
00563   GATFileMode mode)
00564 {
00565   GAT_USES_STATUS(data->context, "fileops_adaptor_FileCPI_Copy");
00566   
00567   char *source = GATLocation_ToString(data->location);
00568   char *target = GATLocation_ToString(targetLocation);
00569 
00570   if (NULL != source && NULL != target)
00571   {
00572     /* get the command prefix from the internal data table */
00573     GATFileOpsAdaptor_Data *internal_data = (GATFileOpsAdaptor_Data *) adaptor_data;
00574     char *copycmd = 
00575       fileops_get_table_entry(internal_data->config_data, "copycmd");
00576     
00577     /* This is a very simple-minded approach, but it works. */
00578     if (NULL != copycmd)
00579     {
00580       char *command_string = 
00581         (char *)malloc(strlen(copycmd) + strlen(source) + strlen(target) + 3);
00582 
00583       if(command_string)
00584       {
00585         /* if the mode if GATFileMode_FailIfExists test, whether the 
00586            destination exists */
00587         struct stat destfile;
00588         
00589         if (GATFileMode_Overwrite == mode || -1 == stat(target, &destfile))
00590         {
00591           int retcode = 0;
00592           
00593           sprintf(command_string, "%s %s %s", copycmd, source, target);
00594           retcode = system(command_string);
00595           
00596           if (0 == retcode)
00597           {
00598             /* fire the file_copied event */
00599             GAT_CREATE_STATUS(fileops_adaptor_FireCopiedEvent(data->context,
00600               data->monitorable, data->source, source));
00601           }
00602 
00603           GAT_CREATE_STATUS(WEXITSTATUS(retcode));
00604         }
00605         else
00606         {
00607           GAT_CREATE_STATUS(GAT_FILEOPEN_ERROR);
00608         }
00609         free(command_string);
00610       }
00611       else
00612       {
00613         GAT_CREATE_STATUS(GAT_MEMORYFAILURE);
00614       }
00615       free(copycmd);
00616     }
00617     else
00618     {
00619       /* something unexpected happened (unable to re-find the copycmd from the
00620          internal data table)
00621        */
00622       GAT_CREATE_STATUS(GAT_FAIL);
00623     }
00624     free(source);
00625     free(target);
00626   }
00627   else
00628   {
00629     GAT_CREATE_STATUS(GAT_MEMORYFAILURE);
00630   }
00631   
00632   return GAT_RETURN_STATUS();
00633 }
00634 
00635 /** fileops_adaptor_FileCPI_Move
00636  *  Move a file from one location to another.
00637  *  Adaptor implementation of file move capability.
00638  *
00639  * @param data Adaptor-provided data object.
00640  * @param instance_data The instance data of this CPI object
00641  * @param targetLocation Location to copy file to.
00642  * 
00643  * @return An error code.
00644  */
00645 static GATResult 
00646 fileops_adaptor_FileCPI_Move(void *adaptor_data, 
00647   GATFileCPI_Instance const *data, GATLocation_const targetLocation,
00648   GATFileMode mode)
00649 {
00650   GAT_USES_STATUS(data->context, "fileops_adaptor_FileCPI_Move");
00651   
00652   char *source = GATLocation_ToString(data->location);
00653   char *target = GATLocation_ToString(targetLocation);
00654 
00655   if (NULL != source && NULL != target)
00656   {
00657     /* get the command prefix from the internal data table */
00658     GATFileOpsAdaptor_Data *internal_data = (GATFileOpsAdaptor_Data *) adaptor_data;
00659     char *copycmd = 
00660       fileops_get_table_entry(internal_data->config_data, "movecmd");
00661     
00662     /* This is a very simple-minded approach, but it works. */
00663     if (NULL != copycmd)
00664     {
00665       char *command_string = 
00666         (char *)malloc(strlen(copycmd) + strlen(source) + strlen(target) + 3);
00667 
00668       if(command_string)
00669       {
00670         /* if the mode if GATFileMode_FailIfExists test, whether the 
00671            destination exists */
00672         struct stat destfile;
00673         
00674         if (GATFileMode_Overwrite == mode || -1 == stat(target, &destfile))
00675         { 
00676           int retcode = 0;
00677           
00678           sprintf(command_string, "%s %s %s", copycmd, source, target);
00679           retcode = system(command_string);
00680 
00681           if (0 == retcode)
00682           {
00683             /* fire the file_copied event */
00684             GAT_CREATE_STATUS(fileops_adaptor_FireMovedEvent(data->context,
00685               data->monitorable, data->source, source));
00686           }
00687           GAT_CREATE_STATUS(WEXITSTATUS(retcode));
00688         }
00689         else
00690         {
00691           GAT_CREATE_STATUS(GAT_FILEOPEN_ERROR); /* destination exists */
00692         }
00693         free(command_string);
00694       }
00695       else
00696       {
00697         GAT_CREATE_STATUS(GAT_MEMORYFAILURE);
00698       }
00699       free(copycmd);
00700     }
00701     else
00702     {
00703       /* something unexpected happened (unable to re-find the movecmd from the
00704          internal data table)
00705        */
00706       GAT_CREATE_STATUS(GAT_FAIL);
00707     }
00708     free(source);
00709     free(target);
00710   }
00711   else
00712   {
00713     GAT_CREATE_STATUS(GAT_MEMORYFAILURE);
00714   }
00715   return GAT_RETURN_STATUS();
00716 }
00717 
00718 /** fileops_adaptor_FileCPI_Delete
00719  *  Delete a file.
00720  *  Adaptor implementation of file delete capability.
00721  *
00722  * @param data Adaptor-provided data object.
00723  * @param instance_data The instance data of this CPI object
00724  * 
00725  * @return An error code.
00726  */
00727 static GATResult 
00728 fileops_adaptor_FileCPI_Delete(void *adaptor_data, 
00729   GATFileCPI_Instance const *data)
00730 {
00731   GAT_USES_STATUS(data->context, "fileops_adaptor_FileCPI_Delete");
00732   
00733   char *source = GATLocation_ToString(data->location);
00734 
00735   if (NULL != source)
00736   {
00737     /* get the command prefix from the internal data table */
00738     GATFileOpsAdaptor_Data *internal_data = (GATFileOpsAdaptor_Data *) adaptor_data;
00739     char *copycmd = 
00740       fileops_get_table_entry(internal_data->config_data, "deletecmd");
00741     
00742     /* This is a very simple-minded approach, but it works. */
00743     if (NULL != copycmd)
00744     {
00745       char *command_string = 
00746         (char *)malloc(strlen(copycmd) + strlen(source) + 3);
00747 
00748       if(command_string)
00749       {
00750         int retcode = 0;
00751         sprintf(command_string, "%s %s", copycmd, source);
00752         retcode = system(command_string);
00753         
00754         if (0 == retcode)
00755         {
00756           /* fire the file_copied event */
00757           GAT_CREATE_STATUS(fileops_adaptor_FireDeletedEvent(data->context, 
00758             data->monitorable, data->source, source));
00759         }
00760 
00761         GAT_CREATE_STATUS(WEXITSTATUS(retcode));
00762         free(command_string);
00763       }
00764       else
00765       {
00766         GAT_CREATE_STATUS(GAT_MEMORYFAILURE);
00767       }
00768       free(copycmd);
00769     }
00770     else
00771     {
00772       /* something unexpected happened (unable to re-find the movecmd from the
00773          internal data table)
00774        */
00775       GAT_CREATE_STATUS(GAT_FAIL);
00776     }
00777     free(source);
00778   }
00779   else
00780   {
00781     GAT_CREATE_STATUS(GAT_MEMORYFAILURE);
00782   }
00783   return GAT_RETURN_STATUS();
00784 }
00785 
00786 /** fileops_adaptor_FileCPI_IsReadable
00787  *  Tests a GATFile test for its readability.
00788  *  Adaptor implementation of the is_readable capability.
00789  *
00790  *  @param data Adaptor-provided data object.
00791  *  @param instance_data The instance data of this CPI object
00792  * 
00793  *  @return An error code.
00794  */
00795 static GATResult 
00796 fileops_adaptor_FileCPI_IsReadable(void *adaptor_data, 
00797   GATFileCPI_Instance const *data)
00798 {
00799   GAT_USES_STATUS(data->context, "fileops_adaptor_FileCPI_IsReadable");
00800   
00801   char *source = GATLocation_ToString(data->location);
00802 
00803   if (NULL != source)
00804   {
00805     struct stat file_status; 
00806     if (0 == stat(source, &file_status))
00807     {
00808       /* file does exist */
00809       GAT_CREATE_STATUS((file_status.st_mode & S_IRUSR) ? GAT_SUCCESS : GAT_FALSE);
00810     }
00811     else
00812     {
00813       /* file does not exist */
00814       GAT_CREATE_STATUS(GAT_FILEOPEN_ERROR);
00815     }
00816     free(source);
00817   }
00818   else
00819   {
00820     GAT_CREATE_STATUS(GAT_MEMORYFAILURE);
00821   }
00822   
00823   return GAT_RETURN_STATUS();
00824 }
00825 
00826 /** fileops_adaptor_FileCPI_IsWritable
00827  *  Tests a GATFile test for its writability.
00828  *  Adaptor implementation of the is_writable capability.
00829  *
00830  *  @param data Adaptor-provided data object.
00831  *  @param instance_data The instance data of this CPI object
00832  * 
00833  *  @return An error code.
00834  */
00835 static GATResult 
00836 fileops_adaptor_FileCPI_IsWritable(void *adaptor_data, 
00837   GATFileCPI_Instance const *data)
00838 {
00839   GAT_USES_STATUS(data->context, "fileops_adaptor_FileCPI_IsWritable");
00840 
00841   char *source = GATLocation_ToString(data->location);
00842 
00843   if (NULL != source)
00844   {
00845     struct stat file_status; 
00846     if (0 == stat(source, &file_status))
00847     {
00848       /* file does exist */
00849       GAT_CREATE_STATUS((file_status.st_mode & S_IWUSR) ? GAT_SUCCESS : GAT_FALSE);
00850     }
00851     else
00852     {
00853       /* file does not exist */
00854       GAT_CREATE_STATUS(GAT_FILEOPEN_ERROR);
00855     }
00856     free(source);
00857   }
00858   else
00859   {
00860     GAT_CREATE_STATUS(GAT_MEMORYFAILURE);
00861   }
00862   
00863   return GAT_RETURN_STATUS();
00864 }
00865 
00866 /** fileops_adaptor_FileCPI_GetLength
00867  *  Returns the size of a GATFile.
00868  *  Adaptor implementation of the get_length capability.
00869  *
00870  *  @param data Adaptor-provided data object.
00871  *  @param instance_data The instance data of this CPI object.
00872  *  @param length The pointer to the variable, which receives the current size
00873  *        of the inspected file.
00874  * 
00875  *  @return An error code.
00876  */
00877 static GATResult 
00878 fileops_adaptor_FileCPI_GetLength(void *adaptor_data, 
00879   GATFileCPI_Instance const *data, unsigned long *length)
00880 {
00881   GAT_USES_STATUS(data->context, "fileops_adaptor_FileCPI_GetLength");
00882   
00883   if (NULL == length)
00884   {
00885     GAT_CREATE_STATUS(GAT_INVALID_PARAMETER);
00886   }
00887   else 
00888   {
00889     struct stat file_status; 
00890     char *source = GATLocation_ToString(data->location);
00891     
00892     *length = (unsigned long)(-1);
00893     if (NULL != source)
00894     {
00895       if (0 == stat(source, &file_status))
00896       {
00897         /* file does exist */
00898         *length = file_status.st_size;
00899       }
00900       else
00901       {
00902         /* file does not exist */
00903         GAT_CREATE_STATUS(GAT_FILEOPEN_ERROR); 
00904       }
00905       free(source);
00906     }
00907     else
00908     {
00909       GAT_CREATE_STATUS(GAT_MEMORYFAILURE); 
00910     }
00911   }
00912   return GAT_RETURN_STATUS();
00913 }
00914   
00915 /** fileops_adaptor_FileCPI_LastWriteTime
00916  *  Returns the last write time of a GATFile.
00917  *  Adaptor implementation of the get_lastwritetime capability.
00918  *
00919  *  @param data Adaptor-provided data object.
00920  *  @param instance_data The instance data of this CPI object.
00921  *  @param lw_time The pointer to the variable, which receives the last write
00922  *        time of the inspected file.
00923  * 
00924  *  @return An error code.
00925  */
00926 static GATResult
00927 fileops_adaptor_FileCPI_LastWriteTime(void *adaptor_data, 
00928   GATFileCPI_Instance const *data, GATTime *lw_time)
00929 {
00930   GAT_USES_STATUS(data->context, "fileops_adaptor_FileCPI_LastWriteTime");
00931   
00932   if (NULL == lw_time)
00933   {
00934     GAT_CREATE_STATUS(GAT_INVALID_PARAMETER);
00935   }
00936   else 
00937   {
00938     struct stat file_status; 
00939     char *source = GATLocation_ToString(data->location);
00940     
00941     *lw_time = NULL;
00942     if (NULL != source)
00943     {
00944       if (0 == stat(source, &file_status))
00945       {
00946         /* file exists */
00947         *lw_time = GATTime_Create(file_status.st_mtime);
00948       }
00949       else
00950       {
00951         /* file does not exist */
00952         GAT_CREATE_STATUS(GAT_FILEOPEN_ERROR);
00953       }
00954       free(source);
00955     }
00956     else
00957     {
00958       GAT_CREATE_STATUS(GAT_MEMORYFAILURE);
00959     }
00960   }
00961   
00962   return GAT_RETURN_STATUS();
00963 }
00964 
00965 /** fileops_adaptor_FileCPI_GetMetrics
00966  *
00967  *  The function fileops_adaptor_FileCPI_GetMetrics should return a list of 
00968  *  GATMetric objects supported by this adaptor. I.e. the adaptor is capable to
00969  *  fire GATMetricEvents for the returned metrics. This list should include all
00970  *  the supported metrics, event like and continuous ones.
00971  *
00972  *  @param data Adaptor-provided data object.
00973  *  @param instance_data Instance data for the CPI provider object.
00974  *  @param metrics The pointer to the variable, which receives the returned 
00975  *        list of metrics.
00976  *
00977  *  @return An error code.
00978  */
00979 static GATResult 
00980 fileops_adaptor_FileCPI_GetMetrics(void *data, 
00981   GATFileCPI_Instance const *instance_data, GATList_GATMetric *metrics)
00982 {
00983   return GATMetric_CreateListOfMetrics(metric_data, __countof(metric_data), 
00984     metrics);
00985 }
00986 
00987 /** fileops_adaptor_FileCPI_GetMetricEvent
00988  *
00989  *  The function fileops_adaptor_FileCPI_GetMetricEvent should return the 
00990  *  GATMetricEvent associated with the given continuous metric. This function
00991  *  gets called for continuous metrics only, since returning the metric event
00992  *  object to the caller is th only way for the client to get access to it.
00993  *
00994  *  @param data Adaptor-provided data object.
00995  *  @param instance_data Instance data for the CPI provider object.
00996  *  @param metric The metric instance describing the metric event to return.
00997  *        This metric should be equivalent to one of the metrics returned by
00998  *        our own GetMetrics CPI function (see above). If this is another
00999  *        (not known to us metric), an error should be returned.
01000  *  @param event The pointer to the variable, which receives the metric event 
01001  *        to return.
01002  *
01003  *  @return An error code.
01004  */
01005 static GATResult 
01006 fileops_adaptor_FileCPI_GetMetricEvent(void *data, 
01007   GATFileCPI_Instance const *instance_data, GATMetric metric, 
01008     GATMetricEvent *event)
01009 {
01010   if (NULL != instance_data)
01011   {
01012     GAT_USES_STATUS(instance_data->context, 
01013       "fileops_adaptor_FileCPI_GetMetricEvent");
01014     
01015     GATMetric target_metric = NULL;
01016     GAT_CREATE_STATUS(GATMetric_CreateMetric(&metric_data[METRIC_FILE_SIZE], 
01017       &target_metric));
01018 
01019     if (GAT_SUCCEEDED(GAT_CURRENT_STATUS()))
01020     {
01021       GATBool isequal = GATFalse;
01022       
01023       GAT_CREATE_STATUS(GATMetric_Equals(target_metric, metric, &isequal));
01024       if (GAT_SUCCEEDED(GAT_CURRENT_STATUS()))
01025       {
01026         if (GATTrue == isequal)
01027         {
01028           GATMetricEvent target_event = GATMetricEvent_Create_Continuous(
01029             instance_data->source, metric, fileops_adaptor_get_file_size, 
01030             instance_data->location);
01031           
01032           if (NULL != target_event)
01033           {
01034             if (NULL != event)
01035             {
01036               *event = target_event;
01037             }
01038             else
01039             {
01040               GATMetricEvent_Destroy(&target_event);
01041               GAT_CREATE_STATUS(GAT_INVALID_PARAMETER);
01042             }
01043           }
01044           else
01045           {
01046             GATMetricEvent_Destroy(&target_event);
01047             GAT_CREATE_STATUS(GAT_MEMORYFAILURE);
01048           }
01049         }
01050         else
01051         {
01052           GAT_CREATE_STATUS(GAT_INVALID_PARAMETER);
01053         }
01054       }
01055 
01056       GATMetric_Destroy(&target_metric);
01057     }
01058     
01059     return GAT_RETURN_STATUS();
01060   }
01061   return GAT_INVALID_HANDLE;
01062 }
01063 
01064 /* local functions */
01065 
01066 /** fileops_get_table_entry
01067  *  @brief Get a table entry
01068  *
01069  *  Retrieve the data from a table, which is associated with a given key.
01070  *  
01071  *  @param table The table from which the data is to be retrieved
01072  *  @param key The key to look for
01073  *
01074  *  @return The actual data or 0 (zero), if no data was found. Note, that the
01075  *        returned data is to be freed by the caller.
01076  */
01077 static char *
01078 fileops_get_table_entry(GATTable_const table, char const *key)
01079 {
01080   char *buffer = NULL;
01081   int len = GATTable_Get_String(table, key, 0, 0);
01082   
01083   if (len > 0) 
01084   {
01085     buffer = (char *)malloc(len+1);
01086     if (NULL != buffer) 
01087     {
01088       if (len != GATTable_Get_String(table, key, buffer, len+1))
01089       {
01090         free(buffer);
01091         buffer = NULL;
01092       }
01093     }
01094   }
01095   return buffer;
01096 }
01097 
01098 /** fileops_copy_config
01099  *  @brief Extract configuration data from the config tables 
01100  *
01101  *  The function fileops_copy_config tries to find the data associated with the
01102  *  given key first in the supplied instance_config table and if not found in 
01103  *  the supplied system_config table. If it isn't found either, it uses the
01104  *  supplied default value.
01105  *  The recovered data is stored into the internal_data table.
01106  *
01107  *  @param internal_data The table, where the recovered data is to be stored in
01108  *  @param system_config The system configuration table
01109  *  @param instance_config The instance specific configuration table
01110  *  @param key The key for which the associated data is to be searched
01111  *  @param default_value The value to be used, if no entries in the 
01112  *        configuration tables was found
01113  *
01114  *  @return A GAT error code.
01115  */
01116 static GATResult
01117 fileops_copy_config(GATTable internal_data, GATTable_const system_config, 
01118   GATTable_const instance_config, char const *key, char const *default_value)
01119 {
01120   GATResult retval = GAT_FAIL;
01121   char *value = fileops_get_table_entry(instance_config, key);
01122   if (NULL != value)
01123   {
01124     retval = GATTable_Add_String(internal_data, key, value);
01125     free(value);
01126   }
01127   else if (NULL != (value = fileops_get_table_entry(system_config, key)))
01128   {
01129     retval = GATTable_Add_String(internal_data, key, value);
01130     free(value);
01131   }
01132   else
01133   {
01134     retval = GATTable_Add_String(internal_data, key, default_value);
01135   }
01136   return retval;
01137 }
01138 
01139 /** GATFileOpsAdaptor_Data_Create
01140  *  This helper creates an instance of a GATFileOpsAdaptor_Data object.
01141  *
01142  *  @return The newly created and initialized GATFileOpsAdaptor_Data object.
01143  */
01144 static GATFileOpsAdaptor_Data *
01145 GATFileOpsAdaptor_Data_Create()
01146 {
01147   GATFileOpsAdaptor_Data *data = 
01148     (GATFileOpsAdaptor_Data *)malloc(sizeof(GATFileOpsAdaptor_Data));
01149   if (NULL != data)
01150   {
01151     data->config_data = GATTable_Create();
01152     if (NULL == data->config_data)
01153     {
01154       free(data);
01155       data = NULL;
01156     }
01157   }
01158   return data;
01159 }
01160 
01161 /** GATFileOpsAdaptor_Data_Destroy
01162  *  This helper destroys an instance of a GATFileOpsAdaptor_Data object.
01163  *
01164  *  @param The GATFileOpsAdaptor_Data object to destroy
01165  */
01166 static void 
01167 GATFileOpsAdaptor_Data_Destroy(GATFileOpsAdaptor_Data *data)
01168 {
01169   if (NULL != data)
01170   {
01171     GATTable_Destroy(&data->config_data);
01172     free(data);
01173   }
01174 }
01175 
01176 /** fileops_adaptor_FireCopiedEvent
01177  *
01178  *  The function fileops_adaptor_FireCopiedEvent fires a 'file copied' event
01179  *  to all registered metric listeners.
01180  */
01181 static GATResult 
01182 fileops_adaptor_FireCopiedEvent(GATContext context, 
01183   GATMonitorable_Impl monitorable, GATObject_const source, char const *name)
01184 {
01185   GAT_USES_STATUS(context, "fileops_adaptor_FireCopiedEvent");
01186   
01187   if (NULL != monitorable && NULL != source && NULL != name)
01188   {
01189     GATMetric metric = NULL;
01190     
01191     GAT_CREATE_STATUS(GATMetric_CreateMetric(&metric_data[METRIC_FILE_COPIED], 
01192       &metric));
01193     if (GAT_SUCCEEDED(GAT_CURRENT_STATUS()))
01194     {
01195       GATMetricEvent event = GATMetricEvent_Create_EventLike(source, metric, 
01196         (void *)name, (GATuint32)(strlen(name) + 1));
01197         
01198       if (NULL != event)
01199       {
01200         GAT_CREATE_STATUS(GATMonitorable_Impl_FireEvent(monitorable, metric, 
01201           event));
01202       }
01203       else
01204       {
01205         GAT_CREATE_STATUS(GAT_MEMORYFAILURE);
01206       }
01207       
01208       GATMetricEvent_Destroy(&event);
01209       GATMetric_Destroy(&metric);
01210     }
01211   }
01212   
01213   return GAT_RETURN_STATUS();
01214 }
01215 
01216 /** fileops_adaptor_FireMovedEvent
01217  *
01218  *  The function fileops_adaptor_FireMovedEvent fires a 'file moved' event
01219  *  to all registered metric listeners.
01220  */
01221 static GATResult 
01222 fileops_adaptor_FireMovedEvent(GATContext context, 
01223   GATMonitorable_Impl monitorable, GATObject_const source, char const *name)
01224 {
01225   GAT_USES_STATUS(context, "fileops_adaptor_FireMovedEvent");
01226   
01227   if (NULL != monitorable && NULL != source && NULL != name)
01228   {
01229     GATMetric metric = NULL;
01230     
01231     GAT_CREATE_STATUS(GATMetric_CreateMetric(&metric_data[METRIC_FILE_MOVED], 
01232       &metric));
01233     if (GAT_SUCCEEDED(GAT_CURRENT_STATUS()))
01234     {
01235       GATMetricEvent event = GATMetricEvent_Create_EventLike(source, metric, 
01236         (void *)name, (GATuint32)(strlen(name) + 1));
01237         
01238       if (NULL != event)
01239       {
01240         GAT_CREATE_STATUS(GATMonitorable_Impl_FireEvent(monitorable, metric, 
01241           event));
01242       }
01243       else
01244       {
01245         GAT_CREATE_STATUS(GAT_MEMORYFAILURE);
01246       }
01247       
01248       GATMetricEvent_Destroy(&event);
01249       GATMetric_Destroy(&metric);
01250     }
01251   }
01252   
01253   return GAT_RETURN_STATUS();
01254 }
01255 
01256 /** fileops_adaptor_FireDeletedEvent
01257  *
01258  *  The function fileops_adaptor_FireDeletedEvent fires a 'file deleted' event
01259  *  to all registered metric listeners.
01260  */
01261 static GATResult 
01262 fileops_adaptor_FireDeletedEvent(GATContext context, 
01263   GATMonitorable_Impl monitorable, GATObject_const source, char const *name)
01264 {
01265   GAT_USES_STATUS(context, "fileops_adaptor_FireDeletedEvent");
01266   
01267   if (NULL != monitorable && NULL != source && NULL != name)
01268   {
01269     GATMetric metric = NULL;
01270     
01271     GAT_CREATE_STATUS(GATMetric_CreateMetric(&metric_data[METRIC_FILE_DELETED], 
01272       &metric));
01273     if (GAT_SUCCEEDED(GAT_CURRENT_STATUS()))
01274     {
01275       GATMetricEvent event = GATMetricEvent_Create_EventLike(source, metric, 
01276         (void *)name, (GATuint32)(strlen(name) + 1));
01277         
01278       if (NULL != event)
01279       {
01280         GAT_CREATE_STATUS(GATMonitorable_Impl_FireEvent(monitorable, metric, 
01281           event));
01282       }
01283       else
01284       {
01285         GAT_CREATE_STATUS(GAT_MEMORYFAILURE);
01286       }
01287       
01288       GATMetricEvent_Destroy(&event);
01289       GATMetric_Destroy(&metric);
01290     }
01291   }
01292   
01293   return GAT_RETURN_STATUS();
01294 }
01295 
01296 /** fileops_adaptor_get_file_size
01297  *
01298  *  The function fileops_adaptor_get_file_size has to return the size of the
01299  *  referenced file.
01300  *  This function gets called, whenever the client code tries to retrieve the 
01301  *  value associated with the corresponding GATMetricEvent.
01302  *
01303  */
01304 static GATResult 
01305 fileops_adaptor_get_file_size(void *data, GATType type, 
01306   void *buffer, GATuint32 size)
01307 {
01308   GATResult retval = GAT_INVALID_PARAMETER;
01309   GATLocation location = (GATLocation) data;
01310   if ((NULL != location) && (NULL != buffer) && 
01311       (size >= sizeof(GATint32)) && (GATType_GATuint32 == type))
01312   {
01313     struct stat file_status; 
01314     char *source = GATLocation_ToString(location);
01315 
01316     if (NULL != source)
01317     {
01318       if (0 == stat(source, &file_status))
01319       {
01320         /* file does exist */
01321         *(GATint32 *)buffer = file_status.st_size;
01322         retval = GAT_SUCCESS;
01323       }
01324       else
01325       {
01326         /* file does not exist */
01327         retval = GAT_FILEOPEN_ERROR; 
01328       }
01329       free(source);
01330     }
01331     else
01332     {
01333       retval = GAT_MEMORYFAILURE; 
01334     }
01335   }
01336   return retval;
01337 }