daemon: debug segv correct use of dereferencing NULL.
[libguestfs.git] / daemon / statvfs.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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17  */
18
19 #include <config.h>
20
21 #ifdef HAVE_WINDOWS_H
22 #include <windows.h>
23 #endif
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <sys/types.h>
29 #include <fcntl.h>
30 #include <unistd.h>
31 #include <stdint.h>
32
33 #ifdef HAVE_SYS_STATVFS_H
34 #include <sys/statvfs.h>
35 #endif
36
37 #include <fsusage.h>
38
39 #include "guestfs_protocol.h"
40 #include "daemon.h"
41 #include "actions.h"
42
43 guestfs_int_statvfs *
44 do_statvfs (const char *path)
45 {
46 #ifdef HAVE_STATVFS
47   int r;
48   guestfs_int_statvfs *ret;
49   struct statvfs statbuf;
50
51   CHROOT_IN;
52   r = statvfs (path, &statbuf);
53   CHROOT_OUT;
54
55   if (r == -1) {
56     reply_with_perror ("statvfs");
57     return NULL;
58   }
59
60   ret = malloc (sizeof *ret);
61   if (ret == NULL) {
62     reply_with_perror ("malloc");
63     return NULL;
64   }
65
66   ret->bsize = statbuf.f_bsize;
67   ret->frsize = statbuf.f_frsize;
68   ret->blocks = statbuf.f_blocks;
69   ret->bfree = statbuf.f_bfree;
70   ret->bavail = statbuf.f_bavail;
71   ret->files = statbuf.f_files;
72   ret->ffree = statbuf.f_ffree;
73   ret->favail = statbuf.f_favail;
74   ret->fsid = statbuf.f_fsid;
75   ret->flag = statbuf.f_flag;
76   ret->namemax = statbuf.f_namemax;
77
78   return ret;
79
80 #else /* !HAVE_STATVFS */
81 #  if WIN32
82
83   char *disk;
84   guestfs_int_statvfs *ret;
85   ULONGLONG free_bytes_available; /* for user - similar to bavail */
86   ULONGLONG total_number_of_bytes;
87   ULONGLONG total_number_of_free_bytes; /* for everyone - bfree */
88
89   disk = sysroot_path (path);
90   if (!disk) {
91     reply_with_perror ("malloc");
92     return NULL;
93   }
94
95   if (!GetDiskFreeSpaceEx (disk,
96                            (PULARGE_INTEGER) &free_bytes_available,
97                            (PULARGE_INTEGER) &total_number_of_bytes,
98                            (PULARGE_INTEGER) &total_number_of_free_bytes)) {
99     reply_with_perror ("GetDiskFreeSpaceEx");
100     free (disk);
101     return NULL;
102   }
103   free (disk);
104
105   ret = malloc (sizeof *ret);
106   if (ret == NULL) {
107     reply_with_perror ("malloc");
108     return NULL;
109   }
110
111   /* XXX I couldn't determine how to get block size.  MSDN has a
112    * unhelpful hard-coded list here:
113    *   http://support.microsoft.com/kb/140365
114    * but this depends on the filesystem type, the size of the disk and
115    * the version of Windows.  So this code assumes the disk is NTFS
116    * and the version of Windows is >= Win2K.
117    */
118   if (total_number_of_bytes < UINT64_C(16) * 1024 * 1024 * 1024 * 1024)
119     ret->bsize = 4096;
120   else if (total_number_of_bytes < UINT64_C(32) * 1024 * 1024 * 1024 * 1024)
121     ret->bsize = 8192;
122   else if (total_number_of_bytes < UINT64_C(64) * 1024 * 1024 * 1024 * 1024)
123     ret->bsize = 16384;
124   else if (total_number_of_bytes < UINT64_C(128) * 1024 * 1024 * 1024 * 1024)
125     ret->bsize = 32768;
126   else
127     ret->bsize = 65536;
128
129   /* As with stat, -1 indicates a field is not known. */
130   ret->frsize = ret->bsize;
131   ret->blocks = total_number_of_bytes / ret->bsize;
132   ret->bfree = total_number_of_free_bytes / ret->bsize;
133   ret->bavail = free_bytes_available / ret->bsize;
134   ret->files = -1;
135   ret->ffree = -1;
136   ret->favail = -1;
137   ret->fsid = -1;
138   ret->flag = -1;
139   ret->namemax = FILENAME_MAX;
140
141   return ret;
142
143 #  else /* !WIN32 */
144
145   char *disk;
146   int r;
147   guestfs_int_statvfs *ret;
148   struct fs_usage fsu;
149
150   disk = sysroot_path (path);
151   if (!disk) {
152     reply_with_perror ("malloc");
153     return NULL;
154   }
155
156   r = get_fs_usage (disk, disk, &fsu);
157   free (disk);
158
159   if (r == -1) {
160     reply_with_perror ("get_fs_usage: %s", path);
161     return NULL;
162   }
163
164   ret = malloc (sizeof *ret);
165   if (ret == NULL) {
166     reply_with_perror ("malloc");
167     return NULL;
168   }
169
170   /* As with stat, -1 indicates a field is not known. */
171   ret->bsize = fsu.f_bsize;
172   ret->frsize = -1;
173   ret->blocks = fsu.f_blocks;
174   ret->bfree = fsu.f_bfree;
175   ret->bavail = fsu.f_bavail;
176   ret->files = fsu.f_files;
177   ret->ffree = fsu.f_ffree;
178   ret->favail = -1;
179   ret->fsid = -1;
180   ret->flag = -1;
181   ret->namemax = -1;
182
183   return ret;
184
185 #  endif /* !WIN32 */
186 #endif /* !HAVE_STATVFS */
187 }