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