L4Re/departure

Annotated tests/dstest_host_readdir.cc

160:0bf39e6d7142
2021-08-04 Paul Boddie Added initial support for directory listing retrieval from filesystem objects.
paul@158 1
/*
paul@160 2
 * Test directory reading operations.
paul@158 3
 *
paul@160 4
 * Copyright (C) 2020, 2021 Paul Boddie <paul@boddie.org.uk>
paul@158 5
 *
paul@158 6
 * This program is free software; you can redistribute it and/or
paul@158 7
 * modify it under the terms of the GNU General Public License as
paul@158 8
 * published by the Free Software Foundation; either version 2 of
paul@158 9
 * the License, or (at your option) any later version.
paul@158 10
 *
paul@158 11
 * This program is distributed in the hope that it will be useful,
paul@158 12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
paul@158 13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
paul@158 14
 * GNU General Public License for more details.
paul@158 15
 *
paul@158 16
 * You should have received a copy of the GNU General Public License
paul@158 17
 * along with this program; if not, write to the Free Software
paul@158 18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor,
paul@158 19
 * Boston, MA  02110-1301, USA
paul@158 20
 */
paul@158 21
paul@160 22
#include <l4/re/env.h>
paul@160 23
#include <l4/sys/err.h>
paul@160 24
paul@158 25
#include <dirent.h>
paul@158 26
#include <stdio.h>
paul@160 27
#include <string.h>
paul@160 28
#include <stdlib.h>
paul@160 29
paul@160 30
#include <fsclient/client.h>
paul@160 31
#include <systypes/fcntl.h>
paul@158 32
paul@158 33
paul@158 34
paul@160 35
#define DIRENT_CORE_SIZE (sizeof(struct dirent) - sizeof(((struct dirent *) 0)->d_name))
paul@160 36
paul@158 37
int main(int argc, char *argv[])
paul@158 38
{
paul@158 39
  if (argc < 2)
paul@158 40
  {
paul@160 41
    printf("Need a directory name and an optional user identifier (if used with a filesystem).\n");
paul@160 42
    return 1;
paul@160 43
  }
paul@160 44
paul@160 45
  char *filename = argv[1];
paul@160 46
  bool have_uid = (argc > 2) && strlen(argv[2]);
paul@160 47
  sys_uid_t uid = have_uid ? atoi(argv[2]) : 0;
paul@160 48
  file_t *file;
paul@160 49
paul@160 50
  /* With a user, open a user-specific file opener. */
paul@160 51
paul@160 52
  if (have_uid)
paul@160 53
  {
paul@160 54
    l4_cap_idx_t opener = client_open_for_user((user_t) {uid, uid, 0022});
paul@160 55
paul@160 56
    if (l4_is_invalid_cap(opener))
paul@160 57
    {
paul@160 58
      printf("Could not obtain opener for file.\n");
paul@160 59
      return 1;
paul@160 60
    }
paul@160 61
paul@160 62
    /* Invoke the open method to receive the file reference. */
paul@160 63
paul@160 64
    file = client_open_using(filename, O_DIRECTORY, opener);
paul@160 65
  }
paul@160 66
  else
paul@160 67
  {
paul@160 68
    file = client_open(filename, O_DIRECTORY);
paul@160 69
  }
paul@160 70
paul@160 71
  if (file == NULL)
paul@160 72
  {
paul@160 73
    printf("Could not obtain directory.\n");
paul@158 74
    return 1;
paul@158 75
  }
paul@158 76
paul@160 77
  // NOTE: To be replaced by a proper mechanism identifying the nature of each
paul@160 78
  // NOTE: obtained object.
paul@160 79
paul@160 80
  file->can_mmap = 0;
paul@160 81
  file->has_size = 0;
paul@158 82
paul@160 83
  /* Register the reader for notification. */
paul@160 84
paul@160 85
  long err = client_set_blocking(file, NOTIFY_CONTENT_AVAILABLE);
paul@158 86
paul@160 87
  if (err)
paul@158 88
  {
paul@160 89
    printf("Could not subscribe to notifications: %s\n", l4sys_errtostr(err));
paul@158 90
    return 1;
paul@158 91
  }
paul@158 92
paul@160 93
  char buffer[DIRENT_CORE_SIZE];
paul@160 94
  offset_t nread = client_read(file, buffer, DIRENT_CORE_SIZE);
paul@160 95
  offset_t total = 0;
paul@160 96
paul@160 97
  while (nread)
paul@160 98
  {
paul@160 99
    total += nread;
paul@160 100
paul@160 101
    if (total == DIRENT_CORE_SIZE)
paul@160 102
    {
paul@160 103
      struct dirent *dirent = (struct dirent *) buffer;
paul@160 104
      int remaining = dirent->d_reclen - DIRENT_CORE_SIZE;
paul@160 105
      char entry[DIRENT_CORE_SIZE + remaining], *current;
paul@160 106
paul@160 107
      memcpy(entry, buffer, DIRENT_CORE_SIZE);
paul@160 108
      current = entry + DIRENT_CORE_SIZE;
paul@158 109
paul@160 110
      do
paul@160 111
      {
paul@160 112
        nread = client_read(file, current, remaining);
paul@160 113
        remaining -= nread;
paul@160 114
        current += nread;
paul@160 115
      }
paul@160 116
      while (nread && remaining);
paul@160 117
paul@160 118
      if (remaining)
paul@160 119
        break;
paul@160 120
paul@160 121
      dirent = (struct dirent *) entry;
paul@160 122
      printf("> %s\n", dirent->d_name);
paul@160 123
paul@160 124
      total = 0;
paul@160 125
    }
paul@160 126
paul@160 127
    nread = client_read(file, buffer, DIRENT_CORE_SIZE);
paul@160 128
  }
paul@158 129
paul@158 130
  printf("Directory shown.\n");
paul@158 131
paul@158 132
  return 0;
paul@158 133
}
paul@158 134
paul@158 135
// vim: tabstop=2 expandtab shiftwidth=2