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