1 /****************************************************************************
2 * fs/vfs/fs_truncate.c
3 *
4 * Licensed to the Apache Software Foundation (ASF) under one or more
5 * contributor license agreements. See the NOTICE file distributed with
6 * this work for additional information regarding copyright ownership. The
7 * ASF licenses this file to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance with the
9 * License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
16 * License for the specific language governing permissions and limitations
17 * under the License.
18 *
19 ****************************************************************************/
20
21 /****************************************************************************
22 * Included Files
23 ****************************************************************************/
24
25 #include "vfs_config.h"
26 #include "sys/types.h"
27 #include "unistd.h"
28 #include "fcntl.h"
29 #include "sched.h"
30 #include "assert.h"
31 #include "errno.h"
32
33 #include "vnode.h"
34
35 /****************************************************************************
36 * Name: file_truncate
37 *
38 * Description:
39 * Equivalent to the standard ftruncate() function except that is accepts
40 * a struct file instance instead of a file descriptor and it does not set
41 * the errno variable.
42 *
43 ****************************************************************************/
file_truncate(struct file * filep,off_t length)44 static int file_truncate(struct file *filep, off_t length)
45 {
46 struct Vnode *vnode = NULL;
47 int ret;
48 int err;
49
50 /* Was this file opened for write access? */
51
52 if (((unsigned int)(filep->f_oflags) & O_ACCMODE) == O_RDONLY)
53 {
54 err = EACCES;
55 goto errout;
56 }
57
58 /* Is this vnode a registered mountpoint? Does it support the
59 * truncate operations may be relevant to device drivers but only
60 * the mountpoint operations vtable contains a truncate method.
61 */
62
63 vnode = filep->f_vnode;
64 if (!vnode || !vnode->vop || !vnode->vop->Truncate)
65 {
66 err = ENOSYS;
67 goto errout;
68 }
69
70 /* Does the file system support the truncate method? It should if it is
71 * a write-able file system.
72 */
73
74 ret = vnode->vop->Truncate(vnode, length);
75 if (ret < 0)
76 {
77 err = -ret;
78 goto errout;
79 }
80
81 return ret;
82
83 errout:
84 set_errno(err);
85 return VFS_ERROR;
86 }
87
88 /****************************************************************************
89 * Name: ftruncate
90 *
91 * Description:
92 * The ftruncate() function causes the regular file referenced by fd to
93 * have a size of length bytes.
94 *
95 * If the file previously was larger than length, the extra data is
96 * discarded. If it was previously shorter than length, it is unspecified
97 * whether the file is changed or its size increased. If the file is
98 * extended, the extended area appears as if it were zero-filled. If fd
99 * references a shared memory object, ftruncate() sets the size of the
100 * shared memory object to length. If the file is not a regular file or
101 * a shared memory object, the result is unspecified.
102
103 * With ftruncate(), the file must be open for writing; for truncate(),
104 * the process must have write permission for the file.
105 *
106 * ftruncate() does not modify the file offset for any open file
107 * descriptions associated with the file.
108 *
109 * Input Parameters:
110 * fd - A reference to an open, regular file or shared memory object
111 * to be truncated.
112 * length - The new length of the file or shared memory object.
113 *
114 * Returned Value:
115 * On success, 0.
116 * On error, -1 is returned, and errno is set appro-priately:
117 *
118 *
119 ****************************************************************************/
120
ftruncate(int fd,off_t length)121 int ftruncate(int fd, off_t length)
122 {
123 #if CONFIG_NFILE_DESCRIPTORS > 0
124 struct file *filep = NULL;
125 #endif
126
127 /* Did we get a valid file descriptor? */
128
129 #if CONFIG_NFILE_DESCRIPTORS > 0
130 if ((unsigned int)fd >= CONFIG_NFILE_DESCRIPTORS)
131 #endif
132 {
133 set_errno(EBADF);
134 return VFS_ERROR;
135 }
136
137 #if CONFIG_NFILE_DESCRIPTORS > 0
138 /* The descriptor is in the right range to be a file descriptor... write
139 * to the file.
140 */
141
142 int ret = fs_getfilep(fd, &filep);
143 if (ret < 0)
144 {
145 /* The errno value has already been set */
146
147 return VFS_ERROR;
148 }
149
150 if (filep->f_oflags & O_DIRECTORY)
151 {
152 set_errno(EBADF);
153 return VFS_ERROR;
154 }
155
156 /* Perform the truncate operation using the file descriptor as an index */
157
158 return file_truncate(filep, length);
159 #endif
160 }
161
truncate(const char * path,off_t length)162 int truncate(const char *path, off_t length)
163 {
164 int fd;
165 int ret;
166
167 fd = open(path, O_RDWR);
168 if (fd == VFS_ERROR)
169 {
170 /* The errno value has already been set */
171 return VFS_ERROR;
172 }
173
174 ret = ftruncate(fd, length);
175 close(fd);
176
177 return ret;
178 }
179