]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - libhandle/handle.c
xfs_quota: allow name lookup when reporting from ID range
[thirdparty/xfsprogs-dev.git] / libhandle / handle.c
CommitLineData
e9688c1d 1/*
da23017d
NS
2 * Copyright (c) 1995, 2001-2003, 2005 Silicon Graphics, Inc.
3 * All Rights Reserved.
7c49c48b 4 *
da23017d
NS
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
7c49c48b
DR
7 * as published by the Free Software Foundation.
8 *
da23017d
NS
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.
7c49c48b 13 *
da23017d
NS
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
e9688c1d
NS
17 */
18
a8de1cf9 19#include <libgen.h>
dcabd4e7 20#include "platform_defs.h"
6b803e5a
CH
21#include "xfs.h"
22#include "handle.h"
23#include "parent.h"
e9688c1d 24
e9688c1d
NS
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
38typedef union {
39 int fd;
40 char *path;
41} comarg_t;
42
3fbbdc85
NS
43static int obj_to_handle(char *, int, unsigned int, comarg_t, void**, size_t*);
44static int handle_to_fsfd(void *, char **);
a8de1cf9 45static char *path_to_fspath(char *path);
93d9f139 46
89184fbc
AG
47
48/*
49 * Filesystem Handle -> Open File Descriptor Cache
50 *
51 * Maps filesystem handles to a corresponding open file descriptor for that
93d9f139 52 * filesystem. We need this because we're doing handle operations via xfsctl
89184fbc
AG
53 * and we need to remember the open file descriptor for each filesystem.
54 */
e9688c1d
NS
55
56struct fdhash {
57 int fsfd;
58 char fsh[FSIDSIZE];
59 struct fdhash *fnxt;
93d9f139 60 char fspath[MAXPATHLEN];
e9688c1d
NS
61};
62
dc987226 63static struct fdhash *fdhash_head = NULL;
e9688c1d
NS
64
65int
3fbbdc85 66path_to_fshandle(
e9688c1d 67 char *path, /* input, path to convert */
a3cbe7cd
MK
68 void **fshanp, /* output, pointer to data */
69 size_t *fshlen) /* output, size of returned data */
e9688c1d
NS
70{
71 int result;
72 int fd;
73 comarg_t obj;
74 struct fdhash *fdhp;
dc987226 75 char *tmppath;
a8de1cf9 76 char *fspath;
e9688c1d 77
a8de1cf9
BK
78 fspath = path_to_fspath(path);
79 if (fspath == NULL)
80 return -1;
81
82 fd = open(fspath, O_RDONLY);
3fbbdc85
NS
83 if (fd < 0)
84 return -1;
e9688c1d
NS
85
86 obj.path = path;
a8de1cf9 87 result = obj_to_handle(fspath, fd, XFS_IOC_PATH_TO_FSHANDLE,
a3cbe7cd 88 obj, fshanp, fshlen);
dc987226
BK
89 if (result < 0) {
90 close(fd);
91 return result;
92 }
da23017d 93
dc987226
BK
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 */
e9688c1d 99 fdhp = malloc(sizeof(struct fdhash));
e9688c1d 100 if (fdhp == NULL) {
8f1c8e13 101 free(*fshanp);
11e06961 102 close(fd);
e9688c1d
NS
103 errno = ENOMEM;
104 return -1;
105 }
106
107 fdhp->fsfd = fd;
a8de1cf9 108 strncpy(fdhp->fspath, fspath, sizeof(fdhp->fspath));
a3cbe7cd
MK
109 memcpy(fdhp->fsh, *fshanp, FSIDSIZE);
110
dc987226
BK
111 fdhp->fnxt = fdhash_head;
112 fdhash_head = fdhp;
e9688c1d
NS
113 }
114
115 return result;
116}
117
e9688c1d 118int
3fbbdc85 119path_to_handle(
e9688c1d
NS
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;
a8de1cf9 127 char *fspath;
e9688c1d 128
a8de1cf9
BK
129 fspath = path_to_fspath(path);
130 if (fspath == NULL)
131 return -1;
132
133 fd = open(fspath, O_RDONLY);
3fbbdc85
NS
134 if (fd < 0)
135 return -1;
e9688c1d
NS
136
137 obj.path = path;
a8de1cf9 138 result = obj_to_handle(fspath, fd, XFS_IOC_PATH_TO_HANDLE,
3fbbdc85 139 obj, hanp, hlen);
e9688c1d 140 close(fd);
e9688c1d
NS
141 return result;
142}
143
a8de1cf9
BK
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 */
152static char *
153path_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
55d1fd48
ES
164 strncpy(dirpath, path, MAXPATHLEN);
165 dirpath[MAXPATHLEN-1] = '\0';
a8de1cf9
BK
166 return dirname(dirpath);
167}
8967ee43
TS
168
169int
170fd_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
e9688c1d 182int
3fbbdc85 183handle_to_fshandle(
e9688c1d
NS
184 void *hanp,
185 size_t hlen,
186 void **fshanp,
187 size_t *fshlen)
188{
dc987226
BK
189 if (hlen < FSIDSIZE) {
190 errno = EINVAL;
191 return -1;
192 }
3fbbdc85 193 *fshanp = malloc(FSIDSIZE);
dc987226
BK
194 if (*fshanp == NULL) {
195 errno = ENOMEM;
196 return -1;
197 }
e9688c1d 198 *fshlen = FSIDSIZE;
e9688c1d 199 memcpy(*fshanp, hanp, FSIDSIZE);
e9688c1d
NS
200 return 0;
201}
202
93d9f139
NS
203static int
204handle_to_fsfd(void *hanp, char **path)
89184fbc
AG
205{
206 struct fdhash *fdhp;
207
8967ee43
TS
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 */
89184fbc 214 for (fdhp = fdhash_head; fdhp != NULL; fdhp = fdhp->fnxt) {
93d9f139
NS
215 if (memcmp(fdhp->fsh, hanp, FSIDSIZE) == 0) {
216 *path = fdhp->fspath;
89184fbc 217 return fdhp->fsfd;
93d9f139 218 }
89184fbc 219 }
3fbbdc85 220 errno = EBADF;
89184fbc
AG
221 return -1;
222}
223
93d9f139 224static int
3fbbdc85 225obj_to_handle(
93d9f139 226 char *fspath,
e9688c1d 227 int fsfd,
5b64e00a 228 unsigned int opcode,
e9688c1d
NS
229 comarg_t obj,
230 void **hanp,
231 size_t *hlen)
232{
233 char hbuf [MAXHANSIZ];
234 int ret;
ace4c158 235 __uint32_t handlen;
e9688c1d
NS
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
489aaf4d 246 hreq.oflags = O_LARGEFILE;
e9688c1d
NS
247 hreq.ihandle = NULL;
248 hreq.ihandlen = 0;
249 hreq.ohandle = hbuf;
ace4c158 250 hreq.ohandlen = &handlen;
fe37ab57 251
93d9f139 252 ret = xfsctl(fspath, fsfd, opcode, &hreq);
e9688c1d
NS
253 if (ret)
254 return ret;
255
ace4c158 256 *hanp = malloc(handlen);
e9688c1d
NS
257 if (*hanp == NULL) {
258 errno = ENOMEM;
259 return -1;
260 }
261
ace4c158
CH
262 memcpy(*hanp, hbuf, handlen);
263 *hlen = handlen;
e9688c1d
NS
264 return 0;
265}
266
a3cbe7cd
MK
267int
268open_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
e9688c1d 291int
3fbbdc85 292open_by_handle(
e9688c1d
NS
293 void *hanp,
294 size_t hlen,
295 int rw)
296{
a3cbe7cd 297 int fsfd;
93d9f139 298 char *path;
e9688c1d
NS
299 xfs_fsop_handlereq_t hreq;
300
45243d21 301 if ((fsfd = handle_to_fsfd(hanp, &path)) < 0)
e9688c1d 302 return -1;
e9688c1d
NS
303
304 hreq.fd = 0;
305 hreq.path = NULL;
489aaf4d 306 hreq.oflags = rw | O_LARGEFILE;
e9688c1d
NS
307 hreq.ihandle = hanp;
308 hreq.ihandlen = hlen;
309 hreq.ohandle = NULL;
310 hreq.ohandlen = NULL;
311
a3cbe7cd 312 return xfsctl(path, fsfd, XFS_IOC_OPEN_BY_HANDLE, &hreq);
e9688c1d
NS
313}
314
315int
3fbbdc85 316readlink_by_handle(
e9688c1d
NS
317 void *hanp,
318 size_t hlen,
319 void *buf,
320 size_t bufsiz)
321{
322 int fd;
1771a6dd 323 __u32 buflen = (__u32)bufsiz;
93d9f139 324 char *path;
e9688c1d
NS
325 xfs_fsop_handlereq_t hreq;
326
3fbbdc85 327 if ((fd = handle_to_fsfd(hanp, &path)) < 0)
e9688c1d 328 return -1;
e9688c1d
NS
329
330 hreq.fd = 0;
331 hreq.path = NULL;
489aaf4d 332 hreq.oflags = O_LARGEFILE;
e9688c1d
NS
333 hreq.ihandle = hanp;
334 hreq.ihandlen = hlen;
335 hreq.ohandle = buf;
1771a6dd 336 hreq.ohandlen = &buflen;
e9688c1d 337
93d9f139 338 return xfsctl(path, fd, XFS_IOC_READLINK_BY_HANDLE, &hreq);
e9688c1d
NS
339}
340
8967ee43 341/*ARGSUSED4*/
14290264
NS
342int
343attr_multi_by_handle(
344 void *hanp,
345 size_t hlen,
346 void *buf,
347 int rtrvcnt,
348 int flags)
349{
350 int fd;
93d9f139 351 char *path;
14290264
NS
352 xfs_fsop_attrmulti_handlereq_t amhreq;
353
3fbbdc85 354 if ((fd = handle_to_fsfd(hanp, &path)) < 0)
14290264 355 return -1;
14290264
NS
356
357 amhreq.hreq.fd = 0;
358 amhreq.hreq.path = NULL;
489aaf4d 359 amhreq.hreq.oflags = O_LARGEFILE;
14290264
NS
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
93d9f139 368 return xfsctl(path, fd, XFS_IOC_ATTRMULTI_BY_HANDLE, &amhreq);
14290264
NS
369}
370
371int
372attr_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{
258b00ea 380 int error, fd;
93d9f139 381 char *path;
14290264
NS
382 xfs_fsop_attrlist_handlereq_t alhreq;
383
3fbbdc85 384 if ((fd = handle_to_fsfd(hanp, &path)) < 0)
14290264 385 return -1;
14290264
NS
386
387 alhreq.hreq.fd = 0;
388 alhreq.hreq.path = NULL;
489aaf4d 389 alhreq.hreq.oflags = O_LARGEFILE;
14290264
NS
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;
14290264 397 alhreq.buffer = buf;
aa23a327
MG
398 alhreq.buflen = bufsize;
399 /* prevent needless EINVAL from the kernel */
54e724c0
JT
400 if (alhreq.buflen > XFS_XATTR_LIST_MAX)
401 alhreq.buflen = XFS_XATTR_LIST_MAX;
14290264 402
258b00ea
TS
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
409int
60ac13e8 410parents_by_handle(
258b00ea
TS
411 void *hanp,
412 size_t hlen,
413 parent_t *buf,
414 size_t bufsiz,
60ac13e8
TS
415 unsigned int *count)
416
258b00ea 417{
258b00ea
TS
418 errno = EOPNOTSUPP;
419 return -1;
258b00ea
TS
420}
421
422int
60ac13e8 423parentpaths_by_handle(
258b00ea
TS
424 void *hanp,
425 size_t hlen,
426 parent_t *buf,
427 size_t bufsiz,
60ac13e8 428 unsigned int *count)
258b00ea 429{
258b00ea
TS
430 errno = EOPNOTSUPP;
431 return -1;
14290264
NS
432}
433
e1864286 434int
3fbbdc85 435fssetdm_by_handle(
e1864286
DR
436 void *hanp,
437 size_t hlen,
438 struct fsdmidata *fsdmidata)
439{
440 int fd;
93d9f139 441 char *path;
e1864286
DR
442 xfs_fsop_setdm_handlereq_t dmhreq;
443
3fbbdc85 444 if ((fd = handle_to_fsfd(hanp, &path)) < 0)
e1864286 445 return -1;
e1864286
DR
446
447 dmhreq.hreq.fd = 0;
448 dmhreq.hreq.path = NULL;
489aaf4d 449 dmhreq.hreq.oflags = O_LARGEFILE;
e1864286
DR
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
93d9f139 457 return xfsctl(path, fd, XFS_IOC_FSSETDM_BY_HANDLE, &dmhreq);
e1864286
DR
458}
459
8967ee43 460/*ARGSUSED1*/
e9688c1d 461void
3fbbdc85 462free_handle(
e9688c1d
NS
463 void *hanp,
464 size_t hlen)
465{
3fbbdc85 466 free(hanp);
e9688c1d 467}