@@ -1131,7 +1131,17 @@ func (fs *Share) SetSecurityInfoRaw(name string, flags SecurityInformationReques
11311131 FileId : f .fd ,
11321132 }
11331133
1134- _ , err = fs .sendRecv (SMB2_SET_INFO , req )
1134+ req .CreditCharge , _ , err = fs .loanCredit (req .Size ())
1135+ defer func () {
1136+ if err != nil {
1137+ fs .chargeCredit (req .CreditCharge )
1138+ }
1139+ }()
1140+ if err != nil {
1141+ return fmt .Errorf ("calling loanCredit: %w" , err )
1142+ }
1143+
1144+ _ , err = fs .sendRecv (req , SMB2_SET_INFO )
11351145 if err != nil {
11361146 return & os.PathError {Op : op , Path : name , Err : err }
11371147 }
@@ -1160,6 +1170,51 @@ func (fs *Share) SecurityInfoRaw2(name string, info SecurityInformationRequestFl
11601170 access |= ACCESS_SYSTEM_SECURITY
11611171 }
11621172
1173+ creq := & CreateRequest {
1174+ SecurityFlags : 0 ,
1175+ RequestedOplockLevel : SMB2_OPLOCK_LEVEL_NONE ,
1176+ ImpersonationLevel : Impersonation ,
1177+ SmbCreateFlags : 0 ,
1178+ DesiredAccess : access ,
1179+ FileAttributes : FILE_ATTRIBUTE_NORMAL ,
1180+ ShareAccess : FILE_SHARE_READ ,
1181+ CreateDisposition : FILE_OPEN ,
1182+ CreateOptions : 0 ,
1183+ Mapping : fs .mapping ,
1184+ }
1185+ qreq := & QueryInfoRequest {
1186+ InfoType : SMB2_0_INFO_SECURITY , // TODO: rename info type constants to be more idiomatic with go
1187+ FileInfoClass : 0 , // From the docs: "For security queries, this field MUST be set to 0"
1188+ OutputBufferLength : 64 * 1024 , // Security descriptors have a max size of 64 KiB on NTFS: https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/nf-ntifs-ntquerysecurityobject#remarks
1189+ AdditionalInformation : uint32 (info ),
1190+ Flags : 0 ,
1191+ FileId : & FileId { // in compound requests, this value represents the result of the create request
1192+ Persistent : [8 ]byte {0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF },
1193+ Volatile : [8 ]byte {0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF },
1194+ },
1195+ }
1196+ req := NewCompoundPacket (creq , qreq )
1197+
1198+ var err error
1199+ creq .CreditCharge , _ , err = fs .loanCredit (req .Size ()) // put credit charge in first header
1200+ defer func () {
1201+ if err != nil {
1202+ fs .chargeCredit (creq .CreditCharge )
1203+ }
1204+ }()
1205+ if err != nil {
1206+ return nil , fmt .Errorf ("calling loanCredit: %w" , err )
1207+ }
1208+
1209+ rss , err := fs .sendRecv (req , SMB2_CREATE , SMB2_QUERY_INFO ) // two expected commands for two requests in compound request
1210+ if err != nil {
1211+ return nil , & os.PathError {Op : op , Path : name , Err : err }
1212+ }
1213+
1214+ if len (rss ) < 2 {
1215+ return nil , & os.PathError {Op : op , Path : name , Err : fmt .Errorf ("expecting two commands in compound response, but got one" )}
1216+ }
1217+
11631218 return nil , & os.PathError {Op : op , Path : name , Err : fmt .Errorf ("compound security info not implemented yet" )}
11641219}
11651220
@@ -1184,12 +1239,15 @@ func (fs *Share) createFile(name string, req *CreateRequest, followSymlinks bool
11841239
11851240 req .Name = name
11861241
1187- res , err := fs .sendRecv (SMB2_CREATE , req )
1242+ res , err := fs .sendRecv (req , SMB2_CREATE )
11881243 if err != nil {
11891244 return nil , fmt .Errorf ("calling sendRecv: %w" , err )
11901245 }
1246+ if len (res ) == 0 {
1247+ return nil , & InvalidResponseError {"unexpected empty response" }
1248+ }
11911249
1192- r := CreateResponseDecoder (res )
1250+ r := CreateResponseDecoder (res [ 0 ] )
11931251 if r .IsInvalid () {
11941252 return nil , & InvalidResponseError {"broken create response format" }
11951253 }
@@ -1213,7 +1271,7 @@ func (fs *Share) createFileRec(name string, req *CreateRequest) (f *File, err er
12131271
12141272 req .Name = name
12151273
1216- res , err := fs .sendRecv (SMB2_CREATE , req )
1274+ res , err := fs .sendRecv (req , SMB2_CREATE )
12171275 if err != nil {
12181276 if rerr , ok := err .(* ResponseError ); ok && erref .NtStatus (rerr .Code ) == erref .STATUS_STOPPED_ON_SYMLINK {
12191277 if len (rerr .data ) > 0 {
@@ -1226,8 +1284,11 @@ func (fs *Share) createFileRec(name string, req *CreateRequest) (f *File, err er
12261284 }
12271285 return nil , fmt .Errorf ("calling sendRecv SMB2_CREATE: %w" , err )
12281286 }
1287+ if len (res ) == 0 {
1288+ return nil , & InvalidResponseError {"unexpected empty response" }
1289+ }
12291290
1230- r := CreateResponseDecoder (res )
1291+ r := CreateResponseDecoder (res [ 0 ] )
12311292 if r .IsInvalid () {
12321293 return nil , & InvalidResponseError {"broken create response format" }
12331294 }
@@ -1267,18 +1328,18 @@ func evalSymlinkError(name string, errData []byte, mc utf16le.MapChars) (string,
12671328 return dir (ud ) + target + u , nil
12681329}
12691330
1270- func (fs * Share ) sendRecv (cmd uint16 , req Packet ) (res []byte , err error ) {
1331+ func (fs * Share ) sendRecv (req Packet , cmds ... uint16 ) (res [] []byte , err error ) {
12711332 rr , err := fs .send (req , fs .ctx )
12721333 if err != nil {
12731334 return nil , err
12741335 }
12751336
1276- pkt , err := fs .recv (rr )
1337+ pkts , err := fs .recv (rr )
12771338 if err != nil {
12781339 return nil , err
12791340 }
12801341
1281- return accept (cmd , pkt )
1342+ return accept (pkts , cmds ... )
12821343}
12831344
12841345func (fs * Share ) loanCredit (payloadSize int ) (creditCharge uint16 , grantedPayloadSize int , err error ) {
@@ -1326,12 +1387,15 @@ func (f *File) close() error {
13261387
13271388 req .FileId = f .fd
13281389
1329- res , err := f .sendRecv (SMB2_CLOSE , req )
1390+ res , err := f .sendRecv (req , SMB2_CLOSE )
13301391 if err != nil {
13311392 return err
13321393 }
1394+ if len (res ) == 0 {
1395+ return & InvalidResponseError {"unexpected empty response" }
1396+ }
13331397
1334- r := CloseResponseDecoder (res )
1398+ r := CloseResponseDecoder (res [ 0 ] )
13351399 if r .IsInvalid () {
13361400 return & InvalidResponseError {"broken close response format" }
13371401 }
@@ -1515,12 +1579,15 @@ func (f *File) readAtChunk(n int, off int64) (bs []byte, isEOF bool, err error)
15151579
15161580 req .CreditCharge = creditCharge
15171581
1518- res , err := f .sendRecv (SMB2_READ , req )
1582+ res , err := f .sendRecv (req , SMB2_READ )
15191583 if err != nil {
15201584 return nil , false , err
15211585 }
1586+ if len (res ) == 0 {
1587+ return nil , false , & InvalidResponseError {"unexpected empty response" }
1588+ }
15221589
1523- r := ReadResponseDecoder (res )
1590+ r := ReadResponseDecoder (res [ 0 ] )
15241591 if r .IsInvalid () {
15251592 return nil , false , & InvalidResponseError {"broken read response format" }
15261593 }
@@ -1769,12 +1836,15 @@ func (f *File) Sync() (err error) {
17691836 return & os.PathError {Op : "sync" , Path : f .name , Err : err }
17701837 }
17711838
1772- res , err := f .sendRecv (SMB2_FLUSH , req )
1839+ res , err := f .sendRecv (req , SMB2_FLUSH )
17731840 if err != nil {
17741841 return & os.PathError {Op : "sync" , Path : f .name , Err : err }
17751842 }
1843+ if len (res ) == 0 {
1844+ return & InvalidResponseError {"unexpected empty response" }
1845+ }
17761846
1777- r := FlushResponseDecoder (res )
1847+ r := FlushResponseDecoder (res [ 0 ] )
17781848 if r .IsInvalid () {
17791849 return & os.PathError {Op : "sync" , Path : f .name , Err : & InvalidResponseError {"broken flush response format" }}
17801850 }
@@ -1949,12 +2019,15 @@ func (f *File) writeAtChunk(b []byte, off int64) (n int, err error) {
19492019
19502020 req .CreditCharge = creditCharge
19512021
1952- res , err := f .sendRecv (SMB2_WRITE , req )
2022+ res , err := f .sendRecv (req , SMB2_WRITE )
19532023 if err != nil {
19542024 return 0 , err
19552025 }
2026+ if len (res ) == 0 {
2027+ return 0 , & InvalidResponseError {"unexpected empty response" }
2028+ }
19562029
1957- r := WriteResponseDecoder (res )
2030+ r := WriteResponseDecoder (res [ 0 ] )
19582031 if r .IsInvalid () {
19592032 return 0 , & InvalidResponseError {"broken write response format" }
19602033 }
@@ -2182,16 +2255,22 @@ func (f *File) ioctl(req *IoctlRequest) (output []byte, err error) {
21822255
21832256 req .FileId = f .fd
21842257
2185- res , err := f .sendRecv (SMB2_IOCTL , req )
2258+ res , err := f .sendRecv (req , SMB2_IOCTL )
21862259 if err != nil {
2187- r := IoctlResponseDecoder (res )
2260+ if len (res ) == 0 {
2261+ return nil , err
2262+ }
2263+ r := IoctlResponseDecoder (res [0 ])
21882264 if r .IsInvalid () {
21892265 return nil , err
21902266 }
21912267 return r .Output (), err
21922268 }
2269+ if len (res ) == 0 {
2270+ return nil , & InvalidResponseError {"unexpected empty response" }
2271+ }
21932272
2194- r := IoctlResponseDecoder (res )
2273+ r := IoctlResponseDecoder (res [ 0 ] )
21952274 if r .IsInvalid () {
21962275 return nil , & InvalidResponseError {"broken ioctl response format" }
21972276 }
@@ -2227,12 +2306,15 @@ func (f *File) readdir(pattern string) (fi []os.FileInfo, err error) {
22272306
22282307 req .FileId = f .fd
22292308
2230- res , err := f .sendRecv (SMB2_QUERY_DIRECTORY , req )
2309+ res , err := f .sendRecv (req , SMB2_QUERY_DIRECTORY )
22312310 if err != nil {
22322311 return nil , err
22332312 }
2313+ if len (res ) == 0 {
2314+ return nil , & InvalidResponseError {"unexpected empty response" }
2315+ }
22342316
2235- r := QueryDirectoryResponseDecoder (res )
2317+ r := QueryDirectoryResponseDecoder (res [ 0 ] )
22362318 if r .IsInvalid () {
22372319 return nil , & InvalidResponseError {"broken query directory response format" }
22382320 }
@@ -2291,12 +2373,15 @@ func (f *File) queryInfo(req *QueryInfoRequest) (infoBytes []byte, err error) {
22912373
22922374 req .FileId = f .fd
22932375
2294- res , err := f .sendRecv (SMB2_QUERY_INFO , req )
2376+ res , err := f .sendRecv (req , SMB2_QUERY_INFO )
22952377 if err != nil {
22962378 return nil , err
22972379 }
2380+ if len (res ) == 0 {
2381+ return nil , & InvalidResponseError {"unexpected empty response" }
2382+ }
22982383
2299- r := QueryInfoResponseDecoder (res )
2384+ r := QueryInfoResponseDecoder (res [ 0 ] )
23002385 if r .IsInvalid () {
23012386 return nil , & InvalidResponseError {"broken query info response format" }
23022387 }
@@ -2346,21 +2431,24 @@ func (f *File) setInfo(req *SetInfoRequest) (err error) {
23462431
23472432 req .InfoType = SMB2_0_INFO_FILE
23482433
2349- res , err := f .sendRecv (SMB2_SET_INFO , req )
2434+ res , err := f .sendRecv (req , SMB2_SET_INFO )
23502435 if err != nil {
23512436 return err
23522437 }
2438+ if len (res ) == 0 {
2439+ return & InvalidResponseError {"unexpected empty response" }
2440+ }
23532441
2354- r := SetInfoResponseDecoder (res )
2442+ r := SetInfoResponseDecoder (res [ 0 ] )
23552443 if r .IsInvalid () {
23562444 return & InvalidResponseError {"broken set info response format" }
23572445 }
23582446
23592447 return nil
23602448}
23612449
2362- func (f * File ) sendRecv (cmd uint16 , req Packet ) (res []byte , err error ) {
2363- return f .fs .sendRecv (cmd , req )
2450+ func (f * File ) sendRecv (req Packet , cmd uint16 ) (res [] []byte , err error ) {
2451+ return f .fs .sendRecv (req , cmd )
23642452}
23652453
23662454type FileStat struct {
0 commit comments