1 // SPDX-License-Identifier: LGPL-2.1
3 * Copyright (c) 1995, 2001-2003, 2005 Silicon Graphics, Inc.
8 #include "platform_defs.h"
13 /* just pick a value we know is more than big enough */
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.
31 static int obj_to_handle(char *, int, unsigned int, comarg_t
, void**, size_t*);
32 static char *path_to_fspath(char *path
);
36 * Filesystem Handle -> Open File Descriptor Cache
38 * Maps filesystem handles to a corresponding open file descriptor for that
39 * filesystem. We need this because we're doing handle operations via xfsctl
40 * and we need to remember the open file descriptor for each filesystem.
47 char fspath
[MAXPATHLEN
];
50 static struct fdhash
*fdhash_head
= NULL
;
53 fshandle_destroy(void)
56 struct fdhash
*h
= fdhash_head
;
68 char *path
, /* input, path to convert */
69 void **fshanp
, /* output, pointer to data */
70 size_t *fshlen
) /* output, size of returned data */
79 fspath
= path_to_fspath(path
);
83 fd
= open(fspath
, O_RDONLY
);
88 result
= obj_to_handle(fspath
, fd
, XFS_IOC_PATH_TO_FSHANDLE
,
95 if (handle_to_fsfd(*fshanp
, &tmppath
) >= 0) {
96 /* this filesystem is already in the cache */
99 /* new filesystem. add it to the cache */
100 fdhp
= malloc(sizeof(struct fdhash
));
109 strncpy(fdhp
->fspath
, fspath
, sizeof(fdhp
->fspath
) - 1);
110 fdhp
->fspath
[sizeof(fdhp
->fspath
) - 1] = 0;
111 memcpy(fdhp
->fsh
, *fshanp
, FSIDSIZE
);
113 fdhp
->fnxt
= fdhash_head
;
122 char *path
, /* input, path to convert */
123 void **hanp
, /* output, pointer to data */
124 size_t *hlen
) /* output, size of returned data */
131 fspath
= path_to_fspath(path
);
135 fd
= open(fspath
, O_RDONLY
);
140 result
= obj_to_handle(fspath
, fd
, XFS_IOC_PATH_TO_HANDLE
,
146 /* Given a path, return a suitable "fspath" for use in obtaining
147 * an fd for xfsctl calls. For regular files and directories the
148 * input path is sufficient. For other types the parent directory
149 * is used to avoid issues with opening dangling symlinks and
150 * potentially blocking in an open on a named pipe. Also
151 * symlinks to files on other filesystems would be a problem,
152 * since an fd would be obtained for the wrong fs.
155 path_to_fspath(char *path
)
157 static char dirpath
[MAXPATHLEN
];
160 if (lstat(path
, &statbuf
) != 0)
163 if (S_ISREG(statbuf
.st_mode
) || S_ISDIR(statbuf
.st_mode
))
166 strncpy(dirpath
, path
, MAXPATHLEN
);
167 dirpath
[MAXPATHLEN
-1] = '\0';
168 return dirname(dirpath
);
173 int fd
, /* input, file descriptor */
174 void **hanp
, /* output, pointer to data */
175 size_t *hlen
) /* output, size of returned data */
180 return obj_to_handle(NULL
, fd
, XFS_IOC_FD_TO_HANDLE
, obj
, hanp
, hlen
);
191 if (hlen
< FSIDSIZE
) {
195 *fshanp
= malloc(FSIDSIZE
);
196 if (*fshanp
== NULL
) {
201 memcpy(*fshanp
, hanp
, FSIDSIZE
);
213 * Look in cache for matching fsid field in the handle
214 * (which is at the start of the handle).
215 * When found return the file descriptor and path that
216 * we have in the cache.
218 for (fdhp
= fdhash_head
; fdhp
!= NULL
; fdhp
= fdhp
->fnxt
) {
219 if (memcmp(fdhp
->fsh
, hanp
, FSIDSIZE
) == 0) {
220 *path
= fdhp
->fspath
;
237 char hbuf
[MAXHANSIZ
];
239 uint32_t handlen
= 0;
240 struct xfs_fsop_handlereq hreq
= { };
242 memset(hbuf
, 0, MAXHANSIZ
);
244 if (opcode
== XFS_IOC_FD_TO_HANDLE
) {
249 hreq
.path
= obj
.path
;
252 hreq
.oflags
= O_LARGEFILE
;
256 hreq
.ohandlen
= &handlen
;
258 ret
= xfsctl(fspath
, fsfd
, opcode
, &hreq
);
262 *hanp
= malloc(handlen
);
268 memcpy(*hanp
, hbuf
, handlen
);
281 struct xfs_fsop_handlereq hreq
= { };
283 if ((fsfd
= handle_to_fsfd(fshanp
, &path
)) < 0)
288 hreq
.oflags
= rw
| O_LARGEFILE
;
289 hreq
.ihandle
= fshanp
;
290 hreq
.ihandlen
= fshlen
;
292 hreq
.ohandlen
= NULL
;
294 return xfsctl(path
, fsfd
, XFS_IOC_OPEN_BY_HANDLE
, &hreq
);
305 xfs_fsop_handlereq_t hreq
;
307 if ((fsfd
= handle_to_fsfd(hanp
, &path
)) < 0)
312 hreq
.oflags
= rw
| O_LARGEFILE
;
314 hreq
.ihandlen
= hlen
;
316 hreq
.ohandlen
= NULL
;
318 return xfsctl(path
, fsfd
, XFS_IOC_OPEN_BY_HANDLE
, &hreq
);
329 __u32 buflen
= (__u32
)bufsiz
;
331 xfs_fsop_handlereq_t hreq
;
333 if ((fd
= handle_to_fsfd(hanp
, &path
)) < 0)
338 hreq
.oflags
= O_LARGEFILE
;
340 hreq
.ihandlen
= hlen
;
342 hreq
.ohandlen
= &buflen
;
344 return xfsctl(path
, fd
, XFS_IOC_READLINK_BY_HANDLE
, &hreq
);
349 attr_multi_by_handle(
358 xfs_fsop_attrmulti_handlereq_t amhreq
;
360 if ((fd
= handle_to_fsfd(hanp
, &path
)) < 0)
364 amhreq
.hreq
.path
= NULL
;
365 amhreq
.hreq
.oflags
= O_LARGEFILE
;
366 amhreq
.hreq
.ihandle
= hanp
;
367 amhreq
.hreq
.ihandlen
= hlen
;
368 amhreq
.hreq
.ohandle
= NULL
;
369 amhreq
.hreq
.ohandlen
= NULL
;
371 amhreq
.opcount
= rtrvcnt
;
374 return xfsctl(path
, fd
, XFS_IOC_ATTRMULTI_BY_HANDLE
, &amhreq
);
384 struct attrlist_cursor
*cursor
)
388 struct xfs_fsop_attrlist_handlereq alhreq
= { };
390 if ((fd
= handle_to_fsfd(hanp
, &path
)) < 0)
394 alhreq
.hreq
.path
= NULL
;
395 alhreq
.hreq
.oflags
= O_LARGEFILE
;
396 alhreq
.hreq
.ihandle
= hanp
;
397 alhreq
.hreq
.ihandlen
= hlen
;
398 alhreq
.hreq
.ohandle
= NULL
;
399 alhreq
.hreq
.ohandlen
= NULL
;
401 memcpy(&alhreq
.pos
, cursor
, sizeof(alhreq
.pos
));
402 alhreq
.flags
= flags
;
404 alhreq
.buflen
= bufsize
;
405 /* prevent needless EINVAL from the kernel */
406 if (alhreq
.buflen
> XFS_XATTR_LIST_MAX
)
407 alhreq
.buflen
= XFS_XATTR_LIST_MAX
;
409 error
= xfsctl(path
, fd
, XFS_IOC_ATTRLIST_BY_HANDLE
, &alhreq
);
411 memcpy(cursor
, &alhreq
.pos
, sizeof(alhreq
.pos
));
429 parentpaths_by_handle(
440 /* Deprecated in kernel */
445 struct fsdmidata
*fsdmidata
)