File indexing completed on 2024-05-19 03:56:19

0001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
0002 
0003     SPDX-FileCopyrightText: 2010 Mozilla Foundation
0004     SPDX-FileContributor: Taras Glek <tglek@mozilla.com>
0005 
0006     SPDX-License-Identifier: MPL-1.1 OR GPL-2.0-or-later OR LGPL-2.1-or-later
0007 */
0008 
0009 #ifndef POSIX_FALLOCATE_MAC_H
0010 #define POSIX_FALLOCATE_MAC_H
0011 
0012 #include <fcntl.h>
0013 #include <sys/stat.h>
0014 #include <sys/types.h>
0015 #include <unistd.h>
0016 
0017 // created from the OSX-specific code from Mozilla's mozilla::fallocation() function
0018 // of which the licensing information is copied above.
0019 // Adaptation (C) 2015,2016 R.J.V. Bertin
0020 
0021 // From Linux `man posix_fallocate`:
0022 // DESCRIPTION
0023 //        The function posix_fallocate() ensures that disk space is allocated for
0024 //        the file referred to by the descriptor fd for the bytes  in  the  range
0025 //        starting  at  offset  and continuing for len bytes.  After a successful
0026 //        call to posix_fallocate(), subsequent writes to bytes in the  specified
0027 //        range are guaranteed not to fail because of lack of disk space.
0028 //
0029 //        If  the  size  of  the  file  is less than offset+len, then the file is
0030 //        increased to this size; otherwise the file size is left unchanged.
0031 
0032 // From OS X man fcntl:
0033 //      F_PREALLOCATE      Preallocate file storage space. Note: upon success, the space
0034 //                         that is allocated can be the same size or larger than the space
0035 //                         requested.
0036 //      The F_PREALLOCATE command operates on the following structure:
0037 //              typedef struct fstore {
0038 //                  u_int32_t fst_flags;      /* IN: flags word */
0039 //                  int       fst_posmode;    /* IN: indicates offset field */
0040 //                  off_t     fst_offset;     /* IN: start of the region */
0041 //                  off_t     fst_length;     /* IN: size of the region */
0042 //                  off_t     fst_bytesalloc; /* OUT: number of bytes allocated */
0043 //              } fstore_t;
0044 //      The flags (fst_flags) for the F_PREALLOCATE command are as follows:
0045 //            F_ALLOCATECONTIG   Allocate contiguous space.
0046 //            F_ALLOCATEALL      Allocate all requested space or no space at all.
0047 //      The position modes (fst_posmode) for the F_PREALLOCATE command indicate how to use
0048 //      the offset field.  The modes are as follows:
0049 //            F_PEOFPOSMODE   Allocate from the physical end of file.
0050 //            F_VOLPOSMODE    Allocate from the volume offset.
0051 
0052 // From OS X man ftruncate:
0053 // DESCRIPTION
0054 //      ftruncate() and truncate() cause the file named by path, or referenced by fildes, to
0055 //      be truncated (or extended) to length bytes in size. If the file size exceeds length,
0056 //      any extra data is discarded. If the file size is smaller than length, the file
0057 //      extended and filled with zeros to the indicated length.  The ftruncate() form requires
0058 //      the file to be open for writing.
0059 //      Note: ftruncate() and truncate() do not modify the current file offset for any open
0060 //      file descriptions associated with the file.
0061 
0062 static int posix_fallocate(int fd, off_t offset, off_t len)
0063 {
0064     off_t c_test;
0065     int ret;
0066     if (!__builtin_saddll_overflow(offset, len, &c_test)) {
0067         fstore_t store = {F_ALLOCATECONTIG, F_PEOFPOSMODE, 0, offset + len, 0};
0068         // Try to get a continuous chunk of disk space
0069         ret = fcntl(fd, F_PREALLOCATE, &store);
0070         if (ret < 0) {
0071             // OK, perhaps we are too fragmented, allocate non-continuous
0072             store.fst_flags = F_ALLOCATEALL;
0073             ret = fcntl(fd, F_PREALLOCATE, &store);
0074             if (ret < 0) {
0075                 return ret;
0076             }
0077         }
0078         ret = ftruncate(fd, offset + len);
0079     } else {
0080         // offset+len would overflow.
0081         ret = -1;
0082     }
0083     return ret;
0084 }
0085 
0086 #endif