Beispiel #1
0
  error_t FAT::traverse(Path path, dirvector& ents, const Dirent* const start) const
  {
    // start with given entry (defaults to root)
    uint32_t cluster = start ? start->block() : 0;
    Dirent found(this, INVALID_ENTITY);

    while (!path.empty()) {

      auto S = this->cl_to_sector(cluster);
      ents.clear(); // mui importante
      // sync read entire directory
      auto err = int_ls(S, ents);
      if (UNLIKELY(err)) return err;
      // the name we are looking for
      const std::string name = path.front();
      path.pop_front();

      // check for matches in dirents
      for (auto& e : ents)
      if (UNLIKELY(e.name() == name)) {
        // go to this directory, unless its the last name
        FS_PRINT("traverse_sync: Found match for %s", name.c_str());
        // enter the matching directory
        FS_PRINT("\t\t cluster: %lu\n", e.block());
        // only follow if the name is a directory
        if (e.type() == DIR) {
          found = e;
          break;
        }
        else {
          // not dir = error, for now
          return { error_t::E_NOTDIR, "Cannot list non-directory" };
        }
      } // for (ents)

      // validate result
      if (found.type() == INVALID_ENTITY) {
        FS_PRINT("traverse_sync: NO MATCH for %s\n", name.c_str());
        return { error_t::E_NOENT, name };
      }
      // set next cluster
      cluster = found.block();
    }

    auto S = this->cl_to_sector(cluster);
    // read result directory entries into ents
    ents.clear(); // mui importante!
    return int_ls(S, ents);
  }
Beispiel #2
0
  void FAT::init(uint64_t base, uint64_t size, on_init_func on_init)
  {
    this->lba_base = base;
    this->lba_size = size;

    // read Partition block
    device.read(
      base,
      hw::Block_device::on_read_func::make_packed(
      [this, on_init] (buffer_t data)
      {
        auto* mbr = (MBR::mbr*) data->data();
        if (mbr == nullptr) {
          on_init({ error_t::E_IO, "Could not read MBR" }, *this);
          return;
        }

        // verify image signature
        FS_PRINT("OEM name: \t%s\n", mbr->oem_name);
        FS_PRINT("MBR signature: \t0x%x\n", mbr->magic);
        if (UNLIKELY(mbr->magic != 0xAA55)) {
          on_init({ error_t::E_MNT, "Missing or invalid MBR signature" }, *this);
          return;
        }

        // initialize FAT16 or FAT32 filesystem
        init(mbr);

        // determine which FAT version is initialized
        switch (this->fat_type) {
        case FAT::T_FAT12:
          INFO("FAT", "Initializing FAT12 filesystem");
          break;
        case FAT::T_FAT16:
          INFO("FAT", "Initializing FAT16 filesystem");
          break;
        case FAT::T_FAT32:
          INFO("FAT", "Initializing FAT32 filesystem");
          break;
        }
        INFO2("[ofs=%u  size=%u (%u bytes)]\n",
              this->lba_base, this->lba_size, this->lba_size * 512);

        // on_init callback
        on_init(no_error, *this);
      })
    );
  }
Beispiel #3
0
  Dirent FAT::stat(Path path, const Dirent* const start) const
  {
    if (UNLIKELY(path.empty())) {
      return Dirent(this, Enttype::DIR, "/", 0);
    }

    FS_PRINT("stat_sync: %s\n", path.back().c_str());
    // extract file we are looking for
    const std::string filename = path.back();
    path.pop_back();

    // result directory entries are put into @dirents
    dirvector dirents;

    auto err = traverse(path, dirents, start);
    if (UNLIKELY(err))
      return Dirent(this, INVALID_ENTITY); // for now

    // find the matching filename in directory
    for (auto& e : dirents)
    if (UNLIKELY(e.name() == filename)) {
      // return this directory entry
      return e;
    }
    // entry not found
    return Dirent(this, INVALID_ENTITY);
  }
Beispiel #4
0
static void
fs_print(struct sbuf *sb, struct flowtable_stats *fs)
{

	FS_PRINT(sb, collisions);
	FS_PRINT(sb, allocated);
	FS_PRINT(sb, misses);
	FS_PRINT(sb, max_depth);
	FS_PRINT(sb, free_checks);
	FS_PRINT(sb, frees);
	FS_PRINT(sb, hits);
	FS_PRINT(sb, lookups);
}
Beispiel #5
0
  void FAT::int_ls(
     uint32_t   sector,
     Dirvec_ptr dirents,
     on_internal_ls_func callback) const
  {
    // list contents of meme sector by sector
    typedef delegate<void(uint32_t)> next_func_t;

    auto next = std::make_shared<next_func_t> ();
    auto weak_next = std::weak_ptr<next_func_t>(next);
    *next = next_func_t::make_packed(
    [this, callback, dirents, weak_next] (uint32_t sector)
    {
      FS_PRINT("int_ls: sec=%u\n", sector);
      auto next = weak_next.lock();
      device.read(
        sector,
        hw::Block_device::on_read_func::make_packed(
        [this, sector, callback, dirents, next] (buffer_t data)
        {
          if (data == nullptr) {
            // could not read sector
            callback({ error_t::E_IO, "Unable to read directory" }, dirents);
            return;
          }

          // parse entries in sector
          bool done = int_dirent(sector, data->data(), *dirents);
          if (done)
            // execute callback
            callback(no_error, dirents);
          else
            // go to next sector
            (*next)(sector+1);

        })
      ); // read root dir
    });

    // start reading sectors asynchronously
    (*next)(sector);
  }
Beispiel #6
0
  void FAT::cstat(const std::string& strpath, on_stat_func func)
  {
    // cache lookup
    auto it = stat_cache.find(strpath);
    if (it != stat_cache.end()) {
      FS_PRINT("used cached stat for %s\n", strpath.c_str());
      func(no_error, it->second);
      return;
    }

    File_system::stat(
      strpath,
      fs::on_stat_func::make_packed(
      [this, strpath, func] (error_t error, const Dirent& ent)
      {
        stat_cache.emplace(strpath, ent);
        func(error, ent);
      })
    );
  }
Beispiel #7
0
  void FAT::stat(Path_ptr path, on_stat_func func, const Dirent* const start) const
  {
    // manual lookup
    if (UNLIKELY(path->empty())) {
      // Note: could use ATTR_VOLUME_ID in FAT
      func(no_error, Dirent(this, DIR, "/", 0));
      return;
    }

    FS_PRINT("stat: %s\n", path->back().c_str());
    // extract file we are looking for
    std::string filename = path->back();
    path->pop_back();

    traverse(
      path,
      cluster_func::make_packed(
      [this, filename, func] (error_t error, Dirvec_ptr dirents)
      {
        if (UNLIKELY(error)) {
          // no path, no file!
          func(error, Dirent(this, INVALID_ENTITY, filename));
          return;
        }

        // find the matching filename in directory
        for (auto& e : *dirents) {
          if (UNLIKELY(e.name() == filename)) {
            // return this dir entry
            func(no_error, e);
            return;
          }
        }

        // not found
        func({ error_t::E_NOENT, filename }, Dirent(this, INVALID_ENTITY, filename));
      }),
      start
    );
  }
Beispiel #8
0
  void FAT::traverse(std::shared_ptr<Path> path, cluster_func callback, const Dirent* const start) const
  {
    // parse this path into a stack of memes
    typedef delegate<void(uint32_t)> next_func_t;

    // asynch stack traversal
    auto next = std::make_shared<next_func_t> ();
    auto weak_next = std::weak_ptr<next_func_t>(next);
    *next = next_func_t::make_packed(
    [this, path, weak_next, callback] (uint32_t cluster)
    {
      if (path->empty()) {
        // attempt to read directory
        uint32_t S = this->cl_to_sector(cluster);

        // result allocated on heap
        auto dirents = std::make_shared<std::vector<Dirent>> ();

        int_ls(S, dirents,
        on_internal_ls_func::make_packed(
          [callback] (error_t error, Dirvec_ptr ents)
          { callback(error, ents);}
        ));

        return;
      }

      // retrieve next name
      std::string name = path->front();
      path->pop_front();

      uint32_t S = this->cl_to_sector(cluster);
      FS_PRINT("Current target: %s on cluster %u (sector %u)\n", name.c_str(), cluster, S);

      // result allocated on heap
      auto dirents = std::make_shared<std::vector<Dirent>> ();

      auto next = weak_next.lock();
      // list directory contents
      int_ls(
        S,
        dirents,
        on_internal_ls_func::make_packed(
        [name, dirents, next, callback] (error_t err, Dirvec_ptr ents)
        {
          if (UNLIKELY(err))
          {
            FS_PRINT("Could not find: %s\n", name.c_str());
            callback(err, dirents);
            return;
          }

          // look for name in directory
          for (auto& e : *ents)
          {
            if (UNLIKELY(e.name() == name))
            {
              // go to this directory, unless its the last name
              FS_PRINT("Found match for %s", name.c_str());
              // enter the matching directory
              FS_PRINT("\t\t cluster: %lu\n", e.block());
              // only follow directories
              if (e.type() == DIR)
                (*next)(e.block());
              else
                callback({ error_t::E_NOTDIR, e.name() }, dirents);
              return;
            }
          } // for (ents)

          FS_PRINT("NO MATCH for %s\n", name.c_str());
          callback({ error_t::E_NOENT, name }, dirents);
        })
      );

    });
    // start by reading provided dirent or root
    (*next)(start ? start->block() : 0);
  }
Beispiel #9
0
  void FAT::init(const void* base_sector) {

    // assume its the master boot record for now
    auto* mbr = (MBR::mbr*) base_sector;

    MBR::BPB* bpb = mbr->bpb();
    this->sector_size = bpb->bytes_per_sector;

    if (UNLIKELY(this->sector_size < 512)) {
      fprintf(stderr,
          "Invalid sector size (%u) for FAT32 partition\n", sector_size);
      fprintf(stderr,
          "Are you initializing the correct partition?\n");
      panic("FAT32: Invalid sector size");
    }

    // Let's begin our incantation
    // To drive out the demons of old DOS we have to read some PBP values
    FS_PRINT("Bytes per sector: \t%u\n", bpb->bytes_per_sector);
    FS_PRINT("Sectors per cluster: \t%u\n", bpb->sectors_per_cluster);
    FS_PRINT("Reserved sectors: \t%u\n", bpb->reserved_sectors);
    FS_PRINT("Number of FATs: \t%u\n", bpb->fa_tables);

    FS_PRINT("Small sectors (FAT16): \t%u\n", bpb->small_sectors);

    FS_PRINT("Sectors per FAT: \t%u\n", bpb->sectors_per_fat);
    FS_PRINT("Sectors per Track: \t%u\n", bpb->sectors_per_track);
    FS_PRINT("Number of Heads: \t%u\n", bpb->num_heads);
    FS_PRINT("Hidden sectors: \t%u\n", bpb->hidden_sectors);
    FS_PRINT("Large sectors: \t%u\n", bpb->large_sectors);
    FS_PRINT("Disk number: \t0x%x\n", bpb->disk_number);
    FS_PRINT("Signature: \t0x%x\n", bpb->signature);

    FS_PRINT("System ID: \t%.8s\n", bpb->system_id);

    // sector count
    if (bpb->small_sectors)
      this->sectors  = bpb->small_sectors;
    else
      this->sectors  = bpb->large_sectors;

    // sectors per FAT (not sure about the rule here)
    this->sectors_per_fat = bpb->sectors_per_fat;
    if (this->sectors_per_fat == 0)
      this->sectors_per_fat = *(uint32_t*) &mbr->boot[25];

    // root dir sectors from root entries
    this->root_dir_sectors = ((bpb->root_entries * 32) + (sector_size - 1)) / sector_size;

    // calculate index of first data sector
    this->data_index = bpb->reserved_sectors + (bpb->fa_tables * this->sectors_per_fat) + this->root_dir_sectors;
    FS_PRINT("First data sector: %u\n", this->data_index);

    // number of reserved sectors is needed constantly
    this->reserved = bpb->reserved_sectors;
    FS_PRINT("Reserved sectors: %u\n", this->reserved);

    // number of sectors per cluster is important for calculating entry offsets
    this->sectors_per_cluster = bpb->sectors_per_cluster;
    FS_PRINT("Sectors per cluster: %u\n", this->sectors_per_cluster);

    // calculate number of data sectors
    this->data_sectors = this->sectors - this->data_index;
    FS_PRINT("Data sectors: %u\n", this->data_sectors);

    // calculate total cluster count
    this->clusters = this->data_sectors / this->sectors_per_cluster;
    FS_PRINT("Total clusters: %u\n", this->clusters);

    // now that we're here, we can determine the actual FAT type
    // using the official method:
    if (this->clusters < 4085) {
      this->fat_type = FAT::T_FAT12;
      this->root_cluster = 2;
      FS_PRINT("The image is type FAT12, with %u clusters\n", this->clusters);
    }
    else if (this->clusters < 65525) {
      this->fat_type = FAT::T_FAT16;
      this->root_cluster = 2;
      FS_PRINT("The image is type FAT16, with %u clusters\n", this->clusters);
    }
    else {
      this->fat_type = FAT::T_FAT32;
      this->root_cluster = *(uint32_t*) &mbr->boot[33];
      this->root_cluster = 2;
      FS_PRINT("The image is type FAT32, with %u clusters\n", this->clusters);
      FS_PRINT("Root dir entries: %u clusters\n", bpb->root_entries);
      //assert(bpb->root_entries == 0);
      //this->root_dir_sectors = 0;
      //this->data_index = bpb->reserved_sectors + bpb->fa_tables * this->sectors_per_fat;
    }
    FS_PRINT("Root cluster index: %u (sector %u)\n", this->root_cluster, cl_to_sector(root_cluster));
    FS_PRINT("System ID: %.8s\n", bpb->system_id);
  }
Beispiel #10
0
  bool FAT::int_dirent(uint32_t sector, const void* data, dirvector& dirents) const
  {
    auto* root = (cl_dir*) data;
    bool  found_last = false;

    for (int i = 0; i < 16; i++) {

      if (UNLIKELY(root[i].shortname[0] == 0x0)) {
        found_last = true;
        // end of directory
        break;
      }
      else if (UNLIKELY(root[i].shortname[0] == 0xE5)) {
        // unused index
      }
      else {
        // traverse long names, then final cluster
        // to read all the relevant info

        if (LIKELY(root[i].is_longname())) {
          auto* L = (cl_long*) &root[i];
          // the last long index is part of a chain of entries
          if (L->is_last()) {
            // buffer for long filename
            char final_name[256];
            int  final_count = 0;

            int  total = L->long_index();
            // ignore names we can't complete inside of one sector
            if (i + total >= 16) return false;

            // go to the last entry and work backwards
            i += total-1;
            L += total-1;

            for (int idx = total; idx > 0; idx--) {
              uint16_t longname[13];
              memcpy(longname+ 0, L->first, 10);
              memcpy(longname+ 5, L->second, 12);
              memcpy(longname+11, L->third, 4);

              for (int j = 0; j < 13; j++) {
                // 0xFFFF indicates end of name
                if (UNLIKELY(longname[j] == 0xFFFF)) break;
                // sometimes, invalid stuff are snuck into filenames
                if (UNLIKELY(longname[j] == 0x0)) break;

                final_name[final_count] = longname[j] & 0xFF;
                final_count++;
              }
              L--;

              if (UNLIKELY(final_count > 240)) {
                FS_PRINT("Suspicious long name length, breaking...\n");
                break;
              }
            }

            final_name[final_count] = 0;
            FS_PRINT("Long name: %s\n", final_name);

            i++; // skip over the long version
            // to the short version for the stats and cluster
            auto* D = &root[i];
            std::string dirname(final_name, final_count);

            dirents.emplace_back(
                this,
                D->type(),
                std::move(dirname),
                D->dir_cluster(root_cluster),
                sector, // parent block
                D->size(),
                D->attrib,
                D->get_modified());
          }
        }
        else {
          auto* D = &root[i];
          FS_PRINT("Short name: %.11s\n", D->shortname);

          std::string dirname((char*) D->shortname, 11);
          dirname = trim_right_copy(dirname);

          dirents.emplace_back(
              this,
              D->type(),
              std::move(dirname),
              D->dir_cluster(root_cluster),
              sector, // parent block
              D->size(),
              D->attrib,
              D->get_modified());
        }
      } // entry is long name

    } // directory list
    return found_last;
  }