test41: relax maximum timer tick rate
[minix.git] / servers / iso9660fs / inode.c
blob918e9d2b2419de455dc74a7a8e6d0227fd383a3f
2 /* This file contains all the function that handle the dir records
3 * (inodes) for the ISO9660 filesystem.*/
5 #include "inc.h"
6 #include "buf.h"
7 #include <minix/vfsif.h>
10 /*===========================================================================*
11 * fs_putnode *
12 *===========================================================================*/
13 int fs_putnode()
15 /* Find the inode specified by the request message and decrease its counter. */
16 int count;
17 struct dir_record *dir = NULL;
19 dir = get_dir_record(fs_m_in.REQ_INODE_NR);
20 release_dir_record(dir);
22 count = fs_m_in.REQ_COUNT;
24 if (count <= 0) return(EINVAL);
26 if (count > dir->d_count) {
27 printf("put_inode: count too high: %d > %d\n", count, dir->d_count);
28 return(EINVAL);
31 if (dir->d_count > 1)
32 dir->d_count = dir->d_count - count + 1;/*Keep at least one reference*/
34 release_dir_record(dir); /* Actual inode release, might be last reference */
36 return(OK);
40 /*===========================================================================*
41 * release_dir_record *
42 *===========================================================================*/
43 int release_dir_record(dir)
44 struct dir_record *dir;
46 /* Release a dir record (decrement the counter) */
47 if (dir == NULL)
48 return(EINVAL);
50 if (--dir->d_count == 0) {
51 if (dir->ext_attr != NULL)
52 dir->ext_attr->count = 0;
53 dir->ext_attr = NULL;
54 dir->d_mountpoint = FALSE;
56 dir->d_prior = NULL;
57 if (dir->d_next != NULL)
58 release_dir_record(dir);
59 dir->d_next = NULL;
61 return(OK);
65 /*===========================================================================*
66 * get_free_dir_record *
67 *===========================================================================*/
68 struct dir_record *get_free_dir_record(void)
70 /* Get a free dir record */
71 struct dir_record *dir;
73 for(dir = dir_records; dir < &dir_records[NR_ATTR_RECS]; dir++) {
74 if (dir->d_count == 0) { /* The record is free */
75 dir->d_count = 1; /* Set count to 1 */
76 dir->ext_attr = NULL;
77 return(dir);
81 return(NULL);
85 /*===========================================================================*
86 * get_dir_record *
87 *===========================================================================*/
88 struct dir_record *get_dir_record(id_dir_record)
89 ino_t id_dir_record;
91 struct dir_record *dir = NULL;
92 u32_t address;
93 int i;
95 /* Search through the cache if the inode is still present */
96 for(i = 0; i < NR_DIR_RECORDS && dir == NULL; ++i) {
97 if (dir_records[i].d_ino_nr == id_dir_record
98 && dir_records[i].d_count > 0) {
99 dir = dir_records + i;
100 dir->d_count++;
104 if (dir == NULL) {
105 address = (u32_t)id_dir_record;
106 dir = load_dir_record_from_disk(address);
109 if (dir == NULL) return(NULL);
111 return(dir);
115 /*===========================================================================*
116 * get_free_ext_attr *
117 *===========================================================================*/
118 struct ext_attr_rec *get_free_ext_attr(void) {
119 /* Get a free extended attribute structure */
120 struct ext_attr_rec *dir;
121 for(dir = ext_attr_recs; dir < &ext_attr_recs[NR_ATTR_RECS]; dir++) {
122 if (dir->count == 0) { /* The record is free */
123 dir->count = 1;
124 return(dir);
128 return(NULL);
132 /*===========================================================================*
133 * create_ext_attr *
134 *===========================================================================*/
135 int create_ext_attr(struct ext_attr_rec *ext,char *buffer)
137 /* Fill an extent structure from the data read on the device */
138 if (ext == NULL) return(EINVAL);
140 /* In input we have a stream of bytes that are physically read from the
141 * device. This stream of data is copied to the data structure. */
142 memcpy(&ext->own_id,buffer,sizeof(u32_t));
143 memcpy(&ext->group_id,buffer + 4,sizeof(u32_t));
144 memcpy(&ext->permissions,buffer + 8,sizeof(u16_t));
145 memcpy(&ext->file_cre_date,buffer + 10,ISO9660_SIZE_VOL_CRE_DATE);
146 memcpy(&ext->file_mod_date,buffer + 27,ISO9660_SIZE_VOL_MOD_DATE);
147 memcpy(&ext->file_exp_date,buffer + 44,ISO9660_SIZE_VOL_EXP_DATE);
148 memcpy(&ext->file_eff_date,buffer + 61,ISO9660_SIZE_VOL_EFF_DATE);
149 memcpy(&ext->rec_format,buffer + 78,sizeof(u8_t));
150 memcpy(&ext->rec_attrs,buffer + 79,sizeof(u8_t));
151 memcpy(&ext->rec_length,buffer + 80,sizeof(u32_t));
152 memcpy(&ext->system_id,buffer + 84,ISO9660_SIZE_SYS_ID);
153 memcpy(&ext->system_use,buffer + 116,ISO9660_SIZE_SYSTEM_USE);
154 memcpy(&ext->ext_attr_rec_ver,buffer + 180,sizeof(u8_t));
155 memcpy(&ext->len_esc_seq,buffer + 181,sizeof(u8_t));
157 return(OK);
161 /*===========================================================================*
162 * create_ext_attr *
163 *===========================================================================*/
164 int create_dir_record(dir,buffer,address)
165 struct dir_record *dir;
166 char *buffer;
167 u32_t address;
169 /* Fills a dir record structure from the data read on the device */
170 /* If the flag assign id is active it will return the id associated;
171 * otherwise it will return OK. */
172 short size;
174 size = buffer[0];
175 if (dir == NULL) return(EINVAL);
177 /* The data structure dir record is filled with the stream of data
178 * that is read. */
179 dir->length = size;
180 dir->ext_attr_rec_length = *((u8_t*)buffer + 1);
181 memcpy(&dir->loc_extent_l,buffer + 2,sizeof(u32_t));
182 memcpy(&dir->loc_extent_m,buffer + 6,sizeof(u32_t));
183 memcpy(&dir->data_length_l,buffer + 10,sizeof(u32_t));
184 memcpy(&dir->data_length_m,buffer + 14,sizeof(u32_t));
185 memcpy(dir->rec_date,buffer + 18, sizeof(dir->rec_date));
186 dir->file_flags = *((u8_t*)buffer + 25);
187 dir->file_unit_size = *((u8_t*)buffer + 26);
188 dir->inter_gap_size = *((u8_t*)buffer + 27);
189 dir->vol_seq_number = *((u8_t*)buffer + 28);
190 dir->length_file_id = *((u8_t*)buffer + 32);
191 memcpy(dir->file_id,buffer + 33,dir->length_file_id);
192 dir->ext_attr = NULL;
194 /* set memory attrs */
195 if ((dir->file_flags & D_TYPE) == D_DIRECTORY)
196 dir->d_mode = I_DIRECTORY;
197 else
198 dir->d_mode = I_REGULAR;
200 /* Set permission to read only. Equal for all users. */
201 dir->d_mode |= R_BIT | X_BIT;
202 dir->d_mode |= R_BIT << 3 | X_BIT << 3;
203 dir->d_mode |= R_BIT << 6 | X_BIT << 6;
205 dir->d_mountpoint = FALSE;
206 dir->d_next = NULL;
207 dir->d_prior = NULL;
208 dir->d_file_size = dir->data_length_l;
210 /* Set physical address of the dir record */
211 dir->d_phy_addr = address;
212 dir->d_ino_nr = (ino_t) address; /* u32_t e ino_t are the same datatype so
213 * the cast is safe */
214 return(OK);
218 /*===========================================================================*
219 * load_dir_record_from_disk *
220 *===========================================================================*/
221 struct dir_record *load_dir_record_from_disk(address)
222 u32_t address;
224 /* This function load a particular dir record from a specific address
225 * on the device */
227 int block_nr, offset, block_size, new_pos;
228 struct buf *bp;
229 struct dir_record *dir, *dir_next, *dir_parent, *dir_tmp;
230 char name[NAME_MAX + 1];
231 char old_name[NAME_MAX + 1];
232 u32_t new_address, size;
234 block_size = v_pri.logical_block_size_l; /* Block size */
235 block_nr = address / block_size; /* Block number from the address */
236 offset = address % block_size; /* Offset starting from the block */
238 bp = get_block(block_nr); /* Read the block from the device */
239 if (bp == NULL)
240 return(NULL);
242 dir = get_free_dir_record(); /* Get a free record */
243 if (dir == NULL)
244 return(NULL);
246 /* Fill the dir record with the data read from the device */
247 create_dir_record(dir,b_data(bp) + offset, address);
249 /* In case the file is composed of more file sections, load also the
250 * next section into the structure */
251 new_pos = offset + dir->length;
252 dir_parent = dir;
253 new_address = address + dir->length;
254 while (new_pos < block_size) {
255 dir_next = get_free_dir_record();
256 create_dir_record(dir_next, b_data(bp) + new_pos, new_address);
258 if (dir_next->length > 0) {
259 strncpy(name,dir_next->file_id,dir_next->length_file_id);
260 name[dir_next->length_file_id] = '\0';
261 strncpy(old_name, dir_parent->file_id,
262 dir_parent->length_file_id);
263 old_name[dir_parent->length_file_id] = '\0';
265 if (strcmp(name, old_name) == 0) {
266 dir_parent->d_next = dir_next;
267 dir_next->d_prior = dir_parent;
269 /* Link the dir records */
270 dir_tmp = dir_next;
271 size = dir_tmp->data_length_l;
273 /* Update the file size */
274 while (dir_tmp->d_prior != NULL) {
275 dir_tmp = dir_tmp->d_prior;
276 size += dir_tmp->data_length_l;
277 dir_tmp->d_file_size = size;
280 new_pos += dir_parent->length;
281 new_address += dir_next->length;
282 dir_parent = dir_next;
283 } else { /* This is another inode. */
284 release_dir_record(dir_next);
285 new_pos = block_size;
287 } else { /* record not valid */
288 release_dir_record(dir_next);
289 new_pos = block_size; /* Exit from the while */
293 put_block(bp); /* Release the block read. */
294 return(dir);