go-hep.org/x/hep@v0.38.1/xrootd/xrdfs/stat.go (about) 1 // Copyright ©2018 The go-hep Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package xrdfs // import "go-hep.org/x/hep/xrootd/xrdfs" 6 7 import ( 8 "bytes" 9 "fmt" 10 "os" 11 "strconv" 12 "time" 13 14 "go-hep.org/x/hep/xrootd/internal/xrdenc" 15 ) 16 17 // StatFlags identifies the entry's attributes. 18 type StatFlags int32 19 20 const ( 21 // StatIsFile indicates that entry is a regular file if no other flag is specified. 22 StatIsFile StatFlags = 0 23 // StatIsExecutable indicates that entry is either an executable file or a searchable directory. 24 StatIsExecutable StatFlags = 1 25 // StatIsDir indicates that entry is a directory. 26 StatIsDir StatFlags = 2 27 // StatIsOther indicates that entry is neither a file nor a directory. 28 StatIsOther StatFlags = 4 29 // StatIsOffline indicates that the file is not online (i. e., on disk). 30 StatIsOffline StatFlags = 8 31 // StatIsReadable indicates that read access to that entry is allowed. 32 StatIsReadable StatFlags = 16 33 // StatIsWritable indicates that write access to that entry is allowed. 34 StatIsWritable StatFlags = 32 35 // StatIsPOSCPending indicates that the file was created with kXR_posc and has not yet been successfully closed. 36 // kXR_posc is an option of open request indicating that the "Persist On Successful Close" processing is enabled and 37 // the file will be persisted only when it has been explicitly closed. 38 StatIsPOSCPending StatFlags = 64 39 ) 40 41 // EntryStat holds the entry name and the entry stat information. 42 type EntryStat struct { 43 EntryName string // EntryName is the name of entry. 44 HasStatInfo bool // HasStatInfo indicates if the following stat information is valid. 45 ID int64 // ID is the OS-dependent identifier assigned to this entry. 46 EntrySize int64 // EntrySize is the decimal size of the entry. 47 Flags StatFlags // Flags identifies the entry's attributes. 48 Mtime int64 // Mtime is the last modification time in Unix time units. 49 } 50 51 // EntryStatFrom creates an EntryStat that represents same information as the provided info. 52 func EntryStatFrom(info os.FileInfo) EntryStat { 53 es := EntryStat{ 54 EntryName: info.Name(), 55 EntrySize: info.Size(), 56 Mtime: info.ModTime().Unix(), 57 HasStatInfo: true, 58 } 59 if info.IsDir() { 60 es.Flags |= StatIsDir 61 } 62 if info.Mode()&0400 != 0 { 63 es.Flags |= StatIsReadable 64 } 65 if info.Mode()&0200 != 0 { 66 es.Flags |= StatIsWritable 67 } 68 return es 69 } 70 71 // Name implements os.FileInfo. 72 func (es EntryStat) Name() string { 73 return es.EntryName 74 } 75 76 // Size implements os.FileInfo. 77 func (es EntryStat) Size() int64 { 78 return es.EntrySize 79 } 80 81 // ModTime implements os.FileInfo. 82 func (es EntryStat) ModTime() time.Time { 83 return time.Unix(es.Mtime, 0) 84 } 85 86 // Sys implements os.FileInfo. 87 func (es EntryStat) Sys() any { 88 return nil 89 } 90 91 // Mode implements os.FileInfo. 92 func (es EntryStat) Mode() os.FileMode { 93 var mode os.FileMode 94 if es.IsDir() { 95 mode |= os.ModeDir 96 } 97 if es.IsWritable() { 98 mode |= 0222 99 } 100 if es.IsReadable() { 101 mode |= 0444 102 } 103 return mode 104 } 105 106 // IsExecutable indicates whether this entry is either an executable file or a searchable directory. 107 func (es EntryStat) IsExecutable() bool { 108 return es.Flags&StatIsExecutable != 0 109 } 110 111 // IsDir indicates whether this entry is a directory. 112 func (es EntryStat) IsDir() bool { 113 return es.Flags&StatIsDir != 0 114 } 115 116 // IsOther indicates whether this entry is neither a file nor a directory. 117 func (es EntryStat) IsOther() bool { 118 return es.Flags&StatIsOther != 0 119 } 120 121 // IsOffline indicates whether this the file is not online (i. e., on disk). 122 func (es EntryStat) IsOffline() bool { 123 return es.Flags&StatIsOffline != 0 124 } 125 126 // IsReadable indicates whether this read access to that entry is allowed. 127 func (es EntryStat) IsReadable() bool { 128 return es.Flags&StatIsReadable != 0 129 } 130 131 // IsWritable indicates whether this write access to that entry is allowed. 132 func (es EntryStat) IsWritable() bool { 133 return es.Flags&StatIsWritable != 0 134 } 135 136 // IsPOSCPending indicates whether this the file was created with kXR_posc and has not yet been successfully closed. 137 // kXR_posc is an option of open request indicating that the "Persist On Successful Close" processing is enabled and 138 // the file will be persisted only when it has been explicitly closed. 139 func (es EntryStat) IsPOSCPending() bool { 140 return es.Flags&StatIsPOSCPending != 0 141 } 142 143 // MarshalXrd implements xrdproto.Marshaler. 144 func (o EntryStat) MarshalXrd(wBuffer *xrdenc.WBuffer) error { 145 if !o.HasStatInfo { 146 return nil 147 } 148 149 idStr := strconv.Itoa(int(o.ID)) 150 sizeStr := strconv.Itoa(int(o.EntrySize)) 151 flagsStr := strconv.Itoa(int(o.Flags)) 152 mtimeStr := strconv.Itoa(int(o.Mtime)) 153 154 wBuffer.WriteBytes([]byte(idStr + " " + sizeStr + " " + flagsStr + " " + mtimeStr)) 155 return nil 156 } 157 158 // UnmarshalXrd implements xrdproto.Unmarshaler. 159 func (o *EntryStat) UnmarshalXrd(rBuffer *xrdenc.RBuffer) error { 160 var buf []byte 161 for rBuffer.Len() != 0 { 162 b := rBuffer.ReadU8() 163 if b == '\x00' || b == '\n' { 164 break 165 } 166 buf = append(buf, b) 167 } 168 169 stats := bytes.Split(buf, []byte{' '}) 170 if len(stats) < 4 { 171 return fmt.Errorf("xrootd: statinfo \"%s\" doesn't have enough fields, expected format is: \"id size flags modtime\"", buf) 172 } 173 174 id, err := strconv.Atoi(string(stats[0])) 175 if err != nil { 176 return err 177 } 178 size, err := strconv.Atoi(string(stats[1])) 179 if err != nil { 180 return err 181 } 182 flags, err := strconv.Atoi(string(stats[2])) 183 if err != nil { 184 return err 185 } 186 mtime, err := strconv.Atoi(string(stats[3])) 187 if err != nil { 188 return err 189 } 190 191 o.HasStatInfo = true 192 o.ID = int64(id) 193 o.EntrySize = int64(size) 194 o.Mtime = int64(mtime) 195 o.Flags = StatFlags(flags) 196 197 return nil 198 } 199 200 // VirtualFSStat holds the virtual file system information. 201 type VirtualFSStat struct { 202 NumberRW int // NumberRW is the number of nodes that can provide read/write space. 203 FreeRW int // FreeRW is the size, in megabytes, of the largest contiguous area of read/write free space. 204 UtilizationRW int // UtilizationRW is the percent utilization of the partition represented by FreeRW. 205 NumberStaging int // NumberStaging is the number of nodes that can provide staging space. 206 FreeStaging int // FreeStaging is the size, in megabytes, of the largest contiguous area of staging free space. 207 UtilizationStaging int // UtilizationStaging is the percent utilization of the partition represented by FreeStaging. 208 } 209 210 // MarshalXrd implements xrdproto.Marshaler 211 func (o VirtualFSStat) MarshalXrd(wBuffer *xrdenc.WBuffer) error { 212 nrw := strconv.Itoa(o.NumberRW) 213 frw := strconv.Itoa(o.FreeRW) 214 urw := strconv.Itoa(o.UtilizationRW) 215 nstg := strconv.Itoa(o.NumberStaging) 216 fstg := strconv.Itoa(o.FreeStaging) 217 ustg := strconv.Itoa(o.UtilizationStaging) 218 wBuffer.WriteBytes([]byte(nrw + " " + frw + " " + urw + " " + nstg + " " + fstg + " " + ustg)) 219 return nil 220 } 221 222 // UnmarshalXrd implements xrdproto.Unmarshaler 223 func (o *VirtualFSStat) UnmarshalXrd(rBuffer *xrdenc.RBuffer) error { 224 var buf []byte 225 for rBuffer.Len() != 0 { 226 b := rBuffer.ReadU8() 227 if b == '\x00' || b == '\n' { 228 break 229 } 230 buf = append(buf, b) 231 } 232 233 stats := bytes.Split(buf, []byte{' '}) 234 if len(stats) < 6 { 235 return fmt.Errorf("xrootd: virtual statinfo \"%s\" doesn't have enough fields, expected format is: \"nrw frw urw nstg fstg ustg\"", buf) 236 } 237 238 nrw, err := strconv.Atoi(string(stats[0])) 239 if err != nil { 240 return err 241 } 242 frw, err := strconv.Atoi(string(stats[1])) 243 if err != nil { 244 return err 245 } 246 urw, err := strconv.Atoi(string(stats[2])) 247 if err != nil { 248 return err 249 } 250 nstg, err := strconv.Atoi(string(stats[3])) 251 if err != nil { 252 return err 253 } 254 fstg, err := strconv.Atoi(string(stats[4])) 255 if err != nil { 256 return err 257 } 258 ustg, err := strconv.Atoi(string(stats[5])) 259 if err != nil { 260 return err 261 } 262 263 o.NumberRW = nrw 264 o.FreeRW = frw 265 o.UtilizationRW = urw 266 o.NumberStaging = nstg 267 o.FreeStaging = fstg 268 o.UtilizationStaging = ustg 269 270 return nil 271 } 272 273 var ( 274 _ os.FileInfo = (*EntryStat)(nil) 275 )