L4Re/departure

Annotated libfsserver/lib/directories/ext2_directory_accessor.cc

645:3047b11cc814
7 months ago Paul Boddie Fixed the file_data_available result to return zero if the populated span has somehow become less than the current position in the memory region.
paul@202 1
/*
paul@202 2
 * An object for a directory provided by an Ext2-compatible filesystem.
paul@202 3
 *
paul@417 4
 * Copyright (C) 2021, 2022 Paul Boddie <paul@boddie.org.uk>
paul@202 5
 *
paul@202 6
 * This program is free software; you can redistribute it and/or
paul@202 7
 * modify it under the terms of the GNU General Public License as
paul@202 8
 * published by the Free Software Foundation; either version 2 of
paul@202 9
 * the License, or (at your option) any later version.
paul@202 10
 *
paul@202 11
 * This program is distributed in the hope that it will be useful,
paul@202 12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
paul@202 13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
paul@202 14
 * GNU General Public License for more details.
paul@202 15
 *
paul@202 16
 * You should have received a copy of the GNU General Public License
paul@202 17
 * along with this program; if not, write to the Free Software
paul@202 18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor,
paul@202 19
 * Boston, MA  02110-1301, USA
paul@202 20
 */
paul@202 21
paul@202 22
#include <dirent.h>
paul@202 23
#include <string.h>
paul@202 24
paul@202 25
#include <fsclient/client.h>
paul@202 26
paul@202 27
#include "ext2_directory_accessor.h"
paul@202 28
paul@202 29
paul@202 30
paul@202 31
/* Common definitions. */
paul@202 32
paul@202 33
#define DIRENT_CORE_SIZE (sizeof(struct dirent) - sizeof(((struct dirent *) 0)->d_name))
paul@202 34
paul@202 35
/* File type conversion. */
paul@202 36
paul@202 37
static int convert_file_type(int type)
paul@202 38
{
paul@202 39
  switch (type)
paul@202 40
  {
paul@202 41
    case EXT2_FT_REG_FILE:  return DT_REG;
paul@202 42
    case EXT2_FT_DIR:       return DT_DIR;
paul@202 43
    case EXT2_FT_CHRDEV:    return DT_CHR;
paul@202 44
    case EXT2_FT_BLKDEV:    return DT_BLK;
paul@202 45
    case EXT2_FT_FIFO:      return DT_FIFO;
paul@202 46
    case EXT2_FT_SOCK:      return DT_SOCK;
paul@202 47
    case EXT2_FT_SYMLINK:   return DT_LNK;
paul@202 48
    default:                return DT_UNKNOWN;
paul@202 49
  }
paul@202 50
}
paul@202 51
paul@202 52
/* Helper function to ensure alignment in generated entries. */
paul@202 53
paul@202 54
static int pad_align(int value)
paul@202 55
{
paul@417 56
  return value + (sizeof(l4_umword_t) - (value % sizeof(l4_umword_t)));
paul@202 57
}
paul@202 58
paul@202 59
/* Callback function. */
paul@202 60
paul@202 61
static int read_directory_entry(struct ext2_dir_entry *dir_entry, int offset,
paul@202 62
                                int blocksize, char *buf, void *priv_data)
paul@202 63
{
paul@202 64
    (void) offset; (void) blocksize; (void) buf;
paul@202 65
paul@202 66
    struct Ext2DirectoryState *dir = reinterpret_cast<struct Ext2DirectoryState *>(priv_data);
paul@202 67
paul@202 68
    dir->entry = dir_entry;
paul@202 69
    dir->offset = offset;
paul@202 70
    return dir->directory->write_directory_entry(dir);
paul@202 71
}
paul@202 72
paul@202 73
paul@202 74
paul@202 75
/* Accessor methods. */
paul@202 76
paul@202 77
Ext2DirectoryAccessor::Ext2DirectoryAccessor(Ext2FileOperations *ops,
paul@202 78
                                             fileid_t fileid)
paul@202 79
: _ops(ops), _fileid(fileid)
paul@202 80
{
paul@202 81
}
paul@202 82
paul@202 83
Ext2DirectoryAccessor::~Ext2DirectoryAccessor()
paul@202 84
{
paul@202 85
}
paul@202 86
paul@202 87
/* Thread payload helper method. */
paul@202 88
paul@202 89
void Ext2DirectoryAccessor::read_directory(file_t *writer)
paul@202 90
{
paul@202 91
    /* Initialise directory reading state: directory, writer, entry, offset. */
paul@202 92
paul@202 93
    struct Ext2DirectoryState dir = {this, writer, NULL, 0};
paul@202 94
paul@202 95
    /* Call the handler function for each directory entry. */
paul@202 96
paul@202 97
    _ops->directory_iterate((ext2_ino_t) _fileid, read_directory_entry, &dir);
paul@202 98
}
paul@202 99
paul@202 100
/* Callback method for directory entry output. */
paul@202 101
paul@202 102
int Ext2DirectoryAccessor::write_directory_entry(struct Ext2DirectoryState *dir)
paul@202 103
{
paul@202 104
    struct ext2_inode inode;
paul@202 105
paul@202 106
    /* Obtain the inode details for metadata. */
paul@202 107
paul@202 108
    if (_ops->read_inode(dir->entry->inode, &inode))
paul@202 109
        return DIRENT_ABORT;
paul@202 110
paul@202 111
    /* Align the size of the entry to avoid problems on architectures which
paul@202 112
       require aligned accesses and where the compiler needs to assume an
paul@202 113
       aligned structure. */
paul@202 114
paul@202 115
    offset_t namelen = ext2fs_dirent_name_len(dir->entry);
paul@202 116
    offset_t reclen = pad_align(DIRENT_CORE_SIZE + namelen);
paul@202 117
paul@202 118
    /* Construct a directory entry structure of the calculated size. */
paul@202 119
paul@202 120
    char buffer[reclen];
paul@202 121
    struct dirent *dirent = (struct dirent *) buffer;
paul@202 122
paul@417 123
    memset(dirent, 0, reclen);
paul@417 124
paul@202 125
    dirent->d_ino = dir->entry->inode;
paul@202 126
    dirent->d_off = dir->offset;
paul@202 127
    dirent->d_reclen = reclen;
paul@202 128
    dirent->d_type = convert_file_type(ext2fs_dirent_file_type(dir->entry));
paul@202 129
paul@202 130
    /* Copy the name, padding the memory after it to the alignment boundary. */
paul@202 131
paul@202 132
    memcpy(dirent->d_name, dir->entry->name, namelen);
paul@202 133
paul@202 134
    /* Write the structure to the pipe. */
paul@202 135
paul@202 136
    offset_t nwritten = client_write(dir->writer, (const void *) dirent, reclen);
paul@202 137
paul@202 138
    /* Stop writing if the pipe is closed. */
paul@202 139
paul@202 140
    if (nwritten < reclen)
paul@202 141
        return DIRENT_ABORT;
paul@202 142
paul@202 143
    return 0;
paul@202 144
}
paul@202 145
paul@202 146
// vim: tabstop=4 expandtab shiftwidth=4