{"record":{"id":"943cdc339a26e4e4","repo":"moonD4rk/HackBrowserData","slug":"locked-copy-w","errorCode":null,"errorMessage":"locked copy: %w","messagePattern":"locked copy: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"filemanager/session.go","lineNumber":54,"sourceCode":"// On Windows, if the normal copy fails (e.g. file locked by Chrome),\n// it falls back to DuplicateHandle + FileMapping to bypass exclusive locks.\nfunc (s *Session) Acquire(src, dst string, isDir bool) error {\n\tif isDir {\n\t\treturn copyDir(src, dst, \"lock\")\n\t}\n\n\t// Try normal copy first\n\terr := copyFile(src, dst)\n\tif err != nil {\n\t\t// Only attempt locked-file fallback on Windows where Chrome holds exclusive locks.\n\t\t// On other platforms, return the original error directly.\n\t\tif runtime.GOOS != \"windows\" {\n\t\t\treturn fmt.Errorf(\"copy: %w\", err)\n\t\t}\n\t\tif err2 := copyLocked(src, dst); err2 != nil {\n\t\t\treturn errors.Join(\n\t\t\t\tfmt.Errorf(\"copy: %w\", err),\n\t\t\t\tfmt.Errorf(\"locked copy: %w\", err2),\n\t\t\t)\n\t\t}\n\t}\n\n\t// Copy SQLite WAL/SHM companion files if present\n\tvar walErrs []error\n\tfor _, suffix := range []string{\"-wal\", \"-shm\"} {\n\t\twalSrc := src + suffix\n\t\tif isFileExists(walSrc) {\n\t\t\tif err := copyFile(walSrc, dst+suffix); err != nil {\n\t\t\t\twalErrs = append(walErrs, fmt.Errorf(\"copy %s: %w\", suffix, err))\n\t\t\t}\n\t\t}\n\t}\n\treturn errors.Join(walErrs...)\n}\n\n// Cleanup removes the session's temporary directory and all its contents.","sourceCodeStart":36,"sourceCodeEnd":72,"githubUrl":"https://github.com/moonD4rk/HackBrowserData/blob/0503d04d7a8d0379d060268a74f1b149e5a0aad5/filemanager/session.go#L36-L72","documentation":"Acquire wraps the copyLocked fallback failure with \"locked copy: %w\" and joins it with the original \"copy: %w\" error. This fires only on Windows when BOTH the normal copy failed (file locked by the browser) AND the handle-duplication/file-mapping bypass also failed, meaning the locked file could not be extracted by any available means.","triggerScenarios":"Windows-only. Session.Acquire on a file Chrome/Edge holds with exclusive locking_mode where copyFile fails, and copyLocked subsequently fails — e.g. no process currently has the file open (stale lock from a crashed browser), handle enumeration denied, MapFile/ReadFile/Seek failure inside readFileContent, or os.WriteFile to the destination failing.","commonSituations":"Browser killed uncleanly leaving orphaned locks but no open handles; other instances of the tool or EDR software blocking NtQuerySystemInformation handle enumeration; 32-bit handle-enumeration limitations on large handle tables; destination disk full making the final os.WriteFile fail.","solutions":["Retry after closing the browser normally — most extraction failures of this kind are transient lock races.","Check that the target file actually exists and a live process holds it (the joined error often includes \"no process has file open\").","Ensure no EDR/AV policy blocks handle enumeration (NtQuerySystemInformation) for the tool's process.","Free destination disk space — the final write of the recovered content can also fail."],"exampleFix":"// before\nif err := s.Acquire(src, dst, false); err != nil {\n    return err\n}\n// after\nif err := s.Acquire(src, dst, false); err != nil {\n    log.Warnf(\"acquire %s failed (possibly locked): %v\", src, err)\n    return fmt.Errorf(\"acquire %s: %w\", src, err) // surface both copy and locked-copy branches\n}","handlingStrategy":"fallback","validationCode":"// detect a live browser process before relying on the locked-copy fallback\n// (fallback needs a process that actually holds the file open)\nout, err := exec.Command(\"tasklist\", \"/FI\", \"IMAGENAME eq chrome.exe\").Output()\nif err != nil || !strings.Contains(strings.ToLower(string(out)), \"chrome\") {\n    log.Warn(\"chrome not running: locked-copy fallback will fail with 'no process has file open'\")\n}","typeGuard":null,"tryCatchPattern":"// Go: split the joined error to handle each branch\nif err := s.Acquire(src, dst, false); err != nil {\n    for _, e := range errors.UnwrapMulti(err) { // or iterate joined errors\n        log.Warnf(\"acquire branch failed: %v\", e)\n    }\n    return err\n}","preventionTips":["Have the target browser running when extraction needs the locked-copy path","Avoid killing browsers uncleanly (orphaned locks but no open handles)","Ensure EDR policy permits NtQuerySystemInformation handle enumeration"],"tags":["windows","locked-file","file-copy","handle-duplication","browser-lock"],"backgroundTag":"file-read-failed","analyzedSha":"0503d04d7a8d0379d060268a74f1b149e5a0aad5","analyzedAt":"2026-09-06T13:38:28.707Z","contentChangedAt":"2026-09-06T13:38:28.707Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}