summaryrefslogtreecommitdiffstats
path: root/OvmfPkg/VirtioFsDxe/FuseSetAttr.c
blob: 719584fa322a0f4e96af3839415d38a091875512 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
/** @file
  FUSE_SETATTR wrapper for the Virtio Filesystem device.

  Copyright (C) 2020, Red Hat, Inc.

  SPDX-License-Identifier: BSD-2-Clause-Patent
**/

#include "VirtioFsDxe.h"

/**
  Send the FUSE_SETATTR request to the Virtio Filesystem device, for changing
  the attributes of an inode.

  The function may only be called after VirtioFsFuseInitSession() returns
  successfully and before VirtioFsUninit() is called.

  @param[in,out] VirtioFs  The Virtio Filesystem device to send the
                           FUSE_SETATTR request to. On output, the FUSE request
                           counter "VirtioFs->RequestId" will have been
                           incremented.

  @param[in] NodeId        The inode number representing the regular file or
                           directory whose attributes should be changed.

  @param[in] Size          The new size to set for the regular file. If NULL,
                           then the file size will not be changed. If NodeId
                           refers to a directory, then the caller is
                           responsible for passing NULL as Size.

  @param[in] Atime         The new last access time to set for the regular file
                           or directory (seconds since the Epoch). If NULL,
                           then the last access time is not changed.

  @param[in] Mtime         The new last modification time to set for the
                           regular file or directory (seconds since the Epoch).
                           If NULL, then the last modification time is not
                           changed.

  @param[in] Mode          The new file mode bits to set for the regular file
                           or directory. If NULL, then the file mode bits are
                           not changed.

  @retval EFI_SUCCESS  The attributes have been updated.

  @return              The "errno" value mapped to an EFI_STATUS code, if the
                       Virtio Filesystem device explicitly reported an error.

  @return              Error codes propagated from VirtioFsSgListsValidate(),
                       VirtioFsFuseNewRequest(), VirtioFsSgListsSubmit(),
                       VirtioFsFuseCheckResponse().
**/
EFI_STATUS
VirtioFsFuseSetAttr (
  IN OUT VIRTIO_FS  *VirtioFs,
  IN     UINT64     NodeId,
  IN     UINT64     *Size      OPTIONAL,
  IN     UINT64     *Atime     OPTIONAL,
  IN     UINT64     *Mtime     OPTIONAL,
  IN     UINT32     *Mode      OPTIONAL
  )
{
  VIRTIO_FS_FUSE_REQUEST              CommonReq;
  VIRTIO_FS_FUSE_SETATTR_REQUEST      AttrReq;
  VIRTIO_FS_IO_VECTOR                 ReqIoVec[2];
  VIRTIO_FS_SCATTER_GATHER_LIST       ReqSgList;
  VIRTIO_FS_FUSE_RESPONSE             CommonResp;
  VIRTIO_FS_FUSE_GETATTR_RESPONSE     GetAttrResp;
  VIRTIO_FS_FUSE_ATTRIBUTES_RESPONSE  AttrResp;
  VIRTIO_FS_IO_VECTOR                 RespIoVec[3];
  VIRTIO_FS_SCATTER_GATHER_LIST       RespSgList;
  EFI_STATUS                          Status;

  //
  // Set up the scatter-gather lists.
  //
  ReqIoVec[0].Buffer = &CommonReq;
  ReqIoVec[0].Size   = sizeof CommonReq;
  ReqIoVec[1].Buffer = &AttrReq;
  ReqIoVec[1].Size   = sizeof AttrReq;
  ReqSgList.IoVec    = ReqIoVec;
  ReqSgList.NumVec   = ARRAY_SIZE (ReqIoVec);

  RespIoVec[0].Buffer = &CommonResp;
  RespIoVec[0].Size   = sizeof CommonResp;
  RespIoVec[1].Buffer = &GetAttrResp;
  RespIoVec[1].Size   = sizeof GetAttrResp;
  RespIoVec[2].Buffer = &AttrResp;
  RespIoVec[2].Size   = sizeof AttrResp;
  RespSgList.IoVec    = RespIoVec;
  RespSgList.NumVec   = ARRAY_SIZE (RespIoVec);

  //
  // Validate the scatter-gather lists; calculate the total transfer sizes.
  //
  Status = VirtioFsSgListsValidate (VirtioFs, &ReqSgList, &RespSgList);
  if (EFI_ERROR (Status)) {
    return Status;
  }

  //
  // Populate the common request header.
  //
  Status = VirtioFsFuseNewRequest (
             VirtioFs,
             &CommonReq,
             ReqSgList.TotalSize,
             VirtioFsFuseOpSetAttr,
             NodeId
             );
  if (EFI_ERROR (Status)) {
    return Status;
  }

  //
  // Populate the FUSE_SETATTR-specific fields.
  //
  AttrReq.Valid      = 0;
  AttrReq.Padding    = 0;
  AttrReq.FileHandle = 0;
  AttrReq.Size       = (Size == NULL) ? 0 : *Size;
  AttrReq.LockOwner  = 0;
  AttrReq.Atime      = (Atime == NULL) ? 0 : *Atime;
  AttrReq.Mtime      = (Mtime == NULL) ? 0 : *Mtime;
  AttrReq.Ctime      = 0;
  AttrReq.AtimeNsec  = 0;
  AttrReq.MtimeNsec  = 0;
  AttrReq.CtimeNsec  = 0;
  AttrReq.Mode       = (Mode == NULL) ? 0 : *Mode;
  AttrReq.Unused4    = 0;
  AttrReq.Uid        = 0;
  AttrReq.Gid        = 0;
  AttrReq.Unused5    = 0;

  if (Size != NULL) {
    AttrReq.Valid |= VIRTIO_FS_FUSE_SETATTR_REQ_F_SIZE;
  }

  if (Atime != NULL) {
    AttrReq.Valid |= VIRTIO_FS_FUSE_SETATTR_REQ_F_ATIME;
  }

  if (Mtime != NULL) {
    AttrReq.Valid |= VIRTIO_FS_FUSE_SETATTR_REQ_F_MTIME;
  }

  if (Mode != NULL) {
    AttrReq.Valid |= VIRTIO_FS_FUSE_SETATTR_REQ_F_MODE;
  }

  //
  // Submit the request.
  //
  Status = VirtioFsSgListsSubmit (VirtioFs, &ReqSgList, &RespSgList);
  if (EFI_ERROR (Status)) {
    return Status;
  }

  //
  // Verify the response (all response buffers are fixed size).
  //
  Status = VirtioFsFuseCheckResponse (&RespSgList, CommonReq.Unique, NULL);
  if (Status == EFI_DEVICE_ERROR) {
    DEBUG ((
      DEBUG_ERROR,
      "%a: Label=\"%s\" NodeId=%Lu",
      __func__,
      VirtioFs->Label,
      NodeId
      ));
    if (Size != NULL) {
      DEBUG ((DEBUG_ERROR, " Size=0x%Lx", *Size));
    }

    if (Atime != NULL) {
      DEBUG ((DEBUG_ERROR, " Atime=%Lu", *Atime));
    }

    if (Mtime != NULL) {
      DEBUG ((DEBUG_ERROR, " Mtime=%Lu", *Mtime));
    }

    if (Mode != NULL) {
      DEBUG ((DEBUG_ERROR, " Mode=0x%x", *Mode)); // no support for octal :/
    }

    DEBUG ((DEBUG_ERROR, " Errno=%d\n", CommonResp.Error));
    Status = VirtioFsErrnoToEfiStatus (CommonResp.Error);
  }

  return Status;
}