/* Modify atom refcount */ static int atomref(struct inode *atable, atom_t atom, int use) { if(DEBUG_MODE_K==1) { printf("\t\t\t\t%25s[K] %25s %4d #in\n",__FILE__,__func__,__LINE__); } struct sb *sb = tux_sb(atable->i_sb); unsigned shift = sb->blockbits - ATOMREF_BLKBITS; unsigned block = sb->atomref_base + ATOMREF_SIZE * (atom >> shift); unsigned offset = atom & ~(-1 << shift), kill = 0; struct buffer_head *buffer; __be16 *refcount; int err; buffer = blockread(mapping(atable), block); if (!buffer) return -EIO; refcount = bufdata(buffer); int low = be16_to_cpu(refcount[offset]) + use; trace("inc atom %x by %d, offset %x[%x], low = %d", atom, use, block, offset, low); /* This releases buffer */ err = update_refcount(sb, buffer, offset, low); if (err) return err; if (!low || (low & (-1 << 16))) { buffer = blockread(mapping(atable), block + 1); if (!buffer) return -EIO; refcount = bufdata(buffer); int high = be16_to_cpu(refcount[offset]); if (!low) blockput(buffer); else { trace("carry %d, offset %x[%x], high = %d", (low >> 16), block, offset, high); high += (low >> 16); assert(high >= 0); /* paranoia check */ /* This releases buffer */ err = update_refcount(sb, buffer, offset, high); if (err) { /* FIXME: better set a flag that atomref broke * or something! */ return err; } } kill = !(low | high); }
tux_dirent *tux_find_entry(struct inode *dir, const char *name, unsigned len, struct buffer_head **result, loff_t size) { struct sb *sb = tux_sb(dir->i_sb); unsigned reclen = TUX_REC_LEN(len); block_t block, blocks = size >> sb->blockbits; int err = -ENOENT; for (block = 0; block < blocks; block++) { struct buffer_head *buffer = blockread(mapping(dir), block); if (!buffer) { err = -EIO; // need ERR_PTR for blockread!!! goto error; } tux_dirent *entry = bufdata(buffer); tux_dirent *limit = (void *)entry + sb->blocksize - reclen; while (entry <= limit) { if (entry->rec_len == 0) { blockput(buffer); tux_zero_len_error(dir, block); err = -EIO; goto error; } if (tux_match(entry, name, len)) { *result = buffer; return entry; } entry = next_entry(entry); } blockput(buffer); } error: *result = NULL; /* for debug */ return ERR_PTR(err); }
int tux_readdir(struct file *file, void *state, filldir_t filldir) { loff_t pos = file->f_pos; #ifdef __KERNEL__ struct inode *dir = file->f_dentry->d_inode; #else struct inode *dir = file->f_inode; #endif int revalidate = file->f_version != dir->i_version; struct sb *sb = tux_sb(dir->i_sb); unsigned blockbits = sb->blockbits; block_t block, blocks = dir->i_size >> blockbits; unsigned offset = pos & sb->blockmask; assert(!(dir->i_size & sb->blockmask)); for (block = pos >> blockbits ; block < blocks; block++) { struct buffer_head *buffer = blockread(mapping(dir), block); if (!buffer) return -EIO; void *base = bufdata(buffer); if (revalidate) { if (offset) { tux_dirent *entry = base + offset; tux_dirent *p = base + (offset & sb->blockmask); while (p < entry && p->rec_len) p = next_entry(p); offset = (void *)p - base; file->f_pos = (block << blockbits) + offset; } file->f_version = dir->i_version; revalidate = 0; } tux_dirent *limit = base + sb->blocksize - TUX_REC_LEN(1); for (tux_dirent *entry = base + offset; entry <= limit; entry = next_entry(entry)) { if (entry->rec_len == 0) { blockput(buffer); tux_zero_len_error(dir, block); return -EIO; } if (!is_deleted(entry)) { unsigned type = (entry->type < TUX_TYPES) ? filetype[entry->type] : DT_UNKNOWN; int lame = filldir( state, entry->name, entry->name_len, (block << blockbits) | ((void *)entry - base), be64_to_cpu(entry->inum), type); if (lame) { blockput(buffer); return 0; } } file->f_pos += tux_rec_len_from_disk(entry->rec_len); } blockput(buffer); offset = 0; } return 0; }
int reader::mount() { int i,ofs; if (!tmpsect) return 0; if (!blockread(0,1,tmpsect)) return 0; if (llei16(tmpsect+510) != 0xAA55) return 0; /* NEC MS-DOS 3.30 8-partition support */ /* see http://www.geocities.com/thestarman3/asm/mbr/DOS33MBR.htm for details */ if (llei16(tmpsect+0x17C) == 0xA55A) { entries = 8; ofs = 0x17E; } else { entries = 4; ofs = 0x1BE; } for (i=0;i < entries && i < MAX_ENTRIES;i++) { entry[i].flags = tmpsect[ofs+0x0]; entry[i].start_head = tmpsect[ofs+0x1]; entry[i].start_sector = tmpsect[ofs+0x2] & 0x3F; entry[i].start_cylinder = tmpsect[ofs+0x3] | ((tmpsect[ofs+0x2] & 0xC0) << 2); entry[i].system_id = tmpsect[ofs+0x4]; entry[i].end_head = tmpsect[ofs+0x5]; entry[i].end_sector = tmpsect[ofs+0x6] & 0x3F; entry[i].end_cylinder = tmpsect[ofs+0x7] | ((tmpsect[ofs+0x6] & 0xC0) << 2); entry[i].start = llei32(tmpsect+ofs+0x8); entry[i].size = llei32(tmpsect+ofs+0xC); entry[i].parent_ent = -1; entry[i].partition_sector = 0; entry[i].partition_sector_offset = ofs; ofs += 16; } /* look for extended DOS partitions */ for (i=0;i < entries && i < MAX_ENTRIES;i++) { // TODO } return 1; }
int tux_dir_is_empty(struct inode *dir) { struct sb *sb = tux_sb(dir->i_sb); block_t block, blocks = dir->i_size >> sb->blockbits; __be64 self = cpu_to_be64(tux_inode(dir)->inum); struct buffer_head *buffer; for (block = 0; block < blocks; block++) { buffer = blockread(mapping(dir), block); if (!buffer) return -EIO; tux_dirent *entry = bufdata(buffer); tux_dirent *limit = bufdata(buffer) + sb->blocksize - TUX_REC_LEN(1); for (; entry <= limit; entry = next_entry(entry)) { if (!entry->rec_len) { blockput(buffer); tux_zero_len_error(dir, block); return -EIO; } if (is_deleted(entry)) continue; if (entry->name[0] != '.') goto not_empty; if (entry->name_len > 2) goto not_empty; if (entry->name_len < 2) { if (entry->inum != self) goto not_empty; } else if (entry->name[1] != '.') goto not_empty; } blockput(buffer); } return 0; not_empty: blockput(buffer); return -ENOTEMPTY; }
loff_t tux_create_entry(struct inode *dir, const char *name, unsigned len, inum_t inum, umode_t mode, loff_t *size) { unsigned delta = tux3_get_current_delta(); struct sb *sb = tux_sb(dir->i_sb); tux_dirent *entry; struct buffer_head *buffer, *clone; unsigned reclen = TUX_REC_LEN(len), rec_len, name_len, offset; unsigned blocksize = sb->blocksize; block_t block, blocks = *size >> sb->blockbits; void *olddata; for (block = 0; block < blocks; block++) { buffer = blockread(mapping(dir), block); if (!buffer) return -EIO; entry = bufdata(buffer); tux_dirent *limit = bufdata(buffer) + blocksize - reclen; while (entry <= limit) { if (entry->rec_len == 0) { blockput(buffer); tux_zero_len_error(dir, block); return -EIO; } name_len = TUX_REC_LEN(entry->name_len); rec_len = tux_rec_len_from_disk(entry->rec_len); if (is_deleted(entry) && rec_len >= reclen) goto create; if (rec_len >= name_len + reclen) goto create; entry = (void *)entry + rec_len; } blockput(buffer); } entry = NULL; buffer = blockget(mapping(dir), block); assert(!buffer_dirty(buffer)); create: /* * The directory is protected by i_mutex. * blockdirty() should never return -EAGAIN. */ olddata = bufdata(buffer); clone = blockdirty(buffer, delta); if (IS_ERR(clone)) { assert(PTR_ERR(clone) != -EAGAIN); blockput(buffer); return PTR_ERR(clone); } if (!entry) { /* Expanding the directory size. Initialize block. */ entry = bufdata(clone); memset(entry, 0, blocksize); entry->rec_len = tux_rec_len_to_disk(blocksize); assert(is_deleted(entry)); *size += blocksize; } else { entry = ptr_redirect(entry, olddata, bufdata(clone)); if (!is_deleted(entry)) { tux_dirent *newent = (void *)entry + name_len; unsigned rest_rec_len = rec_len - name_len; newent->rec_len = tux_rec_len_to_disk(rest_rec_len); entry->rec_len = tux_rec_len_to_disk(name_len); entry = newent; } } entry->name_len = len; memcpy(entry->name, name, len); offset = (void *)entry - bufdata(clone); /* this releases buffer */ tux_update_entry(clone, entry, inum, mode); return (block << sb->blockbits) + offset; /* only for xattr create */ }
void main(int argc, char **argv) { char *rargv[10]; int rargc; char *fields[NFLDS], name[2*LEN], *p, *namep; char uid[NAMELEN], gid[NAMELEN]; ulong mode, bytes, mtime; char *file; int i, n, stdin, fd, chatty; char blk[512]; if(argc>1 && strcmp(argv[1], "RAMFS") == 0){ argv[1] = argv[0]; ramfsmain(argc-1, argv+1); exits(nil); } if(argc>1 && strcmp(argv[1], "BUNZIP") == 0){ _unbzip(0, 1); exits(nil); } rfork(RFNOTEG); stdin = 0; file = nil; namep = name; mtpt = "/root"; chatty = 0; ARGBEGIN{ case 'd': chatty = !chatty; break; case 'f': file = ARGF(); break; case 's': stdin++; break; case 'm': mtpt = ARGF(); break; default: usage(); }ARGEND if(argc != 0) usage(); if(file == nil) { fprint(2, "must specify -f file\n"); usage(); } if((fd = open(file, OREAD)) < 0) { fprint(2, "cannot open \"%s\": %r\n", file); exits("open"); } rargv[0] = "ramfs"; rargc = 1; if(stdin) rargv[rargc++] = "-i"; rargv[rargc++] = "-m"; rargv[rargc++] = mtpt; rargv[rargc] = nil; ramfsmain(rargc, rargv); if(1 || strstr(file, "disk")) { /* search for archive on block boundary */ if(chatty) fprint(2, "searching for bz\n"); for(i=0;; i++){ if((n = readn(fd, blk, sizeof blk)) != sizeof blk) sysfatal("read %d gets %d: %r\n", i, n); if(strncmp(blk, "bzfilesystem\n", 13) == 0) break; } if(chatty) fprint(2, "found at %d\n", i); } if(chdir(mtpt) < 0) error("chdir %s: %r", mtpt); fd = unbflz(unbzip(blockread(fd, blk+13, sizeof(blk)-13))); Binits(&bin, fd, OREAD, binbuf, sizeof binbuf); while(p = Brdline(&bin, '\n')){ p[Blinelen(&bin)-1] = '\0'; if(chatty) fprint(2, "%s\n", p); if(strcmp(p, "end of archive") == 0){ _exits(0); } if(getfields(p, fields, NFLDS, 0, " \t") != NFLDS){ warn("too few fields in file header"); continue; } strcpy(namep, fields[0]); mode = strtoul(fields[1], 0, 8); mtime = strtoul(fields[4], 0, 10); bytes = strtoul(fields[5], 0, 10); strncpy(uid, fields[2], NAMELEN); strncpy(gid, fields[3], NAMELEN); if(mode & DMDIR) mkdir(name, mode, mtime, uid, gid); else extract(name, mode, mtime, uid, gid, bytes); } fprint(2, "premature end of archive\n"); exits("premature end of archive"); }