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