aboutsummaryrefslogtreecommitdiffstats
path: root/fs/adfs/inode.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/adfs/inode.c')
-rw-r--r--fs/adfs/inode.c69
1 files changed, 23 insertions, 46 deletions
diff --git a/fs/adfs/inode.c b/fs/adfs/inode.c
index 65794b8fe79e..d5250c5aae21 100644
--- a/fs/adfs/inode.c
+++ b/fs/adfs/inode.c
@@ -7,7 +7,6 @@
7 * it under the terms of the GNU General Public License version 2 as 7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation. 8 * published by the Free Software Foundation.
9 */ 9 */
10#include <linux/smp_lock.h>
11#include <linux/buffer_head.h> 10#include <linux/buffer_head.h>
12#include <linux/writeback.h> 11#include <linux/writeback.h>
13#include "adfs.h" 12#include "adfs.h"
@@ -73,32 +72,18 @@ static sector_t _adfs_bmap(struct address_space *mapping, sector_t block)
73static const struct address_space_operations adfs_aops = { 72static const struct address_space_operations adfs_aops = {
74 .readpage = adfs_readpage, 73 .readpage = adfs_readpage,
75 .writepage = adfs_writepage, 74 .writepage = adfs_writepage,
76 .sync_page = block_sync_page,
77 .write_begin = adfs_write_begin, 75 .write_begin = adfs_write_begin,
78 .write_end = generic_write_end, 76 .write_end = generic_write_end,
79 .bmap = _adfs_bmap 77 .bmap = _adfs_bmap
80}; 78};
81 79
82static inline unsigned int
83adfs_filetype(struct inode *inode)
84{
85 unsigned int type;
86
87 if (ADFS_I(inode)->stamped)
88 type = (ADFS_I(inode)->loadaddr >> 8) & 0xfff;
89 else
90 type = (unsigned int) -1;
91
92 return type;
93}
94
95/* 80/*
96 * Convert ADFS attributes and filetype to Linux permission. 81 * Convert ADFS attributes and filetype to Linux permission.
97 */ 82 */
98static umode_t 83static umode_t
99adfs_atts2mode(struct super_block *sb, struct inode *inode) 84adfs_atts2mode(struct super_block *sb, struct inode *inode)
100{ 85{
101 unsigned int filetype, attr = ADFS_I(inode)->attr; 86 unsigned int attr = ADFS_I(inode)->attr;
102 umode_t mode, rmask; 87 umode_t mode, rmask;
103 struct adfs_sb_info *asb = ADFS_SB(sb); 88 struct adfs_sb_info *asb = ADFS_SB(sb);
104 89
@@ -107,9 +92,7 @@ adfs_atts2mode(struct super_block *sb, struct inode *inode)
107 return S_IFDIR | S_IXUGO | mode; 92 return S_IFDIR | S_IXUGO | mode;
108 } 93 }
109 94
110 filetype = adfs_filetype(inode); 95 switch (ADFS_I(inode)->filetype) {
111
112 switch (filetype) {
113 case 0xfc0: /* LinkFS */ 96 case 0xfc0: /* LinkFS */
114 return S_IFLNK|S_IRWXUGO; 97 return S_IFLNK|S_IRWXUGO;
115 98
@@ -175,50 +158,48 @@ adfs_mode2atts(struct super_block *sb, struct inode *inode)
175 158
176/* 159/*
177 * Convert an ADFS time to Unix time. ADFS has a 40-bit centi-second time 160 * Convert an ADFS time to Unix time. ADFS has a 40-bit centi-second time
178 * referenced to 1 Jan 1900 (til 2248) 161 * referenced to 1 Jan 1900 (til 2248) so we need to discard 2208988800 seconds
162 * of time to convert from RISC OS epoch to Unix epoch.
179 */ 163 */
180static void 164static void
181adfs_adfs2unix_time(struct timespec *tv, struct inode *inode) 165adfs_adfs2unix_time(struct timespec *tv, struct inode *inode)
182{ 166{
183 unsigned int high, low; 167 unsigned int high, low;
168 /* 01 Jan 1970 00:00:00 (Unix epoch) as nanoseconds since
169 * 01 Jan 1900 00:00:00 (RISC OS epoch)
170 */
171 static const s64 nsec_unix_epoch_diff_risc_os_epoch =
172 2208988800000000000LL;
173 s64 nsec;
184 174
185 if (ADFS_I(inode)->stamped == 0) 175 if (ADFS_I(inode)->stamped == 0)
186 goto cur_time; 176 goto cur_time;
187 177
188 high = ADFS_I(inode)->loadaddr << 24; 178 high = ADFS_I(inode)->loadaddr & 0xFF; /* top 8 bits of timestamp */
189 low = ADFS_I(inode)->execaddr; 179 low = ADFS_I(inode)->execaddr; /* bottom 32 bits of timestamp */
190 180
191 high |= low >> 8; 181 /* convert 40-bit centi-seconds to 32-bit seconds
192 low &= 255; 182 * going via nanoseconds to retain precision
183 */
184 nsec = (((s64) high << 32) | (s64) low) * 10000000; /* cs to ns */
193 185
194 /* Files dated pre 01 Jan 1970 00:00:00. */ 186 /* Files dated pre 01 Jan 1970 00:00:00. */
195 if (high < 0x336e996a) 187 if (nsec < nsec_unix_epoch_diff_risc_os_epoch)
196 goto too_early; 188 goto too_early;
197 189
198 /* Files dated post 18 Jan 2038 03:14:05. */ 190 /* convert from RISC OS to Unix epoch */
199 if (high >= 0x656e9969) 191 nsec -= nsec_unix_epoch_diff_risc_os_epoch;
200 goto too_late;
201
202 /* discard 2208988800 (0x336e996a00) seconds of time */
203 high -= 0x336e996a;
204 192
205 /* convert 40-bit centi-seconds to 32-bit seconds */ 193 *tv = ns_to_timespec(nsec);
206 tv->tv_sec = (((high % 100) << 8) + low) / 100 + (high / 100 << 8);
207 tv->tv_nsec = 0;
208 return; 194 return;
209 195
210 cur_time: 196 cur_time:
211 *tv = CURRENT_TIME_SEC; 197 *tv = CURRENT_TIME;
212 return; 198 return;
213 199
214 too_early: 200 too_early:
215 tv->tv_sec = tv->tv_nsec = 0; 201 tv->tv_sec = tv->tv_nsec = 0;
216 return; 202 return;
217
218 too_late:
219 tv->tv_sec = 0x7ffffffd;
220 tv->tv_nsec = 0;
221 return;
222} 203}
223 204
224/* 205/*
@@ -280,7 +261,8 @@ adfs_iget(struct super_block *sb, struct object_info *obj)
280 ADFS_I(inode)->loadaddr = obj->loadaddr; 261 ADFS_I(inode)->loadaddr = obj->loadaddr;
281 ADFS_I(inode)->execaddr = obj->execaddr; 262 ADFS_I(inode)->execaddr = obj->execaddr;
282 ADFS_I(inode)->attr = obj->attr; 263 ADFS_I(inode)->attr = obj->attr;
283 ADFS_I(inode)->stamped = ((obj->loadaddr & 0xfff00000) == 0xfff00000); 264 ADFS_I(inode)->filetype = obj->filetype;
265 ADFS_I(inode)->stamped = ((obj->loadaddr & 0xfff00000) == 0xfff00000);
284 266
285 inode->i_mode = adfs_atts2mode(sb, inode); 267 inode->i_mode = adfs_atts2mode(sb, inode);
286 adfs_adfs2unix_time(&inode->i_mtime, inode); 268 adfs_adfs2unix_time(&inode->i_mtime, inode);
@@ -316,8 +298,6 @@ adfs_notify_change(struct dentry *dentry, struct iattr *attr)
316 unsigned int ia_valid = attr->ia_valid; 298 unsigned int ia_valid = attr->ia_valid;
317 int error; 299 int error;
318 300
319 lock_kernel();
320
321 error = inode_change_ok(inode, attr); 301 error = inode_change_ok(inode, attr);
322 302
323 /* 303 /*
@@ -359,7 +339,6 @@ adfs_notify_change(struct dentry *dentry, struct iattr *attr)
359 if (ia_valid & (ATTR_SIZE | ATTR_MTIME | ATTR_MODE)) 339 if (ia_valid & (ATTR_SIZE | ATTR_MTIME | ATTR_MODE))
360 mark_inode_dirty(inode); 340 mark_inode_dirty(inode);
361out: 341out:
362 unlock_kernel();
363 return error; 342 return error;
364} 343}
365 344
@@ -374,7 +353,6 @@ int adfs_write_inode(struct inode *inode, struct writeback_control *wbc)
374 struct object_info obj; 353 struct object_info obj;
375 int ret; 354 int ret;
376 355
377 lock_kernel();
378 obj.file_id = inode->i_ino; 356 obj.file_id = inode->i_ino;
379 obj.name_len = 0; 357 obj.name_len = 0;
380 obj.parent_id = ADFS_I(inode)->parent_id; 358 obj.parent_id = ADFS_I(inode)->parent_id;
@@ -384,6 +362,5 @@ int adfs_write_inode(struct inode *inode, struct writeback_control *wbc)
384 obj.size = inode->i_size; 362 obj.size = inode->i_size;
385 363
386 ret = adfs_dir_update(sb, &obj, wbc->sync_mode == WB_SYNC_ALL); 364 ret = adfs_dir_update(sb, &obj, wbc->sync_mode == WB_SYNC_ALL);
387 unlock_kernel();
388 return ret; 365 return ret;
389} 366}