Exemple #1
0
    async def mknod(self, parent_inode, name, mode, rdev, ctx):
        _inode = BDFile.get_from_fs_id(parent_inode)
        if not _inode:
            path = '/'
            full_path = path
        else:
            path = _inode.path
            full_path = path + '/'

        name_bytes = name
        name = name.decode('utf-8')

        tmp = is_tmp(name)
        if Env.CLOUD_HOME not in path:
            raise pyfuse3.FUSEError(errno.EACCES)
        if not os.path.isdir(Env.PHYSICS_DIR + path):
            os.makedirs(Env.PHYSICS_DIR + path)

        file_path = Env.PHYSICS_DIR + full_path + name
        if tmp:
            with open(file_path, 'wb') as f:
                f.write(b'')
            inode = random.randint(1000000000000000000, 9999999999999999999)
            ns = (datetime.now().timestamp() * 1e9)
            _cache = self.fs.cache.get(path, None)
            _file = BDFile(isdir=False,
                           server_ctime=ns,
                           server_mtime=ns,
                           local_ctime=ns,
                           local_mtime=ns,
                           fs_id=inode,
                           path=full_path + name,
                           filename=name,
                           filename_bytes=name_bytes,
                           size=0,
                           p_inode=parent_inode)
            BDFile.set_inode_name_pool(parent_inode, name, _file)
            if not _cache:
                self.fs.cache[path] = {
                    'items': [_file],
                    'expire':
                    datetime.now().timestamp() + BaiDu.DIR_EXPIRE_THRESHOLD
                }
            else:
                self.fs.cache[path]['items'].append(_file)
            return await self.getattr(inode, ctx)

        with open(file_path, 'wb') as f:
            f.write(Env.EMPTY_FILE_FLAG)
        upload_path = full_path + name
        # 因为百度不允许创建空文件,这里使用占位符上传临时文件
        fs_id = self.fs.upload(parent_inode, file_path, upload_path)
        if fs_id:
            UploadInfo.add(parent_inode, fs_id, file_path, upload_path)
            # 上传成功后将本地临时文件删除,在写入时重新创建,避免文件写入内容包含占位符
            # os.remove(file_path)
            return await self.getattr(fs_id, ctx)
        raise pyfuse3.FUSEError(errno.EAGAIN)
Exemple #2
0
 def rm(self, p_inode, name):
     f = BDFile.get_from_inode_name(p_inode, name)
     if not f:
         return
     self.__rm_with_path(f.path)
     BDFile.clear_f_cache(p_inode, f)
     rdx = f.path.rindex('/')
     path = '/' if rdx == 0 else f.path[:rdx]
     self.dir_cache(path, p_inode, force=True)
Exemple #3
0
 def __rm(self, p_inode, name):
     if is_tmp(name):
         f = BDFile.get_from_inode_name(p_inode, name)
         if not f:
             return
         try:
             os.remove(Env.PHYSICS_DIR + f.path)
             self.fs.dir_cache(f.path[:f.path.rindex('/')],
                               p_inode,
                               force=True)
             BDFile.del_inode_name_pool(p_inode, name)
         except FileNotFoundError as _:
             return
     self.fs.rm(p_inode, name)
Exemple #4
0
    async def getattr(self, inode, ctx):
        """
        这个方法需要返回文件或文件夹的基本信息,实际上inode为文件或文件夹的索引节点
        因为实现的是网盘文件系统,所以此处虽说物理上不一样,但逻辑上是一样的,在这里我用文件的独立标识fs_id作为inode
        根目录没有inode,默认为1,所以此处判断一下如果inode等于根inode的话,直接将返回设置为目录
        :param inode:
        :param ctx:
        :return:
        """
        entry = pyfuse3.EntryAttributes()
        entry.generation = 0
        entry.entry_timeout = 300
        entry.attr_timeout = 300
        if inode == pyfuse3.ROOT_INODE:
            entry.st_mode = (stat.S_IFDIR | 0o755)
            entry.st_nlink = 0
            entry.st_size = 0
        else:
            f = BDFile.get_from_fs_id(inode)
            entry.st_mode = (stat.S_IFDIR
                             | 0o755) if f.isdir else (stat.S_IFREG | 0o755)
            entry.st_size = f.size
            entry.st_nlink = 1
            entry.st_atime_ns = int(f.server_mtime * 1e9)
            entry.st_ctime_ns = int(f.server_ctime * 1e9)
            entry.st_mtime_ns = int(f.server_mtime * 1e9)
            inode = f.fs_id

        entry.st_rdev = 0
        entry.st_blksize = 512
        entry.st_blocks = 1
        entry.st_gid = os.getgid()
        entry.st_uid = os.getuid()
        entry.st_ino = inode
        return entry
Exemple #5
0
 async def fsync(self, fh, datasync):
     f = BDFile.get_from_fs_id(fh)
     if not f:
         return
     p_path = f.path[:f.path.rindex('/')]
     self.fs.info_cache(f.path, f.fs_id, force=True)
     self.fs.dir_cache(p_path, f.p_inode, force=True)
Exemple #6
0
 def dir(self, d='/', inode=None):
     """
     从百度云盘获取文件列表
     :param inode:
     :param d: 路径
     :return:
     """
     res = self.__request(BaiDu.LIST, {'dir': d}, 'GET')
     return BDFile.from_json_list(res.get('list', []), inode)
Exemple #7
0
 async def mkdir(self, parent_inode, name, mode, ctx):
     if parent_inode == pyfuse3.ROOT_INODE:
         path = '/'
     else:
         f = BDFile.get_from_fs_id(parent_inode)
         path = f.path + '/'
     inode = self.fs.mkdir(parent_inode, path, name.decode('utf-8'))
     if not inode:
         raise pyfuse3.FUSEError(errno.EEXIST)
     return await self.getattr(inode, ctx)
Exemple #8
0
 async def read(self, fh, off, size):
     f = BDFile.get_from_fs_id(fh)
     if not f:
         return b''
     else:
         if is_tmp(f.filename):
             try:
                 with open(Env.PHYSICS_DIR + f.path, 'rb') as f:
                     f.seek(off)
                     res = f.read(size)
             except FileNotFoundError as _:
                 return b''
         else:
             res = self.fs.download(f, off, size)
         return res
Exemple #9
0
 async def setattr(self, inode, attr, fields, fh, ctx):
     f = BDFile.get_from_fs_id(inode)
     if fields.update_size:
         f.size = attr.st_size
     if fields.update_mode:
         pass
     if fields.update_uid:
         pass
     if fields.update_gid:
         pass
     if fields.update_atime:
         f.server_atime = datetime.now().timestamp()
     if fields.update_mtime:
         f.server_mtime = datetime.now().timestamp()
     if fields.update_ctime:
         f.server_ctime = datetime.now().timestamp()
     return await self.getattr(inode, ctx)
Exemple #10
0
 def mv(self, p_inode_old, name_old, p_inode_new, name_new):
     old_f = BDFile.get_from_inode_name(p_inode_old, name_old)
     new_path = '/'
     if p_inode_new == 1:
         self.__mv_with_path(old_f.path, new_path, name_new)
     else:
         new_f = BDFile.get_from_fs_id(p_inode_new)
         if new_f is not None:
             new_path = new_f.path
             self.__mv_with_path(old_f.path, new_path, name_new)
         BDFile.clear_f_cache(p_inode_new, new_f)
     BDFile.clear_f_cache(p_inode_old, old_f)
     rdx = old_f.path.rindex('/')
     path = '/' if rdx == 0 else old_f.path[:rdx]
     self.dir_cache(path, p_inode_old, force=True)
     self.dir_cache(new_path, p_inode_new, force=True)
Exemple #11
0
 async def readdir(self, fh, start_id, token):
     """
     读取目录信息,这个方法会被频繁调用
     所以为了防止百度因为频繁请求封了账号这里加缓存默认1个小时更新保险一点,默认值在entity.Env里可以调整
     缺点就是网页版或者客户端中的更新就不会那么实时了
     因为这个方法会不断的被执行, 所以这里需要加文件列表数量校验
     调试中看来start_id会一直更新,除非切换了inode也就是参数上的fh,(fh逻辑上算是唯一标识,相当于切换了目录的话,start_id就会从0开始)
     需要注意的是这里的inode实际上并不一定是文件系统理解中的inode,但逻辑上是一样的,每个目录和文件都需要有inode。
     此处根目录没有,所以做判断 如果fh(inode) = 根inode 则默认获取根目录列表
     :param fh: fh(inode) 逻辑上的inode,用作文件或文件夹的唯一标识
     :param start_id: start_id 是 pyfuse3.readdir_reply 的最后一个参数,会作为未来的readdir调用参数传入, 应当用作读取区间的标识,
     上层不会一次性读取所有的值, 而是会分多次调用readdir,传入start_id 取不同的区间,实现上需要从start_id开始读取到目录最大下标, 需要注意这点
     :param token:
     :return:
     """
     f = BDFile.get_from_fs_id(fh)
     files = self.fs.dir_cache('/' if not f else f.path,
                               pyfuse3.ROOT_INODE if not f else f.fs_id)
     max_len = len(files)
     for i in range(start_id, max_len):
         pyfuse3.readdir_reply(token, files[i].filename_bytes, await
                               self.getattr(files[i].fs_id, None), i + 1)
Exemple #12
0
 def rename(self, p_inode_old, name_old, name_new):
     f = BDFile.get_from_inode_name(p_inode_old, name_old)
     path = '/' if p_inode_old == 1 else f.path + '/'
     self.__rename(path + name_old, name_new)
     BDFile.clear_f_cache(p_inode_old, f)
     self.dir_cache(path, p_inode_old, force=True)
Exemple #13
0
 async def lookup(self, parent_inode, name, ctx):
     f = BDFile.get_from_inode_name(parent_inode, name)
     if not f:
         raise pyfuse3.FUSEError(errno.ENOENT)
     return await self.getattr(f.fs_id, ctx)
Exemple #14
0
 async def write(self, fh, off, buf):
     node = BDFile.get_from_fs_id(fh)
     file_path = Env.PHYSICS_DIR + node.path
     while buf:
         return await self.__do_write(file_path, off, buf)