async def readdir(self, inode, off, token): assert inode == pyfuse3.ROOT_INODE if off < len(self.info_files): info_file = self.info_files[off] pyfuse3.readdir_reply(token, info_file.name, await self.getattr(info_file.inode), off + 1)
async def readdir(self, dir_inode, offset, token): folder = self._inode_to_folder[dir_inode] logger.debug( f'readdir() called for inode {dir_inode} (folder {folder.name}), offset {offset}, token {token}' ) if folder: for i, subfolder in enumerate(folder.children[offset:], offset + 1): inode = self._folder_to_inode[subfolder] attr = await self.getattr(inode) logger.debug( f'Contents: {dir_inode}[{i}] = {inode} (folder {subfolder.name})' ) if not pyfuse3.readdir_reply(token, os.fsencode( subfolder.name), attr, i): return offset = max(0, offset - len(folder.children)) assets = folder.sorted_named_assets[offset:] for i, (name, asset) in enumerate(assets, len(folder.children) + offset + 1): inode = self._folder_asset_to_inode[(folder, asset)] attr = await self.getattr(inode) logger.debug( f'Contents: {dir_inode}[{i}] = {inode} (asset {asset.id})') if not pyfuse3.readdir_reply(token, os.fsencode(name), attr, i): return else: raise FUSEError(errno.ENOENT)
async def readdir(self, fh, start_id, token): assert fh == pyfuse3.ROOT_INODE # only one entry if start_id == 0: pyfuse3.readdir_reply( token, self.hello_name, await self.getattr(self.hello_inode), 1) return
async def readdir(self, inode, off, token): if off == 0: off = -1 cursor2 = self.db.cursor() cursor2.execute( "SELECT * FROM contents WHERE parent_inode=? AND rowid > ? ORDER BY rowid", (inode, off)) for row in cursor2: pyfuse3.readdir_reply(token, row['name'], await self.getattr(row['inode']), row['rowid'])
async def readdir(self, fh, start_id, token): #node = self.packages.get_inode(start_id) #print('readdir',fh, 'off', start_id) '''print(token.size)''' if fh == pyfuse3.ROOT_INODE: for node in self.dirs: if node['inode'] <= start_id: continue name = f"{node['name']}" if not pyfuse3.readdir_reply(token, f"{name}".encode(), await self.getattr(node['inode'] ), node['inode']): break else: node = self.get_node(fh) if not node: return DEBUGPKGNAME = "vlc" if node['name'] == DEBUGPKGNAME: print(' node name', fh, node['name'], 'offset:', start_id) offset = fh * 100000 if start_id >= offset: return # generate symlinks : Dependencies (and optionals ?) # BUG TODO readdir_reply return false after 16 links !!! if fh > 600: # only one level return offset += 10 i = 0 # count bug -> stop always at 17 !!! (vlc, gimp ...) for link in range(5, 48): if fh == link: continue linknode = self.get_file(str(link)) if not linknode: return offset += 1 mode = await self.getattr(linknode['inode']) mode.st_mode = (stat.S_IFLNK | 0o555) mode.st_nlink = linknode['inode'] #print(' link create for:', node['name'], offset, 'target:', linknode['name'], linknode['inode']) if not pyfuse3.readdir_reply( token, f"{linknode['name']}.link".encode(), mode, offset): ''' print(dir(token)) print(f"ERROR readdir_reply (no:{i} , {token['size']}) link: {linknode['name']} inode: {offset} mode_ino: {mode.st_ino} {mode}") ''' return i += 1 return
async def readdir(self, inode, off, token): path = self._inode_to_path(inode) log.debug('reading %s', path) entries = [] for name in os.listdir(path): if name == '.' or name == '..': continue attr = self._getattr(path=os.path.join(path, name)) entries.append((attr.st_ino, name, attr)) log.debug('read %d entries, starting at %d', len(entries), off) # This is not fully posix compatible. If there are hardlinks # (two names with the same inode), we don't have a unique # offset to start in between them. Note that we cannot simply # count entries, because then we would skip over entries # (or return them more than once) if the number of directory # entries changes between two calls to readdir(). for (ino, name, attr) in sorted(entries): if ino <= off: continue if not pyfuse3.readdir_reply( token, fsencode(name), attr, ino): break self._add_path(attr.st_ino, os.path.join(path, name))
async def readdir(self, inode, off, token): path = self._inode_to_path(inode, fullpath=True) log.debug('reading %s', path) parent_id = self._get_degoo_id(path) children = self._get_degoo_childs(parent_id) # If dir has not children and it is lazy mode, degoo it is called to get the content if self._mode == 'lazy' and len(children) == 0: degoo.tree(dir_id=inode, mode=self._mode) self._refresh_path() children = self._get_degoo_childs(parent_id) entries = [] for element in children: attr = self._get_degoo_attrs(element['FilePath']) entries.append((attr.st_ino, element['Name'], attr)) for (ino, name, attr) in sorted(entries): if ino <= off: continue if not pyfuse3.readdir_reply(token, fsencode(name), attr, ino): break self._add_path(attr.st_ino, self._get_degoo_element_path_by_id(attr.st_ino))
async def readdir(self, fh: int, start_index: int, token: pyfuse3.ReaddirToken): """ Read entries in open directory fh. This method should list the contents of directory fh (as returned by a prior opendir call), starting at the entry identified by start_id. Instead of returning the directory entries directly, the method must call readdir_reply for each directory entry. If readdir_reply returns True, the file system must increase the lookup count for the provided directory entry by one and call readdir_reply again for the next entry (if any). If readdir_reply returns False, the lookup count must not be increased and the method should return without further calls to readdir_reply. The start_id parameter will be either zero (in which case listing should begin with the first entry) or it will correspond to a value that was previously passed by the file system to the readdir_reply function in the next_id parameter. If entries are added or removed during a readdir cycle, they may or may not be returned. However, they must not cause other entries to be skipped or returned more than once. . and .. entries may be included but are not required. However, if they are reported the filesystem must not increase the lookup count for the corresponding inodes (even if readdir_reply returns True). """ info = self._get_fh_info(fh) for i, (name, inode) in enumerate(info.children()): if i < start_index: continue if not pyfuse3.readdir_reply(token, name.encode(), await self.getattr(inode), i + 1): break
async def readdir(self, fh, start_id, token): obj = self.fh[fh] async for (name, inode_obj, next_id) in obj.read(start_id): inode = self.inode.allocate(inode_obj) attr = self.__makeattr(inode, inode_obj) if not pyfuse3.readdir_reply(token, name, attr, next_id): self.inode.deallocate(inode) break
async def readdir(self, inode, off, token): if not off: off = -1 path = self._inode_to_path(inode) LOG.info('readdir %s [inode %s]', path, inode) LOG.debug('\toffset %s', off) entries = self._inode2entries[inode] LOG.info('read %d entries, starting at %d', len(entries), off) # Sort them for the offset for (ino, name, entry) in entries: if ino <= off: continue attrs = self._stats2entry(entry) pyfuse3.readdir_reply(token, fsencode(name), attrs, ino) # ignore result?.... or if not: break? return False # over
async def readdir(self, inode, off, token): childs = list(self.files.get_file(inode).content.values()) for i in filter(lambda i: i > off, childs): child = self.files.get_file(i) r = pyfuse3.readdir_reply( token, child.name, self.files.getattr_from_file(child), i ) if not r: return
async def readdir(self, fh, off, token): logvfs.debug("readdir(%s,%s)" % (fh, off)) assert fh == pyfuse3.ROOT_INODE inodes = self.inodes[off:] for idx, inode in enumerate(inodes, off): file = self.files[inode] if not pyfuse3.readdir_reply(token, file.fname, file.attr, idx + 1): break
async def readdir(self, inode, off, token): self.logger.debug("readdir: %s %s", inode, off) entry = self._entry_by_inode(inode) for index, child_inode in enumerate( itertools.islice(entry.childs.values(), off, None), off + 1): child = self._entry_by_inode(child_inode) if not pyfuse3.readdir_reply( token, child.filename.encode(self._filename_encoding), await self._gen_attr(child), index): break return
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)
async def readdir(self, inode: INode, start_id: int, token: ReaddirToken) -> None: dir_path = self.paths[inode] files = [] for fname in pyfuse3.listdir(dir_path): entry_attrs = self._get_entry_attrs(self.paths.join(inode, fname)) if entry_attrs.st_ino > start_id: files.append((entry_attrs.st_ino, fname, entry_attrs)) for ino, fname, entry_attrs in sorted(files): if not pyfuse3.readdir_reply(token, os.fsencode(fname), entry_attrs, ino): break self.paths[ino] = os.path.join(dir_path, fname)
async def readdir(self, inode, start_id, token): """Read entries in open directory *inode*. This method should list the contents of directory *inode* (as returned by a prior `opendir` call), starting at the entry identified by *start_id*. Instead of returning the directory entries directly, the method must call `readdir_reply` for each directory entry. If `readdir_reply` returns True, the file system must increase the lookup count for the provided directory entry by one and call `readdir_reply` again for the next entry (if any). If `readdir_reply` returns False, the lookup count must *not* be increased and the method should return without further calls to `readdir_reply`. The *start_id* parameter will be either zero (in which case listing should begin with the first entry) or it will correspond to a value that was previously passed by the file system to the `readdir_reply` function in the *next_id* parameter. If entries are added or removed during a `readdir` cycle, they may or may not be returned. However, they must not cause other entries to be skipped or returned more than once. :file:`.` and :file:`..` entries may be included but are not required. However, if they are reported the filesystem *must not* increase the lookup count for the corresponding inodes (even if `readdir_reply` returns True). """ self.log.debug("start_id: %s", start_id) dir_path = self.data.get_entry(inode).get_full_path() self.log.debug("dirpath: %s", dir_path) entries = self.data.get_children(inode) self.log.debug("items in dir: %d", len(entries)) try: for entry in entries: inode = entry.inode if inode <= start_id: continue node = self.data.nodes[inode] self.log.debug("Key: %s, Value_name: %s", inode, entry.name) # Omitting swap files. if node.type == Types.SWAP: self.log.debug("swp: %s", entry.name) continue if node.is_invisible() is True: self.log.debug("Node %s is invisible.", entry.name) continue if not pyfuse3.readdir_reply(token, entry.name, await self.getattr(inode), inode): break except Exception as e: self.log.error("Readdir failed.") self.log.error(e) return
async def readdir(self, fh, start_id, token): # TODO: Could probably implement this with a `DirectoryListing` as well. Class decorator to monkey-patch method from a .listing field? logger.trace(f"readdir({fh})") if fh == pyfuse3.ROOT_INODE: for num, sub in self: if num < start_id: continue if not pyfuse3.readdir_reply(token, sub.name.encode('utf-8'), await sub.getattr(sub.root_inode ), num + 1): return else: fuse_assert(fh in self.open_handles) inode, deref = self.open_handles[fh] # deref() is not None as each SubFS instance is in memory for the life of the program return await deref().readdir(inode, start_id, token)
async def readdir(self, inode, off, token): path = self._inode_to_path(inode) log.debug('reading %s', path) entries = [] for name in os.listdir(path): if name == '.' or name == '..': continue attr = self._getattr(path=os.path.join(path, name)) entries.append((attr.st_ino, name, attr)) log.debug('read %d entries, starting at %d', len(entries), off) for (ino, name, attr) in sorted(entries): if ino <= off: continue if not pyfuse3.readdir_reply(token, fsencode(name), attr, ino): break self._add_path(attr.st_ino, os.path.join(path, name))
async def readdir(self, inode, off, token): self.logger.debug("readdir: %s %s", inode, off) assert inode == pyfuse3.ROOT_INODE filelist = ['.', '..'] try: filelist.extend(self.gridfs.list()) except: raise pyfuse3.FUSEError(errno.ENOTDIR) for index, filename in enumerate(itertools.islice(filelist, off, None), off + 1): bname = filename.encode(self._filename_encoding) if not pyfuse3.readdir_reply(token, bname, await self.lookup( inode, bname), index): break return
async def readdir(self, vnode, offset, token): vinfo_p = self.vm[vnode] _opslog.debug('readdir called: {}'.format(vinfo_p.path)) entries = self._listdir(vinfo_p) _opslog.debug('read %d entries, starting at %d', len(entries), offset) # FIXME: result is break if entries is changed between two calls to readdir() for (ino, name, attr) in sorted(entries): if ino <= offset: continue assert ino in self.vm vinfo_c = self.vm[ino] want_next_entry = pyfuse3.readdir_reply(token, os.fsencode(name), attr, ino) if not want_next_entry: if vinfo_c.refcount == 0: # if newly created in the above code del vinfo_c break # Don't count up reference count if want_next_entry is False path_c = self.vm.make_path(vinfo_p.path, name) vinfo_c.add_path(path_c)
async def readdir(self, id_, off, token): log.debug('started with %d, %d', id_, off) if off == 0: off = -1 inode = self.inodes[id_] if inode.atime_ns < inode.ctime_ns or inode.atime_ns < inode.mtime_ns: inode.atime_ns = time_ns() # NFS treats offsets 1 and 2 special, so we have to exclude # them. with self.db.query( "SELECT name_id, name, inode FROM contents_v " 'WHERE parent_inode=? AND name_id > ? ORDER BY name_id', (id_, off - 3)) as res: for (next_, name, cid_) in res: if not pyfuse3.readdir_reply( token, name, self.inodes[cid_].entry_attributes(), next_ + 3): break self.open_inodes[cid_] += 1
async def readdir(self, vnode, offset, token): vinfo_p = self.vm[vnode] entries = self._readdir(vinfo_p) _opslog.debug('read %d entries, starting at %d', len(entries), offset) # FIXME: result is break if entries is changed between two calls to readdir() if entries: # asking empty directory? when? assert len(tuple(zip(*entries))[0]) == len( set(tuple(zip(*entries))[0])) # entries must not duplicate for ino, name, attr in sorted(entries): if ino <= offset: continue assert ino in self.vm vinfo_c = self.vm[ino] want_next_entry = pyfuse3.readdir_reply(token, os.fsencode(name), attr, ino) if not want_next_entry: if vinfo_c.refcount == 0: # if newly created in the above code del vinfo_c break # Don't count up reference count if want_next_entry is False path_c = self.vm.make_path(vinfo_p.path, name) vinfo_c.add_path(path_c) _acslog.debug('READDIR: {}'.format(vinfo_p.path))
async def readdir(self, fh: int, offset: int, token: pyfuse3.ReaddirToken) -> None: """ Read entries in an open directory """ # opendir() uses inode as directory handle inode = fh direntry = self.inode2entry(inode) self.logger.debug("readdir(dirname=%s, fh=%d, offset=%d)", direntry.name, fh, offset) assert isinstance(direntry, FuseDirEntry) next_id = offset + 1 try: async for entry in direntry.get_entries(offset): name = os.fsencode(entry.name) attrs = await self.get_attrs(entry) if not pyfuse3.readdir_reply(token, name, attrs, next_id): break next_id += 1 self._inode2entry[attrs.st_ino] = entry except Exception as err: self.logger.exception("Cannot readdir: %s", err) raise pyfuse3.FUSEError(errno.ENOENT)
async def readdir(self, fh, start_id, token): for inode, name in self.listings[fh].list_from(start_id): if not pyfuse3.readdir_reply(token, name.encode('utf-8'), await self.getattr(inode), inode + 1): return
async def readdir(self, fh, start_id, token): #node = self.packages.get_inode(start_id) #print('readdir',fh, 'off', start_id) if fh == pyfuse3.ROOT_INODE: for node in self.packages.pkgs: if node.inode <= start_id: continue name = f"{node.name}" if not pyfuse3.readdir_reply(token, f"{name}".encode(), await self.getattr(node.inode), node.inode): break else: node = self.packages.get_inode(fh) if not node: return DEBUGPKGNAME="vlc" if node.name == DEBUGPKGNAME: print(' node name', fh, node.name, 'offset:', start_id) p = self.packages.handle.get_localdb().get_pkg(node.name) offset = fh * 100000 if start_id >= offset: return # generate virtual files for vfile in Fields: offset = (fh * 100000) + vfile.value virtual = VirtualFile.factory(vfile.value, node) virtual.pkg = p if not virtual.readdir_reply(token, await virtual.get_attr(fh, offset), offset): return # generate symlinks : Dependencies (and optionals ?) # BUG TODO readdir_reply return false after 16 links !!! offset += 10 i = 0 # count bug -> stop always at 17 !!! (vlc, gimp ...) for dep in p.depends: deps = dep.split('>', 1) linknode = self.packages.get_file(deps[:1][0]) if not linknode: return offset += 1 mode = await self.getattr(linknode.inode) mode.st_mode = (stat.S_IFLNK | 0o555) mode.st_nlink = linknode.inode if node.name == DEBUGPKGNAME: print(' link create dep for:', node.name, offset, 'target:', linknode.name, linknode.inode) if not pyfuse3.readdir_reply(token, f"{linknode.name}.dep".encode(), mode, offset): print(dir(token)) print(f"ERROR readdir_reply ({i} , {token}) link: {linknode.name} inode: {offset} mode_ino: {mode.st_ino} {mode}") return i += 1 if node.name == DEBUGPKGNAME: print("optionals:", offset, p.optdepends) for dep in p.optdepends: if node.name == DEBUGPKGNAME: print(" ? opt:", dep, "->", dep.split(':', 1)[:1][0] ) linknode = self.packages.get_file(dep.split(':', 1)[:1][0]) if not linknode: return offset += 1 mode = await self.getattr(linknode.inode) mode.st_mode = (stat.S_IFLNK | 0o555) mode.st_nlink = linknode.inode if node.name == DEBUGPKGNAME: print(' link create opt dep for:', node.name, offset, 'target:', linknode.name, linknode.inode) if not pyfuse3.readdir_reply(token, f"{linknode.name}.optional.dep".encode(), mode, offset): print(f"ERROR readdir_reply optional link: {linknode.name} inode: {offset}") return #pkg = self.packages.handle.get_localdb().get_pkg(dep) return
def readdir_reply(self, token, datas, inode): """ add one entry in package virtual directory """ return pyfuse3.readdir_reply(token, self.filename.encode(), datas, inode)
else: entries = () log.debug('read %d entries, starting at %d', len(entries), off) # This is not fully posix compatible. If there are hardlinks # (two names with the same inode), we don't have a unique # offset to start in between them. Note that we cannot simply # count entries, because then we would skip over entries # (or return them more than once) if the number of directory # entries changes between two calls to readdir(). for (ino, name, attr) in sorted(entries): if ino <= off: continue log.debug(f"{ino} {name}, {attr}") if not pyfuse3.readdir_reply( token, fsencode(name), attr, ino): break self._add_path(attr.st_ino, os.path.join(path, name)) # path methods # ============ async def readlink(self, inode, ctx): path = self._inode_to_path(inode) try: target = os.readlink(path) except OSError as exc: raise FUSEError(exc.errno) return fsencode(target) async def link(self, inode, new_inode_p, new_name, ctx):
async def readdir(self, fh, start_id, token): for row in self.db.get_inodes_from_parent(fh, start_id): entry = self._to_entry(row) if not pyfuse3.readdir_reply(token, row['name'], entry, row['link_id']): break
async def readdir(self, inode, off, token): l.debug("readdir: inode=%r, off=%r, token=%r", inode, off, token) if off < 1: pyfuse3.readdir_reply(token, BASHFS_RUN, await self.lookup(inode, BASHFS_RUN), 1) return None
async def readdir(self, fh, off, token): assert fh == pyfuse3.ROOT_INODE if off == 0: pyfuse3.readdir_reply(token, self.hello_name, await self.getattr(self.hello_inode), 1) return