.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * linux/fs/adfs/inode.c |
---|
3 | 4 | * |
---|
4 | 5 | * Copyright (C) 1997-1999 Russell King |
---|
5 | | - * |
---|
6 | | - * This program is free software; you can redistribute it and/or modify |
---|
7 | | - * it under the terms of the GNU General Public License version 2 as |
---|
8 | | - * published by the Free Software Foundation. |
---|
9 | 6 | */ |
---|
10 | 7 | #include <linux/buffer_head.h> |
---|
11 | 8 | #include <linux/writeback.h> |
---|
.. | .. |
---|
23 | 20 | if (block >= inode->i_blocks) |
---|
24 | 21 | goto abort_toobig; |
---|
25 | 22 | |
---|
26 | | - block = __adfs_block_map(inode->i_sb, inode->i_ino, block); |
---|
| 23 | + block = __adfs_block_map(inode->i_sb, ADFS_I(inode)->indaddr, |
---|
| 24 | + block); |
---|
27 | 25 | if (block) |
---|
28 | 26 | map_bh(bh, inode->i_sb, block); |
---|
29 | 27 | return 0; |
---|
.. | .. |
---|
97 | 95 | return S_IFDIR | S_IXUGO | mode; |
---|
98 | 96 | } |
---|
99 | 97 | |
---|
100 | | - switch (ADFS_I(inode)->filetype) { |
---|
| 98 | + switch (adfs_filetype(ADFS_I(inode)->loadaddr)) { |
---|
101 | 99 | case 0xfc0: /* LinkFS */ |
---|
102 | 100 | return S_IFLNK|S_IRWXUGO; |
---|
103 | 101 | |
---|
.. | .. |
---|
129 | 127 | * Convert Linux permission to ADFS attribute. We try to do the reverse |
---|
130 | 128 | * of atts2mode, but there is not a 1:1 translation. |
---|
131 | 129 | */ |
---|
132 | | -static int |
---|
133 | | -adfs_mode2atts(struct super_block *sb, struct inode *inode) |
---|
| 130 | +static int adfs_mode2atts(struct super_block *sb, struct inode *inode, |
---|
| 131 | + umode_t ia_mode) |
---|
134 | 132 | { |
---|
| 133 | + struct adfs_sb_info *asb = ADFS_SB(sb); |
---|
135 | 134 | umode_t mode; |
---|
136 | 135 | int attr; |
---|
137 | | - struct adfs_sb_info *asb = ADFS_SB(sb); |
---|
138 | 136 | |
---|
139 | 137 | /* FIXME: should we be able to alter a link? */ |
---|
140 | 138 | if (S_ISLNK(inode->i_mode)) |
---|
141 | 139 | return ADFS_I(inode)->attr; |
---|
142 | 140 | |
---|
| 141 | + /* Directories do not have read/write permissions on the media */ |
---|
143 | 142 | if (S_ISDIR(inode->i_mode)) |
---|
144 | | - attr = ADFS_NDA_DIRECTORY; |
---|
145 | | - else |
---|
146 | | - attr = 0; |
---|
| 143 | + return ADFS_NDA_DIRECTORY; |
---|
147 | 144 | |
---|
148 | | - mode = inode->i_mode & asb->s_owner_mask; |
---|
| 145 | + attr = 0; |
---|
| 146 | + mode = ia_mode & asb->s_owner_mask; |
---|
149 | 147 | if (mode & S_IRUGO) |
---|
150 | 148 | attr |= ADFS_NDA_OWNER_READ; |
---|
151 | 149 | if (mode & S_IWUGO) |
---|
152 | 150 | attr |= ADFS_NDA_OWNER_WRITE; |
---|
153 | 151 | |
---|
154 | | - mode = inode->i_mode & asb->s_other_mask; |
---|
| 152 | + mode = ia_mode & asb->s_other_mask; |
---|
155 | 153 | mode &= ~asb->s_owner_mask; |
---|
156 | 154 | if (mode & S_IRUGO) |
---|
157 | 155 | attr |= ADFS_NDA_PUBLIC_READ; |
---|
.. | .. |
---|
160 | 158 | |
---|
161 | 159 | return attr; |
---|
162 | 160 | } |
---|
| 161 | + |
---|
| 162 | +static const s64 nsec_unix_epoch_diff_risc_os_epoch = 2208988800000000000LL; |
---|
163 | 163 | |
---|
164 | 164 | /* |
---|
165 | 165 | * Convert an ADFS time to Unix time. ADFS has a 40-bit centi-second time |
---|
.. | .. |
---|
173 | 173 | /* 01 Jan 1970 00:00:00 (Unix epoch) as nanoseconds since |
---|
174 | 174 | * 01 Jan 1900 00:00:00 (RISC OS epoch) |
---|
175 | 175 | */ |
---|
176 | | - static const s64 nsec_unix_epoch_diff_risc_os_epoch = |
---|
177 | | - 2208988800000000000LL; |
---|
178 | 176 | s64 nsec; |
---|
179 | 177 | |
---|
180 | | - if (ADFS_I(inode)->stamped == 0) |
---|
| 178 | + if (!adfs_inode_is_stamped(inode)) |
---|
181 | 179 | goto cur_time; |
---|
182 | 180 | |
---|
183 | 181 | high = ADFS_I(inode)->loadaddr & 0xFF; /* top 8 bits of timestamp */ |
---|
.. | .. |
---|
207 | 205 | return; |
---|
208 | 206 | } |
---|
209 | 207 | |
---|
210 | | -/* |
---|
211 | | - * Convert an Unix time to ADFS time. We only do this if the entry has a |
---|
212 | | - * time/date stamp already. |
---|
213 | | - */ |
---|
214 | | -static void |
---|
215 | | -adfs_unix2adfs_time(struct inode *inode, unsigned int secs) |
---|
| 208 | +/* Convert an Unix time to ADFS time for an entry that is already stamped. */ |
---|
| 209 | +static void adfs_unix2adfs_time(struct inode *inode, |
---|
| 210 | + const struct timespec64 *ts) |
---|
216 | 211 | { |
---|
217 | | - unsigned int high, low; |
---|
| 212 | + s64 cs, nsec = timespec64_to_ns(ts); |
---|
218 | 213 | |
---|
219 | | - if (ADFS_I(inode)->stamped) { |
---|
220 | | - /* convert 32-bit seconds to 40-bit centi-seconds */ |
---|
221 | | - low = (secs & 255) * 100; |
---|
222 | | - high = (secs / 256) * 100 + (low >> 8) + 0x336e996a; |
---|
| 214 | + /* convert from Unix to RISC OS epoch */ |
---|
| 215 | + nsec += nsec_unix_epoch_diff_risc_os_epoch; |
---|
223 | 216 | |
---|
224 | | - ADFS_I(inode)->loadaddr = (high >> 24) | |
---|
225 | | - (ADFS_I(inode)->loadaddr & ~0xff); |
---|
226 | | - ADFS_I(inode)->execaddr = (low & 255) | (high << 8); |
---|
227 | | - } |
---|
| 217 | + /* convert from nanoseconds to centiseconds */ |
---|
| 218 | + cs = div_s64(nsec, 10000000); |
---|
| 219 | + |
---|
| 220 | + cs = clamp_t(s64, cs, 0, 0xffffffffff); |
---|
| 221 | + |
---|
| 222 | + ADFS_I(inode)->loadaddr &= ~0xff; |
---|
| 223 | + ADFS_I(inode)->loadaddr |= (cs >> 32) & 0xff; |
---|
| 224 | + ADFS_I(inode)->execaddr = cs; |
---|
228 | 225 | } |
---|
229 | 226 | |
---|
230 | 227 | /* |
---|
.. | .. |
---|
250 | 247 | |
---|
251 | 248 | inode->i_uid = ADFS_SB(sb)->s_uid; |
---|
252 | 249 | inode->i_gid = ADFS_SB(sb)->s_gid; |
---|
253 | | - inode->i_ino = obj->file_id; |
---|
| 250 | + inode->i_ino = obj->indaddr; |
---|
254 | 251 | inode->i_size = obj->size; |
---|
255 | 252 | set_nlink(inode, 2); |
---|
256 | 253 | inode->i_blocks = (inode->i_size + sb->s_blocksize - 1) >> |
---|
.. | .. |
---|
263 | 260 | * for cross-directory renames. |
---|
264 | 261 | */ |
---|
265 | 262 | ADFS_I(inode)->parent_id = obj->parent_id; |
---|
| 263 | + ADFS_I(inode)->indaddr = obj->indaddr; |
---|
266 | 264 | ADFS_I(inode)->loadaddr = obj->loadaddr; |
---|
267 | 265 | ADFS_I(inode)->execaddr = obj->execaddr; |
---|
268 | 266 | ADFS_I(inode)->attr = obj->attr; |
---|
269 | | - ADFS_I(inode)->filetype = obj->filetype; |
---|
270 | | - ADFS_I(inode)->stamped = ((obj->loadaddr & 0xfff00000) == 0xfff00000); |
---|
271 | 267 | |
---|
272 | 268 | inode->i_mode = adfs_atts2mode(sb, inode); |
---|
273 | 269 | adfs_adfs2unix_time(&inode->i_mtime, inode); |
---|
.. | .. |
---|
320 | 316 | if (ia_valid & ATTR_SIZE) |
---|
321 | 317 | truncate_setsize(inode, attr->ia_size); |
---|
322 | 318 | |
---|
323 | | - if (ia_valid & ATTR_MTIME) { |
---|
324 | | - inode->i_mtime = attr->ia_mtime; |
---|
325 | | - adfs_unix2adfs_time(inode, attr->ia_mtime.tv_sec); |
---|
| 319 | + if (ia_valid & ATTR_MTIME && adfs_inode_is_stamped(inode)) { |
---|
| 320 | + adfs_unix2adfs_time(inode, &attr->ia_mtime); |
---|
| 321 | + adfs_adfs2unix_time(&inode->i_mtime, inode); |
---|
326 | 322 | } |
---|
| 323 | + |
---|
327 | 324 | /* |
---|
328 | 325 | * FIXME: should we make these == to i_mtime since we don't |
---|
329 | 326 | * have the ability to represent them in our filesystem? |
---|
.. | .. |
---|
333 | 330 | if (ia_valid & ATTR_CTIME) |
---|
334 | 331 | inode->i_ctime = attr->ia_ctime; |
---|
335 | 332 | if (ia_valid & ATTR_MODE) { |
---|
336 | | - ADFS_I(inode)->attr = adfs_mode2atts(sb, inode); |
---|
| 333 | + ADFS_I(inode)->attr = adfs_mode2atts(sb, inode, attr->ia_mode); |
---|
337 | 334 | inode->i_mode = adfs_atts2mode(sb, inode); |
---|
338 | 335 | } |
---|
339 | 336 | |
---|
.. | .. |
---|
358 | 355 | struct object_info obj; |
---|
359 | 356 | int ret; |
---|
360 | 357 | |
---|
361 | | - obj.file_id = inode->i_ino; |
---|
| 358 | + obj.indaddr = ADFS_I(inode)->indaddr; |
---|
362 | 359 | obj.name_len = 0; |
---|
363 | 360 | obj.parent_id = ADFS_I(inode)->parent_id; |
---|
364 | 361 | obj.loadaddr = ADFS_I(inode)->loadaddr; |
---|