2 /* This file contains all the function that handle the dir records
3 * (inodes) for the ISO9660 filesystem.*/
7 #include <minix/vfsif.h>
10 /*===========================================================================*
12 *===========================================================================*/
15 /* Find the inode specified by the request message and decrease its counter. */
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
);
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 */
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) */
50 if (--dir
->d_count
== 0) {
51 if (dir
->ext_attr
!= NULL
)
52 dir
->ext_attr
->count
= 0;
54 dir
->d_mountpoint
= FALSE
;
57 if (dir
->d_next
!= NULL
)
58 release_dir_record(dir
);
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 */
85 /*===========================================================================*
87 *===========================================================================*/
88 struct dir_record
*get_dir_record(id_dir_record
)
91 struct dir_record
*dir
= NULL
;
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
;
105 address
= (u32_t
)id_dir_record
;
106 dir
= load_dir_record_from_disk(address
);
109 if (dir
== NULL
) return(NULL
);
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 */
132 /*===========================================================================*
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
));
161 /*===========================================================================*
163 *===========================================================================*/
164 int create_dir_record(dir
,buffer
,address
)
165 struct dir_record
*dir
;
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. */
175 if (dir
== NULL
) return(EINVAL
);
177 /* The data structure dir record is filled with the stream of data
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
;
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
;
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 */
218 /*===========================================================================*
219 * load_dir_record_from_disk *
220 *===========================================================================*/
221 struct dir_record
*load_dir_record_from_disk(address
)
224 /* This function load a particular dir record from a specific address
227 int block_nr
, offset
, block_size
, new_pos
;
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 */
242 dir
= get_free_dir_record(); /* Get a free record */
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
;
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 */
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. */