Changeset bb4d0b5 in mainline


Ignore:
Timestamp:
2025-10-18T19:29:40Z (7 weeks ago)
Author:
Jiri Svoboda <jiri@…>
Branches:
master
Children:
3e41cc4
Parents:
856a7b49
Message:

Allow user to decide whether to retry or abort when I/O error occurs.

Location:
uspace
Files:
3 added
9 edited

Legend:

Unmodified
Added
Removed
  • uspace/app/nav/dlg/newfiledlg.c

    r856a7b49 rbb4d0b5  
    352352}
    353353
    354 /** Destroy prompt dialog.
    355  *
    356  * @param dialog Prompt dialog or @c NULL
     354/** Destroy new file dialog.
     355 *
     356 * @param dialog New file dialog or @c NULL
    357357 */
    358358void new_file_dlg_destroy(new_file_dlg_t *dialog)
     
    365365}
    366366
    367 /** Set mesage dialog callback.
    368  *
    369  * @param dialog Prompt dialog
    370  * @param cb Prompt dialog callbacks
     367/** Set new file dialog callback.
     368 *
     369 * @param dialog new file dialog
     370 * @param cb New file dialog callbacks
    371371 * @param arg Callback argument
    372372 */
     
    378378}
    379379
    380 /** Prompt dialog window close handler.
     380/** New file dialog window close handler.
    381381 *
    382382 * @param window Window
     
    393393}
    394394
    395 /** Prompt dialog window keyboard event handler.
     395/** New file dialog window keyboard event handler.
    396396 *
    397397 * @param window Window
     
    432432}
    433433
    434 /** Prompt dialog OK button click handler.
     434/** New file dialog OK button click handler.
    435435 *
    436436 * @param pbutton Push button
     
    452452}
    453453
    454 /** Prompt dialog cancel button click handler.
     454/** New file dialog cancel button click handler.
    455455 *
    456456 * @param pbutton Push button
  • uspace/app/nav/meson.build

    r856a7b49 rbb4d0b5  
    2929deps = [ 'fmgt', 'ui' ]
    3030src = files(
     31        'dlg/ioerrdlg.c',
    3132        'dlg/newfiledlg.c',
    3233        'dlg/progress.c',
     
    3940
    4041test_src = files(
     42        'dlg/ioerrdlg.c',
    4143        'dlg/newfiledlg.c',
    4244        'dlg/progress.c',
  • uspace/app/nav/nav.c

    r856a7b49 rbb4d0b5  
    3636
    3737#include <fibril.h>
     38#include <fmgt.h>
    3839#include <gfx/coord.h>
    3940#include <stdio.h>
    4041#include <stdlib.h>
    4142#include <str.h>
     43#include <str_error.h>
    4244#include <task.h>
    4345#include <ui/fixed.h>
     
    4648#include <ui/ui.h>
    4749#include <ui/window.h>
     50#include "dlg/ioerrdlg.h"
    4851#include "menu.h"
    4952#include "newfile.h"
     
    8790        .babort = navigator_progress_babort,
    8891        .close = navigator_progress_close
     92};
     93
     94static void navigator_io_err_abort(io_err_dlg_t *, void *);
     95static void navigator_io_err_retry(io_err_dlg_t *, void *);
     96static void navigator_io_err_close(io_err_dlg_t *, void *);
     97
     98static io_err_dlg_cb_t navigator_io_err_dlg_cb = {
     99        .babort = navigator_io_err_abort,
     100        .bretry = navigator_io_err_retry,
     101        .close = navigator_io_err_close
    89102};
    90103
     
    244257        }
    245258
     259        fibril_mutex_initialize(&navigator->io_err_act_lock);
     260        fibril_condvar_initialize(&navigator->io_err_act_cv);
     261        navigator->io_err_act_sel = false;
     262
    246263        *rnavigator = navigator;
    247264        return EOK;
     
    630647}
    631648
     649/** Called by fmgt to query for I/O error recovery action.
     650 *
     651 * @param arg Argument (navigator_t *)
     652 * @param err I/O error report
     653 * @return Recovery action to take.
     654 */
     655fmgt_error_action_t navigator_io_error_query(void *arg, fmgt_io_error_t *err)
     656{
     657        navigator_t *nav = (navigator_t *)arg;
     658        io_err_dlg_t *dlg;
     659        io_err_dlg_params_t params;
     660        fmgt_error_action_t err_act;
     661        char *text1;
     662        errno_t rc;
     663        int rv;
     664
     665        io_err_dlg_params_init(&params);
     666        rv = asprintf(&text1, err->optype == fmgt_io_write ?
     667            "Error writing file %s." : "Error reading file %s.",
     668            err->fname);
     669        if (rv < 0)
     670                return fmgt_er_abort;
     671
     672        params.text1 = text1;
     673        params.text2 = str_error(err->rc);
     674
     675        ui_lock(nav->ui);
     676        rc = io_err_dlg_create(nav->ui, &params, &dlg);
     677        if (rc != EOK) {
     678                ui_unlock(nav->ui);
     679                free(text1);
     680                return fmgt_er_abort;
     681        }
     682
     683        io_err_dlg_set_cb(dlg, &navigator_io_err_dlg_cb, (void *)nav);
     684
     685        ui_unlock(nav->ui);
     686        free(text1);
     687
     688        fibril_mutex_lock(&nav->io_err_act_lock);
     689
     690        while (!nav->io_err_act_sel) {
     691                fibril_condvar_wait(&nav->io_err_act_cv,
     692                    &nav->io_err_act_lock);
     693        }
     694
     695        err_act = nav->io_err_act;
     696        nav->io_err_act_sel = false;
     697        fibril_mutex_unlock(&nav->io_err_act_lock);
     698
     699        return err_act;
     700}
     701
     702/** I/O error dialog abort button was pressed.
     703 *
     704 * @param dlg I/O error dialog
     705 * @param arg Argument (navigator_t *)
     706 */
     707static void navigator_io_err_abort(io_err_dlg_t *dlg, void *arg)
     708{
     709        navigator_t *nav = (navigator_t *)arg;
     710
     711        io_err_dlg_destroy(dlg);
     712
     713        fibril_mutex_lock(&nav->io_err_act_lock);
     714        nav->io_err_act = fmgt_er_abort;
     715        nav->io_err_act_sel = true;
     716        fibril_condvar_signal(&nav->io_err_act_cv);
     717        fibril_mutex_unlock(&nav->io_err_act_lock);
     718}
     719
     720/** I/O error dialog retry button was pressed.
     721 *
     722 * @param dlg I/O error dialog
     723 * @param arg Argument (navigator_t *)
     724 */
     725static void navigator_io_err_retry(io_err_dlg_t *dlg, void *arg)
     726{
     727        navigator_t *nav = (navigator_t *)arg;
     728
     729        io_err_dlg_destroy(dlg);
     730
     731        fibril_mutex_lock(&nav->io_err_act_lock);
     732        nav->io_err_act = fmgt_er_retry;
     733        nav->io_err_act_sel = true;
     734        fibril_condvar_signal(&nav->io_err_act_cv);
     735        fibril_mutex_unlock(&nav->io_err_act_lock);
     736}
     737
     738/** I/O error dialog closure requested.
     739 *
     740 * @param dlg I/O error dialog
     741 * @param arg Argument (navigator_t *)
     742 */
     743static void navigator_io_err_close(io_err_dlg_t *dlg, void *arg)
     744{
     745        navigator_t *nav = (navigator_t *)arg;
     746
     747        io_err_dlg_destroy(dlg);
     748
     749        fibril_mutex_lock(&nav->io_err_act_lock);
     750        nav->io_err_act = fmgt_er_abort;
     751        nav->io_err_act_sel = true;
     752        fibril_condvar_signal(&nav->io_err_act_cv);
     753        fibril_mutex_unlock(&nav->io_err_act_lock);
     754}
     755
    632756/** @}
    633757 */
  • uspace/app/nav/nav.h

    r856a7b49 rbb4d0b5  
    3838
    3939#include <errno.h>
     40#include <fmgt.h>
    4041#include "types/dlg/progress.h"
    4142#include "types/nav.h"
     
    5253extern errno_t navigator_worker_start(navigator_t *, void (*)(void *),
    5354    void *);
     55extern fmgt_error_action_t navigator_io_error_query(void *, fmgt_io_error_t *);
    5456
    5557#endif
  • uspace/app/nav/newfile.c

    r856a7b49 rbb4d0b5  
    6969static fmgt_cb_t new_file_fmgt_cb = {
    7070        .abort_query = new_file_abort_query,
     71        .io_error_query = navigator_io_error_query,
    7172        .progress = new_file_progress,
    7273};
  • uspace/app/nav/types/nav.h

    r856a7b49 rbb4d0b5  
    3838
    3939#include <fibril.h>
     40#include <fmgt.h>
    4041#include <stdbool.h>
    4142#include <ui/fixed.h>
     
    6566        /** Abort current file management operation */
    6667        bool abort_op;
     68
     69        /** @c true if user selected I/O error recovery action */
     70        bool io_err_act_sel;
     71        /** Selected I/O error recovery action */
     72        fmgt_error_action_t io_err_act;
     73        /** Signalled when user selects I/O error recovery action */
     74        fibril_condvar_t io_err_act_cv;
     75        /** Synchronizes access to I/O error recovery action */
     76        fibril_mutex_t io_err_act_lock;
    6777} navigator_t;
    6878
  • uspace/app/newfile/newfile.c

    r856a7b49 rbb4d0b5  
    4949static bool newfile_abort_query(void *);
    5050static void newfile_progress(void *, fmgt_progress_t *);
     51static fmgt_error_action_t newfile_io_error_query(void *, fmgt_io_error_t *);
    5152
    5253static bool prog_upd = false;
     54static bool nonint = false;
    5355static bool quiet = false;
    5456
     
    5759static fmgt_cb_t newfile_fmgt_cb = {
    5860        .abort_query = newfile_abort_query,
    59         .progress = newfile_progress
     61        .io_error_query = newfile_io_error_query,
     62        .progress = newfile_progress,
    6063};
    6164
     
    121124}
    122125
     126/** Called by fmgt to let user choose I/O error recovery action.
     127 *
     128 * @param arg Argument (not used)
     129 * @param err I/O error report
     130 * @return Error recovery action.
     131 */
     132static fmgt_error_action_t newfile_io_error_query(void *arg,
     133    fmgt_io_error_t *err)
     134{
     135        cons_event_t event;
     136        kbd_event_t *ev;
     137        errno_t rc;
     138
     139        (void)arg;
     140
     141        if (nonint)
     142                return fmgt_er_abort;
     143
     144        if (prog_upd)
     145                putchar('\n');
     146
     147        fprintf(stderr, "I/O error %s file '%s' (%s).\n",
     148            err->optype == fmgt_io_write ? "writing" : "reading",
     149            err->fname, str_error(err->rc));
     150        fprintf(stderr, "[A]bort or [R]etry?\n");
     151
     152        if (con == NULL)
     153                return fmgt_er_abort;
     154
     155        while (true) {
     156                rc = console_get_event(con, &event);
     157                if (rc != EOK)
     158                        return fmgt_er_abort;
     159
     160                if (event.type == CEV_KEY && event.ev.key.type == KEY_PRESS) {
     161                        ev = &event.ev.key;
     162                        if ((ev->mods & KM_ALT) == 0 &&
     163                            (ev->mods & KM_CTRL) == 0) {
     164                                if (ev->c == 'r' || ev->c == 'R')
     165                                        return fmgt_er_retry;
     166                                if (ev->c == 'a' || ev->c == 'A')
     167                                        return fmgt_er_abort;
     168                        }
     169                }
     170
     171                if (event.type == CEV_KEY && event.ev.key.type == KEY_PRESS) {
     172                        ev = &event.ev.key;
     173                        if ((ev->mods & KM_ALT) == 0 &&
     174                            (ev->mods & KM_SHIFT) == 0 &&
     175                            (ev->mods & KM_CTRL) != 0) {
     176                                if (ev->key == KC_C)
     177                                        return fmgt_er_abort;
     178                        }
     179                }
     180        }
     181}
     182
    123183int main(int argc, char *argv[])
    124184{
     
    126186        errno_t rc;
    127187        int i;
    128         bool nonint = false;
    129188        bool sparse = false;
    130189        char *fsize = NULL;
     
    210269        rc = fmgt_new_file(fmgt, fname, nbytes, sparse ? nf_sparse : nf_none);
    211270        if (prog_upd)
    212                 printf("\n");
     271                putchar('\n');
    213272        if (rc != EOK) {
    214273                printf("Error creating file: %s.\n", str_error(rc));
  • uspace/lib/fmgt/include/types/fmgt.h

    r856a7b49 rbb4d0b5  
    3939
    4040#include <capa.h>
     41#include <errno.h>
    4142#include <fibril_synch.h>
    4243#include <stdbool.h>
     
    5253} fmgt_progress_t;
    5354
     55/** File management I/O operation type */
     56typedef enum {
     57        /** Read */
     58        fmgt_io_read,
     59        /** Write */
     60        fmgt_io_write
     61} fmgt_io_op_type_t;
     62
     63/** File management I/O error report */
     64typedef struct {
     65        /** File name */
     66        const char *fname;
     67        /** Operation type */
     68        fmgt_io_op_type_t optype;
     69        /** Error code */
     70        errno_t rc;
     71} fmgt_io_error_t;
     72
     73/** File management I/O error recovery action */
     74typedef enum {
     75        /** Retry */
     76        fmgt_er_retry,
     77        /** Abort */
     78        fmgt_er_abort
     79} fmgt_error_action_t;
     80
    5481/** File management callbacks */
    5582typedef struct {
    5683        bool (*abort_query)(void *);
     84        fmgt_error_action_t (*io_error_query)(void *, fmgt_io_error_t *);
    5785        void (*progress)(void *, fmgt_progress_t *);
    5886} fmgt_cb_t;
  • uspace/lib/fmgt/src/fmgt.c

    r856a7b49 rbb4d0b5  
    221221}
    222222
     223/** Stop progress update timer.
     224 *
     225 * @param fmgt File management object
     226 */
     227static void fmgt_timer_stop(fmgt_t *fmgt)
     228{
     229        (void)fibril_timer_clear(fmgt->timer);
     230}
     231
    223232/** Query caller whether operation should be aborted.
    224233 *
     
    232241        else
    233242                return false;
     243}
     244
     245/** Query caller how to recover from I/O error.
     246 *
     247 * @param fmgt File management object
     248 * @param err I/O error report
     249 * @return What error recovery action should be taken.
     250 */
     251static fmgt_error_action_t fmgt_io_error_query(fmgt_t *fmgt,
     252    fmgt_io_error_t *err)
     253{
     254        if (fmgt->cb != NULL && fmgt->cb->io_error_query != NULL)
     255                return fmgt->cb->io_error_query(fmgt->cb_arg, err);
     256        else
     257                return fmgt_er_abort;
    234258}
    235259
     
    250274        uint64_t now;
    251275        char *buffer;
     276        fmgt_io_error_t err;
     277        fmgt_error_action_t action;
    252278        errno_t rc;
    253279
     
    270296        fmgt_initial_progress_update(fmgt);
    271297
     298        /* Create sparse file? */
    272299        if ((flags & nf_sparse) != 0) {
    273300                fmgt->curf_procb = fsize - 1;
     
    280307                        now = BUFFER_SIZE;
    281308
    282                 rc = vfs_write(fd, &pos, buffer, now, &nw);
     309                do {
     310                        rc = vfs_write(fd, &pos, buffer, now, &nw);
     311                        if (rc == EOK)
     312                                break;
     313
     314                        /* I/O error */
     315                        err.fname = fname;
     316                        err.optype = fmgt_io_write;
     317                        err.rc = rc;
     318                        fmgt_timer_stop(fmgt);
     319                        action = fmgt_io_error_query(fmgt, &err);
     320                        fmgt_timer_start(fmgt);
     321                } while (action == fmgt_er_retry);
     322
     323                /* Not recovered? */
    283324                if (rc != EOK) {
    284325                        free(buffer);
Note: See TracChangeset for help on using the changeset viewer.