1 /* 2 * Copyright 2009, Raghuram Nagireddy <raghuram87@gmail.com>. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 #define FUSE_USE_VERSION 27 7 8 #include <fuse/fuse.h> 9 #include <stdio.h> 10 #include <stdlib.h> 11 12 #include "fssh.h" 13 14 #include "driver_settings.h" 15 #include "external_commands.h" 16 #include "fd.h" 17 #include "fssh_dirent.h" 18 #include "fssh_errno.h" 19 #include "fssh_errors.h" 20 #include "fssh_fcntl.h" 21 #include "fssh_fs_info.h" 22 #include "fssh_module.h" 23 #include "fssh_node_monitor.h" 24 #include "fssh_stat.h" 25 #include "fssh_string.h" 26 #include "fssh_type_constants.h" 27 #include "module.h" 28 #include "syscalls.h" 29 #include "vfs.h" 30 31 32 extern fssh_module_info *modules[]; 33 34 extern fssh_file_system_module_info gRootFileSystem; 35 36 namespace FSShell { 37 38 const char* kMountPoint = "/myfs"; 39 40 static mode_t sUmask = 0022; 41 42 #define PRINTD(x) fprintf(stderr, x) 43 44 45 static fssh_status_t 46 init_kernel() 47 { 48 fssh_status_t error; 49 50 // init module subsystem 51 error = module_init(NULL); 52 if (error != FSSH_B_OK) { 53 fprintf(stderr, "module_init() failed: %s\n", fssh_strerror(error)); 54 return error; 55 } 56 57 // init driver settings 58 error = driver_settings_init(); 59 if (error != FSSH_B_OK) { 60 fprintf(stderr, "initializing driver settings failed: %s\n", 61 fssh_strerror(error)); 62 return error; 63 } 64 65 // register built-in modules, i.e. the rootfs and the client FS 66 register_builtin_module(&gRootFileSystem.info); 67 for (int i = 0; modules[i]; i++) 68 register_builtin_module(modules[i]); 69 70 // init VFS 71 error = vfs_init(NULL); 72 if (error != FSSH_B_OK) { 73 fprintf(stderr, "initializing VFS failed: %s\n", fssh_strerror(error)); 74 return error; 75 } 76 77 // init kernel IO context 78 gKernelIOContext = (io_context*)vfs_new_io_context(NULL); 79 if (!gKernelIOContext) { 80 fprintf(stderr, "creating IO context failed!\n"); 81 return FSSH_B_NO_MEMORY; 82 } 83 84 // mount root FS 85 fssh_dev_t rootDev = _kern_mount("/", NULL, "rootfs", 0, NULL, 0); 86 if (rootDev < 0) { 87 fprintf(stderr, "mounting rootfs failed: %s\n", fssh_strerror(rootDev)); 88 return rootDev; 89 } 90 91 // set cwd to "/" 92 error = _kern_setcwd(-1, "/"); 93 if (error != FSSH_B_OK) { 94 fprintf(stderr, "setting cwd failed: %s\n", fssh_strerror(error)); 95 return error; 96 } 97 98 // create mount point for the client FS 99 error = _kern_create_dir(-1, kMountPoint, 0775); 100 if (error != FSSH_B_OK) { 101 fprintf(stderr, "creating mount point failed: %s\n", 102 fssh_strerror(error)); 103 return error; 104 } 105 106 return FSSH_B_OK; 107 } 108 109 110 static void 111 fromFsshStatToStat(struct fssh_stat* f_stbuf, struct stat* stbuf) 112 { 113 stbuf->st_dev = f_stbuf->fssh_st_dev; 114 stbuf->st_ino = f_stbuf->fssh_st_ino; 115 stbuf->st_mode = f_stbuf->fssh_st_mode; 116 stbuf->st_nlink = f_stbuf->fssh_st_nlink; 117 stbuf->st_uid = f_stbuf->fssh_st_uid; 118 stbuf->st_gid = f_stbuf->fssh_st_gid; 119 stbuf->st_rdev = f_stbuf->fssh_st_rdev; 120 stbuf->st_size = f_stbuf->fssh_st_size; 121 stbuf->st_blksize = f_stbuf->fssh_st_blksize; 122 stbuf->st_blocks = f_stbuf->fssh_st_blocks; 123 stbuf->st_atime = f_stbuf->fssh_st_atime; 124 stbuf->st_mtime = f_stbuf->fssh_st_mtime; 125 stbuf->st_ctime = f_stbuf->fssh_st_ctime; 126 } 127 128 #define _ERR(x) (-1*fssh_to_host_error(x)) 129 130 131 // pragma mark - FUSE functions 132 133 134 //extern "C" { 135 136 137 int 138 fuse_getattr(const char* path, struct stat* stbuf) 139 { 140 PRINTD("##getattr\n"); 141 struct fssh_stat f_stbuf; 142 fssh_status_t status = _kern_read_stat(-1, path, false, &f_stbuf, 143 sizeof(f_stbuf)); 144 fromFsshStatToStat(&f_stbuf, stbuf); 145 printf("GETATTR returned: %d\n", status); 146 return _ERR(status); 147 } 148 149 150 static int 151 fuse_access(const char* path, int mask) 152 { 153 PRINTD("##access\n"); 154 return _ERR(_kern_access(path, mask)); 155 } 156 157 158 static int 159 fuse_readlink(const char* path, char* buffer, size_t size) 160 { 161 PRINTD("##readlink\n"); 162 size_t n_size = size - 1; 163 fssh_status_t st = _kern_read_link(-1, path, buffer, &n_size); 164 if (st >= FSSH_B_OK) 165 buffer[n_size] = '\0'; 166 return _ERR(st); 167 } 168 169 170 static int 171 fuse_readdir(const char* path, void* buf, fuse_fill_dir_t filler, 172 off_t offset, struct fuse_file_info* fi) 173 { 174 PRINTD("##readdir\n"); 175 int dfp = _kern_open_dir(-1, path); 176 if (dfp < FSSH_B_OK) 177 return _ERR(dfp); 178 179 fssh_ssize_t entriesRead = 0; 180 struct fssh_stat f_st; 181 struct stat st; 182 char buffer[sizeof(fssh_dirent) + FSSH_B_FILE_NAME_LENGTH]; 183 fssh_dirent* dirEntry = (fssh_dirent*)buffer; 184 while ((entriesRead = _kern_read_dir(dfp, dirEntry, 185 sizeof(buffer), 1)) == 1) { 186 fssh_memset(&st, 0, sizeof(st)); 187 fssh_memset(&f_st, 0, sizeof(f_st)); 188 fssh_status_t status = _kern_read_stat(dfp, dirEntry->d_name, 189 false, &f_st, sizeof(f_st)); 190 if (status >= FSSH_B_OK) { 191 fromFsshStatToStat(&f_st, &st); 192 if (filler(buf, dirEntry->d_name, &st, 0)) 193 break; 194 } 195 } 196 _kern_close(dfp); 197 //TODO: check _kern_close 198 return 0; 199 } 200 201 202 static int 203 fuse_mknod(const char* path, mode_t mode, dev_t rdev) 204 { 205 PRINTD("##mknod\n"); 206 if (S_ISREG(mode)) { 207 int fd = _kern_open(-1, path, 208 FSSH_O_CREAT | FSSH_O_EXCL | FSSH_O_WRONLY, mode); 209 if (fd >= FSSH_B_OK) 210 return _ERR(_kern_close(fd)); 211 return _ERR(fd); 212 } else if (S_ISFIFO(mode)) 213 return _ERR(FSSH_EINVAL); 214 else 215 return _ERR(FSSH_EINVAL); 216 } 217 218 219 static int 220 fuse_mkdir(const char* path, mode_t mode) 221 { 222 PRINTD("##mkdir\n"); 223 return _ERR(_kern_create_dir(-1, path, mode)); 224 } 225 226 227 static int 228 fuse_symlink(const char* from, const char* to) 229 { 230 PRINTD("##symlink\n"); 231 return _ERR(_kern_create_symlink(-1, from, to, 232 FSSH_S_IRWXU | FSSH_S_IRWXG | FSSH_S_IRWXO)); 233 } 234 235 236 static int 237 fuse_unlink(const char* path) 238 { 239 PRINTD("##unlink\n"); 240 return _ERR(_kern_unlink(-1, path)); 241 } 242 243 244 static int 245 fuse_rmdir(const char* path) 246 { 247 PRINTD("##rmdir\n"); 248 return _ERR(_kern_remove_dir(-1, path)); 249 } 250 251 252 static int 253 fuse_rename(const char* from, const char* to) 254 { 255 PRINTD("##rename\n"); 256 return _ERR(_kern_rename(-1, from, -1, to)); 257 } 258 259 260 static int 261 fuse_link(const char* from, const char* to) 262 { 263 PRINTD("##link\n"); 264 return _ERR(_kern_create_link(from, to)); 265 } 266 267 268 static int 269 fuse_chmod(const char* path, mode_t mode) 270 { 271 PRINTD("##chmod\n"); 272 fssh_struct_stat st; 273 st.fssh_st_mode = mode; 274 return _ERR(_kern_write_stat(-1, path, false, &st, sizeof(st), 275 FSSH_B_STAT_MODE)); 276 } 277 278 279 static int 280 fuse_chown(const char* path, uid_t uid, gid_t gid) 281 { 282 PRINTD("##chown\n"); 283 fssh_struct_stat st; 284 st.fssh_st_uid = uid; 285 st.fssh_st_gid = gid; 286 return _ERR(_kern_write_stat(-1, path, false, &st, sizeof(st), 287 FSSH_B_STAT_UID|FSSH_B_STAT_GID)); 288 } 289 290 291 static int 292 fuse_open(const char* path, struct fuse_file_info* fi) 293 { 294 PRINTD("##open\n"); 295 // TODO: Do we have a syscall similar to the open syscall in linux which 296 // takes only two args: path and flags with no mask/perms? 297 int fd = _kern_open(-1, path, fi->flags, 298 (FSSH_S_IRWXU | FSSH_S_IRWXG | FSSH_S_IRWXO) & ~sUmask); 299 _kern_close(fd); 300 if (fd < FSSH_B_OK) 301 return _ERR(fd); 302 else 303 return 0; 304 } 305 306 307 static int 308 fuse_read(const char* path, char* buf, size_t size, off_t offset, 309 struct fuse_file_info* fi) 310 { 311 PRINTD("##read\n"); 312 int fd = _kern_open(-1, path, FSSH_O_RDONLY, 313 (FSSH_S_IRWXU | FSSH_S_IRWXG | FSSH_S_IRWXO) & ~sUmask); 314 if (fd < FSSH_B_OK) 315 return _ERR(fd); 316 317 int res = _kern_read(fd, offset, buf, size); 318 _kern_close(fd); 319 if (res < FSSH_B_OK) 320 res = _ERR(res); 321 return res; 322 } 323 324 325 static int 326 fuse_write(const char* path, const char* buf, size_t size, off_t offset, 327 struct fuse_file_info* fi) 328 { 329 PRINTD("##write\n"); 330 int fd = _kern_open(-1, path, FSSH_O_WRONLY, 331 (FSSH_S_IRWXU | FSSH_S_IRWXG | FSSH_S_IRWXO) & ~sUmask); 332 if (fd < FSSH_B_OK) 333 return _ERR(fd); 334 335 int res = _kern_write(fd, offset, buf, size); 336 _kern_close(fd); 337 if (res < FSSH_B_OK) 338 res = _ERR(res); 339 return res; 340 } 341 342 343 static void 344 fuse_destroy(void* priv_data) 345 { 346 _kern_sync(); 347 } 348 349 350 //} // extern "C" { 351 352 353 struct fuse_operations fuse_cmds; 354 355 356 static void 357 initialiseFuseOps(struct fuse_operations* fuse_cmds) 358 { 359 fuse_cmds->getattr = fuse_getattr; 360 fuse_cmds->access = fuse_access; 361 fuse_cmds->readlink = fuse_readlink; 362 fuse_cmds->readdir = fuse_readdir; 363 fuse_cmds->mknod = fuse_mknod; 364 fuse_cmds->mkdir = fuse_mkdir; 365 fuse_cmds->symlink = fuse_symlink; 366 fuse_cmds->unlink = fuse_unlink; 367 fuse_cmds->rmdir = fuse_rmdir; 368 fuse_cmds->rename = fuse_rename; 369 fuse_cmds->link = fuse_link; 370 fuse_cmds->chmod = fuse_chmod; 371 fuse_cmds->chown = fuse_chown; 372 fuse_cmds->truncate = NULL; 373 fuse_cmds->utimens = NULL; 374 fuse_cmds->open = fuse_open; 375 fuse_cmds->read = fuse_read; 376 fuse_cmds->write = fuse_write; 377 fuse_cmds->statfs = NULL; 378 fuse_cmds->release = NULL; 379 fuse_cmds->fsync = NULL; 380 fuse_cmds->destroy = fuse_destroy; 381 } 382 383 384 static int 385 fssh_fuse_session(const char* device, const char* mntPoint, const char* fsName) 386 { 387 fssh_dev_t fsDev = _kern_mount(kMountPoint, device, fsName, 0, NULL, 0); 388 if (fsDev < 0) { 389 fprintf(stderr, "Error: Mounting FS failed: %s\n", 390 fssh_strerror(fsDev)); 391 return 1; 392 } 393 const char* argv[5]; 394 argv[0] = (const char*)"bfs_shell"; 395 argv[1] = mntPoint; 396 argv[2] = (const char*)"-d"; 397 argv[3] = (const char*)"-s"; 398 initialiseFuseOps(&fuse_cmds); 399 return fuse_main(4, (char**)argv, &fuse_cmds, NULL); 400 } 401 402 403 } // namespace FSShell 404 405 406 using namespace FSShell; 407 408 409 static void 410 print_usage_and_exit(const char* binName) 411 { 412 fprintf(stderr,"Usage: %s <device> <mount point>\n", binName); 413 exit(1); 414 } 415 416 417 int 418 main(int argc, const char* const* argv) 419 { 420 if (argc < 2) 421 print_usage_and_exit(argv[0]); 422 423 const char* device = argv[1]; 424 const char* mntPoint = argv[2]; 425 426 if (!modules[0]) { 427 fprintf(stderr, "Error: Couldn't find FS module!\n"); 428 return 1; 429 } 430 431 fssh_status_t error = init_kernel(); 432 if (error != FSSH_B_OK) { 433 fprintf(stderr, "Error: Initializing kernel failed: %s\n", 434 fssh_strerror(error)); 435 return error; 436 } 437 const char* fsName = modules[0]->name; 438 return fssh_fuse_session(device, mntPoint, fsName); 439 } 440 441