]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - libhandle/handle.c
libxfs: refactor manage_zones()
[thirdparty/xfsprogs-dev.git] / libhandle / handle.c
CommitLineData
959ef981 1// SPDX-License-Identifier: LGPL-2.1
e9688c1d 2/*
da23017d
NS
3 * Copyright (c) 1995, 2001-2003, 2005 Silicon Graphics, Inc.
4 * All Rights Reserved.
e9688c1d
NS
5 */
6
a8de1cf9 7#include <libgen.h>
dcabd4e7 8#include "platform_defs.h"
6b803e5a
CH
9#include "xfs.h"
10#include "handle.h"
11#include "parent.h"
e9688c1d 12
e9688c1d
NS
13/* just pick a value we know is more than big enough */
14#define MAXHANSIZ 64
15
16/*
17 * The actual content of a handle is supposed to be opaque here.
18 * But, to do handle_to_fshandle, we need to know what it is. Sigh.
19 * However we can get by with knowing only that the first 8 bytes of
20 * a file handle are the file system ID, and that a file system handle
21 * consists of only those 8 bytes.
22 */
23
24#define FSIDSIZE 8
25
26typedef union {
27 int fd;
28 char *path;
29} comarg_t;
30
3fbbdc85
NS
31static int obj_to_handle(char *, int, unsigned int, comarg_t, void**, size_t*);
32static int handle_to_fsfd(void *, char **);
a8de1cf9 33static char *path_to_fspath(char *path);
93d9f139 34
89184fbc
AG
35
36/*
37 * Filesystem Handle -> Open File Descriptor Cache
38 *
39 * Maps filesystem handles to a corresponding open file descriptor for that
93d9f139 40 * filesystem. We need this because we're doing handle operations via xfsctl
89184fbc
AG
41 * and we need to remember the open file descriptor for each filesystem.
42 */
e9688c1d
NS
43
44struct fdhash {
45 int fsfd;
46 char fsh[FSIDSIZE];
47 struct fdhash *fnxt;
93d9f139 48 char fspath[MAXPATHLEN];
e9688c1d
NS
49};
50
dc987226 51static struct fdhash *fdhash_head = NULL;
e9688c1d 52
852fe013
DW
53void
54fshandle_destroy(void)
55{
56 struct fdhash *nexth;
57 struct fdhash *h = fdhash_head;
58
59 while (h) {
60 nexth = h->fnxt;
61 free(h);
62 h = nexth;
63 }
1ad4d3ba 64 fdhash_head = NULL;
852fe013
DW
65}
66
e9688c1d 67int
3fbbdc85 68path_to_fshandle(
e9688c1d 69 char *path, /* input, path to convert */
a3cbe7cd
MK
70 void **fshanp, /* output, pointer to data */
71 size_t *fshlen) /* output, size of returned data */
e9688c1d
NS
72{
73 int result;
74 int fd;
75 comarg_t obj;
76 struct fdhash *fdhp;
dc987226 77 char *tmppath;
a8de1cf9 78 char *fspath;
e9688c1d 79
a8de1cf9
BK
80 fspath = path_to_fspath(path);
81 if (fspath == NULL)
82 return -1;
83
84 fd = open(fspath, O_RDONLY);
3fbbdc85
NS
85 if (fd < 0)
86 return -1;
e9688c1d
NS
87
88 obj.path = path;
a8de1cf9 89 result = obj_to_handle(fspath, fd, XFS_IOC_PATH_TO_FSHANDLE,
a3cbe7cd 90 obj, fshanp, fshlen);
dc987226
BK
91 if (result < 0) {
92 close(fd);
93 return result;
94 }
da23017d 95
dc987226
BK
96 if (handle_to_fsfd(*fshanp, &tmppath) >= 0) {
97 /* this filesystem is already in the cache */
98 close(fd);
99 } else {
100 /* new filesystem. add it to the cache */
e9688c1d 101 fdhp = malloc(sizeof(struct fdhash));
e9688c1d 102 if (fdhp == NULL) {
8f1c8e13 103 free(*fshanp);
11e06961 104 close(fd);
e9688c1d
NS
105 errno = ENOMEM;
106 return -1;
107 }
108
109 fdhp->fsfd = fd;
a8de1cf9 110 strncpy(fdhp->fspath, fspath, sizeof(fdhp->fspath));
a3cbe7cd
MK
111 memcpy(fdhp->fsh, *fshanp, FSIDSIZE);
112
dc987226
BK
113 fdhp->fnxt = fdhash_head;
114 fdhash_head = fdhp;
e9688c1d
NS
115 }
116
117 return result;
118}
119
e9688c1d 120int
3fbbdc85 121path_to_handle(
e9688c1d
NS
122 char *path, /* input, path to convert */
123 void **hanp, /* output, pointer to data */
124 size_t *hlen) /* output, size of returned data */
125{
126 int fd;
127 int result;
128 comarg_t obj;
a8de1cf9 129 char *fspath;
e9688c1d 130
a8de1cf9
BK
131 fspath = path_to_fspath(path);
132 if (fspath == NULL)
133 return -1;
134
135 fd = open(fspath, O_RDONLY);
3fbbdc85
NS
136 if (fd < 0)
137 return -1;
e9688c1d
NS
138
139 obj.path = path;
a8de1cf9 140 result = obj_to_handle(fspath, fd, XFS_IOC_PATH_TO_HANDLE,
3fbbdc85 141 obj, hanp, hlen);
e9688c1d 142 close(fd);
e9688c1d
NS
143 return result;
144}
145
a8de1cf9
BK
146/* Given a path, return a suitable "fspath" for use in obtaining
147 * an fd for xfsctl calls. For regular files and directories the
148 * input path is sufficient. For other types the parent directory
149 * is used to avoid issues with opening dangling symlinks and
150 * potentially blocking in an open on a named pipe. Also
151 * symlinks to files on other filesystems would be a problem,
152 * since an fd would be obtained for the wrong fs.
153 */
154static char *
155path_to_fspath(char *path)
156{
157 static char dirpath[MAXPATHLEN];
158 struct stat statbuf;
159
160 if (lstat(path, &statbuf) != 0)
161 return NULL;
162
163 if (S_ISREG(statbuf.st_mode) || S_ISDIR(statbuf.st_mode))
164 return path;
165
55d1fd48
ES
166 strncpy(dirpath, path, MAXPATHLEN);
167 dirpath[MAXPATHLEN-1] = '\0';
a8de1cf9
BK
168 return dirname(dirpath);
169}
8967ee43
TS
170
171int
172fd_to_handle (
173 int fd, /* input, file descriptor */
174 void **hanp, /* output, pointer to data */
175 size_t *hlen) /* output, size of returned data */
176{
177 comarg_t obj;
178
179 obj.fd = fd;
180 return obj_to_handle(NULL, fd, XFS_IOC_FD_TO_HANDLE, obj, hanp, hlen);
181}
182
183
e9688c1d 184int
3fbbdc85 185handle_to_fshandle(
e9688c1d
NS
186 void *hanp,
187 size_t hlen,
188 void **fshanp,
189 size_t *fshlen)
190{
dc987226
BK
191 if (hlen < FSIDSIZE) {
192 errno = EINVAL;
193 return -1;
194 }
3fbbdc85 195 *fshanp = malloc(FSIDSIZE);
dc987226
BK
196 if (*fshanp == NULL) {
197 errno = ENOMEM;
198 return -1;
199 }
e9688c1d 200 *fshlen = FSIDSIZE;
e9688c1d 201 memcpy(*fshanp, hanp, FSIDSIZE);
e9688c1d
NS
202 return 0;
203}
204
93d9f139
NS
205static int
206handle_to_fsfd(void *hanp, char **path)
89184fbc
AG
207{
208 struct fdhash *fdhp;
209
8967ee43
TS
210 /*
211 * Look in cache for matching fsid field in the handle
212 * (which is at the start of the handle).
213 * When found return the file descriptor and path that
214 * we have in the cache.
215 */
89184fbc 216 for (fdhp = fdhash_head; fdhp != NULL; fdhp = fdhp->fnxt) {
93d9f139
NS
217 if (memcmp(fdhp->fsh, hanp, FSIDSIZE) == 0) {
218 *path = fdhp->fspath;
89184fbc 219 return fdhp->fsfd;
93d9f139 220 }
89184fbc 221 }
3fbbdc85 222 errno = EBADF;
89184fbc
AG
223 return -1;
224}
225
93d9f139 226static int
3fbbdc85 227obj_to_handle(
93d9f139 228 char *fspath,
e9688c1d 229 int fsfd,
5b64e00a 230 unsigned int opcode,
e9688c1d
NS
231 comarg_t obj,
232 void **hanp,
233 size_t *hlen)
234{
235 char hbuf [MAXHANSIZ];
236 int ret;
14f8b681 237 uint32_t handlen;
e9688c1d
NS
238 xfs_fsop_handlereq_t hreq;
239
240 if (opcode == XFS_IOC_FD_TO_HANDLE) {
241 hreq.fd = obj.fd;
242 hreq.path = NULL;
243 } else {
244 hreq.fd = 0;
245 hreq.path = obj.path;
246 }
247
489aaf4d 248 hreq.oflags = O_LARGEFILE;
e9688c1d
NS
249 hreq.ihandle = NULL;
250 hreq.ihandlen = 0;
251 hreq.ohandle = hbuf;
ace4c158 252 hreq.ohandlen = &handlen;
fe37ab57 253
93d9f139 254 ret = xfsctl(fspath, fsfd, opcode, &hreq);
e9688c1d
NS
255 if (ret)
256 return ret;
257
ace4c158 258 *hanp = malloc(handlen);
e9688c1d
NS
259 if (*hanp == NULL) {
260 errno = ENOMEM;
261 return -1;
262 }
263
ace4c158
CH
264 memcpy(*hanp, hbuf, handlen);
265 *hlen = handlen;
e9688c1d
NS
266 return 0;
267}
268
a3cbe7cd
MK
269int
270open_by_fshandle(
271 void *fshanp,
272 size_t fshlen,
273 int rw)
274{
275 int fsfd;
276 char *path;
277 xfs_fsop_handlereq_t hreq;
278
279 if ((fsfd = handle_to_fsfd(fshanp, &path)) < 0)
280 return -1;
281
282 hreq.fd = 0;
283 hreq.path = NULL;
284 hreq.oflags = rw | O_LARGEFILE;
285 hreq.ihandle = fshanp;
286 hreq.ihandlen = fshlen;
287 hreq.ohandle = NULL;
288 hreq.ohandlen = NULL;
289
290 return xfsctl(path, fsfd, XFS_IOC_OPEN_BY_HANDLE, &hreq);
291}
292
e9688c1d 293int
3fbbdc85 294open_by_handle(
e9688c1d
NS
295 void *hanp,
296 size_t hlen,
297 int rw)
298{
a3cbe7cd 299 int fsfd;
93d9f139 300 char *path;
e9688c1d
NS
301 xfs_fsop_handlereq_t hreq;
302
45243d21 303 if ((fsfd = handle_to_fsfd(hanp, &path)) < 0)
e9688c1d 304 return -1;
e9688c1d
NS
305
306 hreq.fd = 0;
307 hreq.path = NULL;
489aaf4d 308 hreq.oflags = rw | O_LARGEFILE;
e9688c1d
NS
309 hreq.ihandle = hanp;
310 hreq.ihandlen = hlen;
311 hreq.ohandle = NULL;
312 hreq.ohandlen = NULL;
313
a3cbe7cd 314 return xfsctl(path, fsfd, XFS_IOC_OPEN_BY_HANDLE, &hreq);
e9688c1d
NS
315}
316
317int
3fbbdc85 318readlink_by_handle(
e9688c1d
NS
319 void *hanp,
320 size_t hlen,
321 void *buf,
322 size_t bufsiz)
323{
324 int fd;
1771a6dd 325 __u32 buflen = (__u32)bufsiz;
93d9f139 326 char *path;
e9688c1d
NS
327 xfs_fsop_handlereq_t hreq;
328
3fbbdc85 329 if ((fd = handle_to_fsfd(hanp, &path)) < 0)
e9688c1d 330 return -1;
e9688c1d
NS
331
332 hreq.fd = 0;
333 hreq.path = NULL;
489aaf4d 334 hreq.oflags = O_LARGEFILE;
e9688c1d
NS
335 hreq.ihandle = hanp;
336 hreq.ihandlen = hlen;
337 hreq.ohandle = buf;
1771a6dd 338 hreq.ohandlen = &buflen;
e9688c1d 339
93d9f139 340 return xfsctl(path, fd, XFS_IOC_READLINK_BY_HANDLE, &hreq);
e9688c1d
NS
341}
342
8967ee43 343/*ARGSUSED4*/
14290264
NS
344int
345attr_multi_by_handle(
346 void *hanp,
347 size_t hlen,
348 void *buf,
349 int rtrvcnt,
350 int flags)
351{
352 int fd;
93d9f139 353 char *path;
14290264
NS
354 xfs_fsop_attrmulti_handlereq_t amhreq;
355
3fbbdc85 356 if ((fd = handle_to_fsfd(hanp, &path)) < 0)
14290264 357 return -1;
14290264
NS
358
359 amhreq.hreq.fd = 0;
360 amhreq.hreq.path = NULL;
489aaf4d 361 amhreq.hreq.oflags = O_LARGEFILE;
14290264
NS
362 amhreq.hreq.ihandle = hanp;
363 amhreq.hreq.ihandlen = hlen;
364 amhreq.hreq.ohandle = NULL;
365 amhreq.hreq.ohandlen = NULL;
366
367 amhreq.opcount = rtrvcnt;
368 amhreq.ops = buf;
369
93d9f139 370 return xfsctl(path, fd, XFS_IOC_ATTRMULTI_BY_HANDLE, &amhreq);
14290264
NS
371}
372
373int
374attr_list_by_handle(
375 void *hanp,
376 size_t hlen,
377 void *buf,
378 size_t bufsize,
379 int flags,
380 struct attrlist_cursor *cursor)
381{
258b00ea 382 int error, fd;
93d9f139 383 char *path;
14290264
NS
384 xfs_fsop_attrlist_handlereq_t alhreq;
385
3fbbdc85 386 if ((fd = handle_to_fsfd(hanp, &path)) < 0)
14290264 387 return -1;
14290264
NS
388
389 alhreq.hreq.fd = 0;
390 alhreq.hreq.path = NULL;
489aaf4d 391 alhreq.hreq.oflags = O_LARGEFILE;
14290264
NS
392 alhreq.hreq.ihandle = hanp;
393 alhreq.hreq.ihandlen = hlen;
394 alhreq.hreq.ohandle = NULL;
395 alhreq.hreq.ohandlen = NULL;
396
397 memcpy(&alhreq.pos, cursor, sizeof(alhreq.pos));
398 alhreq.flags = flags;
14290264 399 alhreq.buffer = buf;
aa23a327
MG
400 alhreq.buflen = bufsize;
401 /* prevent needless EINVAL from the kernel */
54e724c0
JT
402 if (alhreq.buflen > XFS_XATTR_LIST_MAX)
403 alhreq.buflen = XFS_XATTR_LIST_MAX;
14290264 404
258b00ea
TS
405 error = xfsctl(path, fd, XFS_IOC_ATTRLIST_BY_HANDLE, &alhreq);
406
407 memcpy(cursor, &alhreq.pos, sizeof(alhreq.pos));
408 return error;
409}
410
411int
60ac13e8 412parents_by_handle(
258b00ea
TS
413 void *hanp,
414 size_t hlen,
415 parent_t *buf,
416 size_t bufsiz,
60ac13e8 417 unsigned int *count)
f8149110 418
258b00ea 419{
258b00ea
TS
420 errno = EOPNOTSUPP;
421 return -1;
258b00ea
TS
422}
423
424int
60ac13e8 425parentpaths_by_handle(
258b00ea
TS
426 void *hanp,
427 size_t hlen,
428 parent_t *buf,
429 size_t bufsiz,
60ac13e8 430 unsigned int *count)
258b00ea 431{
258b00ea
TS
432 errno = EOPNOTSUPP;
433 return -1;
14290264
NS
434}
435
e1864286 436int
3fbbdc85 437fssetdm_by_handle(
e1864286
DR
438 void *hanp,
439 size_t hlen,
440 struct fsdmidata *fsdmidata)
441{
442 int fd;
93d9f139 443 char *path;
e1864286
DR
444 xfs_fsop_setdm_handlereq_t dmhreq;
445
3fbbdc85 446 if ((fd = handle_to_fsfd(hanp, &path)) < 0)
e1864286 447 return -1;
e1864286
DR
448
449 dmhreq.hreq.fd = 0;
450 dmhreq.hreq.path = NULL;
489aaf4d 451 dmhreq.hreq.oflags = O_LARGEFILE;
e1864286
DR
452 dmhreq.hreq.ihandle = hanp;
453 dmhreq.hreq.ihandlen = hlen;
454 dmhreq.hreq.ohandle = NULL;
455 dmhreq.hreq.ohandlen = NULL;
456
457 dmhreq.data = fsdmidata;
458
93d9f139 459 return xfsctl(path, fd, XFS_IOC_FSSETDM_BY_HANDLE, &dmhreq);
e1864286
DR
460}
461
8967ee43 462/*ARGSUSED1*/
e9688c1d 463void
3fbbdc85 464free_handle(
e9688c1d
NS
465 void *hanp,
466 size_t hlen)
467{
3fbbdc85 468 free(hanp);
e9688c1d 469}