Merge branch 'master' into sam460ex

This commit is contained in:
François Revol 2013-03-12 03:24:15 +01:00
commit 8b72ce2651
167 changed files with 17634 additions and 301 deletions

View File

@ -1338,6 +1338,7 @@ if $(HAIKU_NO_WERROR) != 1 {
EnableWerror src add-ons kernel file_systems layers ;
EnableWerror src add-ons kernel file_systems netfs ;
EnableWerror src add-ons kernel file_systems nfs ;
EnableWerror src add-ons kernel file_systems nfs4 ;
# EnableWerror src add-ons kernel file_systems ntfs ;
EnableWerror src add-ons kernel file_systems packagefs ;
EnableWerror src add-ons kernel file_systems ramfs ;
@ -1347,6 +1348,7 @@ if $(HAIKU_NO_WERROR) != 1 {
EnableWerror src add-ons kernel generic ;
# EnableWerror src add-ons kernel network datalink_protocols ;
EnableWerror src add-ons kernel network devices ;
EnableWerror src add-ons kernel network dns_resolver ;
EnableWerror src add-ons kernel network notifications ;
EnableWerror src add-ons kernel network ppp ;
EnableWerror src add-ons kernel network protocols ;

View File

@ -67,7 +67,8 @@ PRIVATE_SYSTEM_LIBS =
SYSTEM_SERVERS = app_server cddb_daemon debug_server input_server midi_server
mount_server net_server notification_server power_daemon print_server
print_addon_server registrar syslog_daemon
print_addon_server registrar syslog_daemon dns_resolver_server
nfs4_idmapper_server
;
SYSTEM_NETWORK_DEVICES = ethernet loopback ;
@ -104,7 +105,7 @@ SYSTEM_ADD_ONS_DRIVERS_NET = 3com atheros813x ar81xx attansic_l1 attansic_l2
SYSTEM_ADD_ONS_BUS_MANAGERS = [ FFilterByBuildFeatures
ata@ata pci ps2 isa scsi config_manager usb
] ;
SYSTEM_ADD_ONS_FILE_SYSTEMS = bfs iso9660 attribute_overlay write_overlay ;
SYSTEM_ADD_ONS_FILE_SYSTEMS = bfs iso9660 nfs4 attribute_overlay write_overlay ;
# modules
AddFilesToHaikuImage system add-ons kernel bus_managers
@ -398,6 +399,7 @@ AddFilesToHaikuImage system add-ons input_server devices
: <input>keyboard <input>mouse <input>tablet <input>wacom ;
AddFilesToHaikuImage system add-ons kernel network
: <net>notifications stack ;
AddFilesToHaikuImage system add-ons kernel network : dns_resolver ;
AddFilesToHaikuImage system add-ons kernel network devices
: $(SYSTEM_NETWORK_DEVICES) ;
AddFilesToHaikuImage system add-ons kernel network datalink_protocols

View File

@ -87,7 +87,7 @@ SYSTEM_SERVERS = [ FFilterByBuildFeatures
app_server cddb_daemon debug_server input_server keystore_server mail_daemon
media_addon_server media_server midi_server mount_server net_server
notification_server power_daemon print_server print_addon_server registrar
syslog_daemon
syslog_daemon dns_resolver_server nfs4_idmapper_server
] ;
SYSTEM_NETWORK_DEVICES = ethernet loopback ;
@ -183,7 +183,7 @@ SYSTEM_ADD_ONS_BUS_MANAGERS = [ FFilterByBuildFeatures
ata@ata pci ps2@x86 isa@x86
ide@ide scsi config_manager agp_gart usb firewire acpi@x86
] ;
SYSTEM_ADD_ONS_FILE_SYSTEMS = bfs btrfs cdda exfat ext2 fat iso9660 nfs
SYSTEM_ADD_ONS_FILE_SYSTEMS = bfs btrfs cdda exfat ext2 fat iso9660 nfs nfs4
attribute_overlay write_overlay ntfs reiserfs udf googlefs ;
# wifi firmware
@ -663,6 +663,7 @@ AddFilesToHaikuImage system add-ons input_server filters
: screen_saver shortcut_catcher ;
AddFilesToHaikuImage system add-ons kernel network
: <net>notifications stack ;
AddFilesToHaikuImage system add-ons kernel network : dns_resolver ;
AddFilesToHaikuImage system add-ons kernel network devices
: $(SYSTEM_NETWORK_DEVICES) ;
AddFilesToHaikuImage system add-ons kernel network datalink_protocols

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,2 +1,2 @@
1 portuguese (brazil) x-vnd.Haiku-IntelDiskAddOn 4191422532
Active partition BFS_Creation_Parameter Partição ativa
1 portuguese (brazil) x-vnd.Haiku-IntelDiskAddOn 946918966
Active partition PrimaryPartitionEditor Partição ativa

View File

@ -0,0 +1,2 @@
1 portuguese (brazil) x-vnd.Haiku-NTFSDiskAddOn 25755486
Name: NTFS_Initialize_Parameter Nome:

View File

@ -1,11 +1,14 @@
1 polish x-vnd.Haiku-DriveSetup 644135944
1 polish x-vnd.Haiku-DriveSetup 1752326393
DriveSetup System name DriveSetup
Cancel AbstractParametersPanel Anuluj
Delete MainWindow Usuń
Are you sure you want to write the changes back to disk now?\n\nAll data on the selected partition will be irretrievably lost if you do so! MainWindow Na pewno chcesz zapisać zmiany na dysk?\n\nWszystkie dane na wybranej partycji bedą bezpowrotnie utracone!
Rescan MainWindow Przeskanuj
OK MainWindow OK
Could not aquire partitioning information. MainWindow Nie można uzyskać informacji na temat partycji.
There's no space on the partition where a child partition could be created. MainWindow Brak miejsca na partycji, gdzie można by utworzyć zagnieżdzoną partycje.
Initialize InitializeParametersPanel Inicjalizacja
OK AbstractParametersPanel OK
<empty> PartitionList <pusty>
Unable to find the selected partition by ID. MainWindow Nie można znaleźć wybranej partycji po ID.
Select a partition from the list below. DiskView Proszę wybrać partycje z listy poniżej.

View File

@ -1,11 +1,14 @@
1 portuguese (brazil) x-vnd.Haiku-DriveSetup 644135944
1 portuguese (brazil) x-vnd.Haiku-DriveSetup 3775412465
DriveSetup System name Configuração de Unidade
Cancel AbstractParametersPanel Cancelar
Delete MainWindow Excluir
Are you sure you want to write the changes back to disk now?\n\nAll data on the selected partition will be irretrievably lost if you do so! MainWindow Tem certeza que deseja aplicar todas as alterações agora?\n\nTodos os dados na partição selecionada serão perdidos de forma irrecuperável se continuar!
Rescan MainWindow Re-examinar
OK MainWindow OK
Could not aquire partitioning information. MainWindow Não foi possível obter informações sobre a divisão em partições
There's no space on the partition where a child partition could be created. MainWindow Não existe espaço suficiente na partição para criar uma partição dentro dela.
Initialize InitializeParametersPanel Inicializar
OK AbstractParametersPanel OK
<empty> PartitionList <vazio>
Unable to find the selected partition by ID. MainWindow Não foi possível encontrar a partição selecionada pelo ID.
Select a partition from the list below. DiskView Selecione a partição a partir da lista abaixo.
@ -15,6 +18,7 @@ The selected disk is read-only. MainWindow O disco selecionado está marcado co
Are you sure you want to format the partition \"%s\"? You will be asked again before changes are written to the disk. MainWindow Deseja realmente formatar a partição \"%s\"? Você será consultado novamente antes que as alterações sejam gravadas no disco.
Could not mount partition %s. MainWindow Não foi possível montar a partição %s.
The partition %s has been successfully formatted.\n MainWindow A partição %s foi formatada com sucesso.\n
Change parameters MainWindow Modificar parâmetros
The partition %s is already unmounted. MainWindow A partição %s já está desmontada.
Failed to delete the partition. No changes have been written to disk. MainWindow Falha ao excluir a partição. Nenhuma alteração foi gravada no disco.
Could not delete the selected partition. MainWindow Não foi possível excluir a partição selecionada.
@ -33,38 +37,53 @@ Write changes MainWindow Gravar alterações
There was an error preparing the disk for modifications. MainWindow Ocorreu um erro ao preparar o disco para modificações.
The partition %s is already mounted. MainWindow A partição %s já está montada.
Are you sure you want to format the partition? You will be asked again before changes are written to the disk. MainWindow Deseja realmente formatar a partição? Você será consultado novamente antes que as alterações sejam gravadas no disco.
Partition name: ChangeParametersPanel Nome da partição:
Change ChangeParametersPanel Modificar
Are you sure you want to write the changes back to disk now?\n\nAll data on the disk %s will be irretrievably lost if you do so! MainWindow Tem certeza que deseja aplicar todas as alterações agora?\n\nTodos os dados na partição selecionada serão perdidos de forma irrecuperável se continuar!
Are you sure you want to delete the selected partition?\n\nAll data on the partition will be irretrievably lost if you do so! MainWindow Tem certeza que deseja apagar a partição selecionada?\n\nTodos os dados na partição serão perdidos de forma irrecuperável se continuar!
Create… MainWindow Criar...
Disk system \"%s\"\" not found! MainWindow Disco de sistema \"%s\"\" não encontrado!
The disk has been successfully initialized.\n MainWindow O disco foi inicializado com sucesso.\n
Could not unmount partition %s. MainWindow Não foi possível desmontar a partição %s.
Failed to change the parameters of the partition. No changes have been written to disk. MainWindow Falha ao modificar os parâmetros da partição. Nenhuma mudança foi gravada no disco.
Failed to format the partition %s!\n MainWindow Falha ao formatar a partição %s!\n
Mount MainWindow Montar
Partition type PartitionList Tipo de partição
Are you sure you want to format a raw disk? (most people initialize the disk with a partitioning system first) You will be asked again before changes are written to the disk. MainWindow Deseja realmente formatar um disco não preparado? (a maioria das pessoas inicializa o disco com um sistema de particionamento primeiro) Você será consultado novamente antes que as alterações sejam gravadas no disco.
The panel experienced a problem! MainWindow Ocorreu um problema com a janela de diálogo!
Change parameters… MainWindow Modificar parâmetros…
Device PartitionList Dispositivo
Disk MainWindow Disco
Are you sure you want to initialize the selected disk? All data will be lost. You will be asked again before changes are written to the disk.\n MainWindow Deseja realmente inicializar o disco selecionado? Todos os dados serão perdidos. Você será consultado novamente antes das alterações serem gravados no disco.\n
Partition size CreateParametersPanel Tamanho da partição
Device DiskView Dispositivo
Active PartitionList Ativo
Volume name PartitionList Nome do volume
Continue MainWindow Continuar
Cannot delete the selected partition. MainWindow Não foi posível deletar a partição selecionada.
Mount all MainWindow Montar tudo
End: %s Support Fim: %s
The panel could not return successfully. MainWindow A janela de diálogo pode não responder adequadamente.
Cancel MainWindow Cancelar
Delete partition MainWindow Excluir partição
Are you sure you want to change parameters of the selected partition?\n\nThe partition may no longer be recognized by other operating systems anymore! MainWindow Está seguro que deseja modificar os parâmetros da partição selecionada?\n\nA partição pode não mais ser reconhecida por outros sistemas operacionais!
Eject MainWindow Ejetar
Partition MainWindow Partição
Validation of the given parameters failed. MainWindow A validação dos parâmetros dados falhou.
Create CreateParametersPanel Criar
File system PartitionList Sistema de arquivos
Validation of the given creation parameters failed. MainWindow A validação dos parâmetros de criação inseridas falhou.
Partition type: ChangeParametersPanel Tipo de partição:
Size PartitionList Tamanho
Wipe (not implemented) MainWindow Limpar (não implementado)
Validation of the given initialization parameters failed. MainWindow A validação dos parâmetros de criação inseridas falhou.
The selected partition does not contain a partitioning system. MainWindow A partição selecionada não contém um sistema de partições.
Offset: %s Support Deslocamento: %s
Are you sure you want to write the changes back to disk now?\n\nAll data on the partition %s will be irretrievably lost if you do so! MainWindow Tem certeza que deseja aplicar todas as alterações agora?\n\nTodos os dados na partição selecionada serão perdidos de forma irrecuperável se continuar!
The partition %s is currently mounted. MainWindow A partição %s está atualmente montada.
Surface test (not implemented) MainWindow Teste de superfície (não implementado)
Format MainWindow Formatar
Could not change the parameters of the selected partition. MainWindow Não foi possível modificar os parâmetros da partição selecionada.
Parameters PartitionList Parâmetros
Creation of the partition has failed. MainWindow A criação da partição selecionada falhou.
The currently selected partition is not empty. MainWindow A partição selecionada não está vazia.

View File

@ -1,4 +1,4 @@
1 portuguese (brazil) x-vnd.Haiku-FontDemo 1300625863
1 portuguese (brazil) x-vnd.Haiku-FontDemo 3522850500
Outline: ControlView Contorno:
Size: 50 ControlView Tamanho: 50
Stop cycling ControlView Parar ciclo
@ -14,6 +14,7 @@ Rotation: 0 ControlView Rotação: 0
Drawing mode: ControlView Modo de desenho:
Haiku, Inc. ControlView Haiku, Inc.
Controls FontDemo Controles
FontDemo System name Demonstração de Fonte
Outline: %d ControlView Contorno: %d
Text: ControlView Texto:
Antialiased text ControlView Texto com antisserrilhamento (suavização)

View File

@ -1,4 +1,4 @@
1 portuguese (brazil) x-vnd.Haiku-LaunchBox 3016105370
1 portuguese (brazil) x-vnd.Haiku-LaunchBox 3692177981
New LaunchBox Novo
Set description… LaunchBox Editar descrição...
Vertical layout LaunchBox Layout vertical
@ -6,6 +6,7 @@ OK LaunchBox OK
Pad 1 LaunchBox Barra 1
last chance LaunchBox última chance
Quit LaunchBox Sair
Open containing folder LaunchBox Abrir conteúdo da pasta
Clear button LaunchBox Botão limpar
LaunchBox System name LaunchBox
Ignore double-click LaunchBox Ignorar clique duplo

View File

@ -1,4 +1,4 @@
1 belarusian x-vnd.Haiku-ShowImage 886873119
1 belarusian x-vnd.Haiku-ShowImage 4011843330
Use as background… Menus Ужыць як фон…
File Menus Файл
Slide delay Menus Затрымка слайду
@ -25,7 +25,6 @@ The document '%s' (page %d) has been changed. Do you want to close the document?
Leave full screen Menus Пакінуць рэжым поўнага экрана
Close Menus Закрыць
Close ClosePrompt Закрыць
Undo Menus Адмяніць
Resize to (in 1/72 inches): PrintOptionsWindow Змяніць памер (у 1/72 дзюйма):
Rating Menus Рэйтынг
Flip left to right Menus Адлюстраваць злева направа

View File

@ -1,4 +1,4 @@
1 german x-vnd.Haiku-ShowImage 886873119
1 german x-vnd.Haiku-ShowImage 4011843330
Use as background… Menus Als Hintergrund verwenden…
File Menus Datei
Slide delay Menus Verzögerung
@ -25,7 +25,6 @@ The document '%s' (page %d) has been changed. Do you want to close the document?
Leave full screen Menus Vollbild verlassen
Close Menus Schließen
Close ClosePrompt Schließen
Undo Menus Rückgängig
Resize to (in 1/72 inches): PrintOptionsWindow Größe ändern zu (in 1/72 Zoll):
Rating Menus Bewertung
Flip left to right Menus Horizontal spiegeln

View File

@ -1,4 +1,4 @@
1 greek, modern (1453-) x-vnd.Haiku-ShowImage 886873119
1 greek, modern (1453-) x-vnd.Haiku-ShowImage 4011843330
Use as background… Menus Ορισμός ως φόντου επιφάνειας εργασίας...
File Menus Αρχείο
Slide delay Menus Καθυστέρηση παρουσίασης
@ -25,7 +25,6 @@ The document '%s' (page %d) has been changed. Do you want to close the document?
Leave full screen Menus Εγκατάλειψη πλήρους οθόνης
Close Menus Κλείσιμο
Close ClosePrompt Κλείσιμο
Undo Menus Αναίρεση
Resize to (in 1/72 inches): PrintOptionsWindow Αλλαγή μεγέθους σε (στο 1/72 ίντσες):
Rating Menus Βαθμολογία
Flip left to right Menus Οριζόντια αναστροφή

View File

@ -1,4 +1,4 @@
1 finnish x-vnd.Haiku-ShowImage 886873119
1 finnish x-vnd.Haiku-ShowImage 4011843330
Use as background… Menus Käytä taustana…
File Menus Tiedosto
Slide delay Menus Diaviive
@ -25,7 +25,6 @@ The document '%s' (page %d) has been changed. Do you want to close the document?
Leave full screen Menus Jätä kokoruututila
Close Menus Sulje
Close ClosePrompt Sulje
Undo Menus Peru
Resize to (in 1/72 inches): PrintOptionsWindow Skaalaa kokoon (1/72 tuumissa):
Rating Menus Arvosana
Flip left to right Menus Käännä ympäri vasemmalta oikealle

View File

@ -1,4 +1,4 @@
1 french x-vnd.Haiku-ShowImage 886873119
1 french x-vnd.Haiku-ShowImage 4011843330
Use as background… Menus Utiliser comme fond d'écran…
File Menus Fichier
Slide delay Menus Délai de diaporama
@ -25,7 +25,6 @@ The document '%s' (page %d) has been changed. Do you want to close the document?
Leave full screen Menus Sortie du plein écran
Close Menus Fermer
Close ClosePrompt Fermer
Undo Menus Annuler
Resize to (in 1/72 inches): PrintOptionsWindow Redimensionner (en 1/72 pouces) :
Rating Menus Évaluation
Flip left to right Menus Mirroir vertical

View File

@ -1,4 +1,4 @@
1 hindi x-vnd.Haiku-ShowImage 886873119
1 hindi x-vnd.Haiku-ShowImage 4011843330
Use as background… Menus पृष्ठभूमि के रूप में प्रयोग करें...
File Menus फ़ाइल
Slide delay Menus स्लाइड मे देरी
@ -25,7 +25,6 @@ The document '%s' (page %d) has been changed. Do you want to close the document?
Leave full screen Menus फूल स्क्रीन को छोड़ें
Close Menus बंद करें
Close ClosePrompt बंद करें
Undo Menus पूर्ववत्
Resize to (in 1/72 inches): PrintOptionsWindow आकार बदलें (1/72 inches में):
Rating Menus रेटिंग
Flip left to right Menus फ्लिप बाएँ से दाएँ करें

View File

@ -1,4 +1,4 @@
1 hungarian x-vnd.Haiku-ShowImage 886873119
1 hungarian x-vnd.Haiku-ShowImage 4011843330
Use as background… Menus Beállítás háttérnek…
File Menus Fájl
Slide delay Menus Képváltás közti szünet
@ -25,7 +25,6 @@ The document '%s' (page %d) has been changed. Do you want to close the document?
Leave full screen Menus Kilépés a teljes képernyős módból
Close Menus Bezárás
Close ClosePrompt Bezárás
Undo Menus Visszavonás
Resize to (in 1/72 inches): PrintOptionsWindow Átméretezés (1/72 colban):
Rating Menus Értékelés
Flip left to right Menus Balról jobbra tükrözés

View File

@ -1,4 +1,4 @@
1 japanese x-vnd.Haiku-ShowImage 886873119
1 japanese x-vnd.Haiku-ShowImage 4011843330
Use as background… Menus デスクトップの背景にする…
File Menus ファイル
Slide delay Menus スライド間隔
@ -25,7 +25,6 @@ The document '%s' (page %d) has been changed. Do you want to close the document?
Leave full screen Menus 全画面表示から戻る
Close Menus 閉じる
Close ClosePrompt 閉じる
Undo Menus 元に戻す
Resize to (in 1/72 inches): PrintOptionsWindow リサイズ (1/72 インチ)
Rating Menus 評価
Flip left to right Menus 左右反転

View File

@ -1,4 +1,4 @@
1 lithuanian x-vnd.Haiku-ShowImage 886873119
1 lithuanian x-vnd.Haiku-ShowImage 4011843330
Use as background… Menus Naudoti kaip darbalaukio foną…
File Menus Failas
Slide delay Menus Skaidrių keitimo dažnis
@ -25,7 +25,6 @@ The document '%s' (page %d) has been changed. Do you want to close the document?
Leave full screen Menus Normalioji veiksena
Close Menus Užverti
Close ClosePrompt Užverti
Undo Menus Atšaukti
Resize to (in 1/72 inches): PrintOptionsWindow Keisti dydį (po 1/72 colio):
Rating Menus Įvertinimas
Flip left to right Menus Apversti horizontaliai

View File

@ -1,4 +1,4 @@
1 dutch; flemish x-vnd.Haiku-ShowImage 886873119
1 dutch; flemish x-vnd.Haiku-ShowImage 4011843330
Use as background… Menus Gebruik als achtergrond…
File Menus Bestand
Slide delay Menus Dia-vertraging
@ -25,7 +25,6 @@ The document '%s' (page %d) has been changed. Do you want to close the document?
Leave full screen Menus Volledig scherm verlaten
Close Menus Sluiten
Close ClosePrompt Sluit
Undo Menus Ongedaan maken
Resize to (in 1/72 inches): PrintOptionsWindow Omvormen naar (in eenheden van 1/72 inch):
Rating Menus Waardering
Flip left to right Menus Omklappen van links naar rechts

View File

@ -1,4 +1,4 @@
1 polish x-vnd.Haiku-ShowImage 886873119
1 polish x-vnd.Haiku-ShowImage 4011843330
Use as background… Menus Użyj jako tapety…
File Menus Plik
Slide delay Menus Opóźnienie
@ -25,7 +25,6 @@ The document '%s' (page %d) has been changed. Do you want to close the document?
Leave full screen Menus Opuść pełny ekran
Close Menus Zamknij
Close ClosePrompt Zamknij
Undo Menus Cofnij
Resize to (in 1/72 inches): PrintOptionsWindow Ustaw rozmiar (w 1/72 cala):
Rating Menus Ocena
Flip left to right Menus Odbij z lewej na prawą

View File

@ -1,4 +1,4 @@
1 portuguese (brazil) x-vnd.Haiku-ShowImage 886873119
1 portuguese (brazil) x-vnd.Haiku-ShowImage 4011843330
Use as background… Menus Utilizar como plano de fundo…
File Menus Arquivo
Slide delay Menus Atraso de deslizamento
@ -25,7 +25,6 @@ The document '%s' (page %d) has been changed. Do you want to close the document?
Leave full screen Menus Sair da tela cheia
Close Menus Fechar
Close ClosePrompt Fechar
Undo Menus Desfazer
Resize to (in 1/72 inches): PrintOptionsWindow Redimensionar para (em 1/72 polegadas):
Rating Menus Classificação
Flip left to right Menus Inverter da esquerda para direita

View File

@ -1,4 +1,4 @@
1 romanian x-vnd.Haiku-ShowImage 2010609106
1 romanian x-vnd.Haiku-ShowImage 840612021
Use as background… Menus Utilizează ca fundal...
File Menus Fișier
Slide delay Menus Întârziere imagine
@ -21,7 +21,6 @@ Could not load image! Either the file or an image translator for it does not exi
First page Menus Prima pagină
Close Menus Închide
Close ClosePrompt Închide
Undo Menus Refă
Resize to (in 1/72 inches): PrintOptionsWindow Redimensionează la (în 1/72 țoli):
Flip left to right Menus Inversează stânga cu dreapta
Show caption in full screen mode Menus Afișează legendă în modul ecran complet

View File

@ -1,4 +1,4 @@
1 russian x-vnd.Haiku-ShowImage 886873119
1 russian x-vnd.Haiku-ShowImage 4011843330
Use as background… Menus Сделать фоном рабочего стола…
File Menus Файл
Slide delay Menus Задержка слайд шоу
@ -25,7 +25,6 @@ The document '%s' (page %d) has been changed. Do you want to close the document?
Leave full screen Menus Выйти из полного экрана
Close Menus Закрыть
Close ClosePrompt Закрыть
Undo Menus Вернуть
Resize to (in 1/72 inches): PrintOptionsWindow Изменить размер (1/72 дюйма):
Rating Menus Рейтинг
Flip left to right Menus Повернуть слева направо

View File

@ -1,4 +1,4 @@
1 slovak x-vnd.Haiku-ShowImage 886873119
1 slovak x-vnd.Haiku-ShowImage 4011843330
Use as background… Menus Použiť ako pozadie…
File Menus Súbor
Slide delay Menus Oneskorenie snímku
@ -25,7 +25,6 @@ The document '%s' (page %d) has been changed. Do you want to close the document?
Leave full screen Menus Opustiť celoobrazovkový režim
Close Menus Zatvoriť
Close ClosePrompt Zatvoriť
Undo Menus Vrátiť späť
Resize to (in 1/72 inches): PrintOptionsWindow Zmeniť veľkosť na (v 1/72 palca):
Rating Menus Hodnotenie
Flip left to right Menus Obrátiť zľava doprava

View File

@ -1,4 +1,4 @@
1 swedish x-vnd.Haiku-ShowImage 886873119
1 swedish x-vnd.Haiku-ShowImage 4011843330
Use as background… Menus Använd som bakgrund…
File Menus Arkiv
Slide delay Menus Bildspelsfördröjning
@ -25,7 +25,6 @@ The document '%s' (page %d) has been changed. Do you want to close the document?
Leave full screen Menus Lämna fullskärmsläge
Close Menus Stäng
Close ClosePrompt Stäng
Undo Menus Ångra
Resize to (in 1/72 inches): PrintOptionsWindow Ändra storlek till (i måttenheten 1/72 tum):
Rating Menus Betyg
Flip left to right Menus Vänd åt sidan

View File

@ -1,4 +1,4 @@
1 ukrainian x-vnd.Haiku-ShowImage 886873119
1 ukrainian x-vnd.Haiku-ShowImage 4011843330
Use as background… Menus Використати як тло…
File Menus Файл
Slide delay Menus Затримка слайда
@ -25,7 +25,6 @@ The document '%s' (page %d) has been changed. Do you want to close the document?
Leave full screen Menus Вийти з повноекранного режиму
Close Menus Закрити
Close ClosePrompt Закрити
Undo Menus Відмінити
Resize to (in 1/72 inches): PrintOptionsWindow Змінити розмір (в 1/72 дюйма):
Rating Menus Оцінка
Flip left to right Menus Пересунути горизонтально

View File

@ -1,4 +1,4 @@
1 english x-vnd.Haiku-ShowImage 886873119
1 english x-vnd.Haiku-ShowImage 4011843330
Use as background… Menus 设置为桌面背景…
File Menus 文件
Slide delay Menus 幻灯片延迟
@ -25,7 +25,6 @@ The document '%s' (page %d) has been changed. Do you want to close the document?
Leave full screen Menus 取消全屏
Close Menus 关闭
Close ClosePrompt 关闭
Undo Menus 撤销
Resize to (in 1/72 inches): PrintOptionsWindow 缩放到(in 1/72 inches):
Rating Menus 评级
Flip left to right Menus 自左向右翻转

View File

@ -1,4 +1,4 @@
1 portuguese (brazil) x-vnd.Haiku-Terminal 766764238
1 portuguese (brazil) x-vnd.Haiku-Terminal 2645209895
Not found. Terminal TermWindow Não localizado.
Switch Terminals Terminal TermWindow Alternar Terminais
Change directory Terminal TermView Mudar de pasta
@ -21,6 +21,7 @@ Font: Terminal AppearancePrefView Fonte:
Copy here Terminal TermView Copiar aqui
Really close? Terminal TermWindow Deseja realmente fechar?
Copy Terminal TermWindow Copiar
Terminal Terminal TermWindow The title for the main window menubar entry related to terminal sessions Terminal
Color scheme: Terminal AppearancePrefView Esquema de cores:
Window title: Terminal TermWindow Título da janela:
Unrecognized option \"%s\"\n Terminal arguments parsing Opção não reconhecida \"%s\"\n
@ -61,6 +62,7 @@ Text not found. Terminal TermWindow Texto não encontrado.
Find… Terminal TermWindow Localizar…
The process \"%1\" is still running.\nIf you close the Terminal, the process will be killed. Terminal TermWindow O processo \"%1\" ainda está executando.\nSe fechar o Terminal, o processo será morto.
Move here Terminal TermView Mover aqui
\t%d\t-\tThe current working directory of the active process in the\n\t\t\tcurrent tab. Optionally the maximum number of path components\n\t\t\tcan be specified. E.g. '%2d' for at most two components.\n\t%T\t-\tThe Terminal application name for the current locale.\n\t%i\t-\tThe index of the window.\n\t%p\t-\tThe name of the active process in the current tab.\n\t%t\t-\tThe title of the current tab.\n\t%%\t-\tThe character '%'. Terminal ToolTips \t %d\t -\t O diretório de trabalho atual do processo ativo na\n\t \t\t aba atual. Opcionalmente o número máximo de componentes do caminho\n\t \t\t pode ser especificado. Por exemplo, '%2d' para no máximo dois componentes.\n\t %T\t -\t O nome do aplicativo Terminal para a localidade atual.\n\t %i\t -\t O índice da janela.\n\t %p\t -\t O nome do processo ativo na guia atual.\n\t %t\t -\t O título da guia atual.\n\t %%\t -\t O caractere '%'.
Retro Terminal colors scheme Retrô
Error! Terminal getString Erro!
New tab Terminal TermWindow Nova aba

View File

@ -1,4 +1,4 @@
1 portuguese (brazil) x-vnd.Haiku-WebPositive 233049275
1 portuguese (brazil) x-vnd.Haiku-WebPositive 3577331897
Show home button Settings Window Exibir botão home
Username: Authentication Panel Nome de Usuário:
Copy URL to clipboard Download Window Copiar URL para a área de transferência
@ -16,6 +16,7 @@ Start page: Settings Window Página inicial:
History WebPositive Window Histórico
Error opening downloads folder Download Window Erro ao abrir pasta de itens baixados
Paste WebPositive Window Colar
Proxy username: Settings Window Nome de usuário do proxy:
Settings Settings Window Definições
%seconds seconds left Download Window %seconds segundos restantes
Confirmation WebPositive Window Confirmação
@ -41,6 +42,7 @@ Quit WebPositive Window Sair
Full screen WebPositive Window Tela cheia
Open download error Download Window Abrir erro de download
Standard font: Settings Window Fonte padrão:
Find previous occurrence of search terms WebPositive Window find bar previous button tooltip Localizar a ocorrência anterior dos termos da pesquisa
Restart Download Window Reiniciar
Proxy server Settings Window Servidor proxy
Open containing folder Download Window Abrir pasta de contenção
@ -58,6 +60,7 @@ Cut WebPositive Window Cortar
Bookmark this page WebPositive Window Marcar esta página
There was an error trying to show the Bookmarks folder.\n\nError: %error WebPositive Window Don't translate variable %error Ocorreu um erro tentando exibir a pasta de marcadores.\n\nErro: %error
Open downloads folder Download Window Abrir pasta de downloads
Proxy password: Settings Window Senha do proxy:
Number of days to keep links in History menu: Settings Window Número de dias para manter vínculos no menu Histórico:
Hide Download Window Ocultar
Reset size WebPositive Window Restaurar tamanho
@ -67,6 +70,7 @@ There was an error retrieving the bookmark folder.\n\nError: %error WebPositive
Over 1 day left Download Window Mais de 1 dia restante
Downloads WebPositive Window Itens baixados
Requesting %url WebPositive Window Solicitando %url
Find next occurrence of search terms WebPositive Window find bar next button tooltip Localizar a próxima ocorrência dos termos da pesquisa
Apply Settings Window Aplicar
Bookmark info WebPositive Window Informações de marcador
Size: Font Selection view Tamanho:
@ -80,6 +84,7 @@ Open blank page Settings Window Abrir página em branco
New tabs: Settings Window Novas guias:
Cancel WebPositive Window Cancelar
Open all WebPositive Window Abrir tudo
Proxy server requires authentication Settings Window Servidor proxy requer autenticação
Clear URL Bar Limpar
Cut URL Bar Cortar
Clear WebPositive Window Limpar

View File

@ -1,4 +1,4 @@
1 portuguese (brazil) x-vnd.Haiku-libtracker 3375521561
1 portuguese (brazil) x-vnd.Haiku-libtracker 4167158175
common B_COMMON_DIRECTORY comum
OK WidgetAttributeText OK
Icon view VolumeWindow Em ícones
@ -74,6 +74,7 @@ Arrange by ContainerWindow Ordenar por
Mount server error AutoMounterSettings Erro do servidor de montagem
Search FindPanel Localizar
Preparing to empty Trash… StatusWindow Preparando para limpar a Lixeira...
You cannot put the selected item(s) into the trash. FSUtils Não é possível colocar o(s) item(ns) selecionados na lixeira.
Disks Model Discos
Create link ContainerWindow Criar atalho
develop B_COMMON_DEVELOP_DIRECTORY desenvolvimento

View File

@ -1,4 +1,4 @@
1 belarusian x-vnd.Haiku-Appearance 2950529393
1 belarusian x-vnd.Haiku-Appearance 76206318
Plain font: Font view Просты шрыфт:
Control highlight Colors tab Выдзяленне кнопак
Control border Colors tab Аблямоўка кнопак
@ -13,7 +13,6 @@ Off AntialiasingSettingsView Выкл.
Choose Decorator DecorSettingsView Абраць Дэкаратар
Success Colors tab Паспяхова
Inactive window tab text Colors tab Тэкст неактыўнай укладкі вакна
About Decorator DecorSettingsView Пра Decorator
Failure Colors tab Непаспяхова
Hinting menu AntialiasingSettingsView Меню хінтынгу
Document background Colors tab Фон дакумента
@ -29,7 +28,6 @@ Double: DecorSettingsView Падвойны:
Window tab text Colors tab Тэкст загалоўку акна
Document text Colors tab Тэкст дакументу
Navigation pulse Colors tab Колер падсветкі навігацыі
Window decorator: DecorSettingsView Дэкаратар вокнаў:
Selected menu item text Colors tab Тэкст пазначанага пункту меню
Menu background Colors tab Фон меню
List background Colors tab Фон радкоў

View File

@ -1,4 +1,4 @@
1 german x-vnd.Haiku-Appearance 2950529393
1 german x-vnd.Haiku-Appearance 76206318
Plain font: Font view Normal:
Control highlight Colors tab Steuerelement - Ausgewählt
Control border Colors tab Steuerelement - Rahmen
@ -13,7 +13,6 @@ Off AntialiasingSettingsView Aus
Choose Decorator DecorSettingsView Dekorator wählen
Success Colors tab Erfolg
Inactive window tab text Colors tab Reiter - Text (inaktiv)
About Decorator DecorSettingsView Über Dekorator
Failure Colors tab Fehler
Hinting menu AntialiasingSettingsView Hinting-Menü
Document background Colors tab Dokument - Hintergrund
@ -29,7 +28,6 @@ Double: DecorSettingsView Doppelt:
Window tab text Colors tab Reiter - Text
Document text Colors tab Dokument - Text
Navigation pulse Colors tab Navigation - Leuchtfarbe
Window decorator: DecorSettingsView Fenster-Dekorator:
Selected menu item text Colors tab Menü - Text (ausgewählt)
Menu background Colors tab Menü - Hintergrund
List background Colors tab Liste - Hintergrund

View File

@ -1,4 +1,4 @@
1 greek, modern (1453-) x-vnd.Haiku-Appearance 1492316509
1 greek, modern (1453-) x-vnd.Haiku-Appearance 963859935
Control highlight Colors tab Έλεγχος φωτεινότητας
Control border Colors tab Έλεγχος περιγράμματος
Antialiasing type: AntialiasingSettingsView Τύπος εξομάλυνσης:
@ -12,7 +12,6 @@ Off AntialiasingSettingsView Κλειστό
Choose Decorator DecorSettingsView Επιλέξετε Διακοσμητή
Success Colors tab Επιτυχία
Inactive window tab text Colors tab Κείμενο της αδρανής καρτέλας παράθυρου
About Decorator DecorSettingsView Σχετικά Με Τον Διακοσμητή
Failure Colors tab Αποτυχία
Hinting menu AntialiasingSettingsView Μενού υποδείξεων
Document background Colors tab Φόντο εγγράφου

View File

@ -1,4 +1,4 @@
1 finnish x-vnd.Haiku-Appearance 2950529393
1 finnish x-vnd.Haiku-Appearance 76206318
Plain font: Font view Pelkkä kirjasin:
Control highlight Colors tab Kontrollin korostus
Control border Colors tab Kontrollin reuna
@ -13,7 +13,6 @@ Off AntialiasingSettingsView Pois päältä
Choose Decorator DecorSettingsView Valitse koristelu
Success Colors tab Onnistuminen
Inactive window tab text Colors tab Epäaktiivisen ikkunavälilehden tekstin väri
About Decorator DecorSettingsView Koristeluohjelmasta
Failure Colors tab Epäonnistuminen
Hinting menu AntialiasingSettingsView Vinkkausvalikko
Document background Colors tab Dokumentin tausta
@ -29,7 +28,6 @@ Double: DecorSettingsView Kaksikko:
Window tab text Colors tab Ikkunavälilehden teksti
Document text Colors tab Dokumentin teksti
Navigation pulse Colors tab Navigoinnin välke
Window decorator: DecorSettingsView Ikkunan kehystäjä:
Selected menu item text Colors tab Valitun valikkovalinnan teksti
Menu background Colors tab Valikon tausta
List background Colors tab Luettelotausta

View File

@ -1,4 +1,4 @@
1 french x-vnd.Haiku-Appearance 2950529393
1 french x-vnd.Haiku-Appearance 76206318
Plain font: Font view Police simple :
Control highlight Colors tab Mise en valeur de contrôle
Control border Colors tab Bordure des contrôles
@ -13,7 +13,6 @@ Off AntialiasingSettingsView Désactivé
Choose Decorator DecorSettingsView Choisir un décorateur
Success Colors tab Réussite
Inactive window tab text Colors tab Texte des titres de fenêtres inactives
About Decorator DecorSettingsView À propos du Décorateur
Failure Colors tab Échec
Hinting menu AntialiasingSettingsView Menu ajustement
Document background Colors tab Arrière plan du document
@ -29,7 +28,6 @@ Double: DecorSettingsView Double :
Window tab text Colors tab Texte des titres de fenêtres
Document text Colors tab Texte du document
Navigation pulse Colors tab Pulsation de navigation
Window decorator: DecorSettingsView Décorateur de fenêtre :
Selected menu item text Colors tab Texte de l'élément sélectionné dans le menu
Menu background Colors tab Arrière plan de menu
List background Colors tab Arrière-plan de la liste

View File

@ -1,4 +1,4 @@
1 hindi x-vnd.Haiku-Appearance 1492316509
1 hindi x-vnd.Haiku-Appearance 963859935
Control highlight Colors tab उजागर के लिए नियंत्रण
Control border Colors tab नियंत्रण सीमा
Antialiasing type: AntialiasingSettingsView एंटीएलिअसिंग टाइप:
@ -12,7 +12,6 @@ Off AntialiasingSettingsView बंद
Choose Decorator DecorSettingsView डेकोरेटर चुनें
Success Colors tab सफलता
Inactive window tab text Colors tab निष्क्रिय विंडो टैब टेक्स्ट
About Decorator DecorSettingsView डेकोरेटर के बारे में
Failure Colors tab असफलता
Hinting menu AntialiasingSettingsView सहाईता के लिए मेनू
Document background Colors tab दस्तावेज़ पृष्ठभूमि

View File

@ -1,4 +1,4 @@
1 hungarian x-vnd.Haiku-Appearance 2950529393
1 hungarian x-vnd.Haiku-Appearance 76206318
Plain font: Font view Alap betűtípus:
Control highlight Colors tab Kiválasztott vezérlőelem
Control border Colors tab Vezérlőelem kerete
@ -13,7 +13,6 @@ Off AntialiasingSettingsView Ki
Choose Decorator DecorSettingsView Dekoráció kiválasztása
Success Colors tab Sikerült
Inactive window tab text Colors tab Inaktív ablak címszövege
About Decorator DecorSettingsView Dekoráció névjegye
Failure Colors tab Nem sikerült
Hinting menu AntialiasingSettingsView Körvonalmenü
Document background Colors tab Dokumentum háttere
@ -29,7 +28,6 @@ Double: DecorSettingsView Dupla:
Window tab text Colors tab Ablakfül szövege
Document text Colors tab Dokumentumszöveg
Navigation pulse Colors tab Navigációs pulzálás
Window decorator: DecorSettingsView Ablakdekoráció:
Selected menu item text Colors tab Kiválasztott menüelem
Menu background Colors tab Menü háttere
List background Colors tab Lista háttere

View File

@ -1,4 +1,4 @@
1 japanese x-vnd.Haiku-Appearance 2950529393
1 japanese x-vnd.Haiku-Appearance 76206318
Plain font: Font view 標準フォント:
Control highlight Colors tab コントロールのハイライト
Control border Colors tab コントロールの境界
@ -13,7 +13,6 @@ Off AntialiasingSettingsView 無効
Choose Decorator DecorSettingsView デコレーターを選択
Success Colors tab 成功
Inactive window tab text Colors tab 非アクティブウィンドウタブの文字
About Decorator DecorSettingsView デコレーターについて
Failure Colors tab 失敗
Hinting menu AntialiasingSettingsView ヒンティングメニュー
Document background Colors tab ドキュメントの背景
@ -29,7 +28,6 @@ Double: DecorSettingsView 両方向:
Window tab text Colors tab ウィンドウタブの文字
Document text Colors tab ドキュメントの文字
Navigation pulse Colors tab ナビゲーションの点滅
Window decorator: DecorSettingsView ウィンドウデコレーター:
Selected menu item text Colors tab メニュー選択項目の文字
Menu background Colors tab メニューの背景
List background Colors tab リストの背景

View File

@ -1,4 +1,4 @@
1 lithuanian x-vnd.Haiku-Appearance 3654950032
1 lithuanian x-vnd.Haiku-Appearance 780626957
Plain font: Font view Paprastas šriftas:
Control highlight Colors tab Valdiklių paryškinimas
Control border Colors tab Valdiklių rėmeliai
@ -13,7 +13,6 @@ Off AntialiasingSettingsView išjungta
Choose Decorator DecorSettingsView Išsirinkite dekoruoklį
Success Colors tab Sėkminga baigtis
Inactive window tab text Colors tab Neaktyvių langų antraščių tekstas
About Decorator DecorSettingsView Apie dekoruoklį
Failure Colors tab Nesėkminga baigtis
Hinting menu AntialiasingSettingsView Taškinės korekcijos meniu
Document background Colors tab Dokumento fonas
@ -28,7 +27,6 @@ Double: DecorSettingsView Dvigubas:
Window tab text Colors tab Veikiamojo lango antraštės tekstas
Document text Colors tab Dokumento tekstas
Navigation pulse Colors tab Veikiamojo elemento (židinio) žybsniai
Window decorator: DecorSettingsView Langų dekoruoklis:
Selected menu item text Colors tab Veikiamojo meniu elemento tekstas
Menu background Colors tab Meniu fonas
List background Colors tab Sąrašo fonas

View File

@ -1,4 +1,4 @@
1 dutch; flemish x-vnd.Haiku-Appearance 1428480647
1 dutch; flemish x-vnd.Haiku-Appearance 2849124868
Plain font: Font view Standaardlettertype:
Control highlight Colors tab Keuze-accent
Control border Colors tab Keuzerand
@ -13,7 +13,6 @@ Off AntialiasingSettingsView Uit
Choose Decorator DecorSettingsView Decorator kiezen
Success Colors tab Gelukt
Inactive window tab text Colors tab Tabtekst niet-actief venster
About Decorator DecorSettingsView Over decorator
Failure Colors tab Mislukt
Hinting menu AntialiasingSettingsView Hinting-menu
Document background Colors tab Achtergrond document
@ -27,7 +26,6 @@ Window border Colors tab Vensterrand
Window tab text Colors tab Tekst venstertab
Document text Colors tab Tekst document
Navigation pulse Colors tab Puls navigatie
Window decorator: DecorSettingsView Vensterdecorator:
Selected menu item text Colors tab Tekst geselecteerd menu-item
Menu background Colors tab Achtergrond menu
OK DecorSettingsView OK

View File

@ -1,4 +1,4 @@
1 polish x-vnd.Haiku-Appearance 3956654572
1 polish x-vnd.Haiku-Appearance 1082331497
Plain font: Font view Zwykła czcionka:
Control highlight Colors tab Podkreślenie kontrolki
Control border Colors tab Obramowanie kontrolki
@ -13,7 +13,6 @@ Off AntialiasingSettingsView Wyłącz
Choose Decorator DecorSettingsView Wybierz Dekorator
Success Colors tab Sukces
Inactive window tab text Colors tab Tekst nieaktywnej zakładki okna
About Decorator DecorSettingsView O Dekoratorze
Failure Colors tab Niepowodzenie
Hinting menu AntialiasingSettingsView Menu hintingu
Document background Colors tab Tło dokumentu
@ -28,7 +27,6 @@ Window border Colors tab Obramowanie okna
Window tab text Colors tab Tekst zakładki okna
Document text Colors tab Tekst dokumentu
Navigation pulse Colors tab Puls nawigacji
Window decorator: DecorSettingsView Dekorator okna:
Selected menu item text Colors tab Tekst zaznaczonego elementu menu
Menu background Colors tab Tło menu
OK DecorSettingsView OK

View File

@ -1,4 +1,4 @@
1 portuguese (brazil) x-vnd.Haiku-Appearance 2950529393
1 portuguese (brazil) x-vnd.Haiku-Appearance 76206318
Plain font: Font view Fonte plana:
Control highlight Colors tab Realce do controle
Control border Colors tab Borda do controle
@ -13,7 +13,6 @@ Off AntialiasingSettingsView Desligado
Choose Decorator DecorSettingsView Escolher Decorador
Success Colors tab Sucesso
Inactive window tab text Colors tab Texto da aba de janela inativa
About Decorator DecorSettingsView Sobre o Decorador
Failure Colors tab Falha
Hinting menu AntialiasingSettingsView Menu de sugestão
Document background Colors tab Plano de fundo do documento
@ -29,7 +28,6 @@ Double: DecorSettingsView Duplo:
Window tab text Colors tab Texto da aba da Janela
Document text Colors tab Texto do documento
Navigation pulse Colors tab Navegação de pulso
Window decorator: DecorSettingsView Decorador de janela:
Selected menu item text Colors tab Texto do item do menu selecionado
Menu background Colors tab Plano de fundo de menu
List background Colors tab Plano de fundo da lista

View File

@ -1,4 +1,4 @@
1 romanian x-vnd.Haiku-Appearance 1492316509
1 romanian x-vnd.Haiku-Appearance 963859935
Control highlight Colors tab Punct principal de control
Control border Colors tab Margine de control
Antialiasing type: AntialiasingSettingsView Tip de anti-alias:
@ -12,7 +12,6 @@ Off AntialiasingSettingsView Oprit
Choose Decorator DecorSettingsView Alege decorator
Success Colors tab Succes
Inactive window tab text Colors tab Text de fereastră tab inactivă
About Decorator DecorSettingsView Despre Decorator
Failure Colors tab Eşec
Hinting menu AntialiasingSettingsView Meniu de sugestii
Document background Colors tab Fundalul documentului

View File

@ -1,4 +1,4 @@
1 russian x-vnd.Haiku-Appearance 3266657197
1 russian x-vnd.Haiku-Appearance 392334122
Plain font: Font view Простой шрифт:
Control highlight Colors tab Подсветка элемента
Control border Colors tab Граница элемента
@ -13,7 +13,6 @@ Off AntialiasingSettingsView Выключить
Choose Decorator DecorSettingsView Выберите декоратор
Success Colors tab Успех
Inactive window tab text Colors tab Текст заголовка неактивного окна
About Decorator DecorSettingsView Об этом декораторе
Failure Colors tab Неудача
Hinting menu AntialiasingSettingsView Корректировка (хинтинг)
Document background Colors tab Фон документа
@ -29,7 +28,6 @@ Double: DecorSettingsView Двойной:
Window tab text Colors tab Текст заголовка окна
Document text Colors tab Текст документа
Navigation pulse Colors tab Навигационная пульсация
Window decorator: DecorSettingsView Оконный декоратор:
Selected menu item text Colors tab Текст выделенного пункта меню
Menu background Colors tab Фон меню
OK DecorSettingsView ОК

View File

@ -1,4 +1,4 @@
1 slovak x-vnd.Haiku-Appearance 2950529393
1 slovak x-vnd.Haiku-Appearance 76206318
Plain font: Font view Základné písmo:
Control highlight Colors tab Zvýraznenie ovládacieho prvku
Control border Colors tab Okraj ovládacieho prvku
@ -13,7 +13,6 @@ Off AntialiasingSettingsView Vypnutý
Choose Decorator DecorSettingsView Vyberte dekorátor
Success Colors tab Úspešné
Inactive window tab text Colors tab Text záložky neaktívneho okna
About Decorator DecorSettingsView O dekorátore
Failure Colors tab Zlyhanie
Hinting menu AntialiasingSettingsView Menu s tipmi
Document background Colors tab Pozadie dokumentu
@ -29,7 +28,6 @@ Double: DecorSettingsView Dvojité:
Window tab text Colors tab Text záložky okna
Document text Colors tab Text dokumentu
Navigation pulse Colors tab Pulz navigácie
Window decorator: DecorSettingsView Dekorátor okna:
Selected menu item text Colors tab Text položky zvoleného menu
Menu background Colors tab Pozadie menu
List background Colors tab Pozadie zoznamu

View File

@ -1,4 +1,4 @@
1 swedish x-vnd.Haiku-Appearance 2950529393
1 swedish x-vnd.Haiku-Appearance 76206318
Plain font: Font view Vanlig font:
Control highlight Colors tab Framhävd kontroll
Control border Colors tab Kontrollkant
@ -13,7 +13,6 @@ Off AntialiasingSettingsView Av
Choose Decorator DecorSettingsView Välj dekor
Success Colors tab Framgång
Inactive window tab text Colors tab Fliktext för inaktiva fönster
About Decorator DecorSettingsView Om Dekor
Failure Colors tab Misslyckande
Hinting menu AntialiasingSettingsView Betoningsmeny
Document background Colors tab Dokument bakgrund
@ -29,7 +28,6 @@ Double: DecorSettingsView Dubbel
Window tab text Colors tab Fönsterflik text
Document text Colors tab Dokument text
Navigation pulse Colors tab Navigeringspuls
Window decorator: DecorSettingsView Fönsterdekor:
Selected menu item text Colors tab Textfärg för valt menyalternativ
Menu background Colors tab Menybakgrund
List background Colors tab Lista bakgrund

View File

@ -1,4 +1,4 @@
1 ukrainian x-vnd.Haiku-Appearance 1492316509
1 ukrainian x-vnd.Haiku-Appearance 963859935
Control highlight Colors tab Підсвітка елемента
Control border Colors tab Межа елемента
Antialiasing type: AntialiasingSettingsView Тип зглажування:
@ -12,7 +12,6 @@ Off AntialiasingSettingsView Слабе
Choose Decorator DecorSettingsView Вибір декоратора
Success Colors tab Успіх
Inactive window tab text Colors tab Текст заголовку неактивного вікна
About Decorator DecorSettingsView Про Декоратор
Failure Colors tab Невдача
Hinting menu AntialiasingSettingsView Меню коректування
Document background Colors tab Тло документа

View File

@ -1,4 +1,4 @@
1 english x-vnd.Haiku-Appearance 2950529393
1 english x-vnd.Haiku-Appearance 76206318
Plain font: Font view 常规字体
Control highlight Colors tab 控件亮度
Control border Colors tab 控件边界
@ -13,7 +13,6 @@ Off AntialiasingSettingsView 关闭
Choose Decorator DecorSettingsView 选择装饰
Success Colors tab 成功
Inactive window tab text Colors tab 激活窗口标签
About Decorator DecorSettingsView 关于 Decorator
Failure Colors tab 失败
Hinting menu AntialiasingSettingsView 提示菜单
Document background Colors tab 文档背景
@ -29,7 +28,6 @@ Double: DecorSettingsView 双行:
Window tab text Colors tab 窗口标签文本
Document text Colors tab 文件文本
Navigation pulse Colors tab 导航引导
Window decorator: DecorSettingsView 窗口装饰:
Selected menu item text Colors tab 选择菜单文本
Menu background Colors tab 菜单背景
List background Colors tab 列表背景

View File

@ -1,4 +1,4 @@
1 belarusian x-vnd.Haiku-BluetoothPrefs 3926935355
1 belarusian x-vnd.Haiku-BluetoothPrefs 1628593228
About Bluetooth… Window Пра праграму Bluetooth…
Handheld Settings view Наладоннік
Default inquiry time: Settings view Час стандартнага запыту:
@ -36,7 +36,6 @@ Identify us as... Settings view Ідэнтыфікаваць сябе як...
As blocked Remote devices Як блакаваны
Bluetooth System name Bluetooth
Disconnect Remote devices Адключыцца
Pick LocalDevice... Settings view Выбраць прыладу (LocalDevice)…
Defaults Window Прадвызначаныя
Inquiry Inquiry panel Запыт
Desktop Settings view Рабочы стол

View File

@ -1,4 +1,4 @@
1 german x-vnd.Haiku-BluetoothPrefs 3926935355
1 german x-vnd.Haiku-BluetoothPrefs 1628593228
About Bluetooth… Window Über Bluetooth…
Handheld Settings view Handheld
Default inquiry time: Settings view Suchdauer:
@ -36,7 +36,6 @@ Identify us as... Settings view Rolle...
As blocked Remote devices Blockieren
Bluetooth System name Bluetooth
Disconnect Remote devices Trennen
Pick LocalDevice... Settings view Gerät...
Defaults Window Standardwerte
Inquiry Inquiry panel Suchen
Desktop Settings view Desktop

View File

@ -1,4 +1,4 @@
1 greek, modern (1453-) x-vnd.Haiku-BluetoothPrefs 2526531136
1 greek, modern (1453-) x-vnd.Haiku-BluetoothPrefs 228189009
About Bluetooth… Window Περί Bluetooth...
Handheld Settings view Φορητός
Default inquiry time: Settings view Προκαθορισμένος χρόνος έρευνας:
@ -35,7 +35,6 @@ Identify us as... Settings view Αναγνωρίστε μας ως...
As blocked Remote devices Ως αποκλεισμένο
Bluetooth System name Bluetooth
Disconnect Remote devices Αποσύνδεση
Pick LocalDevice... Settings view Επιλογή τοπικής συσκευής
Defaults Window Προεπιλογές
Inquiry Inquiry panel Αίτηση
Desktop Settings view Επιφάνεια εργασίας

View File

@ -1,4 +1,4 @@
1 finnish x-vnd.Haiku-BluetoothPrefs 3926935355
1 finnish x-vnd.Haiku-BluetoothPrefs 1628593228
About Bluetooth… Window Bluetooth-ohjelmasta…
Handheld Settings view Kädessäpidettävät
Default inquiry time: Settings view Oletuskyselyn pituus:
@ -36,7 +36,6 @@ Identify us as... Settings view Tunnista meidät nimellä...
As blocked Remote devices Estettynä
Bluetooth System name Bluetooth-asetukset
Disconnect Remote devices Katkaise yhteys
Pick LocalDevice... Settings view Valitse paikallinen laite...
Defaults Window Oletusasetukset
Inquiry Inquiry panel Tiedustelu
Desktop Settings view Työpöytäasetukset

View File

@ -1,4 +1,4 @@
1 french x-vnd.Haiku-BluetoothPrefs 3926935355
1 french x-vnd.Haiku-BluetoothPrefs 1628593228
About Bluetooth… Window À propos de Bluetooth…
Handheld Settings view Appareil de poche
Default inquiry time: Settings view Temps de requête par défaut :
@ -36,7 +36,6 @@ Identify us as... Settings view S'identifier comme…
As blocked Remote devices Comme bloqué
Bluetooth System name Bluetooth
Disconnect Remote devices Déconnexion
Pick LocalDevice... Settings view Choisir un appareil local…
Defaults Window Défauts
Inquiry Inquiry panel Examiner
Desktop Settings view Bureau

View File

@ -1,4 +1,4 @@
1 hindi x-vnd.Haiku-BluetoothPrefs 3926935355
1 hindi x-vnd.Haiku-BluetoothPrefs 1628593228
About Bluetooth… Window ब्लूटूथ के बारे में ...
Handheld Settings view हैंडहेल्ड
Default inquiry time: Settings view डिफ़ॉल्ट जांच का समय:
@ -36,7 +36,6 @@ Identify us as... Settings view हमें पहचानें के र
As blocked Remote devices के रूप में बंद
Bluetooth System name ब्लूटूथ
Disconnect Remote devices डिसकन्नेक्ट
Pick LocalDevice... Settings view उठाओ लोकाल्देविस ...
Defaults Window चूक
Inquiry Inquiry panel जांच
Desktop Settings view डेस्कटॉप

View File

@ -1,4 +1,4 @@
1 hungarian x-vnd.Haiku-BluetoothPrefs 3926935355
1 hungarian x-vnd.Haiku-BluetoothPrefs 1628593228
About Bluetooth… Window A Bluetooth-ról…
Handheld Settings view Mobiltelefon
Default inquiry time: Settings view Alapértelmezett lekérdezési időkorlát:
@ -36,7 +36,6 @@ Identify us as... Settings view Azonosítása mint…
As blocked Remote devices Blokkoltként
Bluetooth System name Bluetooth
Disconnect Remote devices Kapcsolatbontás
Pick LocalDevice... Settings view Helyi eszköz kiválasztása…
Defaults Window Alapértelmezés
Inquiry Inquiry panel Lekérdezés
Desktop Settings view Asztal

View File

@ -1,4 +1,4 @@
1 japanese x-vnd.Haiku-BluetoothPrefs 3926935355
1 japanese x-vnd.Haiku-BluetoothPrefs 1628593228
About Bluetooth… Window Bluetoothについて…
Handheld Settings view ハンドヘルド機器
Default inquiry time: Settings view デフォルトの問い合わせ時間:
@ -36,7 +36,6 @@ Identify us as... Settings view 自機名…
As blocked Remote devices ブロック状態
Bluetooth System name Bluetooth
Disconnect Remote devices 切断
Pick LocalDevice... Settings view ローカルデバイスの選択…
Defaults Window デフォルト
Inquiry Inquiry panel 問い合わせ
Desktop Settings view デスクトップ

View File

@ -1,4 +1,4 @@
1 lithuanian x-vnd.Haiku-BluetoothPrefs 3926935355
1 lithuanian x-vnd.Haiku-BluetoothPrefs 1628593228
About Bluetooth… Window Apie…
Handheld Settings view delninukas
Default inquiry time: Settings view Numatytasis žvalgymo laikas:
@ -36,7 +36,6 @@ Identify us as... Settings view pasirinkite…
As blocked Remote devices Kaip blokuotas
Bluetooth System name Bluetooth
Disconnect Remote devices Atsijungti
Pick LocalDevice... Settings view pasirinkite vietinį įrenginį…
Defaults Window Numatytai
Inquiry Inquiry panel Žvalgyti
Desktop Settings view stalinis kompiuteris

View File

@ -1,4 +1,4 @@
1 dutch; flemish x-vnd.Haiku-BluetoothPrefs 3926935355
1 dutch; flemish x-vnd.Haiku-BluetoothPrefs 1628593228
About Bluetooth… Window Over Bluetooth…
Handheld Settings view Handheld
Default inquiry time: Settings view Standaard onderzoekstijd:
@ -36,7 +36,6 @@ Identify us as... Settings view Identificeer ons als...
As blocked Remote devices Als geblokkeerd
Bluetooth System name Bluetooth
Disconnect Remote devices Verbreek verbinding
Pick LocalDevice... Settings view Kies een lokaal apparaat...
Defaults Window Standaardwaarden
Inquiry Inquiry panel Onderzoek
Desktop Settings view Bureaublad

View File

@ -1,4 +1,4 @@
1 polish x-vnd.Haiku-BluetoothPrefs 3926935355
1 polish x-vnd.Haiku-BluetoothPrefs 1628593228
About Bluetooth… Window O aplikacji Bluetooth…
Handheld Settings view Handheld
Default inquiry time: Settings view Domyślny czas zapytania:
@ -36,7 +36,6 @@ Identify us as... Settings view Identyfikuj nas jako...
As blocked Remote devices Jako zablokowany
Bluetooth System name Bluetooth
Disconnect Remote devices Rozłączony
Pick LocalDevice... Settings view Wybierz urządzenie lokalne...
Defaults Window Domyślne
Inquiry Inquiry panel Zapytaj
Desktop Settings view Pulpit

View File

@ -1,4 +1,4 @@
1 portuguese (brazil) x-vnd.Haiku-BluetoothPrefs 3926935355
1 portuguese (brazil) x-vnd.Haiku-BluetoothPrefs 1628593228
About Bluetooth… Window Sobre Bluetooth…
Handheld Settings view Handheld
Default inquiry time: Settings view Tempo de consulta padrão:
@ -36,7 +36,6 @@ Identify us as... Settings view Identificar-nos como…
As blocked Remote devices Como bloqueado
Bluetooth System name Bluetooth
Disconnect Remote devices Desconectar
Pick LocalDevice... Settings view Escolher dispositivo local...
Defaults Window Padrões
Inquiry Inquiry panel Inquérito
Desktop Settings view Desktop

View File

@ -1,4 +1,4 @@
1 romanian x-vnd.Haiku-BluetoothPrefs 2526531136
1 romanian x-vnd.Haiku-BluetoothPrefs 228189009
About Bluetooth… Window Despre Bluetooth...
Handheld Settings view Calculator de buzunar
Default inquiry time: Settings view Timp implicit de întrebare:
@ -35,7 +35,6 @@ Identify us as... Settings view Identificare ca...
As blocked Remote devices Ca blocat
Bluetooth System name Bluetooth
Disconnect Remote devices Deconectează
Pick LocalDevice... Settings view Selectează dispozitiv local...
Defaults Window Implicite
Inquiry Inquiry panel Întrebare
Desktop Settings view Desktop

View File

@ -1,4 +1,4 @@
1 russian x-vnd.Haiku-BluetoothPrefs 3926935355
1 russian x-vnd.Haiku-BluetoothPrefs 1628593228
About Bluetooth… Window О программе…
Handheld Settings view Переносной
Default inquiry time: Settings view Время запроса по умолчанию:
@ -36,7 +36,6 @@ Identify us as... Settings view Идентифицировать нас как
As blocked Remote devices Как блокированный
Bluetooth System name Bluetooth
Disconnect Remote devices Отключить
Pick LocalDevice... Settings view Выбор локального устройства…
Defaults Window По умолчанию
Inquiry Inquiry panel Запрос
Desktop Settings view Рабочий стол

View File

@ -1,4 +1,4 @@
1 slovak x-vnd.Haiku-BluetoothPrefs 3926935355
1 slovak x-vnd.Haiku-BluetoothPrefs 1628593228
About Bluetooth… Window O aplikácii Bluetooth…
Handheld Settings view Handheld
Default inquiry time: Settings view Predvolený čas zisťovania:
@ -36,7 +36,6 @@ Identify us as... Settings view Identifikovať sa ako...
As blocked Remote devices Ako blokované
Bluetooth System name Bluetooth
Disconnect Remote devices Odpojiť
Pick LocalDevice... Settings view Vybrať lokálne zariadenie...
Defaults Window Predvolené
Inquiry Inquiry panel Zistenie
Desktop Settings view Plocha

View File

@ -1,4 +1,4 @@
1 swedish x-vnd.Haiku-BluetoothPrefs 3926935355
1 swedish x-vnd.Haiku-BluetoothPrefs 1628593228
About Bluetooth… Window Om Bluetooth…
Handheld Settings view Handhållen
Default inquiry time: Settings view Förvald frågotid:
@ -36,7 +36,6 @@ Identify us as... Settings view Identifiera som...
As blocked Remote devices Som blockerad
Bluetooth System name Bluetooth
Disconnect Remote devices Koppla från
Pick LocalDevice... Settings view Välj lokal enhet...
Defaults Window Förval
Inquiry Inquiry panel Förfrågan
Desktop Settings view Skrivbord

View File

@ -1,4 +1,4 @@
1 ukrainian x-vnd.Haiku-BluetoothPrefs 2526531136
1 ukrainian x-vnd.Haiku-BluetoothPrefs 228189009
About Bluetooth… Window Про Bluetooth…
Handheld Settings view Переносний
Default inquiry time: Settings view Час запиту по замовчуванню:
@ -35,7 +35,6 @@ Identify us as... Settings view Визначити нас як…
As blocked Remote devices Як заблокований
Bluetooth System name Bluetooth
Disconnect Remote devices Роз’єднати
Pick LocalDevice... Settings view Вибір локального приладу…
Defaults Window По замовчуванню
Inquiry Inquiry panel Запит
Desktop Settings view Робочий стіл

View File

@ -1,4 +1,4 @@
1 english x-vnd.Haiku-BluetoothPrefs 3926935355
1 english x-vnd.Haiku-BluetoothPrefs 1628593228
About Bluetooth… Window 关于蓝牙...
Handheld Settings view 手持设备
Default inquiry time: Settings view 默认查询时间:
@ -36,7 +36,6 @@ Identify us as... Settings view 身份识别...
As blocked Remote devices 阻塞状态
Bluetooth System name 蓝牙
Disconnect Remote devices 断开连接
Pick LocalDevice... Settings view 选择本地设备...
Defaults Window 默认
Inquiry Inquiry panel 查询
Desktop Settings view 桌面电脑

View File

@ -1,22 +1,27 @@
1 portuguese (brazil) x-vnd.Haiku-Network 365183238
1 portuguese (brazil) x-vnd.Haiku-Network 1341378870
Choose automatically EthernetSettingsView Escolher automaticamente
Gateway: EthernetSettingsView Gateway:
Netmask: EthernetSettingsView Máscara de rede:
DHCP EthernetSettingsView DHCP
DNS #2: EthernetSettingsView DNS #2:
Apply EthernetSettingsView Aplicar
Netmask is invalid EthernetSettingsView Máscara de rede é inválida
OK EthernetSettingsView OK
DNS #1: EthernetSettingsView DNS #1:
IP address: EthernetSettingsView Endereço de IP:
Adapter: EthernetSettingsView Adaptador:
Domain: EthernetSettingsView Domínio:
Gateway is invalid EthernetSettingsView O Gateway é inválido
DNS #1 is invalid EthernetSettingsView DNS #1 é inválido
Revert EthernetSettingsView Reverter
<no wireless networks found> EthernetSettingsView <nenhuma rede sem fio encontrada>
Network System name Rede
Mode: EthernetSettingsView Modo:
IP address is invalid EthernetSettingsView O endereço IP é inválido
Network: EthernetSettingsView Rede:
The net_server needs to run for the auto configuration! EthernetSettingsView É preciso abrir o net_server para efetuar a configuração automática!
Disabled EthernetSettingsView Desativado
Auto-configuring failed: EthernetSettingsView Auto-configuração falhou:
Static EthernetSettingsView Estático
DNS #2 is invalid EthernetSettingsView DNS #2 é inválido
<no adapter> EthernetSettingsView <nenhum adaptador>

View File

@ -1,4 +1,4 @@
1 portuguese (brazil) x-vnd.Haiku-Notifications 814394708
1 portuguese (brazil) x-vnd.Haiku-Notifications 2177286129
An error occurred saving the preferences.\nIt's possible you are running out of disk space. GeneralView Um erro ocorreu salvando as preferências.\nÉ possível que esteja executando fora do espaço de disco.
Notifications GeneralView Notificações
seconds of inactivity GeneralView segundos de inatividade
@ -17,6 +17,7 @@ Cannot disable notifications because the server can't be reached. GeneralView N
Progress NotificationView Progresso
Last Received NotificationView Último Recebido
General PrefletView Geral
Apply PrefletWin Aplicar
Display PrefletView Tela
Can't enable notifications at startup time, you probably don't have write permission to the boot settings directory. GeneralView Não é possível habilitar notificações em tempo de inicialização, provavelmente não há permissão de escrita para o diretório de definições de inicialização.
Search: NotificationView Pesquisar:

View File

@ -1,4 +1,4 @@
1 portuguese (brazil) x-vnd.Haiku-Time 3544635877
1 portuguese (brazil) x-vnd.Haiku-Time 3259467657
GMT (UNIX compatible) Time GMT (compatível com UNIX)
OK Time OK
Asia Time Ásia
@ -11,6 +11,7 @@ Preview time: Time Pré-visualização de tempo:
Synchronize Time Sincronizar
Revert Time Reverter
Pacific Time Pacífico
Show day of week Time Exibir dia da semana
Add Time Adicionar
Date and time Time Data e hora
about Time sobre
@ -26,6 +27,7 @@ Time Time Hora
Indian Time Índico
Sending request failed Time Falha ao enviar solicitação
Arctic Time Ártico
Display time with seconds Time Mostrar a hora com os segundos
Time System name Hora
America Time América
Reset Time Restaurar
@ -33,6 +35,8 @@ Synchronize at boot Time Sincronizar ao inicializar
Time & Date, written by:\n\n\tAndrew Edward McCall\n\tMike Berg\n\tJulun\n\tPhilippe Saint-Pierre\n\nCopyright 2004-2012, Haiku. Time Hora & Data, escrito por:\n\n\t Andrew Edward McCall\n\t Mike Berg\n\t Julun\n\t Philippe Saint-Pierre\n\nDireitos reservados 2004-2012, Haiku.
Received invalid time Time Recebida hora inválida
Antarctica Time Antártica
Show time zone Time Mostrar fuso horário
Show clock in Deskbar Time Exibir relógio na Deskbar
The following error occured while synchronizing:r\n%s: %s Time Ocorreu o seguinte erro ao sincronizar:r\n%s: %s
<Other> Time <Outro>
Current time: Time Hora atual:

View File

@ -242,6 +242,14 @@ struct fs_vnode_ops {
fs_vnode* _superVnode, ino_t* _nodeID);
status_t (*get_super_vnode)(fs_volume* volume, fs_vnode* vnode,
fs_volume* superVolume, fs_vnode* superVnode);
/* lock operations */
status_t (*test_lock)(fs_volume* volume, fs_vnode* vnode, void* cookie,
struct flock* lock);
status_t (*acquire_lock)(fs_volume* volume, fs_vnode* vnode, void* cookie,
const struct flock* lock, bool wait);
status_t (*release_lock)(fs_volume* volume, fs_vnode* vnode, void* cookie,
const struct flock* lock);
};
struct file_system_module_info {

View File

@ -269,6 +269,7 @@ _AVL_TREE_MAP_CLASS_NAME::MakeEmpty()
{
AVLTreeNode* root = fTree.Root();
_FreeTree(root);
fTree.MakeEmpty();
}

View File

@ -0,0 +1,58 @@
/*
* Copyright 2012 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Paweł Dziepak, pdziepak@quarnos.org
*/
#ifndef DNS_RESOLVER_H
#define DNS_RESOLVER_H
#include <netdb.h>
#include <stdlib.h>
#include <module.h>
#define DNS_RESOLVER_MODULE_NAME "network/dns_resolver/v1"
struct dns_resolver_module {
module_info module;
status_t (*getaddrinfo)(const char* node, const char* service,
const struct addrinfo* hints, struct addrinfo** res);
};
static inline int
kgetaddrinfo(const char* node, const char* service,
const struct addrinfo* hints, struct addrinfo** res)
{
dns_resolver_module* dns;
status_t result = get_module(DNS_RESOLVER_MODULE_NAME,
reinterpret_cast<module_info**>(&dns));
if (result != B_OK)
return result;
result = dns->getaddrinfo(node, service, hints, res);
put_module(DNS_RESOLVER_MODULE_NAME);
return result;
}
static inline void
kfreeaddrinfo(struct addrinfo* res)
{
free(res);
}
#define getaddrinfo kgetaddrinfo
#define freeaddrinfo kfreeaddrinfo
#endif // DNS_RESOLVER_H

View File

@ -123,122 +123,6 @@ set_i2c_signals(void* cookie, int clock, int data)
}
void
set_frame_buffer_base()
{
intel_shared_info &sharedInfo = *gInfo->shared_info;
display_mode &mode = sharedInfo.current_mode;
uint32 baseRegister;
uint32 surfaceRegister;
if (gInfo->head_mode & HEAD_MODE_A_ANALOG) {
baseRegister = INTEL_DISPLAY_A_BASE;
surfaceRegister = INTEL_DISPLAY_A_SURFACE;
} else {
baseRegister = INTEL_DISPLAY_B_BASE;
surfaceRegister = INTEL_DISPLAY_B_SURFACE;
}
if (sharedInfo.device_type.InGroup(INTEL_TYPE_96x)
|| sharedInfo.device_type.InGroup(INTEL_TYPE_G4x)
|| sharedInfo.device_type.InGroup(INTEL_TYPE_ILK)
|| sharedInfo.device_type.InGroup(INTEL_TYPE_SNB)
|| sharedInfo.device_type.InGroup(INTEL_TYPE_IVB)) {
write32(baseRegister, mode.v_display_start * sharedInfo.bytes_per_row
+ mode.h_display_start * (sharedInfo.bits_per_pixel + 7) / 8);
read32(baseRegister);
write32(surfaceRegister, sharedInfo.frame_buffer_offset);
read32(surfaceRegister);
} else {
write32(baseRegister, sharedInfo.frame_buffer_offset
+ mode.v_display_start * sharedInfo.bytes_per_row
+ mode.h_display_start * (sharedInfo.bits_per_pixel + 7) / 8);
read32(baseRegister);
}
}
/*! Creates the initial mode list of the primary accelerant.
It's called from intel_init_accelerant().
*/
status_t
create_mode_list(void)
{
i2c_bus bus;
bus.cookie = (void*)INTEL_I2C_IO_A;
bus.set_signals = &set_i2c_signals;
bus.get_signals = &get_i2c_signals;
ddc2_init_timing(&bus);
status_t error = ddc2_read_edid1(&bus, &gInfo->edid_info, NULL, NULL);
if (error == B_OK) {
edid_dump(&gInfo->edid_info);
gInfo->has_edid = true;
} else {
TRACE("getting EDID on port A (analog) failed : %s. "
"Trying on port C (lvds)\n", strerror(error));
bus.cookie = (void*)INTEL_I2C_IO_C;
error = ddc2_read_edid1(&bus, &gInfo->edid_info, NULL, NULL);
if (error == B_OK) {
edid_dump(&gInfo->edid_info);
gInfo->has_edid = true;
} else {
TRACE("getting EDID on port C failed : %s\n",
strerror(error));
// We could not read any EDID info. Fallback to creating a list with
// only the mode set up by the BIOS.
// TODO: support lower modes via scaling and windowing
if ((gInfo->head_mode & HEAD_MODE_LVDS_PANEL) != 0
&& (gInfo->head_mode & HEAD_MODE_A_ANALOG) == 0) {
size_t size = (sizeof(display_mode) + B_PAGE_SIZE - 1)
& ~(B_PAGE_SIZE - 1);
display_mode* list;
area_id area = create_area("intel extreme modes",
(void**)&list, B_ANY_ADDRESS, size, B_NO_LOCK,
B_READ_AREA | B_WRITE_AREA);
if (area < B_OK)
return area;
memcpy(list, &gInfo->lvds_panel_mode, sizeof(display_mode));
gInfo->mode_list_area = area;
gInfo->mode_list = list;
gInfo->shared_info->mode_list_area = gInfo->mode_list_area;
gInfo->shared_info->mode_count = 1;
return B_OK;
}
}
}
// Otherwise return the 'real' list of modes
display_mode* list;
uint32 count = 0;
gInfo->mode_list_area = create_display_modes("intel extreme modes",
gInfo->has_edid ? &gInfo->edid_info : NULL, NULL, 0, NULL, 0, NULL,
&list, &count);
if (gInfo->mode_list_area < B_OK)
return gInfo->mode_list_area;
gInfo->mode_list = list;
gInfo->shared_info->mode_list_area = gInfo->mode_list_area;
gInfo->shared_info->mode_count = count;
return B_OK;
}
void
wait_for_vblank(void)
{
acquire_sem_etc(gInfo->shared_info->vblank_sem, 1, B_RELATIVE_TIMEOUT,
25000);
// With the output turned off via DPMS, we might not get any interrupts
// anymore that's why we don't wait forever for it.
}
static void
get_pll_limits(pll_limits &limits)
{
@ -398,7 +282,7 @@ compute_pll_divisors(const display_mode &current, pll_divisors& divisors,
}
void
static void
retrieve_current_mode(display_mode& mode, uint32 pllRegister)
{
uint32 pll = read32(pllRegister);
@ -551,19 +435,6 @@ retrieve_current_mode(display_mode& mode, uint32 pllRegister)
}
/*! Store away panel information if identified on startup
(used for pipe B->lvds).
*/
void
save_lvds_mode(void)
{
// dump currently programmed mode.
display_mode biosMode;
retrieve_current_mode(biosMode, INTEL_DISPLAY_B_PLL);
gInfo->lvds_panel_mode = biosMode;
}
static void
get_color_space_format(const display_mode &mode, uint32 &colorMode,
uint32 &bytesPerRow, uint32 &bitsPerPixel)
@ -633,6 +504,143 @@ sanitize_display_mode(display_mode& mode)
}
// #pragma mark -
void
set_frame_buffer_base()
{
intel_shared_info &sharedInfo = *gInfo->shared_info;
display_mode &mode = sharedInfo.current_mode;
uint32 baseRegister;
uint32 surfaceRegister;
if (gInfo->head_mode & HEAD_MODE_A_ANALOG) {
baseRegister = INTEL_DISPLAY_A_BASE;
surfaceRegister = INTEL_DISPLAY_A_SURFACE;
} else {
baseRegister = INTEL_DISPLAY_B_BASE;
surfaceRegister = INTEL_DISPLAY_B_SURFACE;
}
if (sharedInfo.device_type.InGroup(INTEL_TYPE_96x)
|| sharedInfo.device_type.InGroup(INTEL_TYPE_G4x)
|| sharedInfo.device_type.InGroup(INTEL_TYPE_ILK)
|| sharedInfo.device_type.InGroup(INTEL_TYPE_SNB)
|| sharedInfo.device_type.InGroup(INTEL_TYPE_IVB)) {
write32(baseRegister, mode.v_display_start * sharedInfo.bytes_per_row
+ mode.h_display_start * (sharedInfo.bits_per_pixel + 7) / 8);
read32(baseRegister);
write32(surfaceRegister, sharedInfo.frame_buffer_offset);
read32(surfaceRegister);
} else {
write32(baseRegister, sharedInfo.frame_buffer_offset
+ mode.v_display_start * sharedInfo.bytes_per_row
+ mode.h_display_start * (sharedInfo.bits_per_pixel + 7) / 8);
read32(baseRegister);
}
}
/*! Creates the initial mode list of the primary accelerant.
It's called from intel_init_accelerant().
*/
status_t
create_mode_list(void)
{
i2c_bus bus;
bus.cookie = (void*)INTEL_I2C_IO_A;
bus.set_signals = &set_i2c_signals;
bus.get_signals = &get_i2c_signals;
ddc2_init_timing(&bus);
status_t error = ddc2_read_edid1(&bus, &gInfo->edid_info, NULL, NULL);
if (error == B_OK) {
edid_dump(&gInfo->edid_info);
gInfo->has_edid = true;
} else {
TRACE("getting EDID on port A (analog) failed : %s. "
"Trying on port C (lvds)\n", strerror(error));
bus.cookie = (void*)INTEL_I2C_IO_C;
error = ddc2_read_edid1(&bus, &gInfo->edid_info, NULL, NULL);
if (error == B_OK) {
edid_dump(&gInfo->edid_info);
gInfo->has_edid = true;
} else {
TRACE("getting EDID on port C failed : %s\n",
strerror(error));
// We could not read any EDID info. Fallback to creating a list with
// only the mode set up by the BIOS.
// TODO: support lower modes via scaling and windowing
if ((gInfo->head_mode & HEAD_MODE_LVDS_PANEL) != 0
&& (gInfo->head_mode & HEAD_MODE_A_ANALOG) == 0) {
size_t size = (sizeof(display_mode) + B_PAGE_SIZE - 1)
& ~(B_PAGE_SIZE - 1);
display_mode* list;
area_id area = create_area("intel extreme modes",
(void**)&list, B_ANY_ADDRESS, size, B_NO_LOCK,
B_READ_AREA | B_WRITE_AREA);
if (area < B_OK)
return area;
memcpy(list, &gInfo->lvds_panel_mode, sizeof(display_mode));
gInfo->mode_list_area = area;
gInfo->mode_list = list;
gInfo->shared_info->mode_list_area = gInfo->mode_list_area;
gInfo->shared_info->mode_count = 1;
return B_OK;
}
}
}
// Otherwise return the 'real' list of modes
display_mode* list;
uint32 count = 0;
gInfo->mode_list_area = create_display_modes("intel extreme modes",
gInfo->has_edid ? &gInfo->edid_info : NULL, NULL, 0, NULL, 0, NULL,
&list, &count);
if (gInfo->mode_list_area < B_OK)
return gInfo->mode_list_area;
gInfo->mode_list = list;
gInfo->shared_info->mode_list_area = gInfo->mode_list_area;
gInfo->shared_info->mode_count = count;
return B_OK;
}
void
wait_for_vblank(void)
{
acquire_sem_etc(gInfo->shared_info->vblank_sem, 1, B_RELATIVE_TIMEOUT,
25000);
// With the output turned off via DPMS, we might not get any interrupts
// anymore that's why we don't wait forever for it.
}
/*! Store away panel information if identified on startup
(used for pipe B->lvds).
*/
void
save_lvds_mode(void)
{
// dump currently programmed mode.
display_mode biosMode;
retrieve_current_mode(biosMode, INTEL_DISPLAY_B_PLL);
sanitize_display_mode(biosMode);
// The BIOS mode may not be a valid mode, as LVDS output does not
// really care about the sync values
gInfo->lvds_panel_mode = biosMode;
}
// #pragma mark -
@ -667,14 +675,14 @@ intel_propose_display_mode(display_mode* target, const display_mode* low,
// configurations.
for (uint32 i = 0; i < gInfo->shared_info->mode_count; i++) {
display_mode *mode = &gInfo->mode_list[i];
// TODO: improve this, ie. adapt pixel clock to allowed values!!!
if (target->virtual_width != mode->virtual_width
|| target->virtual_height != mode->virtual_height
|| target->space != mode->space)
continue;
*target = *mode;
return B_OK;
}

View File

@ -11,6 +11,7 @@ SubInclude HAIKU_TOP src add-ons kernel file_systems googlefs ;
SubInclude HAIKU_TOP src add-ons kernel file_systems iso9660 ;
SubInclude HAIKU_TOP src add-ons kernel file_systems netfs ;
SubInclude HAIKU_TOP src add-ons kernel file_systems nfs ;
SubInclude HAIKU_TOP src add-ons kernel file_systems nfs4 ;
SubInclude HAIKU_TOP src add-ons kernel file_systems ntfs ;
SubInclude HAIKU_TOP src add-ons kernel file_systems packagefs ;
SubInclude HAIKU_TOP src add-ons kernel file_systems ramfs ;

View File

@ -0,0 +1,798 @@
/*
* Copyright 2012-2013 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Paweł Dziepak, pdziepak@quarnos.org
*/
#include "Connection.h"
#include <arpa/inet.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <AutoDeleter.h>
#include <util/kernel_cpp.h>
#include <net/dns_resolver.h>
#define NFS4_PORT 2049
#define LAST_FRAGMENT 0x80000000
#define MAX_PACKET_SIZE 65535
#define NFS_MIN_PORT 665
bool
PeerAddress::operator==(const PeerAddress& address)
{
return memcmp(&fAddress, &address.fAddress, sizeof(fAddress)) == 0
&& fProtocol == address.fProtocol;
}
bool
PeerAddress::operator<(const PeerAddress& address)
{
int compare = memcmp(&fAddress, &address.fAddress, sizeof(fAddress));
return compare < 0 || (compare == 0 && fProtocol < address.fProtocol);
}
PeerAddress&
PeerAddress::operator=(const PeerAddress& address)
{
fAddress = address.fAddress;
fProtocol = address.fProtocol;
return *this;
}
PeerAddress::PeerAddress()
:
fProtocol(0)
{
memset(&fAddress, 0, sizeof(fAddress));
}
PeerAddress::PeerAddress(int networkFamily)
:
fProtocol(0)
{
ASSERT(networkFamily == AF_INET || networkFamily == AF_INET6);
memset(&fAddress, 0, sizeof(fAddress));
fAddress.ss_family = networkFamily;
switch (networkFamily) {
case AF_INET:
fAddress.ss_len = sizeof(sockaddr_in);
break;
case AF_INET6:
fAddress.ss_len = sizeof(sockaddr_in6);
break;
}
}
const char*
PeerAddress::ProtocolString() const
{
static const char* tcpName = "tcp";
static const char* udpName = "udp";
static const char* unknown = "";
switch (fProtocol) {
case IPPROTO_TCP:
return tcpName;
case IPPROTO_UDP:
return udpName;
default:
return unknown;
}
}
void
PeerAddress::SetProtocol(const char* protocol)
{
ASSERT(protocol != NULL);
if (strcmp(protocol, "tcp") == 0)
fProtocol = IPPROTO_TCP;
else if (strcmp(protocol, "udp") == 0)
fProtocol = IPPROTO_UDP;
}
char*
PeerAddress::UniversalAddress() const
{
char* uAddr = reinterpret_cast<char*>(malloc(INET6_ADDRSTRLEN + 16));
if (uAddr == NULL)
return NULL;
if (inet_ntop(fAddress.ss_family, InAddr(), uAddr, AddressSize()) == NULL)
return NULL;
char port[16];
sprintf(port, ".%d.%d", Port() >> 8, Port() & 0xff);
strcat(uAddr, port);
return uAddr;
}
socklen_t
PeerAddress::AddressSize() const
{
switch (Family()) {
case AF_INET:
return sizeof(sockaddr_in);
case AF_INET6:
return sizeof(sockaddr_in6);
default:
return 0;
}
}
uint16
PeerAddress::Port() const
{
uint16 port;
switch (Family()) {
case AF_INET:
port = reinterpret_cast<const sockaddr_in*>(&fAddress)->sin_port;
break;
case AF_INET6:
port = reinterpret_cast<const sockaddr_in6*>(&fAddress)->sin6_port;
break;
default:
port = 0;
}
return ntohs(port);
}
void
PeerAddress::SetPort(uint16 port)
{
port = htons(port);
switch (Family()) {
case AF_INET:
reinterpret_cast<sockaddr_in*>(&fAddress)->sin_port = port;
break;
case AF_INET6:
reinterpret_cast<sockaddr_in6*>(&fAddress)->sin6_port = port;
break;
}
}
const void*
PeerAddress::InAddr() const
{
switch (Family()) {
case AF_INET:
return &reinterpret_cast<const sockaddr_in*>(&fAddress)->sin_addr;
case AF_INET6:
return &reinterpret_cast<const sockaddr_in6*>(&fAddress)->sin6_addr;
default:
return NULL;
}
}
size_t
PeerAddress::InAddrSize() const
{
switch (Family()) {
case AF_INET:
return sizeof(in_addr);
case AF_INET6:
return sizeof(in6_addr);
default:
return 0;
}
}
AddressResolver::AddressResolver(const char* name)
:
fHead(NULL),
fCurrent(NULL),
fForcedPort(htons(NFS4_PORT)),
fForcedProtocol(IPPROTO_TCP)
{
fStatus = ResolveAddress(name);
}
AddressResolver::~AddressResolver()
{
freeaddrinfo(fHead);
}
status_t
AddressResolver::ResolveAddress(const char* name)
{
ASSERT(name != NULL);
if (fHead != NULL) {
freeaddrinfo(fHead);
fHead = NULL;
fCurrent = NULL;
}
// getaddrinfo() is very expensive when called from kernel, so we do not
// want to call it unless there is no other choice.
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
if (inet_aton(name, &addr.sin_addr) == 1) {
addr.sin_len = sizeof(addr);
addr.sin_family = AF_INET;
addr.sin_port = htons(NFS4_PORT);
memcpy(&fAddress.fAddress, &addr, sizeof(addr));
fAddress.fProtocol = IPPROTO_TCP;
return B_OK;
}
status_t result = getaddrinfo(name, NULL, NULL, &fHead);
fCurrent = fHead;
return result;
}
void
AddressResolver::ForceProtocol(const char* protocol)
{
ASSERT(protocol != NULL);
if (strcmp(protocol, "tcp") == 0)
fForcedProtocol = IPPROTO_TCP;
else if (strcmp(protocol, "udp") == 0)
fForcedProtocol = IPPROTO_UDP;
fAddress.SetProtocol(protocol);
}
void
AddressResolver::ForcePort(uint16 port)
{
fForcedPort = htons(port);
fAddress.SetPort(port);
}
status_t
AddressResolver::GetNextAddress(PeerAddress* address)
{
ASSERT(address != NULL);
if (fStatus != B_OK)
return fStatus;
if (fHead == NULL) {
*address = fAddress;
fStatus = B_NAME_NOT_FOUND;
return B_OK;
}
address->fProtocol = fForcedProtocol;
while (fCurrent != NULL) {
if (fCurrent->ai_family == AF_INET) {
memcpy(&address->fAddress, fCurrent->ai_addr, sizeof(sockaddr_in));
reinterpret_cast<sockaddr_in*>(&address->fAddress)->sin_port
= fForcedPort;
} else if (fCurrent->ai_family == AF_INET6) {
memcpy(&address->fAddress, fCurrent->ai_addr, sizeof(sockaddr_in6));
reinterpret_cast<sockaddr_in6*>(&address->fAddress)->sin6_port
= fForcedPort;
} else {
fCurrent = fCurrent->ai_next;
continue;
}
fCurrent = fCurrent->ai_next;
return B_OK;
}
return B_NAME_NOT_FOUND;
}
Connection::Connection(const PeerAddress& address)
:
ConnectionBase(address)
{
}
ConnectionListener::ConnectionListener(const PeerAddress& address)
:
ConnectionBase(address)
{
}
ConnectionBase::ConnectionBase(const PeerAddress& address)
:
fWaitCancel(create_sem(0, NULL)),
fSocket(-1),
fPeerAddress(address)
{
mutex_init(&fSocketLock, NULL);
}
ConnectionStream::ConnectionStream(const PeerAddress& address)
:
Connection(address)
{
}
ConnectionPacket::ConnectionPacket(const PeerAddress& address)
:
Connection(address)
{
}
ConnectionBase::~ConnectionBase()
{
if (fSocket != -1)
close(fSocket);
mutex_destroy(&fSocketLock);
delete_sem(fWaitCancel);
}
status_t
ConnectionBase::GetLocalAddress(PeerAddress* address)
{
ASSERT(address != NULL);
address->fProtocol = fPeerAddress.fProtocol;
socklen_t addressSize = sizeof(address->fAddress);
return getsockname(fSocket, (struct sockaddr*)&address->fAddress,
&addressSize);
}
status_t
ConnectionStream::Send(const void* buffer, uint32 size)
{
ASSERT(buffer != NULL);
status_t result;
uint32* buf = reinterpret_cast<uint32*>(malloc(size + sizeof(uint32)));
if (buf == NULL)
return B_NO_MEMORY;
MemoryDeleter _(buf);
buf[0] = htonl(size | LAST_FRAGMENT);
memcpy(buf + 1, buffer, size);
// More than one threads may send data and ksend is allowed to send partial
// data. Need a lock here.
uint32 sent = 0;
mutex_lock(&fSocketLock);
do {
result = send(fSocket, buf + sent, size + sizeof(uint32) - sent, 0);
sent += result;
} while (result > 0 && sent < size + sizeof(uint32));
mutex_unlock(&fSocketLock);
if (result < 0) {
result = errno;
return result;
} else if (result == 0)
return B_IO_ERROR;
return B_OK;
}
status_t
ConnectionPacket::Send(const void* buffer, uint32 size)
{
ASSERT(buffer != NULL);
ASSERT(size < 65535);
// send on DGRAM sockets is atomic. No need to lock.
status_t result = send(fSocket, buffer, size, 0);
if (result < 0)
return errno;
return B_OK;
}
status_t
ConnectionStream::Receive(void** _buffer, uint32* _size)
{
ASSERT(_buffer != NULL);
ASSERT(_size != NULL);
status_t result;
uint32 size = 0;
void* buffer = NULL;
uint32 record_size;
bool last_one = false;
object_wait_info object[2];
object[0].object = fWaitCancel;
object[0].type = B_OBJECT_TYPE_SEMAPHORE;
object[0].events = B_EVENT_ACQUIRE_SEMAPHORE;
object[1].object = fSocket;
object[1].type = B_OBJECT_TYPE_FD;
object[1].events = B_EVENT_READ;
do {
object[0].events = B_EVENT_ACQUIRE_SEMAPHORE;
object[1].events = B_EVENT_READ;
result = wait_for_objects(object, 2);
if (result < B_OK
|| (object[0].events & B_EVENT_ACQUIRE_SEMAPHORE) != 0) {
free(buffer);
return ECONNABORTED;
} else if ((object[1].events & B_EVENT_READ) == 0)
continue;
// There is only one listener thread per connection. No need to lock.
uint32 received = 0;
do {
result = recv(fSocket, ((uint8*)&record_size) + received,
sizeof(record_size) - received, 0);
received += result;
} while (result > 0 && received < sizeof(record_size));
if (result < 0) {
result = errno;
free(buffer);
return result;
} else if (result == 0) {
free(buffer);
return ECONNABORTED;
}
record_size = ntohl(record_size);
ASSERT(record_size > 0);
last_one = static_cast<int32>(record_size) < 0;
record_size &= LAST_FRAGMENT - 1;
void* ptr = realloc(buffer, size + record_size);
if (ptr == NULL) {
free(buffer);
return B_NO_MEMORY;
} else
buffer = ptr;
MemoryDeleter bufferDeleter(buffer);
received = 0;
do {
result = recv(fSocket, (uint8*)buffer + size + received,
record_size - received, 0);
received += result;
} while (result > 0 && received < record_size);
if (result < 0)
return errno;
else if (result == 0)
return ECONNABORTED;
bufferDeleter.Detach();
size += record_size;
} while (!last_one);
*_buffer = buffer;
*_size = size;
return B_OK;
}
status_t
ConnectionPacket::Receive(void** _buffer, uint32* _size)
{
ASSERT(_buffer != NULL);
ASSERT(_size != NULL);
status_t result;
int32 size = MAX_PACKET_SIZE;
void* buffer = malloc(size);
if (buffer == NULL)
return B_NO_MEMORY;
object_wait_info object[2];
object[0].object = fWaitCancel;
object[0].type = B_OBJECT_TYPE_SEMAPHORE;
object[0].events = B_EVENT_ACQUIRE_SEMAPHORE;
object[1].object = fSocket;
object[1].type = B_OBJECT_TYPE_FD;
object[1].events = B_EVENT_READ;
do {
object[0].events = B_EVENT_ACQUIRE_SEMAPHORE;
object[1].events = B_EVENT_READ;
result = wait_for_objects(object, 2);
if (result < B_OK
|| (object[0].events & B_EVENT_ACQUIRE_SEMAPHORE) != 0) {
free(buffer);
return ECONNABORTED;
} else if ((object[1].events & B_EVENT_READ) == 0)
continue;
break;
} while (true);
// There is only one listener thread per connection. No need to lock.
size = recv(fSocket, buffer, size, 0);
if (size < 0) {
result = errno;
free(buffer);
return result;
} else if (size == 0) {
free(buffer);
return ECONNABORTED;
}
*_buffer = buffer;
*_size = size;
return B_OK;
}
Connection*
Connection::CreateObject(const PeerAddress& address)
{
switch (address.fProtocol) {
case IPPROTO_TCP:
return new(std::nothrow) ConnectionStream(address);
case IPPROTO_UDP:
return new(std::nothrow) ConnectionPacket(address);
default:
return NULL;
}
}
status_t
Connection::Connect(Connection **_connection, const PeerAddress& address)
{
ASSERT(_connection != NULL);
Connection* conn = CreateObject(address);
if (conn == NULL)
return B_NO_MEMORY;
status_t result;
if (conn->fWaitCancel < B_OK) {
result = conn->fWaitCancel;
delete conn;
return result;
}
result = conn->Connect();
if (result != B_OK) {
delete conn;
return result;
}
*_connection = conn;
return B_OK;
}
status_t
Connection::SetTo(Connection **_connection, int socket,
const PeerAddress& address)
{
ASSERT(_connection != NULL);
ASSERT(socket != -1);
Connection* conn = CreateObject(address);
if (conn == NULL)
return B_NO_MEMORY;
status_t result;
if (conn->fWaitCancel < B_OK) {
result = conn->fWaitCancel;
delete conn;
return result;
}
conn->fSocket = socket;
*_connection = conn;
return B_OK;
}
status_t
Connection::Connect()
{
switch (fPeerAddress.fProtocol) {
case IPPROTO_TCP:
fSocket = socket(fPeerAddress.Family(), SOCK_STREAM, IPPROTO_TCP);
break;
case IPPROTO_UDP:
fSocket = socket(fPeerAddress.Family(), SOCK_DGRAM, IPPROTO_UDP);
break;
default:
return B_BAD_VALUE;
}
if (fSocket < 0)
return errno;
status_t result;
uint16 port, attempt = 0;
PeerAddress address(fPeerAddress.Family());
do {
port = rand() % (IPPORT_RESERVED - NFS_MIN_PORT);
port += NFS_MIN_PORT;
if (attempt == 9)
port = 0;
attempt++;
address.SetPort(port);
result = bind(fSocket, (sockaddr*)&address.fAddress,
address.AddressSize());
} while (attempt <= 10 && result != B_OK);
if (attempt > 10) {
close(fSocket);
return result;
}
result = connect(fSocket, (sockaddr*)&fPeerAddress.fAddress,
fPeerAddress.AddressSize());
if (result != 0) {
result = errno;
close(fSocket);
return result;
}
return B_OK;
}
status_t
Connection::Reconnect()
{
release_sem(fWaitCancel);
close(fSocket);
acquire_sem(fWaitCancel);
return Connect();
}
void
ConnectionBase::Disconnect()
{
release_sem(fWaitCancel);
close(fSocket);
fSocket = -1;
}
status_t
ConnectionListener::Listen(ConnectionListener** listener, int networkFamily,
uint16 port)
{
ASSERT(listener != NULL);
ASSERT(networkFamily == AF_INET || networkFamily == AF_INET6);
int sock = socket(networkFamily, SOCK_STREAM, IPPROTO_TCP);
if (sock < 0)
return errno;
PeerAddress address(networkFamily);
address.SetPort(port);
address.fProtocol = IPPROTO_TCP;
status_t result = bind(sock, (sockaddr*)&address.fAddress,
address.AddressSize());
if (result != B_OK) {
close(sock);
return errno;
}
if (listen(sock, 5) != B_OK) {
close(sock);
return errno;
}
*listener = new(std::nothrow) ConnectionListener(address);
if (*listener == NULL) {
close(sock);
return B_NO_MEMORY;
}
if ((*listener)->fWaitCancel < B_OK) {
result = (*listener)->fWaitCancel;
close(sock);
delete *listener;
return result;
}
(*listener)->fSocket = sock;
return B_OK;
}
status_t
ConnectionListener::AcceptConnection(Connection** connection)
{
ASSERT(connection != NULL);
object_wait_info object[2];
object[0].object = fWaitCancel;
object[0].type = B_OBJECT_TYPE_SEMAPHORE;
object[0].events = B_EVENT_ACQUIRE_SEMAPHORE;
object[1].object = fSocket;
object[1].type = B_OBJECT_TYPE_FD;
object[1].events = B_EVENT_READ;
do {
object[0].events = B_EVENT_ACQUIRE_SEMAPHORE;
object[1].events = B_EVENT_READ;
status_t result = wait_for_objects(object, 2);
if (result < B_OK
|| (object[0].events & B_EVENT_ACQUIRE_SEMAPHORE) != 0) {
return ECONNABORTED;
} else if ((object[1].events & B_EVENT_READ) == 0)
continue;
break;
} while (true);
sockaddr_storage addr;
socklen_t length = sizeof(addr);
int sock = accept(fSocket, reinterpret_cast<sockaddr*>(&addr), &length);
if (sock < 0)
return errno;
PeerAddress address;
address.fProtocol = IPPROTO_TCP;
address.fAddress = addr;
status_t result = Connection::SetTo(connection, sock, address);
if (result != B_OK) {
close(sock);
return result;
}
return B_OK;
}

View File

@ -0,0 +1,146 @@
/*
* Copyright 2012-2013 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Paweł Dziepak, pdziepak@quarnos.org
*/
#ifndef CONNECTION_H
#define CONNECTION_H
#include <netinet/in.h>
#include <lock.h>
#include <SupportDefs.h>
struct PeerAddress {
sockaddr_storage fAddress;
int fProtocol;
bool operator==(const PeerAddress& address);
bool operator<(const PeerAddress& address);
PeerAddress& operator=(const PeerAddress& address);
PeerAddress();
PeerAddress(int networkFamily);
inline int Family() const;
const char* ProtocolString() const;
void SetProtocol(const char* protocol);
char* UniversalAddress() const;
socklen_t AddressSize() const;
void SetPort(uint16 port);
uint16 Port() const;
const void* InAddr() const;
size_t InAddrSize() const;
};
inline int
PeerAddress::Family() const
{
return fAddress.ss_family;
}
struct addrinfo;
class AddressResolver {
public:
AddressResolver(const char* name);
~AddressResolver();
status_t GetNextAddress(PeerAddress* address);
void ForceProtocol(const char* protocol);
void ForcePort(uint16 port);
protected:
status_t ResolveAddress(const char* name);
private:
addrinfo* fHead;
addrinfo* fCurrent;
PeerAddress fAddress;
uint16 fForcedPort;
int fForcedProtocol;
status_t fStatus;
};
class ConnectionBase {
public:
ConnectionBase(const PeerAddress& address);
virtual ~ConnectionBase();
status_t GetLocalAddress(PeerAddress* address);
void Disconnect();
protected:
sem_id fWaitCancel;
int fSocket;
mutex fSocketLock;
const PeerAddress fPeerAddress;
};
class Connection : public ConnectionBase {
public:
static status_t Connect(Connection **connection,
const PeerAddress& address);
static status_t SetTo(Connection **connection, int socket,
const PeerAddress& address);
virtual status_t Send(const void* buffer, uint32 size) = 0;
virtual status_t Receive(void** buffer, uint32* size) = 0;
status_t Reconnect();
protected:
static Connection* CreateObject(const PeerAddress& address);
Connection(const PeerAddress& address);
status_t Connect();
};
class ConnectionStream : public Connection {
public:
ConnectionStream(const PeerAddress& address);
virtual status_t Send(const void* buffer, uint32 size);
virtual status_t Receive(void** buffer, uint32* size);
};
class ConnectionPacket : public Connection {
public:
ConnectionPacket(const PeerAddress& address);
virtual status_t Send(const void* buffer, uint32 size);
virtual status_t Receive(void** buffer, uint32* size);
};
class ConnectionListener : public ConnectionBase {
public:
static status_t Listen(ConnectionListener** listener, int networkFamily,
uint16 port = 0);
status_t AcceptConnection(Connection** connection);
protected:
ConnectionListener(const PeerAddress& address);
};
#endif // CONNECTION_H

View File

@ -0,0 +1,180 @@
/*
* Copyright 2012 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Paweł Dziepak, pdziepak@quarnos.org
*/
#include "Cookie.h"
#include "Inode.h"
#include "Request.h"
LockOwner::LockOwner(uint32 owner)
:
fSequence(0),
fOwner(owner),
fUseCount(0),
fNext(NULL),
fPrev(NULL)
{
memset(fStateId, 0, sizeof(fStateId));
mutex_init(&fLock, NULL);
}
LockOwner::~LockOwner()
{
mutex_destroy(&fLock);
}
LockInfo::LockInfo(LockOwner* owner)
:
fOwner(owner)
{
ASSERT(owner != NULL);
fOwner->fUseCount++;
}
LockInfo::~LockInfo()
{
fOwner->fUseCount--;
}
bool
LockInfo::operator==(const struct flock& lock) const
{
bool eof = lock.l_len + lock.l_start == OFF_MAX;
uint64 start = static_cast<uint64>(lock.l_start);
uint64 len = static_cast<uint64>(lock.l_len);
return fStart == start && (fLength == len
|| (eof && fLength == UINT64_MAX));
}
bool
LockInfo::operator==(const LockInfo& lock) const
{
return fOwner == lock.fOwner && fStart == lock.fStart
&& fLength == lock.fLength && fType == lock.fType;
}
Cookie::Cookie()
:
fRequests(NULL),
fSnoozeCancel(create_sem(1, NULL))
{
acquire_sem(fSnoozeCancel);
mutex_init(&fRequestLock, NULL);
}
Cookie::~Cookie()
{
delete_sem(fSnoozeCancel);
mutex_destroy(&fRequestLock);
}
status_t
Cookie::RegisterRequest(RPC::Request* req)
{
ASSERT(req != NULL);
RequestEntry* ent = new RequestEntry;
if (ent == NULL)
return B_NO_MEMORY;
MutexLocker _(fRequestLock);
ent->fRequest = req;
ent->fNext = fRequests;
fRequests = ent;
return B_OK;
}
status_t
Cookie::UnregisterRequest(RPC::Request* req)
{
ASSERT(req != NULL);
MutexLocker _(fRequestLock);
RequestEntry* ent = fRequests;
RequestEntry* prev = NULL;
while (ent != NULL) {
if (ent->fRequest == req) {
if (prev == NULL)
fRequests = ent->fNext;
else
prev->fNext = ent->fNext;
delete ent;
}
prev = ent;
ent = ent->fNext;
}
return B_OK;
}
status_t
Cookie::CancelAll()
{
release_sem(fSnoozeCancel);
MutexLocker _(fRequestLock);
RequestEntry* ent = fRequests;
while (ent != NULL) {
fFileSystem->Server()->WakeCall(ent->fRequest);
ent = ent->fNext;
}
return B_OK;
}
OpenFileCookie::OpenFileCookie()
:
fLocks(NULL)
{
}
void
OpenFileCookie::AddLock(LockInfo* lock)
{
ASSERT(lock != NULL);
lock->fCookieNext = fLocks;
fLocks = lock;
}
void
OpenFileCookie::RemoveLock(LockInfo* lock, LockInfo* prev)
{
if (prev != NULL)
prev->fCookieNext = lock->fCookieNext;
else {
ASSERT(prev == NULL && fLocks == lock);
fLocks = lock->fCookieNext;
}
}
OpenDirCookie::~OpenDirCookie()
{
if (fSnapshot != NULL)
fSnapshot->ReleaseReference();
}

View File

@ -0,0 +1,106 @@
/*
* Copyright 2012 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Paweł Dziepak, pdziepak@quarnos.org
*/
#ifndef COOKIE_H
#define COOKIE_H
#include <SupportDefs.h>
#include "DirectoryCache.h"
#include "FileSystem.h"
struct OpenState;
struct LockOwner {
uint64 fClientId;
uint32 fStateId[3];
uint32 fStateSeq;
uint32 fSequence;
uint32 fOwner;
uint32 fUseCount;
mutex fLock;
LockOwner* fNext;
LockOwner* fPrev;
LockOwner(uint32 owner);
~LockOwner();
};
struct LockInfo {
LockOwner* fOwner;
uint64 fStart;
uint64 fLength;
LockType fType;
LockInfo* fNext;
LockInfo* fCookieNext;
LockInfo(LockOwner* owner);
~LockInfo();
bool operator==(const struct flock& lock) const;
bool operator==(const LockInfo& lock) const;
};
struct Cookie {
struct RequestEntry {
RPC::Request* fRequest;
RequestEntry* fNext;
};
FileSystem* fFileSystem;
RequestEntry* fRequests;
mutex fRequestLock;
sem_id fSnoozeCancel;
Cookie();
virtual ~Cookie();
status_t RegisterRequest(RPC::Request* req);
status_t UnregisterRequest(RPC::Request* req);
status_t CancelAll();
};
struct OpenStateCookie : public Cookie {
OpenState* fOpenState;
uint32 fMode;
};
struct OpenFileCookie : public OpenStateCookie {
LockInfo* fLocks;
void AddLock(LockInfo* lock);
void RemoveLock(LockInfo* lock, LockInfo* prev);
OpenFileCookie();
};
struct OpenDirCookie : public Cookie {
int fSpecial;
DirectoryCacheSnapshot* fSnapshot;
NameCacheEntry* fCurrent;
bool fEOF;
bool fAttrDir;
~OpenDirCookie();
};
struct OpenAttrCookie : public OpenStateCookie { };
#endif // COOKIE_H

View File

@ -0,0 +1,65 @@
/*
* Copyright 2012 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Paweł Dziepak, pdziepak@quarnos.org
*/
#include "Delegation.h"
#include "Inode.h"
#include "Request.h"
Delegation::Delegation(const OpenDelegationData& data, Inode* inode,
uint64 clientID, bool attribute)
:
fClientID(clientID),
fData(data),
fInode(inode),
fAttribute(attribute)
{
ASSERT(inode != NULL);
}
status_t
Delegation::GiveUp(bool truncate)
{
if (!fAttribute && !truncate)
fInode->SyncAndCommit(true);
ReturnDelegation();
return B_OK;
}
status_t
Delegation::ReturnDelegation()
{
do {
RPC::Server* serv = fFileSystem->Server();
Request request(serv, fFileSystem);
RequestBuilder& req = request.Builder();
req.PutFH(fInfo.fHandle);
req.DelegReturn(fData.fStateID, fData.fStateSeq);
status_t result = request.Send();
if (result != B_OK)
return result;
ReplyInterpreter& reply = request.Reply();
if (HandleErrors(reply.NFS4Error(), serv, NULL, fInode->GetOpenState()))
continue;
reply.PutFH();
return reply.DelegReturn();
} while (true);
}

View File

@ -0,0 +1,65 @@
/*
* Copyright 2012 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Paweł Dziepak, pdziepak@quarnos.org
*/
#ifndef DELEGATION_H
#define DELEGATION_H
#include <lock.h>
#include <SupportDefs.h>
#include "NFS4Object.h"
class Inode;
class Delegation : public NFS4Object,
public DoublyLinkedListLinkImpl<Delegation> {
public:
Delegation(const OpenDelegationData& data, Inode* inode,
uint64 clientID, bool attr = false);
status_t GiveUp(bool truncate = false);
inline void SetData(const OpenDelegationData& data);
inline Inode* GetInode();
inline OpenDelegation Type();
protected:
status_t ReturnDelegation();
private:
uint64 fClientID;
OpenDelegationData fData;
Inode* fInode;
bool fAttribute;
};
inline void
Delegation::SetData(const OpenDelegationData& data)
{
fData = data;
}
inline Inode*
Delegation::GetInode()
{
return fInode;
}
inline OpenDelegation
Delegation::Type()
{
return fData.fType;
}
#endif // DELEGATION_H

View File

@ -0,0 +1,345 @@
/*
* Copyright 2012 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Paweł Dziepak, pdziepak@quarnos.org
*/
#include "DirectoryCache.h"
#include <fs_cache.h>
#include <NodeMonitor.h>
#include "Inode.h"
NameCacheEntry::NameCacheEntry(const char* name, ino_t node)
:
fNode(node),
fName(strdup(name))
{
ASSERT(name != NULL);
}
NameCacheEntry::NameCacheEntry(const NameCacheEntry& entry)
:
fNode(entry.fNode),
fName(strdup(entry.fName))
{
}
NameCacheEntry::~NameCacheEntry()
{
free(const_cast<char*>(fName));
}
DirectoryCacheSnapshot::DirectoryCacheSnapshot()
{
mutex_init(&fLock, NULL);
}
DirectoryCacheSnapshot::DirectoryCacheSnapshot(
const DirectoryCacheSnapshot& snapshot)
{
mutex_init(&fLock, NULL);
MutexLocker _(snapshot.fLock);
NameCacheEntry* entry = snapshot.fEntries.Head();
NameCacheEntry* new_entry;
while (entry) {
new_entry = new NameCacheEntry(*entry);
if (new_entry == NULL)
break;
fEntries.Add(new_entry);
entry = snapshot.fEntries.GetNext(entry);
}
}
DirectoryCacheSnapshot::~DirectoryCacheSnapshot()
{
while (!fEntries.IsEmpty()) {
NameCacheEntry* current = fEntries.RemoveHead();
delete current;
}
mutex_destroy(&fLock);
}
DirectoryCache::DirectoryCache(Inode* inode, bool attr)
:
fRevalidated(false),
fDirectoryCache(NULL),
fInode(inode),
fAttrDir(attr),
fTrashed(true)
{
ASSERT(inode != NULL);
mutex_init(&fLock, NULL);
}
DirectoryCache::~DirectoryCache()
{
mutex_destroy(&fLock);
}
void
DirectoryCache::Reset()
{
Trash();
fExpireTime = system_time() + kExpirationTime;
fTrashed = false;
}
void
DirectoryCache::Trash()
{
while (!fNameCache.IsEmpty()) {
NameCacheEntry* current = fNameCache.RemoveHead();
entry_cache_remove(fInode->GetFileSystem()->DevId(), fInode->ID(),
current->fName);
delete current;
}
_SetSnapshot(NULL);
fTrashed = true;
}
status_t
DirectoryCache::AddEntry(const char* name, ino_t node, bool created)
{
ASSERT(name != NULL);
NameCacheEntry* entry = new(std::nothrow) NameCacheEntry(name, node);
if (entry == NULL)
return B_NO_MEMORY;
if (entry->fName == NULL) {
delete entry;
return B_NO_MEMORY;
}
fNameCache.Add(entry);
if (created && fDirectoryCache != NULL) {
MutexLocker _(fDirectoryCache->fLock);
NameCacheEntry* entry = new(std::nothrow) NameCacheEntry(name, node);
if (entry == NULL)
return B_NO_MEMORY;
if (entry->fName == NULL) {
delete entry;
return B_NO_MEMORY;
}
fDirectoryCache->fEntries.Add(entry);
}
if (!fAttrDir) {
return entry_cache_add(fInode->GetFileSystem()->DevId(), fInode->ID(),
name, node);
}
return B_OK;
}
void
DirectoryCache::RemoveEntry(const char* name)
{
ASSERT(name != NULL);
SinglyLinkedList<NameCacheEntry>::Iterator iterator
= fNameCache.GetIterator();
NameCacheEntry* previous = NULL;
NameCacheEntry* current = iterator.Next();
while (current != NULL) {
if (strcmp(current->fName, name) == 0) {
fNameCache.Remove(previous, current);
delete current;
break;
}
previous = current;
current = iterator.Next();
}
if (fDirectoryCache != NULL) {
MutexLocker _(fDirectoryCache->fLock);
iterator = fDirectoryCache->fEntries.GetIterator();
previous = NULL;
current = iterator.Next();
while (current != NULL) {
if (strcmp(current->fName, name) == 0) {
fDirectoryCache->fEntries.Remove(previous, current);
delete current;
break;
}
previous = current;
current = iterator.Next();
}
}
if (!fAttrDir) {
entry_cache_remove(fInode->GetFileSystem()->DevId(), fInode->ID(),
name);
}
}
void
DirectoryCache::_SetSnapshot(DirectoryCacheSnapshot* snapshot)
{
if (fDirectoryCache != NULL)
fDirectoryCache->ReleaseReference();
fDirectoryCache = snapshot;
}
status_t
DirectoryCache::_LoadSnapshot(bool trash)
{
DirectoryCacheSnapshot* oldSnapshot = fDirectoryCache;
if (oldSnapshot != NULL)
oldSnapshot->AcquireReference();
if (trash)
Trash();
DirectoryCacheSnapshot* newSnapshot;
status_t result = fInode->GetDirSnapshot(&newSnapshot, NULL, &fChange,
fAttrDir);
if (result != B_OK) {
if (oldSnapshot != NULL)
oldSnapshot->ReleaseReference();
return result;
}
newSnapshot->AcquireReference();
_SetSnapshot(newSnapshot);
fExpireTime = system_time() + kExpirationTime;
fTrashed = false;
if (oldSnapshot != NULL)
NotifyChanges(oldSnapshot, newSnapshot);
if (oldSnapshot != NULL)
oldSnapshot->ReleaseReference();
newSnapshot->ReleaseReference();
return B_OK;
}
status_t
DirectoryCache::Revalidate()
{
if (fExpireTime < system_time())
return B_OK;
uint64 change;
if (fInode->GetChangeInfo(&change, fAttrDir) != B_OK) {
Trash();
return B_ERROR;
}
if (change == fChange) {
fExpireTime = system_time() + kExpirationTime;
return B_OK;
}
return _LoadSnapshot(true);
}
void
DirectoryCache::NotifyChanges(DirectoryCacheSnapshot* oldSnapshot,
DirectoryCacheSnapshot* newSnapshot)
{
ASSERT(newSnapshot != NULL);
ASSERT(oldSnapshot != NULL);
MutexLocker _(newSnapshot->fLock);
SinglyLinkedList<NameCacheEntry>::Iterator oldIt
= oldSnapshot->fEntries.GetIterator();
NameCacheEntry* oldCurrent;
SinglyLinkedList<NameCacheEntry>::Iterator newIt
= newSnapshot->fEntries.GetIterator();
NameCacheEntry* newCurrent = newIt.Next();
while (newCurrent != NULL) {
oldIt = oldSnapshot->fEntries.GetIterator();
oldCurrent = oldIt.Next();
bool found = false;
NameCacheEntry* prev = NULL;
while (oldCurrent != NULL) {
if (oldCurrent->fNode == newCurrent->fNode
&& strcmp(oldCurrent->fName, newCurrent->fName) == 0) {
found = true;
break;
}
prev = oldCurrent;
oldCurrent = oldIt.Next();
}
if (!found) {
if (fAttrDir) {
notify_attribute_changed(fInode->GetFileSystem()->DevId(),
fInode->ID(), newCurrent->fName, B_ATTR_CREATED);
} else {
notify_entry_created(fInode->GetFileSystem()->DevId(),
fInode->ID(), newCurrent->fName, newCurrent->fNode);
do {
FileInfo fi;
fi.fFileId = newCurrent->fNode;
fi.fParent = fInode->fInfo.fHandle;
status_t result = fi.CreateName(fInode->fInfo.fPath,
newCurrent->fName);
if (result != B_OK)
break;
fInode->GetFileSystem()->InoIdMap()->AddEntry(fi,
Inode::FileIdToInoT(newCurrent->fNode), true);
} while (false);
}
} else
oldSnapshot->fEntries.Remove(prev, oldCurrent);
newCurrent = newIt.Next();
}
oldIt = oldSnapshot->fEntries.GetIterator();
oldCurrent = oldIt.Next();
while (oldCurrent != NULL) {
if (fAttrDir) {
notify_attribute_changed(fInode->GetFileSystem()->DevId(),
fInode->ID(), newCurrent->fName, B_ATTR_REMOVED);
} else {
notify_entry_removed(fInode->GetFileSystem()->DevId(), fInode->ID(),
oldCurrent->fName, oldCurrent->fNode);
}
oldCurrent = oldIt.Next();
}
}

View File

@ -0,0 +1,175 @@
/*
* Copyright 2012 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Paweł Dziepak, pdziepak@quarnos.org
*/
#ifndef DIRECTORYCACHE_H
#define DIRECTORYCACHE_H
#include <lock.h>
#include <SupportDefs.h>
#include <util/DoublyLinkedList.h>
#include <util/KernelReferenceable.h>
#include <util/SinglyLinkedList.h>
class Inode;
struct NameCacheEntry :
public SinglyLinkedListLinkImpl<NameCacheEntry> {
ino_t fNode;
const char* fName;
NameCacheEntry(const char* name, ino_t node);
NameCacheEntry(const NameCacheEntry& entry);
~NameCacheEntry();
};
struct DirectoryCacheSnapshot : public KernelReferenceable {
SinglyLinkedList<NameCacheEntry> fEntries;
mutable mutex fLock;
DirectoryCacheSnapshot();
DirectoryCacheSnapshot(
const DirectoryCacheSnapshot& snapshot);
~DirectoryCacheSnapshot();
};
class DirectoryCache {
public:
DirectoryCache(Inode* inode, bool attr = false);
~DirectoryCache();
inline void Lock();
inline void Unlock();
void Reset();
void Trash();
inline bool Valid();
status_t AddEntry(const char* name, ino_t node,
bool created = false);
void RemoveEntry(const char* name);
inline status_t GetSnapshot(DirectoryCacheSnapshot** snapshot);
inline SinglyLinkedList<NameCacheEntry>& EntriesList();
status_t Revalidate();
inline status_t ValidateChangeInfo(uint64 change);
inline void SetChangeInfo(uint64 change);
inline uint64 ChangeInfo();
inline Inode* GetInode();
static const bigtime_t kExpirationTime = 15000000;
bool fRevalidated;
protected:
void NotifyChanges(DirectoryCacheSnapshot* oldSnapshot,
DirectoryCacheSnapshot* newSnapshot);
private:
void _SetSnapshot(DirectoryCacheSnapshot* snapshot);
status_t _LoadSnapshot(bool trash);
SinglyLinkedList<NameCacheEntry> fNameCache;
DirectoryCacheSnapshot* fDirectoryCache;
Inode* fInode;
bool fAttrDir;
bool fTrashed;
mutex fLock;
uint64 fChange;
bigtime_t fExpireTime;
};
inline void
DirectoryCache::Lock()
{
mutex_lock(&fLock);
}
inline void
DirectoryCache::Unlock()
{
mutex_unlock(&fLock);
}
inline bool
DirectoryCache::Valid()
{
return !fTrashed;
}
inline status_t
DirectoryCache::GetSnapshot(DirectoryCacheSnapshot** snapshot)
{
ASSERT(snapshot != NULL);
status_t result = B_OK;
if (fDirectoryCache == NULL)
result = _LoadSnapshot(false);
*snapshot = fDirectoryCache;
return result;
}
inline SinglyLinkedList<NameCacheEntry>&
DirectoryCache::EntriesList()
{
return fNameCache;
}
inline status_t
DirectoryCache::ValidateChangeInfo(uint64 change)
{
if (fTrashed || change != fChange) {
Trash();
fChange = change;
fExpireTime = system_time() + kExpirationTime;
fTrashed = false;
return B_ERROR;
}
return B_OK;
}
inline void
DirectoryCache::SetChangeInfo(uint64 change)
{
fExpireTime = system_time() + kExpirationTime;
fChange = change;
}
inline uint64
DirectoryCache::ChangeInfo()
{
return fChange;
}
inline Inode*
DirectoryCache::GetInode()
{
return fInode;
}
#endif // DIRECTORYCACHE_H

View File

@ -0,0 +1,144 @@
/*
* Copyright 2012 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Paweł Dziepak, pdziepak@quarnos.org
*/
#include "FileInfo.h"
#include "FileSystem.h"
#include "Request.h"
status_t
FileInfo::ParsePath(RequestBuilder& req, uint32& count, const char* _path)
{
ASSERT(_path != NULL);
char* path = strdup(_path);
if (path == NULL)
return B_NO_MEMORY;
char* pathStart = path;
char* pathEnd;
while (pathStart != NULL) {
pathEnd = strchr(pathStart, '/');
if (pathEnd != NULL)
*pathEnd = '\0';
if (pathEnd != pathStart) {
if (!strcmp(pathStart, "..")) {
req.LookUpUp();
count++;
} else if (strcmp(pathStart, ".")) {
req.LookUp(pathStart);
count++;
}
}
if (pathEnd != NULL && pathEnd[1] != '\0')
pathStart = pathEnd + 1;
else
pathStart = NULL;
}
free(path);
return B_OK;
}
status_t
FileInfo::CreateName(const char* dirPath, const char* name)
{
ASSERT(name != NULL);
free(const_cast<char*>(fName));
fName = strdup(name);
if (fName == NULL)
return B_NO_MEMORY;
free(const_cast<char*>(fPath));
fPath = NULL;
if (dirPath != NULL) {
char* path = reinterpret_cast<char*>(malloc(strlen(name) + 2
+ strlen(dirPath)));
if (path == NULL)
return B_NO_MEMORY;
strcpy(path, dirPath);
strcat(path, "/");
strcat(path, name);
fPath = path;
} else
fPath = strdup(name);
if (fPath == NULL)
return B_NO_MEMORY;
return B_OK;
}
status_t
FileInfo::UpdateFileHandles(FileSystem* fs)
{
ASSERT(fs != NULL);
Request request(fs->Server(), fs);
RequestBuilder& req = request.Builder();
req.PutRootFH();
uint32 lookupCount = 0;
status_t result;
result = ParsePath(req, lookupCount, fs->Path());
if (result != B_OK)
return result;
result = ParsePath(req, lookupCount, fPath);
if (result != B_OK)
return result;
if (fs->IsAttrSupported(FATTR4_FILEID)) {
AttrValue attr;
attr.fAttribute = FATTR4_FILEID;
attr.fFreePointer = false;
attr.fData.fValue64 = fFileId;
req.Verify(&attr, 1);
}
req.GetFH();
req.LookUpUp();
req.GetFH();
result = request.Send();
if (result != B_OK)
return result;
ReplyInterpreter& reply = request.Reply();
reply.PutRootFH();
for (uint32 i = 0; i < lookupCount; i++)
reply.LookUp();
if (fs->IsAttrSupported(FATTR4_FILEID)) {
result = reply.Verify();
if (result != B_OK)
return result;
}
reply.GetFH(&fHandle);
if (reply.LookUpUp() == B_ENTRY_NOT_FOUND) {
fParent = fHandle;
return B_OK;
}
return reply.GetFH(&fParent);
}

View File

@ -0,0 +1,188 @@
/*
* Copyright 2012 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Paweł Dziepak, pdziepak@quarnos.org
*/
#ifndef FILEINFO_H
#define FILEINFO_H
#include <stdlib.h>
#include <string.h>
#include <SupportDefs.h>
#define NFS4_FHSIZE 128
struct FileHandle {
uint8 fSize;
uint8 fData[NFS4_FHSIZE];
inline FileHandle();
inline FileHandle(const FileHandle& fh);
inline FileHandle& operator=(const FileHandle& fh);
inline bool operator!=(const FileHandle& handle) const;
inline bool operator>(const FileHandle& handle) const;
inline bool operator<(const FileHandle& handle) const;
};
class FileSystem;
class RequestBuilder;
// Complete information needed to identify a file in any situation.
// Unfortunately just a FileHandle is not enough even when they are persistent
// since OPEN requires both parent FileHandle and file name (just like LOOKUP).
struct FileInfo {
uint64 fFileId;
FileHandle fHandle;
FileHandle fParent;
const char* fName;
const char* fPath;
FileHandle fAttrDir;
inline FileInfo();
inline ~FileInfo();
inline FileInfo(const FileInfo& fi);
inline FileInfo& operator=(const FileInfo& fi);
status_t UpdateFileHandles(FileSystem* fs);
static status_t ParsePath(RequestBuilder& req, uint32& count,
const char* _path);
status_t CreateName(const char* dirPath, const char* name);
};
struct FileSystemId {
uint64 fMajor;
uint64 fMinor;
inline bool operator==(const FileSystemId& fsid) const;
inline bool operator!=(const FileSystemId& fsid) const;
};
inline
FileHandle::FileHandle()
:
fSize(0)
{
}
inline
FileHandle::FileHandle(const FileHandle& fh)
:
fSize(fh.fSize)
{
memcpy(fData, fh.fData, fSize);
}
inline FileHandle&
FileHandle::operator=(const FileHandle& fh)
{
fSize = fh.fSize;
memcpy(fData, fh.fData, fSize);
return *this;
}
inline bool
FileHandle::operator!=(const FileHandle& handle) const
{
if (fSize != handle.fSize)
return true;
return memcmp(fData, handle.fData, fSize) != 0;
}
inline bool
FileHandle::operator>(const FileHandle& handle) const
{
if (fSize > handle.fSize)
return true;
return memcmp(fData, handle.fData, fSize) > 0;
}
inline bool
FileHandle::operator<(const FileHandle& handle) const
{
if (fSize < handle.fSize)
return true;
return memcmp(fData, handle.fData, fSize) < 0;
}
inline
FileInfo::FileInfo()
:
fFileId(0),
fName(NULL),
fPath(NULL)
{
}
inline
FileInfo::~FileInfo()
{
free(const_cast<char*>(fName));
free(const_cast<char*>(fPath));
}
inline
FileInfo::FileInfo(const FileInfo& fi)
:
fFileId(fi.fFileId),
fHandle(fi.fHandle),
fParent(fi.fParent),
fName(strdup(fi.fName)),
fPath(strdup(fi.fPath))
{
}
inline FileInfo&
FileInfo::operator=(const FileInfo& fi)
{
fFileId = fi.fFileId;
fHandle = fi.fHandle;
fParent = fi.fParent;
free(const_cast<char*>(fName));
fName = strdup(fi.fName);
free(const_cast<char*>(fPath));
fPath = strdup(fi.fPath);
return *this;
}
inline bool
FileSystemId::operator==(const FileSystemId& fsid) const
{
return fMajor == fsid.fMajor && fMinor == fsid.fMinor;
}
inline bool
FileSystemId::operator!=(const FileSystemId& fsid) const
{
return !operator==(fsid);
}
#endif // FILEHINFO_H

View File

@ -0,0 +1,393 @@
/*
* Copyright 2012 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Paweł Dziepak, pdziepak@quarnos.org
*/
#include "FileSystem.h"
#include <string.h>
#include <AutoDeleter.h>
#include <lock.h>
#include "Request.h"
#include "RootInode.h"
extern RPC::ServerManager* gRPCServerManager;
extern RPC::ProgramData* CreateNFS4Server(RPC::Server* serv);
FileSystem::FileSystem(const MountConfiguration& configuration)
:
fOpenCount(0),
fOpenOwnerSequence(0),
fNamedAttrs(true),
fPath(NULL),
fRoot(NULL),
fId(1),
fConfiguration(configuration)
{
fOpenOwner = rand();
fOpenOwner <<= 32;
fOpenOwner |= rand();
mutex_init(&fOpenOwnerLock, NULL);
mutex_init(&fOpenLock, NULL);
mutex_init(&fDelegationLock, NULL);
mutex_init(&fCreateFileLock, NULL);
}
FileSystem::~FileSystem()
{
NFS4Server* server = reinterpret_cast<NFS4Server*>(fServer->PrivateData());
if (server != NULL)
server->RemoveFileSystem(this);
mutex_destroy(&fDelegationLock);
mutex_destroy(&fOpenLock);
mutex_destroy(&fOpenOwnerLock);
mutex_destroy(&fCreateFileLock);
free(const_cast<char*>(fPath));
delete fRoot;
}
static const char*
GetPath(const char* root, const char* path)
{
ASSERT(path != NULL);
int slash = 0;
int i;
for (i = 0; path[i] != '\0'; i++) {
if (path[i] == '/')
slash = i;
if (root == NULL)
break;
if (path[i] != root[i] || root[i] == '\0')
break;
}
if (path[i] == '\0')
return NULL;
return path + slash;
}
status_t
FileSystem::Mount(FileSystem** _fs, RPC::Server* serv, const char* fsPath,
dev_t id, const MountConfiguration& configuration)
{
ASSERT(_fs != NULL);
ASSERT(serv != NULL);
ASSERT(fsPath != NULL);
FileSystem* fs = new(std::nothrow) FileSystem(configuration);
if (fs == NULL)
return B_NO_MEMORY;
ObjectDeleter<FileSystem> fsDeleter(fs);
Request request(serv, fs);
RequestBuilder& req = request.Builder();
req.PutRootFH();
uint32 lookupCount = 0;
status_t result = FileInfo::ParsePath(req, lookupCount, fsPath);
if (result != B_OK)
return result;
req.GetFH();
req.Access();
Attribute attr[] = { FATTR4_SUPPORTED_ATTRS, FATTR4_FH_EXPIRE_TYPE,
FATTR4_FSID, FATTR4_FS_LOCATIONS };
req.GetAttr(attr, sizeof(attr) / sizeof(Attribute));
result = request.Send();
if (result != B_OK)
return result;
ReplyInterpreter& reply = request.Reply();
reply.PutRootFH();
for (uint32 i = 0; i < lookupCount; i++)
reply.LookUp();
FileHandle fh;
reply.GetFH(&fh);
uint32 allowed;
result = reply.Access(NULL, &allowed);
if (result != B_OK)
return result;
else if ((allowed & (ACCESS4_READ | ACCESS4_LOOKUP))
!= (ACCESS4_READ | ACCESS4_LOOKUP))
return B_PERMISSION_DENIED;
AttrValue* values;
uint32 count;
result = reply.GetAttr(&values, &count);
if (result != B_OK || count < 2)
return result;
// FATTR4_SUPPORTED_ATTRS is mandatory
memcpy(fs->fSupAttrs, &values[0].fData.fValue64, sizeof(fs->fSupAttrs));
// FATTR4_FH_EXPIRE_TYPE is mandatory
fs->fExpireType = values[1].fData.fValue32;
// FATTR4_FSID is mandatory
FileSystemId* fsid
= reinterpret_cast<FileSystemId*>(values[2].fData.fPointer);
if (count == 4 && values[3].fAttribute == FATTR4_FS_LOCATIONS) {
FSLocations* locs
= reinterpret_cast<FSLocations*>(values[3].fData.fLocations);
fs->fPath = strdup(locs->fRootPath);
} else
fs->fPath = NULL;
FileInfo fi;
const char* name;
if (fsPath != NULL && fsPath[0] == '/')
fsPath++;
fs->fServer = serv;
fs->fDevId = id;
fs->fFsId = *fsid;
fi.fHandle = fh;
fi.fParent = fh;
fi.fPath = strdup(GetPath(fs->fPath, fsPath));
if (fi.fPath != NULL) {
name = strrchr(fi.fPath, '/');
if (name != NULL) {
name++;
fi.fName = strdup(name);
}
}
delete[] values;
Inode* inode;
result = Inode::CreateInode(fs, fi, &inode);
if (result != B_OK)
return result;
name = strrchr(fsPath, '/');
if (name != NULL) {
name++;
reinterpret_cast<RootInode*>(inode)->SetName(name);
} else if (fsPath[0] != '\0')
reinterpret_cast<RootInode*>(inode)->SetName(fsPath);
else {
char* address = serv->ID().UniversalAddress();
if (address != NULL)
reinterpret_cast<RootInode*>(inode)->SetName(address);
else
reinterpret_cast<RootInode*>(inode)->SetName("NFS4 Share");
free(address);
}
fs->fRoot = reinterpret_cast<RootInode*>(inode);
fs->NFSServer()->AddFileSystem(fs);
*_fs = fs;
fsDeleter.Detach();
return B_OK;
}
status_t
FileSystem::GetInode(ino_t id, Inode** _inode)
{
ASSERT(_inode != NULL);
FileInfo fi;
status_t result = fInoIdMap.GetFileInfo(&fi, id);
ASSERT(result != B_ENTRY_NOT_FOUND);
if (result != B_OK)
return result;
Inode* inode;
result = Inode::CreateInode(this, fi, &inode);
if (result != B_OK)
return result;
*_inode = inode;
return B_OK;
}
status_t
FileSystem::Migrate(const RPC::Server* serv)
{
ASSERT(serv != NULL);
MutexLocker _(fOpenLock);
if (serv != fServer)
return B_OK;
if (!fRoot->ProbeMigration())
return B_OK;
AttrValue* values;
status_t result = fRoot->GetLocations(&values);
if (result != B_OK)
return result;
FSLocations* locs
= reinterpret_cast<FSLocations*>(values[0].fData.fLocations);
RPC::Server* server = fServer;
for (uint32 i = 0; i < locs->fCount; i++) {
for (uint32 j = 0; j < locs->fLocations[i].fCount; j++) {
AddressResolver resolver(locs->fLocations[i].fLocations[j]);
if (gRPCServerManager->Acquire(&fServer, &resolver,
CreateNFS4Server) == B_OK) {
free(const_cast<char*>(fPath));
fPath = strdup(locs->fLocations[i].fRootPath);
if (fPath == NULL) {
gRPCServerManager->Release(fServer);
fServer = server;
delete[] values;
return B_NO_MEMORY;
}
break;
}
}
}
delete[] values;
if (server == fServer) {
gRPCServerManager->Release(server);
return B_ERROR;
}
NFS4Server* old = reinterpret_cast<NFS4Server*>(server->PrivateData());
old->RemoveFileSystem(this);
NFSServer()->AddFileSystem(this);
gRPCServerManager->Release(server);
return B_OK;
}
DoublyLinkedList<OpenState>&
FileSystem::OpenFilesLock()
{
mutex_lock(&fOpenLock);
return fOpenFiles;
}
void
FileSystem::OpenFilesUnlock()
{
mutex_unlock(&fOpenLock);
}
void
FileSystem::AddOpenFile(OpenState* state)
{
ASSERT(state != NULL);
MutexLocker _(fOpenLock);
fOpenFiles.InsertBefore(fOpenFiles.Head(), state);
NFSServer()->IncUsage();
}
void
FileSystem::RemoveOpenFile(OpenState* state)
{
ASSERT(state != NULL);
MutexLocker _(fOpenLock);
fOpenFiles.Remove(state);
NFSServer()->DecUsage();
}
DoublyLinkedList<Delegation>&
FileSystem::DelegationsLock()
{
mutex_lock(&fDelegationLock);
return fDelegationList;
}
void
FileSystem::DelegationsUnlock()
{
mutex_unlock(&fDelegationLock);
}
void
FileSystem::AddDelegation(Delegation* delegation)
{
ASSERT(delegation != NULL);
MutexLocker _(fDelegationLock);
fDelegationList.InsertBefore(fDelegationList.Head(), delegation);
fHandleToDelegation.Remove(delegation->fInfo.fHandle);
fHandleToDelegation.Insert(delegation->fInfo.fHandle, delegation);
}
void
FileSystem::RemoveDelegation(Delegation* delegation)
{
ASSERT(delegation != NULL);
MutexLocker _(fDelegationLock);
fDelegationList.Remove(delegation);
fHandleToDelegation.Remove(delegation->fInfo.fHandle);
}
Delegation*
FileSystem::GetDelegation(const FileHandle& handle)
{
MutexLocker _(fDelegationLock);
AVLTreeMap<FileHandle, Delegation*>::Iterator it;
it = fHandleToDelegation.Find(handle);
if (!it.HasCurrent())
return NULL;
return it.Current();
}

View File

@ -0,0 +1,247 @@
/*
* Copyright 2012 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Paweł Dziepak, pdziepak@quarnos.org
*/
#ifndef FILESYSTEM_H
#define FILESYSTEM_H
#include "Delegation.h"
#include "InodeIdMap.h"
#include "NFS4Defs.h"
#include "NFS4Server.h"
class Inode;
class RootInode;
struct MountConfiguration {
bool fHard;
int fRetryLimit;
bigtime_t fRequestTimeout;
bool fEmulateNamedAttrs;
bool fCacheMetadata;
};
class FileSystem : public DoublyLinkedListLinkImpl<FileSystem> {
public:
static status_t Mount(FileSystem** pfs, RPC::Server* serv,
const char* path, dev_t id,
const MountConfiguration& configuration);
~FileSystem();
status_t GetInode(ino_t id, Inode** inode);
inline RootInode* Root();
status_t Migrate(const RPC::Server* serv);
DoublyLinkedList<OpenState>& OpenFilesLock();
void OpenFilesUnlock();
inline uint32 OpenFilesCount();
void AddOpenFile(OpenState* state);
void RemoveOpenFile(OpenState* state);
DoublyLinkedList<Delegation>& DelegationsLock();
void DelegationsUnlock();
void AddDelegation(Delegation* delegation);
void RemoveDelegation(Delegation* delegation);
Delegation* GetDelegation(const FileHandle& handle);
inline bool IsAttrSupported(Attribute attr) const;
inline uint32 ExpireType() const;
inline RPC::Server* Server();
inline NFS4Server* NFSServer();
inline const char* Path() const;
inline const FileSystemId& FsId() const;
inline uint64 AllocFileId();
inline dev_t DevId() const;
inline InodeIdMap* InoIdMap();
inline uint64 OpenOwner() const;
inline uint32 OpenOwnerSequenceLock();
inline void OpenOwnerSequenceUnlock(uint32 sequence);
inline bool NamedAttrs();
inline void SetNamedAttrs(bool attrs);
inline const MountConfiguration& GetConfiguration();
inline mutex& CreateFileLock();
private:
FileSystem(const MountConfiguration& config);
mutex fCreateFileLock;
mutex fDelegationLock;
DoublyLinkedList<Delegation> fDelegationList;
AVLTreeMap<FileHandle, Delegation*> fHandleToDelegation;
DoublyLinkedList<OpenState> fOpenFiles;
uint32 fOpenCount;
mutex fOpenLock;
uint64 fOpenOwner;
uint32 fOpenOwnerSequence;
mutex fOpenOwnerLock;
uint32 fExpireType;
uint32 fSupAttrs[2];
bool fNamedAttrs;
FileSystemId fFsId;
const char* fPath;
RootInode* fRoot;
RPC::Server* fServer;
vint64 fId;
dev_t fDevId;
InodeIdMap fInoIdMap;
MountConfiguration fConfiguration;
};
inline RootInode*
FileSystem::Root()
{
return fRoot;
}
inline uint32
FileSystem::OpenFilesCount()
{
return fOpenCount;
}
inline bool
FileSystem::IsAttrSupported(Attribute attr) const
{
return sIsAttrSet(attr, fSupAttrs, 2);
}
inline uint32
FileSystem::ExpireType() const
{
return fExpireType;
}
inline RPC::Server*
FileSystem::Server()
{
ASSERT(fServer != NULL);
return fServer;
}
inline NFS4Server*
FileSystem::NFSServer()
{
ASSERT(fServer->PrivateData() != NULL);
return reinterpret_cast<NFS4Server*>(fServer->PrivateData());
}
inline const char*
FileSystem::Path() const
{
ASSERT(fPath != NULL);
return fPath;
}
inline const FileSystemId&
FileSystem::FsId() const
{
return fFsId;
}
inline uint64
FileSystem::AllocFileId()
{
return atomic_add64(&fId, 1);
}
inline dev_t
FileSystem::DevId() const
{
return fDevId;
}
inline InodeIdMap*
FileSystem::InoIdMap()
{
return &fInoIdMap;
}
inline uint64
FileSystem::OpenOwner() const
{
return fOpenOwner;
}
inline uint32
FileSystem::OpenOwnerSequenceLock()
{
mutex_lock(&fOpenOwnerLock);
return fOpenOwnerSequence;
}
inline void
FileSystem::OpenOwnerSequenceUnlock(uint32 sequence)
{
fOpenOwnerSequence = sequence;
mutex_unlock(&fOpenOwnerLock);
}
inline bool
FileSystem::NamedAttrs()
{
return fNamedAttrs;
}
inline void
FileSystem::SetNamedAttrs(bool attrs)
{
fNamedAttrs = attrs;
}
inline const MountConfiguration&
FileSystem::GetConfiguration()
{
return fConfiguration;
}
inline mutex&
FileSystem::CreateFileLock()
{
return fCreateFileLock;
}
#endif // FILESYSTEM_H

View File

@ -0,0 +1,190 @@
/*
* Copyright 2012 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Paweł Dziepak, pdziepak@quarnos.org
*/
#include "IdMap.h"
#include <AutoDeleter.h>
#include <FindDirectory.h>
#include <team.h>
#include <util/AutoLock.h>
#include "idmapper/IdMapper.h"
IdMap* gIdMapper = NULL;
mutex gIdMapperLock;
IdMap::IdMap()
{
mutex_init(&fLock, NULL);
fInitStatus = _Repair();
}
IdMap::~IdMap()
{
delete_port(fRequestPort);
delete_port(fReplyPort);
mutex_destroy(&fLock);
}
uid_t
IdMap::GetUserId(const char* owner)
{
ASSERT(owner != NULL);
return _GetValue<uid_t>(owner, MsgNameToUID);
}
gid_t
IdMap::GetGroupId(const char* ownerGroup)
{
ASSERT(ownerGroup != NULL);
return _GetValue<gid_t>(ownerGroup, MsgNameToGID);
}
char*
IdMap::GetOwner(uid_t user)
{
return reinterpret_cast<char*>(_GetBuffer(user, MsgUIDToName));
}
char*
IdMap::GetOwnerGroup(gid_t group)
{
return reinterpret_cast<char*>(_GetBuffer(group, MsgGIDToName));
}
template<typename T>
T
IdMap::_GetValue(const char* buffer, int32 code)
{
ASSERT(buffer != NULL);
MutexLocker _(fLock);
do {
status_t result = write_port(fRequestPort, MsgNameToUID, buffer,
strlen(buffer) + 1);
if (result != B_OK) {
if (_Repair() != B_OK)
return 0;
continue;
}
int32 code;
T value;
result = read_port(fReplyPort, &code, &value, sizeof(T));
if (result < B_OK) {
if (_Repair() != B_OK)
return 0;
continue;
}
if (code != MsgReply)
return 0;
return value;
} while (true);
}
template<typename T>
void*
IdMap::_GetBuffer(T value, int32 code)
{
MutexLocker _(fLock);
do {
status_t result = write_port(fRequestPort, code, &value, sizeof(value));
if (result != B_OK) {
if (_Repair() != B_OK)
return NULL;
continue;
}
ssize_t size = port_buffer_size(fReplyPort);
if (size < B_OK) {
if (_Repair() != B_OK)
return NULL;
continue;
}
int32 code;
void* buffer = malloc(size);
if (buffer == NULL)
return NULL;
MemoryDeleter bufferDeleter(buffer);
size = read_port(fReplyPort, &code, buffer, size);
if (size < B_OK) {
if (_Repair() != B_OK)
return 0;
continue;
}
if (code != MsgReply)
return NULL;
bufferDeleter.Detach();
return buffer;
} while (true);
}
status_t
IdMap::_Repair()
{
status_t result = B_OK;
fRequestPort = create_port(1, kRequestPortName);
if (fRequestPort < B_OK)
return fRequestPort;
fReplyPort = create_port(1, kReplyPortName);
if (fReplyPort < B_OK) {
delete_port(fRequestPort);
return fReplyPort;
}
char path[256];
if (find_directory(B_SYSTEM_SERVERS_DIRECTORY, static_cast<dev_t>(-1),
false, path, sizeof(path)) != B_OK) {
delete_port(fReplyPort);
delete_port(fRequestPort);
return B_NAME_NOT_FOUND;
}
strlcat(path, "/nfs4_idmapper_server", sizeof(path));
const char* args[] = { path, NULL };
thread_id thread = load_image_etc(1, args, NULL, B_NORMAL_PRIORITY,
B_SYSTEM_TEAM, 0);
if (thread < B_OK) {
delete_port(fReplyPort);
delete_port(fRequestPort);
return thread;
}
set_port_owner(fRequestPort, thread);
set_port_owner(fReplyPort, thread);
result = resume_thread(thread);
if (result != B_OK) {
kill_thread(thread);
delete_port(fReplyPort);
delete_port(fRequestPort);
return result;
}
return B_OK;
}

View File

@ -0,0 +1,60 @@
/*
* Copyright 2012 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Paweł Dziepak, pdziepak@quarnos.org
*/
#ifndef IDMAP_H
#define IDMAP_H
#include <lock.h>
#include <port.h>
#include <SupportDefs.h>
class IdMap {
public:
IdMap();
~IdMap();
uid_t GetUserId(const char* owner);
gid_t GetGroupId(const char* ownerGroup);
char* GetOwner(uid_t user);
char* GetOwnerGroup(gid_t group);
inline status_t InitStatus();
private:
status_t _Repair();
template<typename T>
void* _GetBuffer(T value, int32 code);
template<typename T>
T _GetValue(const char* buffer, int32 code);
status_t fInitStatus;
mutex fLock;
port_id fRequestPort;
port_id fReplyPort;
};
inline status_t
IdMap::InitStatus()
{
return fInitStatus;
}
extern IdMap* gIdMapper;
extern mutex gIdMapperLock;
#endif // IDMAP_H

View File

@ -0,0 +1,981 @@
/*
* Copyright 2012 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Paweł Dziepak, pdziepak@quarnos.org
*/
#include "Inode.h"
#include <ctype.h>
#include <string.h>
#include <AutoDeleter.h>
#include <fs_cache.h>
#include <NodeMonitor.h>
#include "IdMap.h"
#include "Request.h"
#include "RootInode.h"
Inode::Inode()
:
fMetaCache(this),
fCache(NULL),
fAttrCache(NULL),
fDelegation(NULL),
fFileCache(NULL),
fMaxFileSize(0),
fOpenState(NULL),
fWriteDirty(false),
fAIOWait(create_sem(1, NULL)),
fAIOCount(0)
{
rw_lock_init(&fDelegationLock, NULL);
mutex_init(&fStateLock, NULL);
mutex_init(&fFileCacheLock, NULL);
rw_lock_init(&fWriteLock, NULL);
mutex_init(&fAIOLock, NULL);
}
status_t
Inode::CreateInode(FileSystem* fs, const FileInfo& fi, Inode** _inode)
{
ASSERT(fs != NULL);
ASSERT(_inode != NULL);
Inode* inode = NULL;
if (fs->Root() == NULL)
inode = new(std::nothrow) RootInode;
else
inode = new(std::nothrow) Inode;
if (inode == NULL)
return B_NO_MEMORY;
inode->fInfo = fi;
inode->fFileSystem = fs;
uint64 size;
do {
RPC::Server* serv = fs->Server();
Request request(serv, fs);
RequestBuilder& req = request.Builder();
req.PutFH(inode->fInfo.fHandle);
Attribute attr[] = { FATTR4_TYPE, FATTR4_CHANGE, FATTR4_SIZE,
FATTR4_FSID, FATTR4_FILEID };
req.GetAttr(attr, sizeof(attr) / sizeof(Attribute));
status_t result = request.Send();
if (result != B_OK)
return result;
ReplyInterpreter& reply = request.Reply();
if (inode->HandleErrors(reply.NFS4Error(), serv))
continue;
reply.PutFH();
AttrValue* values;
uint32 count;
result = reply.GetAttr(&values, &count);
if (result != B_OK || count < 4)
return result;
if (fi.fFileId == 0) {
if (count < 5 || values[4].fAttribute != FATTR4_FILEID)
inode->fInfo.fFileId = fs->AllocFileId();
else
inode->fInfo.fFileId = values[4].fData.fValue64;
} else
inode->fInfo.fFileId = fi.fFileId;
// FATTR4_TYPE is mandatory
inode->fType = values[0].fData.fValue32;
if (inode->fType == NF4DIR)
inode->fCache = new DirectoryCache(inode);
inode->fAttrCache = new DirectoryCache(inode, true);
// FATTR4_CHANGE is mandatory
inode->fChange = values[1].fData.fValue64;
// FATTR4_SIZE is mandatory
size = values[2].fData.fValue64;
// FATTR4_FSID is mandatory
FileSystemId* fsid
= reinterpret_cast<FileSystemId*>(values[3].fData.fPointer);
if (*fsid != fs->FsId()) {
delete[] values;
return B_ENTRY_NOT_FOUND;
}
delete[] values;
*_inode = inode;
break;
} while (true);
if (inode->fType == NF4REG)
inode->fFileCache = file_cache_create(fs->DevId(), inode->ID(), size);
return B_OK;
}
Inode::~Inode()
{
if (fDelegation != NULL)
RecallDelegation();
if (fFileCache != NULL)
file_cache_delete(fFileCache);
delete fCache;
delete fAttrCache;
delete_sem(fAIOWait);
mutex_destroy(&fAIOLock);
mutex_destroy(&fStateLock);
mutex_destroy(&fFileCacheLock);
rw_lock_destroy(&fDelegationLock);
rw_lock_destroy(&fWriteLock);
ASSERT(fAIOCount == 0);
}
status_t
Inode::RevalidateFileCache()
{
if (fDelegation != NULL)
return B_OK;
uint64 change;
status_t result = GetChangeInfo(&change);
if (result != B_OK)
return result;
MutexLocker _(fFileCacheLock);
if (change == fChange)
return B_OK;
struct stat st;
result = Stat(&st);
if (result != B_OK)
return result;
SyncAndCommit(true);
file_cache_delete(fFileCache);
fFileCache = file_cache_create(fFileSystem->DevId(), ID(), st.st_size);
change = fChange;
return B_OK;
}
status_t
Inode::LookUp(const char* name, ino_t* id)
{
ASSERT(name != NULL);
ASSERT(id != NULL);
if (fType != NF4DIR)
return B_NOT_A_DIRECTORY;
uint64 change;
uint64 fileID;
FileHandle handle;
status_t result = NFS4Inode::LookUp(name, &change, &fileID, &handle);
if (result != B_OK)
return result;
*id = FileIdToInoT(fileID);
result = ChildAdded(name, fileID, handle);
if (result != B_OK)
return result;
fCache->Lock();
if (!fCache->Valid()) {
fCache->Reset();
fCache->SetChangeInfo(change);
} else
fCache->ValidateChangeInfo(change);
fCache->AddEntry(name, *id);
fCache->Unlock();
return B_OK;
}
status_t
Inode::Link(Inode* dir, const char* name)
{
ASSERT(dir != NULL);
ASSERT(name != NULL);
ChangeInfo changeInfo;
status_t result = NFS4Inode::Link(dir, name, &changeInfo);
if (result != B_OK)
return result;
fFileSystem->Root()->MakeInfoInvalid();
FileInfo fi = fInfo;
fi.fParent = dir->fInfo.fHandle;
result = fi.CreateName(fInfo.fPath, name);
if (result != B_OK)
return result;
fFileSystem->InoIdMap()->AddEntry(fi, fInfo.fFileId);
dir->fCache->Lock();
if (dir->fCache->Valid()) {
if (changeInfo.fAtomic
&& dir->fCache->ChangeInfo() == changeInfo.fBefore) {
dir->fCache->AddEntry(name, fInfo.fFileId, true);
dir->fCache->SetChangeInfo(changeInfo.fAfter);
} else
dir->fCache->Trash();
}
dir->fCache->Unlock();
notify_entry_created(fFileSystem->DevId(), dir->ID(), name, ID());
return B_OK;
}
status_t
Inode::Remove(const char* name, FileType type, ino_t* id)
{
ASSERT(name != NULL);
MemoryDeleter nameDeleter;
if (type == NF4NAMEDATTR) {
status_t result = LoadAttrDirHandle();
if (result != B_OK)
return result;
name = AttrToFileName(name);
if (name == NULL)
return B_NO_MEMORY;
nameDeleter.SetTo(const_cast<char*>(name));
}
ChangeInfo changeInfo;
uint64 fileID;
status_t result = NFS4Inode::RemoveObject(name, type, &changeInfo, &fileID);
if (result != B_OK)
return result;
DirectoryCache* cache = type != NF4NAMEDATTR ? fCache : fAttrCache;
cache->Lock();
if (cache->Valid()) {
if (changeInfo.fAtomic
&& fCache->ChangeInfo() == changeInfo.fBefore) {
cache->RemoveEntry(name);
cache->SetChangeInfo(changeInfo.fAfter);
} else if (cache->ChangeInfo() != changeInfo.fBefore)
cache->Trash();
}
cache->Unlock();
fFileSystem->Root()->MakeInfoInvalid();
if (id != NULL)
*id = FileIdToInoT(fileID);
if (type == NF4NAMEDATTR) {
notify_attribute_changed(fFileSystem->DevId(), ID(), name,
B_ATTR_REMOVED);
} else {
notify_entry_removed(fFileSystem->DevId(), ID(), name,
FileIdToInoT(fileID));
}
return B_OK;
}
status_t
Inode::Rename(Inode* from, Inode* to, const char* fromName, const char* toName,
bool attribute, ino_t* id)
{
ASSERT(from != NULL);
ASSERT(fromName != NULL);
ASSERT(to != NULL);
ASSERT(toName != NULL);
if (from->fFileSystem != to->fFileSystem)
return B_DONT_DO_THAT;
MemoryDeleter fromNameDeleter;
MemoryDeleter toNameDeleter;
if (attribute) {
status_t result = from->LoadAttrDirHandle();
if (result != B_OK)
return result;
result = to->LoadAttrDirHandle();
if (result != B_OK)
return result;
fromName = from->AttrToFileName(fromName);
toName = to->AttrToFileName(toName);
fromNameDeleter.SetTo(const_cast<char*>(fromName));
toNameDeleter.SetTo(const_cast<char*>(toName));
if (fromName == NULL || toName == NULL)
return B_NO_MEMORY;
}
ChangeInfo fromChange, toChange;
uint64 fileID;
status_t result = NFS4Inode::RenameNode(from, to, fromName, toName,
&fromChange, &toChange, &fileID, attribute);
if (result != B_OK)
return result;
from->fFileSystem->Root()->MakeInfoInvalid();
DirectoryCache* cache = attribute ? from->fAttrCache : from->fCache;
cache->Lock();
if (cache->Valid()) {
if (fromChange.fAtomic
&& cache->ChangeInfo() == fromChange.fBefore) {
cache->RemoveEntry(fromName);
cache->SetChangeInfo(fromChange.fAfter);
} else if (cache->ChangeInfo() != fromChange.fBefore)
cache->Trash();
}
cache->Unlock();
if (id != NULL)
*id = FileIdToInoT(fileID);
cache = attribute ? to->fAttrCache : to->fCache;
cache->Lock();
if (cache->Valid()) {
if (toChange.fAtomic
&& cache->ChangeInfo() == toChange.fBefore) {
cache->AddEntry(toName, fileID, true);
cache->SetChangeInfo(toChange.fAfter);
} else if (to->fCache->ChangeInfo() != toChange.fBefore)
cache->Trash();
}
cache->Unlock();
if (attribute) {
notify_attribute_changed(from->fFileSystem->DevId(), from->ID(),
fromName, B_ATTR_REMOVED);
notify_attribute_changed(to->fFileSystem->DevId(), to->ID(), toName,
B_ATTR_CREATED);
} else {
notify_entry_moved(from->fFileSystem->DevId(), from->ID(), fromName,
to->ID(), toName, FileIdToInoT(fileID));
}
return B_OK;
}
status_t
Inode::CreateLink(const char* name, const char* path, int mode, ino_t* id)
{
return CreateObject(name, path, mode, NF4LNK, id);
}
status_t
Inode::CreateObject(const char* name, const char* path, int mode, FileType type,
ino_t* id)
{
ASSERT(name != NULL);
ASSERT(type != NF4LNK || path != NULL);
ChangeInfo changeInfo;
uint64 fileID;
FileHandle handle;
status_t result = NFS4Inode::CreateObject(name, path, mode, type, &changeInfo,
&fileID, &handle);
if (result != B_OK)
return B_OK;
fFileSystem->Root()->MakeInfoInvalid();
result = ChildAdded(name, fileID, handle);
if (result != B_OK)
return B_OK;
fCache->Lock();
if (fCache->Valid()) {
if (changeInfo.fAtomic && fCache->ChangeInfo() == changeInfo.fBefore) {
fCache->AddEntry(name, fileID, true);
fCache->SetChangeInfo(changeInfo.fAfter);
} else
fCache->Trash();
}
fCache->Unlock();
notify_entry_created(fFileSystem->DevId(), ID(), name,
FileIdToInoT(fileID));
*id = FileIdToInoT(fileID);
return B_OK;
}
status_t
Inode::Access(int mode)
{
int acc = 0;
uint32 allowed;
bool cache = fFileSystem->GetConfiguration().fCacheMetadata;
status_t result = fMetaCache.GetAccess(geteuid(), &allowed);
if (result != B_OK || !cache) {
result = NFS4Inode::Access(&allowed);
if (result != B_OK)
return result;
fMetaCache.SetAccess(geteuid(), allowed);
}
if ((allowed & ACCESS4_READ) != 0)
acc |= R_OK;
if ((allowed & ACCESS4_LOOKUP) != 0)
acc |= X_OK | R_OK;
if ((allowed & ACCESS4_EXECUTE) != 0)
acc |= X_OK;
if ((allowed & ACCESS4_MODIFY) != 0)
acc |= W_OK;
if ((mode & acc) != mode)
return B_NOT_ALLOWED;
return B_OK;
}
status_t
Inode::Stat(struct stat* st, OpenAttrCookie* attr)
{
ASSERT(st != NULL);
if (attr != NULL)
return GetStat(st, attr);
bool cache = fFileSystem->GetConfiguration().fCacheMetadata;
if (!cache)
return GetStat(st, NULL);
status_t result = fMetaCache.GetStat(st);
if (result != B_OK) {
struct stat temp;
result = GetStat(&temp);
if (result != B_OK)
return result;
fMetaCache.SetStat(temp);
fMetaCache.GetStat(st);
}
return B_OK;
}
status_t
Inode::GetStat(struct stat* st, OpenAttrCookie* attr)
{
ASSERT(st != NULL);
AttrValue* values;
uint32 count;
status_t result = NFS4Inode::GetStat(&values, &count, attr);
if (result != B_OK)
return result;
// FATTR4_SIZE is mandatory
if (count < 1 || values[0].fAttribute != FATTR4_SIZE) {
delete[] values;
return B_BAD_VALUE;
}
st->st_size = values[0].fData.fValue64;
uint32 next = 1;
st->st_mode = Type();
if (count >= next && values[next].fAttribute == FATTR4_MODE) {
st->st_mode |= values[next].fData.fValue32;
next++;
} else
st->st_mode = 777;
if (count >= next && values[next].fAttribute == FATTR4_NUMLINKS) {
st->st_nlink = values[next].fData.fValue32;
next++;
} else
st->st_nlink = 1;
if (count >= next && values[next].fAttribute == FATTR4_OWNER) {
char* owner = reinterpret_cast<char*>(values[next].fData.fPointer);
if (owner != NULL && isdigit(owner[0]))
st->st_uid = atoi(owner);
else
st->st_uid = gIdMapper->GetUserId(owner);
next++;
} else
st->st_uid = 0;
if (count >= next && values[next].fAttribute == FATTR4_OWNER_GROUP) {
char* group = reinterpret_cast<char*>(values[next].fData.fPointer);
if (group != NULL && isdigit(group[0]))
st->st_gid = atoi(group);
else
st->st_gid = gIdMapper->GetGroupId(group);
next++;
} else
st->st_gid = 0;
if (count >= next && values[next].fAttribute == FATTR4_TIME_ACCESS) {
memcpy(&st->st_atim, values[next].fData.fPointer,
sizeof(timespec));
next++;
} else
memset(&st->st_atim, 0, sizeof(timespec));
if (count >= next && values[next].fAttribute == FATTR4_TIME_CREATE) {
memcpy(&st->st_crtim, values[next].fData.fPointer,
sizeof(timespec));
next++;
} else
memset(&st->st_crtim, 0, sizeof(timespec));
if (count >= next && values[next].fAttribute == FATTR4_TIME_METADATA) {
memcpy(&st->st_ctim, values[next].fData.fPointer,
sizeof(timespec));
next++;
} else
memset(&st->st_ctim, 0, sizeof(timespec));
if (count >= next && values[next].fAttribute == FATTR4_TIME_MODIFY) {
memcpy(&st->st_mtim, values[next].fData.fPointer,
sizeof(timespec));
next++;
} else
memset(&st->st_mtim, 0, sizeof(timespec));
delete[] values;
st->st_blksize = fFileSystem->Root()->IOSize();
st->st_blocks = st->st_size / st->st_blksize;
st->st_blocks += st->st_size % st->st_blksize == 0 ? 0 : 1;
return B_OK;
}
status_t
Inode::WriteStat(const struct stat* st, uint32 mask, OpenAttrCookie* cookie)
{
ASSERT(st != NULL);
status_t result;
AttrValue attr[6];
uint32 i = 0;
if ((mask & B_STAT_SIZE) != 0) {
attr[i].fAttribute = FATTR4_SIZE;
attr[i].fFreePointer = false;
attr[i].fData.fValue64 = st->st_size;
i++;
}
if ((mask & B_STAT_MODE) != 0) {
attr[i].fAttribute = FATTR4_MODE;
attr[i].fFreePointer = false;
attr[i].fData.fValue32 = st->st_mode;
i++;
}
if ((mask & B_STAT_UID) != 0) {
attr[i].fAttribute = FATTR4_OWNER;
attr[i].fFreePointer = true;
attr[i].fData.fPointer = gIdMapper->GetOwner(st->st_uid);
i++;
}
if ((mask & B_STAT_GID) != 0) {
attr[i].fAttribute = FATTR4_OWNER_GROUP;
attr[i].fFreePointer = true;
attr[i].fData.fPointer = gIdMapper->GetOwnerGroup(st->st_gid);
i++;
}
if ((mask & B_STAT_ACCESS_TIME) != 0) {
attr[i].fAttribute = FATTR4_TIME_ACCESS_SET;
attr[i].fFreePointer = true;
attr[i].fData.fPointer = malloc(sizeof(st->st_atim));
memcpy(attr[i].fData.fPointer, &st->st_atim, sizeof(st->st_atim));
i++;
}
if ((mask & B_STAT_MODIFICATION_TIME) != 0) {
attr[i].fAttribute = FATTR4_TIME_MODIFY_SET;
attr[i].fFreePointer = true;
attr[i].fData.fPointer = malloc(sizeof(st->st_mtim));
memcpy(attr[i].fData.fPointer, &st->st_mtim, sizeof(st->st_mtim));
i++;
}
if (cookie == NULL) {
MutexLocker stateLocker(fStateLock);
ASSERT(fOpenState != NULL);
result = NFS4Inode::WriteStat(fOpenState, attr, i);
stateLocker.Unlock();
fMetaCache.InvalidateStat();
if ((mask & B_STAT_MODE) != 0 || (mask & B_STAT_UID) != 0
|| (mask & B_STAT_GID) != 0) {
fMetaCache.InvalidateAccess();
}
} else
result = NFS4Inode::WriteStat(cookie->fOpenState, attr, i);
return result;
}
inline status_t
Inode::CheckLockType(short ltype, uint32 mode)
{
switch (ltype) {
case F_UNLCK:
return B_OK;
case F_RDLCK:
if ((mode & O_RDONLY) == 0 && (mode & O_RDWR) == 0)
return EBADF;
return B_OK;
case F_WRLCK:
if ((mode & O_WRONLY) == 0 && (mode & O_RDWR) == 0)
return EBADF;
return B_OK;
default:
return B_BAD_VALUE;
}
}
status_t
Inode::TestLock(OpenFileCookie* cookie, struct flock* lock)
{
ASSERT(cookie != NULL);
ASSERT(lock != NULL);
if (lock->l_type == F_UNLCK)
return B_OK;
status_t result = CheckLockType(lock->l_type, cookie->fMode);
if (result != B_OK)
return result;
LockType ltype = sGetLockType(lock->l_type, false);
uint64 position = lock->l_start;
uint64 length = lock->l_len;
bool conflict;
result = NFS4Inode::TestLock(cookie, &ltype, &position, &length, conflict);
if (result != B_OK)
return result;
if (conflict) {
lock->l_type = sLockTypeToHaiku(ltype);
lock->l_start = static_cast<off_t>(position);
if (length >= OFF_MAX)
lock->l_len = OFF_MAX;
else
lock->l_len = static_cast<off_t>(length);
} else
lock->l_type = F_UNLCK;
return B_OK;
}
status_t
Inode::AcquireLock(OpenFileCookie* cookie, const struct flock* lock,
bool wait)
{
ASSERT(cookie != NULL);
ASSERT(lock != NULL);
OpenState* state = cookie->fOpenState;
status_t result = CheckLockType(lock->l_type, cookie->fMode);
if (result != B_OK)
return result;
thread_info info;
get_thread_info(find_thread(NULL), &info);
MutexLocker locker(state->fOwnerLock);
LockOwner* owner = state->GetLockOwner(info.team);
if (owner == NULL)
return B_NO_MEMORY;
LockInfo* linfo = new LockInfo(owner);
if (linfo == NULL)
return B_NO_MEMORY;
locker.Unlock();
linfo->fStart = lock->l_start;
if (lock->l_len + lock->l_start == OFF_MAX)
linfo->fLength = UINT64_MAX;
else
linfo->fLength = lock->l_len;
linfo->fType = sGetLockType(lock->l_type, wait);
result = NFS4Inode::AcquireLock(cookie, linfo, wait);
if (result != B_OK)
return result;
MutexLocker _(state->fLocksLock);
state->AddLock(linfo);
cookie->AddLock(linfo);
return B_OK;
}
status_t
Inode::ReleaseLock(OpenFileCookie* cookie, const struct flock* lock)
{
ASSERT(cookie != NULL);
ASSERT(lock != NULL);
SyncAndCommit();
LockInfo* prev = NULL;
thread_info info;
get_thread_info(find_thread(NULL), &info);
uint32 owner = info.team;
OpenState* state = cookie->fOpenState;
MutexLocker locker(state->fLocksLock);
LockInfo* linfo = state->fLocks;
while (linfo != NULL) {
if (linfo->fOwner->fOwner == owner && *linfo == *lock) {
state->RemoveLock(linfo, prev);
break;
}
prev = linfo;
linfo = linfo->fNext;
}
prev = NULL;
linfo = cookie->fLocks;
while (linfo != NULL) {
if (linfo->fOwner->fOwner == owner && *linfo == *lock) {
cookie->RemoveLock(linfo, prev);
break;
}
prev = linfo;
linfo = linfo->fCookieNext;
}
locker.Unlock();
if (linfo == NULL)
return B_BAD_VALUE;
status_t result = NFS4Inode::ReleaseLock(cookie, linfo);
if (result != B_OK)
return result;
state->DeleteLock(linfo);
return B_OK;
}
status_t
Inode::ReleaseAllLocks(OpenFileCookie* cookie)
{
ASSERT(cookie != NULL);
SyncAndCommit();
OpenState* state = cookie->fOpenState;
MutexLocker _(state->fLocksLock);
LockInfo* linfo = cookie->fLocks;
while (linfo != NULL) {
cookie->RemoveLock(linfo, NULL);
LockInfo* prev = NULL;
LockInfo* stateLock = state->fLocks;
while (stateLock != NULL) {
if (*linfo == *stateLock) {
state->RemoveLock(stateLock, prev);
break;
}
prev = stateLock;
stateLock = stateLock->fNext;
}
NFS4Inode::ReleaseLock(cookie, linfo);
state->DeleteLock(linfo);
linfo = cookie->fLocks;
}
return B_OK;
}
status_t
Inode::ChildAdded(const char* name, uint64 fileID,
const FileHandle& fileHandle)
{
ASSERT(name != NULL);
fFileSystem->Root()->MakeInfoInvalid();
FileInfo fi;
fi.fFileId = fileID;
fi.fHandle = fileHandle;
fi.fParent = fInfo.fHandle;
status_t result = fi.CreateName(fInfo.fPath, name);
if (result != B_OK)
return result;
return fFileSystem->InoIdMap()->AddEntry(fi, FileIdToInoT(fileID));
}
const char*
Inode::Name() const
{
return fInfo.fName;
}
void
Inode::SetDelegation(Delegation* delegation)
{
ASSERT(delegation != NULL);
WriteLocker _(fDelegationLock);
fMetaCache.InvalidateStat();
struct stat st;
Stat(&st);
fMetaCache.LockValid();
fDelegation = delegation;
fOpenState->AcquireReference();
fOpenState->fDelegation = delegation;
fFileSystem->AddDelegation(delegation);
}
void
Inode::RecallDelegation(bool truncate)
{
WriteLocker _(fDelegationLock);
if (fDelegation == NULL)
return;
ReturnDelegation(truncate);
}
void
Inode::RecallReadDelegation()
{
WriteLocker _(fDelegationLock);
if (fDelegation == NULL || fDelegation->Type() != OPEN_DELEGATE_READ)
return;
ReturnDelegation(false);
}
void
Inode::ReturnDelegation(bool truncate)
{
ASSERT(fDelegation != NULL);
fDelegation->GiveUp(truncate);
fMetaCache.UnlockValid();
fFileSystem->RemoveDelegation(fDelegation);
MutexLocker stateLocker(fStateLock);
fOpenState->fDelegation = NULL;
ReleaseOpenState();
delete fDelegation;
fDelegation = NULL;
}
void
Inode::ReleaseOpenState()
{
ASSERT(fOpenState != NULL);
if (fOpenState->ReleaseReference() == 1) {
ASSERT(fAIOCount == 0);
fOpenState = NULL;
}
}
status_t
Inode::SyncAndCommit(bool force)
{
if (!force && fDelegation != NULL)
return B_OK;
file_cache_sync(fFileCache);
WaitAIOComplete();
return Commit();
}
void
Inode::BeginAIOOp()
{
MutexLocker _(fAIOLock);
fAIOCount++;
if (fAIOCount == 1)
acquire_sem(fAIOWait);
}
void
Inode::EndAIOOp()
{
MutexLocker _(fAIOLock);
ASSERT(fAIOCount > 0);
fAIOCount--;
if (fAIOCount == 0)
release_sem(fAIOWait);
}

View File

@ -0,0 +1,258 @@
/*
* Copyright 2012 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Paweł Dziepak, pdziepak@quarnos.org
*/
#ifndef INODE_H
#define INODE_H
#include "DirectoryCache.h"
#include "MetadataCache.h"
#include "NFS4Inode.h"
#include "OpenState.h"
class Delegation;
class Inode : public NFS4Inode {
public:
static status_t CreateInode(FileSystem* fs, const FileInfo& fi,
Inode** inode);
virtual ~Inode();
inline ino_t ID() const;
inline mode_t Type() const;
virtual const char* Name() const;
inline FileSystem* GetFileSystem() const;
inline void SetOpenState(OpenState* state);
inline void* FileCache();
status_t RevalidateFileCache();
inline uint64 MaxFileSize();
inline uint64 Change();
inline bool Dirty();
inline OpenState* GetOpenState();
void SetDelegation(Delegation* delegation);
void RecallDelegation(bool truncate = false);
void RecallReadDelegation();
status_t LookUp(const char* name, ino_t* id);
status_t Access(int mode);
status_t Commit();
status_t SyncAndCommit(bool force = false);
status_t CreateObject(const char* name, const char* path,
int mode, FileType type, ino_t* id);
status_t CreateLink(const char* name, const char* path,
int mode, ino_t* id);
status_t Link(Inode* dir, const char* name);
status_t Remove(const char* name, FileType type,
ino_t* id = NULL);
static status_t Rename(Inode* from, Inode* to,
const char* fromName, const char* toName,
bool attribute = false, ino_t* id = NULL);
status_t Stat(struct stat* st,
OpenAttrCookie* attr = NULL);
status_t WriteStat(const struct stat* st, uint32 mask,
OpenAttrCookie* attr = NULL);
status_t Create(const char* name, int mode, int perms,
OpenFileCookie* cookie,
OpenDelegationData* data, ino_t* id);
status_t Open(int mode, OpenFileCookie* cookie);
status_t Close(OpenFileCookie* cookie);
status_t OpenAttr(const char* name, int mode,
OpenAttrCookie* cookie, bool create,
int32 type = 0);
status_t CloseAttr(OpenAttrCookie* cookie);
status_t Read(OpenFileCookie* cookie, off_t pos,
void* buffer, size_t* length);
status_t Write(OpenFileCookie* cookie, off_t pos,
const void* buffer, size_t* _length);
status_t ReadDirect(OpenStateCookie* cookie, off_t pos,
void* buffer, size_t* length, bool* eof);
status_t WriteDirect(OpenStateCookie* cookie, off_t pos,
const void* buffer, size_t* _length);
status_t CreateDir(const char* name, int mode,
ino_t* id);
status_t OpenDir(OpenDirCookie* cookie);
status_t ReadDir(void* buffer, uint32 size,
uint32* count, OpenDirCookie* cookie);
status_t OpenAttrDir(OpenDirCookie* cookie);
status_t TestLock(OpenFileCookie* cookie,
struct flock* lock);
status_t AcquireLock(OpenFileCookie* cookie,
const struct flock* lock, bool wait);
status_t ReleaseLock(OpenFileCookie* cookie,
const struct flock* lock);
status_t ReleaseAllLocks(OpenFileCookie* cookie);
status_t GetDirSnapshot(DirectoryCacheSnapshot**
_snapshot, OpenDirCookie* cookie,
uint64* _change, bool attribute);
status_t LoadAttrDirHandle();
static inline ino_t FileIdToInoT(uint64 fileid);
void BeginAIOOp();
void EndAIOOp();
inline void WaitAIOComplete();
protected:
Inode();
void ReleaseOpenState();
status_t CreateState(const char* name, int mode,
int perms, OpenState* state,
OpenDelegationData* data);
void ReturnDelegation(bool truncate);
status_t ReadDirUp(struct dirent* de, uint32 pos,
uint32 size);
status_t FillDirEntry(struct dirent* de, ino_t id,
const char* name, uint32 pos, uint32 size);
status_t ChildAdded(const char* name, uint64 fileID,
const FileHandle& fileHandle);
status_t GetStat(struct stat* st,
OpenAttrCookie* attr = NULL);
char* AttrToFileName(const char* path);
static inline status_t CheckLockType(short ltype, uint32 mode);
private:
uint32 fType;
MetadataCache fMetaCache;
DirectoryCache* fCache;
DirectoryCache* fAttrCache;
rw_lock fDelegationLock;
Delegation* fDelegation;
uint64 fChange;
void* fFileCache;
mutex fFileCacheLock;
uint64 fMaxFileSize;
OpenState* fOpenState;
mutex fStateLock;
rw_lock fWriteLock;
bool fWriteDirty;
sem_id fAIOWait;
uint32 fAIOCount;
mutex fAIOLock;
};
inline void
Inode::WaitAIOComplete()
{
acquire_sem(fAIOWait);
release_sem(fAIOWait);
}
inline ino_t
Inode::FileIdToInoT(uint64 fileid)
{
if (sizeof(ino_t) >= sizeof(uint64))
return fileid;
else
return (ino_t)fileid ^ (fileid >>
(sizeof(uint64) - sizeof(ino_t)) * 8);
}
inline ino_t
Inode::ID() const
{
return FileIdToInoT(fInfo.fFileId);
}
inline mode_t
Inode::Type() const
{
return sNFSFileTypeToHaiku[fType];
}
inline FileSystem*
Inode::GetFileSystem() const
{
ASSERT(fFileSystem != NULL);
return fFileSystem;
}
inline void*
Inode::FileCache()
{
return fFileCache;
}
inline void
Inode::SetOpenState(OpenState* state)
{
ASSERT(state != NULL);
fOpenState = state;
}
inline uint64
Inode::MaxFileSize()
{
return fMaxFileSize;
}
inline uint64
Inode::Change()
{
return fChange;
}
inline bool
Inode::Dirty()
{
return fWriteDirty;
}
inline OpenState*
Inode::GetOpenState()
{
return fOpenState;
}
#endif // INODE_H

View File

@ -0,0 +1,416 @@
/*
* Copyright 2012 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Paweł Dziepak, pdziepak@quarnos.org
*/
#include "Inode.h"
#include <dirent.h>
#include <string.h>
#include "IdMap.h"
#include "Request.h"
#include "RootInode.h"
status_t
Inode::CreateDir(const char* name, int mode, ino_t* id)
{
return CreateObject(name, NULL, mode, NF4DIR, id);
}
status_t
Inode::OpenDir(OpenDirCookie* cookie)
{
ASSERT(cookie != NULL);
if (fType != NF4DIR)
return B_NOT_A_DIRECTORY;
status_t result = Access(R_OK);
if (result != B_OK)
return result;
cookie->fFileSystem = fFileSystem;
cookie->fSpecial = 0;
cookie->fSnapshot = NULL;
cookie->fCurrent = NULL;
cookie->fEOF = false;
cookie->fAttrDir = false;
return B_OK;
}
status_t
Inode::OpenAttrDir(OpenDirCookie* cookie)
{
ASSERT(cookie != NULL);
cookie->fFileSystem = fFileSystem;
cookie->fSpecial = 0;
cookie->fSnapshot = NULL;
cookie->fCurrent = NULL;
cookie->fEOF = false;
cookie->fAttrDir = true;
return LoadAttrDirHandle();
}
status_t
Inode::LoadAttrDirHandle()
{
if (fInfo.fAttrDir.fSize != 0)
return B_OK;
FileHandle handle;
status_t result;
if (fFileSystem->NamedAttrs()) {
result = NFS4Inode::OpenAttrDir(&handle);
if (result == B_OK) {
fInfo.fAttrDir = handle;
return B_OK;
}
if (result != B_UNSUPPORTED)
return result;
fFileSystem->SetNamedAttrs(false);
}
if (!fFileSystem->GetConfiguration().fEmulateNamedAttrs)
return B_UNSUPPORTED;
char* attrDir
= reinterpret_cast<char*>(malloc(strlen(Name()) + 32));
if (attrDir == NULL)
return B_NO_MEMORY;
strcpy(attrDir, ".");
strcat(attrDir, Name());
strcat(attrDir, "-haiku-attrs");
result = NFS4Inode::LookUp(attrDir, NULL, NULL, &handle, true);
if (result == B_ENTRY_NOT_FOUND) {
ChangeInfo change;
struct stat st;
Stat(&st);
st.st_mode |= S_IXUSR | S_IXGRP | S_IXOTH;
result = NFS4Inode::CreateObject(attrDir, NULL, st.st_mode, NF4DIR,
&change, NULL, &handle, true);
}
free(attrDir);
if (result != B_OK)
return result;
fInfo.fAttrDir = handle;
return B_OK;
}
status_t
Inode::FillDirEntry(struct dirent* de, ino_t id, const char* name, uint32 pos,
uint32 size)
{
ASSERT(de != NULL);
ASSERT(name != NULL);
uint32 nameSize = strlen(name) + 1;
const uint32 entSize = sizeof(struct dirent);
if (pos + entSize + nameSize > size)
return B_BUFFER_OVERFLOW;
de->d_dev = fFileSystem->DevId();
de->d_ino = id;
de->d_reclen = entSize + nameSize;
if (de->d_reclen % 8 != 0)
de->d_reclen += 8 - de->d_reclen % 8;
strcpy(de->d_name, name);
return B_OK;
}
status_t
Inode::ReadDirUp(struct dirent* de, uint32 pos, uint32 size)
{
ASSERT(de != NULL);
do {
RPC::Server* serv = fFileSystem->Server();
Request request(serv, fFileSystem);
RequestBuilder& req = request.Builder();
req.PutFH(fInfo.fHandle);
req.LookUpUp();
req.GetFH();
if (fFileSystem->IsAttrSupported(FATTR4_FILEID)) {
Attribute attr[] = { FATTR4_FILEID };
req.GetAttr(attr, sizeof(attr) / sizeof(Attribute));
}
status_t result = request.Send();
if (result != B_OK)
return result;
ReplyInterpreter& reply = request.Reply();
if (HandleErrors(reply.NFS4Error(), serv))
continue;
reply.PutFH();
result = reply.LookUpUp();
if (result != B_OK)
return result;
FileHandle fh;
reply.GetFH(&fh);
uint64 fileId;
if (fFileSystem->IsAttrSupported(FATTR4_FILEID)) {
AttrValue* values;
uint32 count;
reply.GetAttr(&values, &count);
if (result != B_OK)
return result;
fileId = values[0].fData.fValue64;
delete[] values;
} else
fileId = fFileSystem->AllocFileId();
return FillDirEntry(de, FileIdToInoT(fileId), "..", pos, size);
} while (true);
}
static char*
FileToAttrName(const char* path)
{
ASSERT(path != NULL);
char* name = strdup(path);
if (name == NULL)
return NULL;
char* current = strpbrk(name, "#$");
while (current != NULL) {
switch (*current) {
case '#':
*current = '/';
break;
case '$':
*current = ':';
break;
}
current = strpbrk(name, "#$");
}
return name;
}
status_t
Inode::GetDirSnapshot(DirectoryCacheSnapshot** _snapshot,
OpenDirCookie* cookie, uint64* _change, bool attribute)
{
ASSERT(_snapshot != NULL);
DirectoryCacheSnapshot* snapshot = new DirectoryCacheSnapshot;
if (snapshot == NULL)
return B_NO_MEMORY;
uint64 change = 0;
uint64 dirCookie = 0;
uint64 dirCookieVerf = 0;
bool eof = false;
while (!eof) {
uint32 count;
DirEntry* dirents;
status_t result = ReadDirOnce(&dirents, &count, cookie, &eof, &change,
&dirCookie, &dirCookieVerf, attribute);
if (result != B_OK) {
delete snapshot;
return result;
}
uint32 i;
for (i = 0; i < count; i++) {
// FATTR4_FSID is mandatory
void* data = dirents[i].fAttrs[0].fData.fPointer;
FileSystemId* fsid = reinterpret_cast<FileSystemId*>(data);
if (*fsid != fFileSystem->FsId())
continue;
if (strstr(dirents[i].fName, "-haiku-attrs") != NULL)
continue;
ino_t id;
if (!attribute) {
if (dirents[i].fAttrCount == 2)
id = FileIdToInoT(dirents[i].fAttrs[1].fData.fValue64);
else
id = FileIdToInoT(fFileSystem->AllocFileId());
} else
id = 0;
const char* name = dirents[i].fName;
if (attribute)
name = FileToAttrName(name);
if (name == NULL) {
delete snapshot;
delete[] dirents;
return B_NO_MEMORY;
}
NameCacheEntry* entry = new NameCacheEntry(name, id);
if (attribute)
free(const_cast<char*>(name));
if (entry == NULL || entry->fName == NULL) {
if (entry != NULL)
delete entry;
delete snapshot;
delete[] dirents;
return B_NO_MEMORY;
}
snapshot->fEntries.Add(entry);
}
delete[] dirents;
}
*_snapshot = snapshot;
*_change = change;
return B_OK;
}
status_t
Inode::ReadDir(void* _buffer, uint32 size, uint32* _count,
OpenDirCookie* cookie)
{
ASSERT(_buffer != NULL);
ASSERT(_count != NULL);
ASSERT(cookie != NULL);
if (cookie->fEOF) {
*_count = 0;
return B_OK;
}
status_t result;
DirectoryCache* cache = cookie->fAttrDir ? fAttrCache : fCache;
if (cookie->fSnapshot == NULL) {
cache->Lock();
result = cache->Revalidate();
if (result != B_OK) {
cache->Unlock();
return result;
}
DirectoryCacheSnapshot* snapshot;
result = cache->GetSnapshot(&snapshot);
if (result != B_OK) {
cache->Unlock();
return result;
}
cookie->fSnapshot = new DirectoryCacheSnapshot(*snapshot);
cache->Unlock();
if (cookie->fSnapshot == NULL)
return B_NO_MEMORY;
}
char* buffer = reinterpret_cast<char*>(_buffer);
uint32 pos = 0;
uint32 i = 0;
bool overflow = false;
if (cookie->fSpecial == 0 && i < *_count && !cookie->fAttrDir) {
struct dirent* de = reinterpret_cast<dirent*>(buffer + pos);
status_t result;
result = FillDirEntry(de, fInfo.fFileId, ".", pos, size);
if (result == B_BUFFER_OVERFLOW)
overflow = true;
else if (result == B_OK) {
pos += de->d_reclen;
i++;
cookie->fSpecial++;
} else
return result;
}
if (cookie->fSpecial == 1 && i < *_count && !cookie->fAttrDir) {
struct dirent* de = reinterpret_cast<dirent*>(buffer + pos);
status_t result;
result = ReadDirUp(de, pos, size);
if (result == B_ENTRY_NOT_FOUND) {
result = FillDirEntry(de, FileIdToInoT(fInfo.fFileId), "..", pos,
size);
}
if (result == B_BUFFER_OVERFLOW)
overflow = true;
else if (result == B_OK) {
pos += de->d_reclen;
i++;
cookie->fSpecial++;
} else
return result;
}
MutexLocker _(cookie->fSnapshot->fLock);
for (; !overflow && i < *_count; i++) {
struct dirent* de = reinterpret_cast<dirent*>(buffer + pos);
NameCacheEntry* temp = cookie->fCurrent;
if (cookie->fCurrent == NULL)
cookie->fCurrent = cookie->fSnapshot->fEntries.Head();
else {
cookie->fCurrent
= cookie->fSnapshot->fEntries.GetNext(cookie->fCurrent);
}
if (cookie->fCurrent == NULL) {
cookie->fEOF = true;
break;
}
if (FillDirEntry(de, cookie->fCurrent->fNode, cookie->fCurrent->fName,
pos, size) == B_BUFFER_OVERFLOW) {
cookie->fCurrent = temp;
overflow = true;
break;
}
pos += de->d_reclen;
}
if (i == 0 && overflow)
return B_BUFFER_OVERFLOW;
*_count = i;
return B_OK;
}

View File

@ -0,0 +1,126 @@
/*
* Copyright 2012 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Paweł Dziepak, pdziepak@quarnos.org
*/
#ifndef INODEIDMAP_H
#define INODEIDMAP_H
#include <lock.h>
#include <SupportDefs.h>
#include <util/AutoLock.h>
#include <util/AVLTreeMap.h>
#include "FileInfo.h"
struct InodeIdMapEntry {
FileInfo fFileInfo;
bool fRemoved;
};
class InodeIdMap {
public:
inline InodeIdMap();
inline ~InodeIdMap();
inline status_t AddEntry(const FileInfo& fi,
ino_t id, bool weak = false);
inline status_t MarkRemoved(ino_t id);
inline status_t RemoveEntry(ino_t id);
inline status_t GetFileInfo(FileInfo* fi, ino_t id);
protected:
inline bool _IsEntryRemoved(ino_t id);
private:
AVLTreeMap<ino_t, InodeIdMapEntry> fMap;
mutex fLock;
};
inline
InodeIdMap::InodeIdMap()
{
mutex_init(&fLock, NULL);
}
inline
InodeIdMap::~InodeIdMap()
{
mutex_destroy(&fLock);
}
inline status_t
InodeIdMap::AddEntry(const FileInfo& fi, ino_t id, bool weak)
{
InodeIdMapEntry entry;
MutexLocker _(fLock);
if (!weak || _IsEntryRemoved(id))
fMap.Remove(id);
entry.fFileInfo = fi;
entry.fRemoved = false;
return fMap.Insert(id, entry);
}
inline status_t
InodeIdMap::MarkRemoved(ino_t id)
{
MutexLocker _(fLock);
AVLTreeMap<ino_t, InodeIdMapEntry>::Iterator it = fMap.Find(id);
if (!it.HasCurrent())
return B_ENTRY_NOT_FOUND;
it.CurrentValuePointer()->fRemoved = true;
return B_OK;
}
inline status_t
InodeIdMap::RemoveEntry(ino_t id)
{
MutexLocker _(fLock);
if (_IsEntryRemoved(id))
return fMap.Remove(id);
return B_OK;
}
inline status_t
InodeIdMap::GetFileInfo(FileInfo* fi, ino_t id)
{
ASSERT(fi != NULL);
MutexLocker _(fLock);
AVLTreeMap<ino_t, InodeIdMapEntry>::Iterator it = fMap.Find(id);
if (!it.HasCurrent())
return B_ENTRY_NOT_FOUND;
*fi = it.Current().fFileInfo;
return B_OK;
}
// Caller must hold fLock
inline bool
InodeIdMap::_IsEntryRemoved(ino_t id)
{
AVLTreeMap<ino_t, InodeIdMapEntry>::Iterator it = fMap.Find(id);
if (!it.HasCurrent())
return true;
return it.Current().fRemoved;
}
#endif // INODEIDMAP_H

View File

@ -0,0 +1,446 @@
/*
* Copyright 2012 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Paweł Dziepak, pdziepak@quarnos.org
*/
#include "Inode.h"
#include <string.h>
#include <AutoDeleter.h>
#include <fs_cache.h>
#include <NodeMonitor.h>
#include "IdMap.h"
#include "Request.h"
#include "RootInode.h"
status_t
Inode::CreateState(const char* name, int mode, int perms, OpenState* state,
OpenDelegationData* delegationData) {
ASSERT(name != NULL);
ASSERT(state != NULL);
ASSERT(delegationData != NULL);
uint64 fileID;
FileHandle handle;
ChangeInfo changeInfo;
status_t result = CreateFile(name, mode, perms, state, &changeInfo,
&fileID, &handle, delegationData);
if (result != B_OK)
return result;
FileInfo fi;
fi.fFileId = fileID;
fi.fHandle = handle;
fi.fParent = fInfo.fHandle;
fi.CreateName(fInfo.fPath, name);
fFileSystem->InoIdMap()->AddEntry(fi, FileIdToInoT(fileID));
fCache->Lock();
if (fCache->Valid()) {
if (changeInfo.fAtomic
&& fCache->ChangeInfo() == changeInfo.fBefore) {
fCache->AddEntry(name, fileID, true);
fCache->SetChangeInfo(changeInfo.fAfter);
} else
fCache->Trash();
}
fCache->Unlock();
state->fFileSystem = fFileSystem;
state->fInfo = fi;
state->fMode = mode & O_RWMASK;
return B_OK;
}
status_t
Inode::Create(const char* name, int mode, int perms, OpenFileCookie* cookie,
OpenDelegationData* data, ino_t* id)
{
ASSERT(name != NULL);
ASSERT(cookie != NULL);
ASSERT(data != NULL);
cookie->fMode = mode;
cookie->fLocks = NULL;
OpenState* state = new OpenState;
status_t result = CreateState(name, mode, perms, state, data);
if (result != B_OK)
return result;
cookie->fOpenState = state;
cookie->fFileSystem = fFileSystem;
*id = FileIdToInoT(state->fInfo.fFileId);
fFileSystem->AddOpenFile(state);
fFileSystem->Root()->MakeInfoInvalid();
notify_entry_created(fFileSystem->DevId(), ID(), name, *id);
return B_OK;
}
status_t
Inode::Open(int mode, OpenFileCookie* cookie)
{
ASSERT(cookie != NULL);
MutexLocker locker(fStateLock);
OpenDelegationData data;
data.fType = OPEN_DELEGATE_NONE;
if (fOpenState == NULL) {
RevalidateFileCache();
OpenState* state = new OpenState;
if (state == NULL)
return B_NO_MEMORY;
state->fInfo = fInfo;
state->fFileSystem = fFileSystem;
state->fMode = mode & O_RWMASK;
status_t result = OpenFile(state, mode, &data);
if (result != B_OK)
return result;
fFileSystem->AddOpenFile(state);
fOpenState = state;
cookie->fOpenState = state;
locker.Unlock();
} else {
fOpenState->AcquireReference();
cookie->fOpenState = fOpenState;
locker.Unlock();
int newMode = mode & O_RWMASK;
int oldMode = fOpenState->fMode & O_RWMASK;
if (oldMode != newMode && oldMode != O_RDWR) {
if (oldMode == O_RDONLY)
RecallReadDelegation();
status_t result = OpenFile(fOpenState, O_RDWR, &data);
if (result != B_OK) {
locker.Lock();
ReleaseOpenState();
return result;
}
fOpenState->fMode = O_RDWR;
} else {
int newMode = mode & O_RWMASK;
uint32 allowed = 0;
if (newMode == O_RDWR || newMode == O_RDONLY)
allowed |= R_OK;
if (newMode == O_RDWR || newMode == O_WRONLY)
allowed |= W_OK;
status_t result = Access(allowed);
if (result != B_OK) {
locker.Lock();
ReleaseOpenState();
return result;
}
}
}
if ((mode & O_TRUNC) == O_TRUNC) {
struct stat st;
st.st_size = 0;
WriteStat(&st, B_STAT_SIZE);
file_cache_set_size(fFileCache, 0);
}
cookie->fFileSystem = fFileSystem;
cookie->fMode = mode;
cookie->fLocks = NULL;
if (data.fType != OPEN_DELEGATE_NONE) {
Delegation* delegation
= new(std::nothrow) Delegation(data, this, fOpenState->fClientID);
if (delegation != NULL) {
delegation->fInfo = fOpenState->fInfo;
delegation->fFileSystem = fFileSystem;
SetDelegation(delegation);
}
}
return B_OK;
}
status_t
Inode::Close(OpenFileCookie* cookie)
{
ASSERT(cookie != NULL);
ASSERT(fOpenState == cookie->fOpenState);
SyncAndCommit();
MutexLocker _(fStateLock);
ReleaseOpenState();
return B_OK;
}
char*
Inode::AttrToFileName(const char* path)
{
ASSERT(path != NULL);
char* name = strdup(path);
if (name == NULL)
return NULL;
char* current = strpbrk(name, "/:");
while (current != NULL) {
switch (*current) {
case '/':
*current = '#';
break;
case ':':
*current = '$';
break;
}
current = strpbrk(name, "/:");
}
return name;
}
status_t
Inode::OpenAttr(const char* _name, int mode, OpenAttrCookie* cookie,
bool create, int32 type)
{
ASSERT(_name != NULL);
ASSERT(cookie != NULL);
(void)type;
status_t result = LoadAttrDirHandle();
if (result != B_OK)
return result;
char* name = AttrToFileName(_name);
if (name == NULL)
return B_NO_MEMORY;
MemoryDeleter nameDeleter(name);
OpenDelegationData data;
data.fType = OPEN_DELEGATE_NONE;
OpenState* state = new OpenState;
if (state == NULL)
return B_NO_MEMORY;
state->fInfo.fName = strdup(name);
state->fInfo.fParent = fInfo.fAttrDir;
state->fFileSystem = fFileSystem;
result = NFS4Inode::OpenAttr(state, name, mode, &data, create);
if (result != B_OK) {
delete state;
return result;
}
fFileSystem->AddOpenFile(state);
cookie->fOpenState = state;
cookie->fFileSystem = fFileSystem;
cookie->fMode = mode;
if (data.fType != OPEN_DELEGATE_NONE) {
Delegation* delegation
= new(std::nothrow) Delegation(data, this, state->fClientID, true);
if (delegation != NULL) {
delegation->fInfo = state->fInfo;
delegation->fFileSystem = fFileSystem;
state->fDelegation = delegation;
fFileSystem->AddDelegation(delegation);
}
}
if (create || (mode & O_TRUNC) == O_TRUNC) {
struct stat st;
st.st_size = 0;
WriteStat(&st, B_STAT_SIZE, cookie);
}
return B_OK;
}
status_t
Inode::CloseAttr(OpenAttrCookie* cookie)
{
ASSERT(cookie != NULL);
if (cookie->fOpenState->fDelegation != NULL) {
cookie->fOpenState->fDelegation->GiveUp();
fFileSystem->RemoveDelegation(cookie->fOpenState->fDelegation);
}
delete cookie->fOpenState->fDelegation;
delete cookie->fOpenState;
return B_OK;
}
status_t
Inode::ReadDirect(OpenStateCookie* cookie, off_t pos, void* buffer,
size_t* _length, bool* eof)
{
ASSERT(cookie != NULL || fOpenState != NULL);
ASSERT(buffer != NULL);
ASSERT(_length != NULL);
ASSERT(eof != NULL);
*eof = false;
uint32 size = 0;
uint32 ioSize = fFileSystem->Root()->IOSize();
*_length = min_c(ioSize, *_length);
status_t result;
OpenState* state = cookie != NULL ? cookie->fOpenState : fOpenState;
while (size < *_length && !*eof) {
uint32 len = *_length - size;
result = ReadFile(cookie, state, pos + size, &len,
reinterpret_cast<char*>(buffer) + size, eof);
if (result != B_OK) {
if (size == 0)
return result;
else
break;
}
size += len;
}
*_length = size;
return B_OK;
}
status_t
Inode::Read(OpenFileCookie* cookie, off_t pos, void* buffer, size_t* _length)
{
ASSERT(cookie != NULL);
ASSERT(buffer != NULL);
ASSERT(_length != NULL);
bool eof = false;
if ((cookie->fMode & O_NOCACHE) != 0)
return ReadDirect(cookie, pos, buffer, _length, &eof);
return file_cache_read(fFileCache, cookie, pos, buffer, _length);
}
status_t
Inode::WriteDirect(OpenStateCookie* cookie, off_t pos, const void* _buffer,
size_t* _length)
{
ASSERT(cookie != NULL || fOpenState != NULL);
ASSERT(_buffer != NULL);
ASSERT(_length != NULL);
uint32 size = 0;
const char* buffer = reinterpret_cast<const char*>(_buffer);
uint32 ioSize = fFileSystem->Root()->IOSize();
*_length = min_c(ioSize, *_length);
bool attribute = false;
OpenState* state = fOpenState;
if (cookie != NULL) {
attribute = cookie->fOpenState->fInfo.fHandle != fInfo.fHandle;
state = cookie->fOpenState;
}
if (!attribute) {
ReadLocker _(fWriteLock);
fWriteDirty = true;
}
while (size < *_length) {
uint32 len = *_length - size;
status_t result = WriteFile(cookie, state, pos + size, &len,
buffer + size, attribute);
if (result != B_OK) {
if (size == 0)
return result;
else
break;
}
size += len;
}
*_length = size;
fMetaCache.GrowFile(size + pos);
fFileSystem->Root()->MakeInfoInvalid();
return B_OK;
}
status_t
Inode::Write(OpenFileCookie* cookie, off_t pos, const void* _buffer,
size_t* _length)
{
ASSERT(cookie != NULL);
ASSERT(_buffer != NULL);
ASSERT(_length != NULL);
struct stat st;
status_t result = Stat(&st);
if (result != B_OK)
return result;
if ((cookie->fMode & O_APPEND) != 0)
pos = st.st_size;
uint64 fileSize = max_c(st.st_size, pos + *_length);
fMaxFileSize = max_c(fMaxFileSize, fileSize);
if ((cookie->fMode & O_NOCACHE) != 0) {
WriteDirect(cookie, pos, _buffer, _length);
Commit();
}
result = file_cache_set_size(fFileCache, fileSize);
if (result != B_OK)
return result;
return file_cache_write(fFileCache, cookie, pos, _buffer, _length);
}
status_t
Inode::Commit()
{
WriteLocker _(fWriteLock);
if (!fWriteDirty)
return B_OK;
status_t result = CommitWrites();
if (result != B_OK)
return result;
fWriteDirty = false;
return B_OK;
}

View File

@ -0,0 +1,43 @@
SubDir HAIKU_TOP src add-ons kernel file_systems nfs4 ;
UsePrivateKernelHeaders ;
UsePrivateHeaders shared ;
KernelAddon nfs4 :
Cookie.cpp
Connection.cpp
Delegation.cpp
DirectoryCache.cpp
FileInfo.cpp
FileSystem.cpp
IdMap.cpp
Inode.cpp
InodeDir.cpp
InodeRegular.cpp
kernel_interface.cpp
MetadataCache.cpp
NFS4Inode.cpp
NFS4Object.cpp
NFS4Server.cpp
OpenState.cpp
ReplyBuilder.cpp
ReplyInterpreter.cpp
Request.cpp
RequestBuilder.cpp
RequestInterpreter.cpp
RootInode.cpp
RPCAuth.cpp
RPCCall.cpp
RPCCallback.cpp
RPCCallbackReply.cpp
RPCCallbackRequest.cpp
RPCCallbackServer.cpp
RPCReply.cpp
RPCServer.cpp
VnodeToInode.cpp
WorkQueue.cpp
XDR.cpp
;
SubInclude HAIKU_TOP src add-ons kernel file_systems nfs4 idmapper ;

View File

@ -0,0 +1,180 @@
/*
* Copyright 2012 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Paweł Dziepak, pdziepak@quarnos.org
*/
#include "MetadataCache.h"
#include <NodeMonitor.h>
#include "Inode.h"
MetadataCache::MetadataCache(Inode* inode)
:
fExpire(0),
fForceValid(false),
fInode(inode),
fInited(false)
{
ASSERT(inode != NULL);
mutex_init(&fLock, NULL);
}
MetadataCache::~MetadataCache()
{
mutex_destroy(&fLock);
}
status_t
MetadataCache::GetStat(struct stat* st)
{
ASSERT(st != NULL);
MutexLocker _(fLock);
if (fForceValid || fExpire > time(NULL)) {
// Do not touch other members of struct stat
st->st_size = fStatCache.st_size;
st->st_mode = fStatCache.st_mode;
st->st_nlink = fStatCache.st_nlink;
st->st_uid = fStatCache.st_uid;
st->st_gid = fStatCache.st_gid;
st->st_atim = fStatCache.st_atim;
st->st_ctim = fStatCache.st_ctim;
st->st_crtim = fStatCache.st_crtim;
st->st_mtim = fStatCache.st_mtim;
st->st_blksize = fStatCache.st_blksize;
st->st_blocks = fStatCache.st_blocks;
return B_OK;
}
return B_ERROR;
}
void
MetadataCache::SetStat(const struct stat& st)
{
MutexLocker _(fLock);
if (fInited)
NotifyChanges(&fStatCache, &st);
fStatCache = st;
fExpire = time(NULL) + kExpirationTime;
fInited = true;
}
void
MetadataCache::GrowFile(size_t newSize)
{
MutexLocker _(fLock);
fStatCache.st_size = max_c(newSize, fStatCache.st_size);
}
status_t
MetadataCache::GetAccess(uid_t uid, uint32* allowed)
{
ASSERT(allowed != NULL);
MutexLocker _(fLock);
AVLTreeMap<uid_t, AccessEntry>::Iterator it = fAccessCache.Find(uid);
if (!it.HasCurrent())
return B_ENTRY_NOT_FOUND;
if (!fForceValid)
it.CurrentValuePointer()->fForceValid = false;
if (!it.Current().fForceValid && it.Current().fExpire < time(NULL)) {
it.Remove();
return B_ERROR;
}
*allowed = it.Current().fAllowed;
return B_OK;
}
void
MetadataCache::SetAccess(uid_t uid, uint32 allowed)
{
MutexLocker _(fLock);
AVLTreeMap<uid_t, AccessEntry>::Iterator it = fAccessCache.Find(uid);
if (it.HasCurrent())
it.Remove();
AccessEntry entry;
entry.fAllowed = allowed;
entry.fExpire = time(NULL) + kExpirationTime;
entry.fForceValid = fForceValid;
fAccessCache.Insert(uid, entry);
}
status_t
MetadataCache::LockValid()
{
MutexLocker _(fLock);
if (fForceValid || fExpire > time(NULL)) {
fForceValid = true;
return B_OK;
}
return B_ERROR;
}
void
MetadataCache::UnlockValid()
{
MutexLocker _(fLock);
fExpire = time(NULL) + kExpirationTime;
fForceValid = false;
}
void
MetadataCache::NotifyChanges(const struct stat* oldStat,
const struct stat* newStat)
{
ASSERT(oldStat != NULL);
ASSERT(newStat != NULL);
uint32 flags = 0;
if (oldStat->st_size != newStat->st_size)
flags |= B_STAT_SIZE;
if (oldStat->st_mode != newStat->st_mode)
flags |= B_STAT_MODE;
if (oldStat->st_uid != newStat->st_uid)
flags |= B_STAT_UID;
if (oldStat->st_gid != newStat->st_gid)
flags |= B_STAT_GID;
if (memcmp(&oldStat->st_atim, &newStat->st_atim,
sizeof(struct timespec) == 0))
flags |= B_STAT_ACCESS_TIME;
if (memcmp(&oldStat->st_ctim, &newStat->st_ctim,
sizeof(struct timespec) == 0))
flags |= B_STAT_CHANGE_TIME;
if (memcmp(&oldStat->st_crtim, &newStat->st_crtim,
sizeof(struct timespec) == 0))
flags |= B_STAT_CREATION_TIME;
if (memcmp(&oldStat->st_mtim, &newStat->st_mtim,
sizeof(struct timespec) == 0))
flags |= B_STAT_MODIFICATION_TIME;
notify_stat_changed(fInode->GetFileSystem()->DevId(), fInode->ID(), flags);
}

View File

@ -0,0 +1,95 @@
/*
* Copyright 2012 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Paweł Dziepak, pdziepak@quarnos.org
*/
#ifndef METADATACACHE_H
#define METADATACACHE_H
#include <fs_interface.h>
#include <lock.h>
#include <SupportDefs.h>
#include <util/AutoLock.h>
#include <util/AVLTreeMap.h>
class Inode;
struct AccessEntry {
time_t fExpire;
bool fForceValid;
uint32 fAllowed;
};
class MetadataCache {
public:
MetadataCache(Inode* inode);
~MetadataCache();
status_t GetStat(struct stat* st);
void SetStat(const struct stat& st);
void GrowFile(size_t newSize);
status_t GetAccess(uid_t uid, uint32* allowed);
void SetAccess(uid_t uid, uint32 allowed);
status_t LockValid();
void UnlockValid();
inline void InvalidateStat();
inline void InvalidateAccess();
inline void Invalidate();
static const time_t kExpirationTime = 60;
protected:
void NotifyChanges(const struct stat* oldStat,
const struct stat* newStat);
private:
struct stat fStatCache;
time_t fExpire;
bool fForceValid;
Inode* fInode;
bool fInited;
AVLTreeMap<uid_t, AccessEntry> fAccessCache;
mutex fLock;
};
inline void
MetadataCache::InvalidateStat()
{
MutexLocker _(fLock);
if (!fForceValid)
fExpire = 0;
}
inline void
MetadataCache::InvalidateAccess()
{
MutexLocker _(fLock);
if (!fForceValid)
fAccessCache.MakeEmpty();
}
inline void
MetadataCache::Invalidate()
{
InvalidateStat();
InvalidateAccess();
}
#endif // METADATACACHE_H

Some files were not shown because too many files have changed in this diff Show More