Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
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
Generated on Tue Jul 12 2022 19:18:38 by
1.7.2