blob: eb7d6c522684249da4306db7ddf29962542c08a9 [file] [log] [blame]
// Copyright 2016 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef ARC_OBB_MOUNTER_VOLUME_H_
#define ARC_OBB_MOUNTER_VOLUME_H_
#include <linux/msdos_fs.h>
#include <base/callback_forward.h>
#include <base/files/file.h>
#include <base/macros.h>
#include <base/strings/string_piece.h>
#include <base/time/time.h>
namespace fat {
const int64_t kInvalidValue = -1;
enum class FatType {
FAT_12,
FAT_16,
FAT_32,
};
// Volume is a class to access a FAT volume.
//
// Structure of a FAT volume:
// [ Boot sector + Reserved sectors ]
// [ File allocation tables (FATs) ]
// [ Root directory (FAT12/16 only, FAT32 root dir is in the data region) ]
// [ Data region ]
class Volume {
public:
// Time in FAT's format.
struct Time {
uint16_t time = 0;
uint16_t date = 0;
// Converts the values to base::Time.
base::Time ToBaseTime() const;
};
// Metadata of a file or a directory stored under a directory.
struct DirectoryEntry {
bool is_directory = false;
int64_t file_size = 0;
int64_t start_cluster = 0; // The first cluster of the contents.
Time last_modification;
};
using ReadDirectoryCallback = base::Callback<bool(
const base::StringPiece16& name, const DirectoryEntry& entry)>;
// Object to read the contents of a file.
class FileReader {
public:
FileReader(Volume* volume, int64_t start_cluster, int64_t file_size);
~FileReader();
// Reads the given number of bytes from the given offset and returns the
// number of bytes read, or -1 on error.
int64_t Read(char* buf, int64_t size, int64_t offset);
private:
// Updates current_offset_ and current_cluster_ with the given offset value.
bool Seek(int64_t offset);
Volume* volume_;
const int64_t start_cluster_; // Start cluster of the file being read.
const int64_t file_size_; // Size of the file being read.
int64_t current_offset_; // Current offset within the file being read.
int64_t current_cluster_; // Current cluster in the image file.
DISALLOW_COPY_AND_ASSIGN(FileReader);
};
Volume();
~Volume();
// Reads the boot sector from the image and initializes member variables.
bool Initialize(base::File image_file);
// Returns the sector where the root directory starts.
int64_t root_dir_start_sector() const { return root_dir_start_sector_; }
// Returns the given cluster's first sector.
int64_t GetClusterStartSector(int64_t cluster) const {
if (cluster < FAT_START_ENT)
return kInvalidValue;
return data_start_sector_ +
(cluster - FAT_START_ENT) * sectors_per_cluster_;
}
// Reads the directory from the given sector and calls the callback with each
// file/directory found under it. When the callback returns false, returns
// true immediately without processing the remaining entries.
bool ReadDirectory(int64_t start_sector,
const ReadDirectoryCallback& callback);
private:
// Returns the position of the give sector in the image file.
int64_t GetSectorPosition(int64_t sector) const {
return sector * bytes_per_sector_;
}
// Returns the cluster to which the given sector belongs.
int64_t GetCluster(int64_t sector) const {
if (sector < data_start_sector_) {
return kInvalidValue;
}
return (sector - data_start_sector_) / sectors_per_cluster_ + FAT_START_ENT;
}
// Returns the next sector to read after the given sector. If there is an
// error, or reached EOF, returns kInvalidValue.
int64_t GetNextSector(int64_t sector);
base::File image_file_;
int bytes_per_sector_ = 0; // Size of a sector. Usually this is 512.
int sectors_per_cluster_ = 0; // Size of a cluster.
// The sector from which the FAT (file allocation table) starts.
int64_t fat_start_sector_ = 0;
// The sector from which the root dir starts.
int64_t root_dir_start_sector_ = 0;
// The sector from which the data region starts.
int64_t data_start_sector_ = 0;
FatType fat_type_ = FatType::FAT_12; // The type of this FAT volume.
DISALLOW_COPY_AND_ASSIGN(Volume);
};
} // namespace fat
#endif // ARC_OBB_MOUNTER_VOLUME_H_