ShingledFS 2.0
SMR-AwareFUSE-basedFileSystem

fuseops.c

Go to the documentation of this file.
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 }