file: Fix file command on /dev/VG/LV paths (RHBZ#582484).
[libguestfs.git] / daemon / stat.c
1 /* libguestfs - the guestfsd daemon
2  * Copyright (C) 2009 Red Hat Inc.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will 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 General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  */
18
19 #include <config.h>
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <fcntl.h>
27 #include <unistd.h>
28
29 #include "../src/guestfs_protocol.h"
30 #include "daemon.h"
31 #include "actions.h"
32
33 guestfs_int_stat *
34 do_stat (const char *path)
35 {
36   int r;
37   guestfs_int_stat *ret;
38   struct stat statbuf;
39
40   CHROOT_IN;
41   r = stat (path, &statbuf);
42   CHROOT_OUT;
43
44   if (r == -1) {
45     reply_with_perror ("stat");
46     return NULL;
47   }
48
49   ret = malloc (sizeof *ret);
50   if (ret == NULL) {
51     reply_with_perror ("malloc");
52     return NULL;
53   }
54
55   ret->dev = statbuf.st_dev;
56   ret->ino = statbuf.st_ino;
57   ret->mode = statbuf.st_mode;
58   ret->nlink = statbuf.st_nlink;
59   ret->uid = statbuf.st_uid;
60   ret->gid = statbuf.st_gid;
61   ret->rdev = statbuf.st_rdev;
62   ret->size = statbuf.st_size;
63 #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
64   ret->blksize = statbuf.st_blksize;
65 #else
66   ret->blksize = -1;
67 #endif
68 #ifdef HAVE_STRUCT_STAT_ST_BLOCKS
69   ret->blocks = statbuf.st_blocks;
70 #else
71   ret->blocks = -1;
72 #endif
73   ret->atime = statbuf.st_atime;
74   ret->mtime = statbuf.st_mtime;
75   ret->ctime = statbuf.st_ctime;
76
77   return ret;
78 }
79
80 guestfs_int_stat *
81 do_lstat (const char *path)
82 {
83   int r;
84   guestfs_int_stat *ret;
85   struct stat statbuf;
86
87   CHROOT_IN;
88   r = lstat (path, &statbuf);
89   CHROOT_OUT;
90
91   if (r == -1) {
92     reply_with_perror ("stat");
93     return NULL;
94   }
95
96   ret = malloc (sizeof *ret);
97   if (ret == NULL) {
98     reply_with_perror ("malloc");
99     return NULL;
100   }
101
102   ret->dev = statbuf.st_dev;
103   ret->ino = statbuf.st_ino;
104   ret->mode = statbuf.st_mode;
105   ret->nlink = statbuf.st_nlink;
106   ret->uid = statbuf.st_uid;
107   ret->gid = statbuf.st_gid;
108   ret->rdev = statbuf.st_rdev;
109   ret->size = statbuf.st_size;
110 #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
111   ret->blksize = statbuf.st_blksize;
112 #else
113   ret->blksize = -1;
114 #endif
115 #ifdef HAVE_STRUCT_STAT_ST_BLOCKS
116   ret->blocks = statbuf.st_blocks;
117 #else
118   ret->blocks = -1;
119 #endif
120   ret->atime = statbuf.st_atime;
121   ret->mtime = statbuf.st_mtime;
122   ret->ctime = statbuf.st_ctime;
123
124   return ret;
125 }
126
127 guestfs_int_stat_list *
128 do_lstatlist (const char *path, char *const *names)
129 {
130   int path_fd;
131   guestfs_int_stat_list *ret;
132   size_t i, nr_names;
133
134   nr_names = count_strings (names);
135
136   ret = malloc (sizeof *ret);
137   if (!ret) {
138     reply_with_perror ("malloc");
139     return NULL;
140   }
141   ret->guestfs_int_stat_list_len = nr_names;
142   ret->guestfs_int_stat_list_val = calloc (nr_names, sizeof (guestfs_int_stat));
143   if (ret->guestfs_int_stat_list_val == NULL) {
144     reply_with_perror ("malloc");
145     free (ret);
146     return NULL;
147   }
148
149   CHROOT_IN;
150   path_fd = open (path, O_RDONLY | O_DIRECTORY);
151   CHROOT_OUT;
152
153   if (path_fd == -1) {
154     reply_with_perror ("%s", path);
155     free (ret->guestfs_int_stat_list_val);
156     free (ret);
157     return NULL;
158   }
159
160   for (i = 0; names[i] != NULL; ++i) {
161     int r;
162     struct stat statbuf;
163
164     r = fstatat (path_fd, names[i], &statbuf, AT_SYMLINK_NOFOLLOW);
165     if (r == -1)
166       ret->guestfs_int_stat_list_val[i].ino = -1;
167     else {
168       ret->guestfs_int_stat_list_val[i].dev = statbuf.st_dev;
169       ret->guestfs_int_stat_list_val[i].ino = statbuf.st_ino;
170       ret->guestfs_int_stat_list_val[i].mode = statbuf.st_mode;
171       ret->guestfs_int_stat_list_val[i].nlink = statbuf.st_nlink;
172       ret->guestfs_int_stat_list_val[i].uid = statbuf.st_uid;
173       ret->guestfs_int_stat_list_val[i].gid = statbuf.st_gid;
174       ret->guestfs_int_stat_list_val[i].rdev = statbuf.st_rdev;
175       ret->guestfs_int_stat_list_val[i].size = statbuf.st_size;
176 #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
177       ret->guestfs_int_stat_list_val[i].blksize = statbuf.st_blksize;
178 #else
179       ret->guestfs_int_stat_list_val[i].blksize = -1;
180 #endif
181 #ifdef HAVE_STRUCT_STAT_ST_BLOCKS
182       ret->guestfs_int_stat_list_val[i].blocks = statbuf.st_blocks;
183 #else
184       ret->guestfs_int_stat_list_val[i].blocks = -1;
185 #endif
186       ret->guestfs_int_stat_list_val[i].atime = statbuf.st_atime;
187       ret->guestfs_int_stat_list_val[i].mtime = statbuf.st_mtime;
188       ret->guestfs_int_stat_list_val[i].ctime = statbuf.st_ctime;
189     }
190   }
191
192   if (close (path_fd) == -1) {
193     reply_with_perror ("close: %s", path);
194     free (ret->guestfs_int_stat_list_val);
195     free (ret);
196     return NULL;
197   }
198
199   return ret;
200 }