Roberto Chavez Jr

Software Engineer

Resume


File System Inode Structure

Prompt

Maintain a tree structure with a simple hierarchy, maintained by a map of functions. Header files: Include only C++11 header files and facilities where feasible, and use namespace std. Include cheader files only when C++-style files are unavailable. Include header.h files from C only when an appropriate cheader file is unavailable. Use the script cpplint.py.perl (a wrapper for cpplint.py) to check style.

Main Setup

The file system header file will contain a list of classes defining and manipulating an inode.
// $Id: file_sys.h,v 1.5 2016-04-07 13:36:11-07 - - $
#ifndef __INODE_H__
#define __INODE_H__

#include <map>
#include <memory>
#include <vector>
#include <iostream>
#include <exception>
using namespace std;

#include "util.h"

// inode_t -
//    An inode is either a directory or a plain file.

enum file_type{
  PLAIN_TYPE, 
  DIRECTORY_TYPE
};

class inode;
class base_file;
class plain_file;
class directory;

using inode_ptr = shared_ptr<inode>;
using base_file_ptr = shared_ptr<base_file>;
using plain_file_ptr = shared_ptr<plain_file>;
using directory_ptr = shared_ptr<directory>;

ostream& operator<< (ostream&, file_type);
</code></pre>
        </div>
        <div class="col">
          <div class="lead">
            An inode can either be a plain file or a directory, so we distinguish via <code>enum file_type</code>:
          </div>
          <pre><code class="language-cpp">enum file_type{
  PLAIN_TYPE, 
  DIRECTORY_TYPE
};
Checking type:
 if (nameOfInode::file_type == PLAIN_TYPE) {
  // plain file
} else {
  // directory
}
Use shared pointers for polymorphic ownership:
using inode_ptr = shared_ptr<inode>;
using base_file_ptr = shared_ptr<base_file>;
using plain_file_ptr = shared_ptr<plain_file>;
using directory_ptr = shared_ptr<directory>;`}
In the inode class, a private member contents of type base_file_ptr allows retrieving resources from plain_file and directory children without copying whole objects.

Inode State

A small convenience class to maintain the simulated process state: root (/), current directory (.), and the prompt.
            
                class inode_state {
                    friend class inode;
                    friend ostream&amp; operator&lt;&lt; (ostream&amp; out, const inode_state&);
                    private:
                    string prompt_ {"==&gt;$ "};
                    inode_ptr cwd {nullptr};
                    inode_ptr root {nullptr};
                    public:
                    inode_state();
                    inode_state(const inode_state&) = delete;
                    inode_state&amp; operator=(const inode_state&) = delete;

                    const string prompt();
                    void cat(const wordvec&amp; words);
                    void cd(const wordvec&amp; words);
                    void echo(const wordvec&amp; words);
                    void ls(const wordvec&amp; words);
                    void lsr(const wordvec&amp; words);
                    void lsr_pathname(const wordvec&amp; words);
                    void make(const wordvec&amp; words);
                    void mkdir(const wordvec&amp; words);
                    void prompt(const wordvec&amp; words);
                    void pwd(const wordvec&amp; words);
                    void pwd(const wordvec&amp; words, const inode_ptr pwdLocation);
                    void rm(const wordvec&amp; words);
                    void rmr(const wordvec&amp; words);
                    bool does_dir_file_exist(const wordvec&amp; path, const inode_ptr potentialFile);
                    string pwd_str(const wordvec&amp; words, const inode_ptr pwdLocation);
                    inode_ptr naviPath(const wordvec&amp; words, int path_index);
                }
            
        
Instantiate inode_state in the command loop to track root, cwd, and prompt. The navigation helper naviPath returns an inode_ptr for a user-supplied pathname or nullptr if not found.

Inode

inode tracks an inode number, name, type, and its contents (polymorphic base).
class inode {
  friend class inode_state;
private:
  static int next_inode_nr;
  string name;
  int inode_nr;
  file_type type;
  base_file_ptr contents;
public:
  inode (file_type type);
  size_t size() const;
  int get_inode_nr() const;
  void set_name(const string&amp; newName);
  string get_name() const;
  file_type get_type() const;
  base_file_ptr get_contents() const;
};
The key is contents, a base_file_ptr that can point to a plain_file or directory.

Base File

Abstract base from which plain files and directories derive.
class file_error: public runtime_error {
public:
  explicit file_error (const string&amp; what);
};

class base_file {
protected:
  base_file() = default;
public:
  virtual ~base_file() = default;
  base_file (const base_file&amp;) = delete;
  base_file&amp; operator= (const base_file&amp;) = delete;

  virtual size_t size() const = 0;
  void mkfile (const string&amp; filename);

  friend plain_file_ptr plain_file_ptr_of (base_file_ptr);
  friend directory_ptr  directory_ptr_of  (base_file_ptr);
};
Use dynamic_pointer_cast to obtain concrete pointers:
auto pf  = dynamic_pointer_cast&lt;plain_file&gt;(ptr);
auto dir = dynamic_pointer_cast&lt;directory&gt;(ptr);
Once cast, call the subclass methods as needed.

Plain File

A plain file stores a vector of words.
class plain_file: public base_file {
private:
  wordvec data;
public:
  size_t size() const override;
  const wordvec&amp; readfile() const;
  void writefile (const wordvec&amp; newdata);
  void remove (const string&amp; filename);
  void mkfile (const string&amp; filename);
};
When the inode’s type is PLAIN_TYPE, cast contents to plain_file and call writefile with the parsed words.

Directory

A directory maps names to child inodes.
class directory: public base_file {
private:
  // Must be ordered so printing is lexicographic
  map&lt;string, inode_ptr&gt; dirents;
public:
  size_t size() const override;
  const wordvec&amp; readfile() const;
  void iterate_ls();
  vector&lt;inode_ptr&gt; subDirectory();
  void mkdir (const string&amp; dirname);
  void new_directory(inode_ptr root);
  void remove (const string&amp; filename);
  void set_parent_child(inode_ptr parent, inode_ptr child);
  inode_ptr lookup (const string&amp; lookup);
  inode_ptr mkfile (const string&amp; filename);
  inode_ptr get_child(const string&amp; filename);
};
dirents holds ".", "..", and children. Helpers like mkdir, lookup, and get_child encapsulate updates and queries on this map.