| .. | .. |
|---|
| 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; |
|---|