* The Regents of the University of California. All rights reserved.
* This code is derived from software contributed to Berkeley by
* The Mach Operating System project at Carnegie-Mellon University.
* %sccs.include.redist.c%
* @(#)ufs.c 8.1 (Berkeley) %G%
* Copyright (c) 1990, 1991 Carnegie Mellon University
* Permission to use, copy, modify and distribute this software and its
* documentation is hereby granted, provided that both the copyright
* notice and this permission notice appear in all copies of the
* software, derivative works or modified versions, and any portions
* thereof, and that both notices appear in supporting documentation.
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
* ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
* Carnegie Mellon requests users of this software to return to
* Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
* School of Computer Science
* Carnegie Mellon University
* Pittsburgh PA 15213-3890
* any improvements or extensions that they make and grant Carnegie the
* rights to redistribute these changes.
* Stand-alone file reading package.
#include <ufs/ufs/dinode.h>
off_t f_seekp
; /* seek pointer */
struct fs
*f_fs
; /* pointer to super-block */
struct dinode f_di
; /* copy of on-disk inode */
/* number of blocks mapped by
indirect block at level i */
char *f_blk
[NIADDR
]; /* buffer for indirect block at
u_long f_blksize
[NIADDR
];
daddr_t f_blkno
[NIADDR
];/* disk address of block in buffer */
char *f_buf
; /* buffer for data block */
u_int f_buf_size
; /* size of data block */
daddr_t f_buf_blkno
; /* block number of data block */
* Read a new inode into a file structure.
register struct file
*fp
= (struct file
*)f
->f_fsdata
;
register struct fs
*fs
= fp
->f_fs
;
* Read inode and save it.
buf
= alloc(fs
->fs_bsize
);
rc
= (f
->f_dev
->dv_strategy
)(f
->f_devdata
, F_READ
,
fsbtodb(fs
, itod(fs
, inumber
)), fs
->fs_bsize
, buf
, &rsize
);
if (rsize
!= fs
->fs_bsize
) {
register struct dinode
*dp
;
dp
= (struct dinode
*)buf
;
fp
->f_di
= dp
[itoo(fs
, inumber
)];
* Clear out the old buffers
for (level
= 0; level
< NIADDR
; level
++)
* Given an offset in a file, find the disk block number that
block_map(f
, file_block
, disk_block_p
)
daddr_t
*disk_block_p
; /* out */
register struct file
*fp
= (struct file
*)f
->f_fsdata
;
register struct fs
*fs
= fp
->f_fs
;
* Index structure of an inode:
* di_db[0..NDADDR-1] hold block numbers for blocks
* di_ib[0] index block 0 is the single indirect block
* holds block numbers for blocks
* NDADDR .. NDADDR + NINDIR(fs)-1
* di_ib[1] index block 1 is the double indirect block
* holds block numbers for INDEX blocks for blocks
* NDADDR + NINDIR(fs) + NINDIR(fs)**2 - 1
* di_ib[2] index block 2 is the triple indirect block
* holds block numbers for double-indirect
* NDADDR + NINDIR(fs) + NINDIR(fs)**2 ..
* NDADDR + NINDIR(fs) + NINDIR(fs)**2
if (file_block
< NDADDR
) {
*disk_block_p
= fp
->f_di
.di_db
[file_block
];
for (level
= 0; level
< NIADDR
; level
++) {
if (file_block
< fp
->f_nindir
[level
])
file_block
-= fp
->f_nindir
[level
];
/* Block number too high */
ind_block_num
= fp
->f_di
.di_ib
[level
];
for (; level
>= 0; level
--) {
if (ind_block_num
== 0) {
*disk_block_p
= 0; /* missing */
if (fp
->f_blkno
[level
] != ind_block_num
) {
if (fp
->f_blk
[level
] == (char *)0)
rc
= (f
->f_dev
->dv_strategy
)(f
->f_devdata
, F_READ
,
fsbtodb(fp
->f_fs
, ind_block_num
),
if (fp
->f_blksize
[level
] != fs
->fs_bsize
)
fp
->f_blkno
[level
] = ind_block_num
;
ind_p
= (daddr_t
*)fp
->f_blk
[level
];
idx
= file_block
/ fp
->f_nindir
[level
- 1];
file_block
%= fp
->f_nindir
[level
- 1];
ind_block_num
= ind_p
[idx
];
*disk_block_p
= ind_block_num
;
* Read a portion of a file into an internal buffer. Return
* the location in the buffer and the amount in the buffer.
buf_read_file(f
, buf_p
, size_p
)
register struct file
*fp
= (struct file
*)f
->f_fsdata
;
register struct fs
*fs
= fp
->f_fs
;
register daddr_t file_block
;
off
= blkoff(fs
, fp
->f_seekp
);
file_block
= lblkno(fs
, fp
->f_seekp
);
block_size
= dblksize(fs
, &fp
->f_di
, file_block
);
if (file_block
!= fp
->f_buf_blkno
) {
rc
= block_map(f
, file_block
, &disk_block
);
if (fp
->f_buf
== (char *)0)
fp
->f_buf
= alloc(fs
->fs_bsize
);
bzero(fp
->f_buf
, block_size
);
fp
->f_buf_size
= block_size
;
rc
= (f
->f_dev
->dv_strategy
)(f
->f_devdata
, F_READ
,
block_size
, fp
->f_buf
, &fp
->f_buf_size
);
fp
->f_buf_blkno
= file_block
;
* Return address of byte in buffer corresponding to
* offset, and size of remainder of buffer after that
*buf_p
= fp
->f_buf
+ off
;
*size_p
= block_size
- off
;
* But truncate buffer at end of file.
if (*size_p
> fp
->f_di
.di_size
- fp
->f_seekp
)
*size_p
= fp
->f_di
.di_size
- fp
->f_seekp
;
* Search a directory for a name and return its
search_directory(name
, f
, inumber_p
)
ino_t
*inumber_p
; /* out */
register struct file
*fp
= (struct file
*)f
->f_fsdata
;
register struct direct
*dp
;
while (fp
->f_seekp
< fp
->f_di
.di_size
) {
rc
= buf_read_file(f
, &buf
, &buf_size
);
dp
= (struct direct
*)buf
;
edp
= (struct direct
*)(buf
+ buf_size
);
if (dp
->d_ino
== (ino_t
)0)
#if BYTE_ORDER == LITTLE_ENDIAN
if (fp
->f_fs
->fs_maxsymlinklen
<= 0)
!strcmp(name
, dp
->d_name
)) {
dp
= (struct direct
*)((char *)dp
+ dp
->d_reclen
);
ino_t inumber
, parent_inumber
;
char namebuf
[MAXPATHLEN
+1];
/* allocate file system specific data structure */
fp
= alloc(sizeof(struct file
));
bzero(fp
, sizeof(struct file
));
f
->f_fsdata
= (void *)fp
;
/* allocate space and read super block */
rc
= (f
->f_dev
->dv_strategy
)(f
->f_devdata
, F_READ
,
SBLOCK
, SBSIZE
, (char *)fs
, &buf_size
);
if (buf_size
!= SBSIZE
|| fs
->fs_magic
!= FS_MAGIC
||
fs
->fs_bsize
> MAXBSIZE
|| fs
->fs_bsize
< sizeof(struct fs
)) {
* Calculate indirect block levels.
for (level
= 0; level
< NIADDR
; level
++) {
fp
->f_nindir
[level
] = mult
;
if ((rc
= read_inode(inumber
, f
)) != 0)
* Remove extra separators
* Check that current node is a directory.
if ((fp
->f_di
.di_mode
& IFMT
) != IFDIR
) {
* Get next component of path name.
while ((c
= *cp
) != '\0' && c
!= '/') {
* Look up component in current directory.
* Save directory inumber in case we find a
parent_inumber
= inumber
;
rc
= search_directory(ncp
, f
, &inumber
);
if ((rc
= read_inode(inumber
, f
)) != 0)
* Check for symbolic link.
if ((fp
->i_mode
& IFMT
) == IFLNK
) {
int link_len
= fp
->f_di
.di_size
;
if (fp
->f_di
.di_size
>= MAXPATHLEN
- 1 ||
++nlinks
> MAXSYMLINKS
) {
strcpy(&namebuf
[link_len
], cp
);
if ((fp
->i_flags
& IC_FASTLINK
) != 0) {
bcopy(fp
->i_symlink
, namebuf
, (unsigned) link_len
);
* Read file for symbolic link
register struct fs
*fs
= fp
->f_fs
;
(void) block_map(f
, (daddr_t
)0, &disk_block
);
rc
= device_read(&fp
->f_dev
,
bcopy((char *)buf
, namebuf
, (unsigned)link_len
);
* If relative pathname, restart at parent directory.
* If absolute pathname, restart at root.
inumber
= parent_inumber
;
inumber
= (ino_t
)ROOTINO
;
if ((rc
= read_inode(inumber
, fp
)) != 0)
* Found terminal component.
free(fp
, sizeof(struct file
));
register struct file
*fp
= (struct file
*)f
->f_fsdata
;
if (fp
== (struct file
*)0)
for (level
= 0; level
< NIADDR
; level
++) {
free(fp
->f_blk
[level
], fp
->f_fs
->fs_bsize
);
free(fp
->f_buf
, fp
->f_fs
->fs_bsize
);
free(fp
, sizeof(struct file
));
* Copy a portion of a file into kernel memory.
* Cross block boundaries when necessary.
ufs_read(f
, start
, size
, resid
)
register struct file
*fp
= (struct file
*)f
->f_fsdata
;
if (fp
->f_seekp
>= fp
->f_di
.di_size
)
rc
= buf_read_file(f
, &buf
, &buf_size
);
bcopy(buf
, start
, csize
);
ufs_write(f
, start
, size
, resid
)
ufs_seek(f
, offset
, where
)
register struct file
*fp
= (struct file
*)f
->f_fsdata
;
fp
->f_seekp
= fp
->f_di
.di_size
- offset
;
register struct file
*fp
= (struct file
*)f
->f_fsdata
;
/* only important stuff */
sb
->st_mode
= fp
->f_di
.di_mode
;
sb
->st_uid
= fp
->f_di
.di_uid
;
sb
->st_gid
= fp
->f_di
.di_gid
;
sb
->st_size
= fp
->f_di
.di_size
;