]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - libhandle/handle.c
libhandle: fix potential unterminated string problem
[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;
14f8b681 238 uint32_t handlen;
e9688c1d
NS
239 xfs_fsop_handlereq_t hreq;
240
241 if (opcode == XFS_IOC_FD_TO_HANDLE) {
242 hreq.fd = obj.fd;
243 hreq.path = NULL;
244 } else {
245 hreq.fd = 0;
246 hreq.path = obj.path;
247 }
248
489aaf4d 249 hreq.oflags = O_LARGEFILE;
e9688c1d
NS
250 hreq.ihandle = NULL;
251 hreq.ihandlen = 0;
252 hreq.ohandle = hbuf;
ace4c158 253 hreq.ohandlen = &handlen;
fe37ab57 254
93d9f139 255 ret = xfsctl(fspath, fsfd, opcode, &hreq);
e9688c1d
NS
256 if (ret)
257 return ret;
258
ace4c158 259 *hanp = malloc(handlen);
e9688c1d
NS
260 if (*hanp == NULL) {
261 errno = ENOMEM;
262 return -1;
263 }
264
ace4c158
CH
265 memcpy(*hanp, hbuf, handlen);
266 *hlen = handlen;
e9688c1d
NS
267 return 0;
268}
269
a3cbe7cd
MK
270int
271open_by_fshandle(
272 void *fshanp,
273 size_t fshlen,
274 int rw)
275{
276 int fsfd;
277 char *path;
278 xfs_fsop_handlereq_t hreq;
279
280 if ((fsfd = handle_to_fsfd(fshanp, &path)) < 0)
281 return -1;
282
283 hreq.fd = 0;
284 hreq.path = NULL;
285 hreq.oflags = rw | O_LARGEFILE;
286 hreq.ihandle = fshanp;
287 hreq.ihandlen = fshlen;
288 hreq.ohandle = NULL;
289 hreq.ohandlen = NULL;
290
291 return xfsctl(path, fsfd, XFS_IOC_OPEN_BY_HANDLE, &hreq);
292}
293
e9688c1d 294int
3fbbdc85 295open_by_handle(
e9688c1d
NS
296 void *hanp,
297 size_t hlen,
298 int rw)
299{
a3cbe7cd 300 int fsfd;
93d9f139 301 char *path;
e9688c1d
NS
302 xfs_fsop_handlereq_t hreq;
303
45243d21 304 if ((fsfd = handle_to_fsfd(hanp, &path)) < 0)
e9688c1d 305 return -1;
e9688c1d
NS
306
307 hreq.fd = 0;
308 hreq.path = NULL;
489aaf4d 309 hreq.oflags = rw | O_LARGEFILE;
e9688c1d
NS
310 hreq.ihandle = hanp;
311 hreq.ihandlen = hlen;
312 hreq.ohandle = NULL;
313 hreq.ohandlen = NULL;
314
a3cbe7cd 315 return xfsctl(path, fsfd, XFS_IOC_OPEN_BY_HANDLE, &hreq);
e9688c1d
NS
316}
317
318int
3fbbdc85 319readlink_by_handle(
e9688c1d
NS
320 void *hanp,
321 size_t hlen,
322 void *buf,
323 size_t bufsiz)
324{
325 int fd;
1771a6dd 326 __u32 buflen = (__u32)bufsiz;
93d9f139 327 char *path;
e9688c1d
NS
328 xfs_fsop_handlereq_t hreq;
329
3fbbdc85 330 if ((fd = handle_to_fsfd(hanp, &path)) < 0)
e9688c1d 331 return -1;
e9688c1d
NS
332
333 hreq.fd = 0;
334 hreq.path = NULL;
489aaf4d 335 hreq.oflags = O_LARGEFILE;
e9688c1d
NS
336 hreq.ihandle = hanp;
337 hreq.ihandlen = hlen;
338 hreq.ohandle = buf;
1771a6dd 339 hreq.ohandlen = &buflen;
e9688c1d 340
93d9f139 341 return xfsctl(path, fd, XFS_IOC_READLINK_BY_HANDLE, &hreq);
e9688c1d
NS
342}
343
8967ee43 344/*ARGSUSED4*/
14290264
NS
345int
346attr_multi_by_handle(
347 void *hanp,
348 size_t hlen,
349 void *buf,
350 int rtrvcnt,
351 int flags)
352{
353 int fd;
93d9f139 354 char *path;
14290264
NS
355 xfs_fsop_attrmulti_handlereq_t amhreq;
356
3fbbdc85 357 if ((fd = handle_to_fsfd(hanp, &path)) < 0)
14290264 358 return -1;
14290264
NS
359
360 amhreq.hreq.fd = 0;
361 amhreq.hreq.path = NULL;
489aaf4d 362 amhreq.hreq.oflags = O_LARGEFILE;
14290264
NS
363 amhreq.hreq.ihandle = hanp;
364 amhreq.hreq.ihandlen = hlen;
365 amhreq.hreq.ohandle = NULL;
366 amhreq.hreq.ohandlen = NULL;
367
368 amhreq.opcount = rtrvcnt;
369 amhreq.ops = buf;
370
93d9f139 371 return xfsctl(path, fd, XFS_IOC_ATTRMULTI_BY_HANDLE, &amhreq);
14290264
NS
372}
373
374int
375attr_list_by_handle(
376 void *hanp,
377 size_t hlen,
378 void *buf,
379 size_t bufsize,
380 int flags,
381 struct attrlist_cursor *cursor)
382{
258b00ea 383 int error, fd;
93d9f139 384 char *path;
14290264
NS
385 xfs_fsop_attrlist_handlereq_t alhreq;
386
3fbbdc85 387 if ((fd = handle_to_fsfd(hanp, &path)) < 0)
14290264 388 return -1;
14290264
NS
389
390 alhreq.hreq.fd = 0;
391 alhreq.hreq.path = NULL;
489aaf4d 392 alhreq.hreq.oflags = O_LARGEFILE;
14290264
NS
393 alhreq.hreq.ihandle = hanp;
394 alhreq.hreq.ihandlen = hlen;
395 alhreq.hreq.ohandle = NULL;
396 alhreq.hreq.ohandlen = NULL;
397
398 memcpy(&alhreq.pos, cursor, sizeof(alhreq.pos));
399 alhreq.flags = flags;
14290264 400 alhreq.buffer = buf;
aa23a327
MG
401 alhreq.buflen = bufsize;
402 /* prevent needless EINVAL from the kernel */
54e724c0
JT
403 if (alhreq.buflen > XFS_XATTR_LIST_MAX)
404 alhreq.buflen = XFS_XATTR_LIST_MAX;
14290264 405
258b00ea
TS
406 error = xfsctl(path, fd, XFS_IOC_ATTRLIST_BY_HANDLE, &alhreq);
407
408 memcpy(cursor, &alhreq.pos, sizeof(alhreq.pos));
409 return error;
410}
411
412int
60ac13e8 413parents_by_handle(
258b00ea
TS
414 void *hanp,
415 size_t hlen,
416 parent_t *buf,
417 size_t bufsiz,
60ac13e8 418 unsigned int *count)
f8149110 419
258b00ea 420{
258b00ea
TS
421 errno = EOPNOTSUPP;
422 return -1;
258b00ea
TS
423}
424
425int
60ac13e8 426parentpaths_by_handle(
258b00ea
TS
427 void *hanp,
428 size_t hlen,
429 parent_t *buf,
430 size_t bufsiz,
60ac13e8 431 unsigned int *count)
258b00ea 432{
258b00ea
TS
433 errno = EOPNOTSUPP;
434 return -1;
14290264
NS
435}
436
e1864286 437int
3fbbdc85 438fssetdm_by_handle(
e1864286
DR
439 void *hanp,
440 size_t hlen,
441 struct fsdmidata *fsdmidata)
442{
443 int fd;
93d9f139 444 char *path;
e1864286
DR
445 xfs_fsop_setdm_handlereq_t dmhreq;
446
3fbbdc85 447 if ((fd = handle_to_fsfd(hanp, &path)) < 0)
e1864286 448 return -1;
e1864286
DR
449
450 dmhreq.hreq.fd = 0;
451 dmhreq.hreq.path = NULL;
489aaf4d 452 dmhreq.hreq.oflags = O_LARGEFILE;
e1864286
DR
453 dmhreq.hreq.ihandle = hanp;
454 dmhreq.hreq.ihandlen = hlen;
455 dmhreq.hreq.ohandle = NULL;
456 dmhreq.hreq.ohandlen = NULL;
457
458 dmhreq.data = fsdmidata;
459
93d9f139 460 return xfsctl(path, fd, XFS_IOC_FSSETDM_BY_HANDLE, &dmhreq);
e1864286
DR
461}
462
8967ee43 463/*ARGSUSED1*/
e9688c1d 464void
3fbbdc85 465free_handle(
e9688c1d
NS
466 void *hanp,
467 size_t hlen)
468{
3fbbdc85 469 free(hanp);
e9688c1d 470}