read_other.odin (1931B)
1 #+build !linux 2 package walk 3 4 import "core:os" 5 import "core:strings" 6 7 /* 8 Read one directory through core:os. 9 10 The reader that works anywhere. core:os describes every entry in full and this keeps 11 the part the tree records, which is most of what it costs: not knowing the platform 12 means not knowing which of that description was worth asking for. 13 */ 14 @(private) 15 read_dir :: proc(d: Dir, w: ^Worker) -> (nodes, bytes: u64, ok: bool) { 16 f, open_err := os.open(d.path) 17 if open_err != nil { 18 return 0, 0, false 19 } 20 defer os.close(f) 21 22 it := os.read_directory_iterator_create(f) 23 defer os.read_directory_iterator_destroy(&it) 24 25 for info in os.read_directory_iterator(&it) { 26 if _, err := os.read_directory_iterator_error(&it); err != nil { 27 continue 28 } 29 e := Entry { 30 name = info.name, 31 size = u64(max(info.size, 0)), 32 directory = info.type == .Directory, 33 symlink = info.type == .Symlink, 34 } 35 if !e.directory && !e.symlink { 36 // core:os reports the logical length and nothing about allocation, so the 37 // on-disk figure is the best estimate available here: the size rounded up 38 // to a block. 39 e.disk = round_up(e.size, BLOCK_ESTIMATE) 40 } 41 index, descend, recorded := record(w, d.index, e) 42 if !recorded { 43 return nodes, bytes, false 44 } 45 if descend { 46 path, clone_err := strings.clone(info.fullpath, w.allocator) 47 if clone_err != nil { 48 w.err = .Out_Of_Memory 49 return nodes, bytes, false 50 } 51 append(&w.found, Dir{index = index, path = path}) 52 } 53 nodes += 1 54 bytes += e.disk 55 } 56 return nodes, bytes, true 57 } 58 59 // Without filesystem-specific knowledge the allocation unit is a guess, and four 60 // kilobytes is the common one. It makes small files cost something rather than 61 // nothing, which matters more than being exactly right. 62 @(private) 63 BLOCK_ESTIMATE :: 4096 64 65 @(private) 66 round_up :: proc(v, unit: u64) -> u64 { 67 if v == 0 { 68 return 0 69 } 70 return (v + unit - 1) / unit * unit 71 }