@@ -420,6 +420,107 @@ func convertInMessage(
420420 Flags : fusekernel .InitFlags (in .Flags ),
421421 }
422422
423+ case fusekernel .OpRemovexattr :
424+ buf := inMsg .ConsumeBytes (inMsg .Len ())
425+ n := len (buf )
426+ if n == 0 || buf [n - 1 ] != '\x00' {
427+ err = errors .New ("Corrupt OpRemovexattr" )
428+ return
429+ }
430+
431+ o = & fuseops.RemoveXattrOp {
432+ Inode : fuseops .InodeID (inMsg .Header ().Nodeid ),
433+ Name : string (buf [:n - 1 ]),
434+ }
435+
436+ case fusekernel .OpGetxattr :
437+ type input fusekernel.GetxattrIn
438+ in := (* input )(inMsg .Consume (unsafe .Sizeof (input {})))
439+ if in == nil {
440+ err = errors .New ("Corrupt OpGetxattr" )
441+ return
442+ }
443+
444+ name := inMsg .ConsumeBytes (inMsg .Len ())
445+ i := bytes .IndexByte (name , '\x00' )
446+ if i < 0 {
447+ err = errors .New ("Corrupt OpGetxattr" )
448+ return
449+ }
450+ name = name [:i ]
451+
452+ to := & fuseops.GetXattrOp {
453+ Inode : fuseops .InodeID (inMsg .Header ().Nodeid ),
454+ Name : string (name ),
455+ }
456+ o = to
457+
458+ readSize := int (in .Size )
459+ p := outMsg .GrowNoZero (readSize )
460+ if p == nil {
461+ err = fmt .Errorf ("Can't grow for %d-byte read" , readSize )
462+ return
463+ }
464+
465+ sh := (* reflect .SliceHeader )(unsafe .Pointer (& to .Dst ))
466+ sh .Data = uintptr (p )
467+ sh .Len = readSize
468+ sh .Cap = readSize
469+
470+ case fusekernel .OpListxattr :
471+ type input fusekernel.ListxattrIn
472+ in := (* input )(inMsg .Consume (unsafe .Sizeof (input {})))
473+ if in == nil {
474+ err = errors .New ("Corrupt OpListxattr" )
475+ return
476+ }
477+
478+ to := & fuseops.ListXattrOp {
479+ Inode : fuseops .InodeID (inMsg .Header ().Nodeid ),
480+ }
481+ o = to
482+
483+ readSize := int (in .Size )
484+ if readSize != 0 {
485+ p := outMsg .GrowNoZero (readSize )
486+ if p == nil {
487+ err = fmt .Errorf ("Can't grow for %d-byte read" , readSize )
488+ return
489+ }
490+ sh := (* reflect .SliceHeader )(unsafe .Pointer (& to .Dst ))
491+ sh .Data = uintptr (p )
492+ sh .Len = readSize
493+ sh .Cap = readSize
494+ }
495+ case fusekernel .OpSetxattr :
496+ type input fusekernel.SetxattrIn
497+ in := (* input )(inMsg .Consume (unsafe .Sizeof (input {})))
498+ if in == nil {
499+ err = errors .New ("Corrupt OpSetxattr" )
500+ return
501+ }
502+
503+ payload := inMsg .ConsumeBytes (inMsg .Len ())
504+ // payload should be "name\x00value"
505+ if len (payload ) < 3 {
506+ err = errors .New ("Corrupt OpSetxattr" )
507+ return
508+ }
509+ i := bytes .IndexByte (payload , '\x00' )
510+ if i < 0 {
511+ err = errors .New ("Corrupt OpSetxattr" )
512+ return
513+ }
514+
515+ name , value := payload [:i ], payload [i + 1 :len (payload )]
516+
517+ o = & fuseops.SetXattrOp {
518+ Inode : fuseops .InodeID (inMsg .Header ().Nodeid ),
519+ Name : string (name ),
520+ Value : value ,
521+ Flags : in .Flags ,
522+ }
523+
423524 default :
424525 o = & unknownOp {
425526 OpCode : inMsg .Header ().Opcode ,
@@ -459,17 +560,32 @@ func (c *Connection) kernelResponse(
459560 // If the user returned the error, fill in the error field of the outgoing
460561 // message header.
461562 if opErr != nil {
462- m .OutHeader ().Error = - int32 (syscall .EIO )
463- if errno , ok := opErr .(syscall.Errno ); ok {
464- m .OutHeader ().Error = - int32 (errno )
563+ handled := false
564+
565+ if opErr == syscall .ERANGE {
566+ switch o := op .(type ) {
567+ case * fuseops.GetXattrOp :
568+ writeXattrSize (m , uint32 (o .BytesRead ))
569+ handled = true
570+ case * fuseops.ListXattrOp :
571+ writeXattrSize (m , uint32 (o .BytesRead ))
572+ handled = true
573+ }
574+ }
575+
576+ if ! handled {
577+ m .OutHeader ().Error = - int32 (syscall .EIO )
578+ if errno , ok := opErr .(syscall.Errno ); ok {
579+ m .OutHeader ().Error = - int32 (errno )
580+ }
581+
582+ // Special case: for some types, convertInMessage grew the message in order
583+ // to obtain a destination buffer. Make sure that we shrink back to just
584+ // the header, because on OS X the kernel otherwise returns EINVAL when we
585+ // attempt to write an error response with a length that extends beyond the
586+ // header.
587+ m .ShrinkTo (buffer .OutMessageHeaderSize )
465588 }
466-
467- // Special case: for some types, convertInMessage grew the message in order
468- // to obtain a destination buffer. Make sure that we shrink back to just
469- // the header, because on OS X the kernel otherwise returns EINVAL when we
470- // attempt to write an error response with a length that extends beyond the
471- // header.
472- m .ShrinkTo (buffer .OutMessageHeaderSize )
473589 }
474590
475591 // Otherwise, fill in the rest of the response.
@@ -623,6 +739,29 @@ func (c *Connection) kernelResponseForOp(
623739 out .St .Bsize = o .IoSize
624740 out .St .Frsize = o .BlockSize
625741
742+ case * fuseops.RemoveXattrOp :
743+ // Empty response
744+
745+ case * fuseops.GetXattrOp :
746+ // convertInMessage already set up the destination buffer to be at the end
747+ // of the out message. We need only shrink to the right size based on how
748+ // much the user read.
749+ if o .BytesRead == 0 {
750+ writeXattrSize (m , uint32 (o .BytesRead ))
751+ } else {
752+ m .ShrinkTo (buffer .OutMessageHeaderSize + o .BytesRead )
753+ }
754+
755+ case * fuseops.ListXattrOp :
756+ if o .BytesRead == 0 {
757+ writeXattrSize (m , uint32 (o .BytesRead ))
758+ } else {
759+ m .ShrinkTo (buffer .OutMessageHeaderSize + o .BytesRead )
760+ }
761+
762+ case * fuseops.SetXattrOp :
763+ // Empty response
764+
626765 case * initOp :
627766 out := (* fusekernel .InitOut )(m .Grow (int (unsafe .Sizeof (fusekernel.InitOut {}))))
628767
@@ -744,3 +883,8 @@ func convertFileMode(unixMode uint32) os.FileMode {
744883 }
745884 return mode
746885}
886+
887+ func writeXattrSize (m * buffer.OutMessage , size uint32 ) {
888+ out := (* fusekernel .GetxattrOut )(m .Grow (int (unsafe .Sizeof (fusekernel.GetxattrOut {}))))
889+ out .Size = size
890+ }
0 commit comments