]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - libhandle/handle.c
mkfs: enable sparse inodes by default
[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 <libgen.h>
20 #include "platform_defs.h"
21 #include "xfs.h"
22 #include "handle.h"
23 #include "parent.h"
24
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
38 typedef union {
39 int fd;
40 char *path;
41 } comarg_t;
42
43 static int obj_to_handle(char *, int, unsigned int, comarg_t, void**, size_t*);
44 static int handle_to_fsfd(void *, char **);
45 static char *path_to_fspath(char *path);
46
47
48 /*
49 * Filesystem Handle -> Open File Descriptor Cache
50 *
51 * Maps filesystem handles to a corresponding open file descriptor for that
52 * filesystem. We need this because we're doing handle operations via xfsctl
53 * and we need to remember the open file descriptor for each filesystem.
54 */
55
56 struct fdhash {
57 int fsfd;
58 char fsh[FSIDSIZE];
59 struct fdhash *fnxt;
60 char fspath[MAXPATHLEN];
61 };
62
63 static struct fdhash *fdhash_head = NULL;
64
65 void
66 fshandle_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 fdhash_head = NULL;
77 }
78
79 int
80 path_to_fshandle(
81 char *path, /* input, path to convert */
82 void **fshanp, /* output, pointer to data */
83 size_t *fshlen) /* output, size of returned data */
84 {
85 int result;
86 int fd;
87 comarg_t obj;
88 struct fdhash *fdhp;
89 char *tmppath;
90 char *fspath;
91
92 fspath = path_to_fspath(path);
93 if (fspath == NULL)
94 return -1;
95
96 fd = open(fspath, O_RDONLY);
97 if (fd < 0)
98 return -1;
99
100 obj.path = path;
101 result = obj_to_handle(fspath, fd, XFS_IOC_PATH_TO_FSHANDLE,
102 obj, fshanp, fshlen);
103 if (result < 0) {
104 close(fd);
105 return result;
106 }
107
108 if (handle_to_fsfd(*fshanp, &tmppath) >= 0) {
109 /* this filesystem is already in the cache */
110 close(fd);
111 } else {
112 /* new filesystem. add it to the cache */
113 fdhp = malloc(sizeof(struct fdhash));
114 if (fdhp == NULL) {
115 free(*fshanp);
116 close(fd);
117 errno = ENOMEM;
118 return -1;
119 }
120
121 fdhp->fsfd = fd;
122 strncpy(fdhp->fspath, fspath, sizeof(fdhp->fspath));
123 memcpy(fdhp->fsh, *fshanp, FSIDSIZE);
124
125 fdhp->fnxt = fdhash_head;
126 fdhash_head = fdhp;
127 }
128
129 return result;
130 }
131
132 int
133 path_to_handle(
134 char *path, /* input, path to convert */
135 void **hanp, /* output, pointer to data */
136 size_t *hlen) /* output, size of returned data */
137 {
138 int fd;
139 int result;
140 comarg_t obj;
141 char *fspath;
142
143 fspath = path_to_fspath(path);
144 if (fspath == NULL)
145 return -1;
146
147 fd = open(fspath, O_RDONLY);
148 if (fd < 0)
149 return -1;
150
151 obj.path = path;
152 result = obj_to_handle(fspath, fd, XFS_IOC_PATH_TO_HANDLE,
153 obj, hanp, hlen);
154 close(fd);
155 return result;
156 }
157
158 /* Given a path, return a suitable "fspath" for use in obtaining
159 * an fd for xfsctl calls. For regular files and directories the
160 * input path is sufficient. For other types the parent directory
161 * is used to avoid issues with opening dangling symlinks and
162 * potentially blocking in an open on a named pipe. Also
163 * symlinks to files on other filesystems would be a problem,
164 * since an fd would be obtained for the wrong fs.
165 */
166 static char *
167 path_to_fspath(char *path)
168 {
169 static char dirpath[MAXPATHLEN];
170 struct stat statbuf;
171
172 if (lstat(path, &statbuf) != 0)
173 return NULL;
174
175 if (S_ISREG(statbuf.st_mode) || S_ISDIR(statbuf.st_mode))
176 return path;
177
178 strncpy(dirpath, path, MAXPATHLEN);
179 dirpath[MAXPATHLEN-1] = '\0';
180 return dirname(dirpath);
181 }
182
183 int
184 fd_to_handle (
185 int fd, /* input, file descriptor */
186 void **hanp, /* output, pointer to data */
187 size_t *hlen) /* output, size of returned data */
188 {
189 comarg_t obj;
190
191 obj.fd = fd;
192 return obj_to_handle(NULL, fd, XFS_IOC_FD_TO_HANDLE, obj, hanp, hlen);
193 }
194
195
196 int
197 handle_to_fshandle(
198 void *hanp,
199 size_t hlen,
200 void **fshanp,
201 size_t *fshlen)
202 {
203 if (hlen < FSIDSIZE) {
204 errno = EINVAL;
205 return -1;
206 }
207 *fshanp = malloc(FSIDSIZE);
208 if (*fshanp == NULL) {
209 errno = ENOMEM;
210 return -1;
211 }
212 *fshlen = FSIDSIZE;
213 memcpy(*fshanp, hanp, FSIDSIZE);
214 return 0;
215 }
216
217 static int
218 handle_to_fsfd(void *hanp, char **path)
219 {
220 struct fdhash *fdhp;
221
222 /*
223 * Look in cache for matching fsid field in the handle
224 * (which is at the start of the handle).
225 * When found return the file descriptor and path that
226 * we have in the cache.
227 */
228 for (fdhp = fdhash_head; fdhp != NULL; fdhp = fdhp->fnxt) {
229 if (memcmp(fdhp->fsh, hanp, FSIDSIZE) == 0) {
230 *path = fdhp->fspath;
231 return fdhp->fsfd;
232 }
233 }
234 errno = EBADF;
235 return -1;
236 }
237
238 static int
239 obj_to_handle(
240 char *fspath,
241 int fsfd,
242 unsigned int opcode,
243 comarg_t obj,
244 void **hanp,
245 size_t *hlen)
246 {
247 char hbuf [MAXHANSIZ];
248 int ret;
249 uint32_t handlen;
250 xfs_fsop_handlereq_t hreq;
251
252 if (opcode == XFS_IOC_FD_TO_HANDLE) {
253 hreq.fd = obj.fd;
254 hreq.path = NULL;
255 } else {
256 hreq.fd = 0;
257 hreq.path = obj.path;
258 }
259
260 hreq.oflags = O_LARGEFILE;
261 hreq.ihandle = NULL;
262 hreq.ihandlen = 0;
263 hreq.ohandle = hbuf;
264 hreq.ohandlen = &handlen;
265
266 ret = xfsctl(fspath, fsfd, opcode, &hreq);
267 if (ret)
268 return ret;
269
270 *hanp = malloc(handlen);
271 if (*hanp == NULL) {
272 errno = ENOMEM;
273 return -1;
274 }
275
276 memcpy(*hanp, hbuf, handlen);
277 *hlen = handlen;
278 return 0;
279 }
280
281 int
282 open_by_fshandle(
283 void *fshanp,
284 size_t fshlen,
285 int rw)
286 {
287 int fsfd;
288 char *path;
289 xfs_fsop_handlereq_t hreq;
290
291 if ((fsfd = handle_to_fsfd(fshanp, &path)) < 0)
292 return -1;
293
294 hreq.fd = 0;
295 hreq.path = NULL;
296 hreq.oflags = rw | O_LARGEFILE;
297 hreq.ihandle = fshanp;
298 hreq.ihandlen = fshlen;
299 hreq.ohandle = NULL;
300 hreq.ohandlen = NULL;
301
302 return xfsctl(path, fsfd, XFS_IOC_OPEN_BY_HANDLE, &hreq);
303 }
304
305 int
306 open_by_handle(
307 void *hanp,
308 size_t hlen,
309 int rw)
310 {
311 int fsfd;
312 char *path;
313 xfs_fsop_handlereq_t hreq;
314
315 if ((fsfd = handle_to_fsfd(hanp, &path)) < 0)
316 return -1;
317
318 hreq.fd = 0;
319 hreq.path = NULL;
320 hreq.oflags = rw | O_LARGEFILE;
321 hreq.ihandle = hanp;
322 hreq.ihandlen = hlen;
323 hreq.ohandle = NULL;
324 hreq.ohandlen = NULL;
325
326 return xfsctl(path, fsfd, XFS_IOC_OPEN_BY_HANDLE, &hreq);
327 }
328
329 int
330 readlink_by_handle(
331 void *hanp,
332 size_t hlen,
333 void *buf,
334 size_t bufsiz)
335 {
336 int fd;
337 __u32 buflen = (__u32)bufsiz;
338 char *path;
339 xfs_fsop_handlereq_t hreq;
340
341 if ((fd = handle_to_fsfd(hanp, &path)) < 0)
342 return -1;
343
344 hreq.fd = 0;
345 hreq.path = NULL;
346 hreq.oflags = O_LARGEFILE;
347 hreq.ihandle = hanp;
348 hreq.ihandlen = hlen;
349 hreq.ohandle = buf;
350 hreq.ohandlen = &buflen;
351
352 return xfsctl(path, fd, XFS_IOC_READLINK_BY_HANDLE, &hreq);
353 }
354
355 /*ARGSUSED4*/
356 int
357 attr_multi_by_handle(
358 void *hanp,
359 size_t hlen,
360 void *buf,
361 int rtrvcnt,
362 int flags)
363 {
364 int fd;
365 char *path;
366 xfs_fsop_attrmulti_handlereq_t amhreq;
367
368 if ((fd = handle_to_fsfd(hanp, &path)) < 0)
369 return -1;
370
371 amhreq.hreq.fd = 0;
372 amhreq.hreq.path = NULL;
373 amhreq.hreq.oflags = O_LARGEFILE;
374 amhreq.hreq.ihandle = hanp;
375 amhreq.hreq.ihandlen = hlen;
376 amhreq.hreq.ohandle = NULL;
377 amhreq.hreq.ohandlen = NULL;
378
379 amhreq.opcount = rtrvcnt;
380 amhreq.ops = buf;
381
382 return xfsctl(path, fd, XFS_IOC_ATTRMULTI_BY_HANDLE, &amhreq);
383 }
384
385 int
386 attr_list_by_handle(
387 void *hanp,
388 size_t hlen,
389 void *buf,
390 size_t bufsize,
391 int flags,
392 struct attrlist_cursor *cursor)
393 {
394 int error, fd;
395 char *path;
396 xfs_fsop_attrlist_handlereq_t alhreq;
397
398 if ((fd = handle_to_fsfd(hanp, &path)) < 0)
399 return -1;
400
401 alhreq.hreq.fd = 0;
402 alhreq.hreq.path = NULL;
403 alhreq.hreq.oflags = O_LARGEFILE;
404 alhreq.hreq.ihandle = hanp;
405 alhreq.hreq.ihandlen = hlen;
406 alhreq.hreq.ohandle = NULL;
407 alhreq.hreq.ohandlen = NULL;
408
409 memcpy(&alhreq.pos, cursor, sizeof(alhreq.pos));
410 alhreq.flags = flags;
411 alhreq.buffer = buf;
412 alhreq.buflen = bufsize;
413 /* prevent needless EINVAL from the kernel */
414 if (alhreq.buflen > XFS_XATTR_LIST_MAX)
415 alhreq.buflen = XFS_XATTR_LIST_MAX;
416
417 error = xfsctl(path, fd, XFS_IOC_ATTRLIST_BY_HANDLE, &alhreq);
418
419 memcpy(cursor, &alhreq.pos, sizeof(alhreq.pos));
420 return error;
421 }
422
423 int
424 parents_by_handle(
425 void *hanp,
426 size_t hlen,
427 parent_t *buf,
428 size_t bufsiz,
429 unsigned int *count)
430
431 {
432 errno = EOPNOTSUPP;
433 return -1;
434 }
435
436 int
437 parentpaths_by_handle(
438 void *hanp,
439 size_t hlen,
440 parent_t *buf,
441 size_t bufsiz,
442 unsigned int *count)
443 {
444 errno = EOPNOTSUPP;
445 return -1;
446 }
447
448 int
449 fssetdm_by_handle(
450 void *hanp,
451 size_t hlen,
452 struct fsdmidata *fsdmidata)
453 {
454 int fd;
455 char *path;
456 xfs_fsop_setdm_handlereq_t dmhreq;
457
458 if ((fd = handle_to_fsfd(hanp, &path)) < 0)
459 return -1;
460
461 dmhreq.hreq.fd = 0;
462 dmhreq.hreq.path = NULL;
463 dmhreq.hreq.oflags = O_LARGEFILE;
464 dmhreq.hreq.ihandle = hanp;
465 dmhreq.hreq.ihandlen = hlen;
466 dmhreq.hreq.ohandle = NULL;
467 dmhreq.hreq.ohandlen = NULL;
468
469 dmhreq.data = fsdmidata;
470
471 return xfsctl(path, fd, XFS_IOC_FSSETDM_BY_HANDLE, &dmhreq);
472 }
473
474 /*ARGSUSED1*/
475 void
476 free_handle(
477 void *hanp,
478 size_t hlen)
479 {
480 free(hanp);
481 }