Bläddra i källkod

Readdir impelemented, added folder check for brfs_delete, created rm program that can recursively delete folders, added mkfile program

bart 7 månader sedan
förälder
incheckning
191845d1da

+ 2 - 3
BCC/BDOS/BDOS.c

@@ -269,14 +269,13 @@ void syscall()
     syscall_data[0] = brfs_get_cursor(syscall_data[1]);
     break;
   case SYS_FS_DELETE:
-    syscall_data[0] = brfs_delete_file((char *)syscall_data[1]);
+    syscall_data[0] = brfs_delete((char *)syscall_data[1]);
     break;
   case SYS_FS_STAT:
     syscall_data[0] = brfs_stat((char *)syscall_data[1]);
     break;
   case SYS_FS_READDIR:
-    brfs_list_directory((char *)syscall_data[1]);
-    syscall_data[0] = 0; // TODO: implement
+    syscall_data[0] = brfs_read_directory((char *)syscall_data[1], (char *)syscall_data[2]);
     break;
   case SYS_FS_GETCWD:
     strcpy(syscall_data, shell_path);

+ 56 - 5
BCC/BDOS/lib/brfs.c

@@ -593,6 +593,45 @@ void brfs_list_directory(char* dir_path)
   uprintln("");
 }
 
+/**
+ * Reads all directory entries of a directory into a buffer
+ * dir_path: full path of the directory
+ * buffer: buffer to store the directory entries
+ * Returns the number of entries read, or -1 on error
+*/
+word brfs_read_directory(char* dir_path, struct brfs_dir_entry* buffer)
+{
+  // Find data block address of parent directory path
+  word dir_fat_idx = brfs_get_fat_idx_of_dir(dir_path);
+  if (dir_fat_idx == -1)
+  {
+    uprint("Parent directory ");
+    uprint(dir_path);
+    uprintln(" not found!");
+    return -1;
+  }
+
+  struct brfs_superblock* superblock = (struct brfs_superblock*) brfs_ram_storage;
+  word* dir_addr = brfs_ram_storage + SUPERBLOCK_SIZE + superblock->total_blocks + (dir_fat_idx * superblock->words_per_block);
+  word dir_entries_max = superblock->words_per_block / sizeof(struct brfs_dir_entry);
+
+  word entries_read = 0;
+
+  word i;
+  for (i = 0; i < dir_entries_max; i++)
+  {
+    struct brfs_dir_entry* dir_entry = (struct brfs_dir_entry*) (dir_addr + (i * sizeof(struct brfs_dir_entry)));
+    if (dir_entry->filename[0] != 0)
+    {
+      memcpy(buffer, dir_entry, sizeof(struct brfs_dir_entry));
+      buffer++;
+      entries_read++;
+    }
+  }
+
+  return entries_read;
+}
+
 /**
  * Open a file for reading and writing
  * Returns the file pointer (FAT idx of file), or -1 on error
@@ -703,10 +742,11 @@ word brfs_close_file(word file_pointer)
 
 /**
  * Delete a file by removing all FAT blocks and the directory entry
+ * Deletes a directory only if it is empty
  * Returns 1 on success, 0 on error
  * file_path: full path of the file
 */
-word brfs_delete_file(char* file_path)
+word brfs_delete(char* file_path)
 {
   // Split filename from path using basename and dirname
   char dirname_output[MAX_PATH_LENGTH];
@@ -736,10 +776,21 @@ word brfs_delete_file(char* file_path)
     {
       char decompressed_filename[17];
       strdecompress(decompressed_filename, (char*)&(dir_entry->filename));
-      // Also check for directory flag to be 0
-      if (strcmp(decompressed_filename, file_path_basename) == 0 && (dir_entry->flags & 0x01) == 0)
+      if (strcmp(decompressed_filename, file_path_basename) == 0)
       {
-        // Found file
+        if ((dir_entry->flags & 0x01) == 1)
+        {
+          // Check if directory is empty
+          struct brfs_dir_entry buffer[128]; // 128 to be safe
+          word num_entries = brfs_read_directory(file_path, buffer);
+          if (num_entries > 2)
+          {
+            uprint("Directory ");
+            uprint(file_path_basename);
+            uprintln(" is not empty!");
+            return 0;
+          }
+        }
         // Check if file is already open
         word j;
         for (j = 0; j < MAX_OPEN_FILES; j++)
@@ -764,7 +815,7 @@ word brfs_delete_file(char* file_path)
           current_fat_idx = next_fat_idx;
         }
 
-        // Delete file
+        // Delete entry
         memset((char*)dir_entry, 0, sizeof(struct brfs_dir_entry));
 
         // Update changed block

+ 1 - 1
BCC/BDOS/lib/netloader.c

@@ -243,7 +243,7 @@ void NETLOADER_handleSession(word s)
                         strcat(new_file_path, fileNameStr);
 
                         // try to delete file in case it exists
-                        brfs_delete_file(new_file_path);
+                        brfs_delete(new_file_path);
                         if (brfs_create_file(shell_path, fileNameStr))
                         {
                             

+ 3 - 0
BCC/userBDOS/lib/brfs.c

@@ -2,6 +2,9 @@
  * User library for file system operations
 */
 
+#define MAX_DIR_ENTRIES 128 // Safe bound on max number of entries in a directory (128 -> full dir on block size of 512 words)
+#define MAX_PATH_LENGTH 127
+
 struct brfs_dir_entry
 {
   word filename[4];       // 4 chars per word

+ 3 - 3
BCC/userBDOS/lib/sys.c

@@ -13,8 +13,6 @@
 #define INTID_UART1   0x7
 #define INTID_UART2   0x8
 
-#define MAX_PATH_LENGTH 127
-
 #define SYSCALL_RETVAL_ADDR 0x200000
 
 // System call IDs
@@ -316,11 +314,13 @@ word fs_stat(char* filename)
 
 /**
  * Lists the contents of a directory in the filesystem
+ * Returns the number of entries in the directory
 */
-word fs_readdir(char* dirname)
+word fs_readdir(char* dirname, char* buffer)
 {
   char* p = (char*) SYSCALL_RETVAL_ADDR;
   p[1] = (char) dirname;
+  p[2] = (char) buffer;  
   syscall(SYS_FS_READDIR);
   return p[0];
 }

+ 1 - 0
BCC/userBDOS/mkdir.c

@@ -3,6 +3,7 @@
 #include "lib/math.c"
 #include "lib/stdlib.c"
 #include "lib/sys.c"
+#include "lib/brfs.c"
 
 int main() 
 {

+ 59 - 0
BCC/userBDOS/mkfile.c

@@ -0,0 +1,59 @@
+#define word char
+
+#include "lib/math.c"
+#include "lib/stdlib.c"
+#include "lib/sys.c"
+#include "lib/brfs.c"
+
+int main() 
+{
+  // Read number of arguments
+  word argc = shell_argc();
+  if (argc < 2)
+  {
+    bdos_println("Usage: mkfile <fname>");
+    return 1;
+  }
+  
+  // Read fname
+  char** args = shell_argv();
+  char* fname = args[1];
+
+  char absolute_path[MAX_PATH_LENGTH];
+  // Check if absolute path
+  if (fname[0] != '/')
+  {
+    char* cwd = fs_getcwd();
+    strcpy(absolute_path, cwd);
+    strcat(absolute_path, "/");
+    strcat(absolute_path, fname);
+  }
+  else
+  {
+    strcpy(absolute_path, fname);
+  }
+
+  // Create file
+  if (fs_mkfile(absolute_path))
+  {
+    fs_syncflash();
+  }
+  else
+  {
+    bdos_println("Could not create file");
+  }
+
+  return 'q';
+}
+
+void interrupt()
+{
+  // Handle all interrupts
+  word i = get_int_id();
+  switch(i)
+  {
+    case INTID_TIMER1:
+      timer1Value = 1;  // Notify ending of timer1
+      break;
+  }
+}

+ 67 - 3
BCC/userBDOS/rm.c

@@ -5,6 +5,60 @@
 #include "lib/sys.c"
 #include "lib/brfs.c"
 
+void remove_dir(char* path)
+{
+  struct brfs_dir_entry entries[MAX_DIR_ENTRIES];
+  word num_entries = fs_readdir(path, entries);
+
+  word i;
+  for (i = 0; i < num_entries; i++)
+  {
+    struct brfs_dir_entry entry = entries[i];
+    char decompressed_filename[17];
+    strdecompress(decompressed_filename, entry.filename);
+    
+    if (strcmp(decompressed_filename, ".") == 0 || strcmp(decompressed_filename, "..") == 0)
+    {
+      continue;
+    }
+
+    char absolute_path[MAX_PATH_LENGTH];
+    strcpy(absolute_path, path);
+    strcat(absolute_path, "/");
+    strcat(absolute_path, decompressed_filename);
+
+    if ((entry.flags & 0x01) == 0)
+    {
+      // File
+      if (fs_delete(absolute_path))
+      {
+        // Do not sync flash after each file deletion
+      }
+      else
+      {
+        bdos_println("Could not delete file");
+      }
+    }
+    else
+    {
+      // Directory
+      remove_dir(absolute_path);
+    }
+  }
+
+  // Delete directory after contents are deleted
+  if (fs_delete(path))
+  {
+    // Do not sync flash after each directory deletion
+  }
+  else
+  {
+    bdos_println("Could not delete directory");
+  }
+  
+  
+}
+
 int main() 
 {
   // Read number of arguments
@@ -25,7 +79,10 @@ int main()
   {
     char* cwd = fs_getcwd();
     strcpy(absolute_path, cwd);
-    strcat(absolute_path, "/");
+    if (absolute_path[strlen(absolute_path) - 1] != '/')
+    {
+      strcat(absolute_path, "/");
+    }
     strcat(absolute_path, fname);
   }
   else
@@ -41,6 +98,13 @@ int main()
     return 1;
   }
 
+  // Check if root directory
+  if (entry->fat_idx == 0)
+  {
+    bdos_println("Cannot delete root directory");
+    return 1;
+  }
+
   if ((entry->flags & 0x01) == 0)
   {
     // File
@@ -56,8 +120,8 @@ int main()
   else
   {
     // Directory
-    uprintln("del dir");
-    // TODO: Implement recursive deletion of directory
+    remove_dir(absolute_path);
+    fs_syncflash();
   }
 
   return 'q';