libexplain  1.4.D001
libexplain/buffer/errno/lseek.c
Go to the documentation of this file.
00001 /*
00002  * libexplain - Explain errno values returned by libc functions
00003  * Copyright (C) 2008-2013 Peter Miller
00004  * Written by Peter Miller <pmiller@opensource.org.au>
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU Lesser General Public License as published by
00008  * the Free Software Foundation; either version 3 of the License, or (at
00009  * your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014  * Lesser General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU Lesser General Public License
00017  * along with this program. If not, see <http://www.gnu.org/licenses/>.
00018  */
00019 
00020 #include <libexplain/ac/errno.h>
00021 #include <libexplain/ac/stdio.h> /* for snprintf */
00022 #include <libexplain/ac/sys/stat.h>
00023 #include <libexplain/ac/unistd.h> /* for fpathconf */
00024 
00025 #include <libexplain/buffer/ebadf.h>
00026 #include <libexplain/buffer/einval.h>
00027 #include <libexplain/buffer/enosys.h>
00028 #include <libexplain/buffer/errno/generic.h>
00029 #include <libexplain/buffer/errno/lseek.h>
00030 #include <libexplain/buffer/fildes.h>
00031 #include <libexplain/buffer/file_type.h>
00032 #include <libexplain/buffer/lseek_whence.h>
00033 #include <libexplain/buffer/off_t.h>
00034 #include <libexplain/explanation.h>
00035 
00036 
00037 static void
00038 explain_buffer_errno_lseek_system_call(explain_string_buffer_t *sb,
00039     int errnum, int fildes, off_t offset, int whence)
00040 {
00041     (void)errnum;
00042     explain_string_buffer_puts(sb, "lseek(fildes = ");
00043     explain_buffer_fildes(sb, fildes);
00044     explain_string_buffer_puts(sb, ", offset = ");
00045     explain_buffer_off_t(sb, offset);
00046     explain_string_buffer_puts(sb, ", whence = ");
00047     explain_buffer_lseek_whence(sb, whence);
00048     explain_string_buffer_putc(sb, ')');
00049 }
00050 
00051 
00052 #if defined(SEEK_HOLE) || defined(SEEK_DATA)
00053 
00054 static int
00055 holes_are_supported(int fildes)
00056 {
00057 #ifdef _PC_MIN_HOLE_SIZE
00058     long            result;
00059 
00060     errno = 0;
00061     result = fpathconf(fildes, _PC_MIN_HOLE_SIZE);
00062     if (result == -1 && errno != 0)
00063     {
00064         switch (errno)
00065         {
00066         case EINVAL:
00067         case ENOSYS:
00068             /* holes are not supported */
00069             return 0;
00070 
00071         case EBADF:
00072         default:
00073             /* can't tell */
00074             return -1;
00075         }
00076     }
00077     if (result <= 0)
00078     {
00079         /* holes are not supported */
00080         return 0;
00081     }
00082     /* holes are supported */
00083     return 1;
00084 #else
00085     /* can't tell */
00086     (void)fildes;
00087     return -1;
00088 #endif
00089 }
00090 
00091 #endif
00092 
00093 
00094 void
00095 explain_buffer_errno_lseek_explanation(explain_string_buffer_t *sb,
00096     int errnum, const char *syscall_name, int fildes, off_t offset, int whence)
00097 {
00098     switch (errnum)
00099     {
00100     case EBADF:
00101         explain_buffer_ebadf(sb, fildes, "fildes");
00102         break;
00103 
00104     case EINVAL:
00105         {
00106             long long       current_position;
00107             long long       destination;
00108 
00109             current_position = lseek(fildes, 0, SEEK_CUR);
00110             switch (whence)
00111             {
00112             default:
00113                 explain_string_buffer_puts
00114                 (
00115                     sb,
00116                     /* FIXME: i18n */
00117                     "'whence' is not one of SEEK_SET, SEEK_CUR, SEEK_END"
00118 #ifdef SEEK_HOLE
00119                     ", SEEK_HOLE"
00120 #endif
00121 #ifdef SEEK_DATA
00122                     ", SEEK_DATA"
00123 #endif
00124                 );
00125                 return;
00126 
00127 #ifdef SEEK_HOLE
00128             case SEEK_HOLE:
00129                 if (!holes_are_supported(fildes))
00130                     goto seek_hole_enosys;
00131                 if (offset < 0)
00132                 {
00133                     explain_buffer_einval_too_small(sb, "offset", offset);
00134                     return;
00135                 }
00136                 destination = lseek(fildes, offset, whence);
00137                 offset = 0;
00138                 break;
00139 #endif
00140 
00141 #ifdef SEEK_DATA
00142             case SEEK_DATA:
00143                 if (!holes_are_supported(fildes))
00144                     goto seek_data_enosys;
00145                 if (offset < 0)
00146                 {
00147                     explain_buffer_einval_too_small(sb, "offset", offset);
00148                     return;
00149                 }
00150                 destination = lseek(fildes, offset, whence);
00151                 offset = 0;
00152                 break;
00153 #endif
00154 
00155             case SEEK_SET:
00156                 current_position = 0;
00157                 destination = offset;
00158                 break;
00159 
00160             case SEEK_CUR:
00161                 destination = current_position + offset;
00162                 break;
00163 
00164             case SEEK_END:
00165                 destination = lseek(fildes, 0, SEEK_END);
00166                 if (destination < 0)
00167                 {
00168                     current_position = -1;
00169                     destination = 0;
00170                 }
00171                 else
00172                 {
00173                     current_position = 0;
00174                     destination += offset;
00175                 }
00176                 break;
00177             }
00178 
00179             if (current_position != (off_t)-1)
00180             {
00181                 if (destination < 0)
00182                 {
00183                     explain_string_buffer_puts
00184                     (
00185                         sb,
00186                         /* FIXME: i18n */
00187                         "the resulting file offset would be "
00188                         "negative"
00189                     );
00190                 }
00191                 else
00192                 {
00193                     explain_string_buffer_puts
00194                     (
00195                         sb,
00196                         /* FIXME: i18n */
00197                         "the resulting offset would be beyond "
00198                         "the end of a seekable device"
00199                     );
00200                 }
00201                 explain_string_buffer_printf
00202                 (
00203                     sb,
00204                     " (%lld)",
00205                     (long long)destination
00206                 );
00207                 break;
00208             }
00209 
00210             explain_string_buffer_puts
00211             (
00212                 sb,
00213                 /* FIXME: i18n */
00214                 "the resulting file offset would be negative, "
00215                 "or beyond the end of a seekable device"
00216             );
00217         }
00218         break;
00219 
00220     case ENXIO:
00221 #ifdef SEEK_HOLE
00222         if (whence == SEEK_HOLE)
00223         {
00224             explain_string_buffer_puts
00225             (
00226                 sb,
00227                 /* FIXME: i18n */
00228                 "there is no hole extent beyond the current file position"
00229             );
00230         }
00231 #endif
00232 #ifdef SEEK_DATA
00233         if (whence == SEEK_DATA)
00234         {
00235             explain_string_buffer_puts
00236             (
00237                 sb,
00238                 /* FIXME: i18n */
00239                 "there is no data extent beyond the current file position"
00240             );
00241         }
00242 #endif
00243         goto generic;
00244 
00245     case EOVERFLOW:
00246         explain_string_buffer_puts
00247         (
00248             sb,
00249             /* FIXME: i18n */
00250             "the resulting file offset cannot be represented in an off_t"
00251         );
00252         break;
00253 
00254     case ESPIPE:
00255         {
00256             struct stat     st;
00257 
00258             if (fstat(fildes, &st) == 0)
00259             {
00260                 explain_string_buffer_puts
00261                 (
00262                     sb,
00263                     /* FIXME: i18n */
00264                     "the file descriptor is associated with a "
00265                 );
00266                 explain_buffer_file_type_st(sb, &st);
00267             }
00268             else
00269             {
00270                 explain_string_buffer_puts
00271                 (
00272                     sb,
00273                     /* FIXME: i18n */
00274                     "the file descriptor is associated with a "
00275                     "pipe, socket, or FIFO"
00276                 );
00277             }
00278         }
00279         break;
00280 
00281     case ENOSYS:
00282 #if defined(EOPNOTSUPP) && EOPNOTSUPP != ENOSYS
00283     case EOPNOTSUPP:
00284 #endif
00285 #ifdef SEEK_HOLE
00286         if (whence == SEEK_HOLE && !holes_are_supported(fildes))
00287         {
00288             char            temp[50];
00289 
00290             seek_hole_enosys:
00291             snprintf(temp, sizeof(temp), "%s SEEK_HOLE", syscall_name);
00292             explain_buffer_enosys_fildes(sb, fildes, "fildes", temp);
00293             break;
00294         }
00295 #endif
00296 #ifdef SEEK_DATA
00297         if (whence == SEEK_DATA && !holes_are_supported(fildes))
00298         {
00299             char            temp[50];
00300 
00301             seek_data_enosys:
00302             snprintf(temp, sizeof(temp), "%s SEEK_DATA", syscall_name);
00303             explain_buffer_enosys_fildes(sb, fildes, "fildes", temp);
00304             break;
00305         }
00306 #endif
00307         explain_buffer_enosys_fildes(sb, fildes, "fildes", syscall_name);
00308         break;
00309 
00310     default:
00311         generic:
00312         explain_buffer_errno_generic(sb, errnum, syscall_name);
00313         break;
00314     }
00315 }
00316 
00317 
00318 void
00319 explain_buffer_errno_lseek(explain_string_buffer_t *sb, int errnum,
00320     int fildes, off_t offset, int whence)
00321 {
00322     explain_explanation_t exp;
00323 
00324     explain_explanation_init(&exp, errnum);
00325     explain_buffer_errno_lseek_system_call
00326     (
00327         &exp.system_call_sb,
00328         errnum,
00329         fildes,
00330         offset,
00331         whence
00332     );
00333     explain_buffer_errno_lseek_explanation
00334     (
00335         &exp.explanation_sb,
00336         errnum,
00337         "lseek",
00338         fildes,
00339         offset,
00340         whence
00341     );
00342     explain_explanation_assemble(&exp, sb);
00343 }
00344 
00345 
00346 /* vim: set ts=8 sw=4 et : */