]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - libhandle/handle.c
xfsprogs: Release v6.8.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
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;
f4d02645
DW
110 strncpy(fdhp->fspath, fspath, sizeof(fdhp->fspath) - 1);
111 fdhp->fspath[sizeof(fdhp->fspath) - 1] = 0;
a3cbe7cd
MK
112 memcpy(fdhp->fsh, *fshanp, FSIDSIZE);
113
dc987226
BK
114 fdhp->fnxt = fdhash_head;
115 fdhash_head = fdhp;
e9688c1d
NS
116 }
117
118 return result;
119}
120
e9688c1d 121int
3fbbdc85 122path_to_handle(
e9688c1d
NS
123 char *path, /* input, path to convert */
124 void **hanp, /* output, pointer to data */
125 size_t *hlen) /* output, size of returned data */
126{
127 int fd;
128 int result;
129 comarg_t obj;
a8de1cf9 130 char *fspath;
e9688c1d 131
a8de1cf9
BK
132 fspath = path_to_fspath(path);
133 if (fspath == NULL)
134 return -1;
135
136 fd = open(fspath, O_RDONLY);
3fbbdc85
NS
137 if (fd < 0)
138 return -1;
e9688c1d
NS
139
140 obj.path = path;
a8de1cf9 141 result = obj_to_handle(fspath, fd, XFS_IOC_PATH_TO_HANDLE,
3fbbdc85 142 obj, hanp, hlen);
e9688c1d 143 close(fd);
e9688c1d
NS
144 return result;
145}
146
a8de1cf9
BK
147/* Given a path, return a suitable "fspath" for use in obtaining
148 * an fd for xfsctl calls. For regular files and directories the
149 * input path is sufficient. For other types the parent directory
150 * is used to avoid issues with opening dangling symlinks and
151 * potentially blocking in an open on a named pipe. Also
152 * symlinks to files on other filesystems would be a problem,
153 * since an fd would be obtained for the wrong fs.
154 */
155static char *
156path_to_fspath(char *path)
157{
158 static char dirpath[MAXPATHLEN];
159 struct stat statbuf;
160
161 if (lstat(path, &statbuf) != 0)
162 return NULL;
163
164 if (S_ISREG(statbuf.st_mode) || S_ISDIR(statbuf.st_mode))
165 return path;
166
55d1fd48
ES
167 strncpy(dirpath, path, MAXPATHLEN);
168 dirpath[MAXPATHLEN-1] = '\0';
a8de1cf9
BK
169 return dirname(dirpath);
170}
8967ee43
TS
171
172int
173fd_to_handle (
174 int fd, /* input, file descriptor */
175 void **hanp, /* output, pointer to data */
176 size_t *hlen) /* output, size of returned data */
177{
178 comarg_t obj;
179
180 obj.fd = fd;
181 return obj_to_handle(NULL, fd, XFS_IOC_FD_TO_HANDLE, obj, hanp, hlen);
182}
183
184
e9688c1d 185int
3fbbdc85 186handle_to_fshandle(
e9688c1d
NS
187 void *hanp,
188 size_t hlen,
189 void **fshanp,
190 size_t *fshlen)
191{
dc987226
BK
192 if (hlen < FSIDSIZE) {
193 errno = EINVAL;
194 return -1;
195 }
3fbbdc85 196 *fshanp = malloc(FSIDSIZE);
dc987226
BK
197 if (*fshanp == NULL) {
198 errno = ENOMEM;
199 return -1;
200 }
e9688c1d 201 *fshlen = FSIDSIZE;
e9688c1d 202 memcpy(*fshanp, hanp, FSIDSIZE);
e9688c1d
NS
203 return 0;
204}
205
93d9f139
NS
206static int
207handle_to_fsfd(void *hanp, char **path)
89184fbc
AG
208{
209 struct fdhash *fdhp;
210
8967ee43
TS
211 /*
212 * Look in cache for matching fsid field in the handle
213 * (which is at the start of the handle).
214 * When found return the file descriptor and path that
215 * we have in the cache.
216 */
89184fbc 217 for (fdhp = fdhash_head; fdhp != NULL; fdhp = fdhp->fnxt) {
93d9f139
NS
218 if (memcmp(fdhp->fsh, hanp, FSIDSIZE) == 0) {
219 *path = fdhp->fspath;
89184fbc 220 return fdhp->fsfd;
93d9f139 221 }
89184fbc 222 }
3fbbdc85 223 errno = EBADF;
89184fbc
AG
224 return -1;
225}
226
93d9f139 227static int
3fbbdc85 228obj_to_handle(
93d9f139 229 char *fspath,
e9688c1d 230 int fsfd,
5b64e00a 231 unsigned int opcode,
e9688c1d
NS
232 comarg_t obj,
233 void **hanp,
234 size_t *hlen)
235{
236 char hbuf [MAXHANSIZ];
237 int ret;
bbfbf5dd
DW
238 uint32_t handlen = 0;
239 struct xfs_fsop_handlereq hreq = { };
240
241 memset(hbuf, 0, MAXHANSIZ);
e9688c1d
NS
242
243 if (opcode == XFS_IOC_FD_TO_HANDLE) {
244 hreq.fd = obj.fd;
245 hreq.path = NULL;
246 } else {
247 hreq.fd = 0;
248 hreq.path = obj.path;
249 }
250
489aaf4d 251 hreq.oflags = O_LARGEFILE;
e9688c1d
NS
252 hreq.ihandle = NULL;
253 hreq.ihandlen = 0;
254 hreq.ohandle = hbuf;
ace4c158 255 hreq.ohandlen = &handlen;
fe37ab57 256
93d9f139 257 ret = xfsctl(fspath, fsfd, opcode, &hreq);
e9688c1d
NS
258 if (ret)
259 return ret;
260
ace4c158 261 *hanp = malloc(handlen);
e9688c1d
NS
262 if (*hanp == NULL) {
263 errno = ENOMEM;
264 return -1;
265 }
266
ace4c158
CH
267 memcpy(*hanp, hbuf, handlen);
268 *hlen = handlen;
e9688c1d
NS
269 return 0;
270}
271
a3cbe7cd
MK
272int
273open_by_fshandle(
274 void *fshanp,
275 size_t fshlen,
276 int rw)
277{
278 int fsfd;
279 char *path;
bbfbf5dd 280 struct xfs_fsop_handlereq hreq = { };
a3cbe7cd
MK
281
282 if ((fsfd = handle_to_fsfd(fshanp, &path)) < 0)
283 return -1;
284
285 hreq.fd = 0;
286 hreq.path = NULL;
287 hreq.oflags = rw | O_LARGEFILE;
288 hreq.ihandle = fshanp;
289 hreq.ihandlen = fshlen;
290 hreq.ohandle = NULL;
291 hreq.ohandlen = NULL;
292
293 return xfsctl(path, fsfd, XFS_IOC_OPEN_BY_HANDLE, &hreq);
294}
295
e9688c1d 296int
3fbbdc85 297open_by_handle(
e9688c1d
NS
298 void *hanp,
299 size_t hlen,
300 int rw)
301{
a3cbe7cd 302 int fsfd;
93d9f139 303 char *path;
e9688c1d
NS
304 xfs_fsop_handlereq_t hreq;
305
45243d21 306 if ((fsfd = handle_to_fsfd(hanp, &path)) < 0)
e9688c1d 307 return -1;
e9688c1d
NS
308
309 hreq.fd = 0;
310 hreq.path = NULL;
489aaf4d 311 hreq.oflags = rw | O_LARGEFILE;
e9688c1d
NS
312 hreq.ihandle = hanp;
313 hreq.ihandlen = hlen;
314 hreq.ohandle = NULL;
315 hreq.ohandlen = NULL;
316
a3cbe7cd 317 return xfsctl(path, fsfd, XFS_IOC_OPEN_BY_HANDLE, &hreq);
e9688c1d
NS
318}
319
320int
3fbbdc85 321readlink_by_handle(
e9688c1d
NS
322 void *hanp,
323 size_t hlen,
324 void *buf,
325 size_t bufsiz)
326{
327 int fd;
1771a6dd 328 __u32 buflen = (__u32)bufsiz;
93d9f139 329 char *path;
e9688c1d
NS
330 xfs_fsop_handlereq_t hreq;
331
3fbbdc85 332 if ((fd = handle_to_fsfd(hanp, &path)) < 0)
e9688c1d 333 return -1;
e9688c1d
NS
334
335 hreq.fd = 0;
336 hreq.path = NULL;
489aaf4d 337 hreq.oflags = O_LARGEFILE;
e9688c1d
NS
338 hreq.ihandle = hanp;
339 hreq.ihandlen = hlen;
340 hreq.ohandle = buf;
1771a6dd 341 hreq.ohandlen = &buflen;
e9688c1d 342
93d9f139 343 return xfsctl(path, fd, XFS_IOC_READLINK_BY_HANDLE, &hreq);
e9688c1d
NS
344}
345
8967ee43 346/*ARGSUSED4*/
14290264
NS
347int
348attr_multi_by_handle(
349 void *hanp,
350 size_t hlen,
351 void *buf,
352 int rtrvcnt,
353 int flags)
354{
355 int fd;
93d9f139 356 char *path;
14290264
NS
357 xfs_fsop_attrmulti_handlereq_t amhreq;
358
3fbbdc85 359 if ((fd = handle_to_fsfd(hanp, &path)) < 0)
14290264 360 return -1;
14290264
NS
361
362 amhreq.hreq.fd = 0;
363 amhreq.hreq.path = NULL;
489aaf4d 364 amhreq.hreq.oflags = O_LARGEFILE;
14290264
NS
365 amhreq.hreq.ihandle = hanp;
366 amhreq.hreq.ihandlen = hlen;
367 amhreq.hreq.ohandle = NULL;
368 amhreq.hreq.ohandlen = NULL;
369
370 amhreq.opcount = rtrvcnt;
371 amhreq.ops = buf;
372
93d9f139 373 return xfsctl(path, fd, XFS_IOC_ATTRMULTI_BY_HANDLE, &amhreq);
14290264
NS
374}
375
376int
377attr_list_by_handle(
378 void *hanp,
379 size_t hlen,
380 void *buf,
381 size_t bufsize,
382 int flags,
383 struct attrlist_cursor *cursor)
384{
258b00ea 385 int error, fd;
93d9f139 386 char *path;
bbfbf5dd 387 struct xfs_fsop_attrlist_handlereq alhreq = { };
14290264 388
3fbbdc85 389 if ((fd = handle_to_fsfd(hanp, &path)) < 0)
14290264 390 return -1;
14290264
NS
391
392 alhreq.hreq.fd = 0;
393 alhreq.hreq.path = NULL;
489aaf4d 394 alhreq.hreq.oflags = O_LARGEFILE;
14290264
NS
395 alhreq.hreq.ihandle = hanp;
396 alhreq.hreq.ihandlen = hlen;
397 alhreq.hreq.ohandle = NULL;
398 alhreq.hreq.ohandlen = NULL;
399
400 memcpy(&alhreq.pos, cursor, sizeof(alhreq.pos));
401 alhreq.flags = flags;
14290264 402 alhreq.buffer = buf;
aa23a327
MG
403 alhreq.buflen = bufsize;
404 /* prevent needless EINVAL from the kernel */
54e724c0
JT
405 if (alhreq.buflen > XFS_XATTR_LIST_MAX)
406 alhreq.buflen = XFS_XATTR_LIST_MAX;
14290264 407
258b00ea
TS
408 error = xfsctl(path, fd, XFS_IOC_ATTRLIST_BY_HANDLE, &alhreq);
409
410 memcpy(cursor, &alhreq.pos, sizeof(alhreq.pos));
411 return error;
412}
413
414int
60ac13e8 415parents_by_handle(
258b00ea
TS
416 void *hanp,
417 size_t hlen,
418 parent_t *buf,
419 size_t bufsiz,
60ac13e8 420 unsigned int *count)
f8149110 421
258b00ea 422{
258b00ea
TS
423 errno = EOPNOTSUPP;
424 return -1;
258b00ea
TS
425}
426
427int
60ac13e8 428parentpaths_by_handle(
258b00ea
TS
429 void *hanp,
430 size_t hlen,
431 parent_t *buf,
432 size_t bufsiz,
60ac13e8 433 unsigned int *count)
258b00ea 434{
258b00ea
TS
435 errno = EOPNOTSUPP;
436 return -1;
14290264
NS
437}
438
e501cb44 439/* Deprecated in kernel */
e1864286 440int
3fbbdc85 441fssetdm_by_handle(
e1864286
DR
442 void *hanp,
443 size_t hlen,
444 struct fsdmidata *fsdmidata)
445{
e501cb44
DW
446 errno = EOPNOTSUPP;
447 return -1;
e1864286
DR
448}
449
8967ee43 450/*ARGSUSED1*/
e9688c1d 451void
3fbbdc85 452free_handle(
e9688c1d
NS
453 void *hanp,
454 size_t hlen)
455{
3fbbdc85 456 free(hanp);
e9688c1d 457}