libexplain  1.4.D001
libexplain/buffer/errno/ftruncate.c
Go to the documentation of this file.
00001 /*
00002  * libexplain - Explain errno values returned by libc functions
00003  * Copyright (C) 2008-2011, 2013 Peter Miller
00004  *
00005  * This program is free software; you can redistribute it and/or modify it
00006  * under the terms of the GNU Lesser General Public License as published by
00007  * the Free Software Foundation; either version 3 of the License, or (at
00008  * your option) any later version.
00009  *
00010  * This program is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013  * Lesser General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU Lesser General Public License
00016  * along with this program. If not, see <http://www.gnu.org/licenses/>.
00017  */
00018 
00019 #include <libexplain/ac/errno.h>
00020 #include <libexplain/ac/fcntl.h>
00021 #include <libexplain/ac/sys/stat.h>
00022 #include <libexplain/ac/unistd.h>
00023 
00024 #include <libexplain/buffer/ebadf.h>
00025 #include <libexplain/buffer/efbig.h>
00026 #include <libexplain/buffer/eintr.h>
00027 #include <libexplain/buffer/eio.h>
00028 #include <libexplain/buffer/erofs.h>
00029 #include <libexplain/buffer/errno/ftruncate.h>
00030 #include <libexplain/buffer/errno/generic.h>
00031 #include <libexplain/buffer/etxtbsy.h>
00032 #include <libexplain/buffer/fildes_to_pathname.h>
00033 #include <libexplain/buffer/fildes_not_open_for_writing.h>
00034 #include <libexplain/buffer/file_type.h>
00035 #include <libexplain/buffer/mount_point.h>
00036 #include <libexplain/buffer/off_t.h>
00037 #include <libexplain/buffer/open_flags.h>
00038 #include <libexplain/explanation.h>
00039 
00040 
00041 static void
00042 explain_buffer_errno_ftruncate_system_call(explain_string_buffer_t *sb,
00043     int errnum, int fildes, off_t length)
00044 {
00045     (void)errnum;
00046     explain_string_buffer_printf(sb, "ftruncate(fildes = %d", fildes);
00047     explain_buffer_fildes_to_pathname(sb, fildes);
00048     explain_string_buffer_puts(sb, ", length = ");
00049     explain_buffer_off_t(sb, length);
00050     explain_string_buffer_putc(sb, ')');
00051 }
00052 
00053 
00054 static void
00055 explain_buffer_errno_ftruncate_explanation(explain_string_buffer_t *sb,
00056     int errnum, int fildes, off_t length)
00057 {
00058     switch (errnum)
00059     {
00060     case EACCES:
00061     case EBADF:
00062         if (explain_buffer_fildes_not_open_for_writing(sb, fildes, "fildes"))
00063             explain_buffer_ebadf(sb, fildes, "fildes");
00064         break;
00065 
00066     case EFBIG:
00067         explain_buffer_efbig_fildes(sb, fildes, length, "length");
00068         break;
00069 
00070     case EINTR:
00071         explain_buffer_eintr(sb, "ftruncate");
00072         break;
00073 
00074     case EINVAL:
00075         if (length < 0)
00076         {
00077             /* FIXME: i18n */
00078             explain_string_buffer_puts(sb, "'length' is negative");
00079         }
00080         else
00081         {
00082 #ifdef _PC_FILESIZEBITS
00083             long            file_size_bits;
00084 
00085             /*
00086              * FIXME: also use getrlimit(RLIMIT_FSIZE)
00087              *
00088              * RLIMIT_FSIZE
00089              *     The maximum size of files that the process may
00090              *     create.  Attempts to extend a file beyond this limit
00091              *     result in delivery of a SIGXFSZ signal.  By default,
00092              *     this signal terminates a process, but a process can
00093              *     catch this signal instead, in which case the relevant
00094              *     system call (e.g., write(2), truncate(2)) fails with
00095              *     the error EFBIG.
00096              */
00097             file_size_bits = fpathconf(fildes, _PC_FILESIZEBITS);
00098             if
00099             (
00100                 file_size_bits > 0
00101             &&
00102                 (size_t)file_size_bits < 8 * sizeof(off_t)
00103             &&
00104                 length > (1LL << file_size_bits)
00105             )
00106             {
00107                 explain_string_buffer_printf
00108                 (
00109                     sb,
00110                     /* FIXME: i18n */
00111                     "'length' is larger than the maximum file size (2 ** %ld)",
00112                     file_size_bits
00113                 );
00114             }
00115             else
00116 #endif
00117             {
00118                 int             flags;
00119 
00120                 /* FIXME: i18n */
00121                 flags = fcntl(fildes, F_GETFL);
00122                 if (flags >= 0 && (flags & O_ACCMODE) == O_RDONLY)
00123                 {
00124                     explain_string_buffer_puts
00125                     (
00126                         sb,
00127                         "the file is not open for writing ("
00128                     );
00129                     explain_buffer_open_flags(sb, flags);
00130                     explain_string_buffer_putc(sb, ')');
00131                 }
00132                 else
00133                 {
00134                     struct stat     st;
00135 
00136                     if (fstat(fildes, &st) >= 0 && !S_ISREG(st.st_mode))
00137                     {
00138                         explain_string_buffer_puts
00139                         (
00140                             sb,
00141                             "fildes refers to a "
00142                         );
00143                         explain_buffer_file_type_st(sb, &st);
00144                         explain_string_buffer_puts
00145                         (
00146                             sb,
00147                             ", it is only possible to truncate a "
00148                         );
00149                         explain_buffer_file_type(sb, S_IFREG);
00150                     }
00151                     else
00152                     {
00153                         explain_string_buffer_puts
00154                         (
00155                             sb,
00156                             "the file is not open for writing; or, the file is "
00157                             "not a "
00158                         );
00159                         explain_buffer_file_type(sb, S_IFREG);
00160                     }
00161                 }
00162             }
00163         }
00164         break;
00165 
00166     case EIO:
00167         explain_buffer_eio_fildes(sb, fildes);
00168         break;
00169 
00170     case EISDIR:
00171         /* FIXME: i18n */
00172         explain_string_buffer_puts
00173         (
00174             sb,
00175             "fildes refers to a "
00176         );
00177         explain_buffer_file_type(sb, S_IFDIR);
00178         explain_string_buffer_puts
00179         (
00180             sb,
00181             ", it is only possible to truncate a "
00182         );
00183         explain_buffer_file_type(sb, S_IFREG);
00184         break;
00185 
00186     case EPERM:
00187         explain_string_buffer_puts
00188         (
00189             sb,
00190             /* FIXME: i18n */
00191             "the underlying file system does not support extending a "
00192             "file beyond its current size"
00193         );
00194         explain_buffer_mount_point_fd(sb, fildes);
00195         break;
00196 
00197     case EROFS:
00198         explain_buffer_erofs_fildes(sb, fildes, "fildes");
00199         break;
00200 
00201     case ETXTBSY:
00202         explain_buffer_etxtbsy_fildes(sb, fildes);
00203         break;
00204 
00205     default:
00206         explain_buffer_errno_generic(sb, errnum, "ftruncate");
00207         break;
00208     }
00209 }
00210 
00211 
00212 void
00213 explain_buffer_errno_ftruncate(explain_string_buffer_t *sb, int errnum,
00214     int fildes, off_t length)
00215 {
00216     explain_explanation_t exp;
00217 
00218     explain_explanation_init(&exp, errnum);
00219     explain_buffer_errno_ftruncate_system_call
00220     (
00221         &exp.system_call_sb,
00222         errnum,
00223         fildes,
00224         length
00225     );
00226     explain_buffer_errno_ftruncate_explanation
00227     (
00228         &exp.explanation_sb,
00229         errnum,
00230         fildes,
00231         length
00232     );
00233     explain_explanation_assemble(&exp, sb);
00234 }
00235 
00236 
00237 /* vim: set ts=8 sw=4 et : */