/* $Id$ * Detect media size of given GIOChannel for libcaptive * Copyright (C) 2002 Jan Kratochvil * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; exactly version 2 of June 1991 is required * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include "captive/storage.h" /* self */ #include "../client/giochannel-blind.h" /* for captive_giochannel_blind_get_size() */ #include "../sandbox/client-CaptiveIOChannel.h" /* for captive_io_channel_get_size() */ #include #include #include #include #include /* Do not: #include * for 'BLKGETSIZE64' * * as including any Linux kernel include files is too much incompatible. */ #include /* for 'BLKGETSIZE' */ static guint64 size_blind(GIOChannel *iochannel) { guint64 r; g_return_val_if_fail(iochannel!=NULL,0); if (!captive_giochannel_blind_get_size(iochannel,&r)) return 0; return r; } static guint64 size_sandbox(GIOChannel *iochannel) { guint64 r; g_return_val_if_fail(iochannel!=NULL,0); if (!captive_io_channel_get_size(iochannel,&r)) return 0; return r; } static GIOChannel *iochannel_null; static int iounixchannel_get_fd(GIOChannel *iochannel) { int r; g_return_val_if_fail(iochannel!=NULL,-1); if (!iochannel_null) { int fd; fd=open("/dev/null",O_RDONLY); g_return_val_if_fail(fd!=-1,-1); iochannel_null=g_io_channel_unix_new(fd); g_return_val_if_fail(iochannel_null!=NULL,-1); } if (iochannel->funcs!=iochannel_null->funcs) { /* Not a UNIX file descriptor */ return -1; } /* It is forbidden to callg_io_channel_unix_get_fd() * if you are not sure it is a 'GIOUnixChannel'. */ r=g_io_channel_unix_get_fd(iochannel); g_return_val_if_fail(r!=-1,-1); return r; } static guint64 size_ioctl(GIOChannel *iochannel) { int fd; guint64 r; long r_long; g_return_val_if_fail(iochannel!=NULL,0); if (-1==(fd=iounixchannel_get_fd(iochannel))) return 0; #ifdef BLKGETSIZE64 if (!ioctl(fd,BLKGETSIZE64,&r)) return r; #endif if (ioctl(fd,BLKGETSIZE,&r_long)) return 0; if (r_long<0) return 0; r=((guint64)512)*r_long; return r; } static guint64 size_seek(GIOChannel *iochannel) { int fd; off_t offset_orig,offset; g_return_val_if_fail(iochannel!=NULL,0); /* We may need '_FILE_OFFSET_BITS=64'. * Setting '__USE_FILE_OFFSET64' did not help. * Done by 'AC_SYS_LARGEFILE' of configure.in. */ g_return_val_if_fail(sizeof(offset)==sizeof(guint64),0); if (-1==(fd=iounixchannel_get_fd(iochannel))) return 0; if (-1==(offset_orig=lseek(fd,0,SEEK_CUR))) return 0; g_return_val_if_fail(offset_orig>=0,0); offset=lseek(fd,0,SEEK_END); if (offset_orig!=lseek(fd,offset_orig,SEEK_SET)) g_assert_not_reached(); if (-1==offset) return 0; g_return_val_if_fail(offset>=0,0); return offset; } static guint64 size_read(GIOChannel *iochannel) { gint64 low,high,mid; GIOStatus erriostatus; gchar bufchar; gsize bufchargot; g_return_val_if_fail(iochannel!=NULL,0); /* Default "UTF-8" encoding is not much usable for us */ g_return_val_if_fail(g_io_channel_get_encoding(iochannel)==NULL,0); /* low ==high: low (high) * low+1==high: mid==low; NORMAL: no change: high * low+1==high: mid==low; EOF : high=mid => 'low==high' case */ for (low=0, high= G_MAXINT64; low+1=0); return high; } guint64 captive_giochannel_size(GIOChannel *iochannel) { guint64 r; if ((r=size_blind(iochannel))) return r; if ((r=size_sandbox(iochannel))) return r; if ((r=size_ioctl(iochannel))) return r; if ((r=size_seek(iochannel))) return r; if ((r=size_read(iochannel))) return r; return r; }