Example #1
0
    def __apply_change(self, change_id, change_tuple):
        """Apply changes to our filesystem reported by GD. All we do is remove 
        the current record components, if it's valid, and then reload it with 
        what we were given. Note that since we don't necessarily know
        about the entries that have been changed, this also allows us to slowly
        increase our knowledge of the filesystem (of, obviously, only those 
        things that change).
        """

        (entry_id, was_deleted, entry) = change_tuple

        is_visible = entry.is_visible if entry else None

        _logger.info(
            "Applying change with change-ID (%d), entry-ID [%s], "
            "and is-visible of [%s]", change_id, entry_id, is_visible)

        # First, remove any current knowledge from the system.

        _logger.debug(
            "Removing all trace of entry with ID [%s] "
            "(apply_change).", entry_id)

        PathRelations.get_instance().remove_entry_all(entry_id)

        # If it wasn't deleted, add it back.

        _logger.debug("Registering changed entry with ID [%s].", entry_id)

        if is_visible:
            path_relations = PathRelations.get_instance()
            path_relations.register_entry(entry)
Example #2
0
    def __apply_change(self, change_id, change_tuple):
        """Apply changes to our filesystem reported by GD. All we do is remove 
        the current record components, if it's valid, and then reload it with 
        what we were given. Note that since we don't necessarily know
        about the entries that have been changed, this also allows us to slowly
        increase our knowledge of the filesystem (of, obviously, only those 
        things that change).
        """

        (entry_id, was_deleted, entry) = change_tuple
        
        is_visible = entry.is_visible if entry else None

        _logger.info("Applying change with change-ID (%d), entry-ID [%s], "
                     "and is-visible of [%s]",
                     change_id, entry_id, is_visible)

        # First, remove any current knowledge from the system.

        _logger.debug("Removing all trace of entry with ID [%s] "
                      "(apply_change).", entry_id)

        PathRelations.get_instance().remove_entry_all(entry_id)

        # If it wasn't deleted, add it back.

        _logger.debug("Registering changed entry with ID [%s].", entry_id)

        if is_visible:
            path_relations = PathRelations.get_instance()
            path_relations.register_entry(entry)
Example #3
0
    def rename(self, filepath_old, filepath_new):
        # Make sure the old filepath exists.
        (entry, path, filename_old) = get_entry_or_raise(filepath_old)

        # At this point, decorations, the is-hidden prefix, etc.. haven't been
        # stripped.
        (path, filename_new_raw) = split(filepath_new)

        # Make sure the new filepath doesn't exist.

        try:
            get_entry_or_raise(filepath_new, True)
        except GdNotFoundError:
            pass

        gd = get_gdrive()

        try:
            entry = gd.rename(entry, filename_new_raw)
        except:
            _logger.exception("Could not update entry [%s] for rename.", entry)
            raise FuseOSError(EIO)

        # Update our knowledge of the entry.

        path_relations = PathRelations.get_instance()

        try:
            path_relations.register_entry(entry)
        except:
            _logger.exception("Could not register renamed entry: %s", entry)
            raise FuseOSError(EIO)
def get_by_path(raw_path):
    try:
        result = split_path(raw_path, path_resolver)
        (parent_clause, path, filename, mime_type, is_hidden) = result
    except:
        print("Could not process file-path [%s]." % (raw_path))
        exit()

    filepath = build_filepath(path, filename)

    path_relations = PathRelations.get_instance()

    try:
        entry_clause = path_relations.get_clause_from_path(filepath)
    except GdNotFoundError:
        print("Could not retrieve clause for non-existent file-path [%s]." %
              (filepath))
        exit()
    except:
        print("Could not retrieve clause for path [%s]. " % (filepath))
        exit()

    if not entry_clause:
        print("Path [%s] does not exist for stat()." % (filepath))
        exit()

    return entry_clause[CLAUSE_ENTRY]
Example #5
0
    def rename(self, filepath_old, filepath_new):
        # Make sure the old filepath exists.
        (entry, path, filename_old) = get_entry_or_raise(filepath_old)

        # At this point, decorations, the is-hidden prefix, etc.. haven't been
        # stripped.
        (path, filename_new_raw) = split(filepath_new)

        # Make sure the new filepath doesn't exist.

        try:
            get_entry_or_raise(filepath_new, True)
        except GdNotFoundError:
            pass

        gd = get_gdrive()

        try:
            entry = gd.rename(entry, filename_new_raw)
        except:
            _logger.exception("Could not update entry [%s] for rename.", entry)
            raise FuseOSError(EIO)

        # Update our knowledge of the entry.

        path_relations = PathRelations.get_instance()

        try:
            path_relations.register_entry(entry)
        except:
            _logger.exception("Could not register renamed entry: %s", entry)
            raise FuseOSError(EIO)
Example #6
0
    def __get_entry_or_raise(self, raw_path):
        try:
            result = split_path(raw_path, path_resolver)
            (parent_clause, path, filename, mime_type, is_hidden) = result
        except:
            self.__log.exception("Could not process file-path [%s]." %
                                 (raw_path))
            raise FuseOSError(EIO)

        filepath = build_filepath(path, filename)
        path_relations = PathRelations.get_instance()

        try:
            entry_clause = path_relations.get_clause_from_path(filepath)
        except GdNotFoundError:
            self.__log.exception("Could not retrieve clause for non-existent "
                                 "file-path [%s]." % (filepath))
            raise FuseOSError(ENOENT)
        except:
            self.__log.exception("Could not retrieve clause for path [%s]. " %
                                 (filepath))
            raise FuseOSError(EIO)

        if not entry_clause:
            self.__log.debug("Path [%s] does not exist for stat()." %
                             (filepath))
            raise FuseOSError(ENOENT)

        return (entry_clause[CLAUSE_ENTRY], path, filename)
def get_by_path(raw_path):
    try:
        result = split_path(raw_path, path_resolver)
        (parent_clause, path, filename, mime_type, is_hidden) = result
    except:
        print("Could not process file-path [%s]." % (raw_path))
        exit()

    filepath = build_filepath(path, filename)
    
    path_relations = PathRelations.get_instance()

    try:
        entry_clause = path_relations.get_clause_from_path(filepath)
    except GdNotFoundError:
        print("Could not retrieve clause for non-existent file-path [%s]." % 
              (filepath))
        exit()
    except:
        print("Could not retrieve clause for path [%s]. " % (filepath))
        exit()

    if not entry_clause:
        print("Path [%s] does not exist for stat()." % (filepath))
        exit()

    return entry_clause[CLAUSE_ENTRY]
Example #8
0
    def __create(self, filepath, mode=None):
        """Create a new file.
                
        We don't implement "mode" (permissions) because the model doesn't agree 
        with GD.
        """

# TODO: Fail if it already exists.

        try:
            result = split_path(filepath, path_resolver)
            (parent_clause, path, filename, mime_type, is_hidden) = result
        except GdNotFoundError:
            _logger.exception("Could not process [%s] (i-create).", filepath)
            raise FuseOSError(ENOENT)
        except:
            _logger.exception("Could not split path [%s] (i-create).",
                              filepath)
            raise FuseOSError(EIO)

        distilled_filepath = build_filepath(path, filename)

        # Try to guess at a mime-type, if not otherwise given.
        if mime_type is None:
            (mimetype_guess, _) = guess_type(filename, True)
            
            if mimetype_guess is not None:
                mime_type = mimetype_guess
            else:
                mime_type = Conf.get('default_mimetype')

        gd = get_gdrive()

        try:
            entry = gd.create_file(
                        filename, 
                        [parent_clause[3]], 
                        mime_type,
                        is_hidden=is_hidden)
        except:
            _logger.exception("Could not create empty file [%s] under "
                              "parent with ID [%s].",
                              filename, parent_clause[3])

            raise FuseOSError(EIO)

        path_relations = PathRelations.get_instance()

        try:
            path_relations.register_entry(entry)
        except:
            _logger.exception("Could not register created file in cache.")
            raise FuseOSError(EIO)

        _logger.info("Inner-create of [%s] completed.", distilled_filepath)

        return (entry, path, filename, mime_type)
Example #9
0
    def rmdir(self, filepath):
        """Remove a directory."""

        path_relations = PathRelations.get_instance()

        try:
            entry_clause = path_relations.get_clause_from_path(filepath)
        except GdNotFoundError:
            _logger.exception("Could not process [%s] (rmdir).", filepath)
            raise FuseOSError(ENOENT)
        except:
            _logger.exception("Could not get clause from file-path [%s] "
                              "(rmdir).", filepath)
            raise FuseOSError(EIO)

        if not entry_clause:
            _logger.error("Path [%s] does not exist for rmdir().", filepath)
            raise FuseOSError(ENOENT)

        entry_id = entry_clause[CLAUSE_ID]
        normalized_entry = entry_clause[CLAUSE_ENTRY]

        # Check if not a directory.

        if not normalized_entry.is_directory:
            _logger.error("Can not rmdir() non-directory [%s] with ID [%s].", 
                          filepath, entry_id)

            raise FuseOSError(ENOTDIR)

        # Ensure the folder is empty.

        gd = get_gdrive()

        try:
            found = gd.get_children_under_parent_id(
                        entry_id,
                        max_results=1)
        except:
            _logger.exception("Could not determine if directory to be removed "
                              "has children.", entry_id)

            raise FuseOSError(EIO)

        if found:
            raise FuseOSError(ENOTEMPTY)

        try:
            gd.remove_entry(normalized_entry)
        except (NameError):
            raise FuseOSError(ENOENT)
        except:
            _logger.exception("Could not remove directory [%s] with ID [%s].",
                              filepath, entry_id)

            raise FuseOSError(EIO)
Example #10
0
    def rmdir(self, filepath):
        """Remove a directory."""

        path_relations = PathRelations.get_instance()

        try:
            entry_clause = path_relations.get_clause_from_path(filepath)
        except GdNotFoundError:
            _logger.exception("Could not process [%s] (rmdir).", filepath)
            raise FuseOSError(ENOENT)
        except:
            _logger.exception(
                "Could not get clause from file-path [%s] "
                "(rmdir).", filepath)
            raise FuseOSError(EIO)

        if not entry_clause:
            _logger.error("Path [%s] does not exist for rmdir().", filepath)
            raise FuseOSError(ENOENT)

        entry_id = entry_clause[CLAUSE_ID]
        normalized_entry = entry_clause[CLAUSE_ENTRY]

        # Check if not a directory.

        if not normalized_entry.is_directory:
            _logger.error("Can not rmdir() non-directory [%s] with ID [%s].",
                          filepath, entry_id)

            raise FuseOSError(ENOTDIR)

        # Ensure the folder is empty.

        gd = get_gdrive()

        try:
            found = gd.get_children_under_parent_id(entry_id, max_results=1)
        except:
            _logger.exception(
                "Could not determine if directory to be removed "
                "has children.", entry_id)

            raise FuseOSError(EIO)

        if found:
            raise FuseOSError(ENOTEMPTY)

        try:
            gd.remove_entry(normalized_entry)
        except (NameError):
            raise FuseOSError(ENOENT)
        except:
            _logger.exception("Could not remove directory [%s] with ID [%s].",
                              filepath, entry_id)

            raise FuseOSError(EIO)
Example #11
0
    def __create(self, filepath, mode=None):
        """Create a new file.
                
        We don't implement "mode" (permissions) because the model doesn't agree 
        with GD.
        """

        # TODO: Fail if it already exists.

        try:
            result = split_path(filepath, path_resolver)
            (parent_clause, path, filename, mime_type, is_hidden) = result
        except GdNotFoundError:
            _logger.exception("Could not process [%s] (i-create).", filepath)
            raise FuseOSError(ENOENT)
        except:
            _logger.exception("Could not split path [%s] (i-create).",
                              filepath)
            raise FuseOSError(EIO)

        distilled_filepath = build_filepath(path, filename)

        # Try to guess at a mime-type, if not otherwise given.
        if mime_type is None:
            (mimetype_guess, _) = guess_type(filename, True)

            if mimetype_guess is not None:
                mime_type = mimetype_guess
            else:
                mime_type = Conf.get('default_mimetype')

        gd = get_gdrive()

        try:
            entry = gd.create_file(filename, [parent_clause[3]],
                                   mime_type,
                                   is_hidden=is_hidden)
        except:
            _logger.exception(
                "Could not create empty file [%s] under "
                "parent with ID [%s].", filename, parent_clause[3])

            raise FuseOSError(EIO)

        path_relations = PathRelations.get_instance()

        try:
            path_relations.register_entry(entry)
        except:
            _logger.exception("Could not register created file in cache.")
            raise FuseOSError(EIO)

        _logger.info("Inner-create of [%s] completed.", distilled_filepath)

        return (entry, path, filename, mime_type)
Example #12
0
    def __create(self, filepath, mode=None):
        """Create a new file.
                
        We don't implement "mode" (permissions) because the model doesn't agree 
        with GD.
        """

# TODO: Fail if it already exists.

        try:
            result = split_path(filepath, path_resolver)
            (parent_clause, path, filename, mime_type, is_hidden) = result
        except GdNotFoundError:
            _logger.exception("Could not process [%s] (i-create).", filepath)
            raise FuseOSError(ENOENT)
        except:
            _logger.exception("Could not split path [%s] (i-create).",
                              filepath)
            raise FuseOSError(EIO)

        if mime_type is None:
            _, ext = os.path.splitext(filename)
            if ext != '':
                ext = ext[1:]

            mime_type = utility.get_first_mime_type_by_extension(ext)

        distilled_filepath = build_filepath(path, filename)

        gd = get_gdrive()

        try:
            entry = gd.create_file(
                        filename, 
                        [parent_clause[3]], 
                        mime_type,
                        is_hidden=is_hidden)
        except:
            _logger.exception("Could not create empty file [%s] under "
                              "parent with ID [%s].",
                              filename, parent_clause[3])

            raise FuseOSError(EIO)

        path_relations = PathRelations.get_instance()

        try:
            path_relations.register_entry(entry)
        except:
            _logger.exception("Could not register created file in cache.")
            raise FuseOSError(EIO)

        _logger.info("Inner-create of [%s] completed.", distilled_filepath)

        return (entry, path, filename, mime_type)
Example #13
0
    def __create(self, filepath, mode=None):
        """Create a new file.
                
        We don't implement "mode" (permissions) because the model doesn't agree 
        with GD.
        """

        # TODO: Fail if it already exists.

        try:
            result = split_path(filepath, path_resolver)
            (parent_clause, path, filename, mime_type, is_hidden) = result
        except GdNotFoundError:
            _logger.exception("Could not process [%s] (i-create).", filepath)
            raise FuseOSError(ENOENT)
        except:
            _logger.exception("Could not split path [%s] (i-create).",
                              filepath)
            raise FuseOSError(EIO)

        if mime_type is None:
            _, ext = os.path.splitext(filename)
            if ext != '':
                ext = ext[1:]

            mime_type = utility.get_first_mime_type_by_extension(ext)

        distilled_filepath = build_filepath(path, filename)

        gd = get_gdrive()

        try:
            entry = gd.create_file(filename, [parent_clause[3]],
                                   mime_type,
                                   is_hidden=is_hidden)
        except:
            _logger.exception(
                "Could not create empty file [%s] under "
                "parent with ID [%s].", filename, parent_clause[3])

            raise FuseOSError(EIO)

        path_relations = PathRelations.get_instance()

        try:
            path_relations.register_entry(entry)
        except:
            _logger.exception("Could not register created file in cache.")
            raise FuseOSError(EIO)

        _logger.info("Inner-create of [%s] completed.", distilled_filepath)

        return (entry, path, filename, mime_type)
Example #14
0
    def readdir(self, path, offset):
        """A generator returning one base filename at a time."""

        # We expect "offset" to always be (0).
        if offset != 0:
            self.__log.warning(
                "readdir() has been invoked for path [%s] and non-"
                "zero offset (%d). This is not allowed." % (path, offset))

# TODO: Once we start working on the cache, make sure we don't make this call,
#       constantly.

        path_relations = PathRelations.get_instance()

        self.__log.debug("Listing files.")

        try:
            entry_clause = path_relations.get_clause_from_path(path)
        except GdNotFoundError:
            self.__log.exception("Could not process [%s] (readdir).")
            raise FuseOSError(ENOENT)
        except:
            self.__log.exception("Could not get clause from path [%s] "
                                 "(readdir)." % (path))
            raise FuseOSError(EIO)

        if not entry_clause:
            self.__log.debug("Path [%s] does not exist for readdir()." %
                             (path))
            raise FuseOSError(ENOENT)

        try:
            entry_tuples = path_relations.get_children_entries_from_entry_id \
                            (entry_clause[CLAUSE_ID])
        except:
            self.__log.exception(
                "Could not render list of filenames under path "
                "[%s]." % (path))
            raise FuseOSError(EIO)

        yield '.'
        yield '..'

        for (filename, entry) in entry_tuples:

            # Decorate any file that -requires- a mime-type (all files can
            # merely accept a mime-type)
            if entry.requires_mimetype:
                filename += '#'

            yield filename
Example #15
0
    def readdir(self, path, offset):
        """A generator returning one base filename at a time."""

        # We expect "offset" to always be (0).
        if offset != 0:
            self.__log.warning("readdir() has been invoked for path [%s] and non-"
                            "zero offset (%d). This is not allowed." % 
                            (path, offset))

# TODO: Once we start working on the cache, make sure we don't make this call, 
#       constantly.

        path_relations = PathRelations.get_instance()

        self.__log.debug("Listing files.")

        try:
            entry_clause = path_relations.get_clause_from_path(path)
        except GdNotFoundError:
            self.__log.exception("Could not process [%s] (readdir).")
            raise FuseOSError(ENOENT)
        except:
            self.__log.exception("Could not get clause from path [%s] "
                              "(readdir)." % (path))
            raise FuseOSError(EIO)

        if not entry_clause:
            self.__log.debug("Path [%s] does not exist for readdir()." % (path))
            raise FuseOSError(ENOENT)

        try:
            entry_tuples = path_relations.get_children_entries_from_entry_id \
                            (entry_clause[CLAUSE_ID])
        except:
            self.__log.exception("Could not render list of filenames under path "
                             "[%s]." % (path))
            raise FuseOSError(EIO)

        yield '.'
        yield '..'

        for (filename, entry) in entry_tuples:

            # Decorate any file that -requires- a mime-type (all files can 
            # merely accept a mime-type)
            if entry.requires_mimetype:
                filename += '#'
        
            yield filename
Example #16
0
    def readdir(self, path, offset):
        """A generator returning one base filename at a time."""

        # We expect "offset" to always be (0).
        if offset != 0:
            _logger.warning(
                "readdir() has been invoked for path [%s] and " "non-zero offset (%d). This is not allowed.",
                path,
                offset,
            )

        # TODO: Once we start working on the cache, make sure we don't make this call,
        #       constantly.

        path_relations = PathRelations.get_instance()

        try:
            entry_clause = path_relations.get_clause_from_path(path)
        except GdNotFoundError:
            _logger.exception("Could not process [%s] (readdir).")
            raise FuseOSError(ENOENT)
        except:
            _logger.exception("Could not get clause from path [%s] " "(readdir)." % (path))
            raise FuseOSError(EIO)

        if not entry_clause:
            raise FuseOSError(ENOENT)

        try:
            entry_tuples = path_relations.get_children_entries_from_entry_id(entry_clause[CLAUSE_ID])
        except:
            _logger.exception("Could not render list of filenames under path " "[%s].", path)

            raise FuseOSError(EIO)

        yield utility.translate_filename_charset(".")
        yield utility.translate_filename_charset("..")

        for (filename, entry) in entry_tuples:

            # Decorate any file that -requires- a mime-type (all files can
            # merely accept a mime-type)
            if entry.requires_mimetype:
                filename += utility.translate_filename_charset("#")

            yield (filename, self.__build_stat_from_entry(entry), 0)
Example #17
0
    def __get_entry_or_raise(self, raw_path, allow_normal_for_missing=False):
        try:
            result = split_path(raw_path, path_resolver)
            (parent_clause, path, filename, mime_type, is_hidden) = result
        except GdNotFoundError:
            self.__log.exception("Could not retrieve clause for non-existent "
                                 "file-path [%s] (parent does not exist)." % 
                                 (raw_path))

            if allow_normal_for_missing is True:
                raise
            else:
                raise FuseOSError(ENOENT)
        except:
            self.__log.exception("Could not process file-path [%s]." % 
                                 (raw_path))
            raise FuseOSError(EIO)

        filepath = build_filepath(path, filename)
        path_relations = PathRelations.get_instance()

        try:
            entry_clause = path_relations.get_clause_from_path(filepath)
        except GdNotFoundError:
            self.__log.exception("Could not retrieve clause for non-existent "
                                 "file-path [%s] (parent exists)." % 
                                 (filepath))

            if allow_normal_for_missing is True:
                raise
            else:
                raise FuseOSError(ENOENT)
        except:
            self.__log.exception("Could not retrieve clause for path [%s]. " %
                                 (filepath))
            raise FuseOSError(EIO)

        if not entry_clause:
            self.__log.debug("Path [%s] does not exist for stat()." % (filepath))

            if allow_normal_for_missing is True:
                raise GdNotFoundError()
            else:
                raise FuseOSError(ENOENT)

        return (entry_clause[CLAUSE_ENTRY], path, filename)
Example #18
0
    def flush(self):
        """The OS wants to effect any changes made to the file."""

        _logger.debug("Flushing opened-file.")

        entry = self.__cache.get(self.__entry_id)

        if self.__is_dirty is False:
            _logger.debug("Flush will be skipped for [%s] because there "
                          "are no changes: [%s] IS_LOADED=[%s] "
                          "IS_DIRTY=[%d]", 
                          entry.id, self.file_path, self.__is_loaded, 
                          self.__is_dirty)
            return
        else:
            st = os.stat(self.__temp_filepath)

            _logger.debug("Pushing (%d) bytes for entry with ID from [%s] to "
                          "GD for file-path [%s].",
                          st.st_size, entry.id, self.__temp_filepath)

# TODO: Make sure we sync the mtime to remote.
            gd = get_gdrive()
            entry = gd.update_entry(
                        entry, 
                        filename=entry.title, 
                        data_filepath=self.__temp_filepath, 
                        mime_type=self.mime_type, 
                        parents=entry.parents, 
                        is_hidden=self.__is_hidden)

            self.__is_dirty = False

# TODO(dustin): For now, we don't cleanup the temporary file. We need to 
#               schedule this using LRU-semantics.

            # Immediately update our current cached entry.

            _logger.debug("Update successful. Updating local cache.")

            path_relations = PathRelations.get_instance()
            path_relations.register_entry(entry)

            _logger.info("Update complete on entry with ID [%s].", entry.id)
Example #19
0
    def mkdir(self, filepath, mode):
        """Create the given directory."""

# TODO: Implement the "mode".

        try:
            result = split_path(filepath, path_resolver)
            (parent_clause, path, filename, mime_type, is_hidden) = result
        except GdNotFoundError:
            self.__log.exception("Could not process [%s] (mkdir).")
            raise FuseOSError(ENOENT)
        except:
            self.__log.exception("Could not split path [%s] (mkdir)." % 
                              (filepath))
            raise FuseOSError(EIO)

        parent_id = parent_clause[CLAUSE_ID]

        self.__log.debug("Creating directory [%s] under parent [%s] with ID "
                         "[%s]." % (filename, path, parent_id))

        try:
            entry = drive_proxy('create_directory', 
                                filename=filename, 
                                parents=[parent_id], 
                                is_hidden=is_hidden)
        except:
            self.__log.exception("Could not create directory with name [%s] "
                                 "and parent with ID [%s]." % 
                                 (filename, parent_clause[0].id))
            raise FuseOSError(EIO)

        self.__log.info("Directory [%s] created as ID [%s] under parent with "
                        "ID [%s]." % (filepath, entry.id, parent_id))

        #parent_clause[4] = False

        path_relations = PathRelations.get_instance()

        try:
            path_relations.register_entry(entry)
        except:
            self.__log.exception("Could not register new directory in cache.")
            raise FuseOSError(EIO)
Example #20
0
    def flush(self):
        """The OS wants to effect any changes made to the file."""

        _logger.debug("Flushing opened-file.")

        entry = self.__cache.get(self.__entry_id)

        if self.__is_dirty is False:
            _logger.debug(
                "Flush will be skipped for [%s] because there "
                "are no changes: [%s] IS_LOADED=[%s] "
                "IS_DIRTY=[%d]", entry.id, self.file_path, self.__is_loaded,
                self.__is_dirty)
            return
        else:
            st = os.stat(self.__temp_filepath)

            _logger.debug(
                "Pushing (%d) bytes for entry with ID from [%s] to "
                "GD for file-path [%s].", st.st_size, entry.id,
                self.__temp_filepath)

            # TODO: Make sure we sync the mtime to remote.
            gd = get_gdrive()
            entry = gd.update_entry(entry,
                                    filename=entry.title,
                                    data_filepath=self.__temp_filepath,
                                    mime_type=self.mime_type,
                                    parents=entry.parents,
                                    is_hidden=self.__is_hidden)

            self.__is_dirty = False

            # TODO(dustin): For now, we don't cleanup the temporary file. We need to
            #               schedule this using LRU-semantics.

            # Immediately update our current cached entry.

            _logger.debug("Update successful. Updating local cache.")

            path_relations = PathRelations.get_instance()
            path_relations.register_entry(entry)

            _logger.info("Update complete on entry with ID [%s].", entry.id)
Example #21
0
    def mkdir(self, filepath, mode):
        """Create the given directory."""

        # TODO: Implement the "mode".

        try:
            result = split_path(filepath, path_resolver)
            (parent_clause, path, filename, mime_type, is_hidden) = result
        except GdNotFoundError:
            self.__log.exception("Could not process [%s] (mkdir).")
            raise FuseOSError(ENOENT)
        except:
            self.__log.exception("Could not split path [%s] (mkdir)." %
                                 (filepath))
            raise FuseOSError(EIO)

        parent_id = parent_clause[CLAUSE_ID]

        self.__log.debug("Creating directory [%s] under parent [%s] with ID "
                         "[%s]." % (filename, path, parent_id))

        try:
            entry = drive_proxy('create_directory',
                                filename=filename,
                                parents=[parent_id],
                                is_hidden=is_hidden)
        except:
            self.__log.exception("Could not create directory with name [%s] "
                                 "and parent with ID [%s]." %
                                 (filename, parent_clause[0].id))
            raise FuseOSError(EIO)

        self.__log.info("Directory [%s] created as ID [%s] under parent with "
                        "ID [%s]." % (filepath, entry.id, parent_id))

        #parent_clause[4] = False

        path_relations = PathRelations.get_instance()

        try:
            path_relations.register_entry(entry)
        except:
            self.__log.exception("Could not register new directory in cache.")
            raise FuseOSError(EIO)
Example #22
0
def get_entry_or_raise(raw_path, allow_normal_for_missing=False):
    try:
        result = split_path(raw_path, path_resolver)
        (parent_clause, path, filename, mime_type, is_hidden) = result
    except GdNotFoundError:
        _logger.exception("Could not retrieve clause for non-existent "
                          "file-path [%s] (parent does not exist)." %
                          (raw_path))

        if allow_normal_for_missing is True:
            raise
        else:
            raise FuseOSError(ENOENT)
    except:
        _logger.exception("Could not process file-path [%s]." % (raw_path))
        raise FuseOSError(EIO)

    filepath = build_filepath(path, filename)
    path_relations = PathRelations.get_instance()

    try:
        entry_clause = path_relations.get_clause_from_path(filepath)
    except GdNotFoundError:
        _logger.exception("Could not retrieve clause for non-existent "
                          "file-path [%s] (parent exists)." % (filepath))

        if allow_normal_for_missing is True:
            raise
        else:
            raise FuseOSError(ENOENT)
    except:
        _logger.exception("Could not retrieve clause for path [%s]. " %
                          (filepath))
        raise FuseOSError(EIO)

    if not entry_clause:
        if allow_normal_for_missing is True:
            raise GdNotFoundError()
        else:
            raise FuseOSError(ENOENT)

    return (entry_clause[CLAUSE_ENTRY], path, filename)
Example #23
0
    def rename(self, filepath_old, filepath_new):

        self.__log.debug("Renaming [%s] to [%s]." %
                         (filepath_old, filepath_new))

        # Make sure the old filepath exists.
        (entry, path, filename_old) = self.__get_entry_or_raise(filepath_old)

        # At this point, decorations, the is-hidden prefix, etc.. haven't been
        # stripped.
        (path, filename_new_raw) = split(filepath_new)

        # Make sure the new filepath doesn't exist.

        try:
            self.__get_entry_or_raise(filepath_new, True)
        except GdNotFoundError:
            pass

        try:
            entry = drive_proxy('rename',
                                normalized_entry=entry,
                                new_filename=filename_new_raw)
        except:
            self.__log.exception("Could not update entry [%s] for rename." %
                                 (entry))
            raise FuseOSError(EIO)

        # Update our knowledge of the entry.

        path_relations = PathRelations.get_instance()

        try:
            path_relations.register_entry(entry)
        except:
            self.__log.exception("Could not register renamed entry: %s" %
                                 (entry))
            raise FuseOSError(EIO)
Example #24
0
    def rename(self, filepath_old, filepath_new):

        self.__log.debug("Renaming [%s] to [%s]." % 
                         (filepath_old, filepath_new))

        # Make sure the old filepath exists.
        (entry, path, filename_old) = self.__get_entry_or_raise(filepath_old)

        # At this point, decorations, the is-hidden prefix, etc.. haven't been
        # stripped.
        (path, filename_new_raw) = split(filepath_new)

        # Make sure the new filepath doesn't exist.

        try:
            self.__get_entry_or_raise(filepath_new, True)
        except GdNotFoundError:
            pass

        try:
            entry = drive_proxy('rename', normalized_entry=entry, 
                                new_filename=filename_new_raw)
        except:
            self.__log.exception("Could not update entry [%s] for rename." %
                                 (entry))
            raise FuseOSError(EIO)

        # Update our knowledge of the entry.

        path_relations = PathRelations.get_instance()

        try:
            path_relations.register_entry(entry)
        except:
            self.__log.exception("Could not register renamed entry: %s" % 
                                 (entry))
            raise FuseOSError(EIO)
Example #25
0
    def unlink(self, file_path):
        """Remove a file."""
        # TODO: Change to simply move to "trash". Have a FUSE option to elect this
        # behavior.
        path_relations = PathRelations.get_instance()

        try:
            entry_clause = path_relations.get_clause_from_path(file_path)
        except GdNotFoundError:
            _logger.exception("Could not process [%s] (unlink).", file_path)
            raise FuseOSError(ENOENT)
        except:
            _logger.exception(
                "Could not get clause from file-path [%s] "
                "(unlink).", file_path)

            raise FuseOSError(EIO)

        if not entry_clause:
            _logger.error("Path [%s] does not exist for unlink().", file_path)

            raise FuseOSError(ENOENT)

        entry_id = entry_clause[CLAUSE_ID]
        normalized_entry = entry_clause[CLAUSE_ENTRY]

        # Check if a directory.

        if normalized_entry.is_directory:
            _logger.error(
                "Can not unlink() directory [%s] with ID [%s]. "
                "Must be file.", file_path, entry_id)

            raise FuseOSError(errno.EISDIR)

        # Remove online. Complements local removal (if not found locally, a
        # follow-up request checks online).

        gd = get_gdrive()

        try:
            gd.remove_entry(normalized_entry)
        except (NameError):
            raise FuseOSError(ENOENT)
        except:
            _logger.exception("Could not remove file [%s] with ID [%s].",
                              file_path, entry_id)

            raise FuseOSError(EIO)

        # Remove from cache. Will no longer be able to be found, locally.

        try:
            PathRelations.get_instance().remove_entry_all(entry_id)
        except:
            _logger.exception(
                "There was a problem removing entry [%s] "
                "from the caches.", normalized_entry)
            raise

        # Remove from among opened-files.

        om = gdrivefs.gdfs.opened_file.get_om()

        try:
            opened_file = om.remove_by_filepath(file_path)
        except:
            _logger.exception(
                "There was an error while removing all "
                "opened-file instances for file [%s] "
                "(remove).", file_path)
            raise FuseOSError(EIO)
Example #26
0
    def __create(self, filepath, mode=None):
        """Create a new file.
                
        We don't implement "mode" (permissions) because the model doesn't agree 
        with GD.
        """
# TODO: Fail if it already exists.

        self.__log.debug("Splitting file-path [%s] for inner create." % 
                         (filepath))

        try:
            result = split_path(filepath, path_resolver)
            (parent_clause, path, filename, mime_type, is_hidden) = result
        except GdNotFoundError:
            self.__log.exception("Could not process [%s] (i-create).")
            raise FuseOSError(ENOENT)
        except:
            self.__log.exception("Could not split path [%s] (i-create)." % 
                              (filepath))
            raise FuseOSError(EIO)

        distilled_filepath = build_filepath(path, filename)

        self.__log.debug("Acquiring file-handle.")

        # Try to guess at a mime-type, if not otherwise given.
        if mime_type is None:
            (mimetype_guess, _) = guess_type(filename, True)
            
            if mimetype_guess is not None:
                mime_type = mimetype_guess
            else:
                mime_type = Conf.get('default_mimetype')

        self.__log.debug("Creating empty file [%s] under parent with ID "
                         "[%s]." % (filename, parent_clause[3]))

        try:
            entry = drive_proxy('create_file', filename=filename, 
                                data_filepath='/dev/null', 
                                parents=[parent_clause[3]], 
                                mime_type=mime_type,
                                is_hidden=is_hidden)
        except:
            self.__log.exception("Could not create empty file [%s] under "
                                 "parent with ID [%s]." % (filename, 
                                                           parent_clause[3]))
            raise FuseOSError(EIO)

        self.__log.debug("Registering created file in cache.")

        path_relations = PathRelations.get_instance()

        try:
            path_relations.register_entry(entry)
        except:
            self.__log.exception("Could not register created file in cache.")
            raise FuseOSError(EIO)

        self.__log.info("Inner-create of [%s] completed." % 
                        (distilled_filepath))

        return (entry, path, filename, mime_type)
Example #27
0
    def rmdir(self, filepath):
        """Remove a directory."""

        path_relations = PathRelations.get_instance()

        self.__log.debug("Removing directory [%s]." % (filepath))

        try:
            entry_clause = path_relations.get_clause_from_path(filepath)
        except GdNotFoundError:
            self.__log.exception("Could not process [%s] (rmdir).")
            raise FuseOSError(ENOENT)
        except:
            self.__log.exception("Could not get clause from file-path [%s] "
                              "(rmdir)." % (filepath))
            raise FuseOSError(EIO)

        if not entry_clause:
            self.__log.error("Path [%s] does not exist for rmdir()." % (filepath))
            raise FuseOSError(ENOENT)

        entry_id = entry_clause[CLAUSE_ID]
        normalized_entry = entry_clause[CLAUSE_ENTRY]

        # Check if not a directory.

        self.__log.debug("Ensuring it is a directory.")

        if not normalized_entry.is_directory:
            self.__log.error("Can not rmdir() non-directory [%s] with ID [%s].", filepath, entry_id)
            raise FuseOSError(ENOTDIR)

        # Ensure the folder is empty.

        self.__log.debug("Checking if empty.")

        try:
            found = drive_proxy('get_children_under_parent_id', 
                                parent_id=entry_id,
                                max_results=1)
        except:
            self.__log.exception("Could not determine if directory to be removed "
                              "has children." % (entry_id))
            raise FuseOSError(EIO)

        if found:
            raise FuseOSError(ENOTEMPTY)

        self.__log.debug("Doing remove of directory [%s] with ID [%s]." % 
                      (filepath, entry_id))

        try:
            drive_proxy('remove_entry', normalized_entry=normalized_entry)
        except (NameError):
            raise FuseOSError(ENOENT)
        except:
            self.__log.exception("Could not remove directory [%s] with ID [%s]." % 
                              (filepath, entry_id))
            raise FuseOSError(EIO)
# TODO: Remove from cache.
        self.__log.debug("Directory removal complete.")
Example #28
0
    def rmdir(self, filepath):
        """Remove a directory."""

        path_relations = PathRelations.get_instance()

        self.__log.debug("Removing directory [%s]." % (filepath))

        try:
            entry_clause = path_relations.get_clause_from_path(filepath)
        except GdNotFoundError:
            self.__log.exception("Could not process [%s] (rmdir).")
            raise FuseOSError(ENOENT)
        except:
            self.__log.exception("Could not get clause from file-path [%s] "
                                 "(rmdir)." % (filepath))
            raise FuseOSError(EIO)

        if not entry_clause:
            self.__log.error("Path [%s] does not exist for rmdir()." %
                             (filepath))
            raise FuseOSError(ENOENT)

        entry_id = entry_clause[CLAUSE_ID]
        normalized_entry = entry_clause[CLAUSE_ENTRY]

        # Check if not a directory.

        self.__log.debug("Ensuring it is a directory.")

        if not normalized_entry.is_directory:
            self.__log.error(
                "Can not rmdir() non-directory [%s] with ID [%s].", filepath,
                entry_id)
            raise FuseOSError(ENOTDIR)

        # Ensure the folder is empty.

        self.__log.debug("Checking if empty.")

        try:
            found = drive_proxy('get_children_under_parent_id',
                                parent_id=entry_id,
                                max_results=1)
        except:
            self.__log.exception(
                "Could not determine if directory to be removed "
                "has children." % (entry_id))
            raise FuseOSError(EIO)

        if found:
            raise FuseOSError(ENOTEMPTY)

        self.__log.debug("Doing remove of directory [%s] with ID [%s]." %
                         (filepath, entry_id))

        try:
            drive_proxy('remove_entry', normalized_entry=normalized_entry)
        except (NameError):
            raise FuseOSError(ENOENT)
        except:
            self.__log.exception(
                "Could not remove directory [%s] with ID [%s]." %
                (filepath, entry_id))
            raise FuseOSError(EIO)


# TODO: Remove from cache.
        self.__log.debug("Directory removal complete.")
Example #29
0
    def __create(self, filepath, mode=None):
        """Create a new file.
                
        We don't implement "mode" (permissions) because the model doesn't agree 
        with GD.
        """
        # TODO: Fail if it already exists.

        self.__log.debug("Splitting file-path [%s] for inner create." %
                         (filepath))

        try:
            result = split_path(filepath, path_resolver)
            (parent_clause, path, filename, mime_type, is_hidden) = result
        except GdNotFoundError:
            self.__log.exception("Could not process [%s] (i-create).")
            raise FuseOSError(ENOENT)
        except:
            self.__log.exception("Could not split path [%s] (i-create)." %
                                 (filepath))
            raise FuseOSError(EIO)

        distilled_filepath = build_filepath(path, filename)

        self.__log.debug("Acquiring file-handle.")

        # Try to guess at a mime-type, if not otherwise given.
        if mime_type is None:
            (mimetype_guess, _) = guess_type(filename, True)

            if mimetype_guess is not None:
                mime_type = mimetype_guess
            else:
                mime_type = Conf.get('default_mimetype')

        self.__log.debug("Creating empty file [%s] under parent with ID "
                         "[%s]." % (filename, parent_clause[3]))

        try:
            entry = drive_proxy('create_file',
                                filename=filename,
                                data_filepath='/dev/null',
                                parents=[parent_clause[3]],
                                mime_type=mime_type,
                                is_hidden=is_hidden)
        except:
            self.__log.exception("Could not create empty file [%s] under "
                                 "parent with ID [%s]." %
                                 (filename, parent_clause[3]))
            raise FuseOSError(EIO)

        self.__log.debug("Registering created file in cache.")

        path_relations = PathRelations.get_instance()

        try:
            path_relations.register_entry(entry)
        except:
            self.__log.exception("Could not register created file in cache.")
            raise FuseOSError(EIO)

        self.__log.info("Inner-create of [%s] completed." %
                        (distilled_filepath))

        return (entry, path, filename, mime_type)
Example #30
0
def create_for_existing_filepath(filepath):
    """Process the file/path that was requested (potential export-type 
    directive, dot-prefix, etc..), and build an opened-file object using 
    the information.
    """

    _logger.debug("Creating OpenedFile for [%s].", filepath)

    # Process/distill the requested file-path.

    try:
        result = split_path(filepath, path_resolver)
    except GdNotFoundError:
        _logger.exception("Could not process [%s] (create_for_requested).",
                          filepath)

        raise fuse.FuseOSError(ENOENT)

    (parent_clause, path, filename, mime_type, is_hidden) = result
    distilled_filepath = build_filepath(path, filename)

    # Look-up the requested entry.

    path_relations = PathRelations.get_instance()

    try:
        entry_clause = path_relations.get_clause_from_path(
                        distilled_filepath)
    except:
        _logger.exception("Could not try to get clause from path [%s] "
                          "(OpenedFile).", distilled_filepath)

        raise fuse.FuseOSError(EIO)

    if not entry_clause:
        _logger.debug("Path [%s] does not exist for stat().", path)
        raise fuse.FuseOSError(ENOENT)

    entry = entry_clause[CLAUSE_ENTRY]

    # Normalize the mime-type by considering what's available for download. 
    # We're going to let the requests that didn't provide a mime-type fail 
    # right here. It will give us the opportunity to try a few options to 
    # get the file.

    try:
        final_mimetype = entry.normalize_download_mimetype(mime_type)
    except ExportFormatError:
        _logger.exception("There was an export-format error "
                          "(create_for_requested_filesystem).")

        raise fuse.FuseOSError(ENOENT)
    except:
        _logger.exception("Could not normalize mime-type [%s] for entry"
                          "[%s].", mime_type, entry)

        raise fuse.FuseOSError(EIO)

    if final_mimetype != mime_type:
        _logger.info("Entry being opened will be opened as [%s] rather "
                     "than [%s].", final_mimetype, mime_type)

    # Build the object.

    return OpenedFile(
            entry_clause[CLAUSE_ID], 
            path, 
            filename, 
            is_hidden, 
            final_mimetype)
Example #31
0
    def unlink(self, file_path):
        """Remove a file."""
        # TODO: Change to simply move to "trash". Have a FUSE option to elect this
        # behavior.
        path_relations = PathRelations.get_instance()

        self.__log.debug("Removing file [%s]." % (file_path))

        try:
            entry_clause = path_relations.get_clause_from_path(file_path)
        except GdNotFoundError:
            self.__log.exception("Could not process [%s] (unlink).")
            raise FuseOSError(ENOENT)
        except:
            self.__log.exception("Could not get clause from file-path [%s] "
                                 "(unlink)." % (file_path))
            raise FuseOSError(EIO)

        if not entry_clause:
            self.__log.error("Path [%s] does not exist for unlink()." %
                             (file_path))
            raise FuseOSError(ENOENT)

        entry_id = entry_clause[CLAUSE_ID]
        normalized_entry = entry_clause[CLAUSE_ENTRY]

        # Check if a directory.

        self.__log.debug("Ensuring it is a file (not a directory).")

        if normalized_entry.is_directory:
            self.__log.error(
                "Can not unlink() directory [%s] with ID [%s]. "
                "Must be file.", file_path, entry_id)
            raise FuseOSError(errno.EISDIR)

        self.__log.debug("Doing remove of directory [%s] with ID [%s]." %
                         (file_path, entry_id))

        # Remove online. Complements local removal (if not found locally, a
        # follow-up request checks online).

        try:
            drive_proxy('remove_entry', normalized_entry=normalized_entry)
        except (NameError):
            raise FuseOSError(ENOENT)
        except:
            self.__log.exception("Could not remove file [%s] with ID [%s]." %
                                 (file_path, entry_id))
            raise FuseOSError(EIO)

        # Remove from cache. Will no longer be able to be found, locally.

        self.__log.debug("Removing all trace of entry [%s] from cache "
                         "(unlink)." % (normalized_entry))

        try:
            PathRelations.get_instance().remove_entry_all(entry_id)
        except:
            self.__log.exception("There was a problem removing entry [%s] "
                                 "from the caches." % (normalized_entry))
            raise

        # Remove from among opened-files.

        self.__log.debug("Removing all opened-files for [%s]." % (file_path))

        try:
            opened_file = OpenedManager.get_instance().\
                            remove_by_filepath(file_path)
        except:
            self.__log.exception("There was an error while removing all "
                                 "opened-file instances for file [%s] "
                                 "(remove)." % (file_path))
            raise FuseOSError(EIO)

        self.__log.debug("File removal complete.")
Example #32
0
    def flush(self):
        """The OS wants to effect any changes made to the file."""

        self.__log.debug("Retrieving entry for write-flush.")

        entry = self.__get_entry_or_raise()
        cache_fault = self.__load_base_from_remote()

        with self.__class__.__update_lock:
            if self.__is_dirty is False:
                self.__log.debug("Flush will be skipped because there are no "
                                 "changes.")
                # TODO: Raise an exception?
                return

            # Write back out to the temporary file.

            self.__log.debug("Writing buffer to temporary file.")
            # TODO: Make sure to uncache the temp data if self.temp_file_path is not None.

            mime_type = self.mime_type

            # If we've already opened a work file, use it. Else, use a
            # temporary file that we'll close at the end of the method.
            if self.__is_loaded:
                is_temp = False

                temp_file_path = get_temp_filepath(entry, mime_type)

                with file(temp_file_path, 'w') as f:
                    for block in self.__buffer.read():
                        f.write(block)

                write_filepath = temp_file_path
            else:
                is_temp = True

                with NamedTemporaryFile(delete=False) as f:
                    write_filepath = f.name
                    for block in self.__buffer.read():
                        f.write(block)

            # Push to GD.

            self.__log.debug("Pushing (%d) bytes for entry with ID from [%s] "
                             "to GD for file-path [%s]." %
                             (self.__buffer.length, entry.id, write_filepath))

            #            print("Sending updates.")

            # TODO: Update mtime?
            try:
                entry = drive_proxy('update_entry',
                                    normalized_entry=entry,
                                    filename=entry.title,
                                    data_filepath=write_filepath,
                                    mime_type=mime_type,
                                    parents=entry.parents,
                                    is_hidden=self.__is_hidden)
            except:
                self.__log.exception("Could not localize displaced file with "
                                     "entry having ID [%s]." % (entry.id))
                raise

            if not is_temp:
                unlink(write_filepath)
            else:
                # Update the write-cache file to the official mtime. We won't
                # redownload it on the next flush if it wasn't changed,
                # elsewhere.

                self.__log.debug("Updating local write-cache file to official "
                                 "mtime [%s]." % (entry.modified_date_epoch))

                try:
                    utime(
                        write_filepath,
                        (entry.modified_date_epoch, entry.modified_date_epoch))
                except:
                    self.__log.exception("Could not update mtime of write-"
                                         "cache [%s] for entry with ID [%s], "
                                         "post-flush." %
                                         (entry.modified_date_epoch, entry.id))
                    raise

        # Immediately update our current cached entry.

        self.__log.debug("Update successful. Updating local cache.")

        path_relations = PathRelations.get_instance()

        try:
            path_relations.register_entry(entry)
        except:
            self.__log.exception("Could not register updated file in cache.")
            raise

        self.__is_dirty = False

        self.__log.info("Update complete on entry with ID [%s]." % (entry.id))
Example #33
0
    def unlink(self, file_path):
        """Remove a file."""
# TODO: Change to simply move to "trash". Have a FUSE option to elect this
# behavior.
        path_relations = PathRelations.get_instance()

        self.__log.debug("Removing file [%s]." % (file_path))

        try:
            entry_clause = path_relations.get_clause_from_path(file_path)
        except GdNotFoundError:
            self.__log.exception("Could not process [%s] (unlink).")
            raise FuseOSError(ENOENT)
        except:
            self.__log.exception("Could not get clause from file-path [%s] "
                                 "(unlink)." % (file_path))
            raise FuseOSError(EIO)

        if not entry_clause:
            self.__log.error("Path [%s] does not exist for unlink()." % 
                             (file_path))
            raise FuseOSError(ENOENT)

        entry_id = entry_clause[CLAUSE_ID]
        normalized_entry = entry_clause[CLAUSE_ENTRY]

        # Check if a directory.

        self.__log.debug("Ensuring it is a file (not a directory).")

        if normalized_entry.is_directory:
            self.__log.error("Can not unlink() directory [%s] with ID [%s]. "
                             "Must be file.", file_path, entry_id)
            raise FuseOSError(errno.EISDIR)

        self.__log.debug("Doing remove of directory [%s] with ID [%s]." % 
                         (file_path, entry_id))

        # Remove online. Complements local removal (if not found locally, a 
        # follow-up request checks online).

        try:
            drive_proxy('remove_entry', normalized_entry=normalized_entry)
        except (NameError):
            raise FuseOSError(ENOENT)
        except:
            self.__log.exception("Could not remove file [%s] with ID [%s]." % 
                                 (file_path, entry_id))
            raise FuseOSError(EIO)

        # Remove from cache. Will no longer be able to be found, locally.

        self.__log.debug("Removing all trace of entry [%s] from cache "
                         "(unlink)." % (normalized_entry))

        try:
            PathRelations.get_instance().remove_entry_all(entry_id)
        except:
            self.__log.exception("There was a problem removing entry [%s] "
                                 "from the caches." % (normalized_entry))
            raise

        # Remove from among opened-files.

        self.__log.debug("Removing all opened-files for [%s]." % (file_path))

        try:
            opened_file = OpenedManager.get_instance().\
                            remove_by_filepath(file_path)
        except:
            self.__log.exception("There was an error while removing all "
                                 "opened-file instances for file [%s] "
                                 "(remove)." % (file_path))
            raise FuseOSError(EIO)

        self.__log.debug("File removal complete.")
Example #34
0
def create_for_existing_filepath(filepath):
    """Process the file/path that was requested (potential export-type 
    directive, dot-prefix, etc..), and build an opened-file object using 
    the information.
    """

    _logger.debug("Creating OpenedFile for [%s].", filepath)

    # Process/distill the requested file-path.

    try:
        result = split_path(filepath, path_resolver)
    except GdNotFoundError:
        _logger.exception("Could not process [%s] (create_for_requested).",
                          filepath)

        raise fuse.FuseOSError(ENOENT)

    (parent_clause, path, filename, mime_type, is_hidden) = result
    distilled_filepath = build_filepath(path, filename)

    # Look-up the requested entry.

    path_relations = PathRelations.get_instance()

    try:
        entry_clause = path_relations.get_clause_from_path(distilled_filepath)
    except:
        _logger.exception(
            "Could not try to get clause from path [%s] "
            "(OpenedFile).", distilled_filepath)

        raise fuse.FuseOSError(EIO)

    if not entry_clause:
        _logger.debug("Path [%s] does not exist for stat().", path)
        raise fuse.FuseOSError(ENOENT)

    entry = entry_clause[CLAUSE_ENTRY]

    # Normalize the mime-type by considering what's available for download.
    # We're going to let the requests that didn't provide a mime-type fail
    # right here. It will give us the opportunity to try a few options to
    # get the file.

    try:
        final_mimetype = entry.normalize_download_mimetype(mime_type)
    except ExportFormatError:
        _logger.exception("There was an export-format error "
                          "(create_for_requested_filesystem).")

        raise fuse.FuseOSError(ENOENT)
    except:
        _logger.exception(
            "Could not normalize mime-type [%s] for entry"
            "[%s].", mime_type, entry)

        raise fuse.FuseOSError(EIO)

    if final_mimetype != mime_type:
        _logger.info(
            "Entry being opened will be opened as [%s] rather "
            "than [%s].", final_mimetype, mime_type)

    # Build the object.

    return OpenedFile(entry_clause[CLAUSE_ID], path, filename, is_hidden,
                      final_mimetype)
Example #35
0
    def flush(self):
        """The OS wants to effect any changes made to the file."""

        self.__log.debug("Retrieving entry for write-flush.")

        entry = self.__get_entry_or_raise()
        cache_fault = self.__load_base_from_remote()

        with self.__class__.__update_lock:
            if self.__is_dirty is False:
                self.__log.debug("Flush will be skipped because there are no "
                                 "changes.")
# TODO: Raise an exception?
                return

            # Write back out to the temporary file.

            self.__log.debug("Writing buffer to temporary file.")
# TODO: Make sure to uncache the temp data if self.temp_file_path is not None.

            mime_type = self.mime_type

            # If we've already opened a work file, use it. Else, use a 
            # temporary file that we'll close at the end of the method.
            if self.__is_loaded:
                is_temp = False

                temp_file_path = get_temp_filepath(entry, mime_type)
                                                   
                with file(temp_file_path, 'w') as f:
                    for block in self.__buffer.read():
                        f.write(block)
                                                   
                write_filepath = temp_file_path
            else:
                is_temp = True
            
                with NamedTemporaryFile(delete=False) as f:
                    write_filepath = f.name
                    for block in self.__buffer.read():
                        f.write(block)

            # Push to GD.

            self.__log.debug("Pushing (%d) bytes for entry with ID from [%s] "
                             "to GD for file-path [%s]." % 
                             (self.__buffer.length, entry.id, write_filepath))

#            print("Sending updates.")

# TODO: Update mtime?
            try:
                entry = drive_proxy('update_entry', 
                                    normalized_entry=entry, 
                                    filename=entry.title, 
                                    data_filepath=write_filepath, 
                                    mime_type=mime_type, 
                                    parents=entry.parents, 
                                    is_hidden=self.__is_hidden)
            except:
                self.__log.exception("Could not localize displaced file with "
                                     "entry having ID [%s]." % (entry.id))
                raise

            if not is_temp:
                unlink(write_filepath)
            else:
                # Update the write-cache file to the official mtime. We won't 
                # redownload it on the next flush if it wasn't changed, 
                # elsewhere.

                self.__log.debug("Updating local write-cache file to official "
                                 "mtime [%s]." % (entry.modified_date_epoch))

                try:
                    utime(write_filepath, (entry.modified_date_epoch, 
                                            entry.modified_date_epoch))
                except:
                    self.__log.exception("Could not update mtime of write-"
                                         "cache [%s] for entry with ID [%s], "
                                         "post-flush." % 
                                         (entry.modified_date_epoch, entry.id))
                    raise

        # Immediately update our current cached entry.

        self.__log.debug("Update successful. Updating local cache.")

        path_relations = PathRelations.get_instance()

        try:
            path_relations.register_entry(entry)
        except:
            self.__log.exception("Could not register updated file in cache.")
            raise

        self.__is_dirty = False

        self.__log.info("Update complete on entry with ID [%s]." % (entry.id))
Example #36
0
    def unlink(self, file_path):
        """Remove a file."""
# TODO: Change to simply move to "trash". Have a FUSE option to elect this
# behavior.
        path_relations = PathRelations.get_instance()

        try:
            entry_clause = path_relations.get_clause_from_path(file_path)
        except GdNotFoundError:
            _logger.exception("Could not process [%s] (unlink).", file_path)
            raise FuseOSError(ENOENT)
        except:
            _logger.exception("Could not get clause from file-path [%s] "
                              "(unlink).", file_path)

            raise FuseOSError(EIO)

        if not entry_clause:
            _logger.error("Path [%s] does not exist for unlink().",
                          file_path)

            raise FuseOSError(ENOENT)

        entry_id = entry_clause[CLAUSE_ID]
        normalized_entry = entry_clause[CLAUSE_ENTRY]

        # Check if a directory.

        if normalized_entry.is_directory:
            _logger.error("Can not unlink() directory [%s] with ID [%s]. "
                          "Must be file.", file_path, entry_id)

            raise FuseOSError(errno.EISDIR)

        # Remove online. Complements local removal (if not found locally, a 
        # follow-up request checks online).

        gd = get_gdrive()

        try:
            gd.remove_entry(normalized_entry)
        except (NameError):
            raise FuseOSError(ENOENT)
        except:
            _logger.exception("Could not remove file [%s] with ID [%s].",
                              file_path, entry_id)

            raise FuseOSError(EIO)

        # Remove from cache. Will no longer be able to be found, locally.

        try:
            PathRelations.get_instance().remove_entry_all(entry_id)
        except:
            _logger.exception("There was a problem removing entry [%s] "
                              "from the caches.", normalized_entry)
            raise

        # Remove from among opened-files.

        om = gdrivefs.gdfs.opened_file.get_om()

        try:
            opened_file = om.remove_by_filepath(file_path)
        except:
            _logger.exception("There was an error while removing all "
                                 "opened-file instances for file [%s] "
                                 "(remove).", file_path)
            raise FuseOSError(EIO)