Changeset d101368 in mainline


Ignore:
Timestamp:
2025-11-14T16:41:33Z (3 months ago)
Author:
Jiri Svoboda <jiri@…>
Branches:
master
Children:
3a4c6d9
Parents:
4b2065a6
git-author:
Jiri Svoboda <jiri@…> (2025-11-14 16:32:57)
git-committer:
Jiri Svoboda <jiri@…> (2025-11-14 16:41:33)
Message:

Split new file creation into a separate fmgt module.

Location:
uspace/lib/fmgt
Files:
4 added
5 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/fmgt/include/fmgt.h

    r4b2065a6 rd101368  
    4242#include <stddef.h>
    4343#include <stdint.h>
     44#include "fmgt/newfile.h"
    4445#include "types/fmgt.h"
    4546
     
    4849extern void fmgt_destroy(fmgt_t *);
    4950extern void fmgt_set_init_update(fmgt_t *, bool);
    50 extern errno_t fmgt_new_file_suggest(char **);
    51 extern errno_t fmgt_new_file(fmgt_t *, const char *, uint64_t, fmgt_nf_flags_t);
    5251
    5352#endif
  • uspace/lib/fmgt/meson.build

    r4b2065a6 rd101368  
    2929src = files(
    3030        'src/fmgt.c',
     31        'src/newfile.c'
    3132)
    3233
     
    3435        'test/fmgt.c',
    3536        'test/main.c',
     37        'test/newfile.c'
    3638)
  • uspace/lib/fmgt/src/fmgt.c

    r4b2065a6 rd101368  
    4444
    4545#include "fmgt.h"
    46 
    47 #define NEWNAME_LEN 64
    48 #define BUFFER_SIZE 16384
     46#include "../private/fmgt.h"
    4947
    5048/** Create file management library instance.
     
    106104}
    107105
    108 /** Suggest file name for new file.
    109  *
    110  * @param fmgt File management object
    111  * @param rstr Place to store pointer to newly allocated string
    112  * @return EOK on success or an error code
    113  */
    114 errno_t fmgt_new_file_suggest(char **rstr)
    115 {
    116         errno_t rc;
    117         vfs_stat_t stat;
    118         unsigned u;
    119         char name[NEWNAME_LEN];
    120 
    121         u = 0;
    122         while (true) {
    123                 snprintf(name, sizeof(name), "noname%02u.txt", u);
    124                 rc = vfs_stat_path(name, &stat);
    125                 if (rc != EOK)
    126                         break;
    127 
    128                 ++u;
    129         }
    130 
    131         *rstr = str_dup(name);
    132         if (*rstr == NULL)
    133                 return ENOMEM;
    134 
    135         return EOK;
    136 }
    137 
    138106/** Get progress update report.
    139107 *
     
    180148 * @param fmgt File management object
    181149 */
    182 static void fmgt_initial_progress_update(fmgt_t *fmgt)
     150void fmgt_initial_progress_update(fmgt_t *fmgt)
    183151{
    184152        if (fmgt->do_init_update)
     
    192160 * @param fmgt File management object
    193161 */
    194 static void fmgt_final_progress_update(fmgt_t *fmgt)
     162void fmgt_final_progress_update(fmgt_t *fmgt)
    195163{
    196164        if (fmgt->curf_progr)
     
    216184 * @param fmgt File management object
    217185 */
    218 static void fmgt_timer_start(fmgt_t *fmgt)
     186void fmgt_timer_start(fmgt_t *fmgt)
    219187{
    220188        fibril_timer_set(fmgt->timer, 500000, fmgt_timer_fun, (void *)fmgt);
     
    225193 * @param fmgt File management object
    226194 */
    227 static void fmgt_timer_stop(fmgt_t *fmgt)
     195void fmgt_timer_stop(fmgt_t *fmgt)
    228196{
    229197        (void)fibril_timer_clear(fmgt->timer);
     
    235203 * @return @c true iff operation should be aborted
    236204 */
    237 static bool fmgt_abort_query(fmgt_t *fmgt)
     205bool fmgt_abort_query(fmgt_t *fmgt)
    238206{
    239207        if (fmgt->cb != NULL && fmgt->cb->abort_query != NULL)
     
    249217 * @return What error recovery action should be taken.
    250218 */
    251 static fmgt_error_action_t fmgt_io_error_query(fmgt_t *fmgt,
     219fmgt_error_action_t fmgt_io_error_query(fmgt_t *fmgt,
    252220    fmgt_io_error_t *err)
    253221{
     
    258226}
    259227
    260 /** Create new file.
    261  *
    262  * @param fmgt File management object
    263  * @param fname File name
    264  * @param fsize Size of new file (number of zero bytes to fill in)
    265  * @param flags New file flags
    266  * @return EOK on success or an error code
    267  */
    268 errno_t fmgt_new_file(fmgt_t *fmgt, const char *fname, uint64_t fsize,
    269     fmgt_nf_flags_t flags)
    270 {
    271         int fd;
    272         size_t nw;
    273         aoff64_t pos = 0;
    274         uint64_t now;
    275         char *buffer;
    276         fmgt_io_error_t err;
    277         fmgt_error_action_t action;
    278         errno_t rc;
    279 
    280         buffer = calloc(BUFFER_SIZE, 1);
    281         if (buffer == NULL)
    282                 return ENOMEM;
    283 
    284         rc = vfs_lookup_open(fname, WALK_REGULAR | WALK_MUST_CREATE,
    285             MODE_WRITE, &fd);
    286         if (rc != EOK) {
    287                 free(buffer);
    288                 return rc;
    289         }
    290 
    291         fmgt->curf_procb = 0;
    292         fmgt->curf_totalb = fsize;
    293         fmgt->curf_progr = false;
    294         fmgt_timer_start(fmgt);
    295 
    296         fmgt_initial_progress_update(fmgt);
    297 
    298         /* Create sparse file? */
    299         if ((flags & nf_sparse) != 0) {
    300                 fmgt->curf_procb = fsize - 1;
    301                 pos = fsize - 1;
    302         }
    303 
    304         while (fmgt->curf_procb < fsize) {
    305                 now = fsize - fmgt->curf_procb;
    306                 if (now > BUFFER_SIZE)
    307                         now = BUFFER_SIZE;
    308 
    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? */
    324                 if (rc != EOK) {
    325                         free(buffer);
    326                         vfs_put(fd);
    327                         fmgt_final_progress_update(fmgt);
    328                         return rc;
    329                 }
    330 
    331                 fmgt->curf_procb += nw;
    332 
    333                 /* User requested abort? */
    334                 if (fmgt_abort_query(fmgt)) {
    335                         free(buffer);
    336                         vfs_put(fd);
    337                         fmgt_final_progress_update(fmgt);
    338                         return EINTR;
    339                 }
    340         }
    341 
    342         free(buffer);
    343         vfs_put(fd);
    344         fmgt_final_progress_update(fmgt);
    345         return EOK;
    346 }
    347 
    348228/** @}
    349229 */
  • uspace/lib/fmgt/test/fmgt.c

    r4b2065a6 rd101368  
    3737PCUT_TEST_SUITE(fmgt);
    3838
    39 #define TEMP_DIR "/tmp"
    40 
    41 static void test_fmgt_progress(void *, fmgt_progress_t *);
    42 
    43 static fmgt_cb_t test_fmgt_cb = {
    44         .progress = test_fmgt_progress
    45 };
    46 
    47 typedef struct {
    48         unsigned nupdates;
    49 } test_resp_t;
    50 
    5139/** Create and destroy file management object succeeds. */
    5240PCUT_TEST(create_destroy)
     
    6250}
    6351
    64 /** Suggesting new file name succeeds and returns unique name. */
    65 PCUT_TEST(new_file_suggest)
    66 {
    67         FILE *f = NULL;
    68         char *fname1 = NULL;
    69         char *fname2 = NULL;
    70         errno_t rc;
    71         int rv;
    72 
    73         rc = vfs_cwd_set(TEMP_DIR);
    74         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    75 
    76         /* Suggest unique file name. */
    77         rc = fmgt_new_file_suggest(&fname1);
    78         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    79 
    80         /* See if we can actually create the file. */
    81         f = fopen(fname1, "wx");
    82         PCUT_ASSERT_NOT_NULL(f);
    83         (void) fclose(f);
    84 
    85         /* Now suggest another unique file name. */
    86         rc = fmgt_new_file_suggest(&fname2);
    87         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    88 
    89         /* They should be different. */
    90         PCUT_ASSERT_FALSE(str_cmp(fname1, fname2) == 0);
    91 
    92         /* Remove the file. */
    93         rv = remove(fname1);
    94         PCUT_ASSERT_INT_EQUALS(0, rv);
    95 
    96         free(fname1);
    97         free(fname2);
    98 }
    99 
    100 /** New empty file can be created. */
    101 PCUT_TEST(new_file_empty)
    102 {
    103         fmgt_t *fmgt = NULL;
    104         char *fname = NULL;
    105         errno_t rc;
    106         int rv;
    107 
    108         rc = vfs_cwd_set(TEMP_DIR);
    109         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    110 
    111         rc = fmgt_create(&fmgt);
    112         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    113 
    114         /* Suggest unique file name. */
    115         rc = fmgt_new_file_suggest(&fname);
    116         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    117 
    118         rc = fmgt_new_file(fmgt, fname, 0, nf_none);
    119         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    120 
    121         /* Remove the file [this also verifies the file exists]. */
    122         rv = remove(fname);
    123         PCUT_ASSERT_INT_EQUALS(0, rv);
    124 
    125         free(fname);
    126         fmgt_destroy(fmgt);
    127 }
    128 
    129 /** New zero-filled file can be created. */
    130 PCUT_TEST(new_file_zerofill)
    131 {
    132         FILE *f = NULL;
    133         fmgt_t *fmgt = NULL;
    134         char *fname = NULL;
    135         char buf[128];
    136         errno_t rc;
    137         size_t nr;
    138         size_t total_rd;
    139         size_t i;
    140         int rv;
    141 
    142         rc = vfs_cwd_set(TEMP_DIR);
    143         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    144 
    145         rc = fmgt_create(&fmgt);
    146         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    147 
    148         /* Suggest unique file name. */
    149         rc = fmgt_new_file_suggest(&fname);
    150         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    151 
    152         rc = fmgt_new_file(fmgt, fname, 20000, nf_none);
    153         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    154 
    155         /* Verify the file. */
    156         f = fopen(fname, "rb");
    157         PCUT_ASSERT_NOT_NULL(f);
    158         total_rd = 0;
    159         do {
    160                 nr = fread(buf, 1, sizeof(buf), f);
    161                 for (i = 0; i < nr; i++)
    162                         PCUT_ASSERT_INT_EQUALS(0, buf[i]);
    163 
    164                 total_rd += nr;
    165         } while (nr > 0);
    166 
    167         PCUT_ASSERT_INT_EQUALS(20000, total_rd);
    168 
    169         (void)fclose(f);
    170 
    171         /* Remove the file. */
    172         rv = remove(fname);
    173         PCUT_ASSERT_INT_EQUALS(0, rv);
    174 
    175         free(fname);
    176         fmgt_destroy(fmgt);
    177 }
    178 
    179 /** New sparse file can be created. */
    180 PCUT_TEST(new_file_sparse)
    181 {
    182         FILE *f = NULL;
    183         fmgt_t *fmgt = NULL;
    184         char *fname = NULL;
    185         char buf[128];
    186         errno_t rc;
    187         size_t nr;
    188         size_t total_rd;
    189         size_t i;
    190         int rv;
    191 
    192         rc = vfs_cwd_set(TEMP_DIR);
    193         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    194 
    195         rc = fmgt_create(&fmgt);
    196         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    197 
    198         /* Suggest unique file name. */
    199         rc = fmgt_new_file_suggest(&fname);
    200         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    201 
    202         rc = fmgt_new_file(fmgt, fname, 20000, nf_sparse);
    203         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    204 
    205         /* Verify the file. */
    206         f = fopen(fname, "rb");
    207         PCUT_ASSERT_NOT_NULL(f);
    208         total_rd = 0;
    209         do {
    210                 nr = fread(buf, 1, sizeof(buf), f);
    211                 for (i = 0; i < nr; i++)
    212                         PCUT_ASSERT_INT_EQUALS(0, buf[i]);
    213 
    214                 total_rd += nr;
    215         } while (nr > 0);
    216 
    217         PCUT_ASSERT_INT_EQUALS(20000, total_rd);
    218 
    219         (void)fclose(f);
    220 
    221         /* Remove the file. */
    222         rv = remove(fname);
    223         PCUT_ASSERT_INT_EQUALS(0, rv);
    224 
    225         free(fname);
    226         fmgt_destroy(fmgt);
    227 }
    228 
    229 /** Initial update provided when requested while creating new file. */
    230 PCUT_TEST(new_file_init_upd)
    231 {
    232         FILE *f = NULL;
    233         fmgt_t *fmgt = NULL;
    234         char *fname = NULL;
    235         char buf[128];
    236         errno_t rc;
    237         size_t nr;
    238         size_t total_rd;
    239         size_t i;
    240         test_resp_t resp;
    241         int rv;
    242 
    243         rc = vfs_cwd_set(TEMP_DIR);
    244         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    245 
    246         rc = fmgt_create(&fmgt);
    247         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    248 
    249         fmgt_set_cb(fmgt, &test_fmgt_cb, (void *)&resp);
    250         resp.nupdates = 0;
    251 
    252         fmgt_set_init_update(fmgt, true);
    253 
    254         /* Suggest unique file name. */
    255         rc = fmgt_new_file_suggest(&fname);
    256         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    257 
    258         rc = fmgt_new_file(fmgt, fname, 20000, nf_none);
    259         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    260 
    261         /* Verify the file. */
    262         f = fopen(fname, "rb");
    263         PCUT_ASSERT_NOT_NULL(f);
    264         total_rd = 0;
    265         do {
    266                 nr = fread(buf, 1, sizeof(buf), f);
    267                 for (i = 0; i < nr; i++)
    268                         PCUT_ASSERT_INT_EQUALS(0, buf[i]);
    269 
    270                 total_rd += nr;
    271         } while (nr > 0);
    272 
    273         PCUT_ASSERT_INT_EQUALS(20000, total_rd);
    274 
    275         (void)fclose(f);
    276 
    277         PCUT_ASSERT_TRUE(resp.nupdates > 0);
    278 
    279         /* Remove the file. */
    280         rv = remove(fname);
    281         PCUT_ASSERT_INT_EQUALS(0, rv);
    282 
    283         free(fname);
    284         fmgt_destroy(fmgt);
    285 }
    286 
    287 static void test_fmgt_progress(void *arg, fmgt_progress_t *progress)
    288 {
    289         test_resp_t *resp = (test_resp_t *)arg;
    290 
    291         (void)progress;
    292         ++resp->nupdates;
    293 }
    294 
    29552PCUT_EXPORT(fmgt);
  • uspace/lib/fmgt/test/main.c

    r4b2065a6 rd101368  
    3232
    3333PCUT_IMPORT(fmgt);
     34PCUT_IMPORT(newfile);
    3435
    3536PCUT_MAIN();
Note: See TracChangeset for help on using the changeset viewer.