2 * Copyright (c) 1995, 2001-2003, 2005 Silicon Graphics, Inc.
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.
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.
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
20 #include "platform_defs.h"
25 /* just pick a value we know is more than big enough */
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.
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
);
49 * Filesystem Handle -> Open File Descriptor Cache
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.
60 char fspath
[MAXPATHLEN
];
63 static struct fdhash
*fdhash_head
= NULL
;
66 fshandle_destroy(void)
69 struct fdhash
*h
= fdhash_head
;
81 char *path
, /* input, path to convert */
82 void **fshanp
, /* output, pointer to data */
83 size_t *fshlen
) /* output, size of returned data */
92 fspath
= path_to_fspath(path
);
96 fd
= open(fspath
, O_RDONLY
);
101 result
= obj_to_handle(fspath
, fd
, XFS_IOC_PATH_TO_FSHANDLE
,
102 obj
, fshanp
, fshlen
);
108 if (handle_to_fsfd(*fshanp
, &tmppath
) >= 0) {
109 /* this filesystem is already in the cache */
112 /* new filesystem. add it to the cache */
113 fdhp
= malloc(sizeof(struct fdhash
));
122 strncpy(fdhp
->fspath
, fspath
, sizeof(fdhp
->fspath
));
123 memcpy(fdhp
->fsh
, *fshanp
, FSIDSIZE
);
125 fdhp
->fnxt
= fdhash_head
;
134 char *path
, /* input, path to convert */
135 void **hanp
, /* output, pointer to data */
136 size_t *hlen
) /* output, size of returned data */
143 fspath
= path_to_fspath(path
);
147 fd
= open(fspath
, O_RDONLY
);
152 result
= obj_to_handle(fspath
, fd
, XFS_IOC_PATH_TO_HANDLE
,
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.
167 path_to_fspath(char *path
)
169 static char dirpath
[MAXPATHLEN
];
172 if (lstat(path
, &statbuf
) != 0)
175 if (S_ISREG(statbuf
.st_mode
) || S_ISDIR(statbuf
.st_mode
))
178 strncpy(dirpath
, path
, MAXPATHLEN
);
179 dirpath
[MAXPATHLEN
-1] = '\0';
180 return dirname(dirpath
);
185 int fd
, /* input, file descriptor */
186 void **hanp
, /* output, pointer to data */
187 size_t *hlen
) /* output, size of returned data */
192 return obj_to_handle(NULL
, fd
, XFS_IOC_FD_TO_HANDLE
, obj
, hanp
, hlen
);
203 if (hlen
< FSIDSIZE
) {
207 *fshanp
= malloc(FSIDSIZE
);
208 if (*fshanp
== NULL
) {
213 memcpy(*fshanp
, hanp
, FSIDSIZE
);
218 handle_to_fsfd(void *hanp
, char **path
)
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.
228 for (fdhp
= fdhash_head
; fdhp
!= NULL
; fdhp
= fdhp
->fnxt
) {
229 if (memcmp(fdhp
->fsh
, hanp
, FSIDSIZE
) == 0) {
230 *path
= fdhp
->fspath
;
247 char hbuf
[MAXHANSIZ
];
250 xfs_fsop_handlereq_t hreq
;
252 if (opcode
== XFS_IOC_FD_TO_HANDLE
) {
257 hreq
.path
= obj
.path
;
260 hreq
.oflags
= O_LARGEFILE
;
264 hreq
.ohandlen
= &handlen
;
266 ret
= xfsctl(fspath
, fsfd
, opcode
, &hreq
);
270 *hanp
= malloc(handlen
);
276 memcpy(*hanp
, hbuf
, handlen
);
289 xfs_fsop_handlereq_t hreq
;
291 if ((fsfd
= handle_to_fsfd(fshanp
, &path
)) < 0)
296 hreq
.oflags
= rw
| O_LARGEFILE
;
297 hreq
.ihandle
= fshanp
;
298 hreq
.ihandlen
= fshlen
;
300 hreq
.ohandlen
= NULL
;
302 return xfsctl(path
, fsfd
, XFS_IOC_OPEN_BY_HANDLE
, &hreq
);
313 xfs_fsop_handlereq_t hreq
;
315 if ((fsfd
= handle_to_fsfd(hanp
, &path
)) < 0)
320 hreq
.oflags
= rw
| O_LARGEFILE
;
322 hreq
.ihandlen
= hlen
;
324 hreq
.ohandlen
= NULL
;
326 return xfsctl(path
, fsfd
, XFS_IOC_OPEN_BY_HANDLE
, &hreq
);
337 __u32 buflen
= (__u32
)bufsiz
;
339 xfs_fsop_handlereq_t hreq
;
341 if ((fd
= handle_to_fsfd(hanp
, &path
)) < 0)
346 hreq
.oflags
= O_LARGEFILE
;
348 hreq
.ihandlen
= hlen
;
350 hreq
.ohandlen
= &buflen
;
352 return xfsctl(path
, fd
, XFS_IOC_READLINK_BY_HANDLE
, &hreq
);
357 attr_multi_by_handle(
366 xfs_fsop_attrmulti_handlereq_t amhreq
;
368 if ((fd
= handle_to_fsfd(hanp
, &path
)) < 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
;
379 amhreq
.opcount
= rtrvcnt
;
382 return xfsctl(path
, fd
, XFS_IOC_ATTRMULTI_BY_HANDLE
, &amhreq
);
392 struct attrlist_cursor
*cursor
)
396 xfs_fsop_attrlist_handlereq_t alhreq
;
398 if ((fd
= handle_to_fsfd(hanp
, &path
)) < 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
;
409 memcpy(&alhreq
.pos
, cursor
, sizeof(alhreq
.pos
));
410 alhreq
.flags
= flags
;
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
;
417 error
= xfsctl(path
, fd
, XFS_IOC_ATTRLIST_BY_HANDLE
, &alhreq
);
419 memcpy(cursor
, &alhreq
.pos
, sizeof(alhreq
.pos
));
437 parentpaths_by_handle(
452 struct fsdmidata
*fsdmidata
)
456 xfs_fsop_setdm_handlereq_t dmhreq
;
458 if ((fd
= handle_to_fsfd(hanp
, &path
)) < 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
;
469 dmhreq
.data
= fsdmidata
;
471 return xfsctl(path
, fd
, XFS_IOC_FSSETDM_BY_HANDLE
, &dmhreq
);