Annotation of qemu/hw/9pfs/virtio-9p-proxy.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Virtio 9p Proxy callback
                      3:  *
                      4:  * Copyright IBM, Corp. 2011
                      5:  *
                      6:  * Authors:
                      7:  * M. Mohan Kumar <[email protected]>
                      8:  *
                      9:  * This work is licensed under the terms of the GNU GPL, version 2.  See
                     10:  * the COPYING file in the top-level directory.
                     11:  */
                     12: #include <sys/socket.h>
                     13: #include <sys/un.h>
                     14: #include "hw/virtio.h"
                     15: #include "virtio-9p.h"
                     16: #include "fsdev/qemu-fsdev.h"
                     17: #include "virtio-9p-proxy.h"
                     18: 
                     19: typedef struct V9fsProxy {
                     20:     int sockfd;
                     21:     QemuMutex mutex;
                     22:     struct iovec in_iovec;
                     23:     struct iovec out_iovec;
                     24: } V9fsProxy;
                     25: 
                     26: /*
                     27:  * Return received file descriptor on success in *status.
                     28:  * errno is also returned on *status (which will be < 0)
                     29:  * return < 0 on transport error.
                     30:  */
                     31: static int v9fs_receivefd(int sockfd, int *status)
                     32: {
                     33:     struct iovec iov;
                     34:     struct msghdr msg;
                     35:     struct cmsghdr *cmsg;
                     36:     int retval, data, fd;
                     37:     union MsgControl msg_control;
                     38: 
                     39:     iov.iov_base = &data;
                     40:     iov.iov_len = sizeof(data);
                     41: 
                     42:     memset(&msg, 0, sizeof(msg));
                     43:     msg.msg_iov = &iov;
                     44:     msg.msg_iovlen = 1;
                     45:     msg.msg_control = &msg_control;
                     46:     msg.msg_controllen = sizeof(msg_control);
                     47: 
                     48:     do {
                     49:         retval = recvmsg(sockfd, &msg, 0);
                     50:     } while (retval < 0 && errno == EINTR);
                     51:     if (retval <= 0) {
                     52:         return retval;
                     53:     }
                     54:     /*
                     55:      * data is set to V9FS_FD_VALID, if ancillary data is sent.  If this
                     56:      * request doesn't need ancillary data (fd) or an error occurred,
                     57:      * data is set to negative errno value.
                     58:      */
                     59:     if (data != V9FS_FD_VALID) {
                     60:         *status = data;
                     61:         return 0;
                     62:     }
                     63:     /*
                     64:      * File descriptor (fd) is sent in the ancillary data. Check if we
                     65:      * indeed received it. One of the reasons to fail to receive it is if
                     66:      * we exceeded the maximum number of file descriptors!
                     67:      */
                     68:     for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
                     69:         if (cmsg->cmsg_len != CMSG_LEN(sizeof(int)) ||
                     70:             cmsg->cmsg_level != SOL_SOCKET ||
                     71:             cmsg->cmsg_type != SCM_RIGHTS) {
                     72:             continue;
                     73:         }
                     74:         fd = *((int *)CMSG_DATA(cmsg));
                     75:         *status = fd;
                     76:         return 0;
                     77:     }
                     78:     *status = -ENFILE;  /* Ancillary data sent but not received */
                     79:     return 0;
                     80: }
                     81: 
                     82: static ssize_t socket_read(int sockfd, void *buff, size_t size)
                     83: {
                     84:     ssize_t retval, total = 0;
                     85: 
                     86:     while (size) {
                     87:         retval = read(sockfd, buff, size);
                     88:         if (retval == 0) {
                     89:             return -EIO;
                     90:         }
                     91:         if (retval < 0) {
                     92:             if (errno == EINTR) {
                     93:                 continue;
                     94:             }
                     95:             return -errno;
                     96:         }
                     97:         size -= retval;
                     98:         buff += retval;
                     99:         total += retval;
                    100:     }
                    101:     return total;
                    102: }
                    103: 
                    104: /* Converts proxy_statfs to VFS statfs structure */
                    105: static void prstatfs_to_statfs(struct statfs *stfs, ProxyStatFS *prstfs)
                    106: {
                    107:     memset(stfs, 0, sizeof(*stfs));
                    108:     stfs->f_type = prstfs->f_type;
                    109:     stfs->f_bsize = prstfs->f_bsize;
                    110:     stfs->f_blocks = prstfs->f_blocks;
                    111:     stfs->f_bfree = prstfs->f_bfree;
                    112:     stfs->f_bavail = prstfs->f_bavail;
                    113:     stfs->f_files = prstfs->f_files;
                    114:     stfs->f_ffree = prstfs->f_ffree;
                    115:     stfs->f_fsid.__val[0] = prstfs->f_fsid[0] & 0xFFFFFFFFU;
                    116:     stfs->f_fsid.__val[1] = prstfs->f_fsid[1] >> 32 & 0xFFFFFFFFU;
                    117:     stfs->f_namelen = prstfs->f_namelen;
                    118:     stfs->f_frsize = prstfs->f_frsize;
                    119: }
                    120: 
                    121: /* Converts proxy_stat structure to VFS stat structure */
                    122: static void prstat_to_stat(struct stat *stbuf, ProxyStat *prstat)
                    123: {
                    124:    memset(stbuf, 0, sizeof(*stbuf));
                    125:    stbuf->st_dev = prstat->st_dev;
                    126:    stbuf->st_ino = prstat->st_ino;
                    127:    stbuf->st_nlink = prstat->st_nlink;
                    128:    stbuf->st_mode = prstat->st_mode;
                    129:    stbuf->st_uid = prstat->st_uid;
                    130:    stbuf->st_gid = prstat->st_gid;
                    131:    stbuf->st_rdev = prstat->st_rdev;
                    132:    stbuf->st_size = prstat->st_size;
                    133:    stbuf->st_blksize = prstat->st_blksize;
                    134:    stbuf->st_blocks = prstat->st_blocks;
                    135:    stbuf->st_atim.tv_sec = prstat->st_atim_sec;
                    136:    stbuf->st_atim.tv_nsec = prstat->st_atim_nsec;
                    137:    stbuf->st_mtime = prstat->st_mtim_sec;
                    138:    stbuf->st_mtim.tv_nsec = prstat->st_mtim_nsec;
                    139:    stbuf->st_ctime = prstat->st_ctim_sec;
                    140:    stbuf->st_ctim.tv_nsec = prstat->st_ctim_nsec;
                    141: }
                    142: 
                    143: /*
                    144:  * Response contains two parts
                    145:  * {header, data}
                    146:  * header.type == T_ERROR, data -> -errno
                    147:  * header.type == T_SUCCESS, data -> response
                    148:  * size of errno/response is given by header.size
                    149:  * returns < 0, on transport error. response is
                    150:  * valid only if status >= 0.
                    151:  */
                    152: static int v9fs_receive_response(V9fsProxy *proxy, int type,
                    153:                                  int *status, void *response)
                    154: {
                    155:     int retval;
                    156:     ProxyHeader header;
                    157:     struct iovec *reply = &proxy->in_iovec;
                    158: 
                    159:     *status = 0;
                    160:     reply->iov_len = 0;
                    161:     retval = socket_read(proxy->sockfd, reply->iov_base, PROXY_HDR_SZ);
                    162:     if (retval < 0) {
                    163:         return retval;
                    164:     }
                    165:     reply->iov_len = PROXY_HDR_SZ;
                    166:     proxy_unmarshal(reply, 0, "dd", &header.type, &header.size);
                    167:     /*
                    168:      * if response size > PROXY_MAX_IO_SZ, read the response but ignore it and
                    169:      * return -ENOBUFS
                    170:      */
                    171:     if (header.size > PROXY_MAX_IO_SZ) {
                    172:         int count;
                    173:         while (header.size > 0) {
                    174:             count = MIN(PROXY_MAX_IO_SZ, header.size);
                    175:             count = socket_read(proxy->sockfd, reply->iov_base, count);
                    176:             if (count < 0) {
                    177:                 return count;
                    178:             }
                    179:             header.size -= count;
                    180:         }
                    181:         *status = -ENOBUFS;
                    182:         return 0;
                    183:     }
                    184: 
                    185:     retval = socket_read(proxy->sockfd,
                    186:                          reply->iov_base + PROXY_HDR_SZ, header.size);
                    187:     if (retval < 0) {
                    188:         return retval;
                    189:     }
                    190:     reply->iov_len += header.size;
                    191:     /* there was an error during processing request */
                    192:     if (header.type == T_ERROR) {
                    193:         int ret;
                    194:         ret = proxy_unmarshal(reply, PROXY_HDR_SZ, "d", status);
                    195:         if (ret < 0) {
                    196:             *status = ret;
                    197:         }
                    198:         return 0;
                    199:     }
                    200: 
                    201:     switch (type) {
                    202:     case T_LSTAT: {
                    203:         ProxyStat prstat;
                    204:         retval = proxy_unmarshal(reply, PROXY_HDR_SZ,
                    205:                                  "qqqdddqqqqqqqqqq", &prstat.st_dev,
                    206:                                  &prstat.st_ino, &prstat.st_nlink,
                    207:                                  &prstat.st_mode, &prstat.st_uid,
                    208:                                  &prstat.st_gid, &prstat.st_rdev,
                    209:                                  &prstat.st_size, &prstat.st_blksize,
                    210:                                  &prstat.st_blocks,
                    211:                                  &prstat.st_atim_sec, &prstat.st_atim_nsec,
                    212:                                  &prstat.st_mtim_sec, &prstat.st_mtim_nsec,
                    213:                                  &prstat.st_ctim_sec, &prstat.st_ctim_nsec);
                    214:         prstat_to_stat(response, &prstat);
                    215:         break;
                    216:     }
                    217:     case T_STATFS: {
                    218:         ProxyStatFS prstfs;
                    219:         retval = proxy_unmarshal(reply, PROXY_HDR_SZ,
                    220:                                  "qqqqqqqqqqq", &prstfs.f_type,
                    221:                                  &prstfs.f_bsize, &prstfs.f_blocks,
                    222:                                  &prstfs.f_bfree, &prstfs.f_bavail,
                    223:                                  &prstfs.f_files, &prstfs.f_ffree,
                    224:                                  &prstfs.f_fsid[0], &prstfs.f_fsid[1],
                    225:                                  &prstfs.f_namelen, &prstfs.f_frsize);
                    226:         prstatfs_to_statfs(response, &prstfs);
                    227:         break;
                    228:     }
                    229:     case T_READLINK: {
                    230:         V9fsString target;
                    231:         v9fs_string_init(&target);
                    232:         retval = proxy_unmarshal(reply, PROXY_HDR_SZ, "s", &target);
                    233:         strcpy(response, target.data);
                    234:         v9fs_string_free(&target);
                    235:         break;
                    236:     }
                    237:     case T_LGETXATTR:
                    238:     case T_LLISTXATTR: {
                    239:         V9fsString xattr;
                    240:         v9fs_string_init(&xattr);
                    241:         retval = proxy_unmarshal(reply, PROXY_HDR_SZ, "s", &xattr);
                    242:         memcpy(response, xattr.data, xattr.size);
                    243:         v9fs_string_free(&xattr);
                    244:         break;
                    245:     }
                    246:     case T_GETVERSION:
                    247:         proxy_unmarshal(reply, PROXY_HDR_SZ, "q", response);
                    248:         break;
                    249:     default:
                    250:         return -1;
                    251:     }
                    252:     if (retval < 0) {
                    253:         *status  = retval;
                    254:     }
                    255:     return 0;
                    256: }
                    257: 
                    258: /*
                    259:  * return < 0 on transport error.
                    260:  * *status is valid only if return >= 0
                    261:  */
                    262: static int v9fs_receive_status(V9fsProxy *proxy,
                    263:                                struct iovec *reply, int *status)
                    264: {
                    265:     int retval;
                    266:     ProxyHeader header;
                    267: 
                    268:     *status = 0;
                    269:     reply->iov_len = 0;
                    270:     retval = socket_read(proxy->sockfd, reply->iov_base, PROXY_HDR_SZ);
                    271:     if (retval < 0) {
                    272:         return retval;
                    273:     }
                    274:     reply->iov_len = PROXY_HDR_SZ;
                    275:     proxy_unmarshal(reply, 0, "dd", &header.type, &header.size);
                    276:     if (header.size != sizeof(int)) {
                    277:         *status = -ENOBUFS;
                    278:         return 0;
                    279:     }
                    280:     retval = socket_read(proxy->sockfd,
                    281:                          reply->iov_base + PROXY_HDR_SZ, header.size);
                    282:     if (retval < 0) {
                    283:         return retval;
                    284:     }
                    285:     reply->iov_len += header.size;
                    286:     proxy_unmarshal(reply, PROXY_HDR_SZ, "d", status);
                    287:     return 0;
                    288: }
                    289: 
                    290: /*
                    291:  * Proxy->header and proxy->request written to socket by QEMU process.
                    292:  * This request read by proxy helper process
                    293:  * returns 0 on success and -errno on error
                    294:  */
                    295: static int v9fs_request(V9fsProxy *proxy, int type,
                    296:                         void *response, const char *fmt, ...)
                    297: {
                    298:     dev_t rdev;
                    299:     va_list ap;
                    300:     int size = 0;
                    301:     int retval = 0;
                    302:     uint64_t offset;
                    303:     ProxyHeader header = { 0, 0};
                    304:     struct timespec spec[2];
                    305:     int flags, mode, uid, gid;
                    306:     V9fsString *name, *value;
                    307:     V9fsString *path, *oldpath;
                    308:     struct iovec *iovec = NULL, *reply = NULL;
                    309: 
                    310:     qemu_mutex_lock(&proxy->mutex);
                    311: 
                    312:     if (proxy->sockfd == -1) {
                    313:         retval = -EIO;
                    314:         goto err_out;
                    315:     }
                    316:     iovec = &proxy->out_iovec;
                    317:     reply = &proxy->in_iovec;
                    318:     va_start(ap, fmt);
                    319:     switch (type) {
                    320:     case T_OPEN:
                    321:         path = va_arg(ap, V9fsString *);
                    322:         flags = va_arg(ap, int);
                    323:         retval = proxy_marshal(iovec, PROXY_HDR_SZ, "sd", path, flags);
                    324:         if (retval > 0) {
                    325:             header.size = retval;
                    326:             header.type = T_OPEN;
                    327:         }
                    328:         break;
                    329:     case T_CREATE:
                    330:         path = va_arg(ap, V9fsString *);
                    331:         flags = va_arg(ap, int);
                    332:         mode = va_arg(ap, int);
                    333:         uid = va_arg(ap, int);
                    334:         gid = va_arg(ap, int);
                    335:         retval = proxy_marshal(iovec, PROXY_HDR_SZ, "sdddd", path,
                    336:                                     flags, mode, uid, gid);
                    337:         if (retval > 0) {
                    338:             header.size = retval;
                    339:             header.type = T_CREATE;
                    340:         }
                    341:         break;
                    342:     case T_MKNOD:
                    343:         path = va_arg(ap, V9fsString *);
                    344:         mode = va_arg(ap, int);
                    345:         rdev = va_arg(ap, long int);
                    346:         uid = va_arg(ap, int);
                    347:         gid = va_arg(ap, int);
                    348:         retval = proxy_marshal(iovec, PROXY_HDR_SZ, "ddsdq",
                    349:                                     uid, gid, path, mode, rdev);
                    350:         if (retval > 0) {
                    351:             header.size = retval;
                    352:             header.type = T_MKNOD;
                    353:         }
                    354:         break;
                    355:     case T_MKDIR:
                    356:         path = va_arg(ap, V9fsString *);
                    357:         mode = va_arg(ap, int);
                    358:         uid = va_arg(ap, int);
                    359:         gid = va_arg(ap, int);
                    360:         retval = proxy_marshal(iovec, PROXY_HDR_SZ, "ddsd",
                    361:                                     uid, gid, path, mode);
                    362:         if (retval > 0) {
                    363:             header.size = retval;
                    364:             header.type = T_MKDIR;
                    365:         }
                    366:         break;
                    367:     case T_SYMLINK:
                    368:         oldpath = va_arg(ap, V9fsString *);
                    369:         path = va_arg(ap, V9fsString *);
                    370:         uid = va_arg(ap, int);
                    371:         gid = va_arg(ap, int);
                    372:         retval = proxy_marshal(iovec, PROXY_HDR_SZ, "ddss",
                    373:                                     uid, gid, oldpath, path);
                    374:         if (retval > 0) {
                    375:             header.size = retval;
                    376:             header.type = T_SYMLINK;
                    377:         }
                    378:         break;
                    379:     case T_LINK:
                    380:         oldpath = va_arg(ap, V9fsString *);
                    381:         path = va_arg(ap, V9fsString *);
                    382:         retval = proxy_marshal(iovec, PROXY_HDR_SZ, "ss",
                    383:                                     oldpath, path);
                    384:         if (retval > 0) {
                    385:             header.size = retval;
                    386:             header.type = T_LINK;
                    387:         }
                    388:         break;
                    389:     case T_LSTAT:
                    390:         path = va_arg(ap, V9fsString *);
                    391:         retval = proxy_marshal(iovec, PROXY_HDR_SZ, "s", path);
                    392:         if (retval > 0) {
                    393:             header.size = retval;
                    394:             header.type = T_LSTAT;
                    395:         }
                    396:         break;
                    397:     case T_READLINK:
                    398:         path = va_arg(ap, V9fsString *);
                    399:         size = va_arg(ap, int);
                    400:         retval = proxy_marshal(iovec, PROXY_HDR_SZ, "sd", path, size);
                    401:         if (retval > 0) {
                    402:             header.size = retval;
                    403:             header.type = T_READLINK;
                    404:         }
                    405:         break;
                    406:     case T_STATFS:
                    407:         path = va_arg(ap, V9fsString *);
                    408:         retval = proxy_marshal(iovec, PROXY_HDR_SZ, "s", path);
                    409:         if (retval > 0) {
                    410:             header.size = retval;
                    411:             header.type = T_STATFS;
                    412:         }
                    413:         break;
                    414:     case T_CHMOD:
                    415:         path = va_arg(ap, V9fsString *);
                    416:         mode = va_arg(ap, int);
                    417:         retval = proxy_marshal(iovec, PROXY_HDR_SZ, "sd", path, mode);
                    418:         if (retval > 0) {
                    419:             header.size = retval;
                    420:             header.type = T_CHMOD;
                    421:         }
                    422:         break;
                    423:     case T_CHOWN:
                    424:         path = va_arg(ap, V9fsString *);
                    425:         uid = va_arg(ap, int);
                    426:         gid = va_arg(ap, int);
                    427:         retval = proxy_marshal(iovec, PROXY_HDR_SZ, "sdd", path, uid, gid);
                    428:         if (retval > 0) {
                    429:             header.size = retval;
                    430:             header.type = T_CHOWN;
                    431:         }
                    432:         break;
                    433:     case T_TRUNCATE:
                    434:         path = va_arg(ap, V9fsString *);
                    435:         offset = va_arg(ap, uint64_t);
                    436:         retval = proxy_marshal(iovec, PROXY_HDR_SZ, "sq", path, offset);
                    437:         if (retval > 0) {
                    438:             header.size = retval;
                    439:             header.type = T_TRUNCATE;
                    440:         }
                    441:         break;
                    442:     case T_UTIME:
                    443:         path = va_arg(ap, V9fsString *);
                    444:         spec[0].tv_sec = va_arg(ap, long);
                    445:         spec[0].tv_nsec = va_arg(ap, long);
                    446:         spec[1].tv_sec = va_arg(ap, long);
                    447:         spec[1].tv_nsec = va_arg(ap, long);
                    448:         retval = proxy_marshal(iovec, PROXY_HDR_SZ, "sqqqq", path,
                    449:                                     spec[0].tv_sec, spec[1].tv_nsec,
                    450:                                     spec[1].tv_sec, spec[1].tv_nsec);
                    451:         if (retval > 0) {
                    452:             header.size = retval;
                    453:             header.type = T_UTIME;
                    454:         }
                    455:         break;
                    456:     case T_RENAME:
                    457:         oldpath = va_arg(ap, V9fsString *);
                    458:         path = va_arg(ap, V9fsString *);
                    459:         retval = proxy_marshal(iovec, PROXY_HDR_SZ, "ss", oldpath, path);
                    460:         if (retval > 0) {
                    461:             header.size = retval;
                    462:             header.type = T_RENAME;
                    463:         }
                    464:         break;
                    465:     case T_REMOVE:
                    466:         path = va_arg(ap, V9fsString *);
                    467:         retval = proxy_marshal(iovec, PROXY_HDR_SZ, "s", path);
                    468:         if (retval > 0) {
                    469:             header.size = retval;
                    470:             header.type = T_REMOVE;
                    471:         }
                    472:         break;
                    473:     case T_LGETXATTR:
                    474:         size = va_arg(ap, int);
                    475:         path = va_arg(ap, V9fsString *);
                    476:         name = va_arg(ap, V9fsString *);
                    477:         retval = proxy_marshal(iovec, PROXY_HDR_SZ,
                    478:                                     "dss", size, path, name);
                    479:         if (retval > 0) {
                    480:             header.size = retval;
                    481:             header.type = T_LGETXATTR;
                    482:         }
                    483:         break;
                    484:     case T_LLISTXATTR:
                    485:         size = va_arg(ap, int);
                    486:         path = va_arg(ap, V9fsString *);
                    487:         retval = proxy_marshal(iovec, PROXY_HDR_SZ, "ds", size, path);
                    488:         if (retval > 0) {
                    489:             header.size = retval;
                    490:             header.type = T_LLISTXATTR;
                    491:         }
                    492:         break;
                    493:     case T_LSETXATTR:
                    494:         path = va_arg(ap, V9fsString *);
                    495:         name = va_arg(ap, V9fsString *);
                    496:         value = va_arg(ap, V9fsString *);
                    497:         size = va_arg(ap, int);
                    498:         flags = va_arg(ap, int);
                    499:         retval = proxy_marshal(iovec, PROXY_HDR_SZ, "sssdd",
                    500:                                     path, name, value, size, flags);
                    501:         if (retval > 0) {
                    502:             header.size = retval;
                    503:             header.type = T_LSETXATTR;
                    504:         }
                    505:         break;
                    506:     case T_LREMOVEXATTR:
                    507:         path = va_arg(ap, V9fsString *);
                    508:         name = va_arg(ap, V9fsString *);
                    509:         retval = proxy_marshal(iovec, PROXY_HDR_SZ, "ss", path, name);
                    510:         if (retval > 0) {
                    511:             header.size = retval;
                    512:             header.type = T_LREMOVEXATTR;
                    513:         }
                    514:         break;
                    515:     case T_GETVERSION:
                    516:         path = va_arg(ap, V9fsString *);
                    517:         retval = proxy_marshal(iovec, PROXY_HDR_SZ, "s", path);
                    518:         if (retval > 0) {
                    519:             header.size = retval;
                    520:             header.type = T_GETVERSION;
                    521:         }
                    522:         break;
                    523:     default:
                    524:         error_report("Invalid type %d\n", type);
                    525:         retval = -EINVAL;
                    526:         break;
                    527:     }
                    528:     va_end(ap);
                    529: 
                    530:     if (retval < 0) {
                    531:         goto err_out;
                    532:     }
                    533: 
                    534:     /* marshal the header details */
                    535:     proxy_marshal(iovec, 0, "dd", header.type, header.size);
                    536:     header.size += PROXY_HDR_SZ;
                    537: 
                    538:     retval = qemu_write_full(proxy->sockfd, iovec->iov_base, header.size);
                    539:     if (retval != header.size) {
                    540:         goto close_error;
                    541:     }
                    542: 
                    543:     switch (type) {
                    544:     case T_OPEN:
                    545:     case T_CREATE:
                    546:         /*
                    547:          * A file descriptor is returned as response for
                    548:          * T_OPEN,T_CREATE on success
                    549:          */
                    550:         if (v9fs_receivefd(proxy->sockfd, &retval) < 0) {
                    551:             goto close_error;
                    552:         }
                    553:         break;
                    554:     case T_MKNOD:
                    555:     case T_MKDIR:
                    556:     case T_SYMLINK:
                    557:     case T_LINK:
                    558:     case T_CHMOD:
                    559:     case T_CHOWN:
                    560:     case T_RENAME:
                    561:     case T_TRUNCATE:
                    562:     case T_UTIME:
                    563:     case T_REMOVE:
                    564:     case T_LSETXATTR:
                    565:     case T_LREMOVEXATTR:
                    566:         if (v9fs_receive_status(proxy, reply, &retval) < 0) {
                    567:             goto close_error;
                    568:         }
                    569:         break;
                    570:     case T_LSTAT:
                    571:     case T_READLINK:
                    572:     case T_STATFS:
                    573:     case T_GETVERSION:
                    574:         if (v9fs_receive_response(proxy, type, &retval, response) < 0) {
                    575:             goto close_error;
                    576:         }
                    577:         break;
                    578:     case T_LGETXATTR:
                    579:     case T_LLISTXATTR:
                    580:         if (!size) {
                    581:             if (v9fs_receive_status(proxy, reply, &retval) < 0) {
                    582:                 goto close_error;
                    583:             }
                    584:         } else {
                    585:             if (v9fs_receive_response(proxy, type, &retval, response) < 0) {
                    586:                 goto close_error;
                    587:             }
                    588:         }
                    589:         break;
                    590:     }
                    591: 
                    592: err_out:
                    593:     qemu_mutex_unlock(&proxy->mutex);
                    594:     return retval;
                    595: 
                    596: close_error:
                    597:     close(proxy->sockfd);
                    598:     proxy->sockfd = -1;
                    599:     qemu_mutex_unlock(&proxy->mutex);
                    600:     return -EIO;
                    601: }
                    602: 
                    603: static int proxy_lstat(FsContext *fs_ctx, V9fsPath *fs_path, struct stat *stbuf)
                    604: {
                    605:     int retval;
                    606:     retval = v9fs_request(fs_ctx->private, T_LSTAT, stbuf, "s", fs_path);
                    607:     if (retval < 0) {
                    608:         errno = -retval;
                    609:         return -1;
                    610:     }
                    611:     return retval;
                    612: }
                    613: 
                    614: static ssize_t proxy_readlink(FsContext *fs_ctx, V9fsPath *fs_path,
                    615:                               char *buf, size_t bufsz)
                    616: {
                    617:     int retval;
                    618:     retval = v9fs_request(fs_ctx->private, T_READLINK, buf, "sd",
                    619:                           fs_path, bufsz);
                    620:     if (retval < 0) {
                    621:         errno = -retval;
                    622:         return -1;
                    623:     }
                    624:     return strlen(buf);
                    625: }
                    626: 
                    627: static int proxy_close(FsContext *ctx, V9fsFidOpenState *fs)
                    628: {
                    629:     return close(fs->fd);
                    630: }
                    631: 
                    632: static int proxy_closedir(FsContext *ctx, V9fsFidOpenState *fs)
                    633: {
                    634:     return closedir(fs->dir);
                    635: }
                    636: 
                    637: static int proxy_open(FsContext *ctx, V9fsPath *fs_path,
                    638:                       int flags, V9fsFidOpenState *fs)
                    639: {
                    640:     fs->fd = v9fs_request(ctx->private, T_OPEN, NULL, "sd", fs_path, flags);
                    641:     if (fs->fd < 0) {
                    642:         errno = -fs->fd;
                    643:         fs->fd = -1;
                    644:     }
                    645:     return fs->fd;
                    646: }
                    647: 
                    648: static int proxy_opendir(FsContext *ctx,
                    649:                          V9fsPath *fs_path, V9fsFidOpenState *fs)
                    650: {
                    651:     int serrno, fd;
                    652: 
                    653:     fs->dir = NULL;
                    654:     fd = v9fs_request(ctx->private, T_OPEN, NULL, "sd", fs_path, O_DIRECTORY);
                    655:     if (fd < 0) {
                    656:         errno = -fd;
                    657:         return -1;
                    658:     }
                    659:     fs->dir = fdopendir(fd);
                    660:     if (!fs->dir) {
                    661:         serrno = errno;
                    662:         close(fd);
                    663:         errno = serrno;
                    664:         return -1;
                    665:     }
                    666:     return 0;
                    667: }
                    668: 
                    669: static void proxy_rewinddir(FsContext *ctx, V9fsFidOpenState *fs)
                    670: {
                    671:     return rewinddir(fs->dir);
                    672: }
                    673: 
                    674: static off_t proxy_telldir(FsContext *ctx, V9fsFidOpenState *fs)
                    675: {
                    676:     return telldir(fs->dir);
                    677: }
                    678: 
                    679: static int proxy_readdir_r(FsContext *ctx, V9fsFidOpenState *fs,
                    680:                            struct dirent *entry,
                    681:                            struct dirent **result)
                    682: {
                    683:     return readdir_r(fs->dir, entry, result);
                    684: }
                    685: 
                    686: static void proxy_seekdir(FsContext *ctx, V9fsFidOpenState *fs, off_t off)
                    687: {
                    688:     return seekdir(fs->dir, off);
                    689: }
                    690: 
                    691: static ssize_t proxy_preadv(FsContext *ctx, V9fsFidOpenState *fs,
                    692:                             const struct iovec *iov,
                    693:                             int iovcnt, off_t offset)
                    694: {
                    695: #ifdef CONFIG_PREADV
                    696:     return preadv(fs->fd, iov, iovcnt, offset);
                    697: #else
                    698:     int err = lseek(fs->fd, offset, SEEK_SET);
                    699:     if (err == -1) {
                    700:         return err;
                    701:     } else {
                    702:         return readv(fs->fd, iov, iovcnt);
                    703:     }
                    704: #endif
                    705: }
                    706: 
                    707: static ssize_t proxy_pwritev(FsContext *ctx, V9fsFidOpenState *fs,
                    708:                              const struct iovec *iov,
                    709:                              int iovcnt, off_t offset)
                    710: {
                    711:     ssize_t ret;
                    712: 
                    713: #ifdef CONFIG_PREADV
                    714:     ret = pwritev(fs->fd, iov, iovcnt, offset);
                    715: #else
                    716:     int err = lseek(fs->fd, offset, SEEK_SET);
                    717:     if (err == -1) {
                    718:         return err;
                    719:     } else {
                    720:         ret = writev(fs->fd, iov, iovcnt);
                    721:     }
                    722: #endif
                    723: #ifdef CONFIG_SYNC_FILE_RANGE
                    724:     if (ret > 0 && ctx->export_flags & V9FS_IMMEDIATE_WRITEOUT) {
                    725:         /*
                    726:          * Initiate a writeback. This is not a data integrity sync.
                    727:          * We want to ensure that we don't leave dirty pages in the cache
                    728:          * after write when writeout=immediate is sepcified.
                    729:          */
                    730:         sync_file_range(fs->fd, offset, ret,
                    731:                         SYNC_FILE_RANGE_WAIT_BEFORE | SYNC_FILE_RANGE_WRITE);
                    732:     }
                    733: #endif
                    734:     return ret;
                    735: }
                    736: 
                    737: static int proxy_chmod(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
                    738: {
                    739:     int retval;
                    740:     retval = v9fs_request(fs_ctx->private, T_CHMOD, NULL, "sd",
                    741:                           fs_path, credp->fc_mode);
                    742:     if (retval < 0) {
                    743:         errno = -retval;
                    744:     }
                    745:     return retval;
                    746: }
                    747: 
                    748: static int proxy_mknod(FsContext *fs_ctx, V9fsPath *dir_path,
                    749:                        const char *name, FsCred *credp)
                    750: {
                    751:     int retval;
                    752:     V9fsString fullname;
                    753: 
                    754:     v9fs_string_init(&fullname);
                    755:     v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
                    756: 
                    757:     retval = v9fs_request(fs_ctx->private, T_MKNOD, NULL, "sdqdd",
                    758:                           &fullname, credp->fc_mode, credp->fc_rdev,
                    759:                           credp->fc_uid, credp->fc_gid);
                    760:     v9fs_string_free(&fullname);
                    761:     if (retval < 0) {
                    762:         errno = -retval;
                    763:         retval = -1;
                    764:     }
                    765:     return retval;
                    766: }
                    767: 
                    768: static int proxy_mkdir(FsContext *fs_ctx, V9fsPath *dir_path,
                    769:                        const char *name, FsCred *credp)
                    770: {
                    771:     int retval;
                    772:     V9fsString fullname;
                    773: 
                    774:     v9fs_string_init(&fullname);
                    775:     v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
                    776: 
                    777:     retval = v9fs_request(fs_ctx->private, T_MKDIR, NULL, "sddd", &fullname,
                    778:                           credp->fc_mode, credp->fc_uid, credp->fc_gid);
                    779:     v9fs_string_free(&fullname);
                    780:     if (retval < 0) {
                    781:         errno = -retval;
                    782:         retval = -1;
                    783:     }
                    784:     v9fs_string_free(&fullname);
                    785:     return retval;
                    786: }
                    787: 
                    788: static int proxy_fstat(FsContext *fs_ctx, int fid_type,
                    789:                        V9fsFidOpenState *fs, struct stat *stbuf)
                    790: {
                    791:     int fd;
                    792: 
                    793:     if (fid_type == P9_FID_DIR) {
                    794:         fd = dirfd(fs->dir);
                    795:     } else {
                    796:         fd = fs->fd;
                    797:     }
                    798:     return fstat(fd, stbuf);
                    799: }
                    800: 
                    801: static int proxy_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name,
                    802:                        int flags, FsCred *credp, V9fsFidOpenState *fs)
                    803: {
                    804:     V9fsString fullname;
                    805: 
                    806:     v9fs_string_init(&fullname);
                    807:     v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
                    808: 
                    809:     fs->fd = v9fs_request(fs_ctx->private, T_CREATE, NULL, "sdddd",
                    810:                           &fullname, flags, credp->fc_mode,
                    811:                           credp->fc_uid, credp->fc_gid);
                    812:     v9fs_string_free(&fullname);
                    813:     if (fs->fd < 0) {
                    814:         errno = -fs->fd;
                    815:         fs->fd = -1;
                    816:     }
                    817:     return fs->fd;
                    818: }
                    819: 
                    820: static int proxy_symlink(FsContext *fs_ctx, const char *oldpath,
                    821:                          V9fsPath *dir_path, const char *name, FsCred *credp)
                    822: {
                    823:     int retval;
                    824:     V9fsString fullname, target;
                    825: 
                    826:     v9fs_string_init(&fullname);
                    827:     v9fs_string_init(&target);
                    828: 
                    829:     v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
                    830:     v9fs_string_sprintf(&target, "%s", oldpath);
                    831: 
                    832:     retval = v9fs_request(fs_ctx->private, T_SYMLINK, NULL, "ssdd",
                    833:                           &target, &fullname, credp->fc_uid, credp->fc_gid);
                    834:     v9fs_string_free(&fullname);
                    835:     v9fs_string_free(&target);
                    836:     if (retval < 0) {
                    837:         errno = -retval;
                    838:         retval = -1;
                    839:     }
                    840:     return retval;
                    841: }
                    842: 
                    843: static int proxy_link(FsContext *ctx, V9fsPath *oldpath,
                    844:                       V9fsPath *dirpath, const char *name)
                    845: {
                    846:     int retval;
                    847:     V9fsString newpath;
                    848: 
                    849:     v9fs_string_init(&newpath);
                    850:     v9fs_string_sprintf(&newpath, "%s/%s", dirpath->data, name);
                    851: 
                    852:     retval = v9fs_request(ctx->private, T_LINK, NULL, "ss", oldpath, &newpath);
                    853:     v9fs_string_free(&newpath);
                    854:     if (retval < 0) {
                    855:         errno = -retval;
                    856:         retval = -1;
                    857:     }
                    858:     return retval;
                    859: }
                    860: 
                    861: static int proxy_truncate(FsContext *ctx, V9fsPath *fs_path, off_t size)
                    862: {
                    863:     int retval;
                    864: 
                    865:     retval = v9fs_request(ctx->private, T_TRUNCATE, NULL, "sq", fs_path, size);
                    866:     if (retval < 0) {
                    867:         errno = -retval;
                    868:         return -1;
                    869:     }
                    870:     return 0;
                    871: }
                    872: 
                    873: static int proxy_rename(FsContext *ctx, const char *oldpath,
                    874:                         const char *newpath)
                    875: {
                    876:     int retval;
                    877:     V9fsString oldname, newname;
                    878: 
                    879:     v9fs_string_init(&oldname);
                    880:     v9fs_string_init(&newname);
                    881: 
                    882:     v9fs_string_sprintf(&oldname, "%s", oldpath);
                    883:     v9fs_string_sprintf(&newname, "%s", newpath);
                    884:     retval = v9fs_request(ctx->private, T_RENAME, NULL, "ss",
                    885:                           &oldname, &newname);
                    886:     v9fs_string_free(&oldname);
                    887:     v9fs_string_free(&newname);
                    888:     if (retval < 0) {
                    889:         errno = -retval;
                    890:     }
                    891:     return retval;
                    892: }
                    893: 
                    894: static int proxy_chown(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
                    895: {
                    896:     int retval;
                    897:     retval = v9fs_request(fs_ctx->private, T_CHOWN, NULL, "sdd",
                    898:                           fs_path, credp->fc_uid, credp->fc_gid);
                    899:     if (retval < 0) {
                    900:         errno = -retval;
                    901:     }
                    902:     return retval;
                    903: }
                    904: 
                    905: static int proxy_utimensat(FsContext *s, V9fsPath *fs_path,
                    906:                            const struct timespec *buf)
                    907: {
                    908:     int retval;
                    909:     retval = v9fs_request(s->private, T_UTIME, NULL, "sqqqq",
                    910:                           fs_path,
                    911:                           buf[0].tv_sec, buf[0].tv_nsec,
                    912:                           buf[1].tv_sec, buf[1].tv_nsec);
                    913:     if (retval < 0) {
                    914:         errno = -retval;
                    915:     }
                    916:     return retval;
                    917: }
                    918: 
                    919: static int proxy_remove(FsContext *ctx, const char *path)
                    920: {
                    921:     int retval;
                    922:     V9fsString name;
                    923:     v9fs_string_init(&name);
                    924:     v9fs_string_sprintf(&name, "%s", path);
                    925:     retval = v9fs_request(ctx->private, T_REMOVE, NULL, "s", &name);
                    926:     v9fs_string_free(&name);
                    927:     if (retval < 0) {
                    928:         errno = -retval;
                    929:     }
                    930:     return retval;
                    931: }
                    932: 
                    933: static int proxy_fsync(FsContext *ctx, int fid_type,
                    934:                        V9fsFidOpenState *fs, int datasync)
                    935: {
                    936:     int fd;
                    937: 
                    938:     if (fid_type == P9_FID_DIR) {
                    939:         fd = dirfd(fs->dir);
                    940:     } else {
                    941:         fd = fs->fd;
                    942:     }
                    943: 
                    944:     if (datasync) {
                    945:         return qemu_fdatasync(fd);
                    946:     } else {
                    947:         return fsync(fd);
                    948:     }
                    949: }
                    950: 
                    951: static int proxy_statfs(FsContext *s, V9fsPath *fs_path, struct statfs *stbuf)
                    952: {
                    953:     int retval;
                    954:     retval = v9fs_request(s->private, T_STATFS, stbuf, "s", fs_path);
                    955:     if (retval < 0) {
                    956:         errno = -retval;
                    957:         return -1;
                    958:     }
                    959:     return retval;
                    960: }
                    961: 
                    962: static ssize_t proxy_lgetxattr(FsContext *ctx, V9fsPath *fs_path,
                    963:                                const char *name, void *value, size_t size)
                    964: {
                    965:     int retval;
                    966:     V9fsString xname;
                    967: 
                    968:     v9fs_string_init(&xname);
                    969:     v9fs_string_sprintf(&xname, "%s", name);
                    970:     retval = v9fs_request(ctx->private, T_LGETXATTR, value, "dss", size,
                    971:                           fs_path, &xname);
                    972:     v9fs_string_free(&xname);
                    973:     if (retval < 0) {
                    974:         errno = -retval;
                    975:     }
                    976:     return retval;
                    977: }
                    978: 
                    979: static ssize_t proxy_llistxattr(FsContext *ctx, V9fsPath *fs_path,
                    980:                                 void *value, size_t size)
                    981: {
                    982:     int retval;
                    983:     retval = v9fs_request(ctx->private, T_LLISTXATTR, value, "ds", size,
                    984:                         fs_path);
                    985:     if (retval < 0) {
                    986:         errno = -retval;
                    987:     }
                    988:     return retval;
                    989: }
                    990: 
                    991: static int proxy_lsetxattr(FsContext *ctx, V9fsPath *fs_path, const char *name,
                    992:                            void *value, size_t size, int flags)
                    993: {
                    994:     int retval;
                    995:     V9fsString xname, xvalue;
                    996: 
                    997:     v9fs_string_init(&xname);
                    998:     v9fs_string_sprintf(&xname, "%s", name);
                    999: 
                   1000:     v9fs_string_init(&xvalue);
                   1001:     xvalue.size = size;
                   1002:     xvalue.data = g_malloc(size);
                   1003:     memcpy(xvalue.data, value, size);
                   1004: 
                   1005:     retval = v9fs_request(ctx->private, T_LSETXATTR, value, "sssdd",
                   1006:                           fs_path, &xname, &xvalue, size, flags);
                   1007:     v9fs_string_free(&xname);
                   1008:     v9fs_string_free(&xvalue);
                   1009:     if (retval < 0) {
                   1010:         errno = -retval;
                   1011:     }
                   1012:     return retval;
                   1013: }
                   1014: 
                   1015: static int proxy_lremovexattr(FsContext *ctx, V9fsPath *fs_path,
                   1016:                               const char *name)
                   1017: {
                   1018:     int retval;
                   1019:     V9fsString xname;
                   1020: 
                   1021:     v9fs_string_init(&xname);
                   1022:     v9fs_string_sprintf(&xname, "%s", name);
                   1023:     retval = v9fs_request(ctx->private, T_LREMOVEXATTR, NULL, "ss",
                   1024:                           fs_path, &xname);
                   1025:     v9fs_string_free(&xname);
                   1026:     if (retval < 0) {
                   1027:         errno = -retval;
                   1028:     }
                   1029:     return retval;
                   1030: }
                   1031: 
                   1032: static int proxy_name_to_path(FsContext *ctx, V9fsPath *dir_path,
                   1033:                               const char *name, V9fsPath *target)
                   1034: {
                   1035:     if (dir_path) {
                   1036:         v9fs_string_sprintf((V9fsString *)target, "%s/%s",
                   1037:                             dir_path->data, name);
                   1038:     } else {
                   1039:         v9fs_string_sprintf((V9fsString *)target, "%s", name);
                   1040:     }
                   1041:     /* Bump the size for including terminating NULL */
                   1042:     target->size++;
                   1043:     return 0;
                   1044: }
                   1045: 
                   1046: static int proxy_renameat(FsContext *ctx, V9fsPath *olddir,
                   1047:                           const char *old_name, V9fsPath *newdir,
                   1048:                           const char *new_name)
                   1049: {
                   1050:     int ret;
                   1051:     V9fsString old_full_name, new_full_name;
                   1052: 
                   1053:     v9fs_string_init(&old_full_name);
                   1054:     v9fs_string_init(&new_full_name);
                   1055: 
                   1056:     v9fs_string_sprintf(&old_full_name, "%s/%s", olddir->data, old_name);
                   1057:     v9fs_string_sprintf(&new_full_name, "%s/%s", newdir->data, new_name);
                   1058: 
                   1059:     ret = proxy_rename(ctx, old_full_name.data, new_full_name.data);
                   1060:     v9fs_string_free(&old_full_name);
                   1061:     v9fs_string_free(&new_full_name);
                   1062:     return ret;
                   1063: }
                   1064: 
                   1065: static int proxy_unlinkat(FsContext *ctx, V9fsPath *dir,
                   1066:                           const char *name, int flags)
                   1067: {
                   1068:     int ret;
                   1069:     V9fsString fullname;
                   1070:     v9fs_string_init(&fullname);
                   1071: 
                   1072:     v9fs_string_sprintf(&fullname, "%s/%s", dir->data, name);
                   1073:     ret = proxy_remove(ctx, fullname.data);
                   1074:     v9fs_string_free(&fullname);
                   1075: 
                   1076:     return ret;
                   1077: }
                   1078: 
                   1079: static int proxy_ioc_getversion(FsContext *fs_ctx, V9fsPath *path,
                   1080:                                 mode_t st_mode, uint64_t *st_gen)
                   1081: {
                   1082:     int err;
                   1083: 
                   1084:     /* Do not try to open special files like device nodes, fifos etc
                   1085:      * we can get fd for regular files and directories only
                   1086:      */
                   1087:     if (!S_ISREG(st_mode) && !S_ISDIR(st_mode)) {
                   1088:         return 0;
                   1089:     }
                   1090:     err = v9fs_request(fs_ctx->private, T_GETVERSION, st_gen, "s", path);
                   1091:     if (err < 0) {
                   1092:         errno = -err;
                   1093:         err = -1;
                   1094:     }
                   1095:     return err;
                   1096: }
                   1097: 
                   1098: static int connect_namedsocket(const char *path)
                   1099: {
                   1100:     int sockfd, size;
                   1101:     struct sockaddr_un helper;
                   1102: 
                   1103:     sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
                   1104:     if (sockfd < 0) {
                   1105:         fprintf(stderr, "socket %s\n", strerror(errno));
                   1106:         return -1;
                   1107:     }
                   1108:     strcpy(helper.sun_path, path);
                   1109:     helper.sun_family = AF_UNIX;
                   1110:     size = strlen(helper.sun_path) + sizeof(helper.sun_family);
                   1111:     if (connect(sockfd, (struct sockaddr *)&helper, size) < 0) {
                   1112:         fprintf(stderr, "socket error\n");
                   1113:         return -1;
                   1114:     }
                   1115: 
                   1116:     /* remove the socket for security reasons */
                   1117:     unlink(path);
                   1118:     return sockfd;
                   1119: }
                   1120: 
                   1121: static int proxy_parse_opts(QemuOpts *opts, struct FsDriverEntry *fs)
                   1122: {
                   1123:     const char *socket = qemu_opt_get(opts, "socket");
                   1124:     const char *sock_fd = qemu_opt_get(opts, "sock_fd");
                   1125: 
                   1126:     if (!socket && !sock_fd) {
                   1127:         fprintf(stderr, "socket and sock_fd none of the option specified\n");
                   1128:         return -1;
                   1129:     }
                   1130:     if (socket && sock_fd) {
                   1131:         fprintf(stderr, "Both socket and sock_fd options specified\n");
                   1132:         return -1;
                   1133:     }
                   1134:     if (socket) {
                   1135:         fs->path = g_strdup(socket);
                   1136:         fs->export_flags = V9FS_PROXY_SOCK_NAME;
                   1137:     } else {
                   1138:         fs->path = g_strdup(sock_fd);
                   1139:         fs->export_flags = V9FS_PROXY_SOCK_FD;
                   1140:     }
                   1141:     return 0;
                   1142: }
                   1143: 
                   1144: static int proxy_init(FsContext *ctx)
                   1145: {
                   1146:     V9fsProxy *proxy = g_malloc(sizeof(V9fsProxy));
                   1147:     int sock_id;
                   1148: 
                   1149:     if (ctx->export_flags & V9FS_PROXY_SOCK_NAME) {
                   1150:         sock_id = connect_namedsocket(ctx->fs_root);
                   1151:     } else {
                   1152:         sock_id = atoi(ctx->fs_root);
                   1153:         if (sock_id < 0) {
                   1154:             fprintf(stderr, "socket descriptor not initialized\n");
                   1155:             return -1;
                   1156:         }
                   1157:     }
                   1158:     g_free(ctx->fs_root);
                   1159: 
                   1160:     proxy->in_iovec.iov_base  = g_malloc(PROXY_MAX_IO_SZ + PROXY_HDR_SZ);
                   1161:     proxy->in_iovec.iov_len   = PROXY_MAX_IO_SZ + PROXY_HDR_SZ;
                   1162:     proxy->out_iovec.iov_base = g_malloc(PROXY_MAX_IO_SZ + PROXY_HDR_SZ);
                   1163:     proxy->out_iovec.iov_len  = PROXY_MAX_IO_SZ + PROXY_HDR_SZ;
                   1164: 
                   1165:     ctx->private = proxy;
                   1166:     proxy->sockfd = sock_id;
                   1167:     qemu_mutex_init(&proxy->mutex);
                   1168: 
                   1169:     ctx->export_flags |= V9FS_PATHNAME_FSCONTEXT;
                   1170:     ctx->exops.get_st_gen = proxy_ioc_getversion;
                   1171:     return 0;
                   1172: }
                   1173: 
                   1174: FileOperations proxy_ops = {
                   1175:     .parse_opts   = proxy_parse_opts,
                   1176:     .init         = proxy_init,
                   1177:     .lstat        = proxy_lstat,
                   1178:     .readlink     = proxy_readlink,
                   1179:     .close        = proxy_close,
                   1180:     .closedir     = proxy_closedir,
                   1181:     .open         = proxy_open,
                   1182:     .opendir      = proxy_opendir,
                   1183:     .rewinddir    = proxy_rewinddir,
                   1184:     .telldir      = proxy_telldir,
                   1185:     .readdir_r    = proxy_readdir_r,
                   1186:     .seekdir      = proxy_seekdir,
                   1187:     .preadv       = proxy_preadv,
                   1188:     .pwritev      = proxy_pwritev,
                   1189:     .chmod        = proxy_chmod,
                   1190:     .mknod        = proxy_mknod,
                   1191:     .mkdir        = proxy_mkdir,
                   1192:     .fstat        = proxy_fstat,
                   1193:     .open2        = proxy_open2,
                   1194:     .symlink      = proxy_symlink,
                   1195:     .link         = proxy_link,
                   1196:     .truncate     = proxy_truncate,
                   1197:     .rename       = proxy_rename,
                   1198:     .chown        = proxy_chown,
                   1199:     .utimensat    = proxy_utimensat,
                   1200:     .remove       = proxy_remove,
                   1201:     .fsync        = proxy_fsync,
                   1202:     .statfs       = proxy_statfs,
                   1203:     .lgetxattr    = proxy_lgetxattr,
                   1204:     .llistxattr   = proxy_llistxattr,
                   1205:     .lsetxattr    = proxy_lsetxattr,
                   1206:     .lremovexattr = proxy_lremovexattr,
                   1207:     .name_to_path = proxy_name_to_path,
                   1208:     .renameat     = proxy_renameat,
                   1209:     .unlinkat     = proxy_unlinkat,
                   1210: };

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.