Changeset 0ce9eb8 in mainline for uspace/lib/fmgt/src


Ignore:
Timestamp:
2026-02-10T12:52:07Z (20 hours ago)
Author:
Jiri Svoboda <jiri@…>
Branches:
master
Children:
857fba8
Parents:
26a9388
git-author:
Jiri Svoboda <jiri@…> (2026-02-10 18:51:59)
git-committer:
Jiri Svoboda <jiri@…> (2026-02-10 12:52:07)
Message:

Ask user what to do if destination file exists while copying.

Location:
uspace/lib/fmgt/src
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/fmgt/src/copy.c

    r26a9388 r0ce9eb8  
    11/*
    2  * Copyright (c) 2025 Jiri Svoboda
     2 * Copyright (c) 2026 Jiri Svoboda
    33 * All rights reserved.
    44 *
     
    5050};
    5151
     52/** Open file.
     53 *
     54 * @param fmgt File management object
     55 * @param fname File name
     56 * @param rfd Place to store file descriptor
     57 * @return EOK on success or an error code
     58 */
     59static errno_t fmgt_open(fmgt_t *fmgt, const char *fname, int *rfd)
     60{
     61        fmgt_io_error_t err;
     62        fmgt_error_action_t action;
     63        errno_t rc;
     64
     65        do {
     66                rc = vfs_lookup_open(fname, WALK_REGULAR, MODE_READ, rfd);
     67                if (rc == EOK)
     68                        break;
     69
     70                /* I/O error */
     71                err.fname = fname;
     72                err.optype = fmgt_io_open;
     73                err.rc = rc;
     74                fmgt_timer_stop(fmgt);
     75                action = fmgt_io_error_query(fmgt, &err);
     76                fmgt_timer_start(fmgt);
     77        } while (action == fmgt_er_retry);
     78
     79        return rc;
     80}
     81
     82/** Create file.
     83 *
     84 * @param fmgt File management object
     85 * @param fname Destination file name
     86 * @param rfd Place to store file descriptor
     87 * @param rskip If @c true, skip existing file and continue
     88 * @return EOK on success or an error code
     89 */
     90static errno_t fmgt_create_file(fmgt_t *fmgt, const char *fname, int *rfd,
     91    bool *rskip)
     92{
     93        fmgt_io_error_t err;
     94        fmgt_error_action_t action;
     95        fmgt_exists_t exists;
     96        fmgt_exists_action_t exaction;
     97        bool may_overwrite = false;
     98        unsigned flags;
     99        errno_t rc;
     100
     101        *rskip = false;
     102
     103        do {
     104                flags = WALK_REGULAR | (may_overwrite ? WALK_MAY_CREATE :
     105                    WALK_MUST_CREATE);
     106                rc = vfs_lookup_open(fname, flags, MODE_WRITE, rfd);
     107                if (rc == EOK)
     108                        break;
     109
     110                if (rc == EEXIST) {
     111                        /* File exists */
     112                        exists.fname = fname;
     113                        fmgt_timer_stop(fmgt);
     114                        exaction = fmgt_exists_query(fmgt, &exists);
     115                        fmgt_timer_start(fmgt);
     116
     117                        if (exaction == fmgt_exr_skip)
     118                                *rskip = true;
     119                        if (exaction != fmgt_exr_overwrite)
     120                                break;
     121
     122                        may_overwrite = true;
     123                } else {
     124                        /* I/O error */
     125                        err.fname = fname;
     126                        err.optype = fmgt_io_create;
     127                        err.rc = rc;
     128                        fmgt_timer_stop(fmgt);
     129                        action = fmgt_io_error_query(fmgt, &err);
     130                        fmgt_timer_start(fmgt);
     131
     132                        if (action != fmgt_er_retry)
     133                                break;
     134                }
     135        } while (true);
     136
     137        return rc;
     138}
     139
     140/** Create directory.
     141 *
     142 * @param fmgt File management object
     143 * @param dname Directory name
     144 * @return EOK on success or an error code
     145 */
     146static errno_t fmgt_create_dir(fmgt_t *fmgt, const char *dname)
     147{
     148        fmgt_io_error_t err;
     149        fmgt_error_action_t action;
     150        errno_t rc;
     151
     152        do {
     153                rc = vfs_link_path(dname, KIND_DIRECTORY, NULL);
     154
     155                /* It is okay if the directory exists. */
     156                if (rc == EOK || rc == EEXIST)
     157                        break;
     158
     159                /* I/O error */
     160                err.fname = dname;
     161                err.optype = fmgt_io_create;
     162                err.rc = rc;
     163
     164                fmgt_timer_stop(fmgt);
     165                action = fmgt_io_error_query(fmgt, &err);
     166                fmgt_timer_start(fmgt);
     167        } while (action == fmgt_er_retry);
     168
     169        if (rc == EEXIST)
     170                return EOK;
     171
     172        return rc;
     173}
     174
     175/** Read data from file.
     176 *
     177 * @param fmgt File management object
     178 * @param fd File descriptor
     179 * @param fname File name (for printing diagnostics)
     180 * @param pos Pointer to current position (will be updated)
     181 * @param buffer Data buffer
     182 * @param nbytes Number of bytes to read
     183 * @param nr Place to store number of bytes read
     184 * @return EOK on success or an error code
     185 */
     186static errno_t fmgt_read(fmgt_t *fmgt, int fd, const char *fname,
     187    aoff64_t *pos, void *buffer, size_t nbytes, size_t *nr)
     188{
     189        char *bp = (char *)buffer;
     190        fmgt_io_error_t err;
     191        fmgt_error_action_t action;
     192        errno_t rc;
     193
     194        do {
     195                rc = vfs_read(fd, pos, bp, nbytes, nr);
     196                if (rc == EOK)
     197                        break;
     198
     199                /* I/O error */
     200                err.fname = fname;
     201                err.optype = fmgt_io_read;
     202                err.rc = rc;
     203                fmgt_timer_stop(fmgt);
     204                action = fmgt_io_error_query(fmgt, &err);
     205                fmgt_timer_start(fmgt);
     206        } while (action == fmgt_er_retry);
     207
     208        /* Not recovered? */
     209        if (rc != EOK)
     210                return rc;
     211
     212        return EOK;
     213}
     214
     215/** Write data to file.
     216 *
     217 * @param fmgt File management object
     218 * @param fd File descriptor
     219 * @param fname File name (for printing diagnostics)
     220 * @param pos Pointer to current position (will be updated)
     221 * @param buffer Pointer to data
     222 * @param nbytes Number of bytes to write
     223 * @return EOK on success or an error code
     224 */
    52225static errno_t fmgt_write(fmgt_t *fmgt, int fd, const char *fname,
    53226    aoff64_t *pos, void *buffer, size_t nbytes)
     
    97270{
    98271        fmgt_t *fmgt = (fmgt_t *)arg;
    99         fmgt_io_error_t err;
    100         fmgt_error_action_t action;
    101         errno_t rc;
    102 
    103         do {
    104                 rc = vfs_link_path(dest, KIND_DIRECTORY, NULL);
    105 
    106                 /* It is okay if the directory exists. */
    107                 if (rc == EOK || rc == EEXIST)
    108                         break;
    109 
    110                 /* I/O error */
    111                 err.fname = dest;
    112                 err.optype = fmgt_io_create;
    113                 err.rc = rc;
    114 
    115                 fmgt_timer_stop(fmgt);
    116                 action = fmgt_io_error_query(fmgt, &err);
    117                 fmgt_timer_start(fmgt);
    118         } while (action == fmgt_er_retry);
    119 
    120         return rc;
     272
     273        (void)dest;
     274        return fmgt_create_dir(fmgt, dest);
    121275}
    122276
     
    137291        aoff64_t wpos = 0;
    138292        char *buffer;
    139         fmgt_io_error_t err;
    140         fmgt_error_action_t action;
     293        bool skip;
    141294        errno_t rc;
    142295
     
    145298                return ENOMEM;
    146299
    147         do {
    148                 rc = vfs_lookup_open(src, WALK_REGULAR, MODE_READ, &rfd);
    149                 if (rc == EOK)
    150                         break;
    151 
    152                 /* I/O error */
    153                 err.fname = src;
    154                 err.optype = fmgt_io_open;
    155                 err.rc = rc;
    156                 fmgt_timer_stop(fmgt);
    157                 action = fmgt_io_error_query(fmgt, &err);
    158                 fmgt_timer_start(fmgt);
    159         } while (action == fmgt_er_retry);
    160 
    161         /* Not recovered? */
     300        rc = fmgt_open(fmgt, src, &rfd);
    162301        if (rc != EOK) {
    163302                free(buffer);
     
    165304        }
    166305
    167         do {
    168                 rc = vfs_lookup_open(dest, WALK_REGULAR | WALK_MAY_CREATE,
    169                     MODE_WRITE, &wfd);
    170                 if (rc == EOK)
    171                         break;
    172 
    173                 /* I/O error */
    174                 err.fname = dest;
    175                 err.optype = fmgt_io_create;
    176                 err.rc = rc;
    177                 fmgt_timer_stop(fmgt);
    178                 action = fmgt_io_error_query(fmgt, &err);
    179                 fmgt_timer_start(fmgt);
    180         } while (action == fmgt_er_retry);
    181 
     306        rc = fmgt_create_file(fmgt, dest, &wfd, &skip);
    182307        if (rc != EOK) {
    183308                free(buffer);
    184309                vfs_put(rfd);
     310
     311                /* User decided to skip and continue. */
     312                if (rc == EEXIST && skip)
     313                        return EOK;
    185314                return rc;
    186315        }
     
    189318
    190319        do {
    191                 do {
    192                         rc = vfs_read(rfd, &rpos, buffer, BUFFER_SIZE, &nr);
    193                         if (rc == EOK)
    194                                 break;
    195 
    196                         /* I/O error */
    197                         err.fname = src;
    198                         err.optype = fmgt_io_read;
    199                         err.rc = rc;
    200                         fmgt_timer_stop(fmgt);
    201                         action = fmgt_io_error_query(fmgt, &err);
    202                         fmgt_timer_start(fmgt);
    203                 } while (action == fmgt_er_retry);
    204 
    205                 /* Not recovered? */
     320                rc = fmgt_read(fmgt, rfd, src, &rpos, buffer, BUFFER_SIZE,
     321                    &nr);
    206322                if (rc != EOK)
    207323                        goto error;
     
    233349}
    234350
    235 /** copy files.
     351/** Copy files.
    236352 *
    237353 * @param fmgt File management object
  • uspace/lib/fmgt/src/fmgt.c

    r26a9388 r0ce9eb8  
    11/*
    2  * Copyright (c) 2025 Jiri Svoboda
     2 * Copyright (c) 2026 Jiri Svoboda
    33 * All rights reserved.
    44 *
     
    283283}
    284284
     285/** Query caller how to recover from existing destination file/directory.
     286 *
     287 * @param fmgt File management object
     288 * @param exists File/directory exists report
     289 * @return What recovery action should be taken.
     290 */
     291fmgt_exists_action_t fmgt_exists_query(fmgt_t *fmgt, fmgt_exists_t *exists)
     292{
     293        if (fmgt->cb != NULL && fmgt->cb->exists_query != NULL)
     294                return fmgt->cb->exists_query(fmgt->cb_arg, exists);
     295        else
     296                return fmgt_exr_abort;
     297}
     298
    285299/** Return base name (without path component).
    286300 *
Note: See TracChangeset for help on using the changeset viewer.