{"record":{"id":"bcc93f0582e22baa","repo":"MuntashirAkon/AppManager","slug":"ebadf","errorCode":"EBADF","errorMessage":"Supplied path is not a Linux path.","messagePattern":"Supplied path is not a Linux path\\.","errorType":"error_code","errorClass":"ErrnoException","httpStatus":null,"severity":"error","filePath":"app/src/main/java/io/github/muntashirakon/io/Paths.java","lineNumber":557,"sourceCode":"            // Other types of files aren't supported\n            return 0;\n        }\n        long length = 0;\n        Path[] files = root.listFiles();\n        for (Path file : files) {\n            if (ThreadUtils.isInterrupted()) {\n                // Size could be too long\n                return length;\n            }\n            length += size(file);\n        }\n        return length;\n    }\n\n    public static void chmod(@NonNull Path path, int mode) throws ErrnoException {\n        ExtendedFile file = path.getFile();\n        if (file == null) {\n            throw new ErrnoException(\"Supplied path is not a Linux path.\", OsConstants.EBADF);\n        }\n        file.setMode(mode);\n    }\n\n    public static void chown(@NonNull Path path, int uid, int gid) throws ErrnoException {\n        ExtendedFile file = path.getFile();\n        if (file == null) {\n            throw new ErrnoException(\"Supplied path is not a Linux path.\", OsConstants.EBADF);\n        }\n        file.setUidGid(uid, gid);\n    }\n\n    /**\n     * Set owner and mode of given path.\n     *\n     * @param mode to apply through {@code chmod}\n     * @param uid  to apply through {@code chown}, or -1 to leave unchanged\n     * @param gid  to apply through {@code chown}, or -1 to leave unchanged","sourceCodeStart":539,"sourceCodeEnd":575,"githubUrl":"https://github.com/MuntashirAkon/AppManager/blob/0152f468fc9463ee02dc2ca83f6fe4989a2c4ca5/app/src/main/java/io/github/muntashirakon/io/Paths.java#L539-L575","documentation":"Paths.chmod wraps ExtendedFile.setMode and requires the Path to be backed by a real Linux (ext4/FUSE) file via path.getFile(). When the Path is not Linux-backed (e.g. a SAF/ContentProvider document or virtual filesystem node), getFile() returns null and an ErrnoException with EBADF is thrown.","triggerScenarios":"Calling Paths.chmod(path, mode) (directly or via Path.setPermissions) on a Path whose underlying file is a SAF document, a content:// Uri, or any non-ExtendedFile backing where Path.getFile() returns null.","commonSituations":"Trying to set permissions on a file picked through the Storage Access Framework or on a virtual/mounted node; code assuming all Paths are filesystem-backed after migrating from java.io.File.","solutions":["Verify the path is Linux-backed (path.getFile() != null) before calling chmod.","Restrict permission changes to files under real filesystem locations (e.g. app-specific or /storage paths), not content:// documents.","For SAF documents, skip chmod or use the documents-contract APIs that support flags instead.","Catch the ErrnoException with code EBADF and surface a clear 'operation not supported on this path type' message."],"exampleFix":"// before\nPaths.chmod(path, mode);\n// after\nExtendedFile f = path.getFile();\nif (f == null) throw new UnsupportedOperationException(\"Not a Linux path: \" + path);\nPaths.chmod(path, mode);","handlingStrategy":"type-guard","validationCode":"boolean canChmod = path.getFile() != null;","typeGuard":"static boolean isLinuxPath(Path p) { return p != null && p.getFile() != null; }","tryCatchPattern":"try {\n    Paths.chmod(path, mode);\n} catch (ErrnoException e) {\n    if (e.code == OsConstants.EBADF) {\n        // not a Linux path: skip or warn\n    } else throw e;\n}","preventionTips":["Only apply Unix permission operations to Linux-backed paths.","Treat SAF/content:// paths as permission-opaque and handle them with provider APIs.","Centralize permission changes behind a helper that checks getFile() first."],"tags":["filesystem","permissions","android","errno"],"backgroundTag":"permission-denied","analyzedSha":"0152f468fc9463ee02dc2ca83f6fe4989a2c4ca5","analyzedAt":"2026-09-12T14:03:37.243Z","contentChangedAt":"2026-09-12T14:03:37.243Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}