ShingledFS 2.0
SMR-AwareFUSE-basedFileSystem
|
00001 00012 #define _XOPEN_SOURCE 500 00013 #include <errno.h> 00014 #include <stdio.h> 00015 #include <stdlib.h> 00016 #include <unistd.h> 00017 #include <string.h> 00018 #include <pthread.h> 00019 #include <dirent.h> 00020 #include <assert.h> 00021 #include <sys/xattr.h> 00022 #include <sys/vfs.h> 00023 00024 #include "shingledfs.h" 00025 #include "emulator.h" 00026 #include "helper.h" 00027 #include "failstop.h" 00028 #include "buffercache.h" 00029 #include "log.h" 00030 00031 #include "inode.h" 00032 #include "band_bitmap.h" 00033 #include "band_log.h" 00034 #include "cleaning_thread.h" 00035 00036 00037 00038 /******************************************************************************* 00039 * FUSE INITIALIZATION AND CLEANUP FUNCTIONS 00040 ******************************************************************************/ 00041 00049 void 00050 *shingledfs_init(struct fuse_conn_info *conn) { 00051 #ifdef GENERATE_LOGS 00052 char filename[50]; 00053 int len; 00054 time_t curtime = time(NULL); 00055 00056 00057 /* Initialize the logging interface */ 00058 len = strftime(filename, 50, "/tmp/smr%Y%m%d%H%M%S_main.log", 00059 localtime(&curtime)); 00060 if (!len) { 00061 fprintf(stderr, "Error generating log file name: %s\n", filename); 00062 assert(0); 00063 } 00064 log_open(filename); 00065 #endif 00066 00067 00068 /* Log the call */ 00069 log(LOG_SFS_CALLS, "shingledfs_init()\n"); 00070 00071 00072 /* Load the Emulated Disk Image and its parameters */ 00073 dod(!edi_init()); 00074 dod((SFSDATA.fd_edi = edi_open(SFSDATA.path_edi)) >= 0); 00075 read_edi_parameters(SFSDATA.fd_edi, &SFSDATA.edi_blksize, 00076 &SFSDATA.edi_bandcount, &SFSDATA.edi_bandsize); 00077 00078 00079 /* Initialize the Buffer Cache */ 00080 bc_init(1 << 30); 00081 00082 00083 /* Initialize the internal data structures and files */ 00084 dod(!init_band_bitmap()); 00085 dod(!init_inodebitmap()); 00086 dod(!init_inodelist()); 00087 log(LOG_SFS_INFO, "Initialized ShingledFS on-disk data structures!\n"); 00088 00089 00090 /* Return the ShingledFS data structure for later use */ 00091 log(LOG_SFS_RETURN, "ShingledFS initialized!\n"); 00092 return &shingledfs_data; 00093 } 00094 00095 00096 00097 /******************************************************************************* 00098 * DIRECTORY MANAGEMENT FUNCTIONS 00099 ******************************************************************************/ 00100 00113 int 00114 shingledfs_mkdir(const char *path, 00115 mode_t mode) { 00116 char path_unshingled[PATH_MAX]; 00117 00118 00119 /* Log the call */ 00120 log(LOG_SFS_CALLS, "shingledfs_mkdir(path=%s, mode=0%3o)\n", path, mode); 00121 00122 /* Translate the path to the Unshingled partition */ 00123 translate_path(path, SFSDATA.path_unshingled, path_unshingled); 00124 00125 /* Create the directory on the unshingled partition */ 00126 dod(!mkdir(path_unshingled, mode | S_IFDIR)); 00127 00128 00129 log(LOG_SFS_RETURN, "Created %s\n", path_unshingled); 00130 return 0; 00131 } 00132 00133 00141 int 00142 shingledfs_rmdir(const char *path) { 00143 char path_unshingled[PATH_MAX]; 00144 00145 00146 /* Log the call */ 00147 log(LOG_SFS_CALLS, "shingledfs_rmdir(path=%s)\n", path); 00148 00149 /* Translate the path to the Unshingled partition */ 00150 translate_path(path, SFSDATA.path_unshingled, path_unshingled); 00151 00152 /* Create the directory on the unshingled partition */ 00153 dod(!rmdir(path_unshingled)); 00154 00155 00156 log(LOG_SFS_RETURN, "Removed %s\n", path_unshingled); 00157 return 0; 00158 } 00159 00160 00169 int 00170 shingledfs_opendir(const char *path, 00171 struct fuse_file_info *fi) { 00172 char path_unshingled[PATH_MAX]; 00173 DIR *dp; 00174 00175 00176 /* Log the call */ 00177 log(LOG_SFS_CALLS, "shingledfs_opendir(path=%s)\n", path); 00178 00179 /* Translate the path to the Unshingled partition */ 00180 translate_path(path, SFSDATA.path_unshingled, path_unshingled); 00181 00182 00183 /* Open the directory */ 00184 dod((dp = opendir(path_unshingled)) != NULL); 00185 00186 /* Store the directory pointer in the FUSE info structure for future use */ 00187 fi->fh = (intptr_t) dp; 00188 00189 00190 log(LOG_SFS_RETURN, "Opened directory %s (ptr %p)\n", path_unshingled, dp); 00191 return 0; 00192 } 00193 00194 00195 00209 int 00210 shingledfs_readdir(const char *path, 00211 void *buf, 00212 fuse_fill_dir_t filler, 00213 off_t offset, 00214 struct fuse_file_info *fi) { 00215 DIR *dp; 00216 struct dirent *de; 00217 int ent_ret, ent_total; 00218 00219 00220 /* Log the call */ 00221 log(LOG_SFS_CALLS, "shingledfs_readdir(path=%s, buf=%p, offset=%ld)\n", 00222 path, buf, offset); 00223 00224 00225 /* Grab the file handle for the directory from the FUSE info structure */ 00226 dp = (DIR *) (uintptr_t) fi->fh; 00227 00228 /* Read directory entries until possible */ 00229 ent_ret = ent_total = 0; 00230 while ((de = readdir(dp)) != NULL) { 00231 /* Increment the total entries counter */ 00232 ent_total++; 00233 00234 /* Filter out ShingledFS internal files */ 00235 if (strncmp(de->d_name, FILE_PREFIX, strlen(FILE_PREFIX))) { 00236 /* Add the entry to the buffer */ 00237 if (filler(buf, de->d_name, NULL, 0) != 0) { 00238 log(LOG_SFS_ERRORS, "filler(): Buffer overflow!\n"); 00239 return -EOVERFLOW; 00240 } 00241 00242 /* Increment the returned entries counter */ 00243 ent_ret++; 00244 } 00245 } 00246 00247 00248 log(LOG_SFS_RETURN, "Returned %d of %d entries\n", ent_ret, ent_total); 00249 return 0; 00250 } 00251 00252 00253 00262 int 00263 shingledfs_releasedir(const char *path, 00264 struct fuse_file_info *fi) { 00265 DIR *dp; 00266 00267 00268 /* Log the call */ 00269 log(LOG_SFS_CALLS, "shingledfs_releasedir(path=%s)\n", path); 00270 00271 #ifdef GENERATE_LOGS 00272 /* Translate the path to the Unshingled partition */ 00273 char path_unshingled[PATH_MAX]; 00274 translate_path(path, SFSDATA.path_unshingled, path_unshingled); 00275 #endif 00276 00277 00278 /* Grab the file handle for the directory from the FUSE info structure */ 00279 dp = (DIR *) (uintptr_t) fi->fh; 00280 00281 /* Close the open directory */ 00282 if (closedir(dp)) { 00283 log(LOG_SFS_ERRORS, "closedir(%s): %s\n", 00284 path_unshingled, strerror(errno)); 00285 return -errno; 00286 } 00287 00288 00289 log(LOG_SFS_RETURN, "Closed directory %s (ptr %p)\n", path_unshingled, dp); 00290 return 0; 00291 } 00292 00293 00294 00295 /******************************************************************************* 00296 * FILE MANAGEMENT FUNCTIONS 00297 ******************************************************************************/ 00298 00316 int 00317 shingledfs_mknod(const char *path, 00318 mode_t mode, 00319 dev_t dev) { 00320 char path_unshingled[PATH_MAX]; 00321 char path_xattr[PATH_MAX]; 00322 struct stat statbuf; 00323 mode_t xattr_mode = S_IFREG|S_IWUSR|S_IRUSR|S_IWGRP|S_IRGRP|S_IWOTH|S_IROTH; 00324 inode_t inode; 00325 00326 00327 /* Log the call */ 00328 log(LOG_SFS_CALLS, "shingledfs_mknod(path=%s, mode=0%3o)\n", path, mode); 00329 00330 /* Translate the path to the Unshingled partition */ 00331 translate_path(path, SFSDATA.path_unshingled, path_unshingled); 00332 00333 /* Generate the name of the Attribute Replication file */ 00334 xattr_path(path_unshingled, path_xattr); 00335 00336 00337 /* Create the file */ 00338 dod(!mknod(path_unshingled, mode, dev)); 00339 00340 /* Read the attributes of the newly created file */ 00341 dod(!stat(path_unshingled, &statbuf)); 00342 00343 00344 /* Create the Attribute Replication file */ 00345 dod(!mknod(path_xattr, xattr_mode, dev)); 00346 00347 00348 /* Initialize the inode structure and allocate one for the new file */ 00349 memset(&inode, 0, sizeof(inode_t)); 00350 dod(inode.inode_num = get_freeinodenum()); 00351 00352 00353 /* Setup extended attributes for the first time. */ 00354 dod(!lsetxattr(path_xattr, X_STATS, &statbuf, sizeof(struct stat), 0)); 00355 xattr_set(path_unshingled, X_INODE, &inode.inode_num, 00356 sizeof(inode.inode_num), 0); 00357 00358 00359 /* Add the inode to the inode file */ 00360 dod(!put_inode(inode.inode_num, &inode)); 00361 00362 00363 log(LOG_SFS_RETURN, "Created %s (inode %d), %s and replicated attributes\n", 00364 path_unshingled, inode.inode_num, path_xattr); 00365 return 0; 00366 } 00367 00368 00369 00382 int 00383 shingledfs_open(const char *path, 00384 struct fuse_file_info *fi) { 00385 char path_unshingled[PATH_MAX]; 00386 bc_file_t *bc_file; 00387 00388 00389 /* Log the call */ 00390 log(LOG_SFS_CALLS, "shingledfs_open(path=%s)\n", path); 00391 00392 /* Translate the path to the Unshingled partition */ 00393 translate_path(path, SFSDATA.path_unshingled, path_unshingled); 00394 00395 /* Pass the task of opening the file to the buffer cache */ 00396 bc_file = bc_open(path_unshingled); 00397 00398 /* Save a reference to the BC File record for later use */ 00399 fi->fh = (uint64_t)bc_file; 00400 00401 00402 log(LOG_SFS_RETURN, "Opened %s (fd = %d)\n", path_unshingled, bc_file->fd); 00403 return 0; 00404 } 00405 00406 00407 00419 int 00420 shingledfs_read(const char *path, 00421 char *buf, 00422 size_t size, 00423 off_t offset, 00424 struct fuse_file_info *fi) { 00425 bc_file_t *bc_file; 00426 int bytes_read; 00427 00428 00429 /* Log the call */ 00430 log(LOG_SFS_CALLS, "shingledfs_read(path=%s, buf=%p, size=%ld, offset=%ld)" 00431 "\n", path, buf, size, offset); 00432 00433 00434 /* Read data from the file */ 00435 bc_file = (bc_file_t *)(fi->fh); 00436 if ((bytes_read = pread(bc_file->fd, buf, size, offset)) < 0) { 00437 log(LOG_SFS_RETURN | LOG_SFS_ERRORS, "pread(): %s\n", strerror(errno)); 00438 return -errno; 00439 } 00440 00441 00442 log(LOG_SFS_RETURN, "Read %d bytes\n", bytes_read); 00443 return bytes_read; 00444 } 00445 00446 00447 00463 int 00464 shingledfs_write(const char *path, 00465 const char *buf, 00466 size_t size, 00467 off_t offset, 00468 struct fuse_file_info *fi) { 00469 bc_file_t *bc_file; 00470 ssize_t bytes_written; 00471 00472 00473 /* Log the call */ 00474 log(LOG_SFS_CALLS, "shingledfs_write(path=%s, buf=%p, size=%ld, offset=%ld)" 00475 "\n", path, buf, size, offset); 00476 00477 00478 /* Retrieve the BC File record for the file */ 00479 bc_file = (bc_file_t *)(fi->fh); 00480 00481 00482 /* Write data to the file */ 00483 while ((bytes_written = pwrite(bc_file->fd, buf, size, offset)) < 0) { 00484 /* Check if the error is because the buffer cache is out of space */ 00485 if (errno != ENOSPC) { 00486 log(LOG_SFS_RETURN | LOG_SFS_ERRORS, "pwrite(): %s\n", 00487 strerror(errno)); 00488 return -errno; 00489 } 00490 00491 /* Clean the buffer cache */ 00492 bc_clean(); 00493 } 00494 00495 /* Update the file stats */ 00496 dod(!pthread_mutex_lock(&(bc_file->mutex))); 00497 bc_file->dirty = 1; 00498 dod(!pthread_mutex_unlock(&(bc_file->mutex))); 00499 00500 00501 log(LOG_SFS_RETURN, "Wrote %d bytes to fd %d\n", bytes_written, bc_file->fd); 00502 return bytes_written; 00503 } 00504 00505 00506 00518 int 00519 shingledfs_flush(const char *path, 00520 struct fuse_file_info *fi) { 00521 /* Log the call */ 00522 log(LOG_SFS_CALLS, "shingledfs_flush(path=%s)\n", path); 00523 00524 00525 log(LOG_SFS_RETURN, "\n", path); 00526 return 0; 00527 } 00528 00529 00530 00539 int 00540 shingledfs_release(const char *path, 00541 struct fuse_file_info *fi) { 00542 char path_unshingled[PATH_MAX]; 00543 00544 00545 /* Log the call */ 00546 log(LOG_SFS_CALLS, "shingledfs_release(path=%s)\n", path); 00547 00548 /* Translate the path to the Unshingled partition */ 00549 translate_path(path, SFSDATA.path_unshingled, path_unshingled); 00550 00551 00552 /* Close the file in the buffer cache */ 00553 bc_close((bc_file_t *)(fi->fh)); 00554 00555 00556 log(LOG_SFS_RETURN, "Successfully closed %s\n", path); 00557 return 0; 00558 } 00559 00560 00561 00570 int 00571 shingledfs_rename(const char *path, 00572 const char *path_new) { 00573 char path_unshingled[PATH_MAX], path_new_unshingled[PATH_MAX]; 00574 char path_xattr[PATH_MAX], path_new_xattr[PATH_MAX]; 00575 char path_bc[PATH_MAX]; 00576 struct stat statbuf; 00577 00578 00579 /* Log the call */ 00580 log(LOG_SFS_CALLS, "shingledfs_rename(path=%s, path_new=%s)\n", 00581 path, path_new); 00582 00583 /* Translate the paths */ 00584 translate_path(path, SFSDATA.path_unshingled, path_unshingled); 00585 translate_path(path_new, SFSDATA.path_unshingled, path_new_unshingled); 00586 xattr_path(path_unshingled, path_xattr); 00587 xattr_path(path_new_unshingled, path_new_xattr); 00588 00589 00590 /* Read the attributes of the file */ 00591 dod(!lstat(path_unshingled, &statbuf)); 00592 00593 /* Check if the path is to a symlink pointing to the tmpFS file. */ 00594 if (S_ISLNK(statbuf.st_mode)) { 00595 /* Rename the tmpFS copy of the file */ 00596 if (bc_rename(path_unshingled, path_new_unshingled)) 00597 log(LOG_SFS_INFO, "%s was not found in the buffer cache!\n", 00598 path_unshingled); 00599 00600 /* Generate the tmpFS file path */ 00601 bc_generate_tmpFS_path(path_bc, path_new_unshingled); 00602 00603 /* Recreate the symbolic link with the new name */ 00604 while (symlink(path_bc, path_new_unshingled)) { 00605 /* Check if the path already exists. */ 00606 if (errno != EEXIST) { 00607 log(LOG_SFS_ERRORS, "Error creating symbolic link from %s to %s" 00608 ": %s\n", path_new_unshingled, path_bc, 00609 strerror(errno)); 00610 dod(0); 00611 } 00612 00613 /* If the path already exists, then delete it and create the symlink 00614 * because rename() atomically replaces the target. We need the same 00615 * behavior. */ 00616 dod(!unlink(path_new_unshingled)); 00617 } 00618 00619 /* Delete the old symlink */ 00620 dod(!unlink(path_unshingled)); 00621 00622 } else { 00623 /* Rename the file */ 00624 dod(!rename(path_unshingled, path_new_unshingled)); 00625 } 00626 00627 00628 /* Rename the Attribute Replication file */ 00629 dod(!rename(path_xattr, path_new_xattr)); 00630 00631 00632 log(LOG_SFS_RETURN, "File rename successful!\n"); 00633 return 0; 00634 } 00635 00636 00637 00647 int 00648 shingledfs_unlink(const char *path) { 00649 char path_unshingled[PATH_MAX], path_xattr[PATH_MAX]; 00650 struct stat statbuf; 00651 inode_t inode; 00652 int inodeno; 00653 00654 00655 /* Log the call */ 00656 log(LOG_SFS_CALLS, "shingledfs_unlink(path=%s)\n", path); 00657 00658 /* Translate the paths */ 00659 translate_path(path, SFSDATA.path_unshingled, path_unshingled); 00660 xattr_path(path_unshingled, path_xattr); 00661 00662 00663 /* Read the attributes of the file */ 00664 dod(!lstat(path_unshingled, &statbuf)); 00665 00666 00667 /* Check if the path is to a symlink pointing to the tmpFS file. */ 00668 if (S_ISLNK(statbuf.st_mode)) { 00669 if (!bc_unlink(path_unshingled)) { 00670 /* bc_unlink() fails when the file is not present in tmpFS. This can 00671 * happen when the file being deleted is an external symlink (one 00672 * created by the user) pointing to an open file; in essence to a 00673 * ShingledFS internal-symlink pointing to a file on tmpFS. */ 00674 log(LOG_SFS_INFO, "Unlinked %s in tmpFS!\n", path_unshingled); 00675 00676 /* Read the inode information for the file */ 00677 dod(!xattr_get(path_unshingled, X_INODE, &inodeno, sizeof(int))); 00678 dod(!get_inode(inodeno, &inode)); 00679 00680 /* Unlink the inode */ 00681 inode_unlink(inode); 00682 } 00683 } 00684 00685 /* Delete the file */ 00686 dod(!unlink(path_unshingled)); 00687 log(LOG_SFS_INFO, "Deleted %s\n", path_unshingled); 00688 00689 /* Delete the Attribute Replication file. If the operation fails, ensure 00690 * that it is NOT ENOENT. This can be the case when deleting symlinks. */ 00691 if (unlink(path_xattr)) { 00692 if (errno != ENOENT) { 00693 log(LOG_SFS_ERRORS, "unlink(%s): %s\n", 00694 path_xattr, strerror(errno)); 00695 dod(0); 00696 } 00697 } else { 00698 log(LOG_SFS_INFO, "Deleted %s\n", path_xattr); 00699 } 00700 00701 00702 log(LOG_SFS_RETURN, "File deletion successful!\n"); 00703 return 0; 00704 } 00705 00706 00707 00721 int 00722 shingledfs_truncate(const char *path, 00723 off_t offset) { 00724 char path_unshingled[PATH_MAX]; 00725 struct stat statbuf; 00726 int inode_no; 00727 inode_t inode; 00728 00729 00730 /* Log the call */ 00731 log(LOG_SFS_CALLS, "shingledfs_truncate(path=%s, offset=%ld)\n", 00732 path, offset); 00733 00734 /* Translate the path to the Unshingled partition */ 00735 translate_path(path, SFSDATA.path_unshingled, path_unshingled); 00736 00737 00738 /* Read the attributes of the file */ 00739 dod(!lstat(path_unshingled, &statbuf)); 00740 00741 00742 /* Check if the path is to a regular file. */ 00743 if (S_ISREG(statbuf.st_mode)) { 00744 /* Update the size in the Attribute Replication file to the specified 00745 * offset */ 00746 dod(!xattr_get(path_unshingled, X_STATS, &statbuf, 00747 sizeof(struct stat))); 00748 statbuf.st_size = offset; 00749 xattr_set(path_unshingled, X_STATS, &statbuf, sizeof(struct stat), 0); 00750 00751 } else if (S_ISLNK(statbuf.st_mode)) { 00752 /* Truncate the file to the specified size */ 00753 dod(!truncate(path_unshingled, offset)); 00754 } 00755 00756 00757 /* Update the file's inode */ 00758 dod(!xattr_get(path_unshingled, X_INODE, &inode_no, sizeof(int))); 00759 dod(!get_inode(inode_no, &inode)); 00760 inode.size = (offset + SFSDATA.edi_blksize - 1) / SFSDATA.edi_blksize; 00761 dod(!put_inode(inode_no, &inode)); 00762 00763 00764 return 0; 00765 } 00766 00767 00768 00770 // * @brief Truncates the file at the specified offset 00771 // * 00772 // * This function relies on the file descriptor of an open file, passed in the 00773 // * fuse_file_info structure. 00774 // * 00775 // * @param path Path to the file whose attributes are to be retrived 00776 // * @param offset Offset into the file to truncate at 00777 // * @param file_info fuse_file_info structure from the call to open() or create() 00778 // * 00779 // * @return 0 on success; -errno on failure 00780 // */ 00781 //int shingledfs_ftruncate(const char *path, off_t offset, 00782 // struct fuse_file_info *fi) { 00783 // char path_unshingled[PATH_MAX]; 00784 // int inode_no, fd_log; 00785 // inode_t inode; 00786 // 00787 // 00788 // /* Log the call */ 00789 // log(LOG_SFS_CALLS, "shingledfs_ftruncate(path=%s, offset=%ld)\n", path, offset); 00790 // 00791 // /* Translate the path to the Unshingled partition */ 00792 // if (translate_path(path, SFSDATA.path_unshingled, path_unshingled)) { 00793 // log("translate_path(%s): %s\n", path, strerror(errno)); 00794 // assert(0); 00795 // return -errno; 00796 // } 00797 // 00798 // 00799 // /* Truncate the file */ 00800 // if (ftruncate(((bc_file_t *)(fi->fh))->fd, offset)) { 00801 // log("ftruncate(%s, %ld): %s\n", path, offset, strerror(errno)); 00802 // assert(0); 00803 // return -errno; 00804 // } 00805 // 00806 // 00807 // /* Update the file's inode */ 00808 // assert(!xattr_get(path_unshingled, X_INODE, &inode_no, sizeof(int))); 00809 // assert(!get_inode(inode_no, &inode)); 00810 // inode.size = (offset + SFSDATA.edi_blksize - 1) / SFSDATA.edi_blksize; 00811 // assert(!put_inode(inode_no, &inode)); 00812 // 00813 // 00814 // /* Write the delete log */ 00815 // assert(offset == 0); 00816 // fd_log = init_deletelog(inode.band_id); 00817 // assert(fd_log); 00818 // append_deletelog(fd_log, inode.band_offset, inode.size, inode.entrynumber); 00819 // close(fd_log); 00820 // log("Delete Log entry: Band %ld, RBA %ld, %d blocks, " 00821 // "Append Log Entry: %d!\n", inode.band_id, inode.band_offset, 00822 // inode.size, inode.entrynumber); 00823 // 00824 // return 0; 00825 //} 00826 00827 00828 00840 int 00841 shingledfs_getattr(const char *path, 00842 struct stat *statbuf) { 00843 char path_unshingled[PATH_MAX], path_target[PATH_MAX]; 00844 int len; 00845 00846 00847 /* Log the call */ 00848 log(LOG_SFS_CALLS, "shingledfs_getattr(path=%s)\n", path); 00849 00850 /* Translate the path to the Unshingled partition */ 00851 translate_path(path, SFSDATA.path_unshingled, path_unshingled); 00852 00853 00854 /* Read the attributes of the file */ 00855 if (lstat(path_unshingled, statbuf)) { 00856 log(LOG_SFS_RETURN | LOG_SFS_ERRORS , "lstat(): %s\n", strerror(errno)); 00857 return -errno; 00858 } 00859 00860 00861 /* Check if the path is to a regular file. */ 00862 if (S_ISREG(statbuf->st_mode)) { 00863 /* Read the stats for the file from the Attribute Replication file */ 00864 dod(!xattr_get(path_unshingled, X_STATS, statbuf, sizeof(struct stat))); 00865 00866 } else if (S_ISLNK(statbuf->st_mode)) { 00867 /* Check if the symlink is a ShingledFS internal symlink i.e. it points 00868 * to a file on tmpFS */ 00869 dod(readlink(path_unshingled, path_target, PATH_MAX) > 0); 00870 00871 /* If the symlink is a ShingledFS internal symlink, then read the stats 00872 * from the tmpFS file */ 00873 len = strlen(SFSDATA.path_tmpfs); 00874 if (!strncmp(path_target, SFSDATA.path_tmpfs, len)) { 00875 dod(!stat(path_unshingled, statbuf)); 00876 } 00877 } 00878 00879 00880 log(LOG_SFS_RETURN, "File stats returned successfully!\n"); 00881 return 0; 00882 } 00883 00884 00885 00901 int 00902 shingledfs_fgetattr(const char *path, 00903 struct stat *statbuf, 00904 struct fuse_file_info *fi) { 00905 /* Log the call */ 00906 log(LOG_SFS_CALLS, "shingledfs_fgetattr(path=%s)\n", path); 00907 00908 /* Read the stats for the file */ 00909 dod(!fstat(((bc_file_t *)(fi->fh))->fd, statbuf)); 00910 00911 00912 log(LOG_SFS_RETURN, "File stats returned successfully!\n"); 00913 return 0; 00914 } 00915 00916 00917 00929 int 00930 shingledfs_setxattr(const char *path, 00931 const char *name, 00932 const char *value, 00933 size_t size, 00934 int flags) { 00935 char path_unshingled[PATH_MAX]; 00936 00937 00938 /* Log the call */ 00939 log(LOG_SFS_CALLS, "shingledfs_setxattr(path=%s, name=%s, value=%p, " 00940 "size=%ld, flags=%d)\n", path, name, value, size, flags); 00941 00942 /* Translate the path to the Unshingled partition */ 00943 translate_path(path, SFSDATA.path_unshingled, path_unshingled); 00944 00945 00946 /* Ensure that there are no naming clashes with ShingledFS internals */ 00947 dod((!strcmp(name, X_INODE)) || (!strcmp(name, X_STATS))); 00948 00949 /* Set the extended attributes on the Attribute Replication file */ 00950 xattr_set(path_unshingled, name, (void *)value, size, flags); 00951 00952 00953 log(LOG_SFS_RETURN, "Set extended attribute %s to %ld-byte value at %p on " 00954 "Attribute Replication file\n", name, size, value); 00955 return 0; 00956 } 00957 00958 00959 00970 int 00971 shingledfs_getxattr(const char *path, 00972 const char *name, 00973 char *value, 00974 size_t size) { 00975 char path_unshingled[PATH_MAX]; 00976 00977 00978 /* Log the call */ 00979 log(LOG_SFS_CALLS, "shingledfs_getxattr(path=%s, name=%s, value=%p, " 00980 "size=%ld)\n", path, name, value, size); 00981 00982 /* Translate the path to the Unshingled partition */ 00983 translate_path(path, SFSDATA.path_unshingled, path_unshingled); 00984 00985 /* Ensure that there are no naming clashes with ShingledFS internals */ 00986 dod((strcmp(name, X_INODE)) && (strcmp(name, X_STATS))); 00987 00988 /* Get the extended attributes */ 00989 if (xattr_get(path_unshingled, name, value, size)) { 00990 log(LOG_SFS_RETURN | LOG_SFS_ERRORS, "xattr_get(): %s\n", 00991 strerror(errno)); 00992 return -errno; 00993 } 00994 00995 00996 log(LOG_SFS_RETURN, "Retrieved a %ld-byte value at %p for extended " 00997 "attribute %s from Attribute Replication file\n", 00998 size, value, name); 00999 return 0; 01000 } 01001 01002 01003 01013 int 01014 shingledfs_listxattr(const char *path, 01015 char *list, 01016 size_t size) { 01017 char path_unshingled[PATH_MAX]; 01018 01019 01020 /* Log the call */ 01021 log(LOG_SFS_CALLS, "shingledfs_listxattr(path=%s, list=%p)\n", path, list); 01022 01023 /* Translate the path to the Unshingled partition */ 01024 translate_path(path, SFSDATA.path_unshingled, path_unshingled); 01025 01026 01027 /* Get the list of extended attributes */ 01028 dod(!llistxattr(path_unshingled, list, size)); 01029 01030 01031 log(LOG_SFS_RETURN, "Listed %ld extended attributes from Attribute " 01032 "Replication file into list at %p\n", size, list); 01033 return 0; 01034 } 01035 01036 01037 01046 int 01047 shingledfs_removexattr(const char *path, 01048 const char *name) { 01049 char path_unshingled[PATH_MAX]; 01050 01051 01052 /* Log the call */ 01053 log(LOG_SFS_CALLS, "shingledfs_removexattr(path=%s, name=%s)\n", 01054 path, name); 01055 01056 /* Translate the path to the Unshingled partition */ 01057 translate_path(path, SFSDATA.path_unshingled, path_unshingled); 01058 01059 01060 /* Remove the extended attribute */ 01061 dod(!lremovexattr(path_unshingled, name)); 01062 01063 01064 log(LOG_SFS_RETURN, "Removed extended attribute %s from Attribute " 01065 "Replication file\n", name); 01066 return 0; 01067 } 01068 01069 01070 01083 int 01084 shingledfs_access(const char *path, 01085 int mask) { 01086 char path_unshingled[PATH_MAX]; 01087 struct stat stats, *statbuf; 01088 01089 01090 /* Log the call */ 01091 log(LOG_SFS_CALLS, "shingledfs_access(path=%s, mask=0%3o)\n", path, mask); 01092 01093 /* Translate the path to the Unshingled partition */ 01094 translate_path(path, SFSDATA.path_unshingled, path_unshingled); 01095 01096 01097 /* Read the attributes of the file */ 01098 statbuf = &stats; 01099 dod(!lstat(path_unshingled, statbuf)); 01100 01101 01102 /* Check if the path is to a regular file. */ 01103 if (S_ISREG(statbuf->st_mode)) { 01104 /* Read the stats for the file from the Attribute Replication file */ 01105 dod(!xattr_get(path_unshingled, X_STATS, statbuf, sizeof(struct stat))); 01106 01107 /* Check if the request is for file existence */ 01108 if (mask == F_OK) 01109 return 0; 01110 01111 /* Check the access credentials */ 01112 if (!((statbuf->st_mode) & (mask << 6))) { 01113 log(LOG_SFS_RETURN | LOG_SFS_ERRORS, "File permissions 0%3o don't " 01114 "permit 0%3o!\n", 01115 statbuf->st_mode, mask); 01116 errno = EPERM; 01117 return -1; 01118 } 01119 01120 } else { 01121 /* Check the access permissions */ 01122 dod(!access(path_unshingled, mask)); 01123 } 01124 01125 01126 log(LOG_SFS_RETURN, "Access permission granted!\n"); 01127 return 0; 01128 } 01129 01130 01131 01142 int 01143 shingledfs_utime(const char *path, 01144 struct utimbuf *tv) { 01145 char path_unshingled[PATH_MAX]; 01146 struct stat stats, *statbuf; 01147 01148 01149 /* Log the call */ 01150 log(LOG_SFS_CALLS, "shingledfs_utime(path=%s)\n", path); 01151 01152 /* Translate the path to the Unshingled partition */ 01153 translate_path(path, SFSDATA.path_unshingled, path_unshingled); 01154 01155 01156 /* Read the attributes of the file */ 01157 statbuf = &stats; 01158 dod(!lstat(path_unshingled, statbuf)); 01159 01160 01161 /* Check if the path is to a regular file. */ 01162 if (S_ISREG(statbuf->st_mode)) { 01163 /* Update the time stamps */ 01164 dod(!xattr_get(path_unshingled, X_STATS, statbuf, sizeof(struct stat))); 01165 statbuf->st_atime = tv->actime; 01166 statbuf->st_mtime = tv->modtime; 01167 xattr_set(path_unshingled, X_STATS, statbuf, sizeof(struct stat), 0); 01168 01169 } else { 01170 /* Set the access and/or modification times of the file */ 01171 dod(!utime(path_unshingled, tv)); 01172 } 01173 01174 01175 log(LOG_SFS_RETURN, "File timestamps updated successfully!\n"); 01176 return 0; 01177 } 01178 01179 01180 01189 int 01190 shingledfs_chmod(const char *path, 01191 mode_t mode) { 01192 char path_unshingled[PATH_MAX]; 01193 struct stat stats, *statbuf; 01194 01195 01196 /* Log the call */ 01197 log(LOG_SFS_CALLS, "shingledfs_chmod(path=%s, mode=0%o)\n", path, mode); 01198 01199 /* Translate the path to the Unshingled partition */ 01200 translate_path(path, SFSDATA.path_unshingled, path_unshingled); 01201 01202 01203 /* Read the attributes of the file */ 01204 statbuf = &stats; 01205 dod(!lstat(path_unshingled, statbuf)); 01206 01207 /* Check if the path is to a regular file. */ 01208 if (S_ISREG(statbuf->st_mode)) { 01209 /* Update the permissions */ 01210 dod(!xattr_get(path_unshingled, X_STATS, statbuf, sizeof(struct stat))); 01211 statbuf->st_mode = mode; 01212 xattr_set(path_unshingled, X_STATS, statbuf, sizeof(struct stat), 0); 01213 01214 } else { 01215 /* Change the permission bits of the file */ 01216 dod(!chmod(path_unshingled, mode)); 01217 } 01218 01219 01220 log(LOG_SFS_RETURN, "File access permissions updated successfully!\n"); 01221 return 0; 01222 } 01223 01224 01225 01237 int 01238 shingledfs_chown(const char *path, 01239 uid_t uid, 01240 gid_t gid) { 01241 char path_unshingled[PATH_MAX]; 01242 struct stat stats, *statbuf; 01243 01244 01245 /* Log the call */ 01246 log(LOG_SFS_CALLS, "shingledfs_chown(path=%s, uid=%d, gid=%d)\n", 01247 path, uid, gid); 01248 01249 /* Translate the path to the Unshingled partition */ 01250 translate_path(path, SFSDATA.path_unshingled, path_unshingled); 01251 01252 01253 /* Read the attributes of the file */ 01254 statbuf = &stats; 01255 dod(!lstat(path_unshingled, statbuf)); 01256 01257 01258 /* Check if the path is to a regular file. */ 01259 if (S_ISREG(statbuf->st_mode)) { 01260 /* Update the file owners */ 01261 dod(!xattr_get(path_unshingled, X_STATS, statbuf, sizeof(struct stat))); 01262 statbuf->st_uid = uid; 01263 statbuf->st_gid = gid; 01264 xattr_set(path_unshingled, X_STATS, statbuf, sizeof(struct stat), 0); 01265 01266 } else { 01267 /* Change the uid of the file */ 01268 dod(!chown(path_unshingled, uid, gid)); 01269 } 01270 01271 01272 log(LOG_SFS_RETURN, "File owner and/or group updated successfully!\n"); 01273 return 0; 01274 } 01275 01276 01277 01286 int 01287 shingledfs_symlink(const char *path, 01288 const char *path_target) { 01289 char path_unshingled[PATH_MAX]; 01290 01291 01292 /* Log the call */ 01293 log(LOG_SFS_CALLS, "shingledfs_symlink(path=%s, path_target=%s)\n", 01294 path, path_target); 01295 01296 /* Translate the link target path to the Unshingled partition */ 01297 translate_path(path_target, SFSDATA.path_unshingled, path_unshingled); 01298 01299 01300 /* Create the symbolic link */ 01301 dod(!symlink(path, path_unshingled)); 01302 01303 01304 log(LOG_SFS_RETURN, "Created symlink from %s to %s\n", path_unshingled, path); 01305 return 0; 01306 } 01307 01308 01309 01319 int 01320 shingledfs_readlink(const char *path, 01321 char *buf, 01322 size_t size) { 01323 char path_unshingled[PATH_MAX]; 01324 int bytes_written; 01325 01326 01327 /* Log the call */ 01328 log(LOG_SFS_CALLS, "shingledfs_readlink(path=%s)\n", path); 01329 01330 /* Translate the path to the Unshingled partition */ 01331 translate_path(path, SFSDATA.path_unshingled, path_unshingled); 01332 01333 01334 /* Read the target of the link */ 01335 dod((bytes_written = readlink(path_unshingled, buf, size)) >= 0); 01336 01337 /* Null-terminate the buffer */ 01338 if (bytes_written == size) 01339 bytes_written--; 01340 buf[bytes_written] = '\0'; 01341 01342 01343 log(LOG_SFS_RETURN, "Symlink %s points to %s\n", path_unshingled, buf); 01344 return 0; 01345 } 01346 01347 01348 01363 int 01364 shingledfs_link(const char *path, 01365 const char *path_target) { 01366 char path_unshingled[PATH_MAX], path_target_unshingled[PATH_MAX]; 01367 struct stat stats, *statbuf; 01368 01369 01370 /* Log the call */ 01371 log(LOG_SFS_CALLS, "shingledfs_link(path=%s, path_target=%s)\n", 01372 path, path_target); 01373 01374 /* Translate the paths */ 01375 translate_path(path, SFSDATA.path_unshingled, path_unshingled); 01376 translate_path(path_target, SFSDATA.path_unshingled, 01377 path_target_unshingled); 01378 01379 01380 /* Create the link */ 01381 dod(!link(path_unshingled, path_target_unshingled)); 01382 01383 01384 /* Read the attributes of the file */ 01385 statbuf = &stats; 01386 dod(lstat(path_unshingled, statbuf)); 01387 01388 /* Check if the path is to a regular file. */ 01389 if (S_ISREG(statbuf->st_mode)) { 01390 /* Read the attributes of the file */ 01391 statbuf = &stats; 01392 /* Update the no. of hard links */ 01393 dod(!xattr_get(path_unshingled, X_STATS, statbuf, sizeof(struct stat))); 01394 statbuf->st_nlink++; 01395 xattr_set(path_unshingled, X_STATS, statbuf, sizeof(struct stat), 0); 01396 } 01397 01398 01399 log(LOG_SFS_RETURN, "Created link from %s to %s\n", 01400 path_unshingled, path_target_unshingled); 01401 return 0; 01402 } 01403 01404 01405 01414 int 01415 shingledfs_statfs(const char *path, 01416 struct statvfs *statv) { 01417 char path_unshingled[PATH_MAX]; 01418 01419 01420 /* Log the call */ 01421 log(LOG_SFS_CALLS, "shingledfs_statfs(path=%s)\n", path); 01422 01423 /* Translate the path to the Unshingled partition */ 01424 translate_path(path, SFSDATA.path_unshingled, path_unshingled); 01425 01426 01427 /* Read the stats for the local file system */ 01428 dod(!statvfs(path_unshingled, statv)); 01429 01430 01431 log(LOG_SFS_RETURN, "bsize: %ld, frsize: %ld, blocks: %ld, bfree: %ld, " 01432 "bavail: %ld, files: %ld, ffree: %ld, favail: %ld, " 01433 "fsid: %ld, namemax: %d\n", 01434 statv->f_bsize, statv->f_frsize, statv->f_blocks, 01435 statv->f_bfree, statv->f_bavail, statv->f_files, 01436 statv->f_ffree, statv->f_favail, statv->f_fsid, 01437 statv->f_namemax); 01438 return 0; 01439 }