Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/lib9p/backend/fs.c
39534 views
1
/*
2
* Copyright 2016 Jakub Klama <[email protected]>
3
* All rights reserved
4
*
5
* Redistribution and use in source and binary forms, with or without
6
* modification, are permitted providing that the following conditions
7
* are met:
8
* 1. Redistributions of source code must retain the above copyright
9
* notice, this list of conditions and the following disclaimer.
10
* 2. Redistributions in binary form must reproduce the above copyright
11
* notice, this list of conditions and the following disclaimer in the
12
* documentation and/or other materials provided with the distribution.
13
*
14
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
18
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
22
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
23
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24
* POSSIBILITY OF SUCH DAMAGE.
25
*
26
*/
27
28
/*
29
* Based on libixp code: �2007-2010 Kris Maglione <maglione.k at Gmail>
30
*/
31
32
#include <stdlib.h>
33
#include <string.h>
34
#include <unistd.h>
35
#include <stdbool.h>
36
#include <fcntl.h>
37
#include <errno.h>
38
#include <assert.h>
39
#include <sys/types.h>
40
#include <sys/stat.h>
41
#include <sys/mount.h>
42
#include <sys/param.h>
43
#include <sys/queue.h>
44
#include <sys/socket.h>
45
#include <sys/un.h>
46
#include <dirent.h>
47
#include <pwd.h>
48
#include <grp.h>
49
#include <libgen.h>
50
#include <pthread.h>
51
#include "../lib9p.h"
52
#include "../lib9p_impl.h"
53
#include "../fid.h"
54
#include "../log.h"
55
#include "../rfuncs.h"
56
#include "../genacl.h"
57
#include "backend.h"
58
#include "fs.h"
59
60
#if defined(WITH_CASPER)
61
#include <libcasper.h>
62
#include <casper/cap_pwd.h>
63
#include <casper/cap_grp.h>
64
#endif
65
66
#if defined(__FreeBSD__)
67
#include <sys/param.h>
68
#if __FreeBSD_version >= 1000000
69
#define HAVE_BINDAT
70
#endif
71
#endif
72
73
#if defined(__FreeBSD__)
74
#define HAVE_BIRTHTIME
75
#endif
76
77
#if defined(__APPLE__)
78
#include <sys/syscall.h>
79
#include "Availability.h"
80
#define ACL_TYPE_NFS4 ACL_TYPE_EXTENDED
81
#endif
82
83
struct fs_softc {
84
int fs_rootfd;
85
bool fs_readonly;
86
#if defined(WITH_CASPER)
87
cap_channel_t *fs_cappwd;
88
cap_channel_t *fs_capgrp;
89
#endif
90
};
91
92
struct fs_fid {
93
DIR *ff_dir;
94
int ff_dirfd;
95
int ff_fd;
96
int ff_flags;
97
char *ff_name;
98
struct fs_authinfo *ff_ai;
99
pthread_mutex_t ff_mtx;
100
struct l9p_acl *ff_acl; /* cached ACL if any */
101
};
102
103
#define FF_NO_NFSV4_ACL 0x01 /* don't go looking for NFSv4 ACLs */
104
/* FF_NO_POSIX_ACL 0x02 -- not yet */
105
106
/*
107
* Our authinfo consists of:
108
*
109
* - a reference count
110
* - a uid
111
* - a gid-set
112
*
113
* The "default" gid is the first gid in the git-set, provided the
114
* set size is at least 1. The set-size may be zero, though.
115
*
116
* Adjustments to the ref-count must be atomic, once it's shared.
117
* It would be nice to use C11 atomics here but they are not common
118
* enough to all systems just yet; for now, we use a mutex.
119
*
120
* Note that some ops (Linux style ones) pass an effective gid for
121
* the op, in which case, that gid may override. To achieve this
122
* effect, permissions testing functions also take an extra gid.
123
* If this gid is (gid_t)-1 it is not used and only the remaining
124
* gids take part.
125
*
126
* The uid may also be (uid_t)-1, meaning "no uid was available
127
* at all at attach time". In this case, new files inherit parent
128
* directory uids.
129
*
130
* The refcount is simply the number of "openfile"s using this
131
* authinfo (so that when the last ref goes away, we can free it).
132
*
133
* There are also master ACL flags (same as in ff_flags).
134
*/
135
struct fs_authinfo {
136
pthread_mutex_t ai_mtx; /* lock for refcnt */
137
uint32_t ai_refcnt;
138
int ai_flags;
139
uid_t ai_uid;
140
int ai_ngids;
141
gid_t ai_gids[]; /* NB: flexible array member */
142
};
143
144
/*
145
* We have a global-static mutex for single-threading Tattach
146
* requests, which use getpwnam (and indirectly, getgr* functions)
147
* which are not reentrant.
148
*/
149
static bool fs_attach_mutex_inited;
150
static pthread_mutex_t fs_attach_mutex;
151
152
/*
153
* Internal functions (except inline functions).
154
*/
155
static struct passwd *fs_getpwuid(struct fs_softc *, uid_t, struct r_pgdata *);
156
static struct group *fs_getgrgid(struct fs_softc *, gid_t, struct r_pgdata *);
157
static int fs_buildname(struct l9p_fid *, char *, char *, size_t);
158
static int fs_pdir(struct fs_softc *, struct l9p_fid *, char *, size_t,
159
struct stat *st);
160
static int fs_dpf(char *, char *, size_t);
161
static int fs_oflags_dotu(int, int *);
162
static int fs_oflags_dotl(uint32_t, int *, enum l9p_omode *);
163
static int fs_nde(struct fs_softc *, struct l9p_fid *, bool, gid_t,
164
struct stat *, uid_t *, gid_t *);
165
static struct fs_fid *open_fid(int, const char *, struct fs_authinfo *, bool);
166
static void dostat(struct fs_softc *, struct l9p_stat *, char *,
167
struct stat *, bool dotu);
168
static void dostatfs(struct l9p_statfs *, struct statfs *, long);
169
static void fillacl(struct fs_fid *ff);
170
static struct l9p_acl *getacl(struct fs_fid *ff, int fd, const char *path);
171
static void dropacl(struct fs_fid *ff);
172
static struct l9p_acl *look_for_nfsv4_acl(struct fs_fid *ff, int fd,
173
const char *path);
174
static int check_access(int32_t,
175
struct l9p_acl *, struct stat *, struct l9p_acl *, struct stat *,
176
struct fs_authinfo *, gid_t);
177
static void generate_qid(struct stat *, struct l9p_qid *);
178
179
static int fs_icreate(void *, struct l9p_fid *, char *, int,
180
bool, mode_t, gid_t, struct stat *);
181
static int fs_iopen(void *, struct l9p_fid *, int, enum l9p_omode,
182
gid_t, struct stat *);
183
static int fs_imkdir(void *, struct l9p_fid *, char *,
184
bool, mode_t, gid_t, struct stat *);
185
static int fs_imkfifo(void *, struct l9p_fid *, char *,
186
bool, mode_t, gid_t, struct stat *);
187
static int fs_imknod(void *, struct l9p_fid *, char *,
188
bool, mode_t, dev_t, gid_t, struct stat *);
189
static int fs_imksocket(void *, struct l9p_fid *, char *,
190
bool, mode_t, gid_t, struct stat *);
191
static int fs_isymlink(void *, struct l9p_fid *, char *, char *,
192
gid_t, struct stat *);
193
194
/*
195
* Internal functions implementing backend.
196
*/
197
static int fs_attach(void *, struct l9p_request *);
198
static int fs_clunk(void *, struct l9p_fid *);
199
static int fs_create(void *, struct l9p_request *);
200
static int fs_open(void *, struct l9p_request *);
201
static int fs_read(void *, struct l9p_request *);
202
static int fs_remove(void *, struct l9p_fid *);
203
static int fs_stat(void *, struct l9p_request *);
204
static int fs_walk(void *, struct l9p_request *);
205
static int fs_write(void *, struct l9p_request *);
206
static int fs_wstat(void *, struct l9p_request *);
207
static int fs_statfs(void *, struct l9p_request *);
208
static int fs_lopen(void *, struct l9p_request *);
209
static int fs_lcreate(void *, struct l9p_request *);
210
static int fs_symlink(void *, struct l9p_request *);
211
static int fs_mknod(void *, struct l9p_request *);
212
static int fs_rename(void *, struct l9p_request *);
213
static int fs_readlink(void *, struct l9p_request *);
214
static int fs_getattr(void *, struct l9p_request *);
215
static int fs_setattr(void *, struct l9p_request *);
216
static int fs_xattrwalk(void *, struct l9p_request *);
217
static int fs_xattrcreate(void *, struct l9p_request *);
218
static int fs_readdir(void *, struct l9p_request *);
219
static int fs_fsync(void *, struct l9p_request *);
220
static int fs_lock(void *, struct l9p_request *);
221
static int fs_getlock(void *, struct l9p_request *);
222
static int fs_link(void *, struct l9p_request *);
223
static int fs_renameat(void *, struct l9p_request *);
224
static int fs_unlinkat(void *, struct l9p_request *);
225
static void fs_freefid(void *, struct l9p_fid *);
226
227
/*
228
* Convert from 9p2000 open/create mode to Unix-style O_* flags.
229
* This includes 9p2000.u extensions, but not 9p2000.L protocol,
230
* which has entirely different open, create, etc., flag bits.
231
*
232
* The <mode> given here is the one-byte (uint8_t) "mode"
233
* argument to Tcreate or Topen, so it can have at most 8 bits.
234
*
235
* https://swtch.com/plan9port/man/man9/open.html and
236
* http://plan9.bell-labs.com/magic/man2html/5/open
237
* both say:
238
*
239
* The [low two bits of the] mode field determines the
240
* type of I/O ... [I]f mode has the OTRUNC (0x10) bit
241
* set, the file is to be truncated, which requires write
242
* permission ...; if the mode has the ORCLOSE (0x40) bit
243
* set, the file is to be removed when the fid is clunked,
244
* which requires permission to remove the file from its
245
* directory. All other bits in mode should be zero. It
246
* is illegal to write a directory, truncate it, or
247
* attempt to remove it on close.
248
*
249
* 9P2000.u may add ODIRECT (0x80); this is not completely clear.
250
* The fcall.h header defines OCEXEC (0x20) as well, but it makes
251
* no sense to send this to a server. There seem to be no bits
252
* 0x04 and 0x08.
253
*
254
* We always turn on O_NOCTTY since as a server, we never want
255
* to gain a controlling terminal. We always turn on O_NOFOLLOW
256
* for reasons described elsewhere.
257
*/
258
static int
259
fs_oflags_dotu(int mode, int *aflags)
260
{
261
int flags;
262
#define CONVERT(theirs, ours) \
263
do { \
264
if (mode & (theirs)) { \
265
mode &= ~(theirs); \
266
flags |= ours; \
267
} \
268
} while (0)
269
270
switch (mode & L9P_OACCMODE) {
271
272
case L9P_OREAD:
273
default:
274
flags = O_RDONLY;
275
break;
276
277
case L9P_OWRITE:
278
flags = O_WRONLY;
279
break;
280
281
case L9P_ORDWR:
282
flags = O_RDWR;
283
break;
284
285
case L9P_OEXEC:
286
if (mode & L9P_OTRUNC)
287
return (EINVAL);
288
flags = O_RDONLY;
289
break;
290
}
291
292
flags |= O_NOCTTY | O_NOFOLLOW;
293
294
CONVERT(L9P_OTRUNC, O_TRUNC);
295
296
/*
297
* Now take away some flags locally:
298
* the access mode (already translated)
299
* ORCLOSE - caller only
300
* OCEXEC - makes no sense in server
301
* ODIRECT - not applicable here
302
* If there are any flag bits left after this,
303
* we were unable to translate them. For now, let's
304
* treat this as EINVAL so that we can catch problems.
305
*/
306
mode &= ~(L9P_OACCMODE | L9P_ORCLOSE | L9P_OCEXEC | L9P_ODIRECT);
307
if (mode != 0) {
308
L9P_LOG(L9P_INFO,
309
"fs_oflags_dotu: untranslated bits: %#x",
310
(unsigned)mode);
311
return (EINVAL);
312
}
313
314
*aflags = flags;
315
return (0);
316
#undef CONVERT
317
}
318
319
/*
320
* Convert from 9P2000.L (Linux) open mode bits to O_* flags.
321
* See fs_oflags_dotu above.
322
*
323
* Linux currently does not have open-for-exec, but there is a
324
* proposal for it using O_PATH|O_NOFOLLOW, now handled here.
325
*
326
* We may eventually also set L9P_ORCLOSE for L_O_TMPFILE.
327
*/
328
static int
329
fs_oflags_dotl(uint32_t l_mode, int *aflags, enum l9p_omode *ap9)
330
{
331
int flags;
332
enum l9p_omode p9;
333
#define CLEAR(theirs) l_mode &= ~(uint32_t)(theirs)
334
#define CONVERT(theirs, ours) \
335
do { \
336
if (l_mode & (theirs)) { \
337
CLEAR(theirs); \
338
flags |= ours; \
339
} \
340
} while (0)
341
342
/*
343
* Linux O_RDONLY, O_WRONLY, O_RDWR (0,1,2) match BSD/MacOS.
344
*/
345
flags = l_mode & O_ACCMODE;
346
if (flags == 3)
347
return (EINVAL);
348
CLEAR(O_ACCMODE);
349
350
if ((l_mode & (L9P_L_O_PATH | L9P_L_O_NOFOLLOW)) ==
351
(L9P_L_O_PATH | L9P_L_O_NOFOLLOW)) {
352
CLEAR(L9P_L_O_PATH | L9P_L_O_NOFOLLOW);
353
p9 = L9P_OEXEC;
354
} else {
355
/*
356
* Slightly dirty, but same dirt, really, as
357
* setting flags from l_mode & O_ACCMODE.
358
*/
359
p9 = (enum l9p_omode)flags; /* slightly dirty */
360
}
361
362
/* turn L_O_TMPFILE into L9P_ORCLOSE in *p9? */
363
if (l_mode & L9P_L_O_TRUNC)
364
p9 |= L9P_OTRUNC; /* but don't CLEAR yet */
365
366
flags |= O_NOCTTY | O_NOFOLLOW;
367
368
/*
369
* L_O_CREAT seems to be noise, since we get separate open
370
* and create. But it is actually set sometimes. We just
371
* throw it out here; create ops must set it themselves and
372
* open ops have no permissions bits and hence cannot create.
373
*
374
* L_O_EXCL does make sense on create ops, i.e., we can
375
* take a create op with or without L_O_EXCL. We pass that
376
* through.
377
*/
378
CLEAR(L9P_L_O_CREAT);
379
CONVERT(L9P_L_O_EXCL, O_EXCL);
380
CONVERT(L9P_L_O_TRUNC, O_TRUNC);
381
CONVERT(L9P_L_O_DIRECTORY, O_DIRECTORY);
382
CONVERT(L9P_L_O_APPEND, O_APPEND);
383
CONVERT(L9P_L_O_NONBLOCK, O_NONBLOCK);
384
385
/*
386
* Discard these as useless noise at our (server) end.
387
* (NOATIME might be useful but we can only set it on a
388
* per-mount basis.)
389
*/
390
CLEAR(L9P_L_O_CLOEXEC);
391
CLEAR(L9P_L_O_DIRECT);
392
CLEAR(L9P_L_O_DSYNC);
393
CLEAR(L9P_L_O_FASYNC);
394
CLEAR(L9P_L_O_LARGEFILE);
395
CLEAR(L9P_L_O_NOATIME);
396
CLEAR(L9P_L_O_NOCTTY);
397
CLEAR(L9P_L_O_NOFOLLOW);
398
CLEAR(L9P_L_O_SYNC);
399
400
if (l_mode != 0) {
401
L9P_LOG(L9P_INFO,
402
"fs_oflags_dotl: untranslated bits: %#x",
403
(unsigned)l_mode);
404
return (EINVAL);
405
}
406
407
*aflags = flags;
408
*ap9 = p9;
409
return (0);
410
#undef CLEAR
411
#undef CONVERT
412
}
413
414
static struct passwd *
415
fs_getpwuid(struct fs_softc *sc, uid_t uid, struct r_pgdata *pg)
416
{
417
#if defined(WITH_CASPER)
418
return (r_cap_getpwuid(sc->fs_cappwd, uid, pg));
419
#else
420
(void)sc;
421
return (r_getpwuid(uid, pg));
422
#endif
423
}
424
425
static struct group *
426
fs_getgrgid(struct fs_softc *sc, gid_t gid, struct r_pgdata *pg)
427
{
428
#if defined(WITH_CASPER)
429
return (r_cap_getgrgid(sc->fs_capgrp, gid, pg));
430
#else
431
(void)sc;
432
return (r_getgrgid(gid, pg));
433
#endif
434
}
435
436
/*
437
* Build full name of file by appending given name to directory name.
438
*/
439
static int
440
fs_buildname(struct l9p_fid *dir, char *name, char *buf, size_t size)
441
{
442
struct fs_fid *dirf = dir->lo_aux;
443
size_t dlen, nlen1;
444
445
assert(dirf != NULL);
446
dlen = strlen(dirf->ff_name);
447
nlen1 = strlen(name) + 1; /* +1 for '\0' */
448
if (dlen + 1 + nlen1 > size)
449
return (ENAMETOOLONG);
450
memcpy(buf, dirf->ff_name, dlen);
451
buf[dlen] = '/';
452
memcpy(buf + dlen + 1, name, nlen1);
453
return (0);
454
}
455
456
/*
457
* Build parent name of file by splitting it off. Return an error
458
* if the given fid represents the root, so that there is no such
459
* parent, or if the discovered parent is not a directory.
460
*/
461
static int
462
fs_pdir(struct fs_softc *sc __unused, struct l9p_fid *fid, char *buf,
463
size_t size, struct stat *st)
464
{
465
struct fs_fid *ff;
466
char *path;
467
468
ff = fid->lo_aux;
469
assert(ff != NULL);
470
path = ff->ff_name;
471
path = r_dirname(path, buf, size);
472
if (path == NULL)
473
return (ENAMETOOLONG);
474
if (fstatat(ff->ff_dirfd, path, st, AT_SYMLINK_NOFOLLOW) != 0)
475
return (errno);
476
if (!S_ISDIR(st->st_mode))
477
return (ENOTDIR);
478
return (0);
479
}
480
481
/*
482
* Like fs_buildname() but for adding a file name to a buffer
483
* already holding a directory name. Essentially does
484
* strcat(dbuf, "/");
485
* strcat(dbuf, fname);
486
* but with size checking and an ENAMETOOLONG error as needed.
487
*
488
* (Think of the function name as "directory plus-equals file".)
489
*/
490
static int
491
fs_dpf(char *dbuf, char *fname, size_t size)
492
{
493
size_t dlen, nlen1;
494
495
dlen = strlen(dbuf);
496
nlen1 = strlen(fname) + 1;
497
if (dlen + 1 + nlen1 > size)
498
return (ENAMETOOLONG);
499
dbuf[dlen] = '/';
500
memcpy(dbuf + dlen + 1, fname, nlen1);
501
return (0);
502
}
503
504
/*
505
* Prepare to create a new directory entry (open with O_CREAT,
506
* mkdir, etc -- any operation that creates a new inode),
507
* operating in parent data <dir>, based on authinfo <ai> and
508
* effective gid <egid>.
509
*
510
* The new entity should be owned by user/group <*nuid, *ngid>,
511
* if it's really a new entity. It will be a directory if isdir.
512
*
513
* Returns an error number if the entry should not be created
514
* (e.g., read-only file system or no permission to write in
515
* parent directory). Always sets *nuid and *ngid on success:
516
* in the worst case, when there is no available ID, this will
517
* use the parent directory's IDs. Fills in <*st> on success.
518
*/
519
static int
520
fs_nde(struct fs_softc *sc, struct l9p_fid *dir, bool isdir, gid_t egid,
521
struct stat *st, uid_t *nuid, gid_t *ngid)
522
{
523
struct fs_fid *dirf;
524
struct fs_authinfo *ai;
525
int32_t op;
526
int error;
527
528
if (sc->fs_readonly)
529
return (EROFS);
530
dirf = dir->lo_aux;
531
assert(dirf != NULL);
532
if (fstatat(dirf->ff_dirfd, dirf->ff_name, st,
533
AT_SYMLINK_NOFOLLOW) != 0)
534
return (errno);
535
if (!S_ISDIR(st->st_mode))
536
return (ENOTDIR);
537
dirf = dir->lo_aux;
538
ai = dirf->ff_ai;
539
fillacl(dirf);
540
op = isdir ? L9P_ACE_ADD_SUBDIRECTORY : L9P_ACE_ADD_FILE;
541
error = check_access(op, dirf->ff_acl, st, NULL, NULL, ai, egid);
542
if (error)
543
return (EPERM);
544
545
*nuid = ai->ai_uid != (uid_t)-1 ? ai->ai_uid : st->st_uid;
546
*ngid = egid != (gid_t)-1 ? egid :
547
ai->ai_ngids > 0 ? ai->ai_gids[0] : st->st_gid;
548
return (0);
549
}
550
551
/*
552
* Allocate new open-file data structure to attach to a fid.
553
*
554
* The new file's authinfo is the same as the old one's, and
555
* we gain a reference.
556
*/
557
static struct fs_fid *
558
open_fid(int dirfd, const char *path, struct fs_authinfo *ai, bool creating)
559
{
560
struct fs_fid *ret;
561
uint32_t newcount;
562
int error;
563
564
ret = l9p_calloc(1, sizeof(*ret));
565
error = pthread_mutex_init(&ret->ff_mtx, NULL);
566
if (error) {
567
free(ret);
568
return (NULL);
569
}
570
ret->ff_fd = -1;
571
ret->ff_dirfd = dirfd;
572
ret->ff_name = strdup(path);
573
if (ret->ff_name == NULL) {
574
pthread_mutex_destroy(&ret->ff_mtx);
575
free(ret);
576
return (NULL);
577
}
578
pthread_mutex_lock(&ai->ai_mtx);
579
newcount = ++ai->ai_refcnt;
580
pthread_mutex_unlock(&ai->ai_mtx);
581
/*
582
* If we just incremented the count to 1, we're the *first*
583
* reference. This is only allowed when creating the authinfo,
584
* otherwise it means something has gone wrong. This cannot
585
* catch every bad (re)use of a freed authinfo but it may catch
586
* a few.
587
*/
588
assert(newcount > 1 || creating);
589
L9P_LOG(L9P_DEBUG, "authinfo %p now used by %lu",
590
(void *)ai, (u_long)newcount);
591
ret->ff_ai = ai;
592
return (ret);
593
}
594
595
static void
596
dostat(struct fs_softc *sc, struct l9p_stat *s, char *name,
597
struct stat *buf, bool dotu)
598
{
599
struct passwd *user;
600
struct group *group;
601
602
memset(s, 0, sizeof(struct l9p_stat));
603
604
generate_qid(buf, &s->qid);
605
606
s->type = 0;
607
s->dev = 0;
608
s->mode = buf->st_mode & 0777;
609
610
if (S_ISDIR(buf->st_mode))
611
s->mode |= L9P_DMDIR;
612
613
if (S_ISLNK(buf->st_mode) && dotu)
614
s->mode |= L9P_DMSYMLINK;
615
616
if (S_ISCHR(buf->st_mode) || S_ISBLK(buf->st_mode))
617
s->mode |= L9P_DMDEVICE;
618
619
if (S_ISSOCK(buf->st_mode))
620
s->mode |= L9P_DMSOCKET;
621
622
if (S_ISFIFO(buf->st_mode))
623
s->mode |= L9P_DMNAMEDPIPE;
624
625
s->atime = (uint32_t)buf->st_atime;
626
s->mtime = (uint32_t)buf->st_mtime;
627
s->length = (uint64_t)buf->st_size;
628
629
s->name = r_basename(name, NULL, 0);
630
631
if (!dotu) {
632
struct r_pgdata udata, gdata;
633
634
user = fs_getpwuid(sc, buf->st_uid, &udata);
635
group = fs_getgrgid(sc, buf->st_gid, &gdata);
636
s->uid = user != NULL ? strdup(user->pw_name) : NULL;
637
s->gid = group != NULL ? strdup(group->gr_name) : NULL;
638
s->muid = user != NULL ? strdup(user->pw_name) : NULL;
639
r_pgfree(&udata);
640
r_pgfree(&gdata);
641
} else {
642
/*
643
* When using 9P2000.u, we don't need to bother about
644
* providing user and group names in textual form.
645
*
646
* NB: if the asprintf()s fail, s->extension should
647
* be unset so we can ignore these.
648
*/
649
s->n_uid = buf->st_uid;
650
s->n_gid = buf->st_gid;
651
s->n_muid = buf->st_uid;
652
653
if (S_ISLNK(buf->st_mode)) {
654
char target[MAXPATHLEN];
655
ssize_t ret = readlink(name, target, MAXPATHLEN);
656
657
if (ret < 0) {
658
s->extension = NULL;
659
return;
660
}
661
662
s->extension = strndup(target, (size_t)ret);
663
}
664
665
if (S_ISBLK(buf->st_mode)) {
666
asprintf(&s->extension, "b %d %d", major(buf->st_rdev),
667
minor(buf->st_rdev));
668
}
669
670
if (S_ISCHR(buf->st_mode)) {
671
asprintf(&s->extension, "c %d %d", major(buf->st_rdev),
672
minor(buf->st_rdev));
673
}
674
}
675
}
676
677
static void dostatfs(struct l9p_statfs *out, struct statfs *in, long namelen)
678
{
679
680
out->type = L9P_FSTYPE;
681
out->bsize = in->f_bsize;
682
out->blocks = in->f_blocks;
683
out->bfree = in->f_bfree;
684
out->bavail = in->f_bavail;
685
out->files = in->f_files;
686
out->ffree = in->f_ffree;
687
out->namelen = (uint32_t)namelen;
688
out->fsid = ((uint64_t)in->f_fsid.val[0] << 32) |
689
(uint64_t)in->f_fsid.val[1];
690
}
691
692
static void
693
generate_qid(struct stat *buf, struct l9p_qid *qid)
694
{
695
qid->path = buf->st_ino;
696
qid->version = 0;
697
698
if (S_ISREG(buf->st_mode))
699
qid->type |= L9P_QTFILE;
700
701
if (S_ISDIR(buf->st_mode))
702
qid->type |= L9P_QTDIR;
703
704
if (S_ISLNK(buf->st_mode))
705
qid->type |= L9P_QTSYMLINK;
706
}
707
708
/*
709
* Fill in ff->ff_acl if it's not set yet. Skip if the "don't use
710
* ACLs" flag is set, and use the flag to remember failure so
711
* we don't bother retrying either.
712
*/
713
static void
714
fillacl(struct fs_fid *ff)
715
{
716
717
if (ff->ff_acl == NULL && (ff->ff_flags & FF_NO_NFSV4_ACL) == 0) {
718
ff->ff_acl = look_for_nfsv4_acl(ff, ff->ff_fd, ff->ff_name);
719
if (ff->ff_acl == NULL)
720
ff->ff_flags |= FF_NO_NFSV4_ACL;
721
}
722
}
723
724
/*
725
* Get an ACL given fd and/or path name. We check for the "don't get
726
* ACL" flag in the given ff_fid data structure first, but don't set
727
* the flag here. The fillacl() code is similar but will set the
728
* flag; it also uses the ff_fd and ff_name directly.
729
*
730
* (This is used to get ACLs for parent directories, for instance.)
731
*/
732
static struct l9p_acl *
733
getacl(struct fs_fid *ff, int fd, const char *path)
734
{
735
736
if (ff->ff_flags & FF_NO_NFSV4_ACL)
737
return (NULL);
738
return look_for_nfsv4_acl(ff, fd, path);
739
}
740
741
/*
742
* Drop cached ff->ff_acl, e.g., after moving from one directory to
743
* another, where inherited ACLs might change.
744
*/
745
static void
746
dropacl(struct fs_fid *ff)
747
{
748
749
l9p_acl_free(ff->ff_acl);
750
ff->ff_acl = NULL;
751
ff->ff_flags = ff->ff_ai->ai_flags;
752
}
753
754
/*
755
* Check to see if we can find NFSv4 ACLs for the given file.
756
* If we have an open fd, we can use that, otherwise we need
757
* to use the path.
758
*/
759
static struct l9p_acl *
760
look_for_nfsv4_acl(struct fs_fid *ff, int fd, const char *path)
761
{
762
struct l9p_acl *acl;
763
acl_t sysacl;
764
int doclose = 0;
765
766
if (fd < 0) {
767
fd = openat(ff->ff_dirfd, path, 0);
768
doclose = 1;
769
}
770
771
sysacl = acl_get_fd_np(fd, ACL_TYPE_NFS4);
772
if (sysacl == NULL) {
773
/*
774
* EINVAL means no NFSv4 ACLs apply for this file.
775
* Other error numbers indicate some kind of problem.
776
*/
777
if (errno != EINVAL) {
778
L9P_LOG(L9P_ERROR,
779
"error retrieving NFSv4 ACL from "
780
"fdesc %d (%s): %s", fd,
781
path, strerror(errno));
782
}
783
784
if (doclose)
785
close(fd);
786
787
return (NULL);
788
}
789
#if defined(HAVE_FREEBSD_ACLS)
790
acl = l9p_freebsd_nfsv4acl_to_acl(sysacl);
791
#else
792
acl = NULL; /* XXX need a l9p_darwin_acl_to_acl */
793
#endif
794
acl_free(sysacl);
795
796
if (doclose)
797
close(fd);
798
799
return (acl);
800
}
801
802
/*
803
* Verify that the user whose authinfo is in <ai> and effective
804
* group ID is <egid> ((gid_t)-1 means no egid supplied) has
805
* permission to do something.
806
*
807
* The "something" may be rather complex: we allow NFSv4 style
808
* operation masks here, and provide parent and child ACLs and
809
* stat data. At most one of pacl+pst and cacl+cst can be NULL,
810
* unless ACLs are not supported; then pacl and cacl can both
811
* be NULL but pst or cst must be non-NULL depending on the
812
* operation.
813
*/
814
static int
815
check_access(int32_t opmask,
816
struct l9p_acl *pacl, struct stat *pst,
817
struct l9p_acl *cacl, struct stat *cst,
818
struct fs_authinfo *ai, gid_t egid)
819
{
820
struct l9p_acl_check_args args;
821
822
/*
823
* If we have ACLs, use them exclusively, ignoring Unix
824
* permissions. Otherwise, fall back on stat st_mode
825
* bits, and allow super-user as well.
826
*/
827
args.aca_uid = ai->ai_uid;
828
args.aca_gid = egid;
829
args.aca_groups = ai->ai_gids;
830
args.aca_ngroups = (size_t)ai->ai_ngids;
831
args.aca_parent = pacl;
832
args.aca_pstat = pst;
833
args.aca_child = cacl;
834
args.aca_cstat = cst;
835
args.aca_aclmode = pacl == NULL && cacl == NULL
836
? L9P_ACM_STAT_MODE
837
: L9P_ACM_NFS_ACL | L9P_ACM_ZFS_ACL;
838
839
args.aca_superuser = true;
840
return (l9p_acl_check_access(opmask, &args));
841
}
842
843
static int
844
fs_attach(void *softc, struct l9p_request *req)
845
{
846
struct fs_authinfo *ai;
847
struct fs_softc *sc = (struct fs_softc *)softc;
848
struct fs_fid *file;
849
struct passwd *pwd;
850
struct stat st;
851
struct r_pgdata udata;
852
uint32_t n_uname;
853
gid_t *gids;
854
uid_t uid;
855
int error;
856
int ngroups;
857
858
assert(req->lr_fid != NULL);
859
860
/*
861
* Single-thread pwd/group related items. We have a reentrant
862
* r_getpwuid but not a reentrant r_getpwnam, and l9p_getgrlist
863
* may use non-reentrant C library getgr* routines.
864
*/
865
pthread_mutex_lock(&fs_attach_mutex);
866
867
n_uname = req->lr_req.tattach.n_uname;
868
if (n_uname != L9P_NONUNAME) {
869
uid = (uid_t)n_uname;
870
pwd = fs_getpwuid(sc, uid, &udata);
871
if (pwd == NULL)
872
L9P_LOG(L9P_DEBUG,
873
"Tattach: uid %ld: no such user", (long)uid);
874
} else {
875
uid = (uid_t)-1;
876
#if defined(WITH_CASPER)
877
pwd = cap_getpwnam(sc->fs_cappwd, req->lr_req.tattach.uname);
878
#else
879
pwd = getpwnam(req->lr_req.tattach.uname);
880
#endif
881
if (pwd == NULL)
882
L9P_LOG(L9P_DEBUG,
883
"Tattach: %s: no such user",
884
req->lr_req.tattach.uname);
885
}
886
887
/*
888
* If caller didn't give a numeric UID, pick it up from pwd
889
* if possible. If that doesn't work we can't continue.
890
*
891
* Note that pwd also supplies the group set. This assumes
892
* the server has the right mapping; this needs improvement.
893
* We do at least support ai->ai_ngids==0 properly now though.
894
*/
895
if (uid == (uid_t)-1 && pwd != NULL)
896
uid = pwd->pw_uid;
897
if (uid == (uid_t)-1)
898
error = EPERM;
899
else {
900
error = 0;
901
if (fstat(sc->fs_rootfd, &st) != 0)
902
error = errno;
903
else if (!S_ISDIR(st.st_mode))
904
error = ENOTDIR;
905
}
906
if (error) {
907
pthread_mutex_unlock(&fs_attach_mutex);
908
L9P_LOG(L9P_DEBUG,
909
"Tattach: denying uid=%ld access to rootdir: %s",
910
(long)uid, strerror(error));
911
/*
912
* Pass ENOENT and ENOTDIR through for diagnosis;
913
* others become EPERM. This should not leak too
914
* much security.
915
*/
916
return (error == ENOENT || error == ENOTDIR ? error : EPERM);
917
}
918
919
if (pwd != NULL) {
920
/*
921
* This either succeeds and fills in ngroups and
922
* returns non-NULL, or fails and sets ngroups to 0
923
* and returns NULL. Either way ngroups is correct.
924
*/
925
gids = l9p_getgrlist(pwd->pw_name, pwd->pw_gid, &ngroups);
926
} else {
927
gids = NULL;
928
ngroups = 0;
929
}
930
931
/*
932
* Done with pwd and group related items that may use
933
* non-reentrant C library routines; allow other threads in.
934
*/
935
pthread_mutex_unlock(&fs_attach_mutex);
936
937
ai = malloc(sizeof(*ai) + (size_t)ngroups * sizeof(gid_t));
938
if (ai == NULL) {
939
free(gids);
940
return (ENOMEM);
941
}
942
error = pthread_mutex_init(&ai->ai_mtx, NULL);
943
if (error) {
944
free(gids);
945
free(ai);
946
return (error);
947
}
948
ai->ai_refcnt = 0;
949
ai->ai_uid = uid;
950
ai->ai_flags = 0; /* XXX for now */
951
ai->ai_ngids = ngroups;
952
memcpy(ai->ai_gids, gids, (size_t)ngroups * sizeof(gid_t));
953
free(gids);
954
955
file = open_fid(sc->fs_rootfd, ".", ai, true);
956
if (file == NULL) {
957
pthread_mutex_destroy(&ai->ai_mtx);
958
free(ai);
959
return (ENOMEM);
960
}
961
962
req->lr_fid->lo_aux = file;
963
generate_qid(&st, &req->lr_resp.rattach.qid);
964
return (0);
965
}
966
967
static int
968
fs_clunk(void *softc __unused, struct l9p_fid *fid)
969
{
970
struct fs_fid *file;
971
972
file = fid->lo_aux;
973
assert(file != NULL);
974
975
if (file->ff_dir) {
976
closedir(file->ff_dir);
977
file->ff_dir = NULL;
978
} else if (file->ff_fd != -1) {
979
close(file->ff_fd);
980
file->ff_fd = -1;
981
}
982
983
return (0);
984
}
985
986
/*
987
* Create ops.
988
*
989
* We are to create a new file under some existing path,
990
* where the new file's name is in the Tcreate request and the
991
* existing path is due to a fid-based file (req->lr_fid).
992
*
993
* One op (create regular file) sets file->fd, the rest do not.
994
*/
995
static int
996
fs_create(void *softc, struct l9p_request *req)
997
{
998
struct l9p_fid *dir;
999
struct stat st;
1000
uint32_t dmperm;
1001
mode_t perm;
1002
char *name;
1003
int error;
1004
1005
dir = req->lr_fid;
1006
name = req->lr_req.tcreate.name;
1007
dmperm = req->lr_req.tcreate.perm;
1008
perm = (mode_t)(dmperm & 0777);
1009
1010
if (dmperm & L9P_DMDIR)
1011
error = fs_imkdir(softc, dir, name, true,
1012
perm, (gid_t)-1, &st);
1013
else if (dmperm & L9P_DMSYMLINK)
1014
error = fs_isymlink(softc, dir, name,
1015
req->lr_req.tcreate.extension, (gid_t)-1, &st);
1016
else if (dmperm & L9P_DMNAMEDPIPE)
1017
error = fs_imkfifo(softc, dir, name, true,
1018
perm, (gid_t)-1, &st);
1019
else if (dmperm & L9P_DMSOCKET)
1020
error = fs_imksocket(softc, dir, name, true,
1021
perm, (gid_t)-1, &st);
1022
else if (dmperm & L9P_DMDEVICE) {
1023
unsigned int major, minor;
1024
char type;
1025
dev_t dev;
1026
1027
/*
1028
* ??? Should this be testing < 3? For now, allow a single
1029
* integer mode with minor==0 implied.
1030
*/
1031
minor = 0;
1032
if (sscanf(req->lr_req.tcreate.extension, "%c %u %u",
1033
&type, &major, &minor) < 2) {
1034
return (EINVAL);
1035
}
1036
1037
switch (type) {
1038
case 'b':
1039
perm |= S_IFBLK;
1040
break;
1041
case 'c':
1042
perm |= S_IFCHR;
1043
break;
1044
default:
1045
return (EINVAL);
1046
}
1047
dev = makedev(major, minor);
1048
error = fs_imknod(softc, dir, name, true, perm, dev,
1049
(gid_t)-1, &st);
1050
} else {
1051
enum l9p_omode p9;
1052
int flags;
1053
1054
p9 = req->lr_req.tcreate.mode;
1055
error = fs_oflags_dotu(p9, &flags);
1056
if (error)
1057
return (error);
1058
error = fs_icreate(softc, dir, name, flags,
1059
true, perm, (gid_t)-1, &st);
1060
req->lr_resp.rcreate.iounit = req->lr_conn->lc_max_io_size;
1061
}
1062
1063
if (error == 0)
1064
generate_qid(&st, &req->lr_resp.rcreate.qid);
1065
1066
return (error);
1067
}
1068
1069
/*
1070
* https://swtch.com/plan9port/man/man9/open.html and
1071
* http://plan9.bell-labs.com/magic/man2html/5/open
1072
* say that permissions are actually
1073
* perm & (~0666 | (dir.perm & 0666))
1074
* for files, and
1075
* perm & (~0777 | (dir.perm & 0777))
1076
* for directories. That is, the parent directory may
1077
* take away permissions granted by the operation.
1078
*
1079
* This seems a bit restrictive; probably
1080
* there should be a control knob for this.
1081
*/
1082
static inline mode_t
1083
fs_p9perm(mode_t perm, mode_t dir_perm, bool isdir)
1084
{
1085
1086
if (isdir)
1087
perm &= ~0777 | (dir_perm & 0777);
1088
else
1089
perm &= ~0666 | (dir_perm & 0666);
1090
return (perm);
1091
}
1092
1093
/*
1094
* Internal form of create (plain file).
1095
*
1096
* Our caller takes care of splitting off all the special
1097
* types of create (mknod, etc), so this is purely for files.
1098
* We receive the fs_softc <softc>, the directory fid <dir>
1099
* in which the new file is to be created, the name of the
1100
* new file, a flag <isp9> indicating whether to do plan9 style
1101
* permissions or Linux style permissions, the permissions <perm>,
1102
* an effective group id <egid>, and a pointer to a stat structure
1103
* <st> to fill in describing the final result on success.
1104
*
1105
* On successful create, the fid switches to the newly created
1106
* file, which is now open; its associated file-name changes too.
1107
*
1108
* Note that the original (dir) fid is never currently open,
1109
* so there is nothing to close.
1110
*/
1111
static int
1112
fs_icreate(void *softc, struct l9p_fid *dir, char *name, int flags,
1113
bool isp9, mode_t perm, gid_t egid, struct stat *st)
1114
{
1115
struct fs_fid *file;
1116
gid_t gid;
1117
uid_t uid;
1118
char newname[MAXPATHLEN];
1119
int error, fd;
1120
1121
file = dir->lo_aux;
1122
1123
/*
1124
* Build full path name from directory + file name. We'll
1125
* check permissions on the parent directory, then race to
1126
* create the file before anything bad happens like symlinks.
1127
*
1128
* (To close this race we need to use openat(), which is
1129
* left for a later version of this code.)
1130
*/
1131
error = fs_buildname(dir, name, newname, sizeof(newname));
1132
if (error)
1133
return (error);
1134
1135
/* In case of success, we will need a new file->ff_name. */
1136
name = strdup(newname);
1137
if (name == NULL)
1138
return (ENOMEM);
1139
1140
/* Check create permission and compute new file ownership. */
1141
error = fs_nde(softc, dir, false, egid, st, &uid, &gid);
1142
if (error) {
1143
free(name);
1144
return (error);
1145
}
1146
1147
/* Adjust new-file permissions for Plan9 protocol. */
1148
if (isp9)
1149
perm = fs_p9perm(perm, st->st_mode, false);
1150
1151
/* Create is always exclusive so O_TRUNC is irrelevant. */
1152
fd = openat(file->ff_dirfd, newname, flags | O_CREAT | O_EXCL, perm);
1153
if (fd < 0) {
1154
error = errno;
1155
free(name);
1156
return (error);
1157
}
1158
1159
/* Fix permissions and owner. */
1160
if (fchmod(fd, perm) != 0 ||
1161
fchown(fd, uid, gid) != 0 ||
1162
fstat(fd, st) != 0) {
1163
error = errno;
1164
(void) close(fd);
1165
/* unlink(newname); ? */
1166
free(name);
1167
return (error);
1168
}
1169
1170
/* It *was* a directory; now it's a file, and it's open. */
1171
free(file->ff_name);
1172
file->ff_name = name;
1173
file->ff_fd = fd;
1174
return (0);
1175
}
1176
1177
/*
1178
* Internal form of open: stat file and verify permissions (from p9
1179
* argument), then open the file-or-directory, leaving the internal
1180
* fs_fid fields set up. If we cannot open the file, return a
1181
* suitable error number, and leave everything unchanged.
1182
*
1183
* To mitigate the race between permissions testing and the actual
1184
* open, we can stat the file twice (once with lstat() before open,
1185
* then with fstat() after). We assume O_NOFOLLOW is set in flags,
1186
* so if some other race-winner substitutes in a symlink we won't
1187
* open it here. (However, embedded symlinks, if they occur, are
1188
* still an issue. Ideally we would like to have an O_NEVERFOLLOW
1189
* that fails on embedded symlinks, and a way to pass this to
1190
* lstat() as well.)
1191
*
1192
* When we use opendir() we cannot pass O_NOFOLLOW, so we must rely
1193
* on substitution-detection via fstat(). To simplify the code we
1194
* just always re-check.
1195
*
1196
* (For a proper fix in the future, we can require openat(), keep
1197
* each parent directory open during walk etc, and allow only final
1198
* name components with O_NOFOLLOW.)
1199
*
1200
* On successful return, st has been filled in.
1201
*/
1202
static int
1203
fs_iopen(void *softc, struct l9p_fid *fid, int flags, enum l9p_omode p9,
1204
gid_t egid __unused, struct stat *st)
1205
{
1206
struct fs_softc *sc = softc;
1207
struct fs_fid *file;
1208
struct stat first;
1209
int32_t op;
1210
char *name;
1211
int error;
1212
int fd;
1213
DIR *dirp;
1214
1215
/* Forbid write ops on read-only file system. */
1216
if (sc->fs_readonly) {
1217
if ((flags & O_TRUNC) != 0)
1218
return (EROFS);
1219
if ((flags & O_ACCMODE) != O_RDONLY)
1220
return (EROFS);
1221
if (p9 & L9P_ORCLOSE)
1222
return (EROFS);
1223
}
1224
1225
file = fid->lo_aux;
1226
assert(file != NULL);
1227
name = file->ff_name;
1228
1229
if (fstatat(file->ff_dirfd, name, &first, AT_SYMLINK_NOFOLLOW) != 0)
1230
return (errno);
1231
if (S_ISLNK(first.st_mode))
1232
return (EPERM);
1233
1234
/* Can we rely on O_APPEND here? Best not, can be cleared. */
1235
switch (flags & O_ACCMODE) {
1236
case O_RDONLY:
1237
op = L9P_ACE_READ_DATA;
1238
break;
1239
case O_WRONLY:
1240
op = L9P_ACE_WRITE_DATA;
1241
break;
1242
case O_RDWR:
1243
op = L9P_ACE_READ_DATA | L9P_ACE_WRITE_DATA;
1244
break;
1245
default:
1246
return (EINVAL);
1247
}
1248
fillacl(file);
1249
error = check_access(op, NULL, NULL, file->ff_acl, &first,
1250
file->ff_ai, (gid_t)-1);
1251
if (error)
1252
return (error);
1253
1254
if (S_ISDIR(first.st_mode)) {
1255
/* Forbid write or truncate on directory. */
1256
if ((flags & O_ACCMODE) != O_RDONLY || (flags & O_TRUNC))
1257
return (EPERM);
1258
fd = openat(file->ff_dirfd, name, O_DIRECTORY);
1259
dirp = fdopendir(fd);
1260
if (dirp == NULL)
1261
return (EPERM);
1262
fd = dirfd(dirp);
1263
} else {
1264
dirp = NULL;
1265
fd = openat(file->ff_dirfd, name, flags);
1266
if (fd < 0)
1267
return (EPERM);
1268
}
1269
1270
/*
1271
* We have a valid fd, and maybe non-null dirp. Re-check
1272
* the file, and fail if st_dev or st_ino changed.
1273
*/
1274
if (fstat(fd, st) != 0 ||
1275
first.st_dev != st->st_dev ||
1276
first.st_ino != st->st_ino) {
1277
if (dirp != NULL)
1278
(void) closedir(dirp);
1279
else
1280
(void) close(fd);
1281
return (EPERM);
1282
}
1283
if (dirp != NULL)
1284
file->ff_dir = dirp;
1285
else
1286
file->ff_fd = fd;
1287
return (0);
1288
}
1289
1290
/*
1291
* Internal form of mkdir (common code for all forms).
1292
* We receive the fs_softc <softc>, the directory fid <dir>
1293
* in which the new entry is to be created, the name of the
1294
* new entry, a flag <isp9> indicating whether to do plan9 style
1295
* permissions or Linux style permissions, the permissions <perm>,
1296
* an effective group id <egid>, and a pointer to a stat structure
1297
* <st> to fill in describing the final result on success.
1298
*
1299
* See also fs_icreate() above.
1300
*/
1301
static int
1302
fs_imkdir(void *softc, struct l9p_fid *dir, char *name,
1303
bool isp9, mode_t perm, gid_t egid, struct stat *st)
1304
{
1305
struct fs_fid *ff;
1306
gid_t gid;
1307
uid_t uid;
1308
char newname[MAXPATHLEN];
1309
int error, fd;
1310
1311
ff = dir->lo_aux;
1312
error = fs_buildname(dir, name, newname, sizeof(newname));
1313
if (error)
1314
return (error);
1315
1316
error = fs_nde(softc, dir, true, egid, st, &uid, &gid);
1317
if (error)
1318
return (error);
1319
1320
if (isp9)
1321
perm = fs_p9perm(perm, st->st_mode, true);
1322
1323
if (mkdirat(ff->ff_dirfd, newname, perm) != 0)
1324
return (errno);
1325
1326
fd = openat(ff->ff_dirfd, newname,
1327
O_DIRECTORY | O_RDONLY | O_NOFOLLOW);
1328
if (fd < 0 ||
1329
fchown(fd, uid, gid) != 0 ||
1330
fchmod(fd, perm) != 0 ||
1331
fstat(fd, st) != 0) {
1332
error = errno;
1333
/* rmdir(newname) ? */
1334
}
1335
if (fd >= 0)
1336
(void) close(fd);
1337
1338
return (error);
1339
}
1340
1341
#ifdef __APPLE__
1342
/*
1343
* This is an undocumented OS X syscall. It would be best to avoid it,
1344
* but there doesn't seem to be another safe way to implement mknodat.
1345
* Dear Apple, please implement mknodat before you remove this syscall.
1346
*/
1347
static int fs_ifchdir_thread_local(int fd)
1348
{
1349
#pragma clang diagnostic push
1350
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
1351
return syscall(SYS___pthread_fchdir, fd);
1352
#pragma clang diagnostic pop
1353
}
1354
#endif
1355
1356
/*
1357
* Internal form of mknod (special device).
1358
*
1359
* The device type (S_IFBLK, S_IFCHR) is included in the <mode> parameter.
1360
*/
1361
static int
1362
fs_imknod(void *softc, struct l9p_fid *dir, char *name,
1363
bool isp9, mode_t mode, dev_t dev, gid_t egid, struct stat *st)
1364
{
1365
struct fs_fid *ff;
1366
mode_t perm;
1367
gid_t gid;
1368
uid_t uid;
1369
char newname[MAXPATHLEN];
1370
int error;
1371
1372
ff = dir->lo_aux;
1373
error = fs_buildname(dir, name, newname, sizeof(newname));
1374
if (error)
1375
return (error);
1376
1377
error = fs_nde(softc, dir, false, egid, st, &uid, &gid);
1378
if (error)
1379
return (error);
1380
1381
if (isp9) {
1382
perm = fs_p9perm(mode & 0777, st->st_mode, false);
1383
mode = (mode & ~0777) | perm;
1384
} else {
1385
perm = mode & 0777;
1386
}
1387
1388
#ifdef __APPLE__
1389
if (fs_ifchdir_thread_local(ff->ff_dirfd) < 0) {
1390
return -1;
1391
}
1392
error = mknod(newname, mode, dev);
1393
int preserved_errno = errno;
1394
/* Stop using the thread-local cwd */
1395
fs_ifchdir_thread_local(-1);
1396
if (error < 0) {
1397
errno = preserved_errno;
1398
return errno;
1399
}
1400
#else
1401
if (mknodat(ff->ff_dirfd, newname, mode, dev) != 0)
1402
return (errno);
1403
#endif
1404
1405
/* We cannot open the new name; race to use l* syscalls. */
1406
if (fchownat(ff->ff_dirfd, newname, uid, gid, AT_SYMLINK_NOFOLLOW) != 0 ||
1407
fchmodat(ff->ff_dirfd, newname, perm, AT_SYMLINK_NOFOLLOW) != 0 ||
1408
fstatat(ff->ff_dirfd, newname, st, AT_SYMLINK_NOFOLLOW) != 0)
1409
error = errno;
1410
else if ((st->st_mode & S_IFMT) != (mode & S_IFMT))
1411
error = EPERM; /* ??? lost a race anyway */
1412
1413
/* if (error) unlink(newname) ? */
1414
1415
return (error);
1416
}
1417
1418
/*
1419
* Internal form of mkfifo.
1420
*/
1421
static int
1422
fs_imkfifo(void *softc, struct l9p_fid *dir, char *name,
1423
bool isp9, mode_t perm, gid_t egid, struct stat *st)
1424
{
1425
struct fs_fid *ff;
1426
gid_t gid;
1427
uid_t uid;
1428
char newname[MAXPATHLEN];
1429
int error;
1430
1431
ff = dir->lo_aux;
1432
error = fs_buildname(dir, name, newname, sizeof(newname));
1433
if (error)
1434
return (error);
1435
1436
error = fs_nde(softc, dir, false, egid, st, &uid, &gid);
1437
if (error)
1438
return (error);
1439
1440
if (isp9)
1441
perm = fs_p9perm(perm, st->st_mode, false);
1442
1443
if (mkfifo(newname, perm) != 0)
1444
return (errno);
1445
1446
/* We cannot open the new name; race to use l* syscalls. */
1447
if (fchownat(ff->ff_dirfd, newname, uid, gid, AT_SYMLINK_NOFOLLOW) != 0 ||
1448
fchmodat(ff->ff_dirfd, newname, perm, AT_SYMLINK_NOFOLLOW) != 0 ||
1449
fstatat(ff->ff_dirfd, newname, st, AT_SYMLINK_NOFOLLOW) != 0)
1450
error = errno;
1451
else if (!S_ISFIFO(st->st_mode))
1452
error = EPERM; /* ??? lost a race anyway */
1453
1454
/* if (error) unlink(newname) ? */
1455
1456
return (error);
1457
}
1458
1459
/*
1460
* Internal form of mksocket.
1461
*
1462
* This is a bit different because of the horrible socket naming
1463
* system (bind() with sockaddr_un sun_path).
1464
*/
1465
static int
1466
fs_imksocket(void *softc, struct l9p_fid *dir, char *name,
1467
bool isp9, mode_t perm, gid_t egid, struct stat *st)
1468
{
1469
struct fs_fid *ff;
1470
struct sockaddr_un sun;
1471
char *path;
1472
char newname[MAXPATHLEN];
1473
gid_t gid;
1474
uid_t uid;
1475
int error = 0, s, fd;
1476
1477
ff = dir->lo_aux;
1478
error = fs_buildname(dir, name, newname, sizeof(newname));
1479
if (error)
1480
return (error);
1481
1482
error = fs_nde(softc, dir, false, egid, st, &uid, &gid);
1483
if (error)
1484
return (error);
1485
1486
if (isp9)
1487
perm = fs_p9perm(perm, st->st_mode, false);
1488
1489
s = socket(AF_UNIX, SOCK_STREAM, 0);
1490
if (s < 0)
1491
return (errno);
1492
1493
path = newname;
1494
fd = -1;
1495
#ifdef HAVE_BINDAT
1496
/* Try bindat() if needed. */
1497
if (strlen(path) >= sizeof(sun.sun_path)) {
1498
fd = openat(ff->ff_dirfd, ff->ff_name,
1499
O_RDONLY | O_DIRECTORY | O_NOFOLLOW);
1500
if (fd >= 0)
1501
path = name;
1502
}
1503
#endif
1504
1505
/*
1506
* Can only create the socket if the path will fit.
1507
* Even if we are using bindat() there are limits
1508
* (the API for AF_UNIX sockets is ... not good).
1509
*
1510
* Note: in theory we can fill sun_path to the end
1511
* (omitting a terminating '\0') but in at least one
1512
* Unix-like system, this was known to behave oddly,
1513
* so we test for ">=" rather than just ">".
1514
*/
1515
if (strlen(path) >= sizeof(sun.sun_path)) {
1516
error = ENAMETOOLONG;
1517
goto out;
1518
}
1519
sun.sun_family = AF_UNIX;
1520
sun.sun_len = sizeof(struct sockaddr_un);
1521
strncpy(sun.sun_path, path, sizeof(sun.sun_path));
1522
1523
#ifdef HAVE_BINDAT
1524
if (fd >= 0) {
1525
if (bindat(fd, s, (struct sockaddr *)&sun, sun.sun_len) < 0)
1526
error = errno;
1527
goto out; /* done now, for good or ill */
1528
}
1529
#endif
1530
1531
if (bind(s, (struct sockaddr *)&sun, sun.sun_len) < 0)
1532
error = errno;
1533
out:
1534
1535
if (error == 0) {
1536
/*
1537
* We believe we created the socket-inode. Fix
1538
* permissions etc. Note that we cannot use
1539
* fstat() on the socket descriptor: it succeeds,
1540
* but we get bogus data!
1541
*/
1542
if (fchownat(ff->ff_dirfd, newname, uid, gid, AT_SYMLINK_NOFOLLOW) != 0 ||
1543
fchmodat(ff->ff_dirfd, newname, perm, AT_SYMLINK_NOFOLLOW) != 0 ||
1544
fstatat(ff->ff_dirfd, newname, st, AT_SYMLINK_NOFOLLOW) != 0)
1545
error = errno;
1546
else if (!S_ISSOCK(st->st_mode))
1547
error = EPERM; /* ??? lost a race anyway */
1548
1549
/* if (error) unlink(newname) ? */
1550
}
1551
1552
/*
1553
* It's not clear which error should override, although
1554
* ideally we should never see either close() call fail.
1555
* In any case we do want to try to close both fd and s,
1556
* always. Let's set error only if it is not already set,
1557
* so that all exit paths can use the same code.
1558
*/
1559
if (fd >= 0 && close(fd) != 0)
1560
if (error == 0)
1561
error = errno;
1562
if (close(s) != 0)
1563
if (error == 0)
1564
error = errno;
1565
1566
return (error);
1567
}
1568
1569
/*
1570
* Internal form of symlink.
1571
*
1572
* Note that symlinks are presumed to carry no permission bits.
1573
* They do have owners, however (who may be charged for quotas).
1574
*/
1575
static int
1576
fs_isymlink(void *softc, struct l9p_fid *dir, char *name,
1577
char *symtgt, gid_t egid, struct stat *st)
1578
{
1579
struct fs_fid *ff;
1580
gid_t gid;
1581
uid_t uid;
1582
char newname[MAXPATHLEN];
1583
int error;
1584
1585
ff = dir->lo_aux;
1586
error = fs_buildname(dir, name, newname, sizeof(newname));
1587
if (error)
1588
return (error);
1589
1590
error = fs_nde(softc, dir, false, egid, st, &uid, &gid);
1591
if (error)
1592
return (error);
1593
1594
if (symlinkat(symtgt, ff->ff_dirfd, newname) != 0)
1595
return (errno);
1596
1597
/* We cannot open the new name; race to use l* syscalls. */
1598
if (fchownat(ff->ff_dirfd, newname, uid, gid, AT_SYMLINK_NOFOLLOW) != 0 ||
1599
fstatat(ff->ff_dirfd, newname, st, AT_SYMLINK_NOFOLLOW) != 0)
1600
error = errno;
1601
else if (!S_ISLNK(st->st_mode))
1602
error = EPERM; /* ??? lost a race anyway */
1603
1604
/* if (error) unlink(newname) ? */
1605
1606
return (error);
1607
}
1608
1609
static int
1610
fs_open(void *softc, struct l9p_request *req)
1611
{
1612
struct l9p_fid *fid = req->lr_fid;
1613
struct stat st;
1614
enum l9p_omode p9;
1615
int error, flags;
1616
1617
p9 = req->lr_req.topen.mode;
1618
error = fs_oflags_dotu(p9, &flags);
1619
if (error)
1620
return (error);
1621
1622
error = fs_iopen(softc, fid, flags, p9, (gid_t)-1, &st);
1623
if (error)
1624
return (error);
1625
1626
generate_qid(&st, &req->lr_resp.ropen.qid);
1627
req->lr_resp.ropen.iounit = req->lr_conn->lc_max_io_size;
1628
return (0);
1629
}
1630
1631
/*
1632
* Helper for directory read. We want to run an lstat on each
1633
* file name within the directory. This is a lot faster if we
1634
* have lstatat (or fstatat with AT_SYMLINK_NOFOLLOW), but not
1635
* all systems do, so hide the ifdef-ed code in an inline function.
1636
*/
1637
static inline int
1638
fs_lstatat(struct fs_fid *file, char *name, struct stat *st)
1639
{
1640
1641
return (fstatat(dirfd(file->ff_dir), name, st, AT_SYMLINK_NOFOLLOW));
1642
}
1643
1644
static int
1645
fs_read(void *softc, struct l9p_request *req)
1646
{
1647
struct l9p_stat l9stat;
1648
struct fs_softc *sc;
1649
struct fs_fid *file;
1650
bool dotu = req->lr_conn->lc_version >= L9P_2000U;
1651
ssize_t ret;
1652
1653
sc = softc;
1654
file = req->lr_fid->lo_aux;
1655
assert(file != NULL);
1656
1657
if (file->ff_dir != NULL) {
1658
struct dirent *d;
1659
struct stat st;
1660
struct l9p_message msg;
1661
long o;
1662
1663
pthread_mutex_lock(&file->ff_mtx);
1664
1665
/*
1666
* Must use telldir before readdir since seekdir
1667
* takes cookie values. Unfortunately this wastes
1668
* a lot of time (and memory) building unneeded
1669
* cookies that can only be flushed by closing
1670
* the directory.
1671
*
1672
* NB: FreeBSD libc seekdir has SINGLEUSE defined,
1673
* so in fact, we can discard the cookies by
1674
* calling seekdir on them. This clears up wasted
1675
* memory at the cost of even more wasted time...
1676
*
1677
* XXX: readdir/telldir/seekdir not thread safe
1678
*/
1679
l9p_init_msg(&msg, req, L9P_PACK);
1680
for (;;) {
1681
o = telldir(file->ff_dir);
1682
d = readdir(file->ff_dir);
1683
if (d == NULL)
1684
break;
1685
if (fs_lstatat(file, d->d_name, &st))
1686
continue;
1687
dostat(sc, &l9stat, d->d_name, &st, dotu);
1688
if (l9p_pack_stat(&msg, req, &l9stat) != 0) {
1689
seekdir(file->ff_dir, o);
1690
break;
1691
}
1692
#if defined(__FreeBSD__)
1693
seekdir(file->ff_dir, o);
1694
(void) readdir(file->ff_dir);
1695
#endif
1696
}
1697
1698
pthread_mutex_unlock(&file->ff_mtx);
1699
} else {
1700
size_t niov = l9p_truncate_iov(req->lr_data_iov,
1701
req->lr_data_niov, req->lr_req.io.count);
1702
1703
#if defined(__FreeBSD__)
1704
ret = preadv(file->ff_fd, req->lr_data_iov, niov,
1705
req->lr_req.io.offset);
1706
#else
1707
/* XXX: not thread safe, should really use aio_listio. */
1708
if (lseek(file->ff_fd, (off_t)req->lr_req.io.offset, SEEK_SET) < 0)
1709
return (errno);
1710
1711
ret = (uint32_t)readv(file->ff_fd, req->lr_data_iov, (int)niov);
1712
#endif
1713
1714
if (ret < 0)
1715
return (errno);
1716
1717
req->lr_resp.io.count = (uint32_t)ret;
1718
}
1719
1720
return (0);
1721
}
1722
1723
static int
1724
fs_remove(void *softc, struct l9p_fid *fid)
1725
{
1726
struct fs_softc *sc = softc;
1727
struct l9p_acl *parent_acl;
1728
struct fs_fid *file;
1729
struct stat pst, cst;
1730
char dirname[MAXPATHLEN];
1731
int error;
1732
1733
if (sc->fs_readonly)
1734
return (EROFS);
1735
1736
error = fs_pdir(sc, fid, dirname, sizeof(dirname), &pst);
1737
if (error)
1738
return (error);
1739
1740
file = fid->lo_aux;
1741
if (fstatat(file->ff_dirfd, file->ff_name, &cst, AT_SYMLINK_NOFOLLOW) != 0)
1742
return (error);
1743
1744
parent_acl = getacl(file, -1, dirname);
1745
fillacl(file);
1746
1747
error = check_access(L9P_ACOP_UNLINK,
1748
parent_acl, &pst, file->ff_acl, &cst, file->ff_ai, (gid_t)-1);
1749
l9p_acl_free(parent_acl);
1750
if (error)
1751
return (error);
1752
1753
if (unlinkat(file->ff_dirfd, file->ff_name,
1754
S_ISDIR(cst.st_mode) ? AT_REMOVEDIR : 0) != 0)
1755
error = errno;
1756
1757
return (error);
1758
}
1759
1760
static int
1761
fs_stat(void *softc, struct l9p_request *req)
1762
{
1763
struct fs_softc *sc;
1764
struct fs_fid *file;
1765
struct stat st;
1766
bool dotu = req->lr_conn->lc_version >= L9P_2000U;
1767
1768
sc = softc;
1769
file = req->lr_fid->lo_aux;
1770
assert(file);
1771
1772
if (fstatat(file->ff_dirfd, file->ff_name, &st,
1773
AT_SYMLINK_NOFOLLOW) != 0)
1774
return (errno);
1775
1776
dostat(sc, &req->lr_resp.rstat.stat, file->ff_name, &st, dotu);
1777
return (0);
1778
}
1779
1780
static int
1781
fs_walk(void *softc, struct l9p_request *req)
1782
{
1783
struct l9p_acl *acl;
1784
struct fs_authinfo *ai;
1785
struct fs_fid *file = req->lr_fid->lo_aux;
1786
struct fs_fid *newfile;
1787
struct stat st;
1788
size_t clen, namelen, need;
1789
char *comp, *succ, *next, *swtmp;
1790
bool atroot;
1791
bool dotdot;
1792
int i, nwname;
1793
int error = 0;
1794
char namebufs[2][MAXPATHLEN];
1795
1796
/*
1797
* https://swtch.com/plan9port/man/man9/walk.html:
1798
*
1799
* It is legal for nwname to be zero, in which case newfid
1800
* will represent the same file as fid and the walk will
1801
* usually succeed; this is equivalent to walking to dot.
1802
* [Aside: it's not clear if we should test S_ISDIR here.]
1803
* ...
1804
* The name ".." ... represents the parent directory.
1805
* The name "." ... is not used in the protocol.
1806
* ... A walk of the name ".." in the root directory
1807
* of the server is equivalent to a walk with no name
1808
* elements.
1809
*
1810
* Note that req.twalk.nwname never exceeds L9P_MAX_WELEM,
1811
* so it is safe to convert to plain int.
1812
*
1813
* We are to return an error only if the first walk fails,
1814
* else stop at the end of the names or on the first error.
1815
* The final fid is based on the last name successfully
1816
* walked.
1817
*
1818
* Note that we *do* get Twalk requests with nwname==0 on files.
1819
*
1820
* Set up "successful name" buffer pointer with base fid name,
1821
* initially. We'll swap each new success into it as we go.
1822
*
1823
* Invariant: atroot and stat data correspond to current
1824
* (succ) path.
1825
*/
1826
succ = namebufs[0];
1827
next = namebufs[1];
1828
namelen = strlcpy(succ, file->ff_name, MAXPATHLEN);
1829
if (namelen >= MAXPATHLEN)
1830
return (ENAMETOOLONG);
1831
if (fstatat(file->ff_dirfd, succ, &st, AT_SYMLINK_NOFOLLOW) < 0)
1832
return (errno);
1833
ai = file->ff_ai;
1834
atroot = strlen(succ) == 0; /* XXX? */
1835
fillacl(file);
1836
acl = file->ff_acl;
1837
1838
nwname = (int)req->lr_req.twalk.nwname;
1839
1840
for (i = 0; i < nwname; i++) {
1841
/*
1842
* Must have execute permission to search a directory.
1843
* Then, look up each component in its directory-so-far.
1844
* Check for ".." along the way, handlng specially
1845
* as needed. Forbid "/" in name components.
1846
*
1847
*/
1848
if (!S_ISDIR(st.st_mode)) {
1849
error = ENOTDIR;
1850
goto out;
1851
}
1852
error = check_access(L9P_ACE_EXECUTE,
1853
NULL, NULL, acl, &st, ai, (gid_t)-1);
1854
if (error) {
1855
L9P_LOG(L9P_DEBUG,
1856
"Twalk: denying dir-walk on \"%s\" for uid %u",
1857
succ, (unsigned)ai->ai_uid);
1858
error = EPERM;
1859
goto out;
1860
}
1861
comp = req->lr_req.twalk.wname[i];
1862
if (strchr(comp, '/') != NULL) {
1863
error = EINVAL;
1864
break;
1865
}
1866
1867
clen = strlen(comp);
1868
dotdot = false;
1869
1870
/*
1871
* Build next pathname (into "next"). If "..",
1872
* just strip one name component off the success
1873
* name so far. Since we know this name fits, the
1874
* stripped down version also fits. Otherwise,
1875
* the name is the base name plus '/' plus the
1876
* component name plus terminating '\0'; this may
1877
* or may not fit.
1878
*/
1879
if (comp[0] == '.') {
1880
if (clen == 1) {
1881
error = EINVAL;
1882
break;
1883
}
1884
if (comp[1] == '.' && clen == 2)
1885
dotdot = true;
1886
}
1887
if (dotdot) {
1888
/*
1889
* It's not clear how ".." at root should
1890
* be handled when i > 0. Obeying the man
1891
* page exactly, we reset i to 0 and stop,
1892
* declaring terminal success.
1893
*
1894
* Otherwise, we just climbed up one level
1895
* so adjust "atroot".
1896
*/
1897
if (atroot) {
1898
i = 0;
1899
break;
1900
}
1901
(void) r_dirname(succ, next, MAXPATHLEN);
1902
namelen = strlen(next);
1903
atroot = strlen(next) == 0; /* XXX? */
1904
} else {
1905
need = namelen + 1 + clen + 1;
1906
if (need > MAXPATHLEN) {
1907
error = ENAMETOOLONG;
1908
break;
1909
}
1910
memcpy(next, succ, namelen);
1911
next[namelen++] = '/';
1912
memcpy(&next[namelen], comp, clen + 1);
1913
namelen += clen;
1914
/*
1915
* Since name is never ".", we are necessarily
1916
* descending below the root now.
1917
*/
1918
atroot = false;
1919
}
1920
1921
if (fstatat(file->ff_dirfd, next, &st, AT_SYMLINK_NOFOLLOW) < 0) {
1922
error = ENOENT;
1923
break;
1924
}
1925
1926
/*
1927
* Success: generate qid and swap this
1928
* successful name into place. Update acl.
1929
*/
1930
generate_qid(&st, &req->lr_resp.rwalk.wqid[i]);
1931
swtmp = succ;
1932
succ = next;
1933
next = swtmp;
1934
if (acl != NULL && acl != file->ff_acl)
1935
l9p_acl_free(acl);
1936
acl = getacl(file, -1, next);
1937
}
1938
1939
/*
1940
* Fail only if we failed on the first name.
1941
* Otherwise we succeeded on something, and "succ"
1942
* points to the last successful name in namebufs[].
1943
*/
1944
if (error) {
1945
if (i == 0)
1946
goto out;
1947
error = 0;
1948
}
1949
1950
newfile = open_fid(file->ff_dirfd, succ, ai, false);
1951
if (newfile == NULL) {
1952
error = ENOMEM;
1953
goto out;
1954
}
1955
if (req->lr_newfid == req->lr_fid) {
1956
/*
1957
* Before overwriting fid->lo_aux, free the old value.
1958
* Note that this doesn't free the l9p_fid data,
1959
* just the fs_fid data. (But it does ditch ff_acl.)
1960
*/
1961
if (acl == file->ff_acl)
1962
acl = NULL;
1963
fs_freefid(softc, req->lr_fid);
1964
file = NULL;
1965
}
1966
req->lr_newfid->lo_aux = newfile;
1967
if (file != NULL && acl != file->ff_acl) {
1968
newfile->ff_acl = acl;
1969
acl = NULL;
1970
}
1971
req->lr_resp.rwalk.nwqid = (uint16_t)i;
1972
out:
1973
if (file != NULL && acl != file->ff_acl)
1974
l9p_acl_free(acl);
1975
return (error);
1976
}
1977
1978
static int
1979
fs_write(void *softc, struct l9p_request *req)
1980
{
1981
struct fs_softc *sc = softc;
1982
struct fs_fid *file;
1983
ssize_t ret;
1984
1985
file = req->lr_fid->lo_aux;
1986
assert(file != NULL);
1987
1988
if (sc->fs_readonly)
1989
return (EROFS);
1990
1991
size_t niov = l9p_truncate_iov(req->lr_data_iov,
1992
req->lr_data_niov, req->lr_req.io.count);
1993
1994
#if defined(__FreeBSD__)
1995
ret = pwritev(file->ff_fd, req->lr_data_iov, niov,
1996
req->lr_req.io.offset);
1997
#else
1998
/* XXX: not thread safe, should really use aio_listio. */
1999
if (lseek(file->ff_fd, (off_t)req->lr_req.io.offset, SEEK_SET) < 0)
2000
return (errno);
2001
2002
ret = writev(file->ff_fd, req->lr_data_iov,
2003
(int)niov);
2004
#endif
2005
2006
if (ret < 0)
2007
return (errno);
2008
2009
req->lr_resp.io.count = (uint32_t)ret;
2010
return (0);
2011
}
2012
2013
static int
2014
fs_wstat(void *softc, struct l9p_request *req)
2015
{
2016
struct fs_softc *sc = softc;
2017
struct l9p_stat *l9stat = &req->lr_req.twstat.stat;
2018
struct l9p_fid *fid;
2019
struct fs_fid *file;
2020
int error = 0;
2021
2022
fid = req->lr_fid;
2023
file = fid->lo_aux;
2024
assert(file != NULL);
2025
2026
/*
2027
* XXX:
2028
*
2029
* stat(9P) sez:
2030
*
2031
* Either all the changes in wstat request happen, or none of them
2032
* does: if the request succeeds, all changes were made; if it fails,
2033
* none were.
2034
*
2035
* Atomicity is clearly missing in current implementation.
2036
*/
2037
2038
if (sc->fs_readonly)
2039
return (EROFS);
2040
2041
if (l9stat->atime != (uint32_t)~0) {
2042
/* XXX: not implemented, ignore */
2043
}
2044
2045
if (l9stat->mtime != (uint32_t)~0) {
2046
/* XXX: not implemented, ignore */
2047
}
2048
2049
if (l9stat->dev != (uint32_t)~0) {
2050
error = EPERM;
2051
goto out;
2052
}
2053
2054
if (l9stat->length != (uint64_t)~0) {
2055
if (file->ff_dir != NULL) {
2056
error = EINVAL;
2057
goto out;
2058
}
2059
2060
if (truncate(file->ff_name, (off_t)l9stat->length) != 0) {
2061
error = errno;
2062
goto out;
2063
}
2064
}
2065
2066
if (req->lr_conn->lc_version >= L9P_2000U) {
2067
if (fchownat(file->ff_dirfd, file->ff_name, l9stat->n_uid,
2068
l9stat->n_gid, AT_SYMLINK_NOFOLLOW) != 0) {
2069
error = errno;
2070
goto out;
2071
}
2072
}
2073
2074
if (l9stat->mode != (uint32_t)~0) {
2075
if (fchmodat(file->ff_dirfd, file->ff_name,
2076
l9stat->mode & 0777, 0) != 0) {
2077
error = errno;
2078
goto out;
2079
}
2080
}
2081
2082
if (strlen(l9stat->name) > 0) {
2083
struct l9p_acl *parent_acl;
2084
struct stat st;
2085
char *tmp;
2086
char newname[MAXPATHLEN];
2087
2088
/*
2089
* Rename-within-directory: it's not deleting anything,
2090
* but we need write permission on the directory. This
2091
* should suffice.
2092
*/
2093
error = fs_pdir(softc, fid, newname, sizeof(newname), &st);
2094
if (error)
2095
goto out;
2096
parent_acl = getacl(file, -1, newname);
2097
error = check_access(L9P_ACE_ADD_FILE,
2098
parent_acl, &st, NULL, NULL, file->ff_ai, (gid_t)-1);
2099
l9p_acl_free(parent_acl);
2100
if (error)
2101
goto out;
2102
error = fs_dpf(newname, l9stat->name, sizeof(newname));
2103
if (error)
2104
goto out;
2105
tmp = strdup(newname);
2106
if (tmp == NULL) {
2107
error = ENOMEM;
2108
goto out;
2109
}
2110
if (renameat(file->ff_dirfd, file->ff_name, file->ff_dirfd,
2111
tmp) != 0) {
2112
error = errno;
2113
free(tmp);
2114
goto out;
2115
}
2116
/* Successful rename, update file->ff_name. ACL can stay. */
2117
free(file->ff_name);
2118
file->ff_name = tmp;
2119
}
2120
out:
2121
return (error);
2122
}
2123
2124
static int
2125
fs_statfs(void *softc __unused, struct l9p_request *req)
2126
{
2127
struct fs_fid *file;
2128
struct stat st;
2129
struct statfs f;
2130
long name_max;
2131
int error;
2132
int fd;
2133
2134
file = req->lr_fid->lo_aux;
2135
assert(file);
2136
2137
if (fstatat(file->ff_dirfd, file->ff_name, &st,
2138
AT_SYMLINK_NOFOLLOW) != 0)
2139
return (errno);
2140
2141
/*
2142
* Not entirely clear what access to require; we'll go
2143
* for "read data".
2144
*/
2145
fillacl(file);
2146
error = check_access(L9P_ACE_READ_DATA, NULL, NULL,
2147
file->ff_acl, &st, file->ff_ai, (gid_t)-1);
2148
if (error)
2149
return (error);
2150
2151
fd = openat(file->ff_dirfd, file->ff_name, 0);
2152
if (fd < 0)
2153
return (errno);
2154
2155
if (fstatfs(fd, &f) != 0)
2156
return (errno);
2157
2158
name_max = fpathconf(fd, _PC_NAME_MAX);
2159
error = errno;
2160
close(fd);
2161
2162
if (name_max == -1)
2163
return (error);
2164
2165
dostatfs(&req->lr_resp.rstatfs.statfs, &f, name_max);
2166
2167
return (0);
2168
}
2169
2170
static int
2171
fs_lopen(void *softc, struct l9p_request *req)
2172
{
2173
struct l9p_fid *fid = req->lr_fid;
2174
struct stat st;
2175
enum l9p_omode p9;
2176
gid_t gid;
2177
int error, flags;
2178
2179
error = fs_oflags_dotl(req->lr_req.tlopen.flags, &flags, &p9);
2180
if (error)
2181
return (error);
2182
2183
gid = req->lr_req.tlopen.gid;
2184
error = fs_iopen(softc, fid, flags, p9, gid, &st);
2185
if (error)
2186
return (error);
2187
2188
generate_qid(&st, &req->lr_resp.rlopen.qid);
2189
req->lr_resp.rlopen.iounit = req->lr_conn->lc_max_io_size;
2190
return (0);
2191
}
2192
2193
static int
2194
fs_lcreate(void *softc, struct l9p_request *req)
2195
{
2196
struct l9p_fid *dir;
2197
struct stat st;
2198
enum l9p_omode p9;
2199
char *name;
2200
mode_t perm;
2201
gid_t gid;
2202
int error, flags;
2203
2204
dir = req->lr_fid;
2205
name = req->lr_req.tlcreate.name;
2206
2207
error = fs_oflags_dotl(req->lr_req.tlcreate.flags, &flags, &p9);
2208
if (error)
2209
return (error);
2210
2211
perm = (mode_t)req->lr_req.tlcreate.mode & 0777; /* ? set-id bits? */
2212
gid = req->lr_req.tlcreate.gid;
2213
error = fs_icreate(softc, dir, name, flags, false, perm, gid, &st);
2214
if (error == 0)
2215
generate_qid(&st, &req->lr_resp.rlcreate.qid);
2216
req->lr_resp.rlcreate.iounit = req->lr_conn->lc_max_io_size;
2217
return (error);
2218
}
2219
2220
static int
2221
fs_symlink(void *softc, struct l9p_request *req)
2222
{
2223
struct l9p_fid *dir;
2224
struct stat st;
2225
gid_t gid;
2226
char *name, *symtgt;
2227
int error;
2228
2229
dir = req->lr_fid;
2230
name = req->lr_req.tsymlink.name;
2231
symtgt = req->lr_req.tsymlink.symtgt;
2232
gid = req->lr_req.tsymlink.gid;
2233
error = fs_isymlink(softc, dir, name, symtgt, gid, &st);
2234
if (error == 0)
2235
generate_qid(&st, &req->lr_resp.rsymlink.qid);
2236
return (error);
2237
}
2238
2239
static int
2240
fs_mknod(void *softc, struct l9p_request *req)
2241
{
2242
struct l9p_fid *dir;
2243
struct stat st;
2244
uint32_t mode, major, minor;
2245
dev_t dev;
2246
gid_t gid;
2247
char *name;
2248
int error;
2249
2250
dir = req->lr_fid;
2251
name = req->lr_req.tmknod.name;
2252
mode = req->lr_req.tmknod.mode;
2253
gid = req->lr_req.tmknod.gid;
2254
2255
switch (mode & S_IFMT) {
2256
case S_IFBLK:
2257
case S_IFCHR:
2258
mode = (mode & S_IFMT) | (mode & 0777); /* ??? */
2259
major = req->lr_req.tmknod.major;
2260
minor = req->lr_req.tmknod.major;
2261
dev = makedev(major, minor);
2262
error = fs_imknod(softc, dir, name, false,
2263
(mode_t)mode, dev, gid, &st);
2264
break;
2265
2266
case S_IFIFO:
2267
error = fs_imkfifo(softc, dir, name, false,
2268
(mode_t)(mode & 0777), gid, &st);
2269
break;
2270
2271
case S_IFSOCK:
2272
error = fs_imksocket(softc, dir, name, false,
2273
(mode_t)(mode & 0777), gid, &st);
2274
break;
2275
2276
default:
2277
error = EINVAL;
2278
break;
2279
}
2280
if (error == 0)
2281
generate_qid(&st, &req->lr_resp.rmknod.qid);
2282
return (error);
2283
}
2284
2285
static int
2286
fs_rename(void *softc, struct l9p_request *req)
2287
{
2288
struct fs_softc *sc = softc;
2289
struct fs_authinfo *ai;
2290
struct l9p_acl *oparent_acl;
2291
struct l9p_fid *fid, *f2;
2292
struct fs_fid *file, *f2ff;
2293
struct stat cst, opst, npst;
2294
int32_t op;
2295
bool reparenting;
2296
char *tmp;
2297
char olddir[MAXPATHLEN], newname[MAXPATHLEN];
2298
int error;
2299
2300
if (sc->fs_readonly)
2301
return (EROFS);
2302
2303
/*
2304
* Note: lr_fid represents the file that is to be renamed,
2305
* so we must locate its parent directory and verify that
2306
* both this parent directory and the new directory f2 are
2307
* writable. But if the new parent directory is the same
2308
* path as the old parent directory, our job is simpler.
2309
*/
2310
fid = req->lr_fid;
2311
file = fid->lo_aux;
2312
assert(file != NULL);
2313
ai = file->ff_ai;
2314
2315
error = fs_pdir(sc, fid, olddir, sizeof(olddir), &opst);
2316
if (error)
2317
return (error);
2318
2319
f2 = req->lr_fid2;
2320
f2ff = f2->lo_aux;
2321
assert(f2ff != NULL);
2322
2323
reparenting = strcmp(olddir, f2ff->ff_name) != 0;
2324
2325
fillacl(file);
2326
fillacl(f2ff);
2327
2328
if (fstatat(file->ff_dirfd, file->ff_name, &cst,
2329
AT_SYMLINK_NOFOLLOW) != 0)
2330
return (errno);
2331
2332
/*
2333
* Are we moving from olddir? If so, we're unlinking
2334
* from it, in terms of ACL access.
2335
*/
2336
if (reparenting) {
2337
oparent_acl = getacl(file, -1, olddir);
2338
error = check_access(L9P_ACOP_UNLINK,
2339
oparent_acl, &opst, file->ff_acl, &cst, ai, (gid_t)-1);
2340
l9p_acl_free(oparent_acl);
2341
if (error)
2342
return (error);
2343
}
2344
2345
/*
2346
* Now check that we're allowed to "create" a file or directory in
2347
* f2. (Should we do this, too, only if reparenting? Maybe check
2348
* for dir write permission if not reparenting -- but that's just
2349
* add-file/add-subdir, which means doing this always.)
2350
*/
2351
if (fstatat(f2ff->ff_dirfd, f2ff->ff_name, &npst,
2352
AT_SYMLINK_NOFOLLOW) != 0)
2353
return (errno);
2354
2355
op = S_ISDIR(cst.st_mode) ? L9P_ACE_ADD_SUBDIRECTORY : L9P_ACE_ADD_FILE;
2356
error = check_access(op, f2ff->ff_acl, &npst, NULL, NULL,
2357
ai, (gid_t)-1);
2358
if (error)
2359
return (error);
2360
2361
/*
2362
* Directories OK, file systems not R/O, etc; build final name.
2363
* f2ff->ff_name cannot exceed MAXPATHLEN, but out of general
2364
* paranoia, let's double check anyway.
2365
*/
2366
if (strlcpy(newname, f2ff->ff_name, sizeof(newname)) >= sizeof(newname))
2367
return (ENAMETOOLONG);
2368
error = fs_dpf(newname, req->lr_req.trename.name, sizeof(newname));
2369
if (error)
2370
return (error);
2371
tmp = strdup(newname);
2372
if (tmp == NULL)
2373
return (ENOMEM);
2374
2375
if (renameat(file->ff_dirfd, file->ff_name, file->ff_dirfd, tmp) != 0) {
2376
error = errno;
2377
free(tmp);
2378
return (error);
2379
}
2380
2381
/* file has been renamed but old fid is not clunked */
2382
free(file->ff_name);
2383
file->ff_name = tmp;
2384
2385
dropacl(file);
2386
return (0);
2387
}
2388
2389
static int
2390
fs_readlink(void *softc __unused, struct l9p_request *req)
2391
{
2392
struct fs_fid *file;
2393
ssize_t linklen;
2394
char buf[MAXPATHLEN];
2395
int error = 0;
2396
2397
file = req->lr_fid->lo_aux;
2398
assert(file);
2399
2400
linklen = readlinkat(file->ff_dirfd, file->ff_name, buf, sizeof(buf));
2401
if (linklen < 0)
2402
error = errno;
2403
else if ((size_t)linklen >= sizeof(buf))
2404
error = ENOMEM; /* todo: allocate dynamically */
2405
else if ((req->lr_resp.rreadlink.target = strndup(buf,
2406
(size_t)linklen)) == NULL)
2407
error = ENOMEM;
2408
return (error);
2409
}
2410
2411
static int
2412
fs_getattr(void *softc __unused, struct l9p_request *req)
2413
{
2414
uint64_t mask, valid;
2415
struct fs_fid *file;
2416
struct stat st;
2417
int error = 0;
2418
2419
file = req->lr_fid->lo_aux;
2420
assert(file);
2421
2422
valid = 0;
2423
if (fstatat(file->ff_dirfd, file->ff_name, &st, AT_SYMLINK_NOFOLLOW)) {
2424
error = errno;
2425
goto out;
2426
}
2427
/* ?? Can we provide items not-requested? If so, can skip tests. */
2428
mask = req->lr_req.tgetattr.request_mask;
2429
if (mask & L9PL_GETATTR_MODE) {
2430
/* It is not clear if we need any translations. */
2431
req->lr_resp.rgetattr.mode = st.st_mode;
2432
valid |= L9PL_GETATTR_MODE;
2433
}
2434
if (mask & L9PL_GETATTR_NLINK) {
2435
req->lr_resp.rgetattr.nlink = st.st_nlink;
2436
valid |= L9PL_GETATTR_NLINK;
2437
}
2438
if (mask & L9PL_GETATTR_UID) {
2439
/* provide st_uid, or file->ff_uid? */
2440
req->lr_resp.rgetattr.uid = st.st_uid;
2441
valid |= L9PL_GETATTR_UID;
2442
}
2443
if (mask & L9PL_GETATTR_GID) {
2444
/* provide st_gid, or file->ff_gid? */
2445
req->lr_resp.rgetattr.gid = st.st_gid;
2446
valid |= L9PL_GETATTR_GID;
2447
}
2448
if (mask & L9PL_GETATTR_RDEV) {
2449
/* It is not clear if we need any translations. */
2450
req->lr_resp.rgetattr.rdev = (uint64_t)st.st_rdev;
2451
valid |= L9PL_GETATTR_RDEV;
2452
}
2453
if (mask & L9PL_GETATTR_ATIME) {
2454
req->lr_resp.rgetattr.atime_sec =
2455
(uint64_t)st.st_atimespec.tv_sec;
2456
req->lr_resp.rgetattr.atime_nsec =
2457
(uint64_t)st.st_atimespec.tv_nsec;
2458
valid |= L9PL_GETATTR_ATIME;
2459
}
2460
if (mask & L9PL_GETATTR_MTIME) {
2461
req->lr_resp.rgetattr.mtime_sec =
2462
(uint64_t)st.st_mtimespec.tv_sec;
2463
req->lr_resp.rgetattr.mtime_nsec =
2464
(uint64_t)st.st_mtimespec.tv_nsec;
2465
valid |= L9PL_GETATTR_MTIME;
2466
}
2467
if (mask & L9PL_GETATTR_CTIME) {
2468
req->lr_resp.rgetattr.ctime_sec =
2469
(uint64_t)st.st_ctimespec.tv_sec;
2470
req->lr_resp.rgetattr.ctime_nsec =
2471
(uint64_t)st.st_ctimespec.tv_nsec;
2472
valid |= L9PL_GETATTR_CTIME;
2473
}
2474
if (mask & L9PL_GETATTR_BTIME) {
2475
#if defined(HAVE_BIRTHTIME)
2476
req->lr_resp.rgetattr.btime_sec =
2477
(uint64_t)st.st_birthtim.tv_sec;
2478
req->lr_resp.rgetattr.btime_nsec =
2479
(uint64_t)st.st_birthtim.tv_nsec;
2480
#else
2481
req->lr_resp.rgetattr.btime_sec = 0;
2482
req->lr_resp.rgetattr.btime_nsec = 0;
2483
#endif
2484
valid |= L9PL_GETATTR_BTIME;
2485
}
2486
if (mask & L9PL_GETATTR_INO)
2487
valid |= L9PL_GETATTR_INO;
2488
if (mask & L9PL_GETATTR_SIZE) {
2489
req->lr_resp.rgetattr.size = (uint64_t)st.st_size;
2490
valid |= L9PL_GETATTR_SIZE;
2491
}
2492
if (mask & L9PL_GETATTR_BLOCKS) {
2493
req->lr_resp.rgetattr.blksize = (uint64_t)st.st_blksize;
2494
req->lr_resp.rgetattr.blocks = (uint64_t)st.st_blocks;
2495
valid |= L9PL_GETATTR_BLOCKS;
2496
}
2497
if (mask & L9PL_GETATTR_GEN) {
2498
req->lr_resp.rgetattr.gen = st.st_gen;
2499
valid |= L9PL_GETATTR_GEN;
2500
}
2501
/* don't know what to do with data version yet */
2502
2503
generate_qid(&st, &req->lr_resp.rgetattr.qid);
2504
out:
2505
req->lr_resp.rgetattr.valid = valid;
2506
return (error);
2507
}
2508
2509
/*
2510
* Should combine some of this with wstat code.
2511
*/
2512
static int
2513
fs_setattr(void *softc, struct l9p_request *req)
2514
{
2515
uint64_t mask;
2516
struct fs_softc *sc = softc;
2517
struct timespec ts[2];
2518
struct fs_fid *file;
2519
struct stat st;
2520
int error = 0;
2521
uid_t uid, gid;
2522
2523
file = req->lr_fid->lo_aux;
2524
assert(file);
2525
2526
if (sc->fs_readonly)
2527
return (EROFS);
2528
2529
/*
2530
* As with WSTAT we have atomicity issues.
2531
*/
2532
mask = req->lr_req.tsetattr.valid;
2533
2534
if (fstatat(file->ff_dirfd, file->ff_name, &st, AT_SYMLINK_NOFOLLOW)) {
2535
error = errno;
2536
goto out;
2537
}
2538
2539
if ((mask & L9PL_SETATTR_SIZE) && S_ISDIR(st.st_mode)) {
2540
error = EISDIR;
2541
goto out;
2542
}
2543
2544
if (mask & L9PL_SETATTR_MODE) {
2545
if (fchmodat(file->ff_dirfd, file->ff_name,
2546
req->lr_req.tsetattr.mode & 0777,
2547
AT_SYMLINK_NOFOLLOW)) {
2548
error = errno;
2549
goto out;
2550
}
2551
}
2552
2553
if (mask & (L9PL_SETATTR_UID | L9PL_SETATTR_GID)) {
2554
uid = mask & L9PL_SETATTR_UID
2555
? req->lr_req.tsetattr.uid
2556
: (uid_t)-1;
2557
2558
gid = mask & L9PL_SETATTR_GID
2559
? req->lr_req.tsetattr.gid
2560
: (gid_t)-1;
2561
2562
if (fchownat(file->ff_dirfd, file->ff_name, uid, gid,
2563
AT_SYMLINK_NOFOLLOW)) {
2564
error = errno;
2565
goto out;
2566
}
2567
}
2568
2569
if (mask & L9PL_SETATTR_SIZE) {
2570
/* Truncate follows symlinks, is this OK? */
2571
int fd = openat(file->ff_dirfd, file->ff_name, O_RDWR);
2572
if (ftruncate(fd, (off_t)req->lr_req.tsetattr.size)) {
2573
error = errno;
2574
(void) close(fd);
2575
goto out;
2576
}
2577
(void) close(fd);
2578
}
2579
2580
if (mask & (L9PL_SETATTR_ATIME | L9PL_SETATTR_MTIME)) {
2581
ts[0].tv_sec = st.st_atimespec.tv_sec;
2582
ts[0].tv_nsec = st.st_atimespec.tv_nsec;
2583
ts[1].tv_sec = st.st_mtimespec.tv_sec;
2584
ts[1].tv_nsec = st.st_mtimespec.tv_nsec;
2585
2586
if (mask & L9PL_SETATTR_ATIME) {
2587
if (mask & L9PL_SETATTR_ATIME_SET) {
2588
ts[0].tv_sec = req->lr_req.tsetattr.atime_sec;
2589
ts[0].tv_nsec = req->lr_req.tsetattr.atime_nsec;
2590
} else {
2591
if (clock_gettime(CLOCK_REALTIME, &ts[0]) != 0) {
2592
error = errno;
2593
goto out;
2594
}
2595
}
2596
}
2597
2598
if (mask & L9PL_SETATTR_MTIME) {
2599
if (mask & L9PL_SETATTR_MTIME_SET) {
2600
ts[1].tv_sec = req->lr_req.tsetattr.mtime_sec;
2601
ts[1].tv_nsec = req->lr_req.tsetattr.mtime_nsec;
2602
} else {
2603
if (clock_gettime(CLOCK_REALTIME, &ts[1]) != 0) {
2604
error = errno;
2605
goto out;
2606
}
2607
}
2608
}
2609
2610
if (utimensat(file->ff_dirfd, file->ff_name, ts,
2611
AT_SYMLINK_NOFOLLOW)) {
2612
error = errno;
2613
goto out;
2614
}
2615
}
2616
out:
2617
return (error);
2618
}
2619
2620
static int
2621
fs_xattrwalk(void *softc __unused, struct l9p_request *req __unused)
2622
{
2623
return (EOPNOTSUPP);
2624
}
2625
2626
static int
2627
fs_xattrcreate(void *softc __unused, struct l9p_request *req __unused)
2628
{
2629
return (EOPNOTSUPP);
2630
}
2631
2632
static int
2633
fs_readdir(void *softc __unused, struct l9p_request *req)
2634
{
2635
struct l9p_message msg;
2636
struct l9p_dirent de;
2637
struct fs_fid *file;
2638
struct dirent *dp;
2639
struct stat st;
2640
uint32_t count;
2641
int error = 0;
2642
2643
file = req->lr_fid->lo_aux;
2644
assert(file);
2645
2646
if (file->ff_dir == NULL)
2647
return (ENOTDIR);
2648
2649
pthread_mutex_lock(&file->ff_mtx);
2650
2651
/*
2652
* It's not clear whether we can use the same trick for
2653
* discarding offsets here as we do in fs_read. It
2654
* probably should work, we'll have to see if some
2655
* client(s) use the zero-offset thing to rescan without
2656
* clunking the directory first.
2657
*
2658
* Probably the thing to do is switch to calling
2659
* getdirentries() / getdents() directly, instead of
2660
* going through libc.
2661
*/
2662
if (req->lr_req.io.offset == 0)
2663
rewinddir(file->ff_dir);
2664
else
2665
seekdir(file->ff_dir, (long)req->lr_req.io.offset);
2666
2667
l9p_init_msg(&msg, req, L9P_PACK);
2668
count = (uint32_t)msg.lm_size; /* in case we get no entries */
2669
while ((dp = readdir(file->ff_dir)) != NULL) {
2670
/*
2671
* Although "." is forbidden in naming and ".." is
2672
* special cased, testing shows that we must transmit
2673
* them through readdir. (For ".." at root, we
2674
* should perhaps alter the inode number, but not
2675
* yet.)
2676
*/
2677
2678
/*
2679
* TODO: we do a full lstat here; could use dp->d_*
2680
* to construct the qid more efficiently, as long
2681
* as dp->d_type != DT_UNKNOWN.
2682
*/
2683
if (fs_lstatat(file, dp->d_name, &st))
2684
continue;
2685
2686
de.qid.type = 0;
2687
generate_qid(&st, &de.qid);
2688
de.offset = (uint64_t)telldir(file->ff_dir);
2689
de.type = dp->d_type;
2690
de.name = dp->d_name;
2691
2692
/* Update count only if we completely pack the dirent. */
2693
if (l9p_pudirent(&msg, &de) < 0)
2694
break;
2695
count = (uint32_t)msg.lm_size;
2696
}
2697
2698
pthread_mutex_unlock(&file->ff_mtx);
2699
req->lr_resp.io.count = count;
2700
return (error);
2701
}
2702
2703
static int
2704
fs_fsync(void *softc __unused, struct l9p_request *req)
2705
{
2706
struct fs_fid *file;
2707
int error = 0;
2708
2709
file = req->lr_fid->lo_aux;
2710
assert(file);
2711
if (fsync(file->ff_dir != NULL ? dirfd(file->ff_dir) : file->ff_fd))
2712
error = errno;
2713
return (error);
2714
}
2715
2716
static int
2717
fs_lock(void *softc __unused, struct l9p_request *req)
2718
{
2719
2720
switch (req->lr_req.tlock.type) {
2721
case L9PL_LOCK_TYPE_RDLOCK:
2722
case L9PL_LOCK_TYPE_WRLOCK:
2723
case L9PL_LOCK_TYPE_UNLOCK:
2724
break;
2725
default:
2726
return (EINVAL);
2727
}
2728
2729
req->lr_resp.rlock.status = L9PL_LOCK_SUCCESS;
2730
return (0);
2731
}
2732
2733
static int
2734
fs_getlock(void *softc __unused, struct l9p_request *req)
2735
{
2736
2737
/*
2738
* Client wants to see if a request to lock a region would
2739
* block. This is, of course, not atomic anyway, so the
2740
* op is useless. QEMU simply says "unlocked!", so we do
2741
* too.
2742
*/
2743
switch (req->lr_req.getlock.type) {
2744
case L9PL_LOCK_TYPE_RDLOCK:
2745
case L9PL_LOCK_TYPE_WRLOCK:
2746
case L9PL_LOCK_TYPE_UNLOCK:
2747
break;
2748
default:
2749
return (EINVAL);
2750
}
2751
2752
req->lr_resp.getlock = req->lr_req.getlock;
2753
req->lr_resp.getlock.type = L9PL_LOCK_TYPE_UNLOCK;
2754
req->lr_resp.getlock.client_id = strdup(""); /* XXX what should go here? */
2755
return (0);
2756
}
2757
2758
static int
2759
fs_link(void *softc __unused, struct l9p_request *req)
2760
{
2761
struct l9p_fid *dir;
2762
struct fs_fid *file;
2763
struct fs_fid *dirf;
2764
struct stat fst, tdst;
2765
int32_t op;
2766
char *name;
2767
char newname[MAXPATHLEN];
2768
int error;
2769
2770
/* N.B.: lr_fid is the file to link, lr_fid2 is the target dir */
2771
dir = req->lr_fid2;
2772
dirf = dir->lo_aux;
2773
assert(dirf != NULL);
2774
2775
name = req->lr_req.tlink.name;
2776
error = fs_buildname(dir, name, newname, sizeof(newname));
2777
if (error)
2778
return (error);
2779
2780
file = req->lr_fid->lo_aux;
2781
assert(file != NULL);
2782
2783
if (fstatat(dirf->ff_dirfd, dirf->ff_name, &tdst, AT_SYMLINK_NOFOLLOW) != 0 ||
2784
fstatat(file->ff_dirfd, file->ff_name, &fst, AT_SYMLINK_NOFOLLOW) != 0)
2785
return (errno);
2786
if (S_ISDIR(fst.st_mode))
2787
return (EISDIR);
2788
fillacl(dirf);
2789
op = S_ISDIR(fst.st_mode) ? L9P_ACE_ADD_SUBDIRECTORY : L9P_ACE_ADD_FILE;
2790
error = check_access(op,
2791
dirf->ff_acl, &tdst, NULL, NULL, file->ff_ai, (gid_t)-1);
2792
if (error)
2793
return (error);
2794
2795
if (linkat(file->ff_dirfd, file->ff_name, file->ff_dirfd,
2796
newname, 0) != 0)
2797
error = errno;
2798
else
2799
dropacl(file);
2800
2801
return (error);
2802
}
2803
2804
static int
2805
fs_mkdir(void *softc, struct l9p_request *req)
2806
{
2807
struct l9p_fid *dir;
2808
struct stat st;
2809
mode_t perm;
2810
gid_t gid;
2811
char *name;
2812
int error;
2813
2814
dir = req->lr_fid;
2815
name = req->lr_req.tmkdir.name;
2816
perm = (mode_t)req->lr_req.tmkdir.mode;
2817
gid = req->lr_req.tmkdir.gid;
2818
2819
error = fs_imkdir(softc, dir, name, false, perm, gid, &st);
2820
if (error == 0)
2821
generate_qid(&st, &req->lr_resp.rmkdir.qid);
2822
return (error);
2823
}
2824
2825
static int
2826
fs_renameat(void *softc, struct l9p_request *req)
2827
{
2828
struct fs_softc *sc = softc;
2829
struct l9p_fid *olddir, *newdir;
2830
struct l9p_acl *facl;
2831
struct fs_fid *off, *nff;
2832
struct stat odst, ndst, fst;
2833
int32_t op;
2834
bool reparenting;
2835
char *onp, *nnp;
2836
char onb[MAXPATHLEN], nnb[MAXPATHLEN];
2837
int error;
2838
2839
if (sc->fs_readonly)
2840
return (EROFS);
2841
2842
olddir = req->lr_fid;
2843
newdir = req->lr_fid2;
2844
assert(olddir != NULL && newdir != NULL);
2845
off = olddir->lo_aux;
2846
nff = newdir->lo_aux;
2847
assert(off != NULL && nff != NULL);
2848
2849
onp = req->lr_req.trenameat.oldname;
2850
nnp = req->lr_req.trenameat.newname;
2851
error = fs_buildname(olddir, onp, onb, sizeof(onb));
2852
if (error)
2853
return (error);
2854
error = fs_buildname(newdir, nnp, nnb, sizeof(nnb));
2855
if (error)
2856
return (error);
2857
if (fstatat(off->ff_dirfd, onb, &fst, AT_SYMLINK_NOFOLLOW) != 0)
2858
return (errno);
2859
2860
reparenting = olddir != newdir &&
2861
strcmp(off->ff_name, nff->ff_name) != 0;
2862
2863
if (fstatat(off->ff_dirfd, off->ff_name, &odst, AT_SYMLINK_NOFOLLOW) != 0)
2864
return (errno);
2865
if (!S_ISDIR(odst.st_mode))
2866
return (ENOTDIR);
2867
fillacl(off);
2868
2869
if (reparenting) {
2870
if (fstatat(nff->ff_dirfd, nff->ff_name, &ndst, AT_SYMLINK_NOFOLLOW) != 0)
2871
return (errno);
2872
if (!S_ISDIR(ndst.st_mode))
2873
return (ENOTDIR);
2874
facl = getacl(off, -1, onb);
2875
fillacl(nff);
2876
2877
error = check_access(L9P_ACOP_UNLINK,
2878
off->ff_acl, &odst, facl, &fst, off->ff_ai, (gid_t)-1);
2879
l9p_acl_free(facl);
2880
if (error)
2881
return (error);
2882
op = S_ISDIR(fst.st_mode) ? L9P_ACE_ADD_SUBDIRECTORY :
2883
L9P_ACE_ADD_FILE;
2884
error = check_access(op,
2885
nff->ff_acl, &ndst, NULL, NULL, nff->ff_ai, (gid_t)-1);
2886
if (error)
2887
return (error);
2888
}
2889
2890
if (renameat(off->ff_dirfd, onb, nff->ff_dirfd, nnb))
2891
error = errno;
2892
2893
return (error);
2894
}
2895
2896
/*
2897
* Unlink file in given directory, or remove directory in given
2898
* directory, based on flags.
2899
*/
2900
static int
2901
fs_unlinkat(void *softc, struct l9p_request *req)
2902
{
2903
struct fs_softc *sc = softc;
2904
struct l9p_acl *facl;
2905
struct l9p_fid *dir;
2906
struct fs_fid *dirff;
2907
struct stat dirst, fst;
2908
char *name;
2909
char newname[MAXPATHLEN];
2910
int error;
2911
2912
if (sc->fs_readonly)
2913
return (EROFS);
2914
2915
dir = req->lr_fid;
2916
dirff = dir->lo_aux;
2917
assert(dirff != NULL);
2918
name = req->lr_req.tunlinkat.name;
2919
error = fs_buildname(dir, name, newname, sizeof(newname));
2920
if (error)
2921
return (error);
2922
if (fstatat(dirff->ff_dirfd, newname, &fst, AT_SYMLINK_NOFOLLOW) != 0 ||
2923
fstatat(dirff->ff_dirfd, dirff->ff_name, &dirst, AT_SYMLINK_NOFOLLOW) != 0)
2924
return (errno);
2925
fillacl(dirff);
2926
facl = getacl(dirff, -1, newname);
2927
error = check_access(L9P_ACOP_UNLINK,
2928
dirff->ff_acl, &dirst, facl, &fst, dirff->ff_ai, (gid_t)-1);
2929
l9p_acl_free(facl);
2930
if (error)
2931
return (error);
2932
2933
if (req->lr_req.tunlinkat.flags & L9PL_AT_REMOVEDIR) {
2934
if (unlinkat(dirff->ff_dirfd, newname, AT_REMOVEDIR) != 0)
2935
error = errno;
2936
} else {
2937
if (unlinkat(dirff->ff_dirfd, newname, 0) != 0)
2938
error = errno;
2939
}
2940
return (error);
2941
}
2942
2943
static void
2944
fs_freefid(void *softc __unused, struct l9p_fid *fid)
2945
{
2946
struct fs_fid *f = fid->lo_aux;
2947
struct fs_authinfo *ai;
2948
uint32_t newcount;
2949
2950
if (f == NULL) {
2951
/* Nothing to do here */
2952
return;
2953
}
2954
2955
if (f->ff_fd != -1)
2956
close(f->ff_fd);
2957
2958
if (f->ff_dir)
2959
closedir(f->ff_dir);
2960
2961
pthread_mutex_destroy(&f->ff_mtx);
2962
free(f->ff_name);
2963
ai = f->ff_ai;
2964
l9p_acl_free(f->ff_acl);
2965
free(f);
2966
pthread_mutex_lock(&ai->ai_mtx);
2967
newcount = --ai->ai_refcnt;
2968
pthread_mutex_unlock(&ai->ai_mtx);
2969
if (newcount == 0) {
2970
/*
2971
* We *were* the last ref, no one can have gained a ref.
2972
*/
2973
L9P_LOG(L9P_DEBUG, "dropped last ref to authinfo %p",
2974
(void *)ai);
2975
pthread_mutex_destroy(&ai->ai_mtx);
2976
free(ai);
2977
} else {
2978
L9P_LOG(L9P_DEBUG, "authinfo %p now used by %lu",
2979
(void *)ai, (u_long)newcount);
2980
}
2981
}
2982
2983
int
2984
l9p_backend_fs_init(struct l9p_backend **backendp, int rootfd, bool ro)
2985
{
2986
struct l9p_backend *backend;
2987
struct fs_softc *sc;
2988
int error;
2989
#if defined(WITH_CASPER)
2990
cap_channel_t *capcas;
2991
#endif
2992
2993
if (!fs_attach_mutex_inited) {
2994
error = pthread_mutex_init(&fs_attach_mutex, NULL);
2995
if (error) {
2996
errno = error;
2997
return (-1);
2998
}
2999
fs_attach_mutex_inited = true;
3000
}
3001
3002
backend = l9p_malloc(sizeof(*backend));
3003
backend->attach = fs_attach;
3004
backend->clunk = fs_clunk;
3005
backend->create = fs_create;
3006
backend->open = fs_open;
3007
backend->read = fs_read;
3008
backend->remove = fs_remove;
3009
backend->stat = fs_stat;
3010
backend->walk = fs_walk;
3011
backend->write = fs_write;
3012
backend->wstat = fs_wstat;
3013
backend->statfs = fs_statfs;
3014
backend->lopen = fs_lopen;
3015
backend->lcreate = fs_lcreate;
3016
backend->symlink = fs_symlink;
3017
backend->mknod = fs_mknod;
3018
backend->rename = fs_rename;
3019
backend->readlink = fs_readlink;
3020
backend->getattr = fs_getattr;
3021
backend->setattr = fs_setattr;
3022
backend->xattrwalk = fs_xattrwalk;
3023
backend->xattrcreate = fs_xattrcreate;
3024
backend->readdir = fs_readdir;
3025
backend->fsync = fs_fsync;
3026
backend->lock = fs_lock;
3027
backend->getlock = fs_getlock;
3028
backend->link = fs_link;
3029
backend->mkdir = fs_mkdir;
3030
backend->renameat = fs_renameat;
3031
backend->unlinkat = fs_unlinkat;
3032
backend->freefid = fs_freefid;
3033
3034
sc = l9p_malloc(sizeof(*sc));
3035
sc->fs_rootfd = rootfd;
3036
sc->fs_readonly = ro;
3037
backend->softc = sc;
3038
3039
#if defined(WITH_CASPER)
3040
capcas = cap_init();
3041
if (capcas == NULL)
3042
return (-1);
3043
3044
sc->fs_cappwd = cap_service_open(capcas, "system.pwd");
3045
if (sc->fs_cappwd == NULL)
3046
return (-1);
3047
3048
sc->fs_capgrp = cap_service_open(capcas, "system.grp");
3049
if (sc->fs_capgrp == NULL)
3050
return (-1);
3051
3052
cap_setpassent(sc->fs_cappwd, 1);
3053
cap_setgroupent(sc->fs_capgrp, 1);
3054
cap_close(capcas);
3055
#else
3056
setpassent(1);
3057
#endif
3058
3059
*backendp = backend;
3060
return (0);
3061
}
3062
3063