catalog.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:39k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  * linux/fs/hfs/catalog.c
  3.  *
  4.  * Copyright (C) 1995-1997  Paul H. Hargrove
  5.  * This file may be distributed under the terms of the GNU General Public License.
  6.  *
  7.  * This file contains the functions related to the catalog B-tree.
  8.  *
  9.  * "XXX" in a comment is a note to myself to consider changing something.
  10.  *
  11.  * Cache code shamelessly stolen from 
  12.  *     linux/fs/inode.c Copyright (C) 1991, 1992  Linus Torvalds
  13.  *     re-shamelessly stolen Copyright (C) 1997 Linus Torvalds
  14.  *
  15.  * In function preconditions the term "valid" applied to a pointer to
  16.  * a structure means that the pointer is non-NULL and the structure it
  17.  * points to has all fields initialized to consistent values.
  18.  *
  19.  * The code in this file initializes some structures by calling
  20.  * memset(&foo, 0, sizeof(foo)).  This produces the desired behavior
  21.  * only due to the non-ANSI assumption that the machine representation
  22.  */
  23. #include "hfs.h"
  24. /*================ Variable-like macros ================*/
  25. /* Number of hash table slots */
  26. #define C_HASHBITS  10
  27. #define C_HASHSIZE  (1UL << C_HASHBITS)
  28. #define C_HASHMASK  (C_HASHSIZE - 1)
  29. /* Number of entries to fit in a single page on an i386.
  30.  * Actually, now it's used to increment the free entry pool. */
  31. #define CCACHE_INC (PAGE_SIZE/sizeof(struct hfs_cat_entry))
  32. #define CCACHE_MAX (CCACHE_INC * 8)
  33. /*================ File-local data types ================*/
  34. /* The catalog record for a file */
  35. typedef struct {
  36. hfs_byte_t Flags; /* Flags such as read-only */
  37. hfs_byte_t Typ; /* file version number = 0 */
  38. hfs_finfo_t UsrWds; /* data used by the Finder */
  39. hfs_lword_t FlNum; /* The CNID */
  40. hfs_word_t StBlk; /* obsolete */
  41. hfs_lword_t LgLen; /* The logical EOF of the data fork*/
  42. hfs_lword_t PyLen; /* The physical EOF of the data fork */
  43. hfs_word_t RStBlk; /* obsolete */
  44. hfs_lword_t RLgLen; /* The logical EOF of the rsrc fork */
  45. hfs_lword_t RPyLen; /* The physical EOF of the rsrc fork */
  46. hfs_lword_t CrDat; /* The creation date */
  47. hfs_lword_t MdDat; /* The modified date */
  48. hfs_lword_t BkDat; /* The last backup date */
  49. hfs_fxinfo_t FndrInfo; /* more data for the Finder */
  50. hfs_word_t ClpSize; /* number of bytes to allocate
  51.    when extending files */
  52. hfs_byte_t ExtRec[12]; /* first extent record
  53.    for the data fork */
  54. hfs_byte_t RExtRec[12]; /* first extent record
  55.    for the resource fork */
  56. hfs_lword_t Resrv; /* reserved by Apple */
  57. } __attribute__((packed)) FIL_REC;
  58. /* the catalog record for a directory */
  59. typedef struct {
  60. hfs_word_t Flags; /* flags */
  61. hfs_word_t Val; /* Valence: number of files and
  62.    dirs in the directory */
  63. hfs_lword_t DirID; /* The CNID */
  64. hfs_lword_t CrDat; /* The creation date */
  65. hfs_lword_t MdDat; /* The modification date */
  66. hfs_lword_t BkDat; /* The last backup date */
  67. hfs_dinfo_t UsrInfo; /* data used by the Finder */
  68. hfs_dxinfo_t FndrInfo; /* more data used by Finder */
  69. hfs_byte_t Resrv[16]; /* reserved by Apple */
  70. } __attribute__((packed)) DIR_REC;
  71. /* the catalog record for a thread */
  72. typedef struct {
  73. hfs_byte_t Reserv[8]; /* reserved by Apple */
  74. hfs_lword_t ParID; /* CNID of parent directory */
  75. struct hfs_name CName; /* The name of this entry */
  76. }  __attribute__((packed)) THD_REC;
  77. /* A catalog tree record */
  78. struct hfs_cat_rec {
  79. hfs_byte_t cdrType; /* The type of entry */
  80. hfs_byte_t cdrResrv2; /* padding */
  81. union {
  82. FIL_REC fil;
  83. DIR_REC dir;
  84. THD_REC thd;
  85. } u;
  86. } __attribute__((packed));
  87. /*================ File-local variables ================*/
  88.  
  89. static LIST_HEAD(entry_in_use);
  90. static LIST_HEAD(entry_unused);
  91. static struct list_head hash_table[C_HASHSIZE];
  92. static spinlock_t entry_lock = SPIN_LOCK_UNLOCKED;
  93. static struct {
  94.         int nr_entries;
  95.         int nr_free_entries;
  96. } entries_stat;
  97. /*================ File-local functions ================*/
  98. /*
  99.  * brec_to_id
  100.  *
  101.  * Get the CNID from a brec
  102.  */
  103. static inline hfs_u32 brec_to_id(struct hfs_brec *brec)
  104. {
  105. struct hfs_cat_rec *rec = brec->data;
  106. return hfs_get_nl((rec->cdrType==HFS_CDR_FIL) ?
  107. rec->u.fil.FlNum : rec->u.dir.DirID);
  108. }
  109. /*
  110.  * hashfn()
  111.  *
  112.  * hash an (struct mdb *) and a (struct hfs_cat_key *) to an integer.
  113.  */
  114. static inline unsigned int hashfn(const struct hfs_mdb *mdb,
  115.   const struct hfs_cat_key *key)
  116. {
  117. unsigned int hash;
  118. hash = (unsigned long) mdb | (unsigned long) key->ParID[3] | 
  119. hfs_strhash(key->CName.Name, key->CName.Len);
  120. hash = hash ^ (hash >> C_HASHBITS) ^ (hash >> C_HASHBITS*2);
  121. return hash & C_HASHMASK;
  122. }
  123. /*
  124.  * hash()
  125.  *
  126.  * hash an (struct mdb *) and a (struct hfs_cat_key *)
  127.  * to a pointer to a slot in the hash table.
  128.  */
  129. static inline struct list_head *hash(struct hfs_mdb *mdb,
  130.      const struct hfs_cat_key *key)
  131. {
  132. return hash_table + hashfn(mdb, key);
  133. }
  134. static inline void insert_hash(struct hfs_cat_entry *entry)
  135. {
  136. struct list_head *head = hash(entry->mdb, &entry->key);
  137. list_add(&entry->hash, head);
  138. }
  139. static inline void remove_hash(struct hfs_cat_entry *entry)
  140. {
  141. list_del(&entry->hash);
  142. INIT_LIST_HEAD(&entry->hash);
  143. }
  144. /*
  145.  * wait_on_entry()
  146.  *
  147.  * Sleep until a locked entry is unlocked.
  148.  */
  149. static inline void wait_on_entry(struct hfs_cat_entry * entry)
  150. {
  151. while ((entry->state & HFS_LOCK)) {
  152. hfs_sleep_on(&entry->wait);
  153. }
  154. }
  155. /*
  156.  * lock_entry()
  157.  *
  158.  * Obtain an exclusive lock on an entry.
  159.  */
  160. static void lock_entry(struct hfs_cat_entry * entry)
  161. {
  162. wait_on_entry(entry);
  163. spin_lock(&entry_lock);
  164. entry->state |= HFS_LOCK;
  165. spin_unlock(&entry_lock);
  166. }
  167. /*
  168.  * lock_entry()
  169.  *
  170.  * Relinquish an exclusive lock on an entry.
  171.  */
  172. static void unlock_entry(struct hfs_cat_entry * entry)
  173. {
  174. spin_lock(&entry_lock);
  175. entry->state &= ~HFS_LOCK;
  176. spin_unlock(&entry_lock);
  177. hfs_wake_up(&entry->wait);
  178. }
  179. /* put entry on mdb dirty list. */
  180. void hfs_cat_mark_dirty(struct hfs_cat_entry *entry)
  181. {
  182.         struct hfs_mdb *mdb = entry->mdb;
  183. spin_lock(&entry_lock);
  184. if (!(entry->state & HFS_DIRTY)) {
  185.         entry->state |= HFS_DIRTY;
  186. /* Only add valid (ie hashed) entries to the dirty list. */
  187. if (!list_empty(&entry->hash)) {
  188.         list_del(&entry->list);
  189. list_add(&entry->list, &mdb->entry_dirty);
  190. }
  191. }
  192. spin_unlock(&entry_lock);
  193. }
  194. /* delete an entry and remove it from the hash table. */
  195. static void delete_entry(struct hfs_cat_entry *entry)
  196. {
  197.         if (!(entry->state & HFS_DELETED)) {
  198.         entry->state |= HFS_DELETED;
  199. list_del(&entry->hash);
  200. INIT_LIST_HEAD(&entry->hash);
  201.         if (entry->type == HFS_CDR_FIL) {
  202.   /* free all extents */
  203.   entry->u.file.data_fork.lsize = 0;
  204.   hfs_extent_adj(&entry->u.file.data_fork);
  205.   entry->u.file.rsrc_fork.lsize = 0;
  206.   hfs_extent_adj(&entry->u.file.rsrc_fork);
  207. }
  208. }
  209. }
  210. static inline void init_entry(struct hfs_cat_entry *entry)
  211. {
  212. memset(entry, 0, sizeof(*entry));
  213. hfs_init_waitqueue(&entry->wait);
  214. INIT_LIST_HEAD(&entry->hash);
  215. INIT_LIST_HEAD(&entry->list);
  216. }
  217. /*
  218.  * hfs_cat_alloc()
  219.  *
  220.  * Try to allocate another entry. 
  221.  */
  222. static inline struct hfs_cat_entry *hfs_cat_alloc(void)
  223. {
  224.         struct hfs_cat_entry *entry;
  225. if (!HFS_NEW(entry))
  226.         return NULL;
  227. init_entry(entry);
  228. return entry;
  229. }
  230. /* this gets called with the spinlock held. */
  231. static int grow_entries(void)
  232. {
  233.         struct hfs_cat_entry *entry;
  234. int i;
  235. for (i = 0; i < CCACHE_INC; i++) {
  236.         if (!(entry = hfs_cat_alloc()))
  237.         break;
  238. list_add(&entry->list, &entry_unused);
  239. }
  240. entries_stat.nr_entries += i;
  241. entries_stat.nr_free_entries += i;
  242.         
  243. return i;
  244. }
  245. /*
  246.  * __read_entry()
  247.  *
  248.  * Convert a (struct hfs_cat_rec) to a (struct hfs_cat_entry).
  249.  */
  250. static void __read_entry(struct hfs_cat_entry *entry,
  251.  const struct hfs_cat_rec *cat)
  252. {
  253. entry->type = cat->cdrType;
  254. if (cat->cdrType == HFS_CDR_DIR) {
  255. struct hfs_dir *dir = &entry->u.dir;
  256. entry->cnid = hfs_get_nl(cat->u.dir.DirID);
  257. dir->magic = HFS_DIR_MAGIC;
  258. dir->flags = hfs_get_ns(cat->u.dir.Flags);
  259. memcpy(&entry->info.dir.dinfo, &cat->u.dir.UsrInfo, 16);
  260. memcpy(&entry->info.dir.dxinfo, &cat->u.dir.FndrInfo, 16);
  261. entry->create_date = hfs_get_nl(cat->u.dir.CrDat);
  262. entry->modify_date = hfs_get_nl(cat->u.dir.MdDat);
  263. entry->backup_date = hfs_get_nl(cat->u.dir.BkDat);
  264. dir->dirs = dir->files = 0;
  265. hfs_init_waitqueue(&dir->read_wait);
  266. hfs_init_waitqueue(&dir->write_wait);
  267. } else if (cat->cdrType == HFS_CDR_FIL) {
  268. struct hfs_file *fil = &entry->u.file;
  269. entry->cnid = hfs_get_nl(cat->u.fil.FlNum);
  270. fil->magic = HFS_FILE_MAGIC;
  271. fil->data_fork.fork = HFS_FK_DATA;
  272. fil->data_fork.entry = entry;
  273. fil->data_fork.lsize = hfs_get_hl(cat->u.fil.LgLen);
  274. fil->data_fork.psize = hfs_get_hl(cat->u.fil.PyLen) >>
  275.      HFS_SECTOR_SIZE_BITS;
  276. hfs_extent_in(&fil->data_fork, cat->u.fil.ExtRec);
  277. fil->rsrc_fork.fork = HFS_FK_RSRC;
  278. fil->rsrc_fork.entry = entry;
  279. fil->rsrc_fork.lsize = hfs_get_hl(cat->u.fil.RLgLen);
  280. fil->rsrc_fork.psize = hfs_get_hl(cat->u.fil.RPyLen) >>
  281.      HFS_SECTOR_SIZE_BITS;
  282. hfs_extent_in(&fil->rsrc_fork, cat->u.fil.RExtRec);
  283. memcpy(&entry->info.file.finfo, &cat->u.fil.UsrWds, 16);
  284. memcpy(&entry->info.file.fxinfo, &cat->u.fil.FndrInfo, 16);
  285. entry->create_date = hfs_get_nl(cat->u.fil.CrDat);
  286. entry->modify_date = hfs_get_nl(cat->u.fil.MdDat);
  287. entry->backup_date = hfs_get_nl(cat->u.fil.BkDat);
  288. fil->clumpablks = (hfs_get_hs(cat->u.fil.ClpSize)
  289. / entry->mdb->alloc_blksz)
  290. >> HFS_SECTOR_SIZE_BITS;
  291. fil->flags = cat->u.fil.Flags;
  292. } else {
  293. hfs_warn("hfs_fs: entry is neither file nor directory!n");
  294. }
  295. }
  296. /*
  297.  * count_dir_entries()
  298.  *
  299.  * Count the number of files and directories in a given directory.
  300.  */
  301. static inline void count_dir_entries(struct hfs_cat_entry *entry,
  302.      struct hfs_brec *brec)
  303. {
  304. int error = 0;
  305. hfs_u32 cnid;
  306. hfs_u8 type;
  307. if (!hfs_cat_open(entry, brec)) {
  308. while (!(error = hfs_cat_next(entry, brec, 1, &cnid, &type))) {
  309. if (type == HFS_CDR_FIL) {
  310. ++entry->u.dir.files;
  311. } else if (type == HFS_CDR_DIR) {
  312. ++entry->u.dir.dirs;
  313. }
  314. } /* -ENOENT is normal termination */
  315. }
  316. if (error != -ENOENT) {
  317. entry->cnid = 0;
  318. }
  319. }
  320. /*
  321.  * read_entry()
  322.  *
  323.  * Convert a (struct hfs_brec) to a (struct hfs_cat_entry).
  324.  */
  325. static inline void read_entry(struct hfs_cat_entry *entry,
  326.       struct hfs_brec *brec)
  327. {
  328. int need_count;
  329. struct hfs_cat_rec *rec = brec->data;
  330. __read_entry(entry, rec);
  331. need_count = (rec->cdrType == HFS_CDR_DIR) && rec->u.dir.Val;
  332. hfs_brec_relse(brec, NULL);
  333. if (need_count) {
  334. count_dir_entries(entry, brec);
  335. }
  336. }
  337. /*
  338.  * __write_entry()
  339.  *
  340.  * Convert a (struct hfs_cat_entry) to a (struct hfs_cat_rec).
  341.  */
  342. static void __write_entry(const struct hfs_cat_entry *entry,
  343.   struct hfs_cat_rec *cat)
  344. {
  345. if (entry->type == HFS_CDR_DIR) {
  346. const struct hfs_dir *dir = &entry->u.dir;
  347. hfs_put_ns(dir->flags,             cat->u.dir.Flags);
  348. hfs_put_hs(dir->dirs + dir->files, cat->u.dir.Val);
  349. hfs_put_nl(entry->cnid,            cat->u.dir.DirID);
  350. hfs_put_nl(entry->create_date,     cat->u.dir.CrDat);
  351. hfs_put_nl(entry->modify_date,     cat->u.dir.MdDat);
  352. hfs_put_nl(entry->backup_date,     cat->u.dir.BkDat);
  353. memcpy(&cat->u.dir.UsrInfo, &entry->info.dir.dinfo, 16);
  354. memcpy(&cat->u.dir.FndrInfo, &entry->info.dir.dxinfo, 16);
  355. } else if (entry->type == HFS_CDR_FIL) {
  356. const struct hfs_file *fil = &entry->u.file;
  357. cat->u.fil.Flags = fil->flags;
  358. hfs_put_nl(entry->cnid,            cat->u.fil.FlNum);
  359. memcpy(&cat->u.fil.UsrWds, &entry->info.file.finfo, 16);
  360. hfs_put_hl(fil->data_fork.lsize, cat->u.fil.LgLen);
  361. hfs_put_hl(fil->data_fork.psize << HFS_SECTOR_SIZE_BITS,
  362.   cat->u.fil.PyLen);
  363. hfs_put_hl(fil->rsrc_fork.lsize, cat->u.fil.RLgLen);
  364. hfs_put_hl(fil->rsrc_fork.psize << HFS_SECTOR_SIZE_BITS,
  365.   cat->u.fil.RPyLen);
  366. hfs_put_nl(entry->create_date,     cat->u.fil.CrDat);
  367. hfs_put_nl(entry->modify_date,     cat->u.fil.MdDat);
  368. hfs_put_nl(entry->backup_date,     cat->u.fil.BkDat);
  369. memcpy(&cat->u.fil.FndrInfo, &entry->info.file.fxinfo, 16);
  370. hfs_put_hs((fil->clumpablks * entry->mdb->alloc_blksz)
  371. << HFS_SECTOR_SIZE_BITS, cat->u.fil.ClpSize);
  372. hfs_extent_out(&fil->data_fork, cat->u.fil.ExtRec);
  373. hfs_extent_out(&fil->rsrc_fork, cat->u.fil.RExtRec);
  374. } else {
  375. hfs_warn("__write_entry: invalid entryn");
  376. }
  377. }
  378. /*
  379.  * write_entry()
  380.  *
  381.  * Write a modified entry back to the catalog B-tree. this gets called
  382.  * with the entry locked.
  383.  */
  384. static void write_entry(struct hfs_cat_entry * entry)
  385. {
  386. struct hfs_brec brec;
  387. int error;
  388. if (!(entry->state & HFS_DELETED)) {
  389. error = hfs_bfind(&brec, entry->mdb->cat_tree,
  390.   HFS_BKEY(&entry->key), HFS_BFIND_WRITE);
  391. if (!error) {
  392. if ((entry->state & HFS_KEYDIRTY)) {
  393. /* key may have changed case due to a rename */
  394. entry->state &= ~HFS_KEYDIRTY;
  395. if (brec.key->KeyLen != entry->key.KeyLen) {
  396. hfs_warn("hfs_write_entry: key length "
  397.  "changed!n");
  398. error = 1;
  399. } else {
  400. memcpy(brec.key, &entry->key,
  401.        entry->key.KeyLen);
  402. }
  403. } else if (entry->cnid != brec_to_id(&brec)) {
  404. hfs_warn("hfs_write_entry: CNID "
  405.  "changed unexpectedly!n");
  406. error = 1;
  407. }
  408. if (!error) {
  409. __write_entry(entry, brec.data);
  410. }
  411. hfs_brec_relse(&brec, NULL);
  412. }
  413. if (error) {
  414. hfs_warn("hfs_write_entry: unable to write "
  415.  "entry %08xn", entry->cnid);
  416. }
  417. }
  418. }
  419. /* this gets called with the spinlock held. */
  420. static struct hfs_cat_entry *find_entry(struct hfs_mdb *mdb,
  421. const struct hfs_cat_key *key)
  422. {
  423. struct list_head *tmp, *head = hash(mdb, key);
  424. struct hfs_cat_entry * entry;
  425. tmp = head;
  426. for (;;) {
  427. tmp = tmp->next;
  428. entry = NULL;
  429. if (tmp == head)
  430. break;
  431. entry = list_entry(tmp, struct hfs_cat_entry, hash);
  432. if (entry->mdb != mdb)
  433. continue;
  434. if (hfs_cat_compare(&entry->key, key)) {
  435. continue;
  436. }
  437. entry->count++;
  438. break;
  439. }
  440. return entry;
  441. }
  442. /* be careful. this gets called with the spinlock held. */
  443. static struct hfs_cat_entry *get_new_entry(struct hfs_mdb *mdb,
  444.    const struct hfs_cat_key *key,
  445.    const int read)
  446. {
  447. struct hfs_cat_entry *entry;
  448. struct list_head *head = hash(mdb, key);
  449. struct list_head *tmp;
  450. add_new_entry:
  451. tmp = entry_unused.next;
  452. if ((tmp != &entry_unused) ) {
  453. list_del(tmp);
  454. entries_stat.nr_free_entries--;
  455. entry = list_entry(tmp, struct hfs_cat_entry, list);
  456. list_add(&entry->list, &entry_in_use);
  457. list_add(&entry->hash, head);
  458. entry->mdb = mdb;
  459. entry->count = 1;
  460. memcpy(&entry->key, key, sizeof(*key));
  461. entry->state = HFS_LOCK;
  462. spin_unlock(&entry_lock);
  463. if (read) {
  464.    struct hfs_brec brec;
  465.    if (hfs_bfind(&brec, mdb->cat_tree,
  466.  HFS_BKEY(key), HFS_BFIND_READ_EQ)) {
  467.         /* uh oh. we failed to read the record.
  468.  * the entry doesn't actually exist. */
  469.         goto read_fail;
  470.    }
  471.    read_entry(entry, &brec);
  472.    
  473.    /* error */
  474.    if (!entry->cnid) {
  475.         goto read_fail;
  476.    }
  477.    /* we don't have to acquire a spinlock here or
  478.     * below for the unlocking bits as we're the first
  479.     * user of this entry. */
  480.    entry->state &= ~HFS_LOCK;
  481.    hfs_wake_up(&entry->wait);
  482. }
  483. return entry;
  484. }
  485. /* try to allocate more entries. grow_entries() doesn't release
  486.  * the spinlock. */
  487. if (grow_entries())
  488.         goto add_new_entry;
  489. spin_unlock(&entry_lock);
  490. return NULL;
  491. read_fail: 
  492. /* short-cut hfs_cat_put by doing everything here. */
  493. spin_lock(&entry_lock);
  494. list_del(&entry->hash);
  495. list_del(&entry->list);
  496. init_entry(entry);
  497. list_add(&entry->list, &entry_unused);
  498. entries_stat.nr_free_entries++;
  499. spin_unlock(&entry_lock);
  500. return NULL;
  501. }
  502. /*
  503.  * get_entry()
  504.  *
  505.  * Try to return an entry for the indicated file or directory.
  506.  * If ('read' == 0) then no attempt will be made to read it from disk
  507.  * and a locked, but uninitialized, entry is returned.
  508.  */
  509. static struct hfs_cat_entry *get_entry(struct hfs_mdb *mdb,
  510.        const struct hfs_cat_key *key,
  511.        const int read)
  512. {
  513. struct hfs_cat_entry * entry;
  514. #if defined(DEBUG_CATALOG) || defined(DEBUG_ALL)
  515. hfs_warn("hfs_get_entry: mdb=%p key=%s read=%dn",
  516.  mdb, key->CName.Name, read);
  517. #endif
  518. spin_lock(&entry_lock);
  519. entry = find_entry(mdb, key);
  520. if (!entry) {
  521.         return get_new_entry(mdb, key, read);
  522. }
  523. spin_unlock(&entry_lock);
  524. wait_on_entry(entry);
  525. return entry;
  526. }
  527. /* 
  528.  * new_cnid()
  529.  *
  530.  * Allocate a CNID to use for a new file or directory.
  531.  */
  532. static inline hfs_u32 new_cnid(struct hfs_mdb *mdb)
  533. {
  534. /* If the create succeeds then the mdb will get dirtied */
  535. return htonl(mdb->next_id++);
  536. }
  537. /*
  538.  * update_dir()
  539.  *
  540.  * Update counts, times and dirt on a changed directory
  541.  */
  542. static void update_dir(struct hfs_mdb *mdb, struct hfs_cat_entry *dir,
  543.        int is_dir, int count)
  544. {
  545. /* update counts */
  546. if (is_dir) {
  547. mdb->dir_count += count;
  548. dir->u.dir.dirs += count;
  549. if (dir->cnid == htonl(HFS_ROOT_CNID)) {
  550. mdb->root_dirs += count;
  551. }
  552. } else {
  553. mdb->file_count += count;
  554. dir->u.dir.files += count;
  555. if (dir->cnid == htonl(HFS_ROOT_CNID)) {
  556. mdb->root_files += count;
  557. }
  558. }
  559. /* update times and dirt */
  560. dir->modify_date = hfs_time();
  561. hfs_cat_mark_dirty(dir);
  562. }
  563. /*
  564.  * Add a writer to dir, excluding readers.
  565.  *
  566.  * XXX: this is wrong. it allows a move to occur when a directory
  567.  *      is being written to. 
  568.  */
  569. static inline void start_write(struct hfs_cat_entry *dir)
  570. {
  571. if (dir->u.dir.readers || waitqueue_active(&dir->u.dir.read_wait)) {
  572. hfs_sleep_on(&dir->u.dir.write_wait);
  573. }
  574. ++dir->u.dir.writers;
  575. }
  576. /*
  577.  * Add a reader to dir, excluding writers.
  578.  */
  579. static inline void start_read(struct hfs_cat_entry *dir)
  580. {
  581. if (dir->u.dir.writers || waitqueue_active(&dir->u.dir.write_wait)) {
  582. hfs_sleep_on(&dir->u.dir.read_wait);
  583. }
  584. ++dir->u.dir.readers;
  585. }
  586. /*
  587.  * Remove a writer from dir, possibly admitting readers.
  588.  */
  589. static inline void end_write(struct hfs_cat_entry *dir)
  590. {
  591. if (!(--dir->u.dir.writers)) {
  592. hfs_wake_up(&dir->u.dir.read_wait);
  593. }
  594. }
  595. /*
  596.  * Remove a reader from dir, possibly admitting writers.
  597.  */
  598. static inline void end_read(struct hfs_cat_entry *dir)
  599. {
  600. if (!(--dir->u.dir.readers)) {
  601. hfs_wake_up(&dir->u.dir.write_wait);
  602. }
  603. }
  604. /*
  605.  * create_entry()
  606.  *
  607.  * Add a new file or directory to the catalog B-tree and
  608.  * return a (struct hfs_cat_entry) for it in '*result'.
  609.  */
  610. static int create_entry(struct hfs_cat_entry *parent, struct hfs_cat_key *key,
  611. const struct hfs_cat_rec *record, int is_dir,
  612. hfs_u32 cnid, struct hfs_cat_entry **result)
  613. {
  614. struct hfs_mdb *mdb = parent->mdb;
  615. struct hfs_cat_entry *entry;
  616. struct hfs_cat_key thd_key;
  617. struct hfs_cat_rec thd_rec;
  618. int error, has_thread;
  619. if (result) {
  620. *result = NULL;
  621. }
  622. /* keep readers from getting confused by changing dir size */
  623. start_write(parent);
  624. /* create a locked entry in the cache */
  625. entry = get_entry(mdb, key, 0);
  626. if (!entry) {
  627. /* The entry exists but can't be read */
  628. error = -EIO;
  629. goto done;
  630. }
  631. if (entry->cnid) {
  632. /* The (unlocked) entry exists in the cache */
  633. error = -EEXIST;
  634. goto bail2;
  635. }
  636. /* limit directory valence to signed 16-bit integer */
  637.         if ((parent->u.dir.dirs + parent->u.dir.files) >= HFS_MAX_VALENCE) {
  638. error = -ENOSPC;
  639. goto bail1;
  640. }
  641. has_thread = is_dir || (record->u.fil.Flags & HFS_FIL_THD);
  642. if (has_thread) {
  643. /* init some fields for the thread record */
  644. memset(&thd_rec, 0, sizeof(thd_rec));
  645. thd_rec.cdrType = is_dir ? HFS_CDR_THD : HFS_CDR_FTH;
  646. memcpy(&thd_rec.u.thd.ParID, &key->ParID,
  647.        sizeof(hfs_u32) + sizeof(struct hfs_name));
  648. /* insert the thread record */
  649. hfs_cat_build_key(cnid, NULL, &thd_key);
  650. error = hfs_binsert(mdb->cat_tree, HFS_BKEY(&thd_key),
  651.     &thd_rec, 2 + sizeof(THD_REC));
  652. if (error) {
  653. goto bail1;
  654. }
  655. }
  656. /* insert the record */
  657. error = hfs_binsert(mdb->cat_tree, HFS_BKEY(key), record,
  658. is_dir ?  2 + sizeof(DIR_REC) :
  659.   2 + sizeof(FIL_REC));
  660. if (error) {
  661. if (has_thread && (error != -EIO)) {
  662. /* at least TRY to remove the thread record */
  663. (void)hfs_bdelete(mdb->cat_tree, HFS_BKEY(&thd_key));
  664. }
  665. goto bail1;
  666. }
  667. /* update the parent directory */
  668. update_dir(mdb, parent, is_dir, 1);
  669. /* complete the cache entry and return success */
  670. __read_entry(entry, record);
  671. unlock_entry(entry);
  672. if (result) {
  673. *result = entry;
  674. } else {
  675. hfs_cat_put(entry);
  676. }
  677. goto done;
  678. bail1:
  679. /* entry really didn't exist, so we don't need to really delete it.
  680.  * we do need to remove it from the hash, though. */
  681. entry->state |= HFS_DELETED;
  682. remove_hash(entry);
  683. unlock_entry(entry);
  684. bail2:
  685. hfs_cat_put(entry);
  686. done:
  687. end_write(parent);
  688. return error;
  689. }
  690. /*================ Global functions ================*/
  691. /* 
  692.  * hfs_cat_put()
  693.  *
  694.  * Release an entry we aren't using anymore.
  695.  *
  696.  * nothing in hfs_cat_put goes to sleep now except on the initial entry.  
  697.  */
  698. void hfs_cat_put(struct hfs_cat_entry * entry)
  699. {
  700. if (entry) {
  701.         wait_on_entry(entry);
  702. /* just in case. this should never happen. */
  703. if (!entry->count) { 
  704.   hfs_warn("hfs_cat_put: trying to free free entry: %pn",
  705.    entry);
  706.   return;
  707. }
  708. #if defined(DEBUG_CATALOG) || defined(DEBUG_ALL)
  709. hfs_warn("hfs_cat_put: %p(%u) type=%d state=%lun", 
  710.  entry, entry->count, entry->type, entry->state);
  711. #endif
  712. spin_lock(&entry_lock);
  713. if (!--entry->count) {
  714. if ((entry->state & HFS_DELETED))
  715.         goto entry_deleted;
  716. if ((entry->type == HFS_CDR_FIL)) {
  717.                 /* clear out any cached extents */
  718.         if (entry->u.file.data_fork.first.next) {
  719.   hfs_extent_free(&entry->u.file.data_fork);
  720. }
  721. if (entry->u.file.rsrc_fork.first.next) {
  722.   hfs_extent_free(&entry->u.file.rsrc_fork);
  723. }
  724. }
  725. /* if we put a dirty entry, write it out. */
  726. if ((entry->state & HFS_DIRTY)) {
  727.         entry->state ^= HFS_DIRTY | HFS_LOCK;
  728. write_entry(entry);
  729. entry->state &= ~HFS_LOCK;
  730. }
  731. list_del(&entry->hash);
  732. entry_deleted:  /* deleted entries have already been removed
  733.  * from the hash list. */
  734. list_del(&entry->list);
  735. if (entries_stat.nr_free_entries > CCACHE_MAX) {
  736.         HFS_DELETE(entry);
  737. entries_stat.nr_entries--;
  738. } else {
  739. init_entry(entry);
  740. list_add(&entry->list, &entry_unused);
  741. entries_stat.nr_free_entries++;
  742. }
  743. }
  744. spin_unlock(&entry_lock);
  745. }
  746. }
  747. /* 
  748.  * hfs_cat_get()
  749.  *
  750.  * Wrapper for get_entry() which always calls with ('read'==1).
  751.  * Used for access to get_entry() from outside this file.
  752.  */
  753. struct hfs_cat_entry *hfs_cat_get(struct hfs_mdb *mdb,
  754.   const struct hfs_cat_key *key)
  755. {
  756. return get_entry(mdb, key, 1);
  757. }
  758. /* invalidate all entries for a device */
  759. static void invalidate_list(struct list_head *head, struct hfs_mdb *mdb,
  760.     struct list_head *dispose)
  761. {
  762.         struct list_head *next;
  763. next = head->next;
  764. for (;;) {
  765.         struct list_head *tmp = next;
  766. struct hfs_cat_entry * entry;
  767. next = next->next;
  768. if (tmp == head)
  769.         break;
  770. entry = list_entry(tmp, struct hfs_cat_entry, list);
  771. if (entry->mdb != mdb) {
  772. continue;
  773. }
  774. if (!entry->count) {
  775.         list_del(&entry->hash);
  776. INIT_LIST_HEAD(&entry->hash);
  777. list_del(&entry->list);
  778. list_add(&entry->list, dispose);
  779. continue;
  780. }
  781. hfs_warn("hfs_fs: entry %p(%u) busy on removed device %s.n",
  782.  entry, entry->count, 
  783.  hfs_mdb_name(entry->mdb->sys_mdb));
  784. }
  785. }
  786. /* delete entries from a list */
  787. static void delete_list(struct list_head *head) 
  788. {
  789. struct list_head *next = head->next;
  790. struct hfs_cat_entry *entry;
  791. for (;;) {
  792. struct list_head * tmp = next;
  793. next = next->next;
  794. if (tmp == head) {
  795. break;
  796. }
  797. entry = list_entry(tmp, struct hfs_cat_entry, list);
  798. HFS_DELETE(entry);
  799. }
  800. }
  801. /* 
  802.  * hfs_cat_invalidate()
  803.  *
  804.  * Called by hfs_mdb_put() to remove all the entries
  805.  * in the cache that are associated with a given MDB.
  806.  */
  807. void hfs_cat_invalidate(struct hfs_mdb *mdb)
  808. {
  809. LIST_HEAD(throw_away);
  810. spin_lock(&entry_lock);
  811. invalidate_list(&entry_in_use, mdb, &throw_away);
  812. invalidate_list(&mdb->entry_dirty, mdb, &throw_away);
  813. spin_unlock(&entry_lock);
  814. delete_list(&throw_away);
  815. #if defined(DEBUG_CATALOG) || defined(DEBUG_ALL)
  816. hfs_warn("hfs_cat_invalidate: free=%d total=%dn",
  817.  entries_stat.nr_free_entries,
  818.  entries_stat.nr_entries);
  819. #endif
  820. }
  821. /*
  822.  * hfs_cat_commit()
  823.  *
  824.  * Called by hfs_mdb_commit() to write dirty entries to the disk buffers.
  825.  */
  826. void hfs_cat_commit(struct hfs_mdb *mdb)
  827. {
  828.         struct list_head *tmp, *head = &mdb->entry_dirty;
  829. struct hfs_cat_entry *entry;
  830. spin_lock(&entry_lock);
  831. while ((tmp = head->prev) != head) {
  832.         entry = list_entry(tmp, struct hfs_cat_entry, list);
  833.   
  834. if ((entry->state & HFS_LOCK)) {
  835.         spin_unlock(&entry_lock);
  836. wait_on_entry(entry);
  837. spin_lock(&entry_lock);
  838. } else {
  839.        struct list_head *insert = &entry_in_use;
  840.        if (!entry->count)
  841.         insert = entry_in_use.prev;
  842.        /* add to in_use list */
  843.        list_del(&entry->list);
  844.        list_add(&entry->list, insert);
  845.        /* reset DIRTY, set LOCK */
  846.        entry->state ^= HFS_DIRTY | HFS_LOCK;
  847.        spin_unlock(&entry_lock);
  848.        write_entry(entry);
  849.        spin_lock(&entry_lock);
  850.        entry->state &= ~HFS_LOCK;
  851.        hfs_wake_up(&entry->wait);
  852. }
  853. }
  854. spin_unlock(&entry_lock);
  855. }
  856. /*
  857.  * hfs_cat_free()
  858.  *
  859.  * Releases all the memory allocated in grow_entries().
  860.  * Must call hfs_cat_invalidate() on all MDBs before calling this.
  861.  * This only gets rid of the unused pool of entries. all the other
  862.  * entry references should have either been freed by cat_invalidate
  863.  * or moved onto the unused list.
  864.  */
  865. void hfs_cat_free(void)
  866. {
  867. delete_list(&entry_unused);
  868. }
  869. /*
  870.  * hfs_cat_compare()
  871.  *
  872.  * Description:
  873.  *   This is the comparison function used for the catalog B-tree.  In
  874.  *   comparing catalog B-tree entries, the parent id is the most
  875.  *   significant field (compared as unsigned ints).  The name field is
  876.  *   the least significant (compared in "Macintosh lexical order",
  877.  *   see hfs_strcmp() in string.c)
  878.  * Input Variable(s):
  879.  *   struct hfs_cat_key *key1: pointer to the first key to compare
  880.  *   struct hfs_cat_key *key2: pointer to the second key to compare
  881.  * Output Variable(s):
  882.  *   NONE
  883.  * Returns:
  884.  *   int: negative if key1<key2, positive if key1>key2, and 0 if key1==key2
  885.  * Preconditions:
  886.  *   key1 and key2 point to "valid" (struct hfs_cat_key)s.
  887.  * Postconditions:
  888.  *   This function has no side-effects
  889.  */
  890. int hfs_cat_compare(const struct hfs_cat_key *key1,
  891.     const struct hfs_cat_key *key2)
  892. {
  893. unsigned int parents;
  894. int retval;
  895. parents = hfs_get_hl(key1->ParID) - hfs_get_hl(key2->ParID);
  896. if (parents != 0) {
  897. retval = (int)parents;
  898. } else {
  899. retval = hfs_strcmp(key1->CName.Name, key1->CName.Len,
  900.     key2->CName.Name, key2->CName.Len);
  901. }
  902. return retval;
  903. }
  904. /*
  905.  * hfs_cat_build_key()
  906.  *
  907.  * Given the ID of the parent and the name build a search key.
  908.  */
  909. void hfs_cat_build_key(hfs_u32 parent, const struct hfs_name *cname,
  910.        struct hfs_cat_key *key)
  911. {
  912. hfs_put_nl(parent, key->ParID);
  913. if (cname) {
  914. key->KeyLen = 6 + cname->Len;
  915. memcpy(&key->CName, cname, sizeof(*cname));
  916. } else {
  917. key->KeyLen = 6;
  918. memset(&key->CName, 0, sizeof(*cname));
  919. }
  920. }
  921. /*
  922.  * hfs_cat_open()
  923.  *
  924.  * Given a directory on an HFS filesystem get its thread and
  925.  * lock the directory against insertions and deletions.
  926.  * Return 0 on success or an error code on failure.
  927.  */
  928. int hfs_cat_open(struct hfs_cat_entry *dir, struct hfs_brec *brec)
  929. {
  930. struct hfs_cat_key key;
  931. int error;
  932. if (dir->type != HFS_CDR_DIR) {
  933. return -EINVAL;
  934. }
  935. /* Block writers */
  936. start_read(dir);
  937. /* Find the directory */
  938. hfs_cat_build_key(dir->cnid, NULL, &key);
  939. error = hfs_bfind(brec, dir->mdb->cat_tree,
  940.   HFS_BKEY(&key), HFS_BFIND_READ_EQ);
  941. if (error) {
  942. end_read(dir);
  943. }
  944. return error;
  945. }
  946. /*
  947.  * hfs_cat_next()
  948.  *
  949.  * Given a catalog brec structure, replace it with the count'th next brec
  950.  * in the same directory.
  951.  * Return an error code if there is a problem, 0 if OK.
  952.  * Note that an error code of -ENOENT means there are no more entries
  953.  * in this directory.
  954.  * The directory is "closed" on an error.
  955.  */
  956. int hfs_cat_next(struct hfs_cat_entry *dir, struct hfs_brec *brec,
  957.  hfs_u16 count, hfs_u32 *cnid, hfs_u8 *type)
  958. {
  959. int error;
  960. if (!dir || !brec) {
  961. return -EINVAL;
  962. }
  963. /* Get the count'th next catalog tree entry */
  964. error = hfs_bsucc(brec, count);
  965. if (!error) {
  966. struct hfs_cat_key *key = (struct hfs_cat_key *)brec->key;
  967. if (hfs_get_nl(key->ParID) != dir->cnid) {
  968. hfs_brec_relse(brec, NULL);
  969. error = -ENOENT;
  970. }
  971. }
  972. if (!error) {
  973. *type = ((struct hfs_cat_rec *)brec->data)->cdrType;
  974. *cnid = brec_to_id(brec);
  975. } else {
  976. end_read(dir);
  977. }
  978. return error;
  979. }
  980. /*
  981.  * hfs_cat_close()
  982.  *
  983.  * Given a catalog brec structure, replace it with the count'th next brec
  984.  * in the same directory.
  985.  * Return an error code if there is a problem, 0 if OK.
  986.  * Note that an error code of -ENOENT means there are no more entries
  987.  * in this directory.
  988.  */
  989. void hfs_cat_close(struct hfs_cat_entry *dir, struct hfs_brec *brec)
  990. {
  991. if (dir && brec) {
  992. hfs_brec_relse(brec, NULL);
  993. end_read(dir);
  994. }
  995. }
  996. /*
  997.  * hfs_cat_parent()
  998.  *
  999.  * Given a catalog entry, return the entry for its parent.
  1000.  * Uses catalog key for the entry to get its parent's ID
  1001.  * and then uses the parent's thread record to locate the
  1002.  * parent's actual catalog entry.
  1003.  */
  1004. struct hfs_cat_entry *hfs_cat_parent(struct hfs_cat_entry *entry)
  1005. {
  1006. struct hfs_cat_entry *retval = NULL;
  1007. struct hfs_mdb *mdb = entry->mdb;
  1008. struct hfs_brec brec;
  1009. struct hfs_cat_key key;
  1010. int error;
  1011. lock_entry(entry);
  1012. if (!(entry->state & HFS_DELETED)) {
  1013. hfs_cat_build_key(hfs_get_nl(entry->key.ParID), NULL, &key);
  1014. error = hfs_bfind(&brec, mdb->cat_tree,
  1015.   HFS_BKEY(&key), HFS_BFIND_READ_EQ);
  1016. if (!error) {
  1017. /* convert thread record to key */
  1018. struct hfs_cat_rec *rec = brec.data;
  1019. key.KeyLen = 6 + rec->u.thd.CName.Len;
  1020. memcpy(&key.ParID, &rec->u.thd.ParID,
  1021.                                sizeof(hfs_u32) + sizeof(struct hfs_name));
  1022.                  hfs_brec_relse(&brec, NULL);
  1023. retval = hfs_cat_get(mdb, &key);
  1024. }
  1025. }
  1026. unlock_entry(entry);
  1027. return retval;
  1028. }
  1029. /*
  1030.  * hfs_cat_create()
  1031.  *
  1032.  * Create a new file with the indicated name in the indicated directory.
  1033.  * The file will have the indicated flags, type and creator.
  1034.  * If successful an (struct hfs_cat_entry) is returned in '*result'.
  1035.  */
  1036. int hfs_cat_create(struct hfs_cat_entry *parent, struct hfs_cat_key *key,
  1037.    hfs_u8 flags, hfs_u32 type, hfs_u32 creator,
  1038.    struct hfs_cat_entry **result)
  1039. {
  1040. struct hfs_cat_rec record;
  1041. hfs_u32 id = new_cnid(parent->mdb);
  1042. hfs_u32 mtime = hfs_time();
  1043. #if defined(DEBUG_CATALOG) || defined(DEBUG_ALL)
  1044. hfs_warn("hfs_cat_create: %p/%s flags=%d res=%pn",
  1045.  parent, key->CName.Name, flags, result);
  1046. #endif
  1047. /* init some fields for the file record */
  1048. memset(&record, 0, sizeof(record));
  1049. record.cdrType = HFS_CDR_FIL;
  1050. record.u.fil.Flags = flags | HFS_FIL_USED;
  1051. hfs_put_nl(id,      record.u.fil.FlNum);
  1052. hfs_put_nl(mtime,   record.u.fil.CrDat);
  1053. hfs_put_nl(mtime,   record.u.fil.MdDat);
  1054. hfs_put_nl(0,       record.u.fil.BkDat);
  1055. hfs_put_nl(type,    record.u.fil.UsrWds.fdType);
  1056. hfs_put_nl(creator, record.u.fil.UsrWds.fdCreator);
  1057. return create_entry(parent, key, &record, 0, id, result);
  1058. }
  1059. /*
  1060.  * hfs_cat_mkdir()
  1061.  *
  1062.  * Create a new directory with the indicated name in the indicated directory.
  1063.  * If successful an (struct hfs_cat_entry) is returned in '*result'.
  1064.  */
  1065. int hfs_cat_mkdir(struct hfs_cat_entry *parent, struct hfs_cat_key *key,
  1066.   struct hfs_cat_entry **result)
  1067. {
  1068. struct hfs_cat_rec record;
  1069. hfs_u32 id = new_cnid(parent->mdb);
  1070. hfs_u32 mtime = hfs_time();
  1071. #if defined(DEBUG_CATALOG) || defined(DEBUG_ALL)
  1072. hfs_warn("hfs_cat_mkdir: %p/%s res=%pn", parent, key->CName.Name,
  1073.  result);
  1074. #endif
  1075. /* init some fields for the directory record */
  1076. memset(&record, 0, sizeof(record));
  1077. record.cdrType = HFS_CDR_DIR;
  1078. hfs_put_nl(id,     record.u.dir.DirID);
  1079. hfs_put_nl(mtime, record.u.dir.CrDat);
  1080. hfs_put_nl(mtime, record.u.dir.MdDat);
  1081. hfs_put_nl(0,     record.u.dir.BkDat);
  1082. hfs_put_hs(0xff,  record.u.dir.UsrInfo.frView);
  1083. return create_entry(parent, key, &record, 1, id, result);
  1084. }
  1085. /*
  1086.  * hfs_cat_delete()
  1087.  *
  1088.  * Delete the indicated file or directory.
  1089.  * The associated thread is also removed unless ('with_thread'==0).
  1090.  */
  1091. int hfs_cat_delete(struct hfs_cat_entry *parent, struct hfs_cat_entry *entry,
  1092.    int with_thread)
  1093. {
  1094. struct hfs_cat_key key;
  1095. struct hfs_mdb *mdb = parent->mdb;
  1096. int is_dir, error = 0;
  1097. #if defined(DEBUG_CATALOG) || defined(DEBUG_ALL)
  1098. hfs_warn("hfs_cat_delete: %p/%p type=%d state=%lu, thread=%dn",
  1099.  parent, entry, entry->type, entry->state, with_thread);
  1100. #endif
  1101. if (parent->mdb != entry->mdb) {
  1102. return -EINVAL;
  1103. }
  1104. if (entry->type == HFS_CDR_FIL) {
  1105. with_thread = (entry->u.file.flags&HFS_FIL_THD) && with_thread;
  1106. is_dir = 0;
  1107. } else {
  1108. is_dir = 1;
  1109. }
  1110. /* keep readers from getting confused by changing dir size */
  1111. start_write(parent);
  1112. /* don't delete a busy directory */
  1113. if (entry->type == HFS_CDR_DIR) {
  1114. start_read(entry);
  1115. error = -ENOTEMPTY;
  1116. if (entry->u.dir.files || entry->u.dir.dirs) 
  1117. goto hfs_delete_end;
  1118. }
  1119. /* try to delete the file or directory */
  1120. lock_entry(entry);
  1121. error = -ENOENT;
  1122. if ((entry->state & HFS_DELETED)) {
  1123. /* somebody beat us to it. */
  1124. goto hfs_delete_unlock;
  1125. }
  1126. /* delete the catalog record */
  1127. if ((error = hfs_bdelete(mdb->cat_tree, HFS_BKEY(&entry->key)))) {
  1128. goto hfs_delete_unlock;
  1129. }
  1130. /* Mark the entry deleted and remove it from the cache */
  1131. delete_entry(entry);
  1132. /* try to delete the thread entry if it exists */
  1133. if (with_thread) {
  1134. hfs_cat_build_key(entry->cnid, NULL, &key);
  1135. (void)hfs_bdelete(mdb->cat_tree, HFS_BKEY(&key));
  1136. }
  1137. update_dir(mdb, parent, is_dir, -1);
  1138. hfs_delete_unlock:
  1139. unlock_entry(entry);
  1140. hfs_delete_end:
  1141. if (entry->type == HFS_CDR_DIR) {
  1142. end_read(entry);
  1143. }
  1144. end_write(parent);
  1145. return error;
  1146. }
  1147. /*
  1148.  * hfs_cat_move()
  1149.  *
  1150.  * Rename a file or directory, possibly to a new directory.
  1151.  * If the destination exists it is removed and a
  1152.  * (struct hfs_cat_entry) for it is returned in '*result'.
  1153.  */
  1154. int hfs_cat_move(struct hfs_cat_entry *old_dir, struct hfs_cat_entry *new_dir,
  1155.  struct hfs_cat_entry *entry, struct hfs_cat_key *new_key,
  1156.  struct hfs_cat_entry **removed)
  1157. {
  1158. struct hfs_cat_entry *dest;
  1159. struct hfs_mdb *mdb;
  1160. int error = 0;
  1161. int is_dir, has_thread;
  1162. if (removed) {
  1163. *removed = NULL;
  1164. }
  1165. /* sanity checks */
  1166. if (!old_dir || !new_dir) {
  1167. return -EINVAL;
  1168. }
  1169. mdb = old_dir->mdb;
  1170. if (mdb != new_dir->mdb) {
  1171. return -EXDEV;
  1172. }
  1173. /* precompute a few things */
  1174. if (entry->type == HFS_CDR_DIR) {
  1175. is_dir = 1;
  1176. has_thread = 1;
  1177. } else if (entry->type == HFS_CDR_FIL) {
  1178. is_dir = 0;
  1179. has_thread = entry->u.file.flags & HFS_FIL_THD;
  1180. } else {
  1181. return -EINVAL;
  1182. }
  1183. while (mdb->rename_lock) {
  1184. hfs_sleep_on(&mdb->rename_wait);
  1185. }
  1186. spin_lock(&entry_lock);
  1187. mdb->rename_lock = 1; /* XXX: should be atomic_inc */
  1188. spin_unlock(&entry_lock);
  1189. /* keep readers from getting confused by changing dir size */
  1190. start_write(new_dir);
  1191. if (old_dir != new_dir) {
  1192. start_write(old_dir);
  1193. }
  1194. /* Don't move a directory inside itself */
  1195. if (is_dir) {
  1196. struct hfs_cat_key thd_key;
  1197. struct hfs_brec brec;
  1198. hfs_u32 id = new_dir->cnid;
  1199. while (id != htonl(HFS_ROOT_CNID)) {
  1200. if (id == entry->cnid) {
  1201. error = -EINVAL;
  1202. } else {
  1203. hfs_cat_build_key(id, NULL, &thd_key);
  1204. error = hfs_bfind(&brec, mdb->cat_tree,
  1205.   HFS_BKEY(&thd_key),
  1206.   HFS_BFIND_READ_EQ);
  1207. }
  1208. if (error) {
  1209. goto done;
  1210. } else {
  1211. struct hfs_cat_rec *rec = brec.data;
  1212. id = hfs_get_nl(rec->u.thd.ParID);
  1213. hfs_brec_relse(&brec, NULL);
  1214. }
  1215. }
  1216. }
  1217. restart:
  1218. /* see if the destination exists, getting it if it does */
  1219. dest = hfs_cat_get(mdb, new_key);
  1220. if (!dest) {
  1221. /* destination doesn't exist, so create it */
  1222. struct hfs_cat_rec new_record;
  1223. /* create a locked entry in the cache */
  1224. dest = get_entry(mdb, new_key, 0);
  1225. if (!dest) {
  1226. error = -EIO;
  1227. goto done;
  1228. }
  1229. if (dest->cnid) {
  1230. /* The (unlocked) entry exists in the cache */
  1231. goto have_distinct;
  1232. }
  1233. /* limit directory valence to signed 16-bit integer */
  1234.          if ((new_dir->u.dir.dirs + new_dir->u.dir.files) >=
  1235. HFS_MAX_VALENCE) {
  1236. error = -ENOSPC;
  1237. goto bail3;
  1238. }
  1239. /* build the new record. make sure to zero out the
  1240.                    record. */
  1241. memset(&new_record, 0, sizeof(new_record));
  1242. new_record.cdrType = entry->type;
  1243. __write_entry(entry, &new_record);
  1244. /* insert the new record */
  1245. error = hfs_binsert(mdb->cat_tree, HFS_BKEY(new_key),
  1246.     &new_record, is_dir ? 2 + sizeof(DIR_REC) :
  1247.     2 + sizeof(FIL_REC));
  1248. if (error == -EEXIST) {
  1249. delete_entry(dest);
  1250. unlock_entry(dest);
  1251. hfs_cat_put(dest);
  1252. goto restart;
  1253. } else if (error) {
  1254. goto bail3;
  1255. }
  1256. /* update the destination directory */
  1257. update_dir(mdb, new_dir, is_dir, 1);
  1258. } else if (entry != dest) {
  1259. have_distinct:
  1260. /* The destination exists and is not same as source */
  1261. lock_entry(dest);
  1262. if ((dest->state & HFS_DELETED)) {
  1263.         unlock_entry(dest);
  1264. hfs_cat_put(dest);
  1265. goto restart;
  1266. }
  1267. if (dest->type != entry->type) {
  1268. /* can't move a file on top
  1269.    of a dir nor vice versa. */
  1270. error = is_dir ? -ENOTDIR : -EISDIR;
  1271. } else if (is_dir && (dest->u.dir.dirs || dest->u.dir.files)) {
  1272. /* directory to replace is not empty */
  1273. error = -ENOTEMPTY;
  1274. }
  1275. if (error) {
  1276. goto bail2;
  1277. }
  1278. } else {
  1279. /* The destination exists but is same as source */
  1280.         --entry->count;
  1281. dest = NULL;
  1282. }
  1283. /* lock the entry */
  1284. lock_entry(entry);
  1285. if ((entry->state & HFS_DELETED)) {
  1286. error = -ENOENT;
  1287. goto bail1;
  1288. }
  1289. if (dest) {
  1290. /* remove the old entry */
  1291. error = hfs_bdelete(mdb->cat_tree, HFS_BKEY(&entry->key));
  1292. if (error) {
  1293. /* We couldn't remove the entry for the
  1294.    original file, so nothing has changed. */
  1295. goto bail1;
  1296. }
  1297. update_dir(mdb, old_dir, is_dir, -1);
  1298. }
  1299. /* update the thread of the dir/file we're moving */
  1300. if (has_thread) {
  1301. struct hfs_cat_key thd_key;
  1302. struct hfs_brec brec;
  1303. hfs_cat_build_key(entry->cnid, NULL, &thd_key);
  1304. error = hfs_bfind(&brec, mdb->cat_tree,
  1305.   HFS_BKEY(&thd_key), HFS_BFIND_WRITE);
  1306. if (error == -ENOENT) {
  1307. if (is_dir) {
  1308. /* directory w/o a thread! */
  1309. error = -EIO;
  1310. } else {
  1311. /* We were lied to! */
  1312. entry->u.file.flags &= ~HFS_FIL_THD;
  1313. hfs_cat_mark_dirty(entry);
  1314. }
  1315. }
  1316. if (!error) {
  1317. struct hfs_cat_rec *rec = brec.data;
  1318. memcpy(&rec->u.thd.ParID, &new_key->ParID,
  1319.        sizeof(hfs_u32) + sizeof(struct hfs_name));
  1320. hfs_brec_relse(&brec, NULL);
  1321. } else if (error == -ENOENT) {
  1322. error = 0;
  1323. } else if (!dest) {
  1324. /* Nothing was changed */
  1325. unlock_entry(entry);
  1326. goto done;
  1327. } else {
  1328. /* Something went seriously wrong.
  1329.    The dir/file has been deleted. */
  1330. /* XXX try some recovery? */
  1331. delete_entry(entry);
  1332. goto bail1;
  1333. }
  1334. }
  1335. /* TRY to remove the thread for the pre-existing entry */
  1336. if (dest && dest->cnid &&
  1337.     (is_dir || (dest->u.file.flags & HFS_FIL_THD))) {
  1338. struct hfs_cat_key thd_key;
  1339. hfs_cat_build_key(dest->cnid, NULL, &thd_key);
  1340. (void)hfs_bdelete(mdb->cat_tree, HFS_BKEY(&thd_key));
  1341. }
  1342. /* update directories */
  1343. new_dir->modify_date = hfs_time();
  1344. hfs_cat_mark_dirty(new_dir);
  1345. /* update key */
  1346. remove_hash(entry);
  1347. memcpy(&entry->key, new_key, sizeof(*new_key));
  1348. /* KEYDIRTY as case might differ */
  1349. entry->state |= HFS_KEYDIRTY;
  1350. insert_hash(entry);
  1351. hfs_cat_mark_dirty(entry);
  1352. unlock_entry(entry);
  1353. /* delete any pre-existing or place-holder entry */
  1354. if (dest) {
  1355. delete_entry(dest);
  1356. unlock_entry(dest);
  1357. if (removed && dest->cnid) {
  1358. *removed = dest;
  1359. } else {
  1360. hfs_cat_put(dest);
  1361. }
  1362. }
  1363. goto done;
  1364. bail1:
  1365. unlock_entry(entry);
  1366. bail2:
  1367. if (dest) {
  1368. if (!dest->cnid) {
  1369. /* TRY to remove the new entry */
  1370. (void)hfs_bdelete(mdb->cat_tree, HFS_BKEY(new_key));
  1371. update_dir(mdb, new_dir, is_dir, -1);
  1372. bail3:
  1373. delete_entry(dest);
  1374. }
  1375. unlock_entry(dest);
  1376. hfs_cat_put(dest);
  1377. }
  1378. done:
  1379. if (new_dir != old_dir) {
  1380. end_write(old_dir);
  1381. }
  1382. end_write(new_dir);
  1383. spin_lock(&entry_lock);
  1384. mdb->rename_lock = 0; /* XXX: should use atomic_dec */
  1385. hfs_wake_up(&mdb->rename_wait);
  1386. spin_unlock(&entry_lock);
  1387. return error;
  1388. }
  1389. /*
  1390.  * Initialize the hash tables
  1391.  */
  1392. void hfs_cat_init(void)
  1393. {
  1394. int i;
  1395. struct list_head *head = hash_table;
  1396.         i = C_HASHSIZE;
  1397.         do {
  1398.                 INIT_LIST_HEAD(head);
  1399.                 head++;
  1400.                 i--;
  1401.         } while (i);
  1402. }