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  )