]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - libhandle/handle.c
xfsprogs: Release v6.15.0
[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 31static int obj_to_handle(char *, int, unsigned int, comarg_t, void**, size_t*);
a8de1cf9 32static char *path_to_fspath(char *path);
93d9f139 33
89184fbc
AG
34
35/*
36 * Filesystem Handle -> Open File Descriptor Cache
37 *
38 * Maps filesystem handles to a corresponding open file descriptor for that
93d9f139 39 * filesystem. We need this because we're doing handle operations via xfsctl
89184fbc
AG
40 * and we need to remember the open file descriptor for each filesystem.
41 */
e9688c1d
NS
42
43struct fdhash {
44 int fsfd;
45 char fsh[FSIDSIZE];
46 struct fdhash *fnxt;
93d9f139 47 char fspath[MAXPATHLEN];
e9688c1d
NS
48};
49
dc987226 50static struct fdhash *fdhash_head = NULL;
e9688c1d 51
852fe013
DW
52void
53fshandle_destroy(void)
54{
55 struct fdhash *nexth;
56 struct fdhash *h = fdhash_head;
57
58 while (h) {
59 nexth = h->fnxt;
60 free(h);
61 h = nexth;
62 }
1ad4d3ba 63 fdhash_head = NULL;
852fe013
DW
64}
65
e9688c1d 66int
3fbbdc85 67path_to_fshandle(
e9688c1d 68 char *path, /* input, path to convert */
a3cbe7cd
MK
69 void **fshanp, /* output, pointer to data */
70 size_t *fshlen) /* output, size of returned data */
e9688c1d
NS
71{
72 int result;
73 int fd;
74 comarg_t obj;
75 struct fdhash *fdhp;
dc987226 76 char *tmppath;
a8de1cf9 77 char *fspath;
e9688c1d 78
a8de1cf9
BK
79 fspath = path_to_fspath(path);
80 if (fspath == NULL)
81 return -1;
82
83 fd = open(fspath, O_RDONLY);
3fbbdc85
NS
84 if (fd < 0)
85 return -1;
e9688c1d
NS
86
87 obj.path = path;
a8de1cf9 88 result = obj_to_handle(fspath, fd, XFS_IOC_PATH_TO_FSHANDLE,
a3cbe7cd 89 obj, fshanp, fshlen);
dc987226
BK
90 if (result < 0) {
91 close(fd);
92 return result;
93 }
da23017d 94
dc987226
BK
95 if (handle_to_fsfd(*fshanp, &tmppath) >= 0) {
96 /* this filesystem is already in the cache */
97 close(fd);
98 } else {
99 /* new filesystem. add it to the cache */
e9688c1d 100 fdhp = malloc(sizeof(struct fdhash));
e9688c1d 101 if (fdhp == NULL) {
8f1c8e13 102 free(*fshanp);
11e06961 103 close(fd);
e9688c1d
NS
104 errno = ENOMEM;
105 return -1;
106 }
107
108 fdhp->fsfd = fd;
f4d02645
DW
109 strncpy(fdhp->fspath, fspath, sizeof(fdhp->fspath) - 1);
110 fdhp->fspath[sizeof(fdhp->fspath) - 1] = 0;
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
56f6ba21
DW
205int
206handle_to_fsfd(
207 void *hanp,
208 char **path)
89184fbc
AG
209{
210 struct fdhash *fdhp;
211
8967ee43
TS
212 /*
213 * Look in cache for matching fsid field in the handle
214 * (which is at the start of the handle).
215 * When found return the file descriptor and path that
216 * we have in the cache.
217 */
89184fbc 218 for (fdhp = fdhash_head; fdhp != NULL; fdhp = fdhp->fnxt) {
93d9f139
NS
219 if (memcmp(fdhp->fsh, hanp, FSIDSIZE) == 0) {
220 *path = fdhp->fspath;
89184fbc 221 return fdhp->fsfd;
93d9f139 222 }
89184fbc 223 }
3fbbdc85 224 errno = EBADF;
89184fbc
AG
225 return -1;
226}
227
93d9f139 228static int
3fbbdc85 229obj_to_handle(
93d9f139 230 char *fspath,
e9688c1d 231 int fsfd,
5b64e00a 232 unsigned int opcode,
e9688c1d
NS
233 comarg_t obj,
234 void **hanp,
235 size_t *hlen)
236{
237 char hbuf [MAXHANSIZ];
238 int ret;
bbfbf5dd
DW
239 uint32_t handlen = 0;
240 struct xfs_fsop_handlereq hreq = { };
241
242 memset(hbuf, 0, MAXHANSIZ);
e9688c1d
NS
243
244 if (opcode == XFS_IOC_FD_TO_HANDLE) {
245 hreq.fd = obj.fd;
246 hreq.path = NULL;
247 } else {
248 hreq.fd = 0;
249 hreq.path = obj.path;
250 }
251
489aaf4d 252 hreq.oflags = O_LARGEFILE;
e9688c1d
NS
253 hreq.ihandle = NULL;
254 hreq.ihandlen = 0;
255 hreq.ohandle = hbuf;
ace4c158 256 hreq.ohandlen = &handlen;
fe37ab57 257
93d9f139 258 ret = xfsctl(fspath, fsfd, opcode, &hreq);
e9688c1d
NS
259 if (ret)
260 return ret;
261
ace4c158 262 *hanp = malloc(handlen);
e9688c1d
NS
263 if (*hanp == NULL) {
264 errno = ENOMEM;
265 return -1;
266 }
267
ace4c158
CH
268 memcpy(*hanp, hbuf, handlen);
269 *hlen = handlen;
e9688c1d
NS
270 return 0;
271}
272
a3cbe7cd
MK
273int
274open_by_fshandle(
275 void *fshanp,
276 size_t fshlen,
277 int rw)
278{
279 int fsfd;
280 char *path;
bbfbf5dd 281 struct xfs_fsop_handlereq hreq = { };
a3cbe7cd
MK
282
283 if ((fsfd = handle_to_fsfd(fshanp, &path)) < 0)
284 return -1;
285
286 hreq.fd = 0;
287 hreq.path = NULL;
288 hreq.oflags = rw | O_LARGEFILE;
289 hreq.ihandle = fshanp;
290 hreq.ihandlen = fshlen;
291 hreq.ohandle = NULL;
292 hreq.ohandlen = NULL;
293
294 return xfsctl(path, fsfd, XFS_IOC_OPEN_BY_HANDLE, &hreq);
295}
296
e9688c1d 297int
3fbbdc85 298open_by_handle(
e9688c1d
NS
299 void *hanp,
300 size_t hlen,
301 int rw)
302{
a3cbe7cd 303 int fsfd;
93d9f139 304 char *path;
e9688c1d
NS
305 xfs_fsop_handlereq_t hreq;
306
45243d21 307 if ((fsfd = handle_to_fsfd(hanp, &path)) < 0)
e9688c1d 308 return -1;
e9688c1d
NS
309
310 hreq.fd = 0;
311 hreq.path = NULL;
489aaf4d 312 hreq.oflags = rw | O_LARGEFILE;
e9688c1d
NS
313 hreq.ihandle = hanp;
314 hreq.ihandlen = hlen;
315 hreq.ohandle = NULL;
316 hreq.ohandlen = NULL;
317
a3cbe7cd 318 return xfsctl(path, fsfd, XFS_IOC_OPEN_BY_HANDLE, &hreq);
e9688c1d
NS
319}
320
321int
3fbbdc85 322readlink_by_handle(
e9688c1d
NS
323 void *hanp,
324 size_t hlen,
325 void *buf,
326 size_t bufsiz)
327{
328 int fd;
1771a6dd 329 __u32 buflen = (__u32)bufsiz;
93d9f139 330 char *path;
e9688c1d
NS
331 xfs_fsop_handlereq_t hreq;
332
3fbbdc85 333 if ((fd = handle_to_fsfd(hanp, &path)) < 0)
e9688c1d 334 return -1;
e9688c1d
NS
335
336 hreq.fd = 0;
337 hreq.path = NULL;
489aaf4d 338 hreq.oflags = O_LARGEFILE;
e9688c1d
NS
339 hreq.ihandle = hanp;
340 hreq.ihandlen = hlen;
341 hreq.ohandle = buf;
1771a6dd 342 hreq.ohandlen = &buflen;
e9688c1d 343
93d9f139 344 return xfsctl(path, fd, XFS_IOC_READLINK_BY_HANDLE, &hreq);
e9688c1d
NS
345}
346
8967ee43 347/*ARGSUSED4*/
14290264
NS
348int
349attr_multi_by_handle(
350 void *hanp,
351 size_t hlen,
352 void *buf,
353 int rtrvcnt,
354 int flags)
355{
356 int fd;
93d9f139 357 char *path;
14290264
NS
358 xfs_fsop_attrmulti_handlereq_t amhreq;
359
3fbbdc85 360 if ((fd = handle_to_fsfd(hanp, &path)) < 0)
14290264 361 return -1;
14290264
NS
362
363 amhreq.hreq.fd = 0;
364 amhreq.hreq.path = NULL;
489aaf4d 365 amhreq.hreq.oflags = O_LARGEFILE;
14290264
NS
366 amhreq.hreq.ihandle = hanp;
367 amhreq.hreq.ihandlen = hlen;
368 amhreq.hreq.ohandle = NULL;
369 amhreq.hreq.ohandlen = NULL;
370
371 amhreq.opcount = rtrvcnt;
372 amhreq.ops = buf;
373
93d9f139 374 return xfsctl(path, fd, XFS_IOC_ATTRMULTI_BY_HANDLE, &amhreq);
14290264
NS
375}
376
377int
378attr_list_by_handle(
379 void *hanp,
380 size_t hlen,
381 void *buf,
382 size_t bufsize,
383 int flags,
384 struct attrlist_cursor *cursor)
385{
258b00ea 386 int error, fd;
93d9f139 387 char *path;
bbfbf5dd 388 struct xfs_fsop_attrlist_handlereq alhreq = { };
14290264 389
3fbbdc85 390 if ((fd = handle_to_fsfd(hanp, &path)) < 0)
14290264 391 return -1;
14290264
NS
392
393 alhreq.hreq.fd = 0;
394 alhreq.hreq.path = NULL;
489aaf4d 395 alhreq.hreq.oflags = O_LARGEFILE;
14290264
NS
396 alhreq.hreq.ihandle = hanp;
397 alhreq.hreq.ihandlen = hlen;
398 alhreq.hreq.ohandle = NULL;
399 alhreq.hreq.ohandlen = NULL;
400
401 memcpy(&alhreq.pos, cursor, sizeof(alhreq.pos));
402 alhreq.flags = flags;
14290264 403 alhreq.buffer = buf;
aa23a327
MG
404 alhreq.buflen = bufsize;
405 /* prevent needless EINVAL from the kernel */
54e724c0
JT
406 if (alhreq.buflen > XFS_XATTR_LIST_MAX)
407 alhreq.buflen = XFS_XATTR_LIST_MAX;
14290264 408
258b00ea
TS
409 error = xfsctl(path, fd, XFS_IOC_ATTRLIST_BY_HANDLE, &alhreq);
410
411 memcpy(cursor, &alhreq.pos, sizeof(alhreq.pos));
412 return error;
413}
414
415int
60ac13e8 416parents_by_handle(
258b00ea
TS
417 void *hanp,
418 size_t hlen,
419 parent_t *buf,
420 size_t bufsiz,
60ac13e8 421 unsigned int *count)
f8149110 422
258b00ea 423{
258b00ea
TS
424 errno = EOPNOTSUPP;
425 return -1;
258b00ea
TS
426}
427
428int
60ac13e8 429parentpaths_by_handle(
258b00ea
TS
430 void *hanp,
431 size_t hlen,
432 parent_t *buf,
433 size_t bufsiz,
60ac13e8 434 unsigned int *count)
258b00ea 435{
258b00ea
TS
436 errno = EOPNOTSUPP;
437 return -1;
14290264
NS
438}
439
e501cb44 440/* Deprecated in kernel */
e1864286 441int
3fbbdc85 442fssetdm_by_handle(
e1864286
DR
443 void *hanp,
444 size_t hlen,
445 struct fsdmidata *fsdmidata)
446{
e501cb44
DW
447 errno = EOPNOTSUPP;
448 return -1;
e1864286
DR
449}
450
8967ee43 451/*ARGSUSED1*/
e9688c1d 452void
3fbbdc85 453free_handle(
e9688c1d
NS
454 void *hanp,
455 size_t hlen)
456{
3fbbdc85 457 free(hanp);
e9688c1d 458}