[FREELDR] Advance the file pointers every time a read operation is performed, in...
[reactos.git] / boot / freeldr / freeldr / lib / fs / btrfs.c
index 7c3aa5c..2f763f0 100644 (file)
@@ -8,8 +8,8 @@
 /* Some code was taken from u-boot, https://github.com/u-boot/u-boot/tree/master/fs/btrfs */
 
 #include <freeldr.h>
-#include <debug.h>
 
+#include <debug.h>
 DBG_DEFAULT_CHANNEL(FILESYSTEM);
 
 #define TAG_BTRFS_INFO 'IftB'
@@ -18,7 +18,9 @@ DBG_DEFAULT_CHANNEL(FILESYSTEM);
 #define TAG_BTRFS_FILE  'FftB'
 #define TAG_BTRFS_LINK  'LftB'
 
-#define INVALID_INODE ((ULONGLONG)-1)
+#define INVALID_INODE _UI64_MAX
+#define INVALID_ADDRESS _UI64_MAX
+#define READ_ERROR _UI64_MAX
 
 struct BTRFS_INFO {
     ULONG DeviceId;
@@ -239,9 +241,9 @@ static u64 logical_physical(u64 logical)
     if (ret == 0)
         slot++;
     else if (slot == 0)
-        return -1;
+        return INVALID_ADDRESS;
     if (logical >= chunk_map->map[slot - 1].logical + chunk_map->map[slot - 1].length)
-        return -1;
+        return INVALID_ADDRESS;
 
     TRACE("Address translation: 0x%llx -> 0x%llx\n", logical,
           chunk_map->map[slot - 1].physical + logical - chunk_map->map[slot - 1].logical);
@@ -408,7 +410,7 @@ static int next_slot(struct btrfs_disk_key *key,
     }
     path->slots[0] = slot;
 
-    out:
+out:
     if (path_current_disk_key(path)->objectid && !btrfs_comp_keys_type(key, path_current_disk_key(path)))
         return 0;
     else
@@ -617,7 +619,7 @@ static BOOLEAN BtrFsLookupDirItemI(const struct btrfs_root_item *root, u64 dir_h
         name_buf = (char *) item + sizeof(*item);
         TRACE("Compare names %.*s and %.*s\n", name_len, name, item->name_len, name_buf);
 
-        if (_strnicmp(name, name_buf, name_len) == 0)
+        if (name_len == item->name_len && _strnicmp(name, name_buf, name_len) == 0)
         {
             *ret_item = *item;
             result = TRUE;
@@ -626,7 +628,7 @@ static BOOLEAN BtrFsLookupDirItemI(const struct btrfs_root_item *root, u64 dir_h
 
     } while (!next_slot(&key, &path));
 
-    cleanup:
+cleanup:
     free_path(&path);
     return result;
 }
@@ -652,7 +654,7 @@ static u64 btrfs_read_extent_inline(struct btrfs_path *path,
     if (offset > dlen)
     {
         ERR("Tried to read offset (%llu) beyond extent length (%lu)\n", offset, dlen);
-        return INVALID_INODE;
+        return READ_ERROR;
     }
 
     if (size > dlen - offset)
@@ -666,7 +668,7 @@ static u64 btrfs_read_extent_inline(struct btrfs_path *path,
     }
 
     ERR("No compression supported right now\n");
-    return INVALID_INODE;
+    return READ_ERROR;
 }
 
 static u64 btrfs_read_extent_reg(struct btrfs_path *path, struct btrfs_file_extent_item *extent,
@@ -679,17 +681,24 @@ static u64 btrfs_read_extent_reg(struct btrfs_path *path, struct btrfs_file_exte
     if (offset > dlen)
     {
         ERR("Tried to read offset (%llu) beyond extent length (%lu)\n", offset, dlen);
-        return -1ULL;
+        return READ_ERROR;
     }
 
     if (size > dlen - offset)
         size = dlen - offset;
 
+    /* Handle sparse extent */
+    if (extent->disk_bytenr == 0 && extent->disk_num_bytes == 0)
+    {
+        RtlZeroMemory(out, size);
+        return size;
+    }
+
     physical = logical_physical(extent->disk_bytenr);
-    if (physical == -1ULL)
+    if (physical == INVALID_ADDRESS)
     {
         ERR("Unable to convert logical address to physical: %llu\n", extent->disk_bytenr);
-        return -1ULL;
+        return READ_ERROR;
     }
 
     if (extent->compression == BTRFS_COMPRESS_NONE)
@@ -704,7 +713,7 @@ static u64 btrfs_read_extent_reg(struct btrfs_path *path, struct btrfs_file_exte
             if (!disk_read(physical, temp_out, size + offset))
             {
                 FrLdrTempFree(temp_out, TAG_BTRFS_FILE);
-                return -1ULL;
+                return READ_ERROR;
             }
 
             memcpy(out, temp_out + offset, size);
@@ -712,14 +721,14 @@ static u64 btrfs_read_extent_reg(struct btrfs_path *path, struct btrfs_file_exte
         } else
         {
             if (!disk_read(physical, out, size))
-                return -1ULL;
+                return READ_ERROR;
         }
 
         return size;
     }
 
     ERR("No compression supported right now\n");
-    return -1ULL;
+    return READ_ERROR;
 }
 
 static u64 btrfs_file_read(const struct btrfs_root_item *root, u64 inr, u64 offset, u64 size, char *buf)
@@ -728,7 +737,7 @@ static u64 btrfs_file_read(const struct btrfs_root_item *root, u64 inr, u64 offs
     struct btrfs_disk_key key;
     struct btrfs_file_extent_item *extent;
     int res = 0;
-    u64 rd, seek_pointer = (u64) -1ULL, offset_in_extent;
+    u64 rd, seek_pointer = READ_ERROR, offset_in_extent;
     BOOLEAN find_res;
 
     TRACE("btrfs_file_read inr=%llu offset=%llu size=%llu\n", inr, offset, size);
@@ -776,10 +785,10 @@ static u64 btrfs_file_read(const struct btrfs_root_item *root, u64 inr, u64 offs
             rd = btrfs_read_extent_reg(&path, extent, offset_in_extent, size, buf);
         }
 
-        if (rd == -1ULL)
+        if (rd == READ_ERROR)
         {
             ERR("Error while reading extent\n");
-            seek_pointer = (u64) -1ULL;
+            seek_pointer = READ_ERROR;
             goto out;
         }
 
@@ -794,12 +803,12 @@ static u64 btrfs_file_read(const struct btrfs_root_item *root, u64 inr, u64 offs
 
     if (res)
     {
-        seek_pointer = (u64) -1ULL;
+        seek_pointer = READ_ERROR;
         goto out;
     }
 
     seek_pointer -= offset;
-    out:
+out:
     free_path(&path);
     return seek_pointer;
 }
@@ -814,7 +823,7 @@ static u64 btrfs_lookup_inode_ref(const struct btrfs_root_item *root, u64 inr,
 {
     struct btrfs_path path;
     struct btrfs_inode_ref *ref;
-    u64 ret = -1ULL;
+    u64 ret = INVALID_INODE;
     init_path(&path);
 
     if (BtrFsSearchTreeType(root, inr, BTRFS_INODE_REF_KEY, &path))
@@ -915,7 +924,7 @@ static BOOLEAN btrfs_readlink(const struct btrfs_root_item *root, u64 inr, char
 
     res = TRUE;
 
-    out:
+out:
     free_path(&path);
     return res;
 }
@@ -1023,7 +1032,7 @@ static u64 btrfs_lookup_path(const struct btrfs_root_item *root, u64 inr, const
         if (len > BTRFS_NAME_MAX)
         {
             ERR("%s: Name too long at \"%.*s\"\n", BTRFS_NAME_MAX, cur);
-            return -1ULL;
+            return INVALID_INODE;
         }
 
         if (len == 1 && cur[0] == '.')
@@ -1113,7 +1122,6 @@ ARC_STATUS BtrFsClose(ULONG FileId)
     TRACE("BtrFsClose %lu\n", FileId);
 
     FrLdrTempFree(phandle, TAG_BTRFS_FILE);
-
     return ESUCCESS;
 }
 
@@ -1121,16 +1129,12 @@ ARC_STATUS BtrFsGetFileInformation(ULONG FileId, FILEINFORMATION *Information)
 {
     pbtrfs_file_info phandle = FsGetDeviceSpecific(FileId);
 
-    TRACE("BtrFsGetFileInformation %lu\n", FileId);
-
-    RtlZeroMemory(Information, sizeof(FILEINFORMATION));
+    RtlZeroMemory(Information, sizeof(*Information));
     Information->EndingAddress.QuadPart = phandle->inode.size;
     Information->CurrentAddress.QuadPart = phandle->position;
 
-    TRACE("BtrFsGetFileInformation() FileSize = %llu\n",
-          Information->EndingAddress.QuadPart);
-    TRACE("BtrFsGetFileInformation() FilePointer = %llu\n",
-          Information->CurrentAddress.QuadPart);
+    TRACE("BtrFsGetFileInformation(%lu) -> FileSize = %llu, FilePointer = 0x%llx\n",
+          FileId, Information->EndingAddress.QuadPart, Information->CurrentAddress.QuadPart);
 
     return ESUCCESS;
 }
@@ -1150,7 +1154,7 @@ ARC_STATUS BtrFsOpen(CHAR *Path, OPENMODE OpenMode, ULONG *FileId)
 
     inr = btrfs_lookup_path(&BtrFsInfo->FsRoot, BtrFsInfo->FsRoot.root_dirid, Path, &type, &temp_file_info.inode, 40);
 
-    if (inr == -1ULL)
+    if (inr == INVALID_INODE)
     {
         TRACE("Cannot lookup file %s\n", Path);
         return ENOENT;
@@ -1191,12 +1195,13 @@ ARC_STATUS BtrFsRead(ULONG FileId, VOID *Buffer, ULONG Size, ULONG *BytesRead)
         Size = phandle->inode.size;
 
     rd = btrfs_file_read(&BtrFsInfo->FsRoot, phandle->inr, phandle->position, Size, Buffer);
-    if (rd == -1ULL)
+    if (rd == READ_ERROR)
     {
         TRACE("An error occured while reading file %lu\n", FileId);
         return ENOENT;
     }
 
+    phandle->position += rd;
     *BytesRead = rd;
     return ESUCCESS;
 }
@@ -1204,15 +1209,24 @@ ARC_STATUS BtrFsRead(ULONG FileId, VOID *Buffer, ULONG Size, ULONG *BytesRead)
 ARC_STATUS BtrFsSeek(ULONG FileId, LARGE_INTEGER *Position, SEEKMODE SeekMode)
 {
     pbtrfs_file_info phandle = FsGetDeviceSpecific(FileId);
+    LARGE_INTEGER NewPosition = *Position;
 
-    TRACE("BtrFsSeek %lu NewFilePointer = %llu\n", FileId, Position->QuadPart);
+    switch (SeekMode)
+    {
+        case SeekAbsolute:
+            break;
+        case SeekRelative:
+            NewPosition.QuadPart += phandle->position;
+            break;
+        default:
+            ASSERT(FALSE);
+            return EINVAL;
+    }
 
-    if (SeekMode != SeekAbsolute)
-        return EINVAL;
-    if (Position->QuadPart >= phandle->inode.size)
+    if (NewPosition.QuadPart >= phandle->inode.size)
         return EINVAL;
 
-    phandle->position = Position->QuadPart;
+    phandle->position = NewPosition.QuadPart;
     return ESUCCESS;
 }
 
@@ -1231,7 +1245,7 @@ const DEVVTBL *BtrFsMount(ULONG DeviceId)
     struct btrfs_path path;
     struct btrfs_root_item fs_root_item;
 
-    TRACE("Enter BtrFsMount(), sizeof %d %d\n", sizeof(struct BTRFS_INFO), sizeof(struct btrfs_super_block));
+    TRACE("Enter BtrFsMount(%lu)\n", DeviceId);
 
     BtrFsInfo = FrLdrTempAlloc(sizeof(struct BTRFS_INFO), TAG_BTRFS_INFO);
     if (!BtrFsInfo)
@@ -1245,39 +1259,37 @@ const DEVVTBL *BtrFsMount(ULONG DeviceId)
         return NULL;
     }
 
-    /* Check if SuperBlock is valid. If yes, return Ext2 function table */
-    if (BtrFsInfo->SuperBlock.magic == BTRFS_MAGIC_N)
+    /* Check if SuperBlock is valid. If yes, return BTRFS function table */
+    if (BtrFsInfo->SuperBlock.magic != BTRFS_MAGIC_N)
     {
-        BtrFsInfo->DeviceId = DeviceId;
-        TRACE("BtrFsMount() superblock magic ok\n");
-
-        btrfs_init_crc32c();
-
-        btrfs_read_sys_chunk_array();
-        btrfs_read_chunk_tree();
+        FrLdrTempFree(BtrFsInfo, TAG_BTRFS_INFO);
+        return NULL;
+    }
 
-        /* setup roots */
-        fs_root_item.bytenr = BtrFsInfo->SuperBlock.root;
-        fs_root_item.level = BtrFsInfo->SuperBlock.root_level;
+    BtrFsInfo->DeviceId = DeviceId;
+    TRACE("BtrFsMount(%lu) superblock magic ok\n", DeviceId);
 
-        init_path(&path);
-        if (!BtrFsSearchTreeType(&fs_root_item, BTRFS_FS_TREE_OBJECTID, BTRFS_ROOT_ITEM_KEY, &path))
-        {
-            FrLdrTempFree(BtrFsInfo, TAG_BTRFS_INFO);
-            free_path(&path);
-            return NULL;
-        }
+    btrfs_init_crc32c();
 
-        BtrFsInfo->FsRoot = *(struct btrfs_root_item *) path_current_data(&path);
-
-        free_path(&path);
+    btrfs_read_sys_chunk_array();
+    btrfs_read_chunk_tree();
 
-        TRACE("BtrFsMount success\n");
+    /* setup roots */
+    fs_root_item.bytenr = BtrFsInfo->SuperBlock.root;
+    fs_root_item.level = BtrFsInfo->SuperBlock.root_level;
 
-        return &BtrFsFuncTable;
-    }
-    else
+    init_path(&path);
+    if (!BtrFsSearchTreeType(&fs_root_item, BTRFS_FS_TREE_OBJECTID, BTRFS_ROOT_ITEM_KEY, &path))
     {
+        FrLdrTempFree(BtrFsInfo, TAG_BTRFS_INFO);
+        free_path(&path);
         return NULL;
     }
+
+    BtrFsInfo->FsRoot = *(struct btrfs_root_item *) path_current_data(&path);
+
+    free_path(&path);
+
+    TRACE("BtrFsMount(%lu) success\n", DeviceId);
+    return &BtrFsFuncTable;
 }