2 * Detect media size of given GIOChannel for libcaptive
3 * Copyright (C) 2002 Jan Kratochvil <project-captive@jankratochvil.net>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; exactly version 2 of June 1991 is required
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.
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "captive/storage.h" /* self */
23 #include "../client/giochannel-blind.h" /* for captive_giochannel_blind_get_size() */
24 #include "../client/giochannel-subrange.h" /* for captive_giochannel_subrange_get_size() */
25 #include "../sandbox/client-CaptiveIOChannel.h" /* for captive_io_channel_get_size() */
26 #include <glib/gmessages.h>
27 #include <glib/gtypes.h>
29 #include <sys/ioctl.h>
31 /* Do not: #include <linux/fs.h> * for 'BLKGETSIZE64' *
32 * as including any Linux kernel include files is too much incompatible.
34 #include <sys/mount.h> /* for 'BLKGETSIZE' */
35 #include "iounixchannel.h"
38 static guint64 size_subrange(GIOChannel *iochannel)
42 g_return_val_if_fail(iochannel!=NULL,0);
44 if (!captive_giochannel_subrange_get_size(iochannel,&r))
51 static guint64 size_blind(GIOChannel *iochannel)
55 g_return_val_if_fail(iochannel!=NULL,0);
57 if (!captive_giochannel_blind_get_size(iochannel,&r))
64 static guint64 size_sandbox(GIOChannel *iochannel)
68 g_return_val_if_fail(iochannel!=NULL,0);
70 if (!captive_io_channel_get_size(iochannel,&r))
77 guint64 captive_giochannel_size_ioctl(GIOChannel *iochannel)
83 g_return_val_if_fail(iochannel!=NULL,0);
85 if (-1==(fd=captive_iounixchannel_get_fd(iochannel)))
89 if (!ioctl(fd,BLKGETSIZE64,&r))
92 if (ioctl(fd,BLKGETSIZE,&r_long))
96 r=((guint64)512)*r_long;
102 static guint64 size_seek(GIOChannel *iochannel)
105 off_t offset_orig,offset;
107 g_return_val_if_fail(iochannel!=NULL,0);
109 /* We may need '_FILE_OFFSET_BITS=64'.
110 * Setting '__USE_FILE_OFFSET64' did not help.
111 * Done by 'AC_SYS_LARGEFILE' of configure.ac.
113 g_return_val_if_fail(sizeof(offset)==sizeof(guint64),0);
115 if (-1==(fd=captive_iounixchannel_get_fd(iochannel)))
118 if (-1==(offset_orig=lseek(fd,0,SEEK_CUR)))
120 g_return_val_if_fail(offset_orig>=0,0);
121 offset=lseek(fd,0,SEEK_END);
122 if (offset_orig!=lseek(fd,offset_orig,SEEK_SET))
123 g_assert_not_reached();
127 g_return_val_if_fail(offset>=0,0);
134 static guint64 size_read(GIOChannel *iochannel)
137 GIOStatus erriostatus;
141 g_return_val_if_fail(iochannel!=NULL,0);
142 /* Default "UTF-8" encoding is not much usable for us */
143 g_return_val_if_fail(g_io_channel_get_encoding(iochannel)==NULL,0);
145 /* low ==high: low (high)
146 * low+1==high: mid==low; NORMAL: no change: high
147 * low+1==high: mid==low; EOF : high=mid => 'low==high' case
153 mid=low+(high-low)/2; /* beware of 'gint64' overflow! */
155 erriostatus=g_io_channel_seek_position(iochannel,mid,G_SEEK_SET,
157 /* During seek in block device such as on URL file:///dev/hda1#captive-fastfat.sys-ro:/
158 * we will do llseek(2) on "/dev/hda1" device from captive_giochannel_size().
159 * Although we are allowed to seek behind EOF on regular files
160 * at least linux-kernel-2.4.19-ac4/fs/block_dev.c/block_llseek() will give
161 * EINVAL on seek behind EOF therefore it must be accepted without complaints by us.
163 if (erriostatus!=G_IO_STATUS_NORMAL) {
164 erriostatus=G_IO_STATUS_EOF;
168 g_assert(sizeof(bufchar)==1);
169 erriostatus=g_io_channel_read_chars(iochannel,
171 sizeof(bufchar), /* count */
172 &bufchargot, /* bytes_read */
174 /* During read on the end boundary of Linux kernel block device we will
175 * get GNOME_VFS_ERROR_IO at least from linux-kernel-2.4.19-ac4
176 * which will get mapped to G_IO_STATUS_ERROR by captive_gnomevfs_giognomevfs_io_read().
179 || erriostatus==G_IO_STATUS_NORMAL
180 || erriostatus==G_IO_STATUS_EOF
181 || erriostatus==G_IO_STATUS_ERROR);
183 || (erriostatus==G_IO_STATUS_NORMAL && bufchargot==1)
184 || (erriostatus==G_IO_STATUS_EOF && bufchargot==0)
185 || (erriostatus==G_IO_STATUS_ERROR && bufchargot==0));
188 if (erriostatus==G_IO_STATUS_NORMAL)
199 guint64 captive_giochannel_size(GIOChannel *iochannel)
203 if ((r=size_subrange(iochannel)))
205 if ((r=size_blind(iochannel)))
207 if ((r=size_sandbox(iochannel)))
209 if ((r=captive_giochannel_size_ioctl(iochannel)))
211 if ((r=size_seek(iochannel)))
213 if ((r=size_read(iochannel)))