filesystem.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749
  1. /*
  2. * filesystem.c
  3. *
  4. * Copyright (C) 2016 Aleksandar Andrejevic <theflash@sdf.lonestar.org>
  5. *
  6. * This program is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU Affero General Public License as
  8. * published by the Free Software Foundation, either version 3 of the
  9. * License, or (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU Affero General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Affero General Public License
  17. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include <filesystem.h>
  20. #include <exception.h>
  21. #include <memory.h>
  22. #include <heap.h>
  23. #include <syscalls.h>
  24. static DECLARE_LIST(fs_driver_list);
  25. static DECLARE_LIST(volumes);
  26. static DECLARE_LOCK(fs_driver_list_lock);
  27. static DECLARE_LOCK(volume_list_lock);
  28. static inline int count_delimiters(const char *string)
  29. {
  30. int count = 0;
  31. while ((string = strchr(string, PATH_DELIMITER_CHAR)) != NULL) count++;
  32. return count;
  33. }
  34. mounted_volume_t *get_volume_from_path(const char *path)
  35. {
  36. mounted_volume_t *volume = NULL;
  37. list_entry_t *ptr;
  38. lock_acquire_shared(&volume_list_lock);
  39. for (ptr = volumes.next; ptr != &volumes; ptr = ptr->next)
  40. {
  41. mounted_volume_t *vol = CONTAINER_OF(ptr, mounted_volume_t, list);
  42. int length = strlen(vol->mountpoint);
  43. if (strncmp(path, vol->mountpoint, length) == 0
  44. && (path[length] == '\0' || path[length] == PATH_DELIMITER_CHAR))
  45. {
  46. volume = vol;
  47. break;
  48. }
  49. }
  50. lock_release(&volume_list_lock);
  51. return volume;
  52. }
  53. void report_filesystem_event(const char *path, dword_t type)
  54. {
  55. list_entry_t *ptr;
  56. mounted_volume_t *volume = get_volume_from_path(path);
  57. int path_length = strlen(path);
  58. lock_acquire(&volume->event_watch_list_lock);
  59. for (ptr = volume->event_watch_list.next; ptr != &volume->event_watch_list; ptr = ptr->next)
  60. {
  61. event_watch_entry_t *watch = CONTAINER_OF(ptr, event_watch_entry_t, list);
  62. reference(&watch->directory->header);
  63. int prefix_length = strlen(watch->directory->global->path);
  64. if (strncmp(path, watch->directory->global->path, prefix_length) == 0
  65. && path[prefix_length] == PATH_DELIMITER_CHAR)
  66. {
  67. file_event_t *file_event = __builtin_alloca(sizeof(file_event_t) + path_length);
  68. file_event->type = type;
  69. strcpy(file_event->filename, path);
  70. write_pipe(&watch->pipe, &file_event, sizeof(file_event) + path_length + 1);
  71. }
  72. dereference(&watch->directory->header);
  73. }
  74. lock_release(&volume->event_watch_list_lock);
  75. }
  76. void file_cleanup(file_t *file)
  77. {
  78. lock_acquire(&file->volume->lock);
  79. file->volume->driver->unload_file(file);
  80. lock_release(&file->volume->lock);
  81. file->volume->open_files--;
  82. }
  83. void file_instance_cleanup(file_instance_t *instance)
  84. {
  85. file_t *file = instance->global;
  86. if (instance->watch)
  87. {
  88. ASSERT(file->attributes & FILE_ATTR_DIRECTORY);
  89. ASSERT(instance->watch->directory == instance);
  90. lock_acquire(&file->volume->event_watch_list_lock);
  91. list_remove(&instance->watch->list);
  92. lock_release(&file->volume->event_watch_list_lock);
  93. pipe_cleanup(&instance->watch->pipe.header);
  94. free(instance->watch);
  95. instance->watch = NULL;
  96. }
  97. file->volume->driver->close_file(instance);
  98. if (instance->mode & FILE_MODE_DELETE_ON_CLOSE)
  99. {
  100. if (file->volume->driver->delete_file(file->volume, file->path, FALSE) == ERR_SUCCESS)
  101. {
  102. file->attributes |= FILE_ATTR_DELETED;
  103. }
  104. }
  105. dereference(&file->header);
  106. }
  107. void register_filesystem_driver(fs_driver_t *driver)
  108. {
  109. lock_acquire(&fs_driver_list_lock);
  110. list_append(&fs_driver_list, &driver->list);
  111. lock_release(&fs_driver_list_lock);
  112. }
  113. bool_t unregister_filesystem_driver(fs_driver_t *driver)
  114. {
  115. lock_acquire(&fs_driver_list_lock);
  116. list_remove(&driver->list);
  117. lock_release(&fs_driver_list_lock);
  118. return TRUE;
  119. }
  120. dword_t register_mounted_volume(mounted_volume_t *volume)
  121. {
  122. lock_acquire(&volume_list_lock);
  123. lock_init(&volume->lock);;
  124. volume->open_files = 0;
  125. list_init(&volume->event_watch_list);
  126. lock_init(&volume->event_watch_list_lock);
  127. int delimiters = count_delimiters(volume->mountpoint);
  128. list_entry_t *ptr;
  129. for (ptr = volumes.next; ptr != &volumes; ptr = ptr->next)
  130. {
  131. mounted_volume_t *current = CONTAINER_OF(ptr, mounted_volume_t, list);
  132. if (delimiters >= count_delimiters(current->mountpoint)) break;
  133. }
  134. list_put_before(ptr, &volume->list);
  135. lock_release(&volume_list_lock);
  136. return ERR_SUCCESS;
  137. }
  138. dword_t unregister_mounted_volume(mounted_volume_t *volume)
  139. {
  140. if (volume->open_files > 0) return ERR_BUSY;
  141. lock_acquire(&volume_list_lock);
  142. lock_acquire(&volume->lock);
  143. list_remove(&volume->list);
  144. lock_release(&volume->lock);
  145. lock_release(&volume_list_lock);
  146. return ERR_SUCCESS;
  147. }
  148. dword_t normalize_path(const char *path, char *normalized_path)
  149. {
  150. static const char *block_dev_prefix = "BlockDevices/";
  151. static const char *char_dev_prefix = "CharDevices/";
  152. dword_t ret = ERR_SUCCESS;
  153. char *path_copy;
  154. char *endptr;
  155. if (*path == '#')
  156. {
  157. path_copy = malloc(strlen(path + 1) + strlen(block_dev_prefix) + 1);
  158. strcpy(path_copy, block_dev_prefix);
  159. strcat(path_copy, path + 1);
  160. }
  161. else if (*path == '@')
  162. {
  163. path_copy = malloc(strlen(path + 1) + strlen(char_dev_prefix) + 1);
  164. strcpy(path_copy, char_dev_prefix);
  165. strcat(path_copy, path + 1);
  166. }
  167. else
  168. {
  169. path_copy = strdup(path);
  170. }
  171. char *token;
  172. *normalized_path = '\0';
  173. for (token = strtok_r(path_copy, PATH_DELIMITER_STRING, &endptr);
  174. token != NULL;
  175. token = strtok_r(NULL, PATH_DELIMITER_STRING, &endptr))
  176. {
  177. if (strcmp(token, ".") == 0) continue;
  178. if (strcmp(token, "..") == 0)
  179. {
  180. char *ptr = strrchr(normalized_path, PATH_DELIMITER_CHAR);
  181. if (ptr) *ptr = '\0';
  182. }
  183. if ((strlen(normalized_path) + strlen(token) + 2) > MAX_PATH)
  184. {
  185. ret = ERR_INVALID;
  186. break;
  187. }
  188. if (normalized_path[0]) strcat(normalized_path, PATH_DELIMITER_STRING);
  189. strcat(normalized_path, token);
  190. }
  191. free(path_copy);
  192. return ret;
  193. }
  194. sysret_t syscall_mount(const char *device, const char *mountpoint, const char *filesystem, dword_t flags)
  195. {
  196. dword_t ret = ERR_NOTFOUND;
  197. list_entry_t *i;
  198. char *safe_device;
  199. char *safe_mountpoint;
  200. char *safe_filesystem;
  201. if (get_previous_mode() == USER_MODE)
  202. {
  203. safe_device = copy_user_string(device);
  204. safe_mountpoint = copy_user_string(mountpoint);
  205. safe_filesystem = copy_user_string(filesystem);
  206. }
  207. else
  208. {
  209. safe_device = (char*)device;
  210. safe_mountpoint = (char*)mountpoint;
  211. safe_filesystem = (char*)filesystem;
  212. }
  213. lock_acquire(&fs_driver_list_lock);
  214. for (i = fs_driver_list.next; i != &fs_driver_list; i = i->next)
  215. {
  216. fs_driver_t *fs = CONTAINER_OF(i, fs_driver_t, list);
  217. if (filesystem == NULL || strcmp(fs->name, safe_filesystem) == 0)
  218. {
  219. ret = fs->mount(safe_device, safe_mountpoint, flags);
  220. if (ret == ERR_SUCCESS) break;
  221. }
  222. }
  223. lock_release(&fs_driver_list_lock);
  224. if (get_previous_mode() == USER_MODE)
  225. {
  226. free(safe_device);
  227. free(safe_mountpoint);
  228. free(safe_filesystem);
  229. }
  230. return ret;
  231. }
  232. sysret_t syscall_unmount(const char *mountpoint)
  233. {
  234. lock_acquire(&volume_list_lock);
  235. list_entry_t *ptr;
  236. mounted_volume_t *vol = NULL;
  237. for (ptr = volumes.next; ptr != &volumes; ptr = ptr->next)
  238. {
  239. mounted_volume_t *current = CONTAINER_OF(ptr, mounted_volume_t, list);
  240. if (strcmp(current->mountpoint, mountpoint) == 0)
  241. {
  242. vol = current;
  243. break;
  244. }
  245. }
  246. lock_release(&volume_list_lock);
  247. if (vol->open_files) return ERR_BUSY;
  248. return vol->driver->unmount(vol);
  249. }
  250. dword_t open_file_internal(const char *path, file_instance_t **file_instance, dword_t mode, dword_t attributes)
  251. {
  252. char normalized_path[MAX_PATH];
  253. file_t *file = NULL;
  254. file_instance_t *instance = NULL;
  255. dword_t ret = normalize_path(path, normalized_path);
  256. if (ret != ERR_SUCCESS) return ret;
  257. mounted_volume_t *vol = get_volume_from_path(normalized_path);
  258. if (vol == NULL) return ERR_NOTFOUND;
  259. if (reference_by_name(normalized_path, OBJECT_FILE, (object_t**)&file))
  260. {
  261. if (file->attributes & FILE_ATTR_DELETED)
  262. {
  263. if (!(mode & FILE_MODE_CREATE))
  264. {
  265. dereference(&file->header);
  266. return ERR_NOTFOUND;
  267. }
  268. mode |= FILE_MODE_TRUNCATE;
  269. }
  270. if (((file->global_mode ^ mode) & (FILE_MODE_SHARE_READ | FILE_MODE_SHARE_WRITE))
  271. || (!(file->global_mode & FILE_MODE_SHARE_READ) && (mode & FILE_MODE_READ))
  272. || (!(file->global_mode & FILE_MODE_SHARE_WRITE) && (mode & (FILE_MODE_WRITE | FILE_MODE_TRUNCATE))))
  273. {
  274. dereference(&file->header);
  275. return ERR_FORBIDDEN;
  276. }
  277. }
  278. else
  279. {
  280. file = (file_t*)malloc(sizeof(file_t));
  281. if (file == NULL) return ERR_NOMEMORY;
  282. init_object(&file->header, normalized_path, OBJECT_FILE);
  283. file->volume = vol;
  284. file->path = &file->header.name[strlen(vol->mountpoint)];
  285. if (*file->path == PATH_DELIMITER_CHAR) file->path++;
  286. file->global_mode = mode;
  287. file->attributes = attributes;
  288. ret = vol->driver->load_file(&file);
  289. if (ret != ERR_SUCCESS)
  290. {
  291. free(file->header.name);
  292. free(file);
  293. return ret;
  294. }
  295. ret = create_object(&file->header);
  296. if (ret != ERR_SUCCESS)
  297. {
  298. free(file->header.name);
  299. free(file);
  300. return ret;
  301. }
  302. }
  303. instance = (file_instance_t*)malloc(sizeof(file_instance_t));
  304. if (instance == NULL)
  305. {
  306. dereference(&file->header);
  307. return ERR_NOMEMORY;
  308. }
  309. init_object(&instance->header, NULL, OBJECT_FILE_INSTANCE);
  310. instance->global = file;
  311. instance->mode = mode;
  312. ret = vol->driver->open_file(&instance);
  313. if (ret != ERR_SUCCESS)
  314. {
  315. free(instance);
  316. dereference(&file->header);
  317. return ERR_NOMEMORY;
  318. }
  319. ret = create_object(&instance->header);
  320. if (ret == ERR_SUCCESS)
  321. {
  322. *file_instance = instance;
  323. }
  324. else
  325. {
  326. free(instance);
  327. dereference(&file->header);
  328. }
  329. return ret;
  330. }
  331. sysret_t syscall_open_file(const char *path, handle_t *handle, dword_t mode, dword_t attributes)
  332. {
  333. dword_t ret = ERR_SUCCESS;
  334. file_instance_t *file;
  335. char *safe_path;
  336. handle_t safe_handle = 0;
  337. if (get_previous_mode() == USER_MODE)
  338. {
  339. if (!check_usermode(handle, sizeof(handle_t))) return ERR_BADPTR;
  340. safe_path = copy_user_string(path);
  341. if (safe_path == NULL)
  342. {
  343. ret = ERR_BADPTR;
  344. goto cleanup;
  345. }
  346. }
  347. else safe_path = (char*)path;
  348. ret = open_file_internal(safe_path, &file, mode, attributes);
  349. if (ret != ERR_SUCCESS) goto cleanup;
  350. ret = open_object(&file->header, 0, &safe_handle);
  351. if (ret != ERR_SUCCESS)
  352. {
  353. dereference(&file->header);
  354. goto cleanup;
  355. }
  356. EH_TRY
  357. {
  358. *handle = safe_handle;
  359. }
  360. EH_CATCH
  361. {
  362. syscall_close_object(safe_handle);
  363. ret = ERR_BADPTR;
  364. }
  365. EH_DONE;
  366. cleanup:
  367. if (get_previous_mode() == USER_MODE) free(safe_path);
  368. return ret;
  369. }
  370. sysret_t syscall_delete_file(const char *path)
  371. {
  372. dword_t ret = ERR_SUCCESS;
  373. char normalized_path[MAX_PATH];
  374. char *safe_path;
  375. if (get_previous_mode() == USER_MODE)
  376. {
  377. safe_path = copy_user_string(path);
  378. if (safe_path == NULL) return ERR_NOMEMORY;
  379. }
  380. else
  381. {
  382. safe_path = (char*)path;
  383. }
  384. ret = normalize_path(safe_path, normalized_path);
  385. if (ret != ERR_SUCCESS) goto cleanup;
  386. mounted_volume_t *vol = get_volume_from_path(normalized_path);
  387. if (vol == NULL) return ERR_NOTFOUND;
  388. if (vol->flags & MOUNT_FLAG_READONLY)
  389. {
  390. ret = ERR_WRITEPROT;
  391. goto cleanup;
  392. }
  393. lock_acquire(&vol->lock);
  394. file_t *file = NULL;
  395. reference_by_name(normalized_path, OBJECT_FILE, (object_t**)&file);
  396. char *relative_path = &normalized_path[strlen(vol->mountpoint)];
  397. if (*relative_path == PATH_DELIMITER_CHAR) relative_path++;
  398. ret = vol->driver->delete_file(vol, relative_path, file == NULL);
  399. if (ret == ERR_SUCCESS && file != NULL)
  400. {
  401. file->attributes |= FILE_ATTR_DELETED;
  402. dereference(&file->header);
  403. }
  404. lock_release(&vol->lock);
  405. cleanup:
  406. if (get_previous_mode() == USER_MODE) free(safe_path);
  407. return ret;
  408. }
  409. sysret_t syscall_query_file(handle_t handle, file_info_type_t type, void *buffer, size_t size)
  410. {
  411. dword_t ret = ERR_SUCCESS;
  412. void *safe_buffer;
  413. file_instance_t *file = NULL;
  414. if (get_previous_mode() == USER_MODE)
  415. {
  416. if (!check_usermode(buffer, size)) return ERR_BADPTR;
  417. safe_buffer = malloc(size);
  418. if (safe_buffer == NULL) return ERR_NOMEMORY;
  419. memset(safe_buffer, 0, size);
  420. }
  421. else
  422. {
  423. safe_buffer = buffer;
  424. }
  425. if (!reference_by_handle(handle, OBJECT_FILE_INSTANCE, (object_t**)&file)) return ERR_INVALID;
  426. lock_acquire_shared(&file->global->volume->lock);
  427. switch (type)
  428. {
  429. case FILE_INFO_ATTRIBUTES:
  430. if (size >= sizeof(dword_t)) *((dword_t*)safe_buffer) = file->global->attributes;
  431. else ret = ERR_SMALLBUF;
  432. break;
  433. case FILE_INFO_NAME:
  434. if (size >= (strlen(file->global->header.name) + 1)) strncpy(safe_buffer, file->global->header.name, size);
  435. else ret = ERR_SMALLBUF;
  436. break;
  437. case FILE_INFO_TIME:
  438. ret = ERR_NOSYSCALL; // TODO
  439. break;
  440. case FILE_INFO_SIZE:
  441. if (size >= sizeof(qword_t)) *((qword_t*)safe_buffer) = file->global->size;
  442. else ret = ERR_SMALLBUF;
  443. break;
  444. case FILE_INFO_OWNER:
  445. if (size >= sizeof(dword_t)) *((dword_t*)safe_buffer) = file->global->owner_uid;
  446. else ret = ERR_SMALLBUF;
  447. break;
  448. default:
  449. ret = ERR_INVALID;
  450. }
  451. lock_release(&file->global->volume->lock);
  452. if (get_previous_mode() == USER_MODE)
  453. {
  454. EH_TRY memcpy(buffer, safe_buffer, size);
  455. EH_CATCH ret = ERR_BADPTR;
  456. EH_DONE;
  457. }
  458. if (file) dereference(&file->header);
  459. if (get_previous_mode() == USER_MODE) free(safe_buffer);
  460. return ret;
  461. }
  462. sysret_t syscall_set_file(handle_t handle, file_info_type_t set_type, void *buffer, size_t size)
  463. {
  464. void *safe_buffer;
  465. file_instance_t *file = NULL;
  466. if (get_previous_mode() == USER_MODE)
  467. {
  468. if (!check_usermode(buffer, size)) return ERR_BADPTR;
  469. safe_buffer = malloc(size);
  470. if (safe_buffer == NULL) return ERR_NOMEMORY;
  471. memcpy(safe_buffer, buffer, size);
  472. }
  473. else
  474. {
  475. safe_buffer = buffer;
  476. }
  477. if (!reference_by_handle(handle, OBJECT_FILE_INSTANCE, (object_t**)&file)) return ERR_INVALID;
  478. lock_acquire(&file->global->volume->lock);
  479. dword_t ret = file->global->volume->driver->set_file(file->global, set_type, safe_buffer, size);
  480. lock_release(&file->global->volume->lock);
  481. if (file) dereference(&file->header);
  482. if (get_previous_mode() == USER_MODE) free(safe_buffer);
  483. return ret;
  484. }
  485. sysret_t syscall_list_directory(handle_t handle, char *filename, bool_t continue_scan)
  486. {
  487. file_instance_t *directory;
  488. char safe_filename[MAX_PATH];
  489. if (!reference_by_handle(handle, OBJECT_FILE_INSTANCE, (object_t**)&directory)) return ERR_INVALID;
  490. lock_acquire_shared(&directory->global->volume->lock);
  491. dword_t ret = directory->global->volume->driver->list_dir(directory, safe_filename, continue_scan);
  492. lock_release(&directory->global->volume->lock);
  493. if (ret == ERR_SUCCESS)
  494. {
  495. if (get_previous_mode() != USER_MODE || check_usermode(filename, strlen(safe_filename) + 1))
  496. {
  497. EH_TRY strcpy(filename, safe_filename);
  498. EH_CATCH ret = ERR_BADPTR;
  499. EH_DONE;
  500. }
  501. else
  502. {
  503. ret = ERR_BADPTR;
  504. }
  505. }
  506. return ret;
  507. }
  508. sysret_t syscall_read_file(handle_t handle, void *buffer, qword_t offset, size_t size, size_t *bytes_read)
  509. {
  510. dword_t ret;
  511. file_instance_t *file;
  512. dword_t read_count = 0;
  513. void *safe_buffer = NULL;
  514. if (get_previous_mode() == USER_MODE)
  515. {
  516. if (!check_usermode(buffer, size)) return ERR_BADPTR;
  517. if (!check_usermode(bytes_read, sizeof(dword_t))) return ERR_BADPTR;
  518. ret = pin_memory(buffer, &safe_buffer, size, FALSE);
  519. if (ret != ERR_SUCCESS) return ret;
  520. }
  521. else
  522. {
  523. safe_buffer = buffer;
  524. }
  525. if (!reference_by_handle(handle, OBJECT_FILE_INSTANCE, (object_t**)&file)) return ERR_INVALID;
  526. if (!(file->mode & FILE_MODE_READ))
  527. {
  528. ret = ERR_FORBIDDEN;
  529. goto cleanup;
  530. }
  531. lock_acquire_shared(&file->global->volume->lock);
  532. ret = file->global->volume->driver->read_file(file, safe_buffer, offset, size, &read_count);
  533. lock_release(&file->global->volume->lock);
  534. cleanup:
  535. EH_TRY *bytes_read = read_count;
  536. EH_CATCH ret = ERR_BADPTR;
  537. EH_DONE;
  538. if (get_previous_mode() == USER_MODE) unmap_memory(safe_buffer);
  539. dereference(&file->header);
  540. return ret;
  541. }
  542. sysret_t syscall_write_file(handle_t handle, const void *buffer, qword_t offset, size_t size, dword_t *bytes_written)
  543. {
  544. dword_t ret;
  545. file_instance_t *file;
  546. dword_t written_count = 0;
  547. void *safe_buffer = NULL;
  548. if (get_previous_mode() == USER_MODE)
  549. {
  550. if (!check_usermode(buffer, size)) return ERR_BADPTR;
  551. if (!check_usermode(bytes_written, sizeof(dword_t))) return ERR_BADPTR;
  552. ret = pin_memory(buffer, &safe_buffer, size, TRUE);
  553. if (ret != ERR_SUCCESS) return ret;
  554. }
  555. else
  556. {
  557. safe_buffer = (void*)buffer;
  558. }
  559. if (!reference_by_handle(handle, OBJECT_FILE_INSTANCE, (object_t**)&file)) return ERR_INVALID;
  560. if (!(file->mode & FILE_MODE_WRITE))
  561. {
  562. ret = ERR_FORBIDDEN;
  563. goto cleanup;
  564. }
  565. if (file->global->volume->flags & MOUNT_FLAG_READONLY)
  566. {
  567. ret = ERR_WRITEPROT;
  568. goto cleanup;
  569. }
  570. lock_acquire(&file->global->volume->lock);
  571. ret = file->global->volume->driver->write_file(file, safe_buffer, offset, size, &written_count);
  572. lock_release(&file->global->volume->lock);
  573. EH_TRY *bytes_written = written_count;
  574. EH_DONE;
  575. cleanup:
  576. if (get_previous_mode() == USER_MODE) unmap_memory(safe_buffer);
  577. dereference(&file->header);
  578. return ret;
  579. }
  580. sysret_t syscall_wait_directory_event(handle_t handle, dword_t event_mask, file_event_t *buffer, size_t size, dword_t timeout)
  581. {
  582. file_instance_t *directory;
  583. if (get_previous_mode() == USER_MODE && !check_usermode(buffer, size)) return ERR_BADPTR;
  584. if (!reference_by_handle(handle, OBJECT_FILE_INSTANCE, (object_t**)&directory)) return ERR_INVALID;
  585. if (!(directory->global->attributes & FILE_ATTR_DIRECTORY))
  586. {
  587. dereference(&directory->header);
  588. return ERR_ISNOTDIR;
  589. }
  590. if (directory->watch == NULL)
  591. {
  592. event_watch_entry_t *watch = (event_watch_entry_t*)malloc(sizeof(event_watch_entry_t));
  593. watch->directory = directory;
  594. init_pipe(&watch->pipe, PIPE_MESSAGE);
  595. mounted_volume_t *volume = directory->global->volume;
  596. lock_acquire(&volume->event_watch_list_lock);
  597. list_append(&volume->event_watch_list, &watch->list);
  598. if (!__sync_bool_compare_and_swap(&directory->watch, NULL, watch))
  599. {
  600. list_remove(&watch->list);
  601. free(watch);
  602. }
  603. lock_release(&volume->event_watch_list_lock);
  604. }
  605. directory->watch->event_mask = event_mask;
  606. dword_t ret = read_pipe(&directory->watch->pipe, buffer, &size, timeout);
  607. dereference(&directory->header);
  608. return ret;
  609. }