Sebastián Pastor / EtheriosCloudConnector
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers connector_file_system.h Source File

connector_file_system.h

00001 /*
00002  * Copyright (c) 2013 Digi International Inc.,
00003  * All rights not expressly granted are reserved.
00004  *
00005  * This Source Code Form is subject to the terms of the Mozilla Public
00006  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
00007  * You can obtain one at http://mozilla.org/MPL/2.0/.
00008  *
00009  * Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343
00010  * =======================================================================
00011  */
00012 
00013 #define FS_TRUNC_FLAG            0x01
00014 #define FS_IS_DIR_FLAG           0x01
00015 #define FS_IS_REG_FLAG           0x02
00016 #define FS_IS_LARGE_FLAG         0x02
00017 #define FS_LS_SINGLE_FILE        0x10
00018 #define FS_ERROR_INTERNAL_FLAG   0x40
00019 #define FS_SESSION_ERROR_CALLED  0x80
00020 
00021 #define FS_OPCODE_BYTES           1
00022 
00023 typedef enum
00024 {
00025     fs_get_request_opcode = 1,
00026     fs_get_response_opcode,
00027     fs_put_request_opcode,
00028     fs_put_response_opcode,
00029     fs_ls_request_opcode,
00030     fs_ls_response_opcode,
00031     fs_rm_request_opcode,
00032     fs_rm_response_opcode,
00033     fs_error_opcode = 200
00034 } fs_opcode_t;
00035 
00036 typedef enum
00037 {
00038     fs_state_none,
00039     fs_state_stat,
00040     fs_state_open,
00041     fs_state_lseek1,
00042     fs_state_lseek,
00043     fs_state_readdir,
00044     fs_state_stat_dir_entry,
00045     fs_state_closing,
00046     fs_state_closed
00047 }fs_state_t;
00048 
00049 typedef struct
00050 {
00051     void * user_context;
00052     void * errnum;
00053 } fs_user_data;
00054 
00055 typedef struct
00056 {
00057     void * user_context;
00058     void * errnum;
00059 
00060     void * handle;
00061 
00062     union
00063     {
00064         struct
00065         {
00066             uint32_t bytes_done;
00067             uint32_t data_length;
00068             connector_file_offset_t offset;
00069         } f;
00070         struct
00071         {
00072             char path[CONNECTOR_FILE_SYSTEM_MAX_PATH_LENGTH];
00073             size_t path_len;
00074             uint32_t last_modified;
00075             connector_file_offset_t file_size;
00076             connector_file_system_hash_algorithm_t hash_alg;
00077         } d;
00078     }data;
00079 
00080     fs_opcode_t opcode;
00081     connector_status_t status;
00082     fs_state_t state;
00083     uint8_t flags;
00084 
00085 } fs_context_t;
00086 
00087 #define FsIsOpen(context) (((context)!=NULL) && ((context)->state >= fs_state_open) && ((context)->state < fs_state_closed))
00088 
00089 #define FsIsBitSet(flag, bit)  (((flag) & (bit)) == (bit))
00090 #define FsBitSet(flag, bit)    ((flag) |= (bit))
00091 #define FsBitClear(flag, bit)  ((flag) &= ~(bit))
00092 
00093 #define FsIsDir(context)    FsIsBitSet(context->flags, FS_IS_DIR_FLAG)
00094 #define FsSetDir(context)   FsBitSet(context->flags, FS_IS_DIR_FLAG)
00095 #define FsClearDir(context) FsBitClear(context->flags, FS_IS_DIR_FLAG)
00096 
00097 #define FsIsReg(context)    FsIsBitSet(context->flags, FS_IS_REG_FLAG)
00098 #define FsSetReg(context)   FsBitSet(context->flags, FS_IS_REG_FLAG)
00099 #define FsClearReg(context) FsBitClear(context->flags, FS_IS_REG_FLAG)
00100 
00101 #define FsNeedTrunc(context)  FsIsBitSet(context->flags, FS_TRUNC_FLAG)
00102 #define FsSetTrunc(context)   FsBitSet(context->flags, FS_TRUNC_FLAG)
00103 #define FsClearTrunc(context) FsBitClear(context->flags, FS_TRUNC_FLAG)
00104 
00105 #define FsIsLsSingleFile(context)   FsIsBitSet(context->flags, FS_LS_SINGLE_FILE)
00106 #define FsSetLsSingleFile(context)  FsBitSet(context->flags, FS_LS_SINGLE_FILE)
00107 
00108 #define FsHasInternalError(context) FsIsBitSet(context->flags, FS_ERROR_INTERNAL_FLAG)
00109 #define FsSetInternalError(context, error) {FsBitSet(context->flags,FS_ERROR_INTERNAL_FLAG); context->errnum=(void *)error;}
00110 
00111 #define FsSessionErrorCalled(context) FsIsBitSet(context->flags, FS_SESSION_ERROR_CALLED)
00112 #define FsSetSessionErrorCalled(context) FsBitSet(context->flags, FS_SESSION_ERROR_CALLED)
00113 
00114 #define FsSetState(context, s) (context->state = s)
00115 #define FsGetState(context)    (context->state)
00116 
00117 
00118 #define FsOperationSuccess(status, context) (status==connector_working && context->errnum==NULL)
00119 
00120 static void fs_set_service_error(msg_service_request_t * const service_request, connector_session_error_t const session_error)
00121 {
00122     service_request->error_value = session_error;
00123     service_request->service_type = msg_service_type_error;
00124 }
00125 
00126 static connector_status_t fs_set_abort(connector_data_t * const connector_ptr,
00127                                    fs_context_t * const context,
00128                                    connector_request_id_file_system_t const file_request,
00129                                    connector_status_t const error_status)
00130 {
00131 
00132     connector_request_id_t request_id;
00133     request_id.file_system_request = file_request;
00134 
00135     notify_error_status(connector_ptr->callback, connector_class_id_file_system, request_id, error_status);
00136     context->status = connector_abort;
00137     return context->status;
00138 }
00139 
00140 typedef enum
00141 {
00142     fs_error_path_too_long,
00143     fs_error_format,
00144     fs_error_invalid_offset,
00145     fs_error_invalid_hash,
00146     fs_error_generic,
00147     fs_error_large_file,
00148     fs_error_session_canceled
00149 }fs_error_internal_t;
00150 
00151 static void fs_get_internal_error_data(connector_file_system_get_error_t * const data)
00152 {
00153 
00154     unsigned long int code = (unsigned long int) data->errnum;
00155 
00156     static struct
00157     {
00158         char const * hint;
00159         connector_file_system_error_t status;
00160 
00161     } error_data[] =
00162     {
00163         {"Path too long",                   connector_file_system_out_of_memory},
00164         {"Request format error",            connector_file_system_request_format_error},
00165         {"Invalid offset",                  connector_file_system_invalid_parameter},
00166         {"Invalid hash algorithm",          connector_file_system_invalid_parameter},
00167         {"Unspecified error",               connector_file_system_unspec_error},
00168         {"Offset is too large or negative", connector_file_system_request_format_error}
00169     };
00170 
00171     switch(code)
00172     {
00173         case fs_error_path_too_long:
00174         case fs_error_format:
00175         case fs_error_invalid_offset:
00176         case fs_error_invalid_hash:
00177         case fs_error_generic:
00178         case fs_error_large_file:
00179             break;
00180 
00181     default:
00182         ASSERT(connector_false);
00183         code = fs_error_generic;
00184         break;
00185     }
00186     ASSERT(code < asizeof(error_data));
00187 
00188     data->error_status = error_data[code].status;
00189     data->bytes_used = MIN_VALUE(data->bytes_available, strlen(error_data[code].hint));
00190     memcpy(data->buffer, error_data[code].hint, data->bytes_used);
00191 }
00192 
00193 static connector_status_t format_file_error_msg(connector_data_t * const connector_ptr,
00194                                                 msg_service_request_t * const service_request,
00195                                                 fs_context_t * const context)
00196 {
00197     connector_status_t status = connector_working;
00198 
00199     if (service_request->service_type != msg_service_type_error) 
00200     {
00201          /* 1st message so let's parse message-start packet:
00202           *
00203           * File System Get request format:
00204           *  ------------------------------------------------------
00205           * |   0    |     +1     |  +1               |    +N      |
00206           *  ------------------------------------------------------
00207           * | Opcode | Error code | Error Hint Length | Error hint |
00208           *  ------------------------------------------------------
00209           *
00210           */
00211          enum  {
00212              field_define(fs_error_response, opcode,         uint8_t),
00213              field_define(fs_error_response, error_code,     uint8_t),
00214              field_define(fs_error_response, error_hint_len, uint8_t),
00215              record_end(fs_error_response_header)
00216          };
00217     
00218          msg_service_data_t * const service_data = service_request->need_data;
00219     
00220          size_t const header_bytes = record_bytes(fs_error_response_header);
00221          size_t const buffer_size  = MIN_VALUE(service_data->length_in_bytes - header_bytes, UCHAR_MAX);
00222     
00223          uint8_t * fs_error_response = service_data->data_ptr;
00224          connector_file_system_get_error_t data;
00225     
00226          data.buffer = fs_error_response + header_bytes;
00227          data.errnum = context->errnum;
00228          data.bytes_available = buffer_size;
00229          data.bytes_used = 0;
00230     
00231          if (FsHasInternalError(context))
00232          {
00233              fs_get_internal_error_data(&data);
00234          }
00235          else
00236          {
00237              connector_request_id_t request_id;
00238              data.user_context = context->user_context;
00239              request_id.file_system_request = connector_request_id_file_system_get_error;
00240              
00241              status = connector_callback(connector_ptr->callback,
00242                                          connector_class_id_file_system,
00243                                          request_id,
00244                                          &data) == connector_callback_continue ? 
00245                             connector_working : connector_abort;
00246     
00247              context->user_context = data.user_context;
00248     
00249              if (status == connector_abort)
00250                  goto done;
00251     
00252              if (data.bytes_used > buffer_size)
00253              {
00254                  fs_set_abort(connector_ptr,
00255                               context,
00256                               connector_request_id_file_system_get_error,
00257                               connector_invalid_data_size);
00258                  status = connector_abort;
00259                  goto done;
00260              }
00261          }
00262          message_store_u8(fs_error_response, opcode, fs_error_opcode);
00263          /* coverity[uninit_use] */
00264          message_store_u8(fs_error_response, error_code, (uint8_t)data.error_status);
00265          message_store_u8(fs_error_response, error_hint_len, (uint8_t) data.bytes_used);
00266     
00267          service_data->length_in_bytes = header_bytes + data.bytes_used;
00268     
00269          MsgSetLastData(service_data->flags);
00270     }
00271 
00272 done:
00273     return status;
00274 }
00275 
00276 static connector_status_t fs_call_user(connector_data_t * const connector_ptr,
00277                                        msg_service_request_t * const service_request,
00278                                        fs_context_t * const context,
00279                                        connector_request_id_file_system_t const fs_request_id,
00280                                        void * const pdata)
00281 {
00282     connector_status_t status = connector_working;
00283     connector_callback_status_t callback_status;
00284     connector_request_id_t request_id;
00285     fs_user_data * const data = pdata;
00286 
00287     request_id.file_system_request = fs_request_id;
00288 
00289     data->user_context = context->user_context;
00290     data->errnum = NULL;
00291 
00292     callback_status = connector_callback(connector_ptr->callback,
00293                                          connector_class_id_file_system,
00294                                          request_id,
00295                                          data);
00296 
00297     context->user_context = data->user_context;
00298 
00299     switch (callback_status)
00300     {
00301         case connector_callback_continue:
00302             status = connector_working;
00303             break;
00304 
00305         case connector_callback_busy:
00306             status = connector_pending;
00307             break;
00308 
00309         case connector_callback_unrecognized:
00310             status = connector_working;
00311             FsSetInternalError(context, fs_error_session_canceled);
00312             fs_set_service_error(service_request, connector_session_error_cancel);
00313             break;
00314 
00315         case connector_callback_abort:
00316             status = context->status = connector_abort;
00317             break;
00318 
00319         case connector_callback_error:
00320             status = connector_working;
00321             /* don't overwrite previous errno */
00322             if (context->errnum == NULL)
00323             {
00324                 if (data->errnum  != NULL)
00325                 {
00326                     /* user returned errno */
00327                     context->errnum = data->errnum;
00328                 }
00329                 else
00330                 {
00331                     /* user returned connector_callback_error without setting errno */
00332                     FsSetInternalError(context, fs_error_generic);
00333                 }
00334             }
00335             break;
00336     }
00337 
00338     return status;
00339 }
00340 
00341 static size_t file_hash_size(connector_file_system_hash_algorithm_t const hash_alg)
00342 {
00343     size_t result;
00344 
00345     switch(hash_alg)
00346     {
00347         case connector_file_system_hash_md5:
00348             result = 16;
00349             break;
00350 
00351         case connector_file_system_hash_crc32:
00352             result = 4;
00353             break;
00354 
00355         default:
00356             result = 0;
00357     }
00358     return result;
00359 }
00360 
00361 static connector_status_t call_file_stat_user(connector_data_t * const connector_ptr,
00362                                               msg_service_request_t * const service_request,
00363                                               fs_context_t * const context,
00364                                               char const * const path,
00365                                               connector_file_system_hash_algorithm_t const hash_alg)
00366 {
00367     connector_status_t status;
00368 
00369     connector_file_system_stat_t data;
00370     data.path = path;
00371     data.hash_algorithm.requested = hash_alg;
00372 
00373     data.statbuf.file_size = 0;
00374     data.statbuf.last_modified = 0;
00375     data.statbuf.flags = connector_file_system_file_type_none;
00376 
00377     status = fs_call_user(connector_ptr,
00378                           service_request,
00379                           context,
00380                           connector_request_id_file_system_stat,
00381                           &data);
00382 
00383     if (status == connector_pending)
00384         goto done;
00385 
00386     if (!FsOperationSuccess(status, context))
00387         goto done;
00388 
00389    context->data.d.file_size = data.statbuf.file_size;
00390    context->data.d.last_modified = data.statbuf.last_modified;
00391 
00392    switch(data.statbuf.flags)
00393    {
00394        case connector_file_system_file_type_is_dir:
00395            FsSetDir(context);
00396            break;
00397 
00398        case connector_file_system_file_type_is_reg:
00399            FsSetReg(context);
00400            break;
00401 
00402        default:
00403            context->flags = 0;
00404            break;
00405    }
00406 
00407    switch(hash_alg)
00408    {
00409        case connector_file_system_hash_none:
00410            context->data.d.hash_alg = hash_alg;
00411            break;
00412 
00413        case connector_file_system_hash_best:
00414            switch(data.hash_algorithm.actual)
00415            {
00416                case connector_file_system_hash_md5:
00417                case connector_file_system_hash_crc32:
00418                    context->data.d.hash_alg = data.hash_algorithm.actual;
00419                    break;
00420 
00421                default:
00422                    context->data.d.hash_alg = connector_file_system_hash_none;
00423                    break;
00424            }
00425            break;
00426 
00427        default:
00428            if (hash_alg != data.hash_algorithm.actual)
00429                context->data.d.hash_alg = connector_file_system_hash_none;
00430            break;
00431    }
00432 
00433    if (context->data.d.hash_alg != connector_file_system_hash_none)
00434    {
00435        if (!FsIsDir(context) && !FsIsReg(context))
00436            context->data.d.hash_alg = connector_file_system_hash_none;
00437    }
00438 done:
00439     return status;
00440 }
00441 
00442 static connector_status_t call_file_stat_dir_entry_user(connector_data_t * const connector_ptr,
00443                                                         msg_service_request_t * const service_request,
00444                                                         fs_context_t * const context,
00445                                                         char const * const path)
00446 {
00447     connector_status_t status;
00448 
00449     connector_file_system_stat_dir_entry_t data;
00450     data.path = path;
00451     data.statbuf.file_size = 0;
00452     data.statbuf.last_modified = 0;
00453     data.statbuf.flags = connector_file_system_file_type_none;
00454 
00455     status = fs_call_user(connector_ptr,
00456                           service_request,
00457                           context,
00458                           connector_request_id_file_system_stat_dir_entry,
00459                           &data);
00460 
00461     if (!FsOperationSuccess(status, context))
00462         goto done;
00463 
00464    context->data.d.file_size = data.statbuf.file_size;
00465    context->data.d.last_modified = data.statbuf.last_modified;
00466 
00467    switch(data.statbuf.flags)
00468    {
00469        case connector_file_system_file_type_is_dir:
00470            FsSetDir(context);
00471            break;
00472 
00473        case connector_file_system_file_type_is_reg:
00474            FsSetReg(context);
00475            break;
00476 
00477        default:
00478            context->flags = 0;
00479            break;
00480    }
00481 
00482 done:
00483     return status;
00484 }
00485 
00486 
00487 static connector_status_t call_file_opendir_user(connector_data_t * const connector_ptr,
00488                                                  msg_service_request_t * const service_request,
00489                                                  fs_context_t * const context,
00490                                                  char const * const path)
00491 {
00492     connector_status_t   status;
00493     connector_file_system_opendir_t data;
00494 
00495     data.path = path;
00496     data.handle = NULL;
00497 
00498     status = fs_call_user(connector_ptr,
00499                           service_request,
00500                           context,
00501                           connector_request_id_file_system_opendir,
00502                           &data);
00503 
00504     if (status == connector_pending)
00505         goto done;
00506 
00507     if (FsOperationSuccess(status, context))
00508     {
00509         if (data.handle != NULL)
00510         {
00511             context->handle = data.handle;
00512             FsSetState(context, fs_state_open);
00513         }
00514         else
00515         {
00516             status = fs_set_abort(connector_ptr,
00517                           context,
00518                           connector_request_id_file_system_opendir,
00519                           connector_invalid_data);
00520         }
00521     }
00522 
00523 done:
00524     return status;
00525 }
00526 
00527 /* This function is a custom implementation of GNU/Linux's non-standard strnlen() */
00528 static int strnlen_(char const * const string, int maxlen)
00529 {
00530     volatile const char *e;
00531     int n;
00532 
00533     for (e = string, n = 0; *e && n < maxlen; e++, n++)
00534         ;
00535 
00536     return n;
00537 }
00538 
00539 static connector_status_t call_file_readdir_user(connector_data_t * const connector_ptr,
00540                                                  msg_service_request_t * const service_request,
00541                                                  fs_context_t * const context,
00542                                                  char * const path,
00543                                                  size_t const buffer_size)
00544 {
00545     connector_status_t  status;
00546 
00547     connector_file_system_readdir_t data;
00548     data.handle = context->handle;
00549     data.entry_name = path;
00550     data.bytes_available = buffer_size;
00551     *path = '\0';
00552 
00553     status = fs_call_user(connector_ptr,
00554                           service_request,
00555                           context,
00556                           connector_request_id_file_system_readdir,
00557                           &data);
00558     if (!FsOperationSuccess(status, context))
00559         goto done;
00560 
00561     if (path[strnlen_(path, buffer_size)] != '\0')
00562     {
00563         /* no NUL-character within buffer */
00564         status =  fs_set_abort(connector_ptr,
00565                                context,
00566                                connector_request_id_file_system_readdir,
00567                                connector_invalid_data_size);
00568      }
00569 
00570 done:
00571     return status;
00572 }
00573 
00574 static connector_status_t call_file_close_user(connector_data_t * const connector_ptr,
00575                                                msg_service_request_t * const service_request,
00576                                                fs_context_t * const context,
00577                                                connector_request_id_file_system_t const fs_request_id)
00578 {
00579     connector_status_t status = context->status;
00580     connector_file_system_close_t data;
00581 
00582     if (!FsIsOpen(context))
00583         goto done;
00584 
00585     data.handle = context->handle;
00586 
00587     FsSetState(context, fs_state_closing);
00588 
00589     status = fs_call_user(connector_ptr,
00590                           service_request,
00591                           context,
00592                           fs_request_id,
00593                           &data);
00594 
00595     if (status == connector_pending)
00596         goto done;
00597 
00598     /* done with close, no matter if success or an error */
00599     FsSetState(context, fs_state_closed);
00600 
00601 done:
00602     return status;
00603 }
00604 
00605 static connector_status_t call_file_hash_user(connector_data_t * const connector_ptr,
00606                                               msg_service_request_t * const service_request,
00607                                               fs_context_t * const context,
00608                                               char const * const path,
00609                                               uint8_t * const hash_ptr)
00610 {
00611     connector_status_t status = connector_working;
00612     connector_file_system_hash_t data;
00613 
00614     data.bytes_requested = file_hash_size(context->data.d.hash_alg);
00615     data.path = path;
00616     data.hash_algorithm = context->data.d.hash_alg;
00617     data.hash_value = hash_ptr;
00618 
00619     status = fs_call_user(connector_ptr,
00620                           service_request,
00621                           context,
00622                           connector_request_id_file_system_hash,
00623                           &data);
00624 
00625     return status;
00626 }
00627 
00628 static connector_status_t call_file_open_user(connector_data_t * const connector_ptr,
00629                                               msg_service_request_t * const service_request,
00630                                               fs_context_t * context,
00631                                               char const * const path,
00632                                               int const oflag)
00633 {
00634     connector_status_t  status;
00635     connector_file_system_open_t data;
00636 
00637     data.path  = path;
00638     data.oflag = oflag;
00639     data.handle = NULL;
00640 
00641     status = fs_call_user(connector_ptr,
00642                           service_request,
00643                           context,
00644                           connector_request_id_file_system_open,
00645                           &data);
00646 
00647     if (status == connector_pending)
00648         goto done;
00649 
00650     if (FsOperationSuccess(status, context))
00651     {
00652         if (data.handle != NULL)
00653         {
00654             context->handle = data.handle;
00655             FsSetState(context, fs_state_open);
00656         }
00657         else
00658         {
00659             status = fs_set_abort(connector_ptr,
00660                           context,
00661                           connector_request_id_file_system_open,
00662                           connector_invalid_data);
00663         }
00664     }
00665 
00666     if (FsGetState(context) != fs_state_open)
00667         FsSetState(context, fs_state_closed);   /* never opened a file */
00668 
00669 done:
00670     return status;
00671 }
00672 
00673 static connector_status_t call_file_lseek_user(connector_data_t * const connector_ptr,
00674                                                msg_service_request_t * const service_request,
00675                                                fs_context_t * const context,
00676                                                connector_file_offset_t const  offset_in,
00677                                                connector_file_system_seek_origin_t  const origin,
00678                                                connector_file_offset_t * const offset_out)
00679 {
00680     connector_file_system_lseek_t data;
00681     connector_status_t status;
00682 
00683     data.handle = context->handle;
00684     data.requested_offset = offset_in;
00685     data.resulting_offset = -1;
00686     data.origin = origin;
00687 
00688     status = fs_call_user(connector_ptr,
00689                           service_request,
00690                           context,
00691                           connector_request_id_file_system_lseek,
00692                           &data);
00693 
00694     *offset_out = data.resulting_offset;
00695 
00696     return status;
00697 }
00698 
00699 
00700 static connector_status_t call_file_ftruncate_user(connector_data_t * const connector_ptr,
00701                                                    msg_service_request_t * const service_request,
00702                                                    fs_context_t * const context)
00703 {
00704     connector_status_t status;
00705     connector_file_system_truncate_t data;
00706 
00707     data.handle = context->handle;
00708     data.length_in_bytes = context->data.f.offset;
00709 
00710     status = fs_call_user(connector_ptr,
00711                           service_request,
00712                           context,
00713                           connector_request_id_file_system_ftruncate,
00714                           &data);
00715     return status;
00716 }
00717 
00718 static connector_status_t call_file_rm_user(connector_data_t * const connector_ptr,
00719                                             msg_service_request_t * const service_request,
00720                                             fs_context_t * const context,
00721                                             char const * const path)
00722 {
00723     connector_status_t status;
00724     connector_file_system_remove_t data;
00725     data.path = path;
00726 
00727     status = fs_call_user(connector_ptr,
00728                           service_request,
00729                           context,
00730                           connector_request_id_file_system_remove,
00731                           &data);
00732     return status;
00733 }
00734 
00735 static connector_status_t call_file_read_user(connector_data_t * const connector_ptr,
00736                                               msg_service_request_t * const service_request,
00737                                               fs_context_t * const context,
00738                                               void   * const buffer,
00739                                               size_t * const buffer_size)
00740 {
00741     connector_status_t status;
00742     connector_file_system_read_t data;
00743 
00744     data.handle = context->handle;
00745     data.buffer = buffer;
00746     data.bytes_available = *buffer_size;
00747     data.bytes_used = 0;
00748 
00749     status = fs_call_user(connector_ptr,
00750                           service_request,
00751                           context,
00752                           connector_request_id_file_system_read,
00753                           &data);
00754 
00755     if (!FsOperationSuccess(status, context))
00756         goto done;
00757 
00758     if (data.bytes_used > *buffer_size)
00759     {
00760         status =  fs_set_abort(connector_ptr,
00761                                context,
00762                                connector_request_id_file_system_read,
00763                                connector_invalid_data_size);
00764         goto done;
00765     }
00766 
00767     *buffer_size = data.bytes_used;
00768 
00769 done:
00770     return status;
00771 }
00772 
00773 static connector_status_t call_file_write_user(connector_data_t * const connector_ptr,
00774                                                msg_service_request_t * const service_request,
00775                                                fs_context_t * const context,
00776                                                void const * const buffer,
00777                                                size_t * const bytes_done)
00778 {
00779     connector_status_t status;
00780     connector_file_system_write_t data;
00781 
00782     data.handle = context->handle;
00783     data.buffer = buffer;
00784     data.bytes_available = *bytes_done;
00785     data.bytes_used = 0;
00786 
00787     status = fs_call_user(connector_ptr,
00788                           service_request,
00789                           context,
00790                           connector_request_id_file_system_write,
00791                           &data);
00792 
00793     if (!FsOperationSuccess(status, context))
00794         goto done;
00795 
00796 
00797     if (data.bytes_used > *bytes_done)
00798     {
00799         status =  fs_set_abort(connector_ptr,
00800                                context,
00801                                connector_request_id_file_system_write,
00802                                connector_invalid_data_size);
00803         goto done;
00804     }
00805 
00806     *bytes_done = data.bytes_used;
00807 
00808     if (*bytes_done == 0)
00809     {
00810         status = connector_pending;
00811     }
00812 
00813 done:
00814     return status;
00815 }
00816 
00817 static size_t parse_file_path(fs_context_t * const context,
00818                               void const * const path_ptr,
00819                               size_t const buffer_size)
00820 {
00821     char const * const path = path_ptr;
00822     size_t path_len = strnlen_(path, buffer_size);
00823 
00824     if (path_len == 0)
00825     {
00826         FsSetInternalError(context, fs_error_format);
00827     }
00828     else
00829     if (path_len >= buffer_size)
00830     {
00831         FsSetInternalError(context, fs_error_path_too_long);
00832         path_len = 0;
00833     }
00834     else
00835         path_len++;
00836 
00837     return path_len;
00838 }
00839 
00840 static size_t parse_file_get_header(fs_context_t * const context,
00841                                     uint8_t const * const header_ptr,
00842                                     size_t const buffer_size)
00843 {
00844 
00845     /* 1st message so let's parse message-start packet:
00846      *
00847      * File System Get request format:
00848      *  -------------------------------------
00849      * |   0    |   N    |  +4    |    +4    |
00850      *  --------------------------------------
00851      * | Opcode | Path   | Offset | Length   |
00852      *  -------------------------------------
00853      *
00854      */
00855 
00856     enum fs_get_request {
00857         field_define(fs_get_request, offset, uint32_t),
00858         field_define(fs_get_request, length, uint32_t),
00859         record_end(fs_get_request_header)
00860     };
00861     uint8_t const * fs_get_request = header_ptr + FS_OPCODE_BYTES;
00862     size_t  const header_len = record_bytes(fs_get_request_header) + FS_OPCODE_BYTES;
00863 
00864     size_t len = parse_file_path(context, fs_get_request, buffer_size - header_len);
00865     if (len == 0)
00866         goto done;
00867 
00868     fs_get_request += len;
00869     context->data.f.offset = message_load_be32(fs_get_request, offset);
00870     if (context->data.f.offset < 0) 
00871     {
00872         FsSetInternalError(context, fs_error_large_file);
00873         len = 0;
00874         goto done;
00875     }
00876     context->data.f.data_length = message_load_be32(fs_get_request, length);
00877     len += header_len;
00878 
00879 done:
00880     return len;
00881 }
00882 
00883 static connector_status_t process_file_get_request(connector_data_t * const connector_ptr,
00884                                                    msg_service_request_t * const service_request,
00885                                                    fs_context_t * const context)
00886 {
00887     msg_service_data_t * const service_data = service_request->have_data;
00888     connector_status_t status = connector_working;
00889 
00890     if (parse_file_get_header(context, service_data->data_ptr, service_data->length_in_bytes) > 0)
00891     {
00892         char const * path = service_data->data_ptr;
00893         path += FS_OPCODE_BYTES;
00894 
00895         status = call_file_open_user(connector_ptr, service_request, context, path, CONNECTOR_FILE_O_RDONLY);
00896     }
00897 
00898     return status;
00899 }
00900 
00901 static connector_status_t set_file_position(connector_data_t * const connector_ptr,
00902                                             msg_service_request_t * const service_request,
00903                                             fs_context_t * const context)
00904 
00905 {
00906     connector_status_t status = connector_working;
00907     connector_file_offset_t ret;
00908 
00909     /* Check that offset is inside the file
00910        Some systems crash, when trying to set offset outside the file
00911      */
00912 
00913     if (FsGetState(context) < fs_state_lseek1)
00914     {
00915         status = call_file_lseek_user(connector_ptr, service_request, context, 0, connector_file_system_seek_end, &ret);
00916         if (!FsOperationSuccess(status, context))
00917             goto done;
00918 
00919         if (ret < context->data.f.offset)
00920         {
00921             ret = -1;
00922             FsSetInternalError(context, fs_error_invalid_offset);
00923             goto done;
00924         }
00925 
00926         FsSetState(context, fs_state_lseek1);
00927         status = call_file_lseek_user(connector_ptr, service_request, context, context->data.f.offset, connector_file_system_seek_set, &ret);
00928         if (FsOperationSuccess(status, context) && ret == -1)
00929         {
00930             FsSetInternalError(context, fs_error_invalid_offset);
00931         }
00932     }
00933 done:
00934     return status;
00935 }
00936 
00937 static connector_status_t process_get_close(connector_data_t * const connector_ptr,
00938                                             msg_service_request_t * const service_request,
00939                                             fs_context_t * const context,
00940                                             connector_request_id_file_system_t close_request)
00941 {
00942 
00943     msg_service_data_t * const service_data = service_request->need_data;
00944     connector_status_t status = connector_working;
00945 
00946     if (FsGetState(context) < fs_state_closed)
00947     {
00948         status = call_file_close_user(connector_ptr,
00949                                       service_request,
00950                                       context,
00951                                       close_request);
00952 
00953         if (status == connector_pending)
00954         {
00955             if (context->status == connector_working &&
00956                 context->errnum == NULL &&
00957                 service_data->length_in_bytes > 0)
00958             {
00959                 /* Return final data portion, will set last bit later
00960                    when closing the file completes in the next callback */
00961                 status = connector_working;
00962             }
00963             goto done;
00964         }
00965     }
00966 
00967     /* finished closing file */
00968     if (context->status == connector_abort)
00969         status = connector_abort;
00970 
00971     /* abort condition or messaging error and session will be canceled */
00972     if (status == connector_abort || service_request->service_type == msg_service_type_error)
00973         goto done;
00974 
00975     /* no errors, set last bit and send out last portion of data */
00976     if (context->errnum == NULL)
00977     {
00978         MsgSetLastData(service_data->flags); 
00979         goto done;
00980     }
00981     /* errors */ 
00982     if (MsgIsStart(service_data->flags))
00983     {
00984         /* send file system-level an error response if no data was sent yet, */
00985         if (format_file_error_msg(connector_ptr, service_request, context) == connector_abort)
00986            status = connector_abort;
00987     }
00988     else
00989     {
00990         /* or cancel the session, if it's late to send a file system level error response */
00991         fs_set_service_error(service_request, connector_session_error_cancel);
00992     }
00993 
00994 done:
00995     return status;
00996 }
00997 
00998 
00999 static connector_status_t process_file_get_response(connector_data_t * const connector_ptr,
01000                                                     msg_service_request_t * const service_request,
01001                                                     fs_context_t * const context)
01002 {
01003     msg_service_data_t * const service_data = service_request->need_data;
01004     connector_status_t status = connector_working;
01005 
01006     if ((context->errnum != NULL) || (FsGetState(context) >= fs_state_closing))
01007     {
01008         service_data->length_in_bytes = 0;
01009         goto close_file;
01010     }
01011 
01012     {
01013         uint8_t * data_ptr = service_data->data_ptr;
01014         size_t buffer_size = service_data->length_in_bytes;
01015         connector_bool_t last_msg = connector_false;
01016         size_t bytes_read = 0;
01017         size_t bytes_to_read;
01018 
01019         if (MsgIsStart(service_data->flags))
01020         {
01021            if (FsGetState(context) < fs_state_lseek)
01022            {
01023                if (context->data.f.offset != 0)
01024                {
01025                     status = set_file_position(connector_ptr, service_request, context);
01026                     if (status == connector_pending)
01027                         goto done;
01028 
01029                     if (!FsOperationSuccess(status, context))
01030                         goto close_file;
01031                }
01032                FsSetState(context, fs_state_lseek);
01033            }
01034            *data_ptr++ = fs_get_response_opcode;
01035            buffer_size--;
01036         }
01037 
01038         /* bytes to read in this callback */
01039         bytes_to_read = MIN_VALUE(buffer_size, context->data.f.data_length - context->data.f.bytes_done);
01040 
01041         while (bytes_to_read > 0)
01042         {
01043             size_t cnt = bytes_to_read;
01044             status = call_file_read_user(connector_ptr, service_request, context, data_ptr, &cnt);
01045 
01046             if (status == connector_pending)
01047             {
01048                 if (bytes_read > 0)
01049                     status = connector_working;  /* Return what's read already */
01050                 break;
01051             }
01052             if (!FsOperationSuccess(status, context))
01053                 goto close_file;
01054 
01055             if (cnt > 0)
01056             {
01057                 data_ptr += cnt;
01058                 bytes_to_read -= cnt;
01059                 bytes_read += cnt;
01060             }
01061             else
01062             {
01063                 bytes_to_read = 0;
01064                 last_msg = connector_true;
01065             }
01066         }
01067         context->data.f.bytes_done += bytes_read;
01068         service_data->length_in_bytes = bytes_read;
01069 
01070         if (MsgIsStart(service_data->flags))
01071             service_data->length_in_bytes++; /* opcode */
01072 
01073         if (context->data.f.data_length == context->data.f.bytes_done)
01074             last_msg = connector_true;
01075 
01076         if (!last_msg)
01077             goto done;
01078     }
01079 
01080 close_file:
01081     status = process_get_close(connector_ptr,
01082                                service_request,
01083                                context,
01084                                connector_request_id_file_system_close);
01085 
01086 done:
01087     return status;
01088 }
01089 
01090 static connector_status_t process_file_rm_request(connector_data_t * const connector_ptr,
01091                                                   msg_service_request_t * const service_request,
01092                                                   fs_context_t * const context)
01093 {
01094     msg_service_data_t * const service_data = service_request->have_data;
01095     char const * path = service_data->data_ptr;
01096     connector_status_t status = connector_working;
01097 
01098     path += FS_OPCODE_BYTES;
01099 
01100     if (parse_file_path(context, path, service_data->length_in_bytes - FS_OPCODE_BYTES) == 0)
01101         goto done;
01102 
01103     status = call_file_rm_user(connector_ptr, service_request, context, path);
01104 
01105 done:
01106     return status;
01107 }
01108 
01109 static connector_status_t process_file_response_nodata(connector_data_t * const connector_ptr,
01110                                                        msg_service_request_t * const service_request,
01111                                                        fs_context_t * const context,
01112                                                        fs_opcode_t const opcode)
01113 {
01114     msg_service_data_t * const service_data = service_request->need_data;
01115     connector_status_t status = connector_working;
01116 
01117     if (context->errnum == NULL)
01118     {
01119         uint8_t * const data_ptr = service_data->data_ptr;
01120 
01121         *data_ptr = opcode;
01122 
01123         service_data->length_in_bytes = sizeof *data_ptr;
01124         MsgSetLastData(service_data->flags);
01125     }
01126     else
01127     {
01128         if (format_file_error_msg(connector_ptr, service_request, context) == connector_abort)
01129         {
01130             status = connector_abort;
01131         }
01132     }
01133     return status;
01134 }
01135 
01136 static size_t parse_file_put_header(fs_context_t * const context,
01137                                     uint8_t const * const header_ptr,
01138                                     size_t const buffer_size)
01139 {
01140     /*
01141      *
01142      * File System Put request format:
01143      *  --------------------------------------------
01144      * |   0    |   N    |  +1   |  +4    |   N     |
01145      *  --------------------------------------------
01146      * | Opcode | Path   | Flags | Offset | Payload |
01147      *  --------------------------------------------
01148      *
01149      */
01150 
01151     enum {
01152         field_define(fs_put_request, flags,  uint8_t),
01153         field_define(fs_put_request, offset, uint32_t),
01154         record_end(fs_put_request_header)
01155     };
01156     uint8_t const *fs_put_request = header_ptr + FS_OPCODE_BYTES;
01157     size_t  const header_len = record_bytes(fs_put_request_header) + FS_OPCODE_BYTES;
01158 
01159     size_t len = parse_file_path(context, fs_put_request, buffer_size - header_len);
01160     if (len == 0)
01161         goto done;
01162 
01163     fs_put_request += len;
01164     context->flags  |= message_load_u8(fs_put_request, flags);
01165     context->data.f.offset = message_load_be32(fs_put_request, offset);
01166     if (context->data.f.offset < 0) 
01167     {
01168         FsSetInternalError(context, fs_error_large_file);
01169         len = 0;
01170         goto done;
01171     }
01172     len   += header_len;
01173 
01174 done:
01175     return len;
01176 }
01177 
01178 
01179 static connector_status_t process_file_put_request(connector_data_t * const connector_ptr,
01180                                                    msg_service_request_t * const service_request,
01181                                                    fs_context_t * const context)
01182 {
01183     connector_status_t status = connector_working;
01184 
01185     if ((context->errnum != NULL) || (FsGetState(context) >= fs_state_closing))
01186         goto close_file;
01187 
01188     {
01189         msg_service_data_t * const service_data = service_request->have_data;
01190         uint8_t const * data_ptr = service_data->data_ptr;
01191         size_t bytes_to_write = service_data->length_in_bytes;
01192         size_t bytes_written = 0;
01193 
01194         if (MsgIsStart(service_data->flags))
01195         {
01196             size_t header_len = parse_file_put_header(context, data_ptr, service_data->length_in_bytes);
01197             if (header_len == 0)
01198                 goto done;
01199 
01200             if (FsGetState(context) < fs_state_open)
01201             {
01202                 int open_flags = CONNECTOR_FILE_O_WRONLY | CONNECTOR_FILE_O_CREAT;
01203                 char const * path = service_data->data_ptr;
01204                 path += FS_OPCODE_BYTES;
01205 
01206                 if (FsNeedTrunc(context))
01207                 {
01208                     if (context->data.f.offset == 0)
01209                     {
01210                         open_flags |= CONNECTOR_FILE_O_TRUNC;
01211                         FsClearTrunc(context);
01212                     }
01213                 }
01214 
01215                 status = call_file_open_user(connector_ptr, service_request, context, path, open_flags);
01216                 if (FsGetState(context) != fs_state_open)
01217                     goto done;
01218             }
01219 
01220             if (FsGetState(context) < fs_state_lseek)
01221             {
01222                 if (context->data.f.offset != 0)
01223                 {
01224                     status = set_file_position(connector_ptr, service_request, context);
01225                     if (status == connector_pending)
01226                         goto done;
01227 
01228                     if (!FsOperationSuccess(status, context))
01229                         goto close_file;
01230                 }
01231                 FsSetState(context, fs_state_lseek);
01232             }
01233             data_ptr  += header_len;
01234             bytes_to_write -= header_len;
01235         }
01236 
01237         data_ptr += context->data.f.bytes_done;
01238         bytes_to_write -= context->data.f.bytes_done;
01239 
01240         while(bytes_to_write > 0)
01241         {
01242             size_t cnt = bytes_to_write;
01243             status = call_file_write_user(connector_ptr, service_request, context, data_ptr, &cnt);
01244 
01245             if (status == connector_pending)
01246             {
01247                 context->data.f.bytes_done += bytes_written;
01248                 context->data.f.offset  += bytes_written;
01249                 goto done;
01250             }
01251             if (!FsOperationSuccess(status, context))
01252                goto close_file;
01253 
01254             data_ptr       += cnt;
01255             bytes_to_write -= cnt;
01256             bytes_written  += cnt;
01257         }
01258         context->data.f.bytes_done = 0;
01259         context->data.f.offset  += bytes_written;
01260 
01261         if (!MsgIsLastData(service_data->flags))
01262             goto done;
01263 
01264         if (FsNeedTrunc(context))
01265         {
01266             status = call_file_ftruncate_user(connector_ptr, service_request, context);
01267             if (status == connector_pending)
01268                 goto done;
01269         }
01270     }
01271 close_file:
01272     status = call_file_close_user(connector_ptr, 
01273                                   service_request, 
01274                                   context, 
01275                                   connector_request_id_file_system_close);
01276     
01277     if (status == connector_pending)
01278         goto done;
01279 
01280     /* finished closing file */
01281     if (context->status == connector_abort)
01282         status = connector_abort;
01283 
01284 done:
01285     return status;
01286 }
01287 
01288 static size_t parse_file_ls_header(fs_context_t * const context,
01289                                    uint8_t const * const header_ptr,
01290                                    size_t const buffer_size)
01291 {
01292     /*
01293      * File System Ls request format:
01294      *  ----------------------------
01295      * |   0    |   N    |   1      |
01296      *  ----------------------------
01297      * | Opcode | Path   | hash alg |
01298      *  ----------------------------
01299      */
01300     uint8_t const * data_ptr = header_ptr + FS_OPCODE_BYTES;
01301     const size_t header_len = 1 + FS_OPCODE_BYTES;
01302     connector_file_system_hash_algorithm_t hash_alg;
01303 
01304     size_t len = parse_file_path(context, data_ptr, buffer_size - header_len);
01305     if (len != 0)
01306     {
01307         data_ptr += len;
01308         len += header_len;
01309 
01310         hash_alg = (connector_file_system_hash_algorithm_t) *data_ptr;
01311 
01312         switch (hash_alg)
01313         {
01314             case connector_file_system_hash_crc32:
01315             case connector_file_system_hash_md5:
01316             case connector_file_system_hash_best:
01317             case connector_file_system_hash_none:
01318                 context->data.d.hash_alg = hash_alg;
01319                 break;
01320 
01321             default:
01322                 FsSetInternalError(context, fs_error_invalid_hash);
01323                 len = 0;
01324         }
01325     }
01326     return len;
01327 }
01328 
01329 static size_t format_file_ls_response_header(connector_file_system_hash_algorithm_t const hash_alg,
01330                                              size_t const hash_size,
01331                                              uint8_t * const data_ptr)
01332 {
01333    /*
01334      * File System Ls response header format:
01335      *  --------------------------------
01336      * |   1    |    1     |    1       |
01337      *  --------------------------------
01338      * | opcode | hash_alg | hash_bytes |
01339      *  --------------------------------
01340      */
01341 
01342     enum {
01343         field_define(fs_ls_response, opcode,     uint8_t),
01344         field_define(fs_ls_response, hash_alg,   uint8_t),
01345         field_define(fs_ls_response, hash_bytes, uint8_t),
01346         record_end(fs_ls_response_header)
01347     };
01348 
01349     uint8_t * fs_ls_response = data_ptr;
01350 
01351     message_store_u8(fs_ls_response, opcode,     fs_ls_response_opcode);
01352     message_store_u8(fs_ls_response, hash_alg,   hash_alg);
01353     message_store_u8(fs_ls_response, hash_bytes, hash_size);
01354 
01355     return record_bytes(fs_ls_response_header);
01356 }
01357 
01358 static size_t file_ls_resp_header_size(void)
01359 {
01360     /*
01361      * File System Ls request format:
01362      *  ----------------------------
01363      * |   1    |     4    |   0/4  |
01364      *  ----------------------------
01365      * | flags  | last     | size   |
01366      * |        | modified |        |
01367      *  ----------------------------
01368      */
01369 
01370     enum  {
01371         field_define(fs_ls_response, flags,  uint8_t),
01372         field_define(fs_ls_response, last_modified, uint32_t),
01373         field_define(fs_ls_response, size, connector_file_offset_t),
01374         record_end(fs_ls_response_file)
01375     };
01376     return record_bytes(fs_ls_response_file);
01377 }
01378 
01379 static size_t format_file_ls_response(fs_context_t const * context,
01380                                       char const * path,
01381                                       size_t const path_len,
01382                                       uint8_t * const data_ptr)
01383 {
01384     /*
01385      * File System Ls request format:
01386      *  ----------------------------
01387      * |   1    |     4    |   0/4  |
01388      *  ----------------------------
01389      * | flags  | last     | size   |
01390      * |        | modified |        |
01391      *  ----------------------------
01392      */
01393 
01394     enum  {
01395         field_define(fs_ls_response, flags,  uint8_t),
01396         field_define(fs_ls_response, last_modified, uint32_t),
01397         record_end(fs_ls_response_dir)
01398     };
01399     enum  {
01400         field_define(fs_ls_response, size, connector_file_offset_t),
01401         record_end(fs_ls_response_file)
01402     };
01403 
01404     uint8_t * fs_ls_response = data_ptr + path_len;
01405     uint8_t flags = FsIsDir(context) ? FS_IS_DIR_FLAG : 0;
01406     size_t result;
01407 
01408 #if (defined CONNECTOR_FILE_SYSTEM_HAS_LARGE_FILES)
01409     flags |= FS_IS_LARGE_FLAG;
01410 #endif
01411     memcpy(data_ptr, path, path_len);
01412 
01413     message_store_u8(fs_ls_response,   flags, flags);
01414     message_store_be32(fs_ls_response, last_modified, context->data.d.last_modified);
01415     result = path_len + record_bytes(fs_ls_response_dir);
01416 
01417     if (!FsIsDir(context))
01418     {
01419         fs_ls_response += record_bytes(fs_ls_response_dir);
01420 #if (defined CONNECTOR_FILE_SYSTEM_HAS_LARGE_FILES)
01421         message_store_be64(fs_ls_response, size, context->data.d.file_size);
01422 #else
01423         message_store_be32(fs_ls_response, size, context->data.d.file_size);
01424 #endif
01425         result += record_bytes(fs_ls_response_file);
01426     }
01427 
01428     return result;
01429 }
01430 
01431 static connector_status_t file_store_path(fs_context_t * const context,
01432                                           char const * const path)
01433 {
01434     connector_status_t status = connector_working;
01435     size_t path_len = strlen(path);
01436 
01437     if (FsIsDir(context) && path[path_len - 1] != '/')
01438     {
01439         path_len++;
01440     }
01441 
01442     if (path_len >= CONNECTOR_FILE_SYSTEM_MAX_PATH_LENGTH)
01443     {
01444         FsSetInternalError(context, fs_error_path_too_long);
01445         goto done;
01446     }
01447 
01448     memcpy(context->data.d.path, path, path_len + 1);
01449 
01450     if (FsIsDir(context) && (path[path_len - 1] != '/'))
01451     {
01452         context->data.d.path[path_len - 1] = '/';
01453         context->data.d.path[path_len] = '\0';
01454     }
01455     context->data.d.path_len = path_len;
01456 
01457 done:
01458     return status;
01459 }
01460 
01461 static connector_status_t process_file_ls_request(connector_data_t * const connector_ptr,
01462                                                   msg_service_request_t * const service_request,
01463                                                   fs_context_t * const context)
01464 {
01465     msg_service_data_t    * const service_data = service_request->have_data;
01466     char const * path = service_data->data_ptr;
01467     connector_status_t status = connector_working;
01468 
01469     path += FS_OPCODE_BYTES;
01470 
01471     if (context->errnum != NULL)
01472         goto done;
01473 
01474     if (parse_file_ls_header(context, service_data->data_ptr, service_data->length_in_bytes) == 0)
01475         goto done;
01476 
01477     if (FsGetState(context) < fs_state_stat)
01478     {
01479         status = call_file_stat_user(connector_ptr, service_request, context, path, context->data.d.hash_alg);
01480         if (!FsOperationSuccess(status, context))
01481         {
01482             goto done;
01483         }
01484 
01485         FsSetState(context, fs_state_stat);
01486     }
01487     if (FsIsDir(context))
01488     {
01489         status = call_file_opendir_user(connector_ptr, service_request, context, path);
01490         if (FsGetState(context) != fs_state_open)
01491             goto done;
01492     }
01493     else
01494     {
01495         FsSetLsSingleFile(context);
01496     }
01497 
01498     /* call_file_stat_user must be done before store path, to strcat '/' to dir path */
01499     status = file_store_path(context, path);
01500 
01501 done:
01502     return status;
01503 }
01504 
01505 static connector_status_t process_file_ls_response(connector_data_t * const connector_ptr,
01506                                                    msg_service_request_t * const service_request,
01507                                                    fs_context_t * const context)
01508 {
01509     msg_service_data_t    * const service_data = service_request->need_data;
01510     connector_status_t status = connector_working;
01511 
01512     if ((context->errnum != NULL) || (FsGetState(context) >= fs_state_closing))
01513     {
01514        service_data->length_in_bytes = 0;
01515        goto close_dir;
01516     }
01517     {
01518         uint8_t * data_ptr = service_data->data_ptr;
01519         size_t buffer_size = service_data->length_in_bytes;
01520         size_t resp_len    = 0;
01521 
01522         size_t const header_len = file_ls_resp_header_size();
01523         size_t hash_len   = file_hash_size(context->data.d.hash_alg);
01524         char * file_path;
01525         size_t file_path_len;
01526 
01527         if (MsgIsStart(service_data->flags))
01528         {
01529             resp_len = format_file_ls_response_header(context->data.d.hash_alg, hash_len, data_ptr);
01530             data_ptr += resp_len;
01531             buffer_size -= resp_len;
01532         }
01533 
01534         if (FsIsLsSingleFile(context))
01535         {
01536             /* ls command was issued for a single file */
01537             file_path_len = context->data.d.path_len + 1;
01538             file_path     = context->data.d.path;
01539 
01540             if ((file_path_len + header_len + hash_len) > buffer_size)
01541             {
01542                 FsSetInternalError(context, fs_error_path_too_long);
01543                 goto close_dir;
01544             }
01545 
01546             if (hash_len != 0)
01547             {
01548                 uint8_t * const hash_ptr = data_ptr + file_path_len + header_len;
01549                 status = call_file_hash_user(connector_ptr, service_request, context, file_path, hash_ptr);
01550                 if (status == connector_pending || status == connector_abort)
01551                     goto done;
01552 
01553                 if (status == connector_working && context->errnum != NULL)
01554                 {
01555                     if (format_file_error_msg(connector_ptr, service_request, context) == connector_abort)
01556                     {
01557                         status = connector_abort;
01558                     }
01559                     goto done;
01560                 }
01561                 resp_len += hash_len;
01562             }
01563 
01564             MsgSetLastData(service_data->flags);
01565         }
01566         else
01567         {
01568             /* ls command was issued for a directory */
01569             file_path = context->data.d.path + context->data.d.path_len;
01570 
01571             while (FsGetState(context) < fs_state_readdir)
01572             {
01573                 /* read next dir entry */
01574                 size_t len = header_len + hash_len + context->data.d.path_len;
01575                 size_t path_max = 0;
01576 
01577                 context->flags = 0;
01578                 /* minimum of bytes left for the entry name in output buffer and context->data.d.path buffer */
01579                 if (len < buffer_size)
01580                     path_max = MIN_VALUE((buffer_size - len), (CONNECTOR_FILE_SYSTEM_MAX_PATH_LENGTH - context->data.d.path_len));
01581 
01582                 status = call_file_readdir_user(connector_ptr, service_request, context, file_path, path_max);
01583                 if (status == connector_pending)
01584                     goto done;
01585 
01586                 if (!FsOperationSuccess(status, context))
01587                     goto close_dir;
01588 
01589                 if (*file_path == '\0')
01590                 {
01591                     /* all entries processed */
01592                     service_data->length_in_bytes = resp_len;
01593                     goto close_dir;
01594                 }
01595                 /* Don't send "." in any directory and ".." in "/" directory up to Device Cloud */
01596                 if ((memcmp(file_path, ".", 2) != 0) &&
01597                     (memcmp(context->data.d.path, "/..", 3) != 0))
01598                 {
01599                     FsSetState(context, fs_state_readdir);
01600                 }
01601             }
01602 
01603             file_path_len = strlen(file_path) + 1;
01604 
01605             if (FsGetState(context) < fs_state_stat_dir_entry)
01606             {
01607                 status = call_file_stat_dir_entry_user(connector_ptr, service_request, context, context->data.d.path);
01608                 if (status == connector_pending)
01609                     goto done;
01610 
01611                 if (!FsOperationSuccess(status, context))
01612                     goto close_dir;
01613 
01614                 FsSetState(context, fs_state_stat_dir_entry);
01615             }
01616             file_path = context->data.d.path;
01617             file_path_len = context->data.d.path_len + file_path_len;
01618 
01619             if (FsIsDir(context))
01620                 hash_len = 0;
01621 
01622             if (hash_len != 0)
01623             {
01624                 uint8_t * const hash_ptr = data_ptr + file_path_len + header_len;
01625 
01626                 if (FsIsReg(context))
01627                 {
01628                     status = call_file_hash_user(connector_ptr, service_request, context, file_path, hash_ptr);
01629                     if (status == connector_pending)
01630                         goto done;
01631     
01632                     if (!FsOperationSuccess(status, context))
01633                         goto close_dir;
01634                 }
01635                 else
01636                 {
01637                     memset(hash_ptr, 0, hash_len);
01638                 }
01639                 resp_len += hash_len;
01640             }
01641 
01642             /* to read next dir entry */
01643             FsSetState(context, fs_state_open);
01644         }
01645         resp_len += format_file_ls_response(context, file_path, file_path_len, data_ptr);
01646         service_data->length_in_bytes = resp_len;
01647         goto done;
01648     }
01649 
01650 close_dir:
01651     status = process_get_close(connector_ptr,
01652                                service_request,
01653                                context,
01654                                connector_request_id_file_system_closedir);
01655 done:
01656     return status;
01657 }
01658 
01659 static connector_status_t allocate_file_context(connector_data_t * const connector_ptr,
01660                                               fs_opcode_t const opcode,
01661                                               fs_context_t * * const result)
01662 {
01663     fs_context_t * context = NULL;
01664     connector_status_t status;
01665 
01666     void * ptr;
01667 
01668     status = malloc_data_buffer(connector_ptr, sizeof *context, named_buffer_id(msg_service), &ptr);
01669     if (status != connector_working)
01670         goto done;
01671 
01672     context = ptr;
01673 
01674     context->handle = NULL;
01675     context->user_context = NULL;
01676     context->flags = 0;
01677     context->errnum = NULL;
01678     context->state = fs_state_none;
01679     context->status = connector_working;
01680 
01681     if (opcode != fs_ls_request_opcode)
01682     {
01683         context->data.f.bytes_done = 0;
01684     }
01685 
01686 done:
01687     *result = context;
01688     return status;
01689 }
01690 
01691 static connector_status_t file_system_request_callback(connector_data_t * const connector_ptr,
01692                                                        msg_service_request_t * const service_request)
01693 {
01694     msg_session_t * const session = service_request->session;
01695     msg_service_data_t * const service_data = service_request->have_data;
01696     fs_context_t * context = session->service_context;
01697     connector_status_t status = connector_working;
01698 
01699     if (MsgIsStart(service_data->flags))
01700     {
01701         if (context == NULL)
01702         {
01703             uint8_t const * const ptr = service_data->data_ptr;
01704             const fs_opcode_t opcode = (fs_opcode_t) *ptr;
01705 
01706             status = allocate_file_context(connector_ptr, opcode, &context);
01707             if (status != connector_working)
01708             {
01709                  goto done;
01710             }
01711             session->service_context = context;
01712             context->opcode = opcode;
01713         }
01714     }
01715     else
01716     {
01717         if (context == NULL)
01718         {
01719             fs_set_service_error(service_request, connector_session_error_format);
01720             ASSERT_GOTO(connector_false, done);
01721         }
01722     }
01723 
01724     if (context->opcode != fs_put_request_opcode)
01725     {
01726         /* don't support request in >1 message */
01727         if ( !(MsgIsStart(service_data->flags) && MsgIsLastData(service_data->flags)) )
01728         {
01729             FsSetInternalError(context, fs_error_path_too_long);
01730             goto done;
01731         }
01732     }
01733 
01734     switch (context->opcode)
01735     {
01736         case fs_get_request_opcode:
01737             status = process_file_get_request(connector_ptr, service_request, context);
01738             break;
01739 
01740         case fs_put_request_opcode:
01741             status = process_file_put_request(connector_ptr, service_request, context);
01742             break;
01743 
01744         case fs_rm_request_opcode:
01745             status = process_file_rm_request(connector_ptr, service_request, context);
01746             break;
01747 
01748         case fs_ls_request_opcode:
01749             status = process_file_ls_request(connector_ptr, service_request, context);
01750             break;
01751 
01752         default:
01753             FsSetInternalError(context, fs_error_format);
01754             ASSERT(connector_false);
01755     }
01756 
01757 done:
01758     return status;
01759 }
01760 
01761 static connector_status_t file_system_response_callback(connector_data_t * const connector_ptr,
01762                                                         msg_service_request_t * const service_request)
01763 {
01764     msg_session_t * const session = service_request->session;
01765     fs_context_t * const context = session->service_context;
01766     connector_status_t status = connector_working;
01767 
01768     if (context == NULL)
01769     {
01770         fs_set_service_error(service_request, connector_session_error_unknown_session);
01771         ASSERT_GOTO(connector_false, done);
01772     }
01773 
01774 
01775     switch (context->opcode)
01776     {
01777         case fs_get_request_opcode:
01778             status = process_file_get_response(connector_ptr, service_request, context);
01779             break;
01780 
01781         case fs_put_request_opcode:
01782             status = process_file_response_nodata(connector_ptr, service_request, context, fs_put_response_opcode);
01783             break;
01784 
01785         case fs_rm_request_opcode:
01786             status = process_file_response_nodata(connector_ptr, service_request, context, fs_rm_response_opcode);
01787             break;
01788 
01789         case fs_ls_request_opcode:
01790             status = process_file_ls_response(connector_ptr, service_request, context);
01791             break;
01792 
01793         default:
01794             fs_set_service_error(service_request, connector_session_error_unknown_session);
01795             ASSERT_GOTO(connector_false, done);
01796             break;
01797     }
01798 
01799 done:
01800     return status;
01801 }
01802 
01803 static connector_status_t file_system_free_callback(connector_data_t * const connector_ptr,
01804                                                     msg_service_request_t * const service_request)
01805 {
01806     msg_session_t * const session = service_request->session;
01807     fs_context_t * const context = session->service_context;
01808     connector_status_t status = connector_working;
01809 
01810     if (context != NULL)
01811     {
01812         status = free_data_buffer(connector_ptr, named_buffer_id(msg_service), context);
01813     }
01814 
01815     return status;
01816 }
01817 
01818 static connector_status_t call_session_error_user(connector_data_t * const connector_ptr,
01819                                                   msg_service_request_t * const service_request,
01820                                                   fs_context_t * const context)
01821 {
01822     connector_status_t status = connector_working;
01823 
01824     if (context != NULL && FsSessionErrorCalled(context)) 
01825         goto done;
01826 
01827     {
01828         connector_file_system_session_error_t data;
01829         connector_request_id_t request_id;
01830         connector_callback_status_t callback_status;
01831     
01832         request_id.file_system_request = connector_request_id_file_system_session_error;
01833         data.session_error = service_request->error_value;
01834         data.user_context = context == NULL ? NULL : context->user_context;
01835     
01836         callback_status = connector_callback(connector_ptr->callback,
01837                                connector_class_id_file_system,
01838                                request_id,
01839                                &data);
01840 
01841         if (context != NULL)
01842             context->user_context = data.user_context;
01843 
01844         switch(callback_status)
01845         {
01846             case connector_callback_busy:
01847                 status = connector_pending;
01848                 goto done;
01849     
01850             case connector_callback_continue:
01851                 break;
01852     
01853             case connector_callback_abort:
01854             default:
01855                 status = connector_abort;
01856                 if (context != NULL) 
01857                     context->status = connector_abort;
01858                 break;
01859         }
01860 
01861         if (context != NULL)
01862             FsSetSessionErrorCalled(context);
01863     }
01864 
01865 done:
01866     return status;
01867 }
01868 
01869 
01870 static connector_status_t file_system_session_error_callback(connector_data_t * const connector_ptr,
01871                                                              msg_service_request_t * const service_request)
01872 {
01873     msg_session_t * const session = service_request->session;
01874     fs_context_t * const context = session->service_context;
01875 
01876     connector_status_t status = call_session_error_user(connector_ptr, service_request, context);
01877 
01878     if (context != NULL) 
01879     {
01880         connector_request_id_file_system_t fs_request_id = context->opcode == fs_ls_request_opcode ?
01881                                         connector_request_id_file_system_closedir : 
01882                                         connector_request_id_file_system_close;
01883 
01884         status = call_file_close_user(connector_ptr, service_request, context, fs_request_id);
01885         if (status == connector_pending)
01886             goto done;
01887 
01888         if (context->status == connector_abort)
01889             status = connector_abort;
01890     }
01891 
01892 done:
01893     return status;
01894 }
01895 
01896 
01897 static connector_status_t file_system_callback(connector_data_t * const connector_ptr,
01898                                                msg_service_request_t * const service_request)
01899 {
01900     connector_status_t status = connector_abort;
01901 
01902     ASSERT_GOTO(connector_ptr != NULL, done);
01903     ASSERT_GOTO(service_request != NULL, done);
01904     ASSERT_GOTO(service_request->session != NULL, done);
01905 
01906     switch (service_request->service_type)
01907     {
01908     case msg_service_type_have_data:
01909         status = file_system_request_callback(connector_ptr, service_request);
01910         break;
01911 
01912     case msg_service_type_need_data:
01913         status = file_system_response_callback(connector_ptr, service_request);
01914         break;
01915 
01916     case msg_service_type_error:
01917          status = file_system_session_error_callback(connector_ptr, service_request);
01918         break;
01919 
01920     case msg_service_type_free:
01921         status = file_system_free_callback(connector_ptr, service_request);
01922         break;
01923 
01924     default:
01925         ASSERT(connector_false);
01926         break;
01927     }
01928 
01929 done:
01930     return status;
01931 }
01932 
01933 static connector_status_t connector_facility_file_system_cleanup(connector_data_t * const connector_ptr)
01934 {
01935     return msg_cleanup_all_sessions(connector_ptr,  msg_service_id_file);
01936 }
01937 
01938 static connector_status_t connector_facility_file_system_delete(connector_data_t * const data_ptr)
01939 {
01940     return msg_delete_facility(data_ptr, msg_service_id_file);
01941 }
01942 
01943 static connector_status_t connector_facility_file_system_init(connector_data_t * const data_ptr, unsigned int const facility_index)
01944 {
01945     return msg_init_facility(data_ptr, facility_index, msg_service_id_file, file_system_callback);
01946 }
01947