/* Student No.: 109350041 Student Name: Dan-Yi, Chen Email: dannychen910608@gmail.com SE tag: xnxcxtxuxoxsx Statement: I am fully aware that this program is not supposed to be posted to a public server, such as a public GitHub repository or a public web page. */ #define FUSE_USE_VERSION 30 #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; struct TarHeader { char name[100]; char mode[8]; char uid[8]; char gid[8]; char size[12]; char mtime[12]; char checksum[8]; char typeflag[1]; char linkname[100]; char magic[6]; char version[2]; char uname[32]; char gname[32]; char devmajor[8]; char devminor[8]; char prefix[155]; }; struct FileEntry { mode_t mode; uid_t uid; gid_t gid; off_t size; time_t mtime; char typeflag; string linkname; vector content; vector pathParts; }; static map fileEntries; static void parseTarFile() { FILE *fp = fopen("test.tar", "rb"); if (!fp) { perror("Failed to open basic.tar"); exit(1); } unsigned char block[512]; while (1) { TarHeader header; memset(&header, 0, sizeof(header)); size_t r = fread(block, 1, 512, fp); if (r < 512) break; memcpy(&header, block, sizeof(header)); if (header.name[0] == '\0') { break; } FileEntry entry; entry.mode = (mode_t)strtol(header.mode, NULL, 8); entry.size = (off_t)strtol(header.size, NULL, 8); entry.mtime = (time_t)strtol(header.mtime, NULL, 8); entry.typeflag = header.typeflag[0]; entry.linkname = string(header.linkname); entry.uid = (uid_t)strtol(header.uid, NULL, 8); entry.gid = (gid_t)strtol(header.gid, NULL, 8); { char *dup = strdup(header.name); char *token = strtok(dup, "/"); while (token) { entry.pathParts.push_back(string(token)); token = strtok(NULL, "/"); } free(dup); } if (entry.typeflag == '0' && entry.size > 0) { entry.content.resize(entry.size); fread(&entry.content[0], 1, entry.size, fp); long skip = (512 - (entry.size % 512)) % 512; fseek(fp, skip, SEEK_CUR); } else if (entry.typeflag == '5') { } else if (entry.typeflag == '2') { long skip = 512 * ((entry.size + 511) / 512); fseek(fp, skip, SEEK_CUR); } else { long skip = 512 * ((entry.size + 511) / 512); fseek(fp, skip, SEEK_CUR); } fileEntries[string(header.name)] = entry; } fclose(fp); } static bool matchPath(const vector &target, const vector &entryPath) { if (target.size() != entryPath.size()) return false; for (size_t i = 0; i < target.size(); ++i) { if (target[i] != entryPath[i]) return false; } return true; } static bool matchDirectory(const vector &parent, const vector &entryPath) { if (entryPath.size() <= parent.size()) return false; for (size_t i = 0; i < parent.size(); ++i) { if (parent[i] != entryPath[i]) return false; } return true; } int my_getattr(const char *path, struct stat *stbuf) { memset(stbuf, 0, sizeof(struct stat)); if (strcmp(path, "/") == 0) { stbuf->st_mode = S_IFDIR | 0755; stbuf->st_uid = 0; stbuf->st_gid = 0; stbuf->st_nlink = 0; stbuf->st_size = 0; stbuf->st_mtime = time(NULL); stbuf->st_blocks = 0; stbuf->st_blksize = 512; return 0; } vector target; { char *dup = strdup(path + 1); char *token = strtok(dup, "/"); while (token) { target.push_back(string(token)); token = strtok(NULL, "/"); } free(dup); } for (auto &it : fileEntries) { FileEntry &e = it.second; if (matchPath(target, e.pathParts)) { stbuf->st_uid = e.uid; // 使用tar記錄的uid stbuf->st_gid = e.gid; // 使用tar記錄的gid stbuf->st_mtime = e.mtime; stbuf->st_size = e.size; stbuf->st_blocks = 0; stbuf->st_blksize = 512; if (e.typeflag == '5') { // 目錄 stbuf->st_mode = S_IFDIR | (e.mode & 0777); //stbuf->st_nlink = 0; } else if (e.typeflag == '0') { // 一般檔案 stbuf->st_mode = S_IFREG | (e.mode & 0777); //stbuf->st_nlink = 0; } else if (e.typeflag == '2') { // 符號連結 stbuf->st_mode = S_IFLNK | 0777; // 符號連結大小顯示為0 stbuf->st_size = 0; //stbuf->st_nlink = 0; } else { stbuf->st_nlink = 0; } return 0; } } return -ENOENT; } int my_readdir(const char *path, void *buffer, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *fi) { vector target; { char *dup = strdup(path + 1); char *token = strtok(dup, "/"); while (token) { target.push_back(string(token)); token = strtok(NULL, "/"); } free(dup); } filler(buffer, ".", NULL, 0); filler(buffer, "..", NULL, 0); for (auto &it : fileEntries) { FileEntry &e = it.second; if (matchDirectory(target, e.pathParts) && e.pathParts.size() == target.size() + 1) { filler(buffer, e.pathParts.back().c_str(), NULL, 0); } } return 0; } int my_read(const char *path, char *buf, size_t size, off_t offset, struct fuse_file_info *fi) { vector target; { char *dup = strdup(path + 1); char *token = strtok(dup, "/"); while (token) { target.push_back(string(token)); token = strtok(NULL, "/"); } free(dup); } for (auto &it : fileEntries) { FileEntry &e = it.second; if (matchPath(target, e.pathParts) && e.typeflag == '0') { if ((off_t)offset >= e.size) { return 0; } size_t bytesToRead = (size_t)((offset + size > e.size) ? (e.size - offset) : size); memcpy(buf, &e.content[offset], bytesToRead); return (int)bytesToRead; } } return -ENOENT; } int my_readlink(const char *path, char *buffer, size_t size) { vector target; { char *dup = strdup(path + 1); char *token = strtok(dup, "/"); while (token) { target.push_back(string(token)); token = strtok(NULL, "/"); } free(dup); } for (auto &it : fileEntries) { FileEntry &e = it.second; if (matchPath(target, e.pathParts) && e.typeflag == '2') { strncpy(buffer, e.linkname.c_str(), size - 1); buffer[size - 1] = '\0'; return 0; } } return -ENOENT; } static struct fuse_operations operations; int main(int argc, char *argv[]) { parseTarFile(); memset(&operations, 0, sizeof(operations)); operations.getattr = my_getattr; operations.readdir = my_readdir; operations.read = my_read; operations.readlink = my_readlink; return fuse_main(argc, argv, &operations, NULL); }