Overview
Comment: | Add "getattr" implementation |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | tcl-ops |
Files: | files | file ages | folders |
SHA1: | d64c2e9bf72d38141c79e99db0cb0ee2a56c3220 |
User & Date: | rkeene on 2014-11-07 11:36:59 |
Other Links: | manifest | tags |
Context
2014-11-07
| ||
12:13 | Added basic "open" support check-in: ebbca87b7e user: rkeene tags: tcl-ops | |
11:36 | Add "getattr" implementation check-in: d64c2e9bf7 user: rkeene tags: tcl-ops | |
08:48 | Added basic "getchildren" implementation in Tcl check-in: ee13ee5aa4 user: rkeene tags: tcl-ops | |
Changes
Modified appfsd.c from [16b07e2510] to [70718fd2dc].
39 39 40 40 /* 41 41 * Global variables, needed for all threads but only initialized before any 42 42 * FUSE threads are created 43 43 */ 44 44 const char *appfs_cachedir; 45 45 time_t appfs_boottime; 46 +int appfs_fuse_started = 0; 46 47 47 48 /* 48 49 * AppFS Path Type: Describes the type of path a given file is 49 50 */ 50 51 typedef enum { 51 52 APPFS_PATHTYPE_INVALID, 52 53 APPFS_PATHTYPE_FILE, 53 54 APPFS_PATHTYPE_DIRECTORY, 54 55 APPFS_PATHTYPE_SYMLINK 55 56 } appfs_pathtype_t; 56 57 57 -/* 58 - * AppFS Children Files linked-list 59 - */ 60 -struct appfs_children { 61 - struct appfs_children *_next; 62 - char name[256]; 63 -}; 64 - 65 58 /* 66 59 * AppFS Path Information: 67 60 * Completely describes a specific path, how it should be returned to 68 61 * to the kernel 69 62 */ 70 63 struct appfs_pathinfo { 71 64 appfs_pathtype_t type; ................................................................................ 260 253 /* 261 254 * Determine the UID for the user making the current FUSE filesystem request. 262 255 * This will be used to lookup the user's home directory so we can search for 263 256 * locally modified files. 264 257 */ 265 258 static uid_t appfs_get_fsuid(void) { 266 259 struct fuse_context *ctx; 260 + 261 + if (!appfs_fuse_started) { 262 + return(getuid()); 263 + } 267 264 268 265 ctx = fuse_get_context(); 269 266 if (ctx == NULL) { 270 267 /* Unable to lookup user for some reason */ 271 268 /* Return an unprivileged user ID */ 272 269 return(1); 273 270 } ................................................................................ 373 370 retval += 10; 374 371 retval %= 4294967296ULL; 375 372 376 373 return(retval); 377 374 } 378 375 379 376 /* Get information about a path, and optionally list children */ 380 -static int appfs_get_path_info(const char *_path, struct appfs_pathinfo *pathinfo, struct appfs_children **children) { 377 +static int appfs_get_path_info(const char *path, struct appfs_pathinfo *pathinfo) { 378 + Tcl_Interp *interp; 379 + Tcl_Obj *attrs_dict, *attr_value; 380 + const char *attr_value_str; 381 + Tcl_WideInt attr_value_wide; 382 + int attr_value_int; 383 + static __thread Tcl_Obj *attr_key_type = NULL, *attr_key_perms = NULL, *attr_key_size = NULL, *attr_key_time = NULL, *attr_key_source = NULL, *attr_key_childcount = NULL; 384 + int tcl_ret; 385 + 386 + interp = appfs_TclInterp(); 387 + if (interp == NULL) { 388 + return(1); 389 + } 390 + 391 + tcl_ret = appfs_Tcl_Eval(interp, 2, "::appfs::getattr", path); 392 + if (tcl_ret != TCL_OK) { 393 + APPFS_DEBUG("::appfs::getattr(%s) failed.", path); 394 + APPFS_DEBUG("Tcl Error is: %s", Tcl_GetStringResult(interp)); 395 + 396 + return(1); 397 + } 398 + 399 + if (attr_key_type == NULL) { 400 + attr_key_type = Tcl_NewStringObj("type", -1); 401 + attr_key_perms = Tcl_NewStringObj("perms", -1); 402 + attr_key_size = Tcl_NewStringObj("size", -1); 403 + attr_key_time = Tcl_NewStringObj("time", -1); 404 + attr_key_source = Tcl_NewStringObj("source", -1); 405 + attr_key_childcount = Tcl_NewStringObj("childcount", -1); 406 + } 407 + 408 + attrs_dict = Tcl_GetObjResult(interp); 409 + tcl_ret = Tcl_DictObjGet(interp, attrs_dict, attr_key_type, &attr_value); 410 + if (tcl_ret != TCL_OK) { 411 + APPFS_DEBUG("[dict get \"type\"] failed"); 412 + APPFS_DEBUG("Tcl Error is: %s", Tcl_GetStringResult(interp)); 413 + 414 + return(1); 415 + } 416 + 417 + if (attr_value == NULL) { 418 + return(1); 419 + } 420 + 421 + pathinfo->packaged = 0; 422 + 423 + attr_value_str = Tcl_GetString(attr_value); 424 + switch (attr_value_str[0]) { 425 + case 'd': /* directory */ 426 + pathinfo->type = APPFS_PATHTYPE_DIRECTORY; 427 + pathinfo->typeinfo.dir.childcount = 0; 428 + 429 + Tcl_DictObjGet(interp, attrs_dict, attr_key_childcount, &attr_value); 430 + if (attr_value != NULL) { 431 + tcl_ret = Tcl_GetWideIntFromObj(NULL, attr_value, &attr_value_wide); 432 + if (tcl_ret == TCL_OK) { 433 + pathinfo->typeinfo.dir.childcount = attr_value_wide; 434 + } 435 + } 436 + 437 + break; 438 + case 'f': /* file */ 439 + pathinfo->type = APPFS_PATHTYPE_FILE; 440 + pathinfo->typeinfo.file.size = 0; 441 + pathinfo->typeinfo.file.executable = 0; 442 + 443 + Tcl_DictObjGet(interp, attrs_dict, attr_key_size, &attr_value); 444 + if (attr_value != NULL) { 445 + tcl_ret = Tcl_GetWideIntFromObj(NULL, attr_value, &attr_value_wide); 446 + if (tcl_ret == TCL_OK) { 447 + pathinfo->typeinfo.file.size = attr_value_wide; 448 + } 449 + } 450 + 451 + Tcl_DictObjGet(interp, attrs_dict, attr_key_perms, &attr_value); 452 + if (attr_value != NULL) { 453 + attr_value_str = Tcl_GetString(attr_value); 454 + if (attr_value_str[0] == 'x') { 455 + pathinfo->typeinfo.file.executable = 1; 456 + } 457 + } 458 + break; 459 + case 's': /* symlink */ 460 + pathinfo->type = APPFS_PATHTYPE_SYMLINK; 461 + pathinfo->typeinfo.symlink.size = 0; 462 + pathinfo->typeinfo.symlink.source[0] = '\0'; 463 + 464 + Tcl_DictObjGet(interp, attrs_dict, attr_key_source, &attr_value); 465 + if (attr_value != NULL) { 466 + attr_value_str = Tcl_GetStringFromObj(attr_value, &attr_value_int); 467 + 468 + if ((attr_value_int + 1) <= sizeof(pathinfo->typeinfo.symlink.source)) { 469 + pathinfo->typeinfo.symlink.size = attr_value_int; 470 + pathinfo->typeinfo.symlink.source[attr_value_int] = '\0'; 471 + 472 + memcpy(pathinfo->typeinfo.symlink.source, attr_value_str, attr_value_int); 473 + } 474 + } 475 + break; 476 + default: 477 + return(1); 478 + } 479 + 480 + Tcl_DictObjGet(interp, attrs_dict, attr_key_time, &attr_value); 481 + if (attr_value != NULL) { 482 + tcl_ret = Tcl_GetWideIntFromObj(NULL, attr_value, &attr_value_wide); 483 + if (tcl_ret == TCL_OK) { 484 + pathinfo->time = attr_value_wide; 485 + } 486 + } else { 487 + pathinfo->time = 0; 488 + } 489 + 490 + return(0); 381 491 } 382 492 383 493 static int appfs_fuse_readlink(const char *path, char *buf, size_t size) { 384 494 struct appfs_pathinfo pathinfo; 385 - int res = 0; 495 + int retval = 0; 386 496 387 497 APPFS_DEBUG("Enter (path = %s, ...)", path); 388 498 389 499 pathinfo.type = APPFS_PATHTYPE_INVALID; 390 500 391 - res = appfs_get_path_info(path, &pathinfo, NULL); 392 - if (res != 0) { 393 - return(res); 501 + retval = appfs_get_path_info(path, &pathinfo); 502 + if (retval != 0) { 503 + return(retval); 394 504 } 395 505 396 506 if (pathinfo.type != APPFS_PATHTYPE_SYMLINK) { 397 507 return(-EINVAL); 398 508 } 399 509 400 510 if ((strlen(pathinfo.typeinfo.symlink.source) + 1) > size) { ................................................................................ 404 514 memcpy(buf, pathinfo.typeinfo.symlink.source, strlen(pathinfo.typeinfo.symlink.source) + 1); 405 515 406 516 return(0); 407 517 } 408 518 409 519 static int appfs_fuse_getattr(const char *path, struct stat *stbuf) { 410 520 struct appfs_pathinfo pathinfo; 411 - int res = 0; 521 + int retval; 522 + 523 + retval = 0; 412 524 413 525 APPFS_DEBUG("Enter (path = %s, ...)", path); 414 526 415 - pathinfo.type = APPFS_PATHTYPE_DIRECTORY; 416 - pathinfo.typeinfo.dir.childcount = 0; 527 + pathinfo.type = APPFS_PATHTYPE_INVALID; 528 + 529 + retval = appfs_get_path_info(path, &pathinfo); 530 + if (retval != 0) { 531 + return(retval); 532 + } 417 533 418 534 memset(stbuf, 0, sizeof(struct stat)); 419 535 420 536 stbuf->st_mtime = pathinfo.time; 421 537 stbuf->st_ctime = pathinfo.time; 422 538 stbuf->st_atime = pathinfo.time; 423 539 stbuf->st_ino = pathinfo.inode; ................................................................................ 440 556 break; 441 557 case APPFS_PATHTYPE_SYMLINK: 442 558 stbuf->st_mode = S_IFLNK | 0555; 443 559 stbuf->st_nlink = 1; 444 560 stbuf->st_size = pathinfo.typeinfo.symlink.size; 445 561 break; 446 562 case APPFS_PATHTYPE_INVALID: 447 - res = -EIO; 563 + retval = -EIO; 448 564 449 565 break; 450 566 } 451 567 452 568 if (pathinfo.packaged) { 453 569 if (0) { 454 570 stbuf->st_mode |= 0222; 455 571 } 456 572 } 457 573 458 - return res; 574 + return(retval); 459 575 } 460 576 461 577 static int appfs_fuse_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *fi) { 462 578 Tcl_Interp *interp; 463 579 Tcl_Obj **children; 464 580 int children_count, idx; 465 581 int tcl_ret; ................................................................................ 470 586 interp = appfs_TclInterp(); 471 587 if (interp == NULL) { 472 588 return(0); 473 589 } 474 590 475 591 filler(buf, ".", NULL, 0); 476 592 filler(buf, "..", NULL, 0); 477 - 478 593 479 594 tcl_ret = appfs_Tcl_Eval(interp, 2, "::appfs::getchildren", path); 480 595 if (tcl_ret != TCL_OK) { 481 596 APPFS_DEBUG("::appfs::getchildren(%s) failed.", path); 482 597 APPFS_DEBUG("Tcl Error is: %s", Tcl_GetStringResult(interp)); 483 598 484 599 return(0); ................................................................................ 763 878 fuse_opt_add_arg(&args, "-oallow_other"); 764 879 } 765 880 766 881 /* 767 882 * Enter the FUSE main loop -- this will process any arguments 768 883 * and start servicing requests. 769 884 */ 885 + appfs_fuse_started = 1; 770 886 return(fuse_main(args.argc, args.argv, &appfs_operations, NULL)); 771 887 } 772 888
Modified appfsd.tcl from [88b17c4a86] to [c564230658].
1 1 #! /usr/bin/env tclsh 2 2 3 3 package require http 2.7 4 4 package require sqlite3 5 5 package require sha1 6 +package require appfsd 6 7 7 8 namespace eval ::appfs { 8 9 variable cachedir "/tmp/appfs-cache" 9 10 variable ttl 3600 10 11 variable nttl 60 11 12 12 13 # User-replacable function to convert a hostname/hash/method to an URL ................................................................................ 335 336 db eval {INSERT INTO files (package_sha1, type, time, source, size, perms, file_sha1, file_name, file_directory) VALUES ($package_sha1, $fileInfo(type), $fileInfo(time), $fileInfo(source), $fileInfo(size), $fileInfo(perms), $fileInfo(sha1), $fileInfo(name), $fileInfo(directory) );} 336 337 db eval {UPDATE packages SET haveManifest = 1 WHERE sha1 = $package_sha1;} 337 338 } 338 339 } 339 340 340 341 return COMPLETE 341 342 } 343 + 344 + proc _localpath {package hostname file} { 345 + set homedir [::appfsd::get_homedir] 346 + set dir [file join $homedir .appfs "./${package}@${hostname}" "./${file}"] 347 + } 342 348 343 349 proc _parsepath {path} { 344 350 set path [string trim $path "/"] 345 351 set path [split $path "/"] 346 352 set pathlen [llength $path] 347 353 348 - array set retval [list _children sites] 354 + array set retval [list _children sites _type toplevel] 349 355 350 356 if {$pathlen > 0} { 351 357 set retval(hostname) [lindex $path 0] 352 358 set retval(_children) packages 359 + set retval(_type) sites 353 360 354 361 if {$pathlen > 1} { 355 362 set package [lindex $path 1] 356 363 if {[string length $package] == "40" && [regexp {^[a-fA-F0-9]*$} $package]} { 357 364 set retval(package_sha1) $package 358 365 set retval(_children) files 366 + set retval(_type) files 367 + 368 + ::appfs::db eval {SELECT package, os, cpuArch, version FROM packages WHERE sha1 = $retval(package_sha1);} pkginfo {} 369 + set retval(package) $pkginfo(package) 370 + set retval(os) $pkginfo(os) 371 + set retval(cpu) $pkginfo(cpuArch) 372 + set retval(version) $pkginfo(version) 359 373 360 374 if {$pathlen > 2} { 361 375 set retval(file) [join [lrange $path 2 end] "/"] 362 376 } else { 363 377 set retval(file) "" 364 378 } 365 - 366 - return [array get retval] 367 379 } else { 368 380 set retval(package) $package 369 381 set retval(_children) os-cpu 370 - } 371 - 372 - if {$pathlen > 2} { 373 - set os_cpu [lindex $path 2] 374 - set os_cpu [split $os_cpu "-"] 375 - 376 - set retval(os) [lindex $os_cpu 0] 377 - set retval(cpu) [lindex $os_cpu 1] 378 - set retval(_children) versions 379 - 380 - if {$pathlen > 3} { 381 - set retval(version) [lindex $path 3] 382 - set retval(_children) files 383 - 384 - set retval(package_sha1) [::appfs::db onecolumn {SELECT sha1 FROM packages WHERE hostname = $retval(hostname) AND os = $retval(os) AND cpuArch = $retval(cpu) AND version = $retval(version);}] 385 - if {$retval(package_sha1) == ""} { 386 - return [list] 387 - } 388 - 389 - if {$pathlen > 4} { 390 - set retval(file) [join [lrange $path 4 end] "/"] 391 - } else { 392 - set retval(file) "" 382 + set retval(_type) packages 383 + 384 + if {$pathlen > 2} { 385 + set os_cpu [lindex $path 2] 386 + set os_cpu [split $os_cpu "-"] 387 + 388 + set retval(os) [lindex $os_cpu 0] 389 + set retval(cpu) [lindex $os_cpu 1] 390 + set retval(_children) versions 391 + set retval(_type) os-cpu 392 + 393 + if {$pathlen > 3} { 394 + set retval(version) [lindex $path 3] 395 + set retval(_children) files 396 + set retval(_type) versions 397 + 398 + set retval(package_sha1) [::appfs::db onecolumn {SELECT sha1 FROM packages WHERE hostname = $retval(hostname) AND os = $retval(os) AND cpuArch = $retval(cpu) AND version = $retval(version);}] 399 + if {$retval(package_sha1) == ""} { 400 + return [list] 401 + } 402 + 403 + if {$pathlen > 4} { 404 + set retval(_type) files 405 + set retval(file) [join [lrange $path 4 end] "/"] 406 + } else { 407 + set retval(file) "" 408 + } 393 409 } 394 410 } 395 411 } 396 412 } 397 413 } 398 414 399 415 return [array get retval] ................................................................................ 410 426 catch { 411 427 ::appfs::getindex $pathinfo(hostname) 412 428 } 413 429 414 430 return [::appfs::db eval {SELECT DISTINCT package FROM packages WHERE hostname = $pathinfo(hostname);}] 415 431 } 416 432 "os-cpu" { 417 - return [::appfs::db eval {SELECT DISTINCT os || "-" || cpuArch FROM packages WHERE hostname = $pathinfo(hostname) AND package = $pathinfo(package);}] 433 + set retval [::appfs::db eval {SELECT DISTINCT os || "-" || cpuArch FROM packages WHERE hostname = $pathinfo(hostname) AND package = $pathinfo(package);}] 434 + 435 + lappend retval "platform" 436 + 437 + return $retval 418 438 } 419 439 "versions" { 420 - return [::appfs::db eval { 440 + set retval [::appfs::db eval { 421 441 SELECT DISTINCT version FROM packages WHERE hostname = $pathinfo(hostname) AND package = $pathinfo(package) AND os = $pathinfo(os) AND cpuArch = $pathinfo(cpu); 422 442 }] 443 + 444 + lappend retval "latest" 445 + 446 + return $retval 423 447 } 424 448 "files" { 425 449 catch { 426 450 ::appfs::getpkgmanifest $pathinfo(hostname) $pathinfo(package_sha1) 427 451 } 428 452 429 - return [::appfs::db eval {SELECT DISTINCT file_name FROM files WHERE package_sha1 = $pathinfo(package_sha1) AND file_directory = $pathinfo(file);}] 453 + set retval [::appfs::db eval {SELECT DISTINCT file_name FROM files WHERE package_sha1 = $pathinfo(package_sha1) AND file_directory = $pathinfo(file);}] 454 + 455 + if {[info exists pathinfo(package)] && [info exists pathinfo(hostname)] && [info exists pathinfo(file)]} { 456 + set dir [_localpath $pathinfo(package) $pathinfo(hostname) $pathinfo(file)] 457 + foreach file [glob -nocomplain -tails -directory $dir -types {d f l} {{.,}*}] { 458 + if {$file == "." || $file == ".."} { 459 + continue 460 + } 461 + 462 + if {[lsearch -exact $retval $file] != -1} { 463 + continue 464 + } 465 + 466 + lappend retval $file 467 + } 468 + } 469 + 470 + return $retval 430 471 } 431 472 } 432 473 433 474 return -code error "Invalid or unacceptable path: $dir" 434 475 } 435 476 436 477 proc getattr {path} { 478 + array set pathinfo [_parsepath $path] 479 + array set retval [list] 480 + 481 + switch -- $pathinfo(_type) { 482 + "toplevel" - "sites" - "packages" - "os-cpu" - "versions" { 483 + set retval(type) directory 484 + set retval(childcount) 2; 485 + } 486 + "files" { 487 + set localpath [_localpath $pathinfo(package) $pathinfo(hostname) $pathinfo(file)] 488 + if {[file exists $localpath]} { 489 + catch { 490 + file lstat $localpath localpathinfo 491 + set retval(time) $localpathinfo(mtime) 492 + 493 + switch -- $localpathinfo(type) { 494 + "directory" { 495 + set retval(type) "directory" 496 + set retval(childcount) 2 497 + } 498 + "file" { 499 + set retval(type) "file" 500 + set retval(size) $localpathinfo(size) 501 + if {[file executable $localpath]} { 502 + set retval(perms) "x" 503 + } else { 504 + set retval(perms) "" 505 + } 506 + } 507 + "link" { 508 + set retval(type) "symlink" 509 + set retval(source) [file readlink $localpath] 510 + } 511 + } 512 + } err 513 + } else { 514 + set work [split $pathinfo(file) "/"] 515 + set directory [join [lrange $work 0 end-1] "/"] 516 + set file [lindex $work end] 517 + ::appfs::db eval {SELECT type, time, source, size, perms FROM files WHERE package_sha1 = $pathinfo(package_sha1) AND file_directory = $directory AND file_name = $file;} retval {} 518 + unset -nocomplain retval(*) 519 + } 520 + 521 + } 522 + } 523 + 524 + if {![info exists retval(type)]} { 525 + return -code error "No such file or directory" 526 + } 527 + 528 + return [array get retval] 437 529 } 438 530 439 531 proc openpath {path mode} { 440 532 } 441 533 }