1 /****************************************************************************
2 * fs/vfs/fs_truncate.c
3 *
4 * Copyright (C) 2018 Gregory Nutt. All rights reserved.
5 * Author: Gregory Nutt <gnutt@nuttx.org>
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
16 * distribution.
17 * 3. Neither the name NuttX nor the names of its contributors may be
18 * used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
28 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 * POSSIBILITY OF SUCH DAMAGE.
33 *
34 ****************************************************************************/
35
36 /****************************************************************************
37 * Included Files
38 ****************************************************************************/
39
40 #include "vfs_config.h"
41 #include "sys/types.h"
42 #include "unistd.h"
43 #include "fcntl.h"
44 #include "sched.h"
45 #include "assert.h"
46 #include "errno.h"
47
48 #include "vnode.h"
49
50 /****************************************************************************
51 * Name: file_truncate
52 *
53 * Description:
54 * Equivalent to the standard ftruncate() function except that is accepts
55 * a struct file instance instead of a file descriptor and it does not set
56 * the errno variable.
57 *
58 ****************************************************************************/
file_truncate(struct file * filep,off_t length)59 static int file_truncate(struct file *filep, off_t length)
60 {
61 struct Vnode *vnode = NULL;
62 int ret;
63 int err;
64
65 /* Was this file opened for write access? */
66
67 if (((unsigned int)(filep->f_oflags) & O_ACCMODE) == O_RDONLY)
68 {
69 err = EACCES;
70 goto errout;
71 }
72
73 /* Is this vnode a registered mountpoint? Does it support the
74 * truncate operations may be relevant to device drivers but only
75 * the mountpoint operations vtable contains a truncate method.
76 */
77
78 vnode = filep->f_vnode;
79 if (!vnode || !vnode->vop || !vnode->vop->Truncate)
80 {
81 err = ENOSYS;
82 goto errout;
83 }
84
85 /* Does the file system support the truncate method? It should if it is
86 * a write-able file system.
87 */
88
89 ret = vnode->vop->Truncate(vnode, length);
90 if (ret < 0)
91 {
92 err = -ret;
93 goto errout;
94 }
95
96 return ret;
97
98 errout:
99 set_errno(err);
100 return VFS_ERROR;
101 }
102
103 /****************************************************************************
104 * Name: ftruncate
105 *
106 * Description:
107 * The ftruncate() function causes the regular file referenced by fd to
108 * have a size of length bytes.
109 *
110 * If the file previously was larger than length, the extra data is
111 * discarded. If it was previously shorter than length, it is unspecified
112 * whether the file is changed or its size increased. If the file is
113 * extended, the extended area appears as if it were zero-filled. If fd
114 * references a shared memory object, ftruncate() sets the size of the
115 * shared memory object to length. If the file is not a regular file or
116 * a shared memory object, the result is unspecified.
117
118 * With ftruncate(), the file must be open for writing; for truncate(),
119 * the process must have write permission for the file.
120 *
121 * ftruncate() does not modify the file offset for any open file
122 * descriptions associated with the file.
123 *
124 * Input Parameters:
125 * fd - A reference to an open, regular file or shared memory object
126 * to be truncated.
127 * length - The new length of the file or shared memory object.
128 *
129 * Returned Value:
130 * On success, 0.
131 * On error, -1 is returned, and errno is set appro-priately:
132 *
133 *
134 ****************************************************************************/
135
ftruncate(int fd,off_t length)136 int ftruncate(int fd, off_t length)
137 {
138 #if CONFIG_NFILE_DESCRIPTORS > 0
139 struct file *filep = NULL;
140 #endif
141
142 /* Did we get a valid file descriptor? */
143
144 #if CONFIG_NFILE_DESCRIPTORS > 0
145 if ((unsigned int)fd >= CONFIG_NFILE_DESCRIPTORS)
146 #endif
147 {
148 set_errno(EBADF);
149 return VFS_ERROR;
150 }
151
152 #if CONFIG_NFILE_DESCRIPTORS > 0
153 /* The descriptor is in the right range to be a file descriptor... write
154 * to the file.
155 */
156
157 int ret = fs_getfilep(fd, &filep);
158 if (ret < 0)
159 {
160 /* The errno value has already been set */
161
162 return VFS_ERROR;
163 }
164
165 if (filep->f_oflags & O_DIRECTORY)
166 {
167 set_errno(EBADF);
168 return VFS_ERROR;
169 }
170
171 /* Perform the truncate operation using the file descriptor as an index */
172
173 return file_truncate(filep, length);
174 #endif
175 }
176
truncate(const char * path,off_t length)177 int truncate(const char *path, off_t length)
178 {
179 int fd;
180 int ret;
181
182 fd = open(path, O_RDWR);
183 if (fd == VFS_ERROR)
184 {
185 /* The errno value has already been set */
186 return VFS_ERROR;
187 }
188
189 ret = ftruncate(fd, length);
190 close(fd);
191
192 return ret;
193 }
194