Ejemplo n.º 1
0
int fs_mkdir(FileSystem *fs, const char *d) {
    int p = 0;
    Inode *inode = NULL;
    Folder *fd = NULL;
    char ppath[4096] = "";
    char cname[4096] = "";
    Folder *pfd = NULL;
    int parent_page_num = 0;
    
    p = freelist_allocate(fs->freelist);
    if (p <= 1) return ERROR;
    inode = inode_new(p);
    if (!inode) return ERROR;
    inode->type = INODE_FOLDER;
    inode->filesize = 0;
    inode->lastmod = time(NULL);
    inode->firstpage = 0;
    fs_save_inode(fs, inode);
    inode_free(&inode);
    
    fs_split_path(d, ppath, cname);
#ifdef DEBUG
    fprintf(stderr, "fs_mkdir, d=`%s`, ppath=`%s`, cname=`%s`\n", d, ppath, cname);
#endif
    
    pfd = folder_open(fs, folder_lookup(fs, fs->cur, ppath));
    parent_page_num = AS_FILE(pfd)->inode->page_num;
    folder_add_child(pfd, cname, p);
    folder_close(&pfd);
    
    fd = folder_open(fs, fs_load_inode(fs, p));
    fs_split_path(d, ppath, cname);
    folder_add_child(fd, "", ROOT_PAGE_NUM());
    folder_add_child(fd, ".", p);
    folder_add_child(fd, "..", parent_page_num);
    folder_close(&fd);
    return OK;
}
Ejemplo n.º 2
0
int fs_create(FileSystem *fs, const char *f) {
    int p = 0;
    Inode *inode = NULL;
    char ppath[4096] = "";
    char cname[4096] = "";
    Folder *pfd = NULL;
    
    p = freelist_allocate(fs->freelist);
    if (p <= 1) return ERROR;
    inode = inode_new(p);
    if (!inode) return ERROR;
    inode->type = INODE_FILE;
    inode->filesize = 0;
    inode->firstpage = 0;
    fs_save_inode(fs, inode);
    inode_free(&inode);
    
    fs_split_path(f, ppath, cname);
    pfd = folder_open(fs, folder_lookup(fs, fs->cur, ppath));
    folder_add_child(pfd, cname, p);
    folder_close(&pfd);
    return OK;
}
Ejemplo n.º 3
0
/**
 * Process a null-terminated path, closing any directories and building the
 * nodes as needed, and opening the new directories to support the current path.
 *
 * Once the proper set of folders are open, create a node and write it into
 * the folder.
 */
static process_path_result_t process_path(
    from_flat_state_t *state,
    const char *path, size_t max_len) {
  size_t path_scan_index;
  size_t current_path_start;
  size_t open_folder_index;

  // match as many path components as we can
  for (path_scan_index = 0,
       current_path_start = 0,
       open_folder_index = 0;
       path[path_scan_index] != 0;
       path_scan_index++) {
    if (path_scan_index == max_len) {
      return COMPOUND_LITERAL(process_path_result_t) {
          PROCESS_PATH_CORRUPT, NULL, 0};
    }

    // check for a path separator.
    if (path[path_scan_index] != '/') {
      continue;
    }
    size_t path_len =
        path_scan_index + 1 /* to include the / */ - current_path_start;

    bool open_new_folder = true;

    // check if the *next* open folder is valid, and if it matches the path
    // component we just found.
    if (open_folder_index + 1 < state->open_folder_count) {
      if (folder_name_compare(
          &path[current_path_start],
          path_len,
          &state->folders[open_folder_index + 1]) == 0) {
        // we found the folder we needed, so we can just reuse it.
        open_new_folder = false;
        open_folder_index++;
      } else {
        close_folder_result_t close_folder_result =
            close_folder(state, open_folder_index + 1);
        if (close_folder_result.code == CLOSE_FOLDER_OOM) {
          return COMPOUND_LITERAL(process_path_result_t) {PROCESS_PATH_OOM, NULL, 0};
        }
      }
    }

    if (open_new_folder == true) {
      // if we're opening a new folder, that means there should be no child
      // folders open.
      assert(state->open_folder_count == open_folder_index + 1);
      open_folder_index++;
      state->open_folder_count++;
      open_folder_t *folder = &state->folders[open_folder_index];

      assert(folder->in_use == false);
      assert(folder->closed_children == folder->closed_children_prealloc);
      assert(folder->closed_children_count == 0);

      // link the name in.  remember, we don't own the memory!!
      folder->in_use = true;
      folder->subfolder_name = &path[current_path_start];
      folder->subfolder_name_sz = path_len;
    }

    // path starts after the /
    current_path_start = path_scan_index + 1;
  }

  // close path components that are not matched, building their nodes.
  if (open_folder_index + 1 < state->open_folder_count) {
    close_folder_result_t close_folder_result =
        close_folder(state, open_folder_index + 1);
    if (close_folder_result.code == CLOSE_FOLDER_OOM) {
      return COMPOUND_LITERAL(process_path_result_t) {PROCESS_PATH_OOM, NULL, 0};
    }
  }

  // build a node for the remaining path (which should just be the
  // filename).  add it to the currently open folder.
  arena_alloc_node_result_t arena_alloc_node_result =
      arena_alloc_node(
          state->tree,
          &path[current_path_start],
          path_scan_index - current_path_start,
          0);

  if (arena_alloc_node_result.code == ARENA_ALLOC_OOM) {
    return COMPOUND_LITERAL(process_path_result_t) {PROCESS_PATH_OOM, NULL, 0};
  }

  arena_alloc_node_result.node->type = TYPE_LEAF;

  // jam the new node into the currently open folder.
  open_folder_t *folder = &state->folders[open_folder_index];
  folder_add_child(state, folder, arena_alloc_node_result.node);

  return COMPOUND_LITERAL(process_path_result_t) {
      PROCESS_PATH_OK, arena_alloc_node_result.node, path_scan_index + 1};
}
Ejemplo n.º 4
0
/**
 * Close the folder at index `folder_index`.  This may require closing nested
 * folders.  If folder_index is > 0, then add the closed folder to its parent.
 * If the folder_index is 0, it is responsibility of the caller to attach the
 * returned node to the shadow root.
 */
static close_folder_result_t close_folder(
    from_flat_state_t *state,
    size_t folder_index) {
  open_folder_t *folder = &state->folders[folder_index];
  assert(folder->in_use == true);

  if (folder_index < MAX_FOLDER_DEPTH - 1) {
    // maybe a nested folder needs to be closed?
    if (state->folders[folder_index + 1].in_use) {
      // yup, it needs to be closed.
      close_folder_result_t close_folder_result =
          close_folder(state, folder_index + 1);

      if (close_folder_result.code != CLOSE_FOLDER_OK) {
        return COMPOUND_LITERAL(close_folder_result_t) {
            close_folder_result.code, NULL};
      }
    }
  }

  // allocate a node and set it up.
  arena_alloc_node_result_t arena_alloc_node_result =
      arena_alloc_node(
          state->tree,
          folder->subfolder_name,
          folder->subfolder_name_sz,
          folder->closed_children_count);

  if (arena_alloc_node_result.code == ARENA_ALLOC_OOM) {
    return COMPOUND_LITERAL(close_folder_result_t) {
        CLOSE_FOLDER_OOM, NULL};
  }
  node_t *node = arena_alloc_node_result.node;
  node->type = TYPE_IMPLICIT;
  // we must initialize flags to a known value, even if it's not used
  // because it participates in checksum calculation.
  node->flags = 0;
  if (!VERIFY_CHILD_NUM(folder->closed_children_count)) {
    abort();
  }
  // this is a huge abstraction violation, but it allows us to use
  // `set_child_by_index`, which is significantly more efficient.
  node->num_children = (child_num_t) folder->closed_children_count;

  // node is set up.  now add all the children!
  intptr_t arena_start = (intptr_t) state->tree->arena;
  for (size_t ix = 0; ix < folder->closed_children_count; ix++) {
    ptrdiff_t child_offset = (intptr_t) folder->closed_children[ix];
    intptr_t address = arena_start + child_offset;

    set_child_by_index(node, ix, (node_t *) address);
  }

  init_open_folder(folder);             // zap the folder so it can be reused.
  state->open_folder_count--;

  // attach to parent folder if it's not the root folder.
  assert(folder_index == state->open_folder_count);
  if (folder_index > 0) {
    open_folder_t *parent_folder = &state->folders[folder_index - 1];
    if (folder_add_child(state, parent_folder, node) == false) {
      return COMPOUND_LITERAL(close_folder_result_t) {
          CLOSE_FOLDER_OOM, NULL};
    }
  }

  return COMPOUND_LITERAL(close_folder_result_t) {
      CLOSE_FOLDER_OK, node};
}