MFS File System Functions: Write, Inode Retrieval, and Directory Operations

MFS File System Functions

mfs_write Function

Function Signature: int mfs_write(int fd, void *buf, size_t count)

This function writes data to a file within the MFS file system. It takes a file descriptor fd, a buffer buf containing the data to write, and the number of bytes count to write.

Functionality:

  • Checks if the file descriptor is valid.
  • Verifies if the file is opened.
  • Adjusts the write count if it exceeds the file’s remaining capacity.
  • Calculates the starting position and block number for writing.
  • Iterates through the data, writing to blocks.
  • Handles partial block writes by reading, modifying, and writing back.
  • Updates the file position and size if necessary.

int mfs_write(int fd, void *buf, size_t count) {
  int start, not_done, num_block;
  char block[fs->sb.block_size];
  char *next;

  if (fd < 0 || fd >= row_num) return -1;
  if (fs->file[fd].num == -1) {
    printf("Trying to write unopened fd \n");
    return -1;
  }
  if (count > fs->file[fd].ino.e.size * fs->sb.block_size - fs->file[fd].pos)
    count = fs->file[fd].ino.e.size * fs->sb.block_size - fs->file[fd].pos;

  start = fs->file[fd].pos % fs->sb.block_size;
  num_block = (fs->file[fd].pos / fs->sb.block_size) + fs->file[fd].ino.e.start;
  not_done = count;
  next = buf;

  while (not_done) {
    int len;
    if (not_done > fs->sb.block_size - start)
      len = fs->sb.block_size - start;
    else
      len = not_done;

    if (len != fs->sb.block_size) {
      data_read(fs, block, num_block);
      memcpy(block + start, next, len);
      data_write(fs, block, num_block);
    } else {
      data_write(fs, next, num_block);
    }
    num_block++;
    not_done -= len;
    next += len;
    start = 0;
  }
  fs->file[fd].pos += count;
  if (fs->file[fd].pos > fs->file[fd].ino.size) {
    fs->file[fd].ino.size = fs->file[fd].pos;
    inode_write(fs, &fs->file[fd].ino, fs->file[fd].num);
  }
  return count;
}

get_inodo_previo Function

Function Signature: static int get_inodo_previo(struct file_system *fs, const char *path)

This function retrieves the inode of the parent directory given a full path.

Functionality:

  • Parses the path to extract directory names.
  • Iterates through the path components to find the parent inode.
  • Handles cases where the path does not exist.

static int get_inodo_previo(struct file_system *fs, const char *path) {
  int i = 0, j = 0, inode = -1, inodo_anterior = -1, con_dir = -1;
  int path_len = strlen(path);
  char *rest = malloc(sizeof(char) * path_len);
  char *name = malloc(sizeof(char) * path_len);
  disk_inode struct ino;

  while (path[i] != '\0' && path[i] != '/') {
    name[i] = path[i];
    i++;
    if (path[i] == '/') con_dir = 0;
    name[i] = '\0';
  }
  i++;
  while (i < strlen(path)) {
    rest[j] = path[i];
    i++;
    j++;
    rest[j] = '\0';
    if (path[i] == '\0') break;
  }
  inode = namei(fs, &(fs->root), name);
  if (con_dir == -1) return 0;
  inodo_anterior = inode;
  if (inode == -1) return -1;
  else
    while (inode != -1) {
      i = 0, j = 0;
      con_dir = -1;
      inode_read(fs, &ino, inode);
      while (rest[i] != '\0' && rest[i] != '/') {
        name[i] = rest[i];
        i++;
        if (rest[i] == '/') con_dir = 0;
        name[i] = '\0';
      }
      i++;
      while (i < strlen(rest)) {
        rest[j] = rest[i];
        i++;
        j++;
        if (rest[i] == '\0') break;
      }
      rest[j] = '\0';
      inodo_anterior = inode;
      inode = namei(fs, &ino, name);
      if (con_dir == 0) continue;
      else
        return inodo_anterior;
    }
  return inode;
}

get_inodo Function

Function Signature: static int get_inodo(struct file_system *fs, const char *path)

This function retrieves the inode of a file or directory given its full path.

Functionality:

  • Parses the path to extract directory and file names.
  • Iterates through the path components to find the target inode.
  • Handles special cases like “..” for parent directory traversal.

static int get_inodo(struct file_system *fs, const char *path) {
  int i = 0, j = 0, s = 0, inode = -1, inodo_anterior = -1, con_dir = -1;
  int path_len = strlen(path);
  char *rest = malloc(sizeof(char) * path_len);
  char *name = malloc(sizeof(char) * path_len);
  char *dir_anterior = malloc(sizeof(char) * path_len);
  disk_inode struct ino;

  while (path[i] != '\0' && path[i] != '/') {
    name[i] = path[i];
    i++;
    if (path[i] == '/') con_dir = 0;
    name[i] = '\0';
  }
  i++;
  while (i < strlen(path)) {
    rest[j] = path[i];
    i++;
    j++;
    rest[j] = '\0';
    if (path[i] == '\0') break;
  }
  if (strcmp(name, "..") == 0) return 0;
  inode = namei(fs, &(fs->root), name);
  if (con_dir == -1) return inode;
  inodo_anterior = inode;
  if (inode == -1) return -1;
  else
    while (inode != -1) {
      i = 0, j = 0;
      con_dir = -1;
      inode_read(fs, &ino, inode);
      while (rest[i] != '\0' && rest[i] != '/') {
        name[i] = rest[i];
        i++;
        if (rest[i] == '/') con_dir = 0;
        name[i] = '\0';
      }
      i++;
      while (i < strlen(rest)) {
        rest[j] = rest[i];
        i++;
        j++;
        if (rest[i] == '\0') break;
      }
      rest[j] = '\0';
      inodo_anterior = inode;
      inode = namei(fs, &ino, name);
      if (name[0] == '.' && name[1] == '.') {
        for (s = 0; s < strlen(path); s++) {
          if ((path[s] == '/') && (path[s + 1] == '.') && (path[s + 2] == '.'))
            return get_inodo_previo(fs, dir_anterior);
          dir_anterior[s] = path[s];
        }
      }
      if (name[0] == '.' && name[1] == '\0') return inodo_anterior;
      if (con_dir == 0) continue;
      else
        return inode;
    }
  return inode;
}

is_dir Function

Function Signature: static int is_dir(struct file_system *fs, struct disk_inode *d, const char *directory)

This function checks if a given name is a directory within the current inode’s directory entries.

Functionality:

  • Reads the directory entries from the inode.
  • Compares the given name with the directory entries.
  • Returns 1 if the name is a directory, 0 otherwise.

static int is_dir(struct file_system *fs, struct disk_inode *d, const char *directory) {
  char block[fs->sb.block_size];
  struct entry *dir = (struct entry *)block;
  int r = 0, i, j;

  if (directory[0] == '.' && directory[1] == '\0') return 1;
  for (i = 0; i < d->e.size; i++) {
    data_read(fs, block, d->e.start + i);
    for (j = 0; j < fs->sb.block_size / sizeof(struct entry); j++) {
      if (dir[j].inode != -1 &&
          strncmp(directory, dir[j].name, ENTRY_SIZE) == 0) {
        if (dir[j].is_dir == 0) r = 1;
      }
    }
  }
  return r;
}

mfs_opendir Function

Function Signature: struct mfs_dir *mfs_opendir(const char *name)

This function opens a directory by name and initializes the directory structure.

Functionality:

  • Initializes the file system if it’s not already initialized.
  • Handles the root directory case.
  • Retrieves the inode of the directory.
  • Initializes the directory structure for subsequent reads.

struct mfs_dir *mfs_opendir(const char *name) {
  if (fs == NULL) fs_init();
  int num_inodo;
  printf("\t\tExploring directory: '%s'\n", name);
  if (name[0] == '.' && name[1] == '\0') {
    if (fs->dir.num_inodo == -1) {
      inode_read(fs, &fs->dir.inodo, fs->sb.root_inode);
      fs->dir.num_inodo = fs->sb.root_inode;
      fs->dir.pos = 0;
      fs->dir.pos_block = 0;
      strcpy(fs->dir.path, name);
    } else
      return NULL;
  } else {
    if (fs->dir.num_inodo == -1) {
      num_inodo = get_inodo(fs, name);
      if (num_inodo == -1) return NULL;
      inode_read(fs, &fs->dir.inodo, num_inodo);
      fs->dir.num_inodo = num_inodo;
      fs->dir.pos = 0;
      fs->dir.pos_block = 0;
      strcpy(fs->dir.path, name);
    } else
      return NULL;
  }
  return &fs->dir;
}

mfs_readdir Function

Function Signature: struct dirent *mfs_readdir(MFS_DIR *dir)

This function reads directory entries from an opened directory.

Functionality:

  • Reads the block corresponding to the directory’s inode.
  • Checks if the current position is valid.
  • Allocates memory for a directory entry.
  • Copies the name of the entry.

struct dirent *mfs_readdir(MFS_DIR *dir) {
  char block[fs->sb.block_size];
  struct dirent *entry = NULL;
  struct entry *ent = (struct entry *)block;
  struct disk_inode ino_previo;
  int num_inodo_root, inodo_root_previo, root_is_dir = 1, i = 0;

  printf("int [dir->pos].name%s\n", ent[dir->pos].name);
  printf("int [dir->pos].inode%d\n", ent[dir->pos].inode);
  printf("dir->inodo.e.start%d\n", dir->inodo.e.start);
  printf("dir->pos%d\n", dir->pos);
  data_read(fs, block, dir->inodo.e.start + i);
  if (dir->pos != -1) {
    if (ent[dir->pos].inode != -1) {
      printf("dir->num_inodo%d\n", dir->num_inodo);
      printf("get_inodo_previo(fs, dir->path)%d\n",
             get_inodo_previo(fs, dir->path));
      entry = malloc(sizeof(struct dirent));
      strcpy(entry->d_name, ent[dir->pos].name);
      num_inodo_root = dir->num_inodo;
    }
  }
  return entry;
}