// // Created by rick on 11-03-21. // #include #include #include #include #include #include typedef struct { char filename[100]; uint64_t mode; uint64_t uid; uint64_t gid; char filesize[12]; char lastmod[12]; uint64_t checksum; char type; char linked[100]; char magic[6]; char version[2]; char username[32]; char groupname[32]; uint64_t device_major; uint64_t device_minor; char prefix[155]; } att_packed ustar_sector; typedef struct { ustar_sector sector; uint32_t lba; } ustar_inode; typedef struct { ustar_inode *first_inode; const block_device_t *device; } ustar_fs; const char *ustar_magic = "ustar"; const char *ustar_version = "00"; #define USTAR_TYPE_FILE '0' #define USTAR_TYPE_LINK '1' #define USTAR_TYPE_SYMBOL '2' #define USTAR_TYPE_CHAR '3' #define USTAR_TYPE_BLOCK '4' #define USTAR_TYPE_DIR '5' #define USTAR_TYPE_FIFO '6' #define SECTOR_SIZE 512 long ustar_oct_to_long(char *oct, uint32_t size) { char value[size + 1]; memcpy(value, oct, size); value[size] = 0; return strtol(value, NULL, 8); } bool ustar_sector_valid(ustar_sector *sector) { return strncmp(ustar_magic, sector->magic, 6) == 0; } ustar_sector *ustar_next(ustar_sector *current) { if (ustar_sector_valid(current)) { return NULL; } long filesize = ustar_oct_to_long(current->filesize, 12); long offset = (((filesize + SECTOR_SIZE - 1) / SECTOR_SIZE) + 1) * SECTOR_SIZE; ustar_sector *next = ((void *) current) + offset; return ustar_sector_valid(next) ? next : NULL; } uint8_t ustar_check_device(const block_device_t *device) { ustar_sector *sector = malloc(512); // todo fix leak if (device->access(device, BLOCK_DEV_DIRECTION_READ, 0, 1, sector) != BLOCK_DEV_ACCESS_OK) { free(sector); return BLOCK_DEV_DRIVER_CHECK_NO_MATCH; } if (!ustar_sector_valid(sector)) { free(sector); return BLOCK_DEV_DRIVER_CHECK_NO_MATCH; } ustar_fs *fs = malloc(sizeof(ustar_fs)); fs->first_inode = malloc(sizeof(ustar_inode)); memcpy(&fs->first_inode->sector, sector, sizeof(ustar_sector)); fs->first_inode->lba = 0; fs->device = device; return BLOCK_DEV_DRIVER_CHECK_OK; } BLOCK_DEV_DRIVER(300) = { .name = "ustar", .check_device = ustar_check_device, .free_device = NULL, };